【问题标题】:What determines binary compatibility of shared libraries on Linux?什么决定了 Linux 上共享库的二进制兼容性?
【发布时间】:2019-04-16 10:36:58
【问题描述】:

我正在 Linux 上构建一个共享库,它充当某些软件的“插件”(具体来说,它扩展了 Mathematica)。

我发现如果我在 Ubuntu 16.04 上构建,生成的库无法在 RHEL 7.6 上运行。但是,如果我在 RHEL 7.6 上构建,则该库可以在 RHEL 和 Ubuntu 上运行。

“不起作用”是指 Mathematica 拒绝加载它,但它只给出一个通用且无用的“加载失败”错误消息。

我已经消除了许多可能破坏兼容性的因素,但我找不到更多了。 这个问题是关于除了我在下面列出的内容之外还有什么可能影响兼容性的问题。

该库是用 C 和 C++ 混合编写的,但它导出了一个 C 接口。它是用-static-libstdc++-static-libgcc 构建的。如果我在.so 文件上使用ldd,它列出的唯一依赖项是:

linux-vdso.so.1 =>  (0x00007ffc757b9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa286e62000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa287854000)

不兼容的一个潜在来源是glibc 版本。我使用nm -gC 查看了库中的符号,我在 Ubuntu 上构建时看到的最高 GLIBC 版本参考是 2.14。 RHEL 7.6 具有 glibc 2.17,即比 2.14 更新。因此我不认为不兼容是由于 glibc 造成的。

还有什么会导致在 Ubuntu 16.04 上编译的共享对象无法在 RHEL 7.6 上加载?


更新:我设法哄 Mathematica 给出一个更具描述性的错误(这是一个没有很好记录的功能),所以我有一个具体的错误消息。 @Ctx 的设置LD_DEBUG=all 的建议也可以看到同样的情况。

错误是:

IGraphM.so: undefined symbol: _ZTVNSt7__cxx1115basic_stringbufIcSt11char_traitsIcESaIcEEE

IGraphM.so 是我的图书馆。)

除非我弄错了,否则这个函数似乎是 libstdc++ 的一部分。如果我指定-static-libstdc++并验证ldd没有列出libstdc++,为什么会出现这个错误?


更新 2:

根据 SergeyA 和 this QA 的建议,我在定义 _GLIBCXX_USE_CXX11_ABI=0 后编译。 这确实解决了不兼容问题。

但我还是不明白为什么。错误消息抱怨缺少符号。这个符号通常从哪里加载?我的印象是,如果我使用-static-libstdc++,那么它应该包含在我的库中。这似乎是错误的。

虽然我似乎对这种特定情况的不兼容性有一个实用的解决方案,但我希望能得到一些解释,以便将来我可以自己解决类似的问题。

【问题讨论】:

  • glibc 应该没问题。我假设两个系统都是同一个平台(比如 x86-64)。也许 Mathematica 是一个 32 位应用程序,但您提供的是 64 位共享对象?您是否尝试过创建一个没有代码的空“虚拟”插件,并且只使用 C 来查看它是否有效?结果可能会排除一些可能性。
  • 同时查看 Mathematica 是否写入了可能包含更多信息的日志文件。如果它没有在某处记录有用的东西,我会感到惊讶。
  • 您可以尝试在控制台中export LD_DEBUG=all 启动mathematica。也许它会产生一些可以帮助您的调试输出。
  • @TypeIA 是的,相同的架构 (x86-64) 和相同版本的 Mathematica,但现在你问了,我开始怀疑两台机器的 CPU 是否支持相同的指令集(例如,当在一个系统上编译,gcc 发出一条只有较新的 CPU 才有的指令)。但是,这会导致崩溃,而不是非致命故障,不是吗?
  • 你缺少符号 demangles 到 vtable for std::__cxx11::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> > stackoverflow.com/questions/33394934/… 可能有一些线索。

标签: c++ c linux shared-libraries abi


【解决方案1】:

我无法解释为什么您的 .so 库没有静态链接所有使用的符号(而是将它们保留为未定义),但我可以就如何解决手头的问题提供实用建议。

您可以停止将libstdc++ 静态链接到您的插件中,而是使用可用于主机系统的那个。由于构建平台和目标平台之间的 ABI 不兼容,这对您不起作用。您可以通过指定宏 _GLIBCXX_USE_CXX11_ABI=0 来降级插件使用的 ABI。

【讨论】:

    猜你喜欢
    • 2016-08-08
    • 2010-10-20
    • 2013-12-09
    • 2013-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    相关资源
    最近更新 更多