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

Correct way of creating wrappers for libraries with lots of dependencies

假设我想为具有大量依赖项的大型库中的特定函数创建一个 c# 包装器。为了争论,假设我想为 CGAL 库中的 convex_hull_3 函数创建一个 C# 包装器。顾名思义,这个函数为 3D 中的一堆点创建了一个凸包 space。您可能已经知道,CGAL 依赖于其他一些库,例如 Boost MPFRGMP 以及其他一些库(它动态链接到这些库)。
您将如何创建这样的包装器?包装函数的正确方法是什么,以便最终包装器最大限度地减少其他库的数量exposed/wrapped?

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

  1. 在 C++ 中创建一个 网关 项目。该网关项目具有 CGAL 的 DLL 以及 CGAL 需要工作的所有其他内容(增强 DLL、MPFR 的 DLL 等)作为依赖项。该项目有 2 个文件:一个头文件和一个 CPP 文件。这些文件声明了一个函数(比如)createConvexHull,它包装了原始的 convex_hull_3。此外,createConvexHull 函数被标记为 __declspec(dllexport).
    这个函数的要点是它改变了 CGAL 处理的数据的低级表示。例如,不必将点云数据声明为 CGAL 的内部数据类型之一,我们可以只传递一个表示 3D 数据向量的双精度数组。因此,这个网关项目避免了包装 CGAL 内部数据结构的需要,并暴露了最少数量的额外依赖项。

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

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

  4. 构建 wrapper 项目并将其添加为对您希望具有创建凸包功能的任何其他 C# 项目的引用。

潜在问题:

首先,我不知道这是否是执行此类操作的标准方法。为了 personal/education 的目的,我一生只创建了 2 个包装器,所以我所知道的大部分都是通过反复试验和查看其他人的代码学到的。
我看到这种方法的一个问题是会有一个额外的 C++ 项目(我指的是 gateway 项目),它相对无用,仅用作抽象层。这种方法的另一个问题是它创建了一个 DLL 地狱。要将我的 C# 包装程序交给其他人,我必须给他们 BoostCGALMPFR以及 GMP DLL。 运行 我的包装器可能需要大量的 DLL。老实说,我什至不知道是否有解决办法。

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

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

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

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

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

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

None 的方法是对还是错,在每一种方法中,您都可以 link 其余的动态或静态依赖关系。

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