CppSharp
CppSharp copied to clipboard
Create a C# cross platform binding file
Is there a way to generate a C# cross platform binding file ? I want to create a GLFW C# binding, so it use libglfw.so.3.3 on linux and glfw3.dll on windows.
MonoGame check the system at runtime and take the right library. Can I do something similarly with CppSharp ?
Hmm I am not sure if this is supported out of the box right now.
Can you send an example of how it should work? How does the code for the selection at runtime look like?
It could be possible for C-library, but not for C++ library.
[SuppressUnmanagedCodeSecurity, DllImport("MOAB", EntryPoint = "imoab_initialize", CallingConvention = __CallingConvention.Cdecl)]
internal static extern int Initialize(int argc, sbyte** argv);
The key is DllImport(), dotnet core 5 support sofile without suffix like *.dll or *.so, just "MOAB" will match "libMOAB.so" and "MOAB.dll". For C-library, the exported name is standardized, so should be portable.
but DllImport()'s EntryPoint parameter is a C++ decorated/mangled name, it is not possible to be cross-platform. so the generated cs file will not portable between Windows and Linux.
So I have 2 projects for Windows and Linux respectively.
generated binding for Windows generated binding for Linux https://bitbucket.org/qingfengxia/moabsharp/src/dev/MOABSharp.Linux/MOABSharp.Linux.cs
The problem is that DllImport cannot be set at runtime. It only accept const value.
MonoGame does something like this :
private class Windows
{
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr LoadLibraryW(string lpszLib);
}
private class Linux
{
[DllImport("libdl.so.2")]
public static extern IntPtr dlopen(string path, int flags);
[DllImport("libdl.so.2")]
public static extern IntPtr dlsym(IntPtr handle, string symbol);
}
public static IntPtr LoadLibrary(string libName)
{
string assemblyLocation = Path.GetDirectoryName(typeof(FuncLoader).Assembly.Location) ?? "./";
string libPath = Path.Combine(assemblyLocation, "runtimes", libName);
if (CurrentPlatform.OS == OS.Windows)
return Windows.LoadLibraryW(libPath);
return Linux.dlopen(libPath, RTLD_LAZY);
}
private static IntPtr NativeLibrary = GetNativeLibrary();
private static IntPtr GetNativeLibrary()
{
if (CurrentPlatform.OS == OS.Windows)
return FuncLoader.LoadLibrary("glfw3.dll");
return FuncLoader.LoadLibrary("libglfw.so.3.3");
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int d_glfwInit();
private static d_glfwInit _glfwInit = FuncLoader.LoadFunction<d_glfwInit>(NativeLibrary, "glfwInit");
public static int glfwInit() => _glfwInit();
I don't know if CppSharp can do the same.
For the time being it can't. The approach we've supported so far is at the time of deployment, that is, referencing a library with the same name and then deploying the specific one for the platform. That is, you generate one library for win and one for Linux, name each, for example, GLFWSharp.dll, use one for development and when you finally deploy, you choose the correct one for your target system.
I believe it is possible to target on dotnet core 5 for the C ABI library
If anyone is interested, I created a C# binding for both OpenGL and GLFW a long time ago. It has been used in some projects already. You can locate it at https://github.com/thebonejarmer/arqan.git. The approach I use is using preprocessor directives to determine the correct dll file at compile time and simply serving a nuget package per operating system.
I don't think you should try to bypass the problem of having to compile for two operating systems and therefore having to provide a version per operating systems. This could introduce more issues than you are solving. The fact is and remains that operating systems are different and at some point you need to stop providing cross-platform solutions and create a bridge between the native solution and the cross-platform one.Shared libraries are quite delicate and if you call them wrongly you'd be dealing with lots of AccessViolationExceptions or worse, none and just a plain crash with nothing but an hex code to work with. It only makes it unnecessarily more complex and most folks don't mind having to compile the same version per os anyway.