是什么决定了 Linux 上共享库的二进制兼容性?
What determines binary compatibility of shared libraries on Linux?
我正在 Linux 上构建一个共享库,作为某些软件的 "plugin"(具体来说,它扩展了 Mathematica)。
我发现如果我在 Ubuntu 16.04 上构建,生成的库不能在 RHEL 7.6 上运行。但是,如果我在 RHEL 7.6 上构建,该库可以在 RHEL 和 Ubuntu.
上运行
"does not work",我的意思是 Mathematica 拒绝加载它,但它只给出一个通用且无用的 "failed to load" 错误消息。
我已经排除了一些可能破坏兼容性的因素,但我再也找不到了。 这个问题是关于除了我在下面列出的之外还有什么可能会影响兼容性。
该库是用 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++,为什么会出现此错误?
更新二:
根据 SergeyA 和 的建议,我在定义 _GLIBCXX_USE_CXX11_ABI=0
后编译。 这确实解决了不兼容问题。
但我还是不明白为什么。错误消息抱怨缺少符号。这个符号通常从哪里加载?我的印象是,如果我使用 -static-libstdc++
,那么它应该包含在我的库中。这似乎是错误的。
虽然我似乎对这种特定情况的不兼容性有一个切实可行的解决方案,但我希望得到一些解释,以便将来我可以自己解决类似的问题。
我无法解释为什么您的 .so 库没有 link 静态地使用所有符号(而是将它们保留为未定义),但我可以提供有关如何解决问题的实用建议手.
您可以停止 linking libstdc++
静态地进入您的插件,而是使用可用于主机系统的插件。这对您不起作用,因为构建平台和目标平台之间的 ABI 不兼容。您可以通过指定宏 _GLIBCXX_USE_CXX11_ABI=0
.
来降级用于您的插件的 ABI
我正在 Linux 上构建一个共享库,作为某些软件的 "plugin"(具体来说,它扩展了 Mathematica)。
我发现如果我在 Ubuntu 16.04 上构建,生成的库不能在 RHEL 7.6 上运行。但是,如果我在 RHEL 7.6 上构建,该库可以在 RHEL 和 Ubuntu.
上运行"does not work",我的意思是 Mathematica 拒绝加载它,但它只给出一个通用且无用的 "failed to load" 错误消息。
我已经排除了一些可能破坏兼容性的因素,但我再也找不到了。 这个问题是关于除了我在下面列出的之外还有什么可能会影响兼容性。
该库是用 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++,为什么会出现此错误?
更新二:
根据 SergeyA 和 _GLIBCXX_USE_CXX11_ABI=0
后编译。 这确实解决了不兼容问题。
但我还是不明白为什么。错误消息抱怨缺少符号。这个符号通常从哪里加载?我的印象是,如果我使用 -static-libstdc++
,那么它应该包含在我的库中。这似乎是错误的。
虽然我似乎对这种特定情况的不兼容性有一个切实可行的解决方案,但我希望得到一些解释,以便将来我可以自己解决类似的问题。
我无法解释为什么您的 .so 库没有 link 静态地使用所有符号(而是将它们保留为未定义),但我可以提供有关如何解决问题的实用建议手.
您可以停止 linking libstdc++
静态地进入您的插件,而是使用可用于主机系统的插件。这对您不起作用,因为构建平台和目标平台之间的 ABI 不兼容。您可以通过指定宏 _GLIBCXX_USE_CXX11_ABI=0
.