为具有大量依赖关系的库创建包装器的正确方法

时间:2015-11-10 21:31:53

标签: c# c++ dll wrapper

假设我想为具有大量依赖性的大型库中的特定函数创建一个c#包装器。为了论证,让我们说我想在CGAL库中为convex_hull_3函数创建一个C#包装器。顾名思义,此函数为3D空间中的一堆点创建凸包。您可能已经知道,CGAL依赖于其他一些库,例如Boost MPFRGMP以及其他一些库(它会动态链接到这些库)。
你会如何创建这样的包装?包装函数的正确方法是什么,以便最终的包装器最小化暴露/包装的其他库的数量?

我能想到的一个解决方案:

  1. 在C ++中创建网关项目。这个网关项目具有依赖CGAL的DLL以及CGAL需要工作的所有其他东西(提升DLL,MPFR&#39s等等)。该项目有2个文件:标题和CPP文件。这些文件声明了一个包含原始createConvexHull的函数(例如)convex_hull_3。此外,createConvexHull功能标记为__declspec(dllexport) 关于这个函数的要点是它改变了CGAL工作的数据的低级表示。例如,我们可以只传递表示3D数据向量的双精度数组,而不必将点云数据声明为CGAL的内部数据类型之一。因此,该网关项目不需要包装CGAL的内部数据结构,并且暴露了最少量的附加依赖项。

  2. 网关项目构建到DLL文件中(例如 CGAL-gateway.dll )。

  3. 使用C#创建项目。让我们将此项目称为包装项目,因为所有P / Invoke操作都将在此项目中执行。添加 CGAL-gateway.dll 作为对此项目的引用以及 Boost DLL&#39; s, MPFR DLL&#39;和< em> GMP DLL&#39; s。在这个项目中写下所有的P / Invoke东西。

  4. 构建包装器项目,并将其添加为您希望具有创建凸包功能的其他C#项目的参考。

  5. 潜在问题:

    首先,我不知道这是否是这样做的标准方式。为了个人/教育的目的,我在生活中只创造了两个包装纸,所以我所知道的只是通过反复试验和看到其他人的代码来学习。 我用这种方法看到的一个问题是,将会有一个额外的C ++项目(我指的是 gateway 项目),它相对无用,只能作为抽象层。这种方法的另一个问题是它会创建一个DLL地狱。要将我的C#包装器交给其他人,我必须给他们 Boost CGAL MPFR GMP DLL也是。运行我的包装器可能需要大量的DLL。老实说,我甚至不知道是否有办法绕过它。

    我在考虑静态链接而不是动态链接,但这里有两个注意事项。首先,我以前从未尝试过静态链接。其次,我不认为你可以静态链接到GPL v3库。因此,如果我决定将来在开源许可下发布我的包装器,我将不得不遵守GPL v3许可证(这不是我想要的)。

    我不知道我是否能够以可理解的方式提出问题。如果问题需要任何澄清,请告诉我。

1 个答案:

答案 0 :(得分:1)

有几种方法可以为C#创建本机库的包装器。以下是其中一些:

1-创建一个混合模式程序集,您可以在C ++ / CLR类中包装本机库所需的功能,该类可以直接在C#中使用。这种方法的缺点是your C# project will now be CPU-architecture-specific(免责声明:这个链接指向我根据SO中的一些帖子加上我自己的经验写的东西)。在C ++ / CLR包装器中,您将有机会将本机C ++类型(如std :: string)转换为C#可以理解的内容(如System.String)。

2-用C ++创建一个也可以直接在C#中使用的COM库。如果您可以在系统中全局注册库,那么您的C#应用​​程序不需要特定于CPU架构。同样在这种情况下,来自.net框架的COM-Interop引擎将为您执行大部分类型编组。

3-使用导出的函数创建常规动态库,该函数总结了您需要的功能,可以使用DllImport属性从C#调用,或者使用Windows API中的LoadLibrary / FreeLibrary / GetProcAddress函数调用。我相信这是你在问题中描述的方法,并且你添加了一个额外的C#包装层,我认为最好让它作为示例代码/文档。

这些方法都没有对错,在每个方法中,您可以动态或静态地链接其余的依赖项。

顺便说一下,如果您的依赖项被许可为GPL-v3,我认为there is no way for you to distribute these dependencies without complying with the GPL-v3 license