小编典典

静态链接libstdc ++:有陷阱吗?

linux

我需要将基于GCC 4.7的libstdc 的,基于Ubuntu 12.10构建的C 应用程序部署到运行Ubuntu
10.04的系统,该系统随附了相当老的libstdc ++版本。

目前,我正在-static-libstdc++ -static-libgcc按照此博客文章的建议进行编译:静态链接libstdc
++
。作者警告不要在静态编译libstdc 时使用任何动态加载的C
代码,这是我尚未检查过的事情。到目前为止,一切似乎都进展顺利:我可以在Ubuntu 10.04上使用C ++ 11功能。

我注意到这篇文章是从2005年开始的,此后也许已经发生了很大的变化。它的建议仍然有效吗?我应该注意哪些潜伏问题?


阅读 1527

收藏
2020-06-02

共1个答案

小编典典

该博客文章非常不准确。

据我所知,GCC的每个主要版本(即那些具有不同的第一或第二版本编号组件的版本)都引入了C ++ ABI更改。

不对。自GCC 3.4以来唯一引入的C ABI更改是向后兼容的,这意味着C ABI稳定了将近9年。

更糟糕的是,大多数主要的Linux发行版都使用GCC快照和/或修补其GCC版本,从而几乎不可能确切知道分发二进制文件时可能要处理的GCC版本。

发行版的GCC补丁版本之间的差异很小,并且不会更改ABI,例如Fedora的4.6.3 20120306(Red Hat 4.6.3-2)与上游FSF
4.6.x版本以及几乎所有4.6都兼容ABI。 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

2020-06-02