How to link a library statically?
(keywords: gcc, static link, statically linked, gcc -static fails)
When trying to compile a binary with a statically linked library I
first read the gcc manpage, and it said:
-static
On systems that support dynamic linking, this prevents linking with the shared
libraries. On other systems, this option has no effect.
A website about Statically Linking X11R6.3 gave the further hint to put the
libraries between -static and -dynamic. When starting
with a command like
gcc -o testprog testprog.c obj1.o obj2.o -llib1 -llib2 -llib3
and now wanting to statically link lib2 while keeping the other bindings
dynamical, that would yield
gcc -o testprog testprog.c obj1.o obj2.o -llib1 -static -llib2 -dynamic -llib3
However the tests I attempted with the
tcptrack software
(where I tried to statically link libpcap) were not successful but
generated a compiler error -- while generating the binary with all libs
bound dynamically was no problem.
Solution
The solution is as follows:
- In order to bind a library statically, first identify the .a file
that belongs to the library, e.g. in case of libpcap and using the
RPM package manager:
$ rpm -ql libpcap|grep a$
/usr/lib/libpcap.a
- Now the .a file is an ar archive which contains object files.
Create a new directory in the source tree, e.g. src/objects, change into
the new directory and unpack the .a file with
ar x ...path_to.../library.a
- Now compile your program in the standard way, e. g. with configure and
make (do not execute make install). Observe what the last commands
of the make step are -- in case of the tcptrack tool the last step was:
g++ -g -O2 -pthread -o tcptrack Collector.o main.o TCContainer.o TextUI.o PacketBuffer.o \
Sniffer.o TCPConnection.o util.o SortedIterator.o IPv4Packet.o IPv4Address.o TCPPacket.o \
NetworkPacket.o IPv4TCPPacket.o IPv4TCPCapture.o TCPTrack.o SocketPair4.o AppError.o PcapError.o \
GenericError.o Guesser.o -lrt -lpthread -lpcap -lncurses -lnsl -lnsl
Here the bold part (-lpcap) must go, because this is the library that is
to be linked statically. Instead the new object files must be added to the compiler call:
g++ -g -O2 -pthread -o tcptrack objects/*.o \
Collector.o main.o TCContainer.o TextUI.o PacketBuffer.o \
Sniffer.o TCPConnection.o util.o SortedIterator.o IPv4Packet.o IPv4Address.o TCPPacket.o \
NetworkPacket.o IPv4TCPPacket.o IPv4TCPCapture.o TCPTrack.o SocketPair4.o AppError.o PcapError.o \
GenericError.o Guesser.o -lrt -lpthread -lncurses -lnsl -lnsl
- That's it -- in this example, calling ldd tcptrack will prove that the
new binary contains pcap and the loader won't try to dynamically bind it.
Questions? More information?
If someone can explain why the suggested -static fails, I'd add that piece
of information to this page. If there's an easier way (e.g. without manually unpacking
the .a file), I'd like to hear of it as well.
Improvements
[2014/02/28] Got a mail today from Florian Schüller which suggested the
following improvement:
"When using a makefile it is sufficient to add LDLIBS+=/usr/lib/library.a
or simply /usr/lib/library.a after the *.c or *.o files -- that way
it is not necessary to unpack the *.a file."
|