在 PInvoke 中管理大量 3rdparty 依赖项以提高编译速度

Posted

技术标签:

【中文标题】在 PInvoke 中管理大量 3rdparty 依赖项以提高编译速度【英文标题】:Managing tons of 3rdparty dependencies in PInvoke for better compilation speed 【发布时间】:2016-10-28 13:08:55 【问题描述】:

情况:

我正在从事一个研究项目,由于某些限制,该项目具有 C# 用户界面(主要用于可视化),但大部分处理都是使用 PInvoke 和非托管 C++ 代码进行的。非托管代码对各种 3rdparty 库有大量依赖:Boost、PCL、OpenCV、CGAL、VTK、Eigen、FLANN、OpenMesh 等(如果你能说出它的名字,我们可能会依赖它!)。 C# 项目与 C++ 项目(从现在起我简称为“包装器”)交互。显然,包装器是使用所有 3rdparty 依赖项的地方,也是定义 PInvokes 入口点的地方。包装器被编译成 DLL 并通过构建后事件复制到 C# 项目的输出目录中。

我是该项目的唯一开发者。我的主要开发平台是带有 Visual Studio 2015 的 Windows 10,Git 是我的版本控制。我主要在 3 台不同的机器上进行开发,但有时我需要在仅安装 Visual Studio 2015 的其他机器上进行开发。

到目前为止我做了什么:

显然,管理所有这些 3rdparty 依赖项对一个人来说是一件麻烦事,而且我讨厌必须在新的开发机器上安装这些库。我所做的是,我已经将所有这些 3rdparty 库从源代码编译成静态库文件(显然只有标头文件除外)。所有源都为Debug 配置构建一次,为Release 配置构建一次。我花了一些时间将它们集成到我的包装器项目中(即定义额外的包含目录,使用大量 #pragma comment (lib, "blah.lib") 引用不同的构建,具体取决于构建配置等)。我还遵循了Microsoft's linker best practices 中的一些建议,以减少链接时间。具体来说,我使用的是增量链接器,我禁用了/LTCG/OPT

现在我的 VS 解决方案中有一个巨大的“依赖项”文件夹,大约 8GB,并且与项目分开进行版本控制(使用 Git 子模块)。包装器项目静态链接到所有这些,因此,如上所述,在构建包装器项目后只生成一个 DLL。这种方法的好处是,在任何新的开发机器上,我都克隆了主存储库,克隆了 Dependencies 子模块,然后就可以开始使用了!但是……

最糟糕的部分:

你猜对了!可怕的链接时间。即使在功能强大的计算机上,在我更改包装器项目中的一行之后,我也必须等待几分钟,直到链接器完成。当我采用上述方法时,我没有看到的是我忘记了我对快速原型设计的重视程度:在将某个特性暴露给 PInvoke 之前,对包装项目中的一些随机特性进行快速而肮脏的测试。理想情况下,我希望能够更改包装器项目中的一些小东西,快速构建、运行和测试该更改,然后继续向 PInvoke 公开该功能。

我的问题:

显然,我在这方面缺乏经验!我应该如何以不同的方式做事,特别是考虑到我上面提到的依赖关系?构建DLL而不是静态库更好吗?但是每次 C# 程序启动时,我都必须将依赖项添加到 PATH (as mentioned here)。作为一个附带问题,您如何评估我目前的方法?

【问题讨论】:

你真的需要一个可执行文件中的所有这些依赖项吗?是否可以将您的应用程序分成不同的“服务”?这样,UI 可以根据任务访问不同的可执行文件,或者如果任务相关,它们可以通过 IPC 进行通信。然后,您可以拥有多个具有较少依赖项的较小可执行文件。 @silverscania 我这样做了,但不幸的是我无法分解可执行文件......问题是,可执行文件定期与另一个组共享,他们将其用于系统的一部分...... . 向他们运送开箱即用的东西会更容易...... 那么我认为如果您的问题纯粹是链接时间问题,那么 DLL 是可行的方法。只要它们位于应用程序的同一目录或子目录中,您就不必更改 PATH。 @silverscania 非常感谢!我根据您的评论发布了答案。我现在超级开心! 【参考方案1】:

根据@silverscania 的评论,我决定只采用 DLL 路线。重建所有依赖项有点痛苦,但我现在对结果非常满意。

现在,从头开始构建整个解决方案需要 36 秒!以前大约是 4 分钟,所以我没有什么可抱怨的。此外,修改包装器项目中的单个文件并再次构建需要 3 秒,这太棒了!所有已编译的依赖项现在大约为 1 GB(静态库约为 8 GB)这一事实是一个加分项!我再高兴不过了。

一些笔记:

    在我进行大部分开发的主机上,我有一块闪迪 SSD。我注意到由于某种我无法理解的原因,与普通 HDD 相比,在该设备上构建项目方式慢。我正在调查这个问题,但没有找到原因(TRIM 已启用且驱动器处于 AHCI 模式)。 我更多地使用了标志。我注意到编译器标志/GL(整个程序优化)在链接过程中导致相当大的速度下降。我也禁用了该选项。

【讨论】:

以上是关于在 PInvoke 中管理大量 3rdparty 依赖项以提高编译速度的主要内容,如果未能解决你的问题,请参考以下文章

PowerEnumerate PInvoke 调整数组大小

PInvoke - 方法的类型签名与 PInvoke 不兼容

如何在nexus上管理jar包

如何在 C# 中 PInvoke 另一个结构内的结构数组

如何使用 ivy 和 nexus 发布 3rdparty 工件

在具有 ui/非 ui 线程差异的 WPF 中使用 PInvoke