1
votes

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

2 Answers

2
votes

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.

1
votes

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.

(GCC 9.2 manual)

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