为什么 g++ 需要 libstdc++.a?为什么不是默认值?

时间:2021-01-22 02:34:47

标签: c++ gcc g++

我有 this problem,解决方案是将 libstdc++.a 显式传递给 g++,如下所示:

/usr/local/gcc-10.2.0/bin/g++ -I/usr/local/gcc-10.2.0/include -L/usr/local/gcc-10.2.0/lib64 -Wl,-rpath,/usr/local/gcc-10.2.0/lib64 b.cpp /usr/local/gcc-10.2.0/lib64/libstdc++.a

我的问题:为什么我需要显式传递 libstdc++.a?我怎样才能让它自动,以便默认使用 libstdc++.a?我怎样才能找到这两个问题的答案?

测试代码:

#include <sstream>
using namespace std;

int
main ()
{
        ostringstream oss;
        unsigned long k = 5;
        oss << k;
}

使用以下参数编译:

/usr/local/gcc-10.2.0/bin/g++ -I/usr/local/gcc-10.2.0/include -L/usr/local/gcc-10.2.0/lib64 -Wl,-rpath,/usr/local/gcc-10.2.0/lib64 -lstdc++ b.cpp

得到以下输出:

/tmp/cclRSXGV.o: In function main': b.cpp:(.text+0x35): undefined reference to std::ostream::operator<<(unsigned long)'
collect2: error: ld returned 1 exit status

使用 GNU gcc 10.2.0,安装如下:

../gcc-10.2.0/configure --prefix=/usr/local/gcc-10.2.0 --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++ --disable-dssi --enable-libgcj-multifile --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux && make install-strip

默认情况下已经在 /usr 安装了 GNU gcc 4.4.7,在 /usr/local/gcc-9.2.0 安装了 GNU gcc 9.2.0

运行 /usr/local/gcc-10.2.0/bin/g++ -v b.cpp 会产生以下结果:

Using built-in specs.
COLLECT_GCC=/usr/local/gcc-10.2.0/bin/g++
COLLECT_LTO_WRAPPER=/usr/local/gcc-10.2.0/libexec/gcc/x86_64-redhat-linux/10.2.0/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../gcc-10.2.0/configure --prefix=/usr/local/gcc-10.2.0 --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++ --disable-dssi --enable-libgcj-multifile --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.2.0 (GCC)
COLLECT_GCC_OPTIONS='-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 /usr/local/gcc-10.2.0/libexec/gcc/x86_64-redhat-linux/10.2.0/cc1plus -quiet -v -D_GNU_SOURCE b.cpp -quiet -dumpbase b.cpp -mtune=generic -march=x86-64 -auxbase b -version -o /tmp/ccJiMH6j.s
GNU C++14 (GCC) version 10.2.0 (x86_64-redhat-linux)
        compiled by GNU C version 10.2.0, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version isl-0.18-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/../../../../include/c++/10.2.0
 /usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/../../../../include/c++/10.2.0/x86_64-redhat-linux
 /usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/../../../../include/c++/10.2.0/backward
 /usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/include
 /usr/local/include
 /usr/local/gcc-10.2.0/include
 /usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/include-fixed
 /usr/include
End of search list.
GNU C++14 (GCC) version 10.2.0 (x86_64-redhat-linux)
        compiled by GNU C version 10.2.0, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version isl-0.18-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 410dfe626634fcd13dbcedee05209c5e
COLLECT_GCC_OPTIONS='-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 as -v --64 -o /tmp/ccUyoUr2.o /tmp/ccJiMH6j.s
GNU assembler version 2.35 (x86_64-pc-linux-gnu) using BFD version (GNU Binutils) 2.35
COMPILER_PATH=/usr/local/gcc-10.2.0/libexec/gcc/x86_64-redhat-linux/10.2.0/:/usr/local/gcc-10.2.0/libexec/gcc/x86_64-redhat-linux/10.2.0/:/usr/local/gcc-10.2.0/libexec/gcc/x86_64-redhat-linux/:/usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/:/usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/
LIBRARY_PATH=/usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/:/usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 /usr/local/gcc-10.2.0/libexec/gcc/x86_64-redhat-linux/10.2.0/collect2 -plugin /usr/local/gcc-10.2.0/libexec/gcc/x86_64-redhat-linux/10.2.0/liblto_plugin.so -plugin-opt=/usr/local/gcc-10.2.0/libexec/gcc/x86_64-redhat-linux/10.2.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccfGN6NK.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/../lib64/crt1.o /usr/lib/../lib64/crti.o /usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/crtbegin.o -L/usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0 -L/usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/../../.. /tmp/ccUyoUr2.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0/crtend.o /usr/lib/../lib64/crtn.o
/usr/local/bin/ld: /tmp/ccUyoUr2.o: in function `main':
b.cpp:(.text+0xc9): undefined reference to `std::cout'
/usr/local/bin/ld: b.cpp:(.text+0x35): undefined reference to std::ostream::operator<<(unsigned long)'
collect2: error: ld returned 1 exit status

1 个答案:

答案 0 :(得分:6)

默认情况下,g++ 链接到动态 libstdc++ 库 (libstdc++.so)。通过显式传递 libstdc++.a,您将链接到静态副本。您可以使用 -static-libstdc++ 获得相同的最终结果。

针对 libstdc++ 的静态和动态链接都应该有效。您的问题可能是由错误地构建或安装 GCC 引起的(例如,应用了不正确的补丁,或混合了来自不同 GCC 构建的包含文件)。

要进行调查,请通过将 b.o 添加到您的 g++ 命令行来生成目标文件 -c,并通过添加 b.ii 来预处理源文件 -E -o b.ii。使用 nm -u b.o 获取未定义符号的重整名称(添加 -C 到 demangle)。您会看到缺失符号的错位名称是 _ZNSolsEm。尝试 grep 由 libstdc++ (nm -D --defined-only /usr/local/gcc-10.2.0/lib64/libstdc++.so) 定义的符号列表中缺少的符号。如果库中缺少它,则问题在于包含的文件希望库提供这些模板实例,而实际库却没有。

如果您查看 b.ii,您会发现它在末尾声明了相应的 extern template

  extern template class basic_ostringstream<char>;

如果您查看此行来自的 gcc 安装树中的 sstream.tcc 文件,您会看到它由 #if _GLIBCXX_EXTERN_TEMPLATE 保护。此宏的定义在 c++config.h 中,并根据 libstdc++ 配置时的 --enable-extern-template 选项进行设置。如果库是使用 --disable-extern-template 构建的,则不会提供这些模板实例。