带有clang++和O2的未定义引用

Undefined reference with clang++ with O2

本文关键字:未定义 引用 O2 clang++ 带有      更新时间:2023-10-16

我在一个项目上尝试CLang 3.4和libc++,但在发布模式中遇到了奇怪的链接错误:

/home/wichtounet/dev/eddic/src/ast/Operator.cpp:17: error: undefined reference to
'std::__1::basic_ostream<char, std::__1::char_traits<char>>&
 std::__1::operator<< <char, std::__1::char_traits<char>, std::__1::allocator<char>>(
   std::__1::basic_ostream<char, std::__1::char_traits<char>>&,
   std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&
 )'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

一切都很顺利。程序在调试模式下正确链接,但在我使用O2时没有。在O0、O1和Os中,一切都很好,但在O2、O3、Os中却没有联系。我也尝试过LTO模式,它运行良好。

我尝试了两个版本的libc++,但都没有用。

代码在我看来并不坏:

std::ostream& ast::operator<< (std::ostream& stream, ast::Operator op){
    std::string value = "asd";
    return stream << value;
}

但我没有一个简单的例子造成这个问题。

clang++用于构建和链接代码。我使用了"-std=c++1y-stdlib=libc++"进行编译,并添加了一些库内容进行链接。

可能是什么原因造成的?

编辑:在发布模式下完全调用链接步骤:

clang++ -v -use-gold -Iinclude -std=c++1y -stdlib=libc++ -Wextra -Wall -Qunused-arguments -Wuninitialized -Wsometimes-uninitialized -Wno-long-long -Winit-self -Wdocumentation -pedantic -isystem /home/wichtounet/build/modular-boost//include -L /home/wichtounet/build/modular-boost//lib -lboost_program_options -g -DLOGGING_DISABLE -DNDEBUG -O3 -march=native -fvectorize -fslp-vectorize-aggressive -fomit-frame-pointer -o release/bin/eddic "TONS OF DOT O"
clang version 3.4 (tags/RELEASE_34/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
Selected GCC installation: /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2
 "/usr/bin/x86_64-pc-linux-gnu-ld" --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o release/bin/eddic /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2/../../../../lib64/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2/crtbegin.o -L/home/wichtounet/build/modular-boost//lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2/../../../../x86_64-pc-linux-gnu/lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2/../../.. -L/lib -L/usr/lib -lboost_program_options "TONS OF DOT O" -lc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2/crtend.o /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2/../../../../lib64/crtn.o
src/ast/Operator.cpp:15: error: undefined reference to 'std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::operator<< <char, std::__1::char_traits<char>, std::__1::allocator<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

我对长期使用g++编译的代码遇到了这个问题,试图使用clang++进行编译。相同症状:未定义引用std::__1::basic_stream<…>当-O2从编译器选项中删除时,它神奇地消失了。我发现的所有类似的报告都是关于错误地使用clang而不是clang++编译C++代码的,但我的情况并非如此:我使用的是clang++。

我终于能够确定(对我来说)问题是在我的头(.h)文件中使用#include <iosfwd>(它只有iostream前向声明,以减少编译时间)来声明一个类,而在实现该类的相应源(.cpp)文件中不使用#include <iostream>

一旦我将#include <iostream>添加到源文件并重新编译,这些未定义的引用错误就消失了。

我注意到错误消息"std::__1::operator<<"。在cpp代码中,我看到了"ast::operator<<"。这给人的印象是名称空间出现了问题。

现在我不知道ast是一个类还是一个命名空间,但在这两种情况下,这看起来都有点不对劲。

如果ast是一个类,那么我不确定运算符<lt;被允许作为类成员。请参阅:http://www.cs.nctu.edu.tw/cis/chinese/doc/research/c++/C++常见问题英文版/in-out.html#FAQ-15.8。这表明运算符<lt;应该作为朋友实现,而不是作为类的成员实现。你可以试着把它作为一种朋友的方法,看看它是否能解决问题。

如果ast是一个命名空间,那么我会尝试删除"asd::",并在定义周围添加单独的命名空间声明。