Friday, June 27, 2008

gcc: statically linked shared library

Usually it's painful to distribute binaries of shared libraries across different linux distributions. They have different set of versions of shared libraries. For example if you have a library that uses libpq.so.5.0 to communicate with PostgreSQL you will fail to link against your library on distribution that has libpq.so.5.1. But there is no difference for you which to use: libpq.so.5.0 or libpq.so.5.1, anyway you will be able to connect to PostgreSQL and do DB related stuff. There is an option to compile a shared library with statically linked shared libraries in it. Let's try to build library that uses PostgreSQL's libpq: At first you just create objects for you library:

gcc -fPIC test.c -c
and compile shared library:
gcc test.o -o libtest.so -static-libgcc -shared -Wl,-soname=libtest.so\
-Wl,-static -lpq -lssl -lcrypt -lcrypto -lz
-static-libgcc is needed to link against libgcc statically[not all versions of gcc need that]. Shared libraries should go after -Wl,-static option. Be aware that you have to specify all shared libraries that can be involved on linking stage, otherwise they should be specified for binary that will be linked against libtest. Here I specified libpq, libssl, libcrypt, libcrypto, libz, to be linked statically. libpq also depends on krb5, but there's no static version of it in my distribution, so I'll link it to final binary. ldd output:
ldd libtest.so 
 statically linked
Now you can link your binary against libtest:
g++ usetest.cc -o usetest -L./ -ltest -lkrb5
That's all. ldd shows:
ldd usetest
 linux-gate.so.1 =>  (0xb7f37000)
 lib1.so => /tmp/work/lib1.so (0xb7c37000)
 libkrb5.so.3 => /usr/lib/libkrb5.so.3 (0xb7bad000)
 libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7aca000)
 libm.so.6 => /lib/libm.so.6 (0xb7aa4000)
 libc.so.6 => /lib/libc.so.6 (0xb7964000)
 libk5crypto.so.3 => /usr/lib/libk5crypto.so.3 (0xb7940000)
 libcom_err.so.2 => /lib/libcom_err.so.2 (0xb793c000)
 libkrb5support.so.0 => /usr/lib/libkrb5support.so.0 (0xb7934000)
 libresolv.so.2 => /lib/libresolv.so.2 (0xb7921000)
 libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0xb7916000)
 /lib/ld-linux.so.2 (0xb7f38000)
 libdl.so.2 => /lib/libdl.so.2 (0xb7912000)
No libpq or libssl, libcrypt, libcrypto, libz. Congratulations. As far as I know, not all versions of ld support this. I succeeded with 'GNU ld version 2.17.50.0.6 20061020' and 'GNU ld (GNU Binutils) 2.18', but failed with 'GNU ld version 2.16.1'[on x86_64]

No comments: