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

Posted

技术标签:

【中文标题】为啥 g++ 需要 libstdc++.a?为啥不是默认值?【英文标题】:Why does g++ require libstdc++.a? Why is it not the default?为什么 g++ 需要 libstdc++.a?为什么不是默认值? 【发布时间】:2021-01-22 02:34:47 【问题描述】:

我有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

GNU gcc 4.4.7 默认安装在 /usr,GNU gcc 9.2.0 安装在 /usr/local/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

【问题讨论】:

g++支持多种标准库,甚至交叉编译等。这些需要指定要链接的自定义标准库。我不知道如何让 g++ 默认使用特定的,所以我会让其他人回答这个问题。 对于正确配置的编译器,您应该不需要这些 -I-L-l 标志。您可能需要的唯一一个是-Wl,-rpath。运行/usr/local/gcc-10.2.0/bin/g++ -v b.cpp 并发布输出。 @n.'pronouns'm。我已经发布了使用-v 编译的输出...您认为可能有什么问题? /usr/local/gcc-10.2.0/lib/gcc/x86_64-redhat-linux/10.2.0//usr/local/gcc-10.2.0/lib64/ 中是否有任何名为 libstdc++.so.6 的文件?它包含什么? libstdc++.a 和 libstdc++.so 都在 /usr/local/gcc-10.2.0/lib64 中。这就是为什么当我用 /usr/local/gcc-10.2 调用 g++ 时它起作用的原因.0/lib64/libstdc++.a 【参考方案1】:

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

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

要进行调查,通过将 -c 添加到 g++ 命令行来生成目标文件 b.o,并通过添加 -E -o b.ii 来预处理源文件 b.ii。使用nm -u b.o 获取未定义符号的错位名称(将-C 添加到demangle)。您会看到缺失符号的错位名称是_ZNSolsEm。尝试在 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 构建的,它不会提供那些模板实例化。

【讨论】:

以上是关于为啥 g++ 需要 libstdc++.a?为啥不是默认值?的主要内容,如果未能解决你的问题,请参考以下文章

安装oracle 11g,为啥不需要windows系统安装jre就可以安装?

为啥A-star算法需要g(n)?

为啥 g++ 不关心初始化列表分配给 (const std::string&) a (std::string)?和其他怪异[关闭]

为啥我需要在 g++ 中使用 typedef typename 而不是 VS?

为啥异常不适用于 OSX 上的 gcc7 和 -static-libgcc?

为啥 C++ 标准库与编译器而不是操作系统捆绑在一起?