静态链接 libstdc++:有什么问题吗? [英] Linking libstdc++ statically: any gotchas?

查看:60
本文介绍了静态链接 libstdc++:有什么问题吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要将基于 Ubuntu 12.10 和 GCC 4.7 的 libstdc++ 构建的 C++ 应用程序部署到运行 Ubuntu 10.04 的系统,该系统带有相当旧版本的 libstdc++.

I need to deploy a C++ application built on Ubuntu 12.10 with GCC 4.7's libstdc++ to systems running Ubuntu 10.04, which comes with a considerably older version of libstdc++.

目前,我正在使用 -static-libstdc++ -static-libgcc 进行编译,正如这篇博文所建议的:静态链接 libstdc++.作者警告在静态编译 libstdc++ 时不要使用任何动态加载的 C++ 代码,这是我尚未检查的内容.尽管如此,到目前为止一切似乎都很顺利:我可以在 Ubuntu 10.04 上使用 C++11 功能,这正是我所追求的.

Currently, I'm compiling with -static-libstdc++ -static-libgcc, as suggested by this blog post: Linking libstdc++ statically. The author warns against using any dynamically-loaded C++ code when compiling libstdc++ statically, which is something I haven't yet checked. Still, everything seems to be going smoothly so far: I can make use of C++11 features on Ubuntu 10.04, which is what I was after.

我注意到这篇文章是 2005 年的,也许从那时起发生了很大的变化.它的建议是否仍然有效?有什么我应该注意的潜在问题吗?

I note that this article is from 2005, and perhaps much has changed since then. Is its advice still current? Are there any lurking issues I should be aware of?

推荐答案

那篇博文相当不准确.

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

As far as I know C++ ABI changes have been introduced with every major release of GCC (i.e. those with different first or second version number components).

不是真的.自 GCC 3.4 以来引入的唯一 C++ ABI 更改是向后兼容的,这意味着 C++ ABI 已经稳定了近九年.

Not true. The only C++ ABI changes introduced since GCC 3.4 have been backward-compatible, meaning the C++ ABI has been stable for nearly nine years.

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

To make matters worse, most major Linux distributions use GCC snapshots and/or patch their GCC versions, making it virtually impossible to know exactly what GCC versions you might be dealing with when you distribute binaries.

发行版的 GCC 补丁版本之间的差异很小,并且 ABI 没有变化,例如Fedora 的 4.6.3 20120306 (Red Hat 4.6.3-2) 与上游 FSF 4.6.x 版本 ABI 兼容,几乎可以肯定与任何其他发行版的任何 4.6.x 兼容.

The differences between distributions' patched versions of GCC are minor, and not ABI changing, e.g. Fedora's 4.6.3 20120306 (Red Hat 4.6.3-2) is ABI compatible with the upstream FSF 4.6.x releases and almost certainly with any 4.6.x from any other distro.

在 GNU/Linux GCC 的运行时库使用 ELF 符号版本控制,因此可以轻松检查对象和库所需的符号版本,如果您有一个 libstdc++.so 提供这些符号,它就可以工作,与您的发行版的另一个版本的修补版本是否略有不同都没有关系.

On GNU/Linux GCC's runtime libraries use ELF symbol versioning so it's easy to check the symbol versions needed by objects and libraries, and if you have a libstdc++.so that provides those symbols it will work, it doesn't matter if it's a slightly different patched version from another version of your distro.

但如果要这样做,则不能动态链接 C++ 代码(或任何使用 C++ 运行时支持的代码).

but no C++ code (or any code using the C++ runtime support) may be linked dynamically if this is to work.

这也不是真的.

也就是说,静态链接到 libstdc++.a 是您的一种选择.

That said, statically linking to libstdc++.a is one option for you.

如果您动态加载库(使用 dlopen),它可能不起作用的原因是当您(静态)链接它时,它所依赖的 libstdc++ 符号可能不需要您的应用程序,所以这些符号不会出现在您的可执行文件中.这可以通过将共享库动态链接到 libstdc++.so 来解决(如果它依赖于它,无论如何这是正确的做法.)ELF 符号插入意味着您的可执行文件中存在的符号将由共享库使用,但其他不在您的可执行文件中的将在它链接到的任何 libstdc++.so 中找到.如果您的应用程序不使用 dlopen,则无需关心.

The reason it might not work if you dynamically load a library (using dlopen) is that libstdc++ symbols it depends on might not have been needed by your application when you (statically) linked it, so those symbols will not be present in your executable. That can be solved by dynamically-linking the shared library to libstdc++.so (which is the right thing to do anyway if it depends on it.) ELF symbol interposition means symbols that are present in your executable will be used by the shared library, but others not present in your executable will be found in whichever libstdc++.so it links to. If your application doesn't use dlopen you don't need to care about that.

另一种选择(也是我更喜欢的选择)是在您的应用程序旁边部署较新的 libstdc++.so,并确保在默认系统 libstdc++.so 之前找到它,这可以通过强制动态链接器查找正确的位置来完成,或者在运行时使用 $LD_LIBRARY_PATH 环境变量,或者通过在可执行文件中设置 RPATH链接时间.我更喜欢使用 RPATH 因为它不依赖于为应用程序正确设置的环境.如果您使用 '-Wl,-rpath,$ORIGIN' 链接您的应用程序(注意单引号以防止 shell 尝试扩展 $ORIGIN),那么可执行文件将具有$ORIGINRPATH 告诉动态链接器在与可执行文件本身相同的目录中查找共享库.如果将较新的 libstdc++.so 放在与可执行文件相同的目录中,它将在运行时找到,问题就解决了.(另一种选择是将可执行文件放在 /some/path/bin/ 中,将较新的 libstdc++.so 放在 /some/path/lib/ 中并与 链接'-Wl,-rpath,$ORIGIN/../lib' 或任何其他相对于可执行文件的固定位置,并将 RPATH 设置为相对于 $ORIGIN)

Another option (and the one I prefer) is to deploy the newer libstdc++.so alongside your application and ensure it is found before the default system libstdc++.so, which can be done by forcing the dynamic linker to look in the right place, either using $LD_LIBRARY_PATH environment variable at run-time, or by setting an RPATH in the executable at link-time. I prefer to use RPATH as it doesn't rely on the environment being set correctly for the application to work. If you link your application with '-Wl,-rpath,$ORIGIN' (note the single quotes to prevent the shell trying to expand $ORIGIN) then the executable will have an RPATH of $ORIGIN which tells the dynamic linker to look for shared libraries in the same directory as the executable itself. If you put the newer libstdc++.so in the same directory as the executable it will be found at run-time, problem solved. (Another option is to put the executable in /some/path/bin/ and the newer libstdc++.so in /some/path/lib/ and link with '-Wl,-rpath,$ORIGIN/../lib' or any other fixed location relative to the executable, and set the RPATH relative to $ORIGIN)

这篇关于静态链接 libstdc++:有什么问题吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