Nic*_*son 81 c++ linux gcc static-libraries libstdc++
我需要使用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年开始的,从那以后可能发生了很大变化.它的建议仍然是最新的吗?我应该注意哪些潜在的问题?
Jon*_*ely 125
那篇博文非常不准确.
据我所知,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版本的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'(注意单引号,以防止shell试图扩展$ORIGIN),那么可执行文件将有一个RPATH的$ORIGIN告诉动态链接程序查找共享库在同一目录中可执行文件本身.如果你把新版本libstdc++.so放在与可执行文件相同的目录中,它将在运行时找到,问题就解决了.(另一种选择是将可执行文件放入/some/path/bin/和更新的libstdc ++.所以进入/some/path/lib/和链接'-Wl,-rpath,$ORIGIN/../lib'或相对于可执行文件的任何其他固定位置,并相对于设置RPATH $ORIGIN)
Emi*_*rke 10
Jonathan Wakely的优秀答案之一,为什么dlopen()有问题:
由于GCC 5中的新异常处理池(参见PR 64535和PR 65434),如果你dlopen和dlclose一个静态链接到libstdc ++的库,你每次都会得到(池对象的)内存泄漏.因此,如果您有可能使用dlopen,静态链接libstdc ++似乎是一个非常糟糕的主意.请注意,这是一个真正的泄漏,而不是PR 65434中提到的良性泄漏.