这里发生了什么魔法?
这主要是 ELF 符号版本控制的魔力。我在这方面看到的最好的参考资料是Ulrich Drepper的How to Write Shared Libraries ,特别是第 3 节。
他们如何提供与旧版本的 libstdc++ 链接的 gcc 4.4.7?我认为这是不可能的。
libstdc++ 开发人员非常注意 ABI 兼容性。这使得查看两个不同版本的 libstdc++ 之间引入的新符号变得相当简单。
查看 libstdc++ 的ABI 兼容性页面,您可以看到 GCC 4.1 的 libstdc++ 具有 GLIBCXX_3.4.8,而 GCC 4.4 的库存(FSF 版本)具有 GLIBCXX_3.4.13。然后可以查看libstdc++ 版本脚本以查看在这两个版本之间添加了哪些符号。
查看符号版本的更经验方法是使用 readelf 之类的工具。例如,在我的 Ubuntu 系统上readelf --dyn-syms --wide /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | c++filt
显示这样的输出(只是几个选定的短线):
223: 000000000006dbe0 2121 FUNC GLOBAL DEFAULT 12 std::ios_base::Init::Init()@@GLIBCXX_3.4
...
226: 00000000002ed920 1 OBJECT GLOBAL DEFAULT 27 std::adopt_lock@@GLIBCXX_3.4.11
注意符号名称末尾的符号版本,在@@
.
这个 stdc++_nonshared 库是什么?
加入上述段落中的点,stdc++_nonshared 是一个静态库,其中包含库存 libstdc++.so.6.0.13 但不在 libstdc++.so.6.0.8 中的符号。
我不知道 .so 文件可以包含该文本。谁解析它(我猜是动态链接器),它的规范和后果是什么?
常规链接器解析这个,而不是运行时链接器。请参阅链接描述文件中 INPUT的 binutils 文档。因此,与这个特殊的 libstdc++.so.6.0.13 链接将导致链接器动态链接到 libstdc++.so.6.0.8,并静态链接到包含额外符号的库。
这样做的缺点是,以这种方式编译的应用程序将比同一个应用程序更臃肿,后者仅动态链接到包含所有必要符号的库存 libstdc++.so.6.0.13。好处是新标准库的功能可以用于旧系统的标准安装,而独立的软件供应商不需要发布他们自己的 libstdc++ 副本。
这个魔法能走多远?我可以将 gcc4.7 与 libstdc++ 6.0.3 一起使用吗?什么是兼容性谱
既然您知道它的魔力是什么,那么您可能会意识到您拥有的这个版本的 GCC 4.4 是专为 Centos 5(嗯,最初是 Red Hat 5)制作的特殊版本。因此,您可能可以创建一个 GCC 4.7,它将生成只需要 libstdc++ 6.0.3 的二进制文件,但它需要大量的工作来修补您的 GCC 树以将正确的符号放入 stdc++_nonshared.a。您至少可以查看 gcc44 RPM 的源代码,了解 Red Hat 是如何做到的。
Red Hat 似乎在他们的Red Hat Developer Toolset中延续了这种方法。在撰写本文时,GCC 4.8.1 是最新的编译器,它可以为 EL5 构建二进制文件,仍然只需要在目标系统上安装 libstdc++.so.6.0.8。这对于想要使用 C++11 编写但需要能够在 EL5 或 EL6 上进行部署的开发人员来说非常有用。