Let's assume I want to create a c# wrapper for a specific function in a big library that has lots of depencencies. For the sake of argument, let's say I want to create a C# wrapper for convex_hull_3
function in CGAL library. As the name suggests, this function creates a convex hull for a bunch of points in 3D space. As you may already know, CGAL depends on some other libraries such as Boost
MPFR
and GMP
and a few others (it links dynamically to these libraries).
How would you go about creating such wrapper? What is the correct way of wrapping the function so that the final wrapper minimizes the number of other libraries exposed/wrapped?
One solution that I can think of:
Create a gateway project in C++. This gateway project has as dependencies CGAL's DLLs and also everything else that CGAL needs to work (boost DLL's, MPFR's DLLs and so on). This project has 2 files: a header and a CPP file. These files declare a function (say) createConvexHull
that wraps the original convex_hull_3
. Additionally, createConvexHull
function is marked as __declspec(dllexport)
.
The point about this function is that it changes the low-level representation of the data that CGAL works on. For instance, instead of having to declare the point cloud data as one of CGAL's internal data types, we could just pass an array of doubles representing 3D vectors of data. As a result, this gateway project obviates the need of wrapping CGAL's internal data structures and exposes a minimal amount of additional dependencies.
Build the gateway project into a DLL file (for instance CGAL-gateway.dll).
Create a project in C#. Let's refer to this project as the wrapper project because all P/Invoke operations will be performed inside this project. Add CGAL-gateway.dll as a reference to this project along with Boost DLL's, MPFR DLL's and GMP DLL's. Write all the P/Invoke stuff in this project.
Build the wrapper project and add it as a reference to whatever other C# project that you'd like to have the functionality of creating convex hulls.
Potential Problems:
First, I have no idea if this is the standard way of doing things like this. I have created only 2 wrappers in my life for personal/education purposes so whatever I know was pretty much learned by trial and error and seeing other people's code.
A problem I see with this approach is that there will be one extra C++ project (I'm referring to the gateway project) which is relatively useless and only serves as an abstraction layer. The other problem with this approach is that it creates a DLL hell. To hand my C# wrapper to somebody else, I would have to give them Boost, CGAL, MPFR and GMP DLLs as well. There maybe a huge number of DLLs needed to run my wrapper. Honestly, I don't even know if there is a way around it.
I was thinking about static linking instead of dynamic linking but there are two considerations here. First, I've never tried static linking before. Second, I don't think you can to static linking to GPL v3 libraries. Therefore, if I decide to release my wrapper under an open source license in the future, I will have to stick to GPL v3 license (which is not what I want).
I don't know if I've been able to word my question in an understandable manner. If the question needs any clarifications, please let me know.
There are several ways of creating a wrapper to a native library for C#. Here are a few of them:
1- Creating a mixed-mode assembly where you wrap the functionality that you need from your native libraries in a C++/CLR class that can be used directly in C#. This approach has the drawback that your C# project will now be CPU-architecture-specific (disclaimer: this link points to something that I wrote based on a few posts in SO plus my own experience). In your C++/CLR wrapper you will have the "opportunity" to convert the native C++ types (like std::string) into something that C# can understand (like System.String).
2- Creating a COM library in C++ that can also be used directly in C#. If your are ok with registering the library globally in the system then your C# app does not need to be CPU-architecture-specific. Also in this case the COM-Interop engine from .net framework will perform most of the type marshaling for you.
3- Creating a regular dynamic library with exported functions that summarizes the functionality that you need and that can be called from C# using the DllImport attribute, or the LoadLibrary/FreeLibrary/GetProcAddress functions from the Windows API. I believe this is the approach you described in your question, and you added one additional layer of a C# wrapper that I think it would be better to give away as sample code/documentation.
None of the approaches is right or wrong, an in each of them you can link the rest of the dependencies dynamically or statically.
By the way, if your dependencies are licensed as GPL-v3, I think that there is no way for you to distribute these dependencies while complying with the GPL-v3 license.