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

10.2 The Libtool Library

A Libtool library is built from Libtool objects in the same way that a native (non-Libtool) library is built from native objects. Building a Libtool library with libtool is as easy as building an old style static archive. Generally, each of the sources is compiled to a Libtool object, and then these objects are combined to create the library.

If you want to try this to see what libtool does on your machine, put the following code in a file ‘hello.c’, in a directory of its own, and run the example shell commands from there:

#include <stdio.h>

hello (char *who)
  printf ("Hello, %s!\n", who);

The traditional way to make a (native) static library is as follows:

$ gcc -c hello.c
$ ls
hello.c  hello.o
$ ar cru libhello.a hello.o
$ ranlib libhello.a
$ ls
hello.c   hello.o   libhello.a

Notice that even when I just want to build an old static archive, I need to know that, in common with most Unices, I have to bless(14) my library with ranlib to make it work optimally on HP-UX.

Essentially, Libtool supports the building of three types of library: shared libraries; static libraries; and convenience libraries. In the following sections I will talk about each in turn, but first you will need to understand how to create and use position independent code, as explained in the next section.

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

10.2.1 Position Independent Code

On most architectures, when you compile source code to object code, you need to specify whether the object code should be position independent or not. There are occasional architectures which don’t make the distinction, usually because all object code is position independent by virtue of the ABI(15), or less often because the load address of the object is fixed at compile time (which implies that shared libraries are not supported by such a platform). If an object is compiled as position independent code (PIC), then the operating system can load the object at any address in preparation for execution. This involves a time overhead, in replacing direct address references with relative addresses at compile time, and a space overhead, in maintaining information to help the runtime loader fill in the unresolved addresses at runtime. Consequently, PIC objects are usually slightly larger and slower at runtime than the equivalent non-PIC object. The advantage of sharing library code on disk and in memory outweigh these problems as soon as the PIC object code in shared libraries is reused.

PIC compilation is exactly what is required for objects which will become part of a shared library. Consequently, libtool builds PIC objects for use in shared libraries and non-PIC objects for use in static libraries. Whenever libtool instructs the compiler to generate a PIC object, it also defines the preprocessor symbol, ‘PIC’, so that assembly code can be aware of whether it will reside in a PIC object or not.

Typically, as libtool is compiling sources, it will generate a ‘.lo’ object, as PIC, and a ‘.o’ object, as non-PIC, and then it will use the appropriate one of the pair when linking executables and libraries of various sorts. On architectures where there is no distinction, the ‘.lo’ file is just a soft link to the ‘.o’ file.

In practice, you can link PIC objects into a static archive for a small overhead in execution and load speed, and often you can similarly link non-PIC objects into shared archives. If you find that you need to do this, libtool provides several ways to override the default behavior (see section Creating libtool).

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

10.2.2 Creating Shared Libraries

From Libtool’s point of view, the term ‘shared library’ is somewhat of a misnomer. Since Libtool is intended to abstract away the details of library building, it doesn’t matter whether Libtool is building a shared library or a static archive. Of course, Libtool will always try to build a shared library by default on the platforms to which it has been ported (see section PLATFORMS), but will equally fall back to building a static archive if the host architecture does not support shared libraries, or if the project developer deliberately configures Libtool to always build static archives only. These libraries are more properly called ‘Libtool libraries’; the underlying native library will usually be a shared library, except as described above.

To create a Libtool library on my HP-UX host, or indeed anywhere else that libtool works, run the following commands:

$ rm hello.o libhello.a
$ libtool gcc -c hello.c
mkdir .libs
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
$ ls
hello.c   hello.lo   hello.o
$ libtool gcc -rpath /usr/local/lib -o libhello.la hello.lo
rm -fr .libs/libhello.la .libs/libhello.* .libs/libhello.*
/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.lo   hello.o   libhello.la

This example illustrates several features of libtool. Compare the command line syntax with the previous example (see section The Libtool Library). They are both very similar. Notice, however, that when compiling the ‘hello.c’ source file, libtool creates two objects. The first, ‘hello.lo’, is the Libtool object which we use for Libtool libraries, and the second, ‘hello.o’ is a standard object. On HP-UX, libtool knows that Libtool objects should be compiled with position independent code, hence the extra switches when creating the first object.

When you run libtool from the command line, you must also specify a compiler for it to call. Similarly when you create a libtool script with ltconfig, a compiler is chosen and interrogated to discover what characteristics it has. See section Creating libtool.

Prior to release 1.4 of Libtool, ltconfig probed the build machine for a suitable compiler, by searching first for gcc and then cc. The functionality of ltconfig is being migrated into the ‘AC_PROG_LIBTOOL’ macro, such that there will be no ltconfig script in Libtool release 1.5. The current release is part way between the two. In all cases, you can specify a particular compiler by setting the ‘CC’ environment variable.

