假设我有三个编译对象,它们都由相同的编译器/版本生成:
为简单起见,我们假设所有头文件都是用 C++11 编写的,仅使用其语义在所有三个标准版本之间都没有改变的构造,因此任何相互依赖性都通过头文件包含正确表达,并且编译器没有反对。
这些对象的哪些组合是它,链接到单个二进制文件是否安全?为什么?
编辑:欢迎回答涵盖主要编译器(例如 gcc、clang、vs++)
最佳答案
Which combinations of these objects is it and isn't it safe to link into a single binary? Why?
对于 GCC ,将对象 A、B 和 C 的任何组合链接在一起是安全的。如果它们都使用相同的版本构建,那么它们是 ABI 兼容的,标准版本(即
-std
选项)不会产生任何区别。为什么?因为这是我们努力确保的实现的一个重要属性。
出现问题的地方是,如果将使用不同版本的 GCC 和 编译的对象链接在一起,则在 GCC 对该标准的支持完成之前,您使用了新 C++ 标准中的不稳定特性。例如,如果您使用 GCC 4.9 和
-std=c++11
编译一个对象,而使用 GCC 5 和 -std=c++11
编译另一个对象,则会遇到问题。 C++11 支持在 GCC 4.x 中是实验性的,因此 GCC 4.9 和 C++11 功能的 5 版本之间存在不兼容的更改。类似地,如果您使用 GCC 7 和 -std=c++17
编译一个对象,而使用 GCC 8 和 -std=c++17
编译另一个对象,则会遇到问题,因为 GCC 7 和 8 中的 C++17 支持仍在试验和发展中。另一方面,以下对象的任何组合都可以使用(尽管请参阅下面关于
libstdc++.so
版本的注释):-std=c++03
-std=c++11
-std=c++17
这是因为 C++03 支持在使用的所有三个编译器版本中都是稳定的,因此 C++03 组件在所有对象之间兼容。自 GCC 5 以来,C++11 支持是稳定的,但对象 D 不使用任何 C++11 功能,对象 E 和 F 都使用 C++11 支持稳定的版本。 C++17 支持在任何使用的编译器版本中都不稳定,但只有对象 F 使用 C++17 特性,因此与其他两个对象不存在兼容性问题(它们共享的唯一特性来自 C++03或 C++11,并且使用的版本使这些部分正常)。如果您稍后想使用 GCC 8 和
-std=c++17
编译第四个对象 G,那么您需要使用相同版本(或不链接到 F)重新编译 F,因为 F 和 G 中的 C++17 符号不兼容。上述 D、E 和 F 之间兼容性的唯一警告是您的程序必须使用 GCC 7(或更高版本)中的
libstdc++.so
共享库。由于对象 F 是使用 GCC 7 编译的,因此您需要使用该版本的共享库,因为使用 GCC 7 编译程序的任何部分可能会引入对 GCC 4.9 或 GCC 5 的 libstdc++.so
中不存在的符号的依赖。 ,如果您链接到使用 GCC 8 构建的对象 G,则需要使用 GCC 8 中的 libstdc++.so
以确保找到 G 所需的所有符号。简单的规则是确保程序在运行时使用的共享库至少与用于编译任何对象的版本一样新。使用 GCC 时的另一个警告,在您的问题的评论中已经提到,是因为 GCC 5 在 libstdc++ 中有两个
std::string
的实现。这两种实现不是链接兼容的(它们具有不同的重整名称,因此不能链接在一起)但可以共存于同一个二进制文件中(它们具有不同的重整名称,因此如果一个对象使用 std::string
和另一个使用 std::__cxx11::string
)。如果您的对象使用 std::string
,那么通常它们都应该使用相同的字符串实现进行编译。编译 -D_GLIBCXX_USE_CXX11_ABI=0
选择原来的 gcc4-compatible
实现,或者 -D_GLIBCXX_USE_CXX11_ABI=1
选择新的 cxx11
实现(别被名字骗了,C++03 也可以用,叫 0x1045 符合 C++7 11 项要求)。哪个实现是默认的取决于 GCC 的配置方式,但默认值总是可以在编译时用宏覆盖。
关于c++ - 链接 C++17、C++14 和 C++11 对象是否安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46746878/