-static-libstdc++ 适用于 g++ 但不适用于纯 gcc?

-static-libstdc++ works on g++ but not on pure gcc?

本文关键字:适用于 gcc g++ -static-libstdc++ 不适用      更新时间:2023-10-16

作为参考,我使用的是MinGW(GCC 5.3)。编译文件时

g++ file.cc -static-libstdc++

它静态链接C++标准库(libstdc++)并生成一个1.9MB的可执行文件。

然而运行

gcc -lstdc++ -static-libstdc++ file.cc

它仍然动态链接到libstdc++-6.dll并生成 34KB 可执行文件。

为什么-static-libstdc++只适用于g++而不适用于纯gcc

GCC 手册,链接选项说:

-

static-libstdc++

当g++程序用于链接C++程序时,它通常会自动链接 反对libstdc++。如果 libstdc++ 可用作共享库,并且 -static 选项未使用,则此链接对应于 libstdc++ 的共享版本。 这通常没问题。但是,有时冻结 程序使用的libstdc++,而无需一直到完全静态的链接。 -static-libstdc++ 选项指示 g++ 驱动程序静态链接 libstdc++, 不必静态链接其他库。

这清楚地表明,选项-static-libstdc++仅对g++编译器驱动程序,而不是gcc或任何其他驱动程序。

另一方面,选项-l<name>有意义,意思相同 到所有 GCC 编译器驱动程序。在此基础上,毫不奇怪:

gcc file.cc -lstdc++ -static-libstdc++

具有与以下相同的含义:

gcc file.cc -lstdc++ 

然而,这一观察并没有真正阐明为什么第一个 命令行动态链接libstdc++:-

-static-libstdc++仅对g++有意义,因为只有g++链接 自动libstdc++。所以问题只是为了g++自动链接的libstdc++是否为动态版本 或静态版本。动态版本为默认值:-static-libstdc++坚持静态版本。

通过g++自动链接libstdc++意味着:静默地g++-lstdc++附加到指定的任何链接选项(以及 相当多的其他样板用于C++链接)。您可以显示所有内容 通过请求详细链接(g++ ... -Wl,-v ...)的样板文件。

追加的-lstdc++本身将导致链接器链接动态版本libstdc++,根据其默认行为。唯一的区别是-static-libstdc++是在-lstdc++本来会的地方 以静默方式传递给链接器,选项如下:

-Bstatic -lstdc++ -Bdynamic

而是默默地传递给它。这些告诉链接器:

  • -Bstatic: 请勿链接动态库,直至另行通知
  • -lstdc++: 链接libstdc++
  • -Bdynamic: 链接动态库,直至另行通知。

您会看到如何在没有的情况下保护libstdc++的静态链接 排除对任何其他库链接的副作用。

但你也可以看到,libstdc++的自动联动,是否 动态或静态,对联动没有追溯效力 您自己指定的任何库。

因此,如果您的链接已经包含-lstdc++在任何样板之前 选项由编译器驱动程序以静默方式附加,然后libstdc++将被链接 与连杆中该位置的任何-l<name>相同 序列。如果以静默方式附加样板选项会导致-lstdc++稍后在链接序列中重新出现,无论是单独出现还是与 周边环境:

-Bstatic -lstdc++ -Bdynamic

那么后面的外观就只是多余的,因为库有 已经链接。

因此,gcc并没有什么特别

之处,会导致:
gcc file.cc -lstdc++ -static-libstdc++

生成动态链接libstdc++的程序。也是如此

g++ file.cc -lstdc++ -static-libstdc++

或者确实:

g++ file.cc -static-libstdc++ -lstdc++

因为生成的链接器命令行的格式为:

... file.o -lstdc++ ... -Bstatic -lstdc++ -Bdynamic ...

-Bstatic -lstdc++ -Bdynamic为时已晚,无法做出任何改变。

看看吧:

file.cc

#include <iostream>
int main()
{
std::cout << "Hello World" << std::endl;
return 0;
}

正常编译和链接,并检查动态依赖ldd

$ g++ -o prog file.cc
$ ldd prog
linux-vdso.so.1 =>  (0x00007ffede76a000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f42fa74c000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f42fa385000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f42fa07c000)
/lib64/ld-linux-x86-64.so.2 (0x0000558ab42bc000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f42f9e65000)

libstdc++.so存在。

现在只有-static-libstdc++

$ g++ -o prog file.cc -static-libstdc++
$ ldd prog
linux-vdso.so.1 =>  (0x00007fff448d7000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fe5f7c71000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe5f78aa000)
/lib64/ld-linux-x86-64.so.2 (0x0000556ebf272000)

libstdc++.so缺席。

最后是-static-libstdc++ -lstdc++

$ g++ -o prog file.cc -static-libstdc++ -lstdc++
$ ldd prog
linux-vdso.so.1 =>  (0x00007ffd12de9000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fd5a1823000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd5a145c000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fd5a1153000)
/lib64/ld-linux-x86-64.so.2 (0x000055bbe31c3000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fd5a0f3c000)

libstdc++.so回来了。

(当然,这是Linux,但你会在Windows上找到同样的东西)。

所以无论你是驱动你的联动g++还是gcc,原因

{gcc|g++} file.cc -lstdc++ ...

将导致libstdc++动态链接

只是
{gcc|g++} file.cc -lfoo ...

将导致libfoo动态链接(如果可以),无论...是什么,前提是...不包含选项-static.

从技术上讲,这不是一个答案,而是针对损坏的构建系统的解决方法。

我正在使用一个构建系统,出于某种非常奇怪的原因,它使用 gcc 而不是 g++ 来驱动构建过程,即使是对于C++对象也是如此。我需要有一个二进制文件,除了glibc库之外不依赖于任何其他东西。所以,我最终这样做了:

$ cat <<EOF > gcc
#!/bin/bash
if [[ $@ == *"-lstdc++"* ]]; then
/full/path/to/g++ -static-libgcc -static-libstdc++ $(echo $@ | sed 's,-lstdc++,,g')
else
/full/path/to/gcc -static-libgcc $@
fi
EOF
$ chmod +x gcc
$ export PATH=$PWD:$PATH