-static-libstdc++ works on g++ but not on pure gcc?
This is technically not an answer, but a workaround for broken build systems.
I was working with a build system which for some very weird reason, used gcc instead of g++ to drive the build process, even for C++ objects. And I needed to have a binary with no dependency on anything other than glibc libraries. So, I ended up doing this:
$ 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
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++
: Linklibstdc++
-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
.