【问题标题】:How to manage compilation of C++ header-only libraries across shared objects如何管理跨共享对象的 C++ 仅标头库的编译
【发布时间】:2019-04-03 14:44:53
【问题描述】:

我正在开发一个大型软件包,其中包含许多编译为共享对象的软件包。出于性能原因,我想用向量指令编译 Eigen 3(仅头文件库),但是模板化的方法正在到处编译。如何确保将 Eigen 函数编译到特定的目标文件中?

该软件包含约 2000 个单独的软件包。为了让开发以合理的速度进行,编译程序的推荐方法是稀疏地检查一些包并编译它们,然后可以使用预编译的(由某些 CI 系统)共享库执行程序。

问题是我的部分职责是优化程序的 CPU 时间。为此,我想用-march 标志编译我正在处理的包(我们称之为A.so),以便Eigen 可以利用现代SIMD 处理器扩展。

不幸的是,因为 Eigen 是一个只有头文件的库,所以 Eigen 函数被编译成许多不同的共享对象。例如,A.so 中调用的 CPU 最密集的方法之一是在B.so 中编译的矩阵乘法内核。许多其他 Eigen 函数被编译成 C.soD.so 等。由于这些对象是为较旧的、更广泛实现的指令集扩展编译的,因此它们不使用 AVX、AVX2 等编译。

当然,一种可能的解决方案是将包BCD 等包含在我自己的稀疏编译中,但这抵消了仅编译项目一部分的优势。此外,如果我真的想在包A 的代码中矢量化所有线性代数运算,它会让我包含越来越多的包。

我正在寻找的是一种将所有打包 A 使用的 Eigen 函数编译成 A.so 的方法,就好像 Eigen 函数是使用 static 关键字定义的一样。这可能吗?我可以利用编译器/链接器中的某种机制来实现这一点吗?

【问题讨论】:

    标签: c++ linker shared-libraries eigen


    【解决方案1】:

    一个明显的解决方案是隐藏这些符号。发生这种情况(如果我正确理解问题的话)是因为这些函数被导出并且可以被其他后续加载的库使用。

    当您构建您的库并链接到其他库时,链接器会重用它所能做的。旧包也是如此。我希望您自己的构建不需要这些库?

    所以有两个选择:

    • 在其他库之前强制加载A(但如果您需要其他库,我认为这是不可行的),
    • 告诉链接器这些函数不应该被其他库看到(默认为visibility=hidden)。

    我看到编译错误的第 3 方库发生了类似的情况。它是在调试模式下构建的,在产品中提供,突然间我们的一个库经历了减速。映射文件确定了罪魁祸首调试函数的来源,因为它默认导出所有符号。

    【讨论】:

    • 如果在 Linux 上,也可以考虑使用 visibility function attribute;见this
    • @Basile 确实如此,这就是我的想法visibility,谢谢你的链接。
    • 感谢使用符号隐藏的建议。如果我理解正确,我将不得不在 all 对象上配置隐藏特征符号,对吗?有没有办法防止链接器在其他对象中重用 Eigen 符号而不更改这些对象的源代码?
    • 我不这么认为,但也许有人会用灵丹妙药来回答!
    【解决方案2】:

    在不修改代码的情况下更改可见性的另一种方法是在链接阶段使用版本脚本过滤符号 -> https://sourceware.org/binutils/docs/ld/VERSION.html。你需要类似的东西 { global: *; local: extern "C++" { Eigen::*; *Eigen::internal::*; }; };

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-26
      • 1970-01-01
      • 2019-12-02
      • 2018-05-30
      • 2018-07-05
      • 2020-02-07
      • 2017-03-24
      相关资源
      最近更新 更多