I am trying to compile a program to have all libraries statically inside the final binary, but I still want glibc to be dynamically linked. If I use "-static" it compiles ALL libraries statically, including glibc. Basically I need a -static parameter together with something like -exclude=glibc Would be awesome with both an example when using "make" as well as an example with pure "gcc". Running "ldd" on the final binary should show only glibc dynamically linked.
2 Answers
You can link a subset of libraries statically using -Bstatic
and -Bdynamic
. On the GCC command line, this looks like this (for linking statically against PCRE, just as an example):
-Wl,-Bstatic -lpcre -Wl,-Bdynamic
Note that -lanl
, -ldl
, -lmvec
, -lnsl
, -lpthread
, -lresolv
, -lrt
, -lutil
are all part of glibc and must therefore come after the -Wl,-Bdynamic
(so that they are linked dynamically). For -lcrypt
, this depends on the distribution.
What you ask can be done on some systems, approximately, but not with GCC's -static
option. That option has global effect on linking:
On systems that support dynamic linking, this overrides -pie and prevents linking with the shared libraries. On other systems, this option has no effect.
To have the wanted level of control over linking, you need to pass flags through to the linker. You can do that with GCC's -Wl
option. If you are using GCC then you are presumably also using the GNU linker, and on build targets that support both static and dynamic linking, it has a variety of mechanisms for mixing them. In particular, the GNU linker's -Bstatic
flag and its counterpart -Bdynamic
flag each take effect only for libraries named after them on the command line, up to the next such flag. That is, they allow you to switch back and forth between designating libraries for static linking and for dynamic linking.
Example:
This C program requires the math library to be linked, which is not automatic with GCC:
link_test.c:
#include <stdio.h>
#include <math.h>
int main(void) {
printf("The square root of 2 is approximately %f\n", sqrt(2.0));
}
This gcc
command will cause the-lm
to be linked statically, but libc to be linked dynamically:
gcc -o link_test link_test.c -Wl,-Bstatic -lm -Wl,-Bdynamic
Any number of addional -l
options, library names, and object file names could be put between the -Wl,-Bstatic
and -Wl,-Bdynamic
options along with -lm
; all such objects will be linked statically. Although libc
is not explicitly linked (GCC does not require that), leaving the link type toggled to "dynamic" at the end of the explicit argument list does, for me, cause libc to be linked dynamically:
$ ldd link_test
linux-vdso.so.1 => (0x00007ffe185af000)
libc.so.6 => /lib64/libc.so.6 (0x00002b775f059000)
/lib64/ld-linux-x86-64.so.2 (0x00002b775ee35000)
(Observe that libm does not appear in the dynamic library listing, unlike when -Wl,-Bstatic
is not used, but libc does.)
Note that your objective that "Running 'ldd' on the final binary should show only glibc dynamically linked" is not necessarily viable, as the above ldd
output demonstrates. If your executable is dynamically linked at all, then in addition to any dynamic libraries it will have the dynamic loader linked in, and possibly also platform-specific pseudo-libraries such as linux-vdso.so.1
.
You ask for a makefile example, but that's like asking just "write me a program". Nothing about this is make
-specific, and there are innumerable ways to incorporate the above approach into a makefile. But since you asked, this is one of the simplest possible variations:
Makefile
link_test: link_test.c
gcc -o $@ $< -Wl,-Bstatic -lm -Wl,-Bdynamic