5
votes

I'm trying to compile a very simple (as simple as hello world) C program using both dynamic and static linking with GCC. I want to know how to do this in general, so my minimal test example is simply trying to link libc as static and libm dynamically.

I've come across at least the following other questions regarding the same topic:

GCC: static linking only some libraries

Static link of shared library function in gcc

Some of the answers therein suggest things such as using -Wl,-Bstatic and -Wl,-Bdynamic to specify which libraries are respectively static and dynamic. Also suggested is among others simply specifying the full path of the static library to link against.

I've tried several of these suggestions, and variants thereof. I don't understand the error message it gives me. I know what PIE is, but I don't see how it relates to what I'm trying to do.

Here are some failed attempts:

$ gcc test.c /usr/lib64/libc.a
linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
urned 1 exit status
$ gcc test.c -Wl,-Bdynamic -lm -Wl,-Bstatic -lc
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bdynamic -lm -Wl,-Bstatic -lc test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bstatic -lc -Wl,-Bdynamic -lm test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status

Compiling just with no arguments, and with -static work fine, but I need partial static compilation:

$ gcc test.c -lm
$ gcc -static test.c -lm

However, the following fails too:

$ gcc test.c /usr/lib64/libc.a /usr/lib64/libm.a

I've come across a similar error in this post:

C++ Statically linked shared library

However the answers do not seem to apply to my problem.

The program I'm trying to compile is simply (as test.c):

#include <stdio.h>
#include <math.h>

int main(int argc, char **argv)
{
    int i = 0;

    for(i = 0; i < 65535; i++) {
            printf("%f\n", sinf(i));
            printf("%f\n", cosf(i));
            printf("%f\n", tanf(i));
            printf("%f\n", sqrtf(i));
    }


    return 0;
}

EDIT: Please note that the program must be complex enough to actually require libm, otherwise linking attempts might give false positives if libm is not really needed. In my original test.c example, I used only sinf() to a constant value, which made the compiler optimize out the sinf() call completely.

I'm using:

$ gcc --version
gcc (Gentoo 4.7.3-r1 p1.4, pie-0.5.5) 4.7.3
1
did you try to do what gcc recommends (looking at the failure messages)?Ashalynd
-fPIE and -pie makes no sense to me, in any case I don't want to compile as PIE.AttributedTensorField

1 Answers

4
votes

The following worked for me

ln -s `gcc -print-file-name=libc.a`
gcc -static-libgcc -L. -lc test.c

Then ldd a.out gives:

not a dynamic executable

Edit:

The OP wants to link one library dynamically and another statically. He have the example of linking libc statically and libm dynamically. That particular case I have not been able to achieve. However, the opposite is possible i.e. linking libc dynamically and libm statically.

ln -s `gcc -print-file-name=libm.a`
gcc test.c -L. -lm

then ldd a.out gives

libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x41960000)
/lib/ld-linux.so.2 (0x4193d000)

Note that the link order matters.e.g gcc -L. -lm test.c does not work.

This works with other libraries as well. For example gomp

gcc -fopenmp test.c

ldd shows libgomp.so.1. We can link it statically like this

ln -s `gcc -print-file-name=libgomp.a`
gcc -L. -fopenmp test.c

Now ldd a.out does not show libgomp.so.1. But in this case pthreads is still linked dynamically. To link pthreads statically requires that libc be linked statically as well.