那篇博文很不准确。
据我所知,GCC 的每个主要版本都引入了 C++ ABI 更改(即具有不同的第一或第二版本号组件的版本)。
不对。自 GCC 3.4 以来引入的唯一 C++ ABI 更改是向后兼容的,这意味着 C++ ABI 已经稳定了近九年。
更糟糕的是,大多数主要的 Linux 发行版都使用 GCC 快照和/或修补它们的 GCC 版本,这使得在分发二进制文件时几乎不可能确切地知道您可能正在处理的 GCC 版本。
发行版的 GCC 补丁版本之间的差异很小,并且 ABI 没有变化,例如 Fedora 的 4.6.3 20120306(Red Hat 4.6.3-2)与上游 FSF 4.6.x 版本的 ABI 兼容,几乎可以肯定与任何 4.6 兼容。 x 来自任何其他发行版。
在 GNU/Linux GCC 的运行时库使用 ELF 符号版本控制,因此很容易检查对象和库所需的符号版本,如果您有一个libstdc++.so
提供这些符号的符号,它将起作用,它是否是一个稍微不同的补丁版本都没关系从您的发行版的另一个版本。
但是如果要工作,则不能动态链接 C++ 代码(或任何使用 C++ 运行时支持的代码)。
这也不是真的。
也就是说,静态链接libstdc++.a
是您的一种选择。
如果您动态加载库(使用 ),它可能不起作用的原因dlopen
是,当您(静态)链接它时,您的应用程序可能不需要它所依赖的 libstdc++ 符号,因此这些符号不会出现在您的可执行文件中。这可以通过将共享库动态链接到来解决libstdc++.so
(如果它依赖于它,这无论如何都是正确的做法。)ELF符号插入意味着您的可执行文件中存在的符号将被共享库使用,但其他符号不会存在于您的可执行文件中的内容将在libstdc++.so
它链接到的任何地方找到。如果您的应用程序不使用dlopen
,则无需关心。
另一种选择(也是我更喜欢的选择)是将更新libstdc++.so
的应用程序与您的应用程序一起部署并确保在默认系统之前找到它libstdc++.so
,这可以通过强制动态链接器查找正确的位置来完成,或者$LD_LIBRARY_PATH
在运行时使用环境变量-时间,或者通过RPATH
在链接时在可执行文件中设置一个。我更喜欢使用RPATH
它,因为它不依赖于为应用程序正确设置的环境。如果您将应用程序与'-Wl,-rpath,$ORIGIN'
(注意单引号以防止外壳尝试扩展)链接,$ORIGIN
那么可执行文件将有一个告诉动态链接器在与可执行文件本身相同的目录中查找共享库。如果你把较新的RPATH
$ORIGIN
libstdc++.so
在与可执行文件相同的目录中,它将在运行时找到,问题已解决。(另一种选择是将可执行文件/some/path/bin/
和较新的 libstdc++.so 放入/some/path/lib/
并链接到'-Wl,-rpath,$ORIGIN/../lib'
或相对于可执行文件的任何其他固定位置,并将 RPATH 设置为相对于$ORIGIN
)