Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

For the reference I'm using MinGW (GCC 5.3). When compiling a file with

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

it statically links the C++ standard lib (libstdc++) and produces a 1.9MB executable.

However running

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

it still dynamically links to libstdc++-6.dll and produces a 34KB executable.

Why does -static-libstdc++ only work with g++ but not with pure gcc?

like image 581
bool3max Avatar asked Jun 11 '17 21:06

bool3max


People also ask

What is __ attribute __ in C?

The __attribute__ directive is used to decorate a code declaration in C, C++ and Objective-C programming languages. This gives the declared code additional attributes that would help the compiler incorporate optimizations or elicit useful warnings to the consumer of that code.

Does GCC optimize by default?

GCC has a range of optimization levels, plus individual options to enable or disable particular optimizations. The overall compiler optimization level is controlled by the command line option -On, where n is the required optimization level, as follows: -O0 . (default).

What is O3 in GCC?

Optimization level -O3 -O3 instructs the compiler to optimize for the performance of generated code and disregard the size of the generated code, which might result in an increased code size. It also degrades the debug experience compared to -O2 .

What does optimization flag do?

Turning on optimization flags makes the compiler attempt to improve the performance and/or code size at the expense of compilation time and possibly the ability to debug the program. The compiler performs optimization based on the knowledge it has of the program.


1 Answers

The GCC manual, Link Options says:

-static-libstdc++

When the g++ program is used to link a C++ program, it normally automatically links against libstdc++. If libstdc++ is available as a shared library, and the -static option is not used, then this links against the shared version of libstdc++. That is normally fine. However, it is sometimes useful to freeze the version of libstdc++ used by the program without going all the way to a fully static link. The -static-libstdc++ option directs the g++ driver to link libstdc++ statically, without necessarily linking other libraries statically.

This makes clear that the option -static-libstdc++ is meaningful only to the g++ compiler driver, not gcc or any other.

On the other hand the option -l<name> is meaningful and means the same thing to all GCC compiler drivers. On that basis it is not surprising that:

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

has the same meaning as:

gcc file.cc -lstdc++ 

However, that observation does not truly illuminate why the first of those commandlines dynamically links libstdc++:-

-static-libstdc++ is meaningful only to g++ because only g++ links libstdc++ automatically. So it is only for g++ that the question arises whether the automatically linked libstdc++ will be the dynamic version or the static version. The dynamic version is the default: -static-libstdc++ insists on the static version.

The automatic linking of libstdc++ by g++ means this: g++ silently appends -lstdc++ to whatever linkage options you specify (along with quite a lot of other boiler-plate for a C++ linkage). You can reveal all the boilerplate by requesting verbose linkage (g++ ... -Wl,-v ...).

By itself, the appended -lstdc++ will cause the linker to link the dynamic version of libstdc++, per its default behaviour. The only difference made by -static-libstdc++ is that in the place where -lstdc++ would otherwise be silently passed to the linker, the options:

-Bstatic -lstdc++ -Bdynamic

are silently passed to it instead. These tell the linker:

  • -Bstatic: Do not link dynamic libraries until further notice
  • -lstdc++: Link libstdc++
  • -Bdynamic: Link dynamic libraries until further notice.

You see how that works to secure the static linkage of libstdc++ without out side-effects on the linkage of any other library.

But you can also see that the automatic linkage of libstdc++, whether dynamically or statically, has no retroactive effect on the linkage of any libraries you have specified yourself.

Hence, if your linkage already includes -lstdc++ before any boiler-plate options are silently appended by the compiler driver, then libstdc++ will be linked in just the same way as any -l<name> at that position in the linkage sequence. And if silently appended boiler-plate options result in -lstdc++ reappearing later in the linkage sequence, whether by itself or with the surroundings:

-Bstatic -lstdc++ -Bdynamic

then the later appearance will simply be redundant, because the library has already been linked.

So there is nothing peculiar about gcc that results in:

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

producing a program in which libstdc++ is dynamically linked. So does

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

or indeed:

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

because the generated linker commandline is of the form:

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

where -Bstatic -lstdc++ -Bdynamic is too late to make any difference.

Check it out:

file.cc

#include <iostream>

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

Compile and link normally and inspect the dynamic dependencies with 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 is present.

Now just with -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 is absent.

And finally with -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 is back.

(This is Linux, of course, but you'll find the same thing on Windows).

So whether you drive your linkage with g++ or gcc, the reason that

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

will result in libstdc++ being dynamically linked is simply that

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

will cause libfoo to be dynamically linked, if it can be, regardless of what ... is, provided only that ... does not contain the option -static.

like image 151
Mike Kinghan Avatar answered Oct 15 '22 19:10

Mike Kinghan