C# Build Net6 library and tests using cmake (#7326)

* Dotnet core build and test for RDKit

* Cmake dot net build and ctest working on windows

* Remove old Linux mono build

* Update to net8 and create RDK_BUILD_DOTNET_CSHARP_TESTS flag
This commit is contained in:
Gareth Jones
2024-04-08 15:15:05 +03:00
committed by GitHub
parent 9e1dbd2f33
commit f99155c325
17 changed files with 177 additions and 71 deletions

7
.gitignore vendored
View File

@@ -3,7 +3,12 @@
/Code/JavaWrappers/gmwrapper/doc/*
/Code/JavaWrappers/gmwrapper/build/*
/Code/JavaWrappers/gmwrapper/build-test/*
/Code/JavaWrappers/csharp_wrapper/swig_csharp
/Code/JavaWrappers/csharp_wrapper/swig_csharp/*.cs
/Code/JavaWrappers/csharp_wrapper/swig_csharp/*.cxx
/Code/JavaWrappers/csharp_wrapper/swig_csharp/bin
/Code/JavaWrappers/csharp_wrapper/swig_csharp/obj
/Code/JavaWrappers/csharp_wrapper/RdkitTests/bin
/Code/JavaWrappers/csharp_wrapper/RdkitTests/obj
/Data/Fonts/ComicNeue-*
/Data/Fonts/OFL.txt
/vcpkg/*

View File

@@ -40,6 +40,7 @@ option(RDK_BUILD_SLN_SUPPORT "include support for the SLN format" ON )
option(RDK_TEST_MULTITHREADED "run some tests of multithreading" ON )
option(RDK_BUILD_SWIG_JAVA_WRAPPER "build the SWIG JAVA wrappers (does nothing if RDK_BUILD_SWIG_WRAPPERS is not set)" ON )
option(RDK_BUILD_SWIG_CSHARP_WRAPPER "build the experimental SWIG C# wrappers (does nothing if RDK_BUILD_SWIG_WRAPPERS is not set)" OFF )
option(RDK_BUILD_DOTNET_CSHARP_TESTS "build the DotNet Core tests for C# wrappers (does nothing if RDK_BUILD_SWIG_CSHARP_WRAPPER is not set)" OFF )
option(RDK_SWIG_STATIC "statically link rdkit libraries into the SWIG wrappers" ON )
option(RDK_TEST_MMFF_COMPLIANCE "run MMFF compliance tests (requires tar/gzip)" ON )
option(RDK_BUILD_CPP_TESTS "build the c++ tests (disabing can speed up builds" ON)

View File

@@ -1,17 +1,6 @@
project (GraphMolCSharp)
include_directories( ${RDKit_ExternalDir} )
# find the mcs executables on non-windows systems:
if(NOT MSVC)
find_program(GMCS_EXE mcs)
if (NOT GMCS_EXE)
MESSAGE ("mcs (executable) is not found. Please add it to PATH and rerun cmake.")
MESSAGE(FATAL_ERROR "Cannot find required executable mcs")
endif (NOT GMCS_EXE)
endif(NOT MSVC)
SET_SOURCE_FILES_PROPERTIES(GraphMolCSharp.i PROPERTIES CPLUSPLUS ON )
# Setup a few variables for environment-specific things
@@ -92,22 +81,32 @@ SWIG_LINK_LIBRARIES(RDKFuncs ${RDKit_Wrapper_Libs}
INSTALL(TARGETS RDKFuncs
DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} )
if (RDK_BUILD_DOTNET_CSHARP_TESTS)
if(NOT MSVC)
# code adapted from the wrapper code for
# GDCM: http://gdcm.svn.sf.net/viewvc/gdcm/trunk/Wrapping/Java/CMakeLists.txt?view=markup
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/RDKit2DotNet.dll
find_program(DOTNET_EXE dotnet)
if (NOT DOTNET_EXE)
MESSAGE("dotnet (executable) is not found. Pleae add it to PATH and rerun cmake.")
MESSAGE(FATAL_ERROR "Cannot find required executable dotnet")
endif (NOT DOTNET_EXE)
COMMAND ${CMAKE_COMMAND} -E make_directory swig_csharp
ADD_CUSTOM_COMMAND(
OUTPUT RDKitDotNetLib SYMBOLIC
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:RDKFuncs> ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${DOTNET_EXE} build RDKitDotNetCore.sln
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS RDKFuncs
)
ADD_CUSTOM_TARGET(RDKitDotNet ALL
DEPENDS RDKFuncs RDKitDotNetLib
COMMENT "Building RDKit DotNet project"
)
ADD_TEST(
NAME CSharpTests
COMMAND ${DOTNET_EXE} test RDKitDotNetCore.sln "-l:console$<SEMICOLON>verbosity=normal"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
## 1. run this custom command only after swig has been run.
COMMAND ${GMCS_EXE} -platform:${PLATFORM} -out:RDKit2DotNet.dll -t:library "swig_csharp/*.cs"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS "${swig_generated_file_fullname}"
)
ADD_CUSTOM_TARGET(RDKFuncsDLL ALL
DEPENDS RDKFuncs ${CMAKE_CURRENT_SOURCE_DIR}/RDKit2DotNet.dll
COMMENT "building mono dll"
)
endif(NOT MSVC)
endif()

View File

@@ -1,30 +0,0 @@
// Linux:
// compile with
// mcs -platform:x64 -r:../RDKit2DotNet.dll -out:MolToFromByteArray.exe MolToFromByteArray.cs
// and run with
// LD_LIBRARY_PATH=..:$RDBASE/lib:$LD_LIBRARY_PATH MONO_PATH=.. mono MolToFromByteArray.exe
using System.IO;
using System.Diagnostics;
using GraphMolWrap;
public class MolToFromByteArrayTest
{
static void Main(string[] args)
{
string smi = "CN(C)c1ccc2c(=O)cc[nH]c2c1";
string pklFileName = "quinolone.pkl";
{
ROMol mol = RWMol.MolFromSmiles(smi);
byte[] pkl = mol.ToByteArray();
File.WriteAllBytes(pklFileName, pkl);
mol.Dispose();
}
{
byte[] pkl = File.ReadAllBytes(pklFileName);
ROMol mol = ROMol.FromByteArray(pkl);
Debug.Assert(mol.MolToSmiles() == smi);
mol.Dispose();
}
}
}

View File

@@ -0,0 +1,28 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RDKitDotNetCoreWrapper", "swig_csharp\RDKitDotNetCoreWrapper.csproj", "{B97DDA0A-D8BF-4653-926B-F13DFC27FA7C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RDKitCSharpTest", "RdkitTests\RDKitCSharpTest.csproj", "{65A680C7-921C-47CF-9737-BF8726396B92}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B97DDA0A-D8BF-4653-926B-F13DFC27FA7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B97DDA0A-D8BF-4653-926B-F13DFC27FA7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B97DDA0A-D8BF-4653-926B-F13DFC27FA7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B97DDA0A-D8BF-4653-926B-F13DFC27FA7C}.Release|Any CPU.Build.0 = Release|Any CPU
{65A680C7-921C-47CF-9737-BF8726396B92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65A680C7-921C-47CF-9737-BF8726396B92}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65A680C7-921C-47CF-9737-BF8726396B92}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65A680C7-921C-47CF-9737-BF8726396B92}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,36 @@
// Linux:
// compile with
// mcs -platform:x64 -r:../RDKit2DotNet.dll -out:MolToFromByteArray.exe MolToFromByteArray.cs
// and run with
// LD_LIBRARY_PATH=..:$RDBASE/lib:$LD_LIBRARY_PATH MONO_PATH=.. mono MolToFromByteArray.exe
using System.IO;
using System.Diagnostics;
using GraphMolWrap;
using Xunit;
namespace RdkitTests
{
public class MolToFromByteArrayTest
{
[Fact]
public void TestMolToFromByteArray()
{
string smi = "CN(C)c1ccc2c(=O)cc[nH]c2c1";
string pklFileName = "quinolone.pkl";
{
ROMol mol = RWMol.MolFromSmiles(smi);
byte[] pkl = mol.ToByteArray();
File.WriteAllBytes(pklFileName, pkl);
mol.Dispose();
}
{
byte[] pkl = File.ReadAllBytes(pklFileName);
ROMol mol = ROMol.FromByteArray(pkl);
Assert.Equal(smi, mol.MolToSmiles());
mol.Dispose();
File.Delete(pklFileName);
}
}
}
}

View File

@@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\swig_csharp\RDKitDotNetCoreWrapper.csproj" />
</ItemGroup>
<Target Name="CopyCustomContent1" AfterTargets="AfterBuild" Condition=" '$(OS)' == 'Windows_NT' ">
<Copy SourceFiles="../RDKFuncs.dll" DestinationFolder="$(OutDir)" />
</Target>
<Target Name="CopyCustomContent2" AfterTargets="CopyCustomContent1" Condition=" '$(OS)' != 'Windows_NT' ">
<Copy SourceFiles="../RDKFuncs.so" DestinationFolder="$(OutDir)" />
</Target>
<ItemGroup>
<None Update="xunit.runner.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -7,7 +7,8 @@ namespace RdkitTests
{
public class ToMolMemoryTest
{
private static readonly long hundredMB = 1024 * 1024 * 100;
private static readonly long OneHundredMB = 1024 * 1024 * 100;
private static readonly long TwoHundredMB = OneHundredMB * 2;
private static void gc()
{
@@ -24,22 +25,28 @@ namespace RdkitTests
"CC(C)C[C@H](NC(=O)[C@H](CC(=O)O)NC(=O)[C@H](Cc1ccccc1)NC(=O)[C@H](CO)NC(=O)[C@@H]1CCCN1C(=O)[C@H](CCC(N)=O)NC(=O)[C@@H](N)CS)C(=O)N[C@@H](CCC(N)=O)C(=O)N[C@@H](CS)C(=O)O";
var before = Process.GetCurrentProcess().VirtualMemorySize64;
var privateBefore = Process.GetCurrentProcess().PrivateMemorySize64;
long after;
for (int i = 0; i < 10000; ++i)
long privateAfter;
for (int i = 0; i < 500; ++i)
{
using RWMol mol = RDKFuncs.SmilesToMol(smi);
mol?.Dispose();
if (i % 1000 == 0)
RWMol mol = RDKFuncs.SmilesToMol(smi);
RWMol mol2 = RWMol.MolFromSmiles(smi);
if (i % 50 == 0)
{
gc();
after = Process.GetCurrentProcess().VirtualMemorySize64;
Assert.True(after - before < hundredMB);
Assert.True(after - before < TwoHundredMB);
privateAfter = Process.GetCurrentProcess().PrivateMemorySize64;
Assert.True(privateAfter - privateBefore < OneHundredMB);
}
}
gc();
after = Process.GetCurrentProcess().VirtualMemorySize64;
Assert.True(after - before < hundredMB);
Assert.True(after - before < TwoHundredMB);
privateAfter = Process.GetCurrentProcess().PrivateMemorySize64;
Assert.True(privateAfter - privateBefore < OneHundredMB);
}
[Fact]
@@ -65,21 +72,20 @@ M END
";
var before = Process.GetCurrentProcess().VirtualMemorySize64;
long after;
for (int i = 0; i < 10000; ++i)
for (int i = 0; i < 500; ++i)
{
using RWMol mol = RDKFuncs.MolBlockToMol(block);
mol?.Dispose();
if (i % 1000 == 0)
RWMol mol = RDKFuncs.MolBlockToMol(block);
if (i % 50 == 0)
{
gc();
after = Process.GetCurrentProcess().VirtualMemorySize64;
Assert.True(after - before < hundredMB);
Assert.True(after - before < TwoHundredMB);
}
}
gc();
after = System.Diagnostics.Process.GetCurrentProcess().PeakVirtualMemorySize64;
Assert.True(after - before < hundredMB);
Assert.True(after - before < TwoHundredMB);
}
}
}

View File

@@ -0,0 +1 @@
global using Xunit;

View File

@@ -0,0 +1,4 @@
{
"parallelizeTestCollections": false,
"maxParallelThreads": -1
}

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<Target Name="CopyCustomContent1" AfterTargets="AfterBuild" Condition=" '$(OS)' == 'Windows_NT' ">
<Copy SourceFiles="../RDKFuncs.dll" DestinationFolder="$(OutDir)" />
</Target>
<Target Name="CopyCustomContent2" AfterTargets="CopyCustomContent1" Condition=" '$(OS)' != 'Windows_NT' ">
<Copy SourceFiles="../RDKFuncs.so" DestinationFolder="$(OutDir)" />
</Target>
</Project>