那篇博客文章相当不准确。
据我所知,每个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发布版本和几乎肯定与任何其他发行版的4.6.x是ABI兼容的。
在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'
(请注意单引号以防止shell尝试展开
$ORIGIN
)链接您的应用程序,则可执行文件将具有
$ORIGIN
的
RPATH
,这告诉动态链接器在与可执行文件本身相同的目录中查找共享库。如果您将更新的
libstdc++.so
放在可执行文件相同的目录中,则可以在运行时找到它,问题解决了。(另一种选择是将可执行文件放在
/some/path/bin/
中,将更新的libstdc++.so放在
/some/path/lib/
中,并使用
'-Wl,-rpath,$ORIGIN/../lib'
或与可执行文件相关的任何其他固定位置链接,并相对于
$ORIGIN
设置RPATH。)
-static-libstdc++
选项就没有意义了,你只需使用-static
即可。 - Jonathan Wakelyobjdump -T [binary path]
命令查看是否动态加载了libstdc++.so
。对于 Golang 程序员,您可以在导入 "C" 之前添加#cgo linux LDFLAGS: -static-libstdc++ -static-libgcc
。 - bronze man-static-libstdc++
而不是-static
,因此libc.so
将不会被静态链接。 - Jonathan Wakely