[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.4 Linking a Library

Libraries often rely on code in other libraries. Traditionally the way to deal with this is to know what the dependencies are and, when linking an executable, be careful to list all of the dependencies on the link line in the correct order. If you have ever built an X Window application using a widget library, you will already be familiar with this notion.

Even though you only use the functions in the widget library directly, a typical link command would need to be:

 
$ gcc -o Xtest -I/usr/X11R6/include Xtest.c -L/usr/X11R6/lib \
-lXm -lXp -lXaw -lXmu -lX11 -lnsl -lsocket

With modern architectures, this problem has been solved by allowing libraries to be linked into other libraries, but this feature is not yet particularly portable. If you are trying to write a portable project, it is not safe to rely on native support for inter-library dependencies, especially if you want to have dependencies between static and shared archives. Some of the features discussed in this section were not fully implemented before Libtool 1.4, so you should make sure that you are using this version or newer if you need these features.

If you want to try the examples in this section to see what libtool does on your machine, you will first need to modify the source of ‘hello.c’ to introduce a dependency on ‘trim.c’:

 
#include <stdio.h>

extern char *trim ();
extern void free ();

void
hello (char *who)
{
  char *trimmed = trim (who);
  printf ("Hello, %s!\n", trimmed);
  free (trimmed);
}


You might also want to modify the ‘main.c’ file to exercise the new ‘trim’ functionality to prove that the newly linked executable is working:

 
void hello ();

int
main (int argc, char *argv[])
{
  hello ("\tWorld \r\n");
  exit (0);
}


Suppose I want to make two libraries, ‘libtrim’ and ‘libhello’. ‘libhello’ uses the ‘trim’ function in ‘libtrim’ but the code in ‘main’ uses only the ‘hello’ function in ‘libhello’. Traditionally, the two libraries are built like this:

 
$ rm hello *.a *.la *.o *.lo
$ gcc -c trim.c
$ ls
hello.c   main.c   trim.c   trim.o
$ ar cru libtrim.a trim.o
$ ranlib libtrim.a
$ gcc -c hello.c
$ ls
hello.c   hello.o   libtrim.a   main.c   trim.c   trim.o
$ ar cru libhello.a hello.o
$ ranlib libhello.a
$ ls
hello.c   libhello.a   main.c   trim.o
hello.o   libtrim.a    trim.c

Notice that there is no way to specify that ‘libhello.a’ won’t work unless it is also linked with ‘libtrim.a’. Because of this I need to list both libraries when I link the application. What’s more, I need to list them in the correct order:

 
$ gcc -o hello main.c libtrim.a libhello.a
/usr/bin/ld: Unsatisfied symbols:
   trim (code)
collect2: ld returned 1 exit status
$ gcc -o hello main.c libhello.a libtrim.a
$ ls
hello     hello.o      libtrim.a   trim.c
hello.c   libhello.a   main.c      trim.o
$ ./hello
Hello, World!

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.4.1 Inter-library Dependencies

libtool’s inter-library dependency support will use the native implementation if there is one available. If there is no native implementation, or if the native implementation is broken or incomplete, libtool will use an implementation of its own.

To build ‘libtrim’ as a standard Libtool library (see section The Libtool Library), as follows:

 
$ rm hello *.a *.o
$ ls
hello.c   main.c   trim.c
$ libtool gcc -c trim.c
rm -f .libs/trim.lo
gcc -c  -fPIC -DPIC trim.c -o .libs/trim.lo
gcc -c trim.c -o trim.o >/dev/null 2>&1
mv -f .libs/trim.lo trim.lo
$ libtool gcc -rpath /usr/local/lib -o libtrim.la trim.lo
rm -fr .libs/libtrim.la .libs/libtrim.* .libs/libtrim.*
/opt/gcc-lib/hp821/2.7.0/ld -b +h libtrim.sl.0 +b /usr/local/lib \
-o .libs/libtrim.sl.0.0  trim.lo
(cd .libs && rm -f libtrim.sl.0 && ln -s libtrim.sl.0.0 libtrim.sl.0)
(cd .libs && rm -f libtrim.sl && ln -s libtrim.sl.0.0 libtrim.sl)
ar cru .libs/libtrim.a  trim.o
ranlib .libs/libtrim.a
creating libtrim.la
(cd .libs && rm -f libtrim.la && ln -s ../libtrim.la libtrim.la)

When you build ‘libhello’, you can specify the libraries it depends on at the command line, like so:

 
$ libtool gcc -c hello.c
rm -f .libs/hello.lo
gcc -c  -fPIC -DPIC hello.c -o .libs/hello.lo
gcc -c hello.c -o hello.o >/dev/null 2>&1
mv -f .libs/hello.lo hello.lo
$ libtool gcc -rpath /usr/local/lib -o libhello.la hello.lo libtrim.la
rm -fr .libs/libhello.la .libs/libhello.* .libs/libhello.*

*** Warning: inter-library dependencies are not known to be supported.
*** All declared inter-library dependencies are being dropped.
*** The inter-library dependencies that have been dropped here will be
*** automatically added whenever a program is linked with this library
*** or is declared to -dlopen it.
/opt/gcc-lib/hp821/2.7.0/ld -b +h libhello.sl.0 +b /usr/local/lib \
-o .libs/libhello.sl.0.0  hello.lo
(cd .libs && rm -f libhello.sl.0 && ln -s libhello.sl.0.0 libhello.sl.0)
(cd .libs && rm -f libhello.sl && ln -s libhello.sl.0.0 libhello.sl)
ar cru .libs/libhello.a  hello.o
ranlib .libs/libhello.a
creating libhello.la
(cd .libs && rm -f libhello.la && ln -s ../libhello.la libhello.la)
$ ls
hello.c    hello.o       libtrim.la   trim.c   trim.o
hello.lo   libhello.la   main.c       trim.lo

Although, on HP-UX, libtool warns that it doesn’t know how to use the native inter-library dependency implementation, it will track the dependencies and make sure they are added to the final link line, so that you only need to specify the libraries that you use directly.

Now, you can rebuild ‘hello’ exactly as in the earlier example (see section Linking an Executable), as in:

 
$ libtool gcc -o hello main.c libhello.la
libtool: link: warning: this platform does not like uninstalled
libtool: link: warning: shared libraries
libtool: link: hello will be relinked during installation
gcc -o .libs/hello main.c /tmp/intro-hello/.libs/libhello.sl \
/tmp/intro-hello/.libs/libtrim.sl \
-Wl,+b -Wl,/tmp/intro-hello/.libs:/usr/local/lib
creating hello
$ ./hello
Hello, World!

Notice that even though you only specified the ‘libhello.la’ library at the command line, libtool remembers that ‘libhello.sl’ depends on ‘libtrim.sl’ and links that library too.

You can also link a static executable, and the dependencies are handled similarly:

 
$ libtool gcc -o hello-again -static main.c libhello.la
gcc -o hello main.c ./.libs/libhello.a /tmp/intro-hello/.libs/libtrim.a
$ ./hello-again
Hello, World!

For your own projects, provided that you use libtool, and that you specify the libraries you wish to link using the ‘.la’ pseudo-libraries, these dependencies can be nested as deeply as you like. You can also register dependencies on native libraries, though you will of course need to specify any dependencies that the native library itself has at the same time.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.4.2 Using Convenience Libraries

To rebuild ‘libtrim’ as a convenience library (see section Creating Convenience Libraries), use the following commands:

 
$ rm hello *.la
$ ls
hello.c   hello.lo   hello.o   main.c   trim.c   trim.lo   trim.o
$ libtool gcc -o libtrim.la trim.lo
rm -fr .libs/libtrim.la .libs/libtrim.* .libs/libtrim.*
ar cru .libs/libtrim.al trim.lo
ranlib .libs/libtrim.al
creating libtrim.la
(cd .libs && rm -f libtrim.la && ln -s ../libtrim.la libtrim.la)

Then, rebuild ‘libhello’, with an inter-library dependency on ‘libtrim’ (see section Inter-library Dependencies), like this:

 
$ libtool gcc -rpath `pwd`/_inst -o libhello.la hello.lo libtrim.la
rm -fr .libs/libhello.la .libs/libhello.* .libs/libhello.*

*** Warning: inter-library dependencies are not known to be supported.
*** All declared inter-library dependencies are being dropped.
*** The inter-library dependencies that have been dropped here will be
*** automatically added whenever a program is linked with this library
*** or is declared to -dlopen it.
rm -fr .libs/libhello.lax
mkdir .libs/libhello.lax
rm -fr .libs/libhello.lax/libtrim.al
mkdir .libs/libhello.lax/libtrim.al
(cd .libs/libhello.lax/libtrim.al && ar x /tmp/./.libs/libtrim.al)
/opt/gcc-lib/hp821/2.7.0/ld -b +h libhello.sl.0 +b /tmp/hello/_inst \
-o .libs/libhello.sl.0.0  hello.lo .libs/libhello.lax/libtrim.al/trim.lo
(cd .libs && rm -f libhello.sl.0 && ln -s libhello.sl.0.0 libhello.sl.0)
(cd .libs && rm -f libhello.sl && ln -s libhello.sl.0.0 libhello.sl)
rm -fr .libs/libhello.lax
mkdir .libs/libhello.lax
rm -fr .libs/libhello.lax/libtrim.al
mkdir .libs/libhello.lax/libtrim.al
(cd .libs/libhello.lax/libtrim.al && ar x /tmp/hello/./.libs/libtrim.al)
ar cru .libs/libhello.a  hello.o  .libs/libhello.lax/libtrim.al/trim.lo
ranlib .libs/libhello.a
rm -fr .libs/libhello.lax .libs/libhello.lax
creating libhello.la
(cd .libs && rm -f libhello.la && ln -s ../libhello.la libhello.la)
$ ls
hello.c    hello.o       libtrim.la   trim.c    trim.o
hello.lo   libhello.la   main.c       trim.lo

Compare this to the previous example of building ‘libhello’ and you can see that things are rather different. On HP-UX, partial linking is not known to work, so libtool extracts the objects from the convenience library, and links them directly into ‘libhello’. That is, ‘libhello’ is comprised of its own objects and the objects in ‘libtrim’. If ‘libtrim’ had had any dependencies, ‘libhello’ would have inherited them too. This technique is especially useful for grouping source files into subdirectories, even though all of the objects compiled in the subdirectories must eventually reside in a big library: compile the sources in each into a convenience library, and in turn link all of these into a single library which will then contain all of the constituent objects and dependencies of the various convenience libraries.

When you relink the hello executable, notice that ‘libtrim’ is not linked, because the ‘libtrim’ objects are already present in ‘libhello’:

 
$ libtool gcc -o hello main.c libhello.la
libtool: link: warning: this platform does not like uninstalled
libtool: link: warning: shared libraries
libtool: link: hello will be relinked during installation
gcc -o .libs/hello main.c /tmp/intro-hello/.libs/libhello.sl \
-Wl,+b -Wl,/tmp/intro-hello/.libs:/usr/local/lib
creating hello
$ ./hello
Hello, World!

[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated by Ben Elliston on July 10, 2015 using texi2html 1.82.