5

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
Community
  • 1
  • 1

1 Answers1

4

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.

Community
  • 1
  • 1
Z boson
  • 32,619
  • 11
  • 123
  • 226
  • You appear to have compiled a static binary. The goal is to compile a binary that has some library statically linked into it, while having a different library dynamically linked. E.g. as in the original question having libc linked statically and libm linked dynamically. This a.out file in your example is only static. – AttributedTensorField Oct 03 '14 at 00:50
  • @AttributedTensorField, I updated my answer with more details. I'm not sure how to link `libc` statically and `libm` dynamically. But the reverse is certainly possible. I think in general you link other libraries statically or dynamically as long as `ligc` is linked dynamically. `pthreads` is one exception though. I'm not sure what happens if you link e.g. musl libc with libm instead of gnu libc. – Z boson Oct 03 '14 at 08:36
  • There is a problem with the source code I included in my example. Since sinf() is called with a constant argument the compiler computes the result before compilation and optimizes it out. Hence libm is not needed. When I change the source to actually require libm, I get the following error with your example when I attempt to compile: test.c:(.text+0x28): undefined reference to `sinf'; I will update the question with a proper code example. – AttributedTensorField Oct 03 '14 at 14:16
  • You can also see that the suggested commands fail to produce a binary that contains any of libm by looking at the file sizes. The size arrived at using gcc -L. -lm test.c is identical to just using gcc test.c with no other arguments. – AttributedTensorField Oct 03 '14 at 14:22
  • @Z boson, more in general. I have a library (libmpx) which I only have the .so (dynamic) version of, which I must link in dynamically, but I want everything else (libc, libm, etc) linked in statically. – AttributedTensorField Oct 03 '14 at 16:24
  • @AttributedTensorField, I got it working. The link order matters `gcc test.c -L. -lm` works but `gcc -L. -lm test.c` does not. I updated my answer (again). – Z boson Oct 03 '14 at 16:25
  • @Z boson, great, thanks. I see now that it works with libm dynamically and libc statically. If I try this with libc as static I get the same weird error with -fPIE and -pie, maybe this is not possible? – AttributedTensorField Oct 03 '14 at 16:30
  • @isedev, having a secondary dynamically linked libc in addition to the static one is fine with me, but how do you do this? How do you avoid the error that I'm receiving? – AttributedTensorField Oct 03 '14 at 16:31
  • @AttributedTensorField, you mean it works with libm static and libc dynamic? – Z boson Oct 03 '14 at 16:34
  • @Z boson, yes, sorry. I meant with libm static and libc dynamic. – AttributedTensorField Oct 03 '14 at 17:03