| Autoconf, Automake, and Libtool | ||
|---|---|---|
| <<< Previous | Introducing GNU Libtool | Next >>> |
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:
|
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! |
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 the section called 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 the section called 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.
To rebuild libtrim as a convenience library (see the section called 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 the section called 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! |
| <<< Previous | Home | Next >>> |
| Linking an Executable | Up | Executing Uninstalled Binaries |