【发布时间】:2017-02-28 16:39:35
【问题描述】:
我遇到了一个奇怪的错误,我怀疑这与我的系统配置有关。我正在使用 g++ --version = g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609 编译/链接一个简单的 c++ 程序。 默认语言标准记录为 c++98,但即使指定了 -std=c++98 选项,我在输出 .o 文件中看到 c++11 符号。这是我的 test.cpp:
#include <string>
int main() {
std::string str = "Hello World!";
return 0;
}
这是我的编译和链接命令(可能带有不必要的显式语言标准选项)和相关输出:
$ g++ -c -Wall -std=c++98 -o test.o test.cpp
$ g++ -Wall -std=c++98 -o test test.o
$ nm -C test.o
U __gxx_personality_v0
0000000000000000 T main
U __stack_chk_fail
U _Unwind_Resume
U std::allocator<char>::allocator()
U std::allocator<char>::~allocator()
U std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)
U std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()
注意对__cxx11::* 的引用。我认为这些是编译器插入的 c++11 符号。我获得了成功的构建,但显然使用了 c++11。这是 ldd 的输出:
$ ldd test
linux-vdso.so.1 => (0x00007ffc381f5000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f6548d48000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f6548b32000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6548768000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f654845f000)
/lib64/ld-linux-x86-64.so.2 (0x000055785493c000)
对于我的真实项目,我必须链接到 c++98 的第三方库,但由于这个编译器问题,我无法这样做。我的目标文件正在这些库中寻找 c++11 符号,但找不到它们。有什么见解吗?
【问题讨论】:
-
在我看来你的 libstdc++ 是用 c++11 编译的,所以你可能需要使用不同的来获取非 c++11 符号。不过,不是 100% 确定,因为我不确定共享库是否可以同时包含 c++11 和旧符号
-
C++11 和 C++98 是语言的一致性级别。要链接库以生成可执行文件,该库必须使用相同的构建系统开发。您不应该将不同编译器生成的对象链接在一起您声明的任何语言一致性级别。
-
根据经验,C++ 代码不能链接到“第三方库”,除非它是使用完全相同的 C++ 编译器构建的。当然,一个编译器可以提供与同一编译器的其他版本的 ABI 兼容性,这种 ABI 兼容性是否由 -std=c++98 提供,尚不清楚。此选项所做的只是指定编译代码所依据的语言标准。
-
GCC 在 v5 时代的某个地方将其 ABI 版本更改为具有小字符串优化的
std::string,而不是 C++11 不兼容的写时复制字符串实现。我认为即使对于 C++03/98 也可以,因为它们仍然符合要求。我怀疑您可以通过强制它或您的标准库使用旧 ABI 来解决您的问题。由于字符串只是一个模板,如果幸运的话,它可以在不重新编译标准库的情况下工作。 -
__cxx11 这个名字有误导性,它也可能是 __version_7,但由于它是与 C++11 同时引入的......这并不意味着编译器使用 C ++11,这只是一个 ABI 细节。