It is important to continue to use the same compiler when you run libtool as the compiler that was used when you created the libtool script. If you create the script with ‘CC’ set to gcc, and subsequently try to compile using, say:

$ libtool c89 -rpath /usr/local/lib -c hello.c

libtool will try to call c89 using the options it discovered for gcc. Needless to say, that doesn’t work!

The link command specifies a Libtool library target, ‘libhello.la’, compiled from a single Libtool object, ‘hello.lo’. Even so, libtool knows how to build both static and shared archives on HP-UX – underneath the libtool abstraction both are created. libtool also understands the particulars of library linking on HP-UX: the static archive, ‘libhello.a’, is blessed; the system (and compiler) dependent compiler and linker flags, versioning scheme and .sl extension are utilised for the shared archive, ‘libhello.sl’. On another host, all of these details may be completely different, yet with exactly the same invocation, libtool will call the native tools with the appropriate options to achieve the same result. Try it on your own machines to see any differences.

It is the ‘-rpath’ switch that tells libtool that you want to build a Libtool library (with both the shared and static components where possible). If you omit the ‘-rpath’ switch, libtool will build a convenience library instead, see Creating convenience Libraries. The ‘-rpath’ switch is doubly important, because it tells libtool that you intend to install ‘libhello.la’ in ‘/usr/local/lib’. This allows libtool to finalize the library correctly after installation on the architectures that need it, see Installing a Library.

Finally, notice that only the Libtool library, ‘libhello.la’, is visible after a successful link. The various files which form the local implementation details of the Libtool library are in a hidden subdirectory, but in order for the abstraction to work cleanly you shouldn’t need to worry about these too much.

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

10.2.3 Creating Static Libraries

In contrast, libtool will create a static library if either the ‘-static’ or ‘-all-static’ switches are specified on the link line for a Libtool library:

$ libtool gcc -static -o libhello.la hello.lo
rm -fr .libs/libhello.la .libs/libhello.* .libs/libhello.*
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)

Note that since libtool will only create a static archive, the ‘-rpath’ switch is not required: once a static library has been installed, there is no need to perform additional finalization for the library to be used from the installed location(16), or to track runtime search paths when installing a static archive.

When you link an executable against this ‘libhello.la’, the objects from the static archive will be statically linked into the executable. The advantage of such a library over the traditional native static archive is that all of the dependency information from the Libtool library is used. For an example, See section Creating Convenience Libraries.

libtool is useful as a general library building toolkit, yet people still seem to regress to the old way of building libraries whenever they want to use static archives. You should exploit the consistent interface of libtool even for static archives. If you don’t want to use shared archives, use the ‘-static’ switch to build a static Libtool library.

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

10.2.4 Creating Convenience Libraries

The third type of library which can be built with libtool is the convenience library. Modern compilers are able to create partially linked objects: intermediate compilation units which comprise several compiled objects, but are neither an executable or a library. Such partially linked objects must be subsequently linked into a library or executable to be useful. Libtool convenience libraries are partially linked objects, but are emulated by libtool on platforms with no native implementation.

If you want to try this to see what libtool does on your machine, put the following code in a file ‘trim.c’, in the same directory as ‘hello.c’ and ‘libhello.la’, and run the example shell commands from there:

#include <string.h>

#define WHITESPACE_STR  " \f\n\r\t\v"

 * Remove whitespace characters from both ends of a copy of
 *  '\0' terminated STRING and return the result.
char *
trim (char *string)
  char *result = 0;

  /* Ignore NULL pointers.  */
  if (string)
      char *ptr = string;

      /* Skip leading whitespace.  */
      while (strchr (WHITESPACE_STR, *ptr))

      /* Make a copy of the remainder.  */
      result = strdup (ptr);

      /* Move to the last character of the copy.  */
      for (ptr = result; *ptr; ++ptr)
        /* NOWORK */;

      /* Remove trailing whitespace.  */
      for (--ptr; strchr (WHITESPACE_STR, *ptr); --ptr)
          *ptr = '\0';

  return result;

To compile the convenience library with libtool, you would do this:

$ 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 -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)

Additionally, you can use a convenience library as an alias for a set of zero or more object files and some dependent libraries. If you need to link several objects against a long list of libraries, it is much more convenient to create an alias:

$ libtool gcc -o libgraphics.la -lpng -ltiff -ljpeg -lz
rm -fr .libs/libgraphics.la .libs/libgraphics.* .libs/libgraphics.*
ar cru .libs/libgraphics.al
ranlib .libs/libgraphics.al
creating libgraphics.la
(cd .libs && rm -f libgraphics.la && \
ln -s ../libgraphics.la libgraphics.la)

Having done this, whenever you link against ‘libgraphics.la’ with libtool, all of the dependent libraries will be linked too. In this case, there are no actual objects compiled into the convenience library, but you can do that too, if need be.

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

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