Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
iakovlev.org

Autoconf, Automake, and Libtool

Авторы :

10. Introducing GNU Libtool

Libtool takes care of all the peculiarities of creating, linking and loading shared and static libraries across a great number of platforms, providing a uniform command line interface to the developer. By using Libtool to manage your project libraries, you only need to concern yourself with Libtool's interface: when someone else builds your project on a platform with a different library architecture, Libtool invokes that platform's compiler and linker with the correct environment and command line switches. It will install libraries and library using binaries according to the conventions of the host platform, and follows that platform's rules for library versioning and library interdependencies.

Libtool empowers you to treat a library as an implementation of a well defined interface of your choosing. This Libtool library may be manifest as a collection of compiler objects, a static ar archive, or a position independent runtime loadable object. By definition, native libraries are fully supported by Libtool since they are an implementation detail of the Libtool library abstraction. It's just that until Libtool achieves complete world domination, you might need to bear in mind what is going on behind the command line interface when you first add Libtool support to your project.

The sheer number of uses of the word `library' in this book could be easily very confusing. In this chapter and throughout the rest of the book, I will refer to various kinds of libraries as follows:

`native'
Low level libraries, that is, libraries provided by the host architecture.

`Libtool library'
The kind of library built by Libtool. This encompasses both the shared and static native components of the implementation of the named library.

`pseudo-library'
The high level `.la' file produced by Libtool. The `pseudo-library' is not a library in its own right, but is treated as if it were from outside the Libtool interface.

Futhermore, in the context of Libtool, there is another subtle (but important) distinction to be drawn:

`static library'
A Libtool library which has no shared archive component.

`static archive'
The static component of a Libtool library.

Many developers use Libtool as a black box which requires adding a few macros to `configure.in' and tweaking a project's `Makefile.am'. The next chapter addresses that school of thought in more detail. In this chapter I will talk a little about the inner workings of Libtool, and show you how it can be used directly from your shell prompt -- how to build various kinds of library, and how those libraries can be used by an application. Before you can do any of this, you need to create a libtool script that is tailored to the platform you are using it from.

10.1 Creating libtool

When you install a distribution of Libtool on your development machine, a host specific libtool program is installed. The examples in the rest of this chapter use this installed instance of libtool.

When you start to use Libtool in the build process of your own projects, you shouldn't require that libtool be installed on the user's machine, particularly since they may have a different libtool version to the one used to develop your project. Instead, distribute some of the files installed by the Libtool distribution along with your project, and custom build a libtool script on the user's machine before invoking ./libtool to build any objects. If you use Autoconf and Automake, these details are taken care of automatically (see section Using GNU Libtool with configure.in and Makefile.am). Otherwise you should copy the following files from your own Libtool installation into the source tree of your own project:

 
$ ls /usr/local/share/libtool
 config.guess   config.sub   libltdl   ltconfig   ltmain.in
 $ cp /usr/local/share/libtool/config.* /usr/local/share/libtool/lt* .
 $ ls
 config.guess   config.sub   ltconfig   ltmain.in
 

You must then arrange for your project build process to create an instance of libtool on the user's machine, so that it is dependent on their target system and not your development machine. The creation process requires the four files you just added to your project. Let's create a libtool instance by hand, so that you can see what is involved:

 
$ ./config.guess
 hppa1.1-hp-hpux10.20
 $ ./ltconfig --disable-static --with-gcc ./ltmain.sh hppa1.1-hp-hpux10.20
 checking host system type... hppa1.1-hp-hpux10.20
 checking build system type... hppa1.1-hp-hpux10.20
 checking whether ln -s works... yes
 checking for ranlib... ranlib
 checking for BSD-compatible nm... /usr/bin/nm -p
 checking for strip... strip
 checking for gcc... gcc
 checking whether we are using GNU C... yes
 checking for objdir... .libs
 checking for object suffix... o
 checking for executable suffix... no
 checking for gcc option to produce PIC... -fPIC
 checking if gcc PIC flag -fPIC works... yes
 checking if gcc static flag -static works... yes
 checking if gcc supports -c -o file.o... yes
 checking if gcc supports -c -o file.lo... yes
 checking if gcc supports -fno-rtti -fno-exceptions ... no
 checking for ld used by GCC... /opt/gcc-lib/hp821/2.7.0/ld
 checking if the linker (/opt/gcc-lib/hp821/2.7.0/ld) is GNU ld... no
 checking whether the linker (/opt/gcc-lib/hp821/2.7.0/ld) supports \
 shared libraries... yes
 checking how to hardcode library paths into programs... relink
 checking whether stripping libraries is possible... yes
 checking for /opt/gcc-lib/hp821/2.7.0/ld option to reload object \
 files... -r
 checking dynamic linker characteristics... hpux10.20 dld.sl
 checking command to parse /usr/bin/nm -p output... ok
 checking if libtool supports shared libraries... yes
 checking whether to build shared libraries... yes
 checking whether to build static libraries... yes
 creating libtool
 $ ls
 config.guess   config.sub   ltconfig
 config.log     libtool      ltmain.sh
 $ ./libtool --version
 ltmain.sh (GNU libtool) 1.3c (1.629 1999/11/02 12:33:04)
 

The examples in this chapter are all performed on a HP-UX system, but the principles depicted are representative of any of the platforms to which Libtool has been ported (see section B. PLATFORMS).

Often you don't need to specify any options, and if you omit the configuration triplet (see section 3.4 Configuration Names), ltconfig will run config.guess itself. There are several options you can specify which affect the generated libtool, See section `Invoking ltconfig' in The Libtool Manual. Unless your project has special requirements, you can usually use the simplified:

 
$ ./ltconfig ./ltmain.sh
 

With the current release of Libtool, you must be careful that `$CC' is set to the same value when you call ltconfig as when you invoke the libtool it generates, otherwise libtool will use the compiler specified in `$CC' currently, but with the semantics probed by ltconfig for the compiler specified in `$CC' at the time it was executed.

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>
 
 void
 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.

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 10.1 Creating libtool).

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 B. 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 10.2 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 10.1 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 10.6 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.

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.

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))
         ++ptr;
 
       /* Make a copy of the remainder.  */
       result = strdup (ptr);
 
       /* Move to the last character of the copy.  */
       for (ptr = result; *ptr; ++ptr)
         /* NOWORK */;
       --ptr;
 
       /* 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.

10.3 Linking an Executable

Continuing the parallel between the syntax used to compile with libtool and the syntax used when building old static libraries, linking an executable is a matter of combining compilation units into a binary in both cases. We tell the compiler which objects and libraries are required, and it creates an executable for us.

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

 
void hello ();
 
 int
 main (int argc, char *argv[])
 {
   hello ("World");
   exit (0);
 }
 
 
 

To compile an executable which uses the non-Libtool `libhello.a' library built previously (see section 10.2 The Libtool Library), I would use the following commands:

 
$ gcc -o hello main.c libhello.a
 $ ./hello
 Hello, World!
 

To create a similar executable on the HP-UX host, using libtool this time:

 
$ 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/hello/.libs/libhello.sl  \
 -Wl,+b -Wl,/tmp/hello/.libs:/usr/local/lib
 creating hello
 $ ls
 hello     hello.lo   libhello.la
 hello.c   hello.o    main.c
 $ ./hello
 Hello, World!
 

Notice that you linked against the Libtool library, `libhello.la', but otherwise the link command you used was not really very different from non-Libtool static library link command used earlier. Still, libtool does several things for you: it links with the shared archive rather than the static archive; and it sets the compiler options so that the program can be run in place, even though it is linked against the uninstalled Libtool library. Using a make rule without the benefit of libtool, it would be almost impossible to reliably link a program against an uninstalled shared library in this way, since the particular switches needed would be different between the various platforms you want the project to work with. Also without the extra compiler options libtool adds for you, the program will search only the standard library direcotories for a shared `libhello'.

The link warning tells you that libtool knows that on HP-UX the program will stop working if it is copied directly to the installation directory; To prevent it breaking, libtool will relink the program when it is installed, see 10.6 Installing a Library.

I discussed the creation of static Libtool libraries in Creating Static Libraries. If you link an executable against such a library, the library objects, by definition, can only be statically linked into your executable. Often this is what you want if the library is not intended for installation, or if you have temporarily disabled building of shared libraries in your development tree to speed up compilation while you are debugging.

Sometimes, this isn't what you want. You might need to install a complete Libtool library with shared and static components, but need to generate a static executable linked against the same library, like this:

 
$ libtool gcc -static -o hello main.c libhello.la
 gcc -o hello main.c ./.libs/libhello.a
 

In this case, the `-static' switch instructs libtool to choose the static component of any uninstalled Libtool library.

You could have specified `-all-static' instead, which instructs libtool to link the executable with only static libraries (wherever possible), for any Libtool or native libraries used.

Finally, you can also link executables against convenience libraries. This makes sense when the convenience library is being used as an alias (see section Creating Convenience Libraries). Notice how `libgraphics.la' expands to its own dependencies in the link command:

 
$ libtool gcc -o image loader.o libgraphics.la
 libtool: link: warning: this platform does not like uninstalled
 libtool: link: warning: shared libraries
 libtool: link: image will be relinked during installation
 gcc -o .libs/image loader.o -lpng -ltiff -ljpeg -lz \
 -Wl,+b -Wl,/tmp/image/.libs:/usr/local/lib
 creating image
 

You can also link against convenience libraries being used as partially linked objects, so long as you are careful that each is linked only once. Remember that a partially linked object is just the same as any other object, and that if you load it twice (even from different libraries), you will get multiple definition errors when you try to link your executable. This is almost the same as using the `-static' switch on the libtool link line to link an executable with the static component of a normal Libtool library, except that the convenience library comprises PIC objects. When statically linking an executable, PIC objects are best avoided however, see 10.2.1 Position Independent Code.

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!
 

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 10.2 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 10.3 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.

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 10.4.1 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!
 

10.5 Executing Uninstalled Binaries

If you look at the contents of the hello program you built in the last section, you will see that it is not actually a binary at all, but a shell script which sets up the environment so that when the real binary is called it finds its the shared libraries in the correct locations. Without this script, the runtime loader might not be able to find the uninstalled libraries. Or worse, it might find an old version and load that by mistake!

In practice, this is all part of the unified interface libtool presents so you needn't worry about it most of the time. The exception is when you need to look at the binary with another program, to debug it for example:

 
$ ls
 hello     hello.lo   libhello.la   main.c   trim.lo
 hello.c   hello.o    libtrim.la    trim.c   trim.o
 $ libtool gdb hello
 GDB is free software and you are welcome to distribute copies of it
 under certain conditions; type "show copying" to see the conditions.
 There is absolutely no warranty for GDB; type "show warranty" for
 details.
 GDB 4.18 (hppa1.0-hp-hpux10.20),
 Copyright 1999 Free Software Foundation, Inc...
 (gdb) bre main
 Breakpoint 1 at 0x5178: file main.c, line 6.
 (gdb) run
 Starting program: /tmp/intro-hello/.libs/hello
 Breakpoint 1, main (argc=1, argv=0x7b03aa70) at main.c:6
 6           return hello("World");
 ...
 

10.6 Installing a Library

Now that the library and an executable which links with it have been successfully built, they can be installed. For the sake of this example I will cp the objects to their destination, though libtool would be just as happy if I were to use install with the long, requisite list of parameters.

It is important to install the library to the `-rpath' destination which was specified when it was linked earlier, or at least that it be visible from that location when the runtime loader searches for it. This rule is not enforced by libtool, since it is often desirable to install libraries to a staging(17) area. Of course, the package must ultimately install the library to the specified `-rpath' destination for it to work correctly, like this:

 
$ libtool cp libtrim.la /usr/local/lib
 cp .libs/libtrim.sl.0.0 /usr/local/lib/libtrim.sl.0.0
 (cd /usr/local/lib && rm -f libtrim.sl.0 && \
 ln -s libtrim.sl.0.0 libtrim.sl.0)
 (cd /usr/local/lib && rm -f libtrim.sl && \
 ln -s libtrim.sl.0.0 libtrim.sl)
 chmod 555 /usr/local/lib/libtrim.sl.0.0
 cp .libs/libtrim.lai /usr/local/lib/libtrim.la
 cp .libs/libtrim.a /usr/local/lib/libtrim.a
 ranlib /usr/local/lib/libtrim.a
 chmod 644 /usr/local/lib/libtrim.a
 ----------------------------------------------------------------------
 Libraries have been installed in:
    /usr/local/lib
 
 If you ever happen to want to link against installed libraries
 in a given directory, LIBDIR, you must either use libtool, and
 specify the full pathname of the library, or use -LLIBDIR
 flag during linking and do at least one of the following:
    - add LIBDIR to the SHLIB_PATH environment variable
      during execution
    - use the -Wl,+b -Wl,LIBDIR linker flag
 
 See any operating system documentation about shared libraries for
 more information, such as the ld(1) and ld.so(8) manual pages.
 ----------------------------------------------------------------------
 

Again, libtool takes care of the details for you. Both the static and shared archives are copied into the installation directory and their access modes are set appropriately. libtool blesses the static archive again with ranlib, which would be easy to forget without the benefit of libtool, especially if I develop on a host where the library will continue to work without this step. Also, libtool creates the necessary links for the shared archive to conform with HP-UXs library versioning rules. Compare this to what you see with the equivalent commands running on GNU/Linux to see how libtool applies these rules according to the requirements of its host. The block of text libtool shows at the end of the installation serves to explain how to link executables against the newly installed library on HP-UX and how to make sure that the executables linked against it will work. Of course, the best way to ensure this is to use libtool to perform the linking. I'll leave the details of linking against an installed Libtool library as an exercise - everything you need to know can be extrapolated from the example of linking against an uninstalled Libtool library, See section 10.3 Linking an Executable.

On some architectures, even shared archives need to be blessed on installation. For example, GNU/Linux requires that ldconfig be run when a new library is installed. Typically, a library will be installed to its target destination after being built, in which case libtool will perform any necessary blessing during installation. Sometimes, when building a binary package for installation on another machine, for example, it is not desirable to perform the blessing on the build machine. No problem, libtool takes care of this too! libtool will detect if you install the library to a destination other than the one specified in the `-rpath' argument passed during the archive link, and will simply remind you what needs to be done before the library can be used:

 
$ mkdir -p /usr/local/stow/hello-1.0/lib
 $ libtool cp libtrim.la /usr/local/stow/hello-1.0/lib
 cp .libs/libtrim.sl.0.0 /usr/local/stow/hello-1.0/lib/libtrim.sl.0.0
 (cd /usr/local/stow/hello-1.0/lib && rm -f libtrim.sl.0 && \
 ln -s libtrim.sl.0.0 libtrim.sl.0)
 (cd /usr/local/stow/hello-1.0/lib && rm -f libtrim.sl && \
 ln -s libtrim.sl.0.0 libtrim.sl)
 chmod 555 /usr/local/stow/hello-1.0/lib/libtrim.sl.0.0
 cp .libs/libtrim.lai /usr/local/stow/hello-1.0/lib/libtrim.la
 cp .libs/libtrim.a /usr/local/stow/hello-1.0/lib/libtrim.a
 ranlib /usr/local/stow/hello-1.0/lib/libtrim.a
 chmod 644 /usr/local/stow/hello-1.0/lib/libtrim.a
 libtool: install: warning: remember to run
 libtool: install: warning: libtool --finish /usr/local/lib
 

If you will make the installed libraries visible in the destination directory with symbolic links, you need to do whatever it is you do to make the library visible, and then bless the library in that location with the libtool --finish /usr/local/lib command:

 
$ cd /usr/local/stow
 $ stow hello-1.0
 $ libtool --finish /usr/local/lib
 

If you are following the examples so far, you will also need to install the Libtool library, `libhello.la', before you move on to the next section:

 
$ libtool cp libhello.la /usr/local/lib
 cp .libs/libhello.sl.0.0 /usr/local/lib/libhello.sl.0.0
 (cd /usr/local/lib && rm -f libhello.sl.0 && \
 ln -s libhello.sl.0.0 libhello.sl.0)
 (cd /usr/local/lib && rm -f libhello.sl && \
 ln -s libhello.sl.0.0 libhello.sl)
 chmod 555 /usr/local/lib/libhello.sl.0.0
 cp .libs/libhello.lai /usr/local/lib/libhello.la
 cp .libs/libhello.a /usr/local/lib/libhello.a
 ranlib /usr/local/lib/libhello.a
 chmod 644 /usr/local/lib/libhello.a
 ----------------------------------------------------------------------
 Libraries have been installed in:
    /usr/local/lib
 
 If you ever happen to want to link against installed libraries
 in a given directory, LIBDIR, you must either use libtool, and
 specify the full pathname of the library, or use -LLIBDIR
 flag during linking and do at least one of the following:
    - add LIBDIR to the SHLIB_PATH environment variable
      during execution
    - use the -Wl,+b -Wl,LIBDIR linker flag
 
 See any operating system documentation about shared libraries for
 more information, such as the ld(1) and ld.so(8) manual pages.
 ----------------------------------------------------------------------
 

Once a Libtool library is installed, binaries which link against it will hardcode the path to the Libtool library, as specified with the `-rpath' switch when the library was built. libtool always encodes the installation directory into a Libtool library for just this purpose. Hardcoding directories in this way is a good thing, because binaries linked against such libraries will continue to work if there are several incompatible versions of the library visible to the runtime loader (say a Trojan `libhello' in a user's LD_LIBRARY_PATH, or a test build of the next release). The disadvantage to this system is that if you move libraries to new directories, executables linked in this way will be unable to find the libraries they need. Moving any library is a bad idea however, doubly so for a Libtool library which has its installation directory encoded internally, so the way to avoid problems of this nature is to not move libraries around after installation!

10.7 Installing an Executable

Installing an executable uses exactly the same command line that I used to install the library earlier:

 
$ libtool cp hello /usr/local/bin
 gcc -o /tmp/libtool-28585/hello main.c /usr/local/lib/libhello.sl \
 /usr/local/lib/libtrim.sl -Wl,+b -Wl,/usr/local/lib
 cp /tmp/libtool-28585/hello /usr/local/bin/hello
 $ /usr/local/bin/hello
 Hello, World!
 

As libtool said earlier, during the initial linking of the hello program in the build directory, hello must be rebuilt before installation. This is a peculiarity of HP-UX (and a few other architectures) which you won't see if you are following the examples on a GNU/Linux system. In the shell trace above, libtool has built an installable version of the hello program, saving me the trouble of remembering (or worse -- coding for) the particulars of HP-UX, which runs correctly from the installed location.

As a matter of interest, if you look at the attributes of the installed program using HP-UX's chatr command:

 
$ chatr /usr/local/bin/hello
 /usr/local/bin/hello: 
          shared executable 
          shared library dynamic path search:
              SHLIB_PATH     disabled  second 
              embedded path  enabled   first  /usr/local/lib
          internal name:
              /tmp/libtool-28585/hello
          shared library list:
              static    /usr/local/lib/libhello.sl.0
              static    /usr/local/lib/libtrim.sl.0
              dynamic   /lib/libc.1
          shared library binding:
              deferred 
 ...
 

You can see that the runtime library search path for the installed hello program has been set to find the installed `libhello.sl.0' shared archive, preventing it from accidentally loading a different library (with the same name) from the default load path. This is a feature of libtool, and a very important one at that, and although it may not seem like the right way to do things initially, it saves a lot of trouble when you end up with several versions of a library installed in several locations, since each program will continue to use the version that it was linked with, subject to library versioning rules, see 11.4 Library Versioning.

Without the help of libtool, it is very difficult to prevent programs and libraries in the build tree from loading earlier (compatible) versions of a shared archive that were previously installed without an intimate knowledge of the build hosts architecture. Making it work portably would be nigh impossible! You should experiment with changes to the uninstalled library and satisfy yourself that the previously installed program continues to load the installed library at runtime, whereas the uninstalled program picks up the modifications in the uninstalled version of the library.

This example introduces the concept of Libtool modes. Most of the time libtool can infer a mode of operation from the contents of the command line, but sometimes (as in this example) it needs to be told. In 10.5 Executing Uninstalled Binaries we already used libtool in execute mode to run gdb against an uninstalled binary. In this example I am telling libtool that I want to pass the hello binary to the chatr command, particularly since I know that the `hello' file is a script to set the local execution environment before running the real binary.

The various modes that libtool has are described in the Libtool reference documentation, and are listed in the Libtool help text:

 
$ libtool --help
 ...
 MODE must be one of the following:
 
       clean           remove files from the build directory
       compile         compile a source file into a libtool object
       execute         automatically set library path, then run a program
       finish          complete the installation of libtool libraries
       install         install libraries or executables
       link            create a library or an executable
       uninstall       remove libraries from an installed directory
 
 MODE-ARGS vary depending on the MODE.  Try `libtool --help --mode=MODE'
 for a more detailed description of MODE.
 

10.8 Uninstalling

Having installed all of these files to `/usr/local', it might be difficult to remember which particular files belong to each installation. In the case of an executable, the uninstallation requires no magic, but when uninstalling a Libtool library all of the files which comprise the implementation of the Libtool library in question must be uninstalled:

 
$ libtool rm -f /usr/local/bin/hello
 rm -f /usr/local/bin/hello
 $ libtool rm -f /usr/local/lib/libhello.la
 rm -f /usr/local/lib/libhello.la /usr/local/lib/libhello.sl.0.0 \
 /usr/local/lib/libhello.sl.0 /usr/local/lib/libhello.sl \
 /usr/local/lib/libhello.a
 $ libtool rm -f /usr/local/lib/libtrim.la
 rm -f /usr/local/lib/libtrim.la /usr/local/lib/libtrim.sl.0.0 \
 /usr/local/lib/libtrim.sl.0 /usr/local/lib/libtrim.sl \
 /usr/local/lib/libtrim.a
 

Using libtool to perform the uninstallation in this way ensures that all of the files that it installed, including any additional soft links required by the architecture versioning scheme for shared archives, are removed with a single command.

Having explored the use of libtool from the command line, the next chapter will discuss how to integrate libtool into the configury of your GNU Autotools based projects.

11. Using GNU Libtool with `configure.in' and `Makefile.am'

Although Libtool is usable by itself, either from the command line or from a non-make driven build system, it is also tightly integrated into Autoconf and Automake. This chapter discusses how to use Libtool with Autoconf and Automake and explains how to set up the files you write (`Makefile.am' and `configure.in') to take advantage of libtool. For a more in depth discussion of the workings of Libtool, particularly its command line interface, See section 10. Introducing GNU Libtool. Using libtool for dynamic runtime loading is described in See section 18. Using GNU libltdl.

11.1 Integration with `configure.in'

Declaring your use of libtool in the project's `configure.in' is a simple matter of adding the `AC_PROG_LIBTOOL'(18) somewhere near the top of the file. I always put it immediately after the other `AC_PROG_...' macros. If you are converting an old project to use libtool, then you will also need to remove any calls to `AC_PROG_RANLIB'. Since Libtool will be handling all of the libraries, it will decide whether or not to call ranlib as appropriate for the build environment.

The code generated by `AC_PROG_LIBTOOL' relies on the shell variable $top_builddir to hold the relative path to the directory which contains the configure script. If you are using Automake, $top_builddir is set in the environment by the generated `Makefile'. If you use Autoconf without Automake then you must ensure that $top_builddir is set before the call to `AC_PROG_LIBTOOL' in `configure.in'.

Adding the following code to `configure.in' is often sufficient:

 
for top_builddir in . .. ../.. $ac_auxdir $ac_auxdir/..; do
   test -f $top_builddir/configure && break
 done
 

Having made these changes to add libtool support to your project, you will need to regenerate the `aclocal.m4' file to pick up the macro definitions required for `AC_PROG_LIBTOOL', and then rebuild your configure script with these new definitions in place. After you have done that, there will be some new options available from configure:

 
$ aclocal
 $ autoconf
 $ ./configure --help
 ...
 --enable and --with options recognized:
   --enable-shared[=PKGS]  build shared libraries [yes]
   --enable-static[=PKGS]  build static libraries [yes]
   --enable-fast-install[=PKGS]  optimize for fast installation [yes]
   --with-gnu-ld           assume the C compiler uses GNU ld [no]
   --disable-libtool-lock  avoid locking (might break parallel builds)
   --with-pic              try to use only PIC/non-PIC objects [both]
 

These new options allow the end user of your project some control over how they want to build the project's libraries. The opposites of each of these switches are also accepted, even though they are not listed by configure --help. You can equally pass, `--disable-fast-install' or `--without-gnu-ld' for example.

11.1.1 Extra Configure Options

What follows is a list that describes the more commonly used options that are automatically added to configure, by virtue of using `AC_PROG_LIBTOOL' in your `configure.in'. The Libtool Manual distributed with Libtool releases always contains the most up to date information about libtool options:

`--enable-shared'
`--enable-static'
More often invoked as `--disable-shared' or equivalently `--enable-shared=no' these switches determine whether libtool should build shared and/or static libraries in this package. If the installer is short of disk space, they might like to build entirely without static archives. To do this they would use:

 
$ ./configure --disable-static
 

Sometimes it is desirable to configure several related packages with the same command line. From a scheduled build script or where subpackages with their own configure scripts are present, for example. The `--enable-shared' and `--enable-static' switches also accept a list of package names, causing the option to be applied to packages whose name is listed, and the opposite to be applied to those not listed.

By specifying:

 
$ ./configure --enable-static=libsnprintfv,autoopts
 

libtool would pass `--enable-static' to only the packages named libsnprintfv and autoopts in the current tree. Any other packages configured would effectively be passed `--disable-static'. Note that this doesn't necessarily mean that the packages must honour these options. Enabling static libraries for a package which consists of only dynamic modules makes no sense, and the package author would probably have decided to ignore such requests, See section 11.1.2 Extra Macros for Libtool.

`--enable-fast-install'
On some machines, libtool has to relink executables when they are installed, See section 10.7 Installing an Executable. Normally, when an end user builds your package, they will probably type:

 
$ ./configure
 $ make
 $ make install
 

libtool will build executables suitable for copying into their respective installation destinations, obviating the need for relinking them on those hosts which would have required it. Whenever libtool links an executable which uses shared libraries, it also creates a wrapper script which ensures that the environment is correct for loading the correct libraries, See section 10.5 Executing Uninstalled Binaries. On those hosts which require it, the wrapper script will also relink the executable in the build tree if you attempt to run it from there before installation.

Sometimes this behaviour is not what you want, particularly if you are developing the package and not installing between test compilations. By passing `--disable-fast-install', the default behaviour is reversed; executables will be built so that they can be run from the build tree without relinking, but during installation they may be relinked.

You can pass a list of executables as the argument to `--enable-fast-install' to determine which set of executables will not be relinked at installation time (on the hosts that require it). By specifying:

 
$ ./configure --enable-fast-install=autogen
 

The autogen executable will be linked for fast installation (without being relinked), and any other executables in the build tree will be linked for fast execution from their build location. This is useful if the remaining executables are for testing only, and will never be installed.

Most machines do not require that executables be relinked in this way, and in these cases libtool will link each executable once only, no matter whether `--disable-fast-install' is used.

`--with-gnu-ld'

This option is used to inform libtool that the C compiler is using GNU ld as its linker. It is more often used in the opposite sense when both gcc and GNU ld are installed, but gcc was built to use the native linker. libtool will probe the system for GNU ld, and assume that it is used by gcc if found, unless `--without-gnu-ld' is passed to configure.

`--disable-libtool-lock'

In normal operation, libtool will build two objects for every source file in a package, one PIC(19) and one non-PIC. With gcc and some other compilers, libtool can specify a different output location for the PIC object:

 
$ libtool gcc -c shell.c
 gcc -c -pic -DPIC shell.c -o .libs/shell.lo
 gcc -c foo.c -o shell.o >/dev/null 2>&1
 

When using a compiler that doesn't accept both `-o' and `-c' in the same command, libtool must compile first the PIC and then the non-PIC object to the same destination file and then move the PIC object before compiling the non-PIC object. This would be a problem for parallel builds, since one file might overwrite the other. libtool uses a simple shell locking mechanism to avoid this eventuality.

If you find yourself building in an environment that has such a compiler, and not using parallel make, then the locking mechanism can be safely turned off by using `--disable-libtool-lock' to gain a little extra speed in the overall compilation.

`--with-pic'
In normal operation, Libtool will build shared libraries from PIC objects and static archives from non-PIC objects, except where one or the other is not provided by the target host. By specifying `--with-pic' you are asking libtool to build static archives from PIC objects, and similarly by specifying `--without-pic' you are asking libtool to build shared libraries from non-PIC objects.

libtool will only honour this flag where it will produce a working library, otherwise it reverts to the default.

11.1.2 Extra Macros for Libtool

There are several macros which can be added to `configure.in' which will change the default behaviour of libtool. If they are used they must appear before the call to the `AC_PROG_LIBTOOL' macro. Note that these macros only change the default behaviour, and options passed in to configure on the command line will always override the defaults. The most up to date information about these macros is available from the Libtool Manual.

`AC_DISABLE_FAST_INSTALL'
This macro tells libtool that on platforms which require relinking at install time, it should build executables so that they can be run from the build tree at the expense of relinking during installation, as if `--disable-fast-install' had been passed on the command line.

`AC_DISABLE_SHARED'
`AC_DISABLE_STATIC'
These macros tell libtool to not try and build either shared or static libraries respectively. libtool will always try to build something however, so even if you turn off static library building in `configure.in', building your package for a target host without shared library support will fallback to building static archives.

The time spent waiting for builds during development can be reduced a little by including these macros temporarily. Don't forget to remove them before you release the project though!

In addition to the macros provided with `AC_PROG_LIBTOOL', there are a few shell variables that you may need to set yourself, depending on the structure of your project:

`LTLIBOBJS'
If your project uses the `AC_REPLACE_FUNCS' macro, or any of the other macros which add object names to the `LIBOBJS' variable, you will also need to provide an equivalent `LTLIBOBJS' definition. At the moment, you must do it manually, but needing to do that is considered to be a bug and will fixed in a future release of Autoconf. The manual generation of `LTLIBOBJS' is a simple matter of replacing the names of the objects mentioned in `LIBOBJS' with equivalent .lo suffixed Libtool object names. The easiest way to do this is to add the following snippet to your `configure.in' near the end, just before the call to `AC_OUTPUT'.

 
Xsed="sed -e s/^X//"
 LTLIBOBJS=`echo X"$LIBOBJS"|\
            [$Xsed -e "s,\.[^.]* ,.lo ,g;s,\.[^.]*$,.lo,"]`
 AC_SUBST(LTLIBOBJS)
 

The Xsed is not usually necessary, though it can prevent problems with the echo command in the event that one of the `LIBOBJS' files begins with a `-' character. It is also a good habit to write shell code like this, as it will avoid problems in your programs.

`LTALLOCA'
If your project uses the `AC_FUNC_ALLOCA' macro, you will need to provide a definition of `LTALLOCA' equivalent to the `ALLOCA' value provided by the macro.

 
Xsed="sed -e s/^X//"
 LTALLOCA=`echo X"$ALLOCA"|[$Xsed -e "s,\.$[^.]*,.lo,g"]`
 AC_SUBST(LTALLOCA)
 

Obviously you don't need to redefine Xsed if you already use it for `LTLIBOBJS' above.

`LIBTOOL_DEPS'
To help you write make rules for automatic updating of the Libtool configuration files, you can use the value of `LIBTOOL_DEPS' after the call to `AC_PROG_LIBTOOL':

 
AC_PROG_LIBTOOL
 AC_SUBST(LIBTOOL_DEPS)
 

Then add the following to the top level `Makefile.in':

 
libtool: @LIBTOOL_DEPS@
         cd $(srcdir) && \
           $(SHELL) ./config.status --recheck
 

If you are using automake in your project, it will generate equivalent rules automatically. You don't need to use this except in circumstances where you want to use libtool and autoconf, but not automake.

11.2.1 Creating Libtool Libraries with Automake

Continuing in the spirit of making Libtool library management look like native static archive management, converting a `Makefile.am' from static archive use to Libtool library use is a matter of changing the name of the library, and adding a Libtool prefix somewhere. For example, a `Makefile.am' for building a static archive might be:

 
lib_LIBRARIES      = libshell.a
 libshell_a_SOURCES = object.c subr.c symbol.c
 

This would build a static archive called `libshell.a' consisting of the objects `object.o', `subr.o' and `bar.o'. To build an equivalent Libtool library from the same objects, you change this to:

 
lib_LTLIBRARIES     = libshell.la
 libshell_la_SOURCES = object.c subr.c symbol.c
 

The only changes are that the library is now named with a .la suffix, and the Automake primary is now `LTLIBRARIES'. Note that since the name of the library has changed, you also need to use `libshell_la_SOURCES', and similarly for any other Automake macros which used to refer to the old archive. As for native libraries, Libtool library names should begin with the letters `lib', so that the linker will be able to find them when passed `-l' options.

Often you will need to add extra objects to the library as determined by configure, but this is also a mechanical process. When building native libraries, the `Makefile.am' would have contained:

 
libshell_a_LDADD = xmalloc.o @LIBOBJS@
 

To add the same objects to an equivalent Libtool library would require:

 
libshell_la_LDADD = xmalloc.lo @LTLIBOBJS@
 

That is, objects added to a Libtool library must be Libtool objects (with a .lo) suffix. You should add code to `configure.in' to ensure that `LTALLOCA' and `LTLIBOBJS' are set appropriately, See section 11.1.2 Extra Macros for Libtool. Automake will take care of generating appropriate rules for building the Libtool objects mentioned in an `LDADD' macro.

If you want to pass any additional flags to libtool when it is building, you use the `LDFLAGS' macro for that library, like this:

 
libshell_la_LDFLAGS = -version-info 1:0:1
 

For a detailed list of all the available options, see section `Link mode' in The Libtool Manual.

Libtool's use of `-rpath' has been a point of contention for some users, since it prevents you from moving shared libraries to another location in the library search path. Or, at least, if you do, all of the executables that were linked with `-rpath' set to the old location will need to be relinked.

We (the Libtool maintainers) assert that always using `-rpath' is a good thing: Mainly because you can guarantee that any executable linked with `-rpath' will find the correct version of the library, in the rpath directory, that was intended when the executable was linked. Library versions can still be managed correctly, and will be found by the run time loader, by installing newer versions to the same directory. Additionally, it is much harder for a malicious user to leave a modified copy of system library in a directory that someone might wish to list in their `LD_LIBRARY_PATH' in the hope that some code they have written will be executed unexpectedly.

The argument against `-rpath' was instigated when one of the GNU/Linux distributions moved some important system libraries to another directory to make room for a different version, and discovered that all of the executables that relied on these libraries and were linked with Libtool no longer worked. Doing this was, arguably, bad system management -- the new libraries should have been placed in a new directory, and the old libraries left alone. Refusing to use `-rpath' incase you want to restructure the system library directories is a very weak argument.

The `-rpath' option (which is required for Libtool libraries) is automatically supplied by automake based on the installation directory specified with the library primary.

 
lib_LTLIBRARIES = libshell.la
 

The example would use the value of the make macro $(libdir) as the argument to `-rpath', since that is where the library will be installed.

A few of the other options you can use in the library `LDFLAGS' are:

`-no-undefined'
Modern architectures allow us to create shared libraries with undefined symbols, provided those symbols are resolved (usually by the executable which loads the library) at runtime. Unfortunately, there are some architectures (notably AIX and Windows) which require that all symbols are resolved when the library is linked. If you know that your library has no unresolved symbols at link time, then adding this option tells libtool that it will be able to build a shared library, even on architectures which have this requirement.

`-static'
Using this option will force libtool to build only a static archive for this library.

`-release'
On occasion, it is desirable to encode the release number of a library into its name. By specifying the release number with this option, libtool will build a library that does this, but will break binary compatibility for each change of the release number. By breaking binary compatibility this way, you negate the possibility of fixing bugs in installed programs by installing an updated shared library. You should probably be using `-version-info' instead.

 
libshell_la_LDFLAGS = -release 27
 

The above fragment might create a library called `libshell-27.so.0.0.0' for example.

`-version-info'
Set the version number of the library according to the native versioning rules based on the numbers supplied, See section 11.4 Library Versioning. You need to be aware that the library version number is for the use of the runtime loader, and is completely unrelated to the release number of your project. If you really want to encode the project release into the library, you can use `-release' to do it.

If this option is not supplied explicitly, it defaults to `-version-info 0:0:0'.

Historically, the default behaviour of Libtool was as if `-no-undefined' was always passed on the command line, but it proved to be annoying to developers who had to constantly turn it off so that their ELF libraries could be featureful. Now it has to be defined explicitly if you need it.

There are is a tradeoff:

  • If you don't specify `-no-undefined', then Libtool will not build shared libraries on platforms which don't allow undefined symbols at link time for such a library.

  • It is only safe to specify this flag when you know for certain that all of the libraries symbols are defined at link time, otherwise the `-no-undefined' link will appear to work until it is tried on a platform which requires all symbols to be defined. Libtool will try to link the shared library in this case (because you told it that you have not left any undefined symbols), but the link will fail, because there are undefined symbols in spite of what you told Libtool.

For more information about this topic, see 18.3 Portable Library Design.

11.2.2 Linking against Libtool Libraries with Automake

Once you have set up your `Makefile.am' to create some Libtool libraries. you will want to link an executable against them. You can do this easily with automake by using the program's qualified `LDADD' macro:

 
bin_PROGRAMS  = shell
 shell_SOURCES = shell.c token.l
 shell_LDADD   = libshell.la
 

This will choose either the static or shared archive from the `libshell.la' Libtool library depending on the target host and any Libtool mode switches metioned in the `Makefile.am', or passed to configure. The chosen archive will be linked with any objects generated from the listed sources to make an executable. Note that the executable itself is a hidden file, and that in its place libtool creates a wrapper script, See section 10.5 Executing Uninstalled Binaries.

As with the Libtool libraries, you can pass additional switches for the libtool invocation in the qualified `LDFLAGS' macros to control how the shell executable is linked:

`-all-static'
Always choose static libraries where possible, and try to create a completely statically linked executable.

`-no-fast-install'
If you really want to use this flag on some targets, you can pass it in an `LDFLAGS' macro. This is not overridden by the configure `--enable-fast-install' switch. Executables built with this flag will not need relinking to be executed from the build tree on platforms which might have otherwise required it.

`-no-install'
You should use this option for any executables which are used only for testing, or for generating other files and are consequently never installed. By specifying this option, you are telling Libtool that the executable it links will only ever be executed from where it is built in the build tree. Libtool is usually able to considerably speed up the link process for such executables.

`-static'
This switch is similar to `-all-static', except that it applies to only the uninstalled Libtool libraries in the build tree. Where possible the static archive from these libraries is used, but the default linking mode is used for libraries which are already installed.

When debugging an executable, for example, it can be useful to temporarily use:

 
shell_LDFLAGS = -all-static
 

You can pass Libtool link options to all of the targets in a given directory by using the unadorned `LDFLAGS' macro:

 
LDFLAGS = -static
 

This is best reserved for directories which have targets of the same type, all Libtool libraries or all executables for instance. The technique still works in a mixed target type directory, and libtool will ignore switches which don't make sense for particular targets. It is less maintainable, and makes it harder to understand what is going on if you do that though.

11.3 Using libtoolize

Having made the necessary editions in `configure.in' and `Makefile.am', all that remains is to add the Libtool infrastructure to your project.

First of all you must ensure that the correct definitions for the new macros you use in `configure.in' are added to `aclocal.m4', See section C. Generated File Dependencies. At the moment, the safest way to do this is to copy `libtool.m4' from the installed libtool to `acinclude.m4' in the toplevel source directory of your package. This is to ensure that when your package ships, there will be no mismatch errors between the M4 macros you provided in the version of libtool you built the distribution with, versus the version of the Libtool installation in another developer's environment. In a future release, libtool will check that the macros in aclocal.m4 are from the same Libtool distribution as the generated libtool script.

 
$ cp /usr/share/libtool/libtool.m4 ./acinclude.m4
 $ aclocal
 

By naming the file `acinclude.m4' you ensure that aclocal can see it and will use macros from it, and that automake will add it to the distribution when you create the tarball.

Next, you should run libtoolize, which adds some files to your distribution that are required by the macros from `libtool.m4'. In particular, you will get `ltconfig'(20) and `ltmain.sh' which are used to create a custom libtool script on the installer's machine.

If you do not yet have them, libtoolize will also add `config.guess' and `config.sub' to your distribution. Sometimes you don't need to run libtoolize manually, since automake will run it for you when it sees the changes you have made to `configure.in', as follows:

 
$ automake --add-missing
 automake: configure.in: installing ./install-sh
 automake: configure.in: installing ./mkinstalldirs
 automake: configure.in: installing ./missing
 configure.in: 8: required file ./ltconfig not found
 

The error message in the last line is an abberation. If it was consistant with the other lines, it would say:

 
automake: configure.in: installing ./ltconfig
 automake: configure.in: installing ./ltmain.sh
 automake: configure.in: installing ./config.guess
 automake: configure.in: installing ./config.sub
 

But the effect is the same, and the files are correctly added to the distribution despite the misleading message.

Before you release a distribution of your project, it is wise to get the latest versions of `config.guess' and `config.sub' from the GNU site(21), since they may be newer than the versions automatically added by libtoolize and automake. Note that automake --add-missing will give you its own version of these two files if `AC_PROG_LIBTOOL' is not used in the project `configure.in', but will give you the versions shipped with libtool if that macro is present!

11.4 Library Versioning

It is important to note from the outset that the version number of your project is a very different thing to the version number of any libraries shipped with your project. It is a common error for maintainers to try to force their libraries to have the same version number as the current release version of the package as a whole. At best, they will break binary compatibility unnecessarily, so that their users won't gain the benefits of the changes in their latest revision without relinking all applications that use it. At worst, they will allow the runtime linker to load binary incompatible libraries, causing applications to crash.

Far better, the Libtool versioning system will build native shared libraries with the correct native library version numbers. Although different architectures use various numbering schemes, Libtool abstracts these away behind the system described here. The various native library version numbering schemes are designed so that when an executable is started, the runtime loader can, where appropriate, choose a more recent installed library version than the one with which the executable was actually built. This allows you to fix bugs in your library, and having built it with the correct Libtool version number, have those fixes propogate into any executables that were built with the old buggy version. This can only work if the runtime loader can tell whether it can load the new library into the old executable and expect them to work together. The library version numbers give this information to the runtime loader, so it is very important to set them correctly.

The version scheme used by Libtool tracks interfaces, where an interface is the set of exported entry points into the library. All Libtool libraries start with `-version-info' set to `0:0:0' -- this will be the default version number if you don't explicitly set it on the Libtool link command line. The meaning of these numbers (from left to right) is as follows:

current
The number of the current interface exported by the library. A current value of `0', means that you are calling the interface exported by this library interface 0.

revision
The implementation number of the most recent interface exported by this library. In this case, a revision value of `0' means that this is the first implementation of the interface.

If the next release of this library exports the same interface, but has a different implementation (perhaps some bugs have been fixed), the revision number will be higher, but current number will be the same. In that case, when given a choice, the library with the highest revision will always be used by the runtime loader.

age
The number of previous additional interfaces supported by this library. If age were `2', then this library can be linked into executables which were built with a release of this library that exported the current interface number, current, or any of the previous two interfaces.

By definition age must be less than or equal to current. At the outset, only the first ever interface is implemented, so age can only be `0'.

For later releases of a library, the `-version-info' argument needs to be set correctly depending on any interface changes you have made. This is quite straightforward when you understand what the three numbers mean:

  1. If you have changed any of the sources for this library, the revision number must be incremented. This is a new revision of the current interface.

  2. If the interface has changed, then current must be incremented, and revision reset to `0'. This is the first revision of a new interface.

  3. If the new interface is a superset of the previous interface (that is, if the previous interface has not been broken by the changes in this new release), then age must be incremented. This release is backwards compatible with the previous release.

  4. If the new interface has removed elements with respect to the previous interface, then you have broken backward compatibility and age must be reset to `0'. This release has a new, but backwards incompatible interface.

For example, if the next release of the library included some new commands for an existing socket protocol, you would use -version-info 1:0:1. This is the first revision of a new interface. This release is backwards compatible with the previous release.

Later, you implement a faster way of handling part of the algorithm at the core of the library, and release it with -version-info 1:1:1. This is a new revision of the current interface.

Unfortunately the speed of your new implementation can only be fully exploited by changing the API to access the structures at a lower level, which breaks compatibility with the previous interface, so you release it as -version-info 2:0:0. This release has a new, but backwards incompatible interface.

When deciding which numbers to change in the -version-info argument for a new release, you must remember that an interface change is not limited to the API of the library. The notion of an interface must include any method by which a user (code or human) can interact with the library: adding new builtin commands to a shell library; the format used in an output file; the handshake protocol required for a client connecting over a socket, and so on.

Additionally, If you use a development model which has both a stable and an unstable tree being developed in parallel, for example, and you don't mind forcing your users to relink all of the applications which use one of your Libtool libraries every time you make a release, then libtool provides the `-release' flag to encode the project version number in the name of the library, See section 11.2.1 Creating Libtool Libraries with Automake. This can save you library compatibility problems later if you need to, say, make a patch release of an older revision of your library, but the library version number that you should use has already been taken by another earlier release. In this case, you could be fairly certain that library releases from the unstable branch will not be binary compatible with the stable releases, so you could make all the stable releases with `-release 1.0' and begin the first unstable release with `-release 1.1'.

11.5 Convenience Libraries

Sometimes it is useful to group objects together in an intermediate stage of a project's compilation to provide a useful handle for that group without having to specify all of the individual objects every time. Convenience libraries are a portable way of creating such a partially linked object: Libtool will handle all of the low level details in a way appropriate to the target host. This section describes the use of convenience libraries in conjunction with Automake. The principles of convenience libraries are discussed in Creating Convenience Libraries.

The key to creating Libtool convenience libraries with Automake is to use the
`noinst_LTLIBRARIES' macro. For the Libtool libraries named in this macro, Automake will create Libtool convenience libraries which can subsequently be linked into other Libtool libraries.

In this section I will create two convenience libraries, each in their own subdirectory, and link them into a third Libtool library, which is ultimately linked into an application.

If you want to follow this example, you should create a directory structure to hold the sources by running the following shell commands:

 
$ mkdir convenience
 $ cd convenience
 $ mkdir lib
 $ mkdir replace
 

The first convenience library is built from two source files in the `lib' subdirectory.

  1. `source.c':

     
    #if HAVE_CONFIG_H
     #  include <config.h>
     #endif
     
     #if HAVE_MATH_H
     #  include <math.h>
     #endif
     
     void
     foo (double argument)
     {
       printf ("cos (%g) => %g\n", argument, cos (argument));
     }
     
     
     

    This file defines a single function to display the cosine of its argument on standard output, and consequently relies on an implementation of the cos function from the system libraries. Note the conditional inclusion of `config.h', which will contain a definition of `HAVE_MATH_H' if `configure' discovers a `math.h' system header (the usual location for the declaration of cos). The `HAVE_CONFIG_H' guard is by convention, so that the source can be linked by passing the preprocessor macro definitions to the compiler on the command line -- if `configure.in' does not use `AM_CONFIG_HEADER' for instance.

  2. `source.h':

     
    extern void foo        (double argument);
     
     

    For brevity, there is no #ifndef SOURCE_H guard. The header is not installed, so you have full control over where it is #includeed, and in any case, function declarations can be safely repeated if the header is accidentally processed more than once. In a real program, it would be better to list the function parameters in the declaration so that the compiler can do type checking. This would limit the code to working only with ANSI compilers, unless you also use a PARAMS macro to conditionally preprocess away the parameters when a K&R compiler is used. These details are beyond the scope of this convenience library example, but are described in full in 9.1.6 K&R Compilers.

You also need a `Makefile.am' to hold the details of how this convenience library is linked:

 
## Process this file with automake to produce Makefile.in
 
 noinst_LTLIBRARIES        = library.la
 library_la_SOURCES        = source.c source.h
 library_la_LIBADD        = -lm
 
 

The `noinst_LTLIBRARIES' macro names the Libtool convenience libraries to be built in this directory, `library.la'. Although not required for compilation, `source.h' is listed in the `SOURCES' macro of `library.la' so that correct source dependencies are generated, and so that it is added to the distribution tarball by automake's `dist' rule.

Finally, since the foo function relies on the cos function from the system math library, `-lm' is named as a required library in the `LIBADD' macro. As with all Libtool libraries, interlibrary dependencies are maintained for convenience libraries so that you need only list the libraries you are using directly when you link your application later. The libraries used by those libraries are added by Libtool.

The parent directory holds the sources for the main executable, `main.c', and for a (non-convenience) Libtool library, `error.c' & `error.h'.

Like `source.h', the functions exported from the Libtool library `liberror.la' are listed in `error.h':

 
extern void gratuitous          (void);
 extern void set_program_name    (char *path);
 extern void error               (char *message);
 
 
 

The corresponding functon definitions are in `error.c':

 
#include <stdio.h>
 
 #include "source.h"
 
 static char *program_name = NULL;
 
 void
 gratuitous (void)
 {
   /* Gratuitous display of convenience library functionality!  */
   double argument = 0.0;
   foo (argument);
 }
 
 void
 set_program_name (char *path)
 {
   if (!program_name)
     program_name = basename (path);
 }
 
 void
 error (char *message)
 {
   fprintf (stderr, "%s: ERROR: %s\n", program_name, message);
   exit (1);
 }
 
 

The gratuitous() function calls the foo() function defined in the `library.la' convenience library in the `lib' directory, hence `source.h' is included.

The definition of error() displays an error message to standard error, along with the name of the program, program_name, which is set by calling set_program_name(). This function, in turn, extracts the basename of the program from the full path using the system function, basename(), and stores it in the library private variable, program_name.

Usually, basename() is part of the system C library, though older systems did not include it. Because of this, there is no portable header file that can be included to get a declaration, and you might see a harmless compiler warning due to the use of the function without a declaration. The alternative would be to add your own declaration in `error.c'. The problem with this approach is that different vendors will provide slightly different declarations (with or without const for instance), so compilation will fail on those architectures which do provide a declaration in the system headers that is different from the declaration you have guessed.

For the benefit of architectures which do not have an implementation of the basename() function, a fallback implementation is provided in the `replace' subdirectory. The file `basename.c' follows:

 
#if HAVE_CONFIG_H
 #  include <config.h>
 #endif
 
 #if HAVE_STRING_H
 #  include <string.h>
 #elif HAVE_STRINGS_H
 #  include <strings.h>
 #endif
 
 #if !HAVE_STRRCHR
 #  ifndef strrchr
 #    define strrchr rindex
 #  endif
 #endif
 
 char*
 basename (char *path)
 {
   /* Search for the last directory separator in PATH.  */
   char *basename = strrchr (path, '/');
   
   /* If found, return the address of the following character,
      or the start of the parameter passed in.  */
   return basename ? ++basename : path;
 }
 
 
 

For brevity, the implementation does not use any const declarations which would be good style for a real project, but would need to be checked at configure time in case the end user needs to compile the package with a K&R compiler.

The use of strrchr() is noteworthy. Sometimes it is declared in `string.h', otherwise it might be declared in `strings.h'. BSD based Unices, on the other hand, do not have this function at all, but provide an equivalent function, rindex(). The preprocessor code at the start of the file is designed to cope with all of these eventualities. The last block of preprocessor code assumes that if strrchr is already defined that it holds a working macro, and does not redefine it.

`Makefile.am' contains:

 
## Process this file with automake to produce Makefile.in
 
 noinst_LTLIBRARIES      = libreplace.la
 libreplace_la_SOURCES   = 
 libreplace_la_LIBADD    = @LTLIBOBJS@
 
 

Once again, the `noinst_LTLIBRARIES' macro names the convenience library,
`libreplace.la'. By default there are no sources, since we expect to have a system definition of basename(). Additional Libtool objects which should be added to the library based on tests at configure time are handled by the `LIBADD' macro. `LTLIBOBJS' will contain `basename.lo' if the system does not provide basename, and will be empty otherwise. Illustrating another feature of convenience libraries: on many architectures, `libreplace.la' will contain no objects.

Back in the toplevel project directory, all of the preceding objects are combined by another `Makefile.am':

 
## Process this file with automake to produce Makefile.in
 
 AUTOMAKE_OPTIONS        = foreign
 
 SUBDIRS                 = replace lib .
 
 CPPFLAGS                = -I$(top_srcdir)/lib
 
 include_HEADERS         = error.h
 
 lib_LTLIBRARIES         = liberror.la
 liberror_la_SOURCES     = error.c
 liberror_la_LDFLAGS     = -no-undefined -version-info 0:0:0
 liberror_la_LIBADD      = replace/libreplace.la lib/library.la
 
 bin_PROGRAMS            = convenience
 convenience_SOURCES     = main.c
 convenience_LDADD       = liberror.la
 
 

The initial `SUBDIRS' macro is necessary to ensure that the libraries in the subdirectories are built before the final library and executable in this directory.

Notice that I have not listed `error.h' in `liberror_la_SOURCES' this time, since `liberror.la' is an installed library, and `error.h' defines the public interface to that library. Since the `liberror.la' Libtool library is installed, I have used the `-version-info' option, and I have also used `-no-undefined' so that the project will compile on architectures which require all library symbols to be defined at link time -- the reason program_name is maintained in `liberror' rather than `main.c' is so that the library does not have a runtime dependency on the executable which links it.

The key to this example is that by linking the `libreplace.la' and `library.la' convenience libraries into `liberror.la', all of the objects in both convenience libraries are compiled into the single installed library, `liberror.la'. Additionally, all of the inter-library dependencies of the convenience libraries (`-lm', from `library.la') are propogated to `liberror.la'.

A common difficulty people experience with Automake is knowing when to use a `LIBADD' primary versus a `LDADD' primary. A useful mnemonic is: `LIBADD' is for ADDitional LIBrary objects. `LDADD' is for ADDitional linker (LD) objects.

The executable, `convenience', is built from `main.c', and requires only `liberror.la'. All of the other implicit dependencies are encoded within `liberror.la'. Here is `main.c':

 
#include <stdio.h>
 #include "error.h"
 
 int
 main (int argc, char *argv[])
 {
   set_program_name (argv[0]);
   gratuitous ();
   error ("This program does nothing!");
 }
 
 

The only file that remains before you can compile the example is `configure.in':

 
# Process this file with autoconf to create configure.
 
 AC_INIT(error.c)
 AM_CONFIG_HEADER(config.h)
 AM_INIT_AUTOMAKE(convenience, 1.0)
 
 AC_PROG_CC
 AM_PROG_LIBTOOL
 
 AC_CHECK_HEADERS(math.h)
 AC_CHECK_HEADERS(string.h strings.h, break)
 
 AC_CHECK_FUNCS(strrchr)
 AC_REPLACE_FUNCS(basename)
 
 Xsed="sed -e s/^X//"
 LTLIBOBJS=echo X"$LIBOBJS" | \
     $Xsed -e "s,\.[^.]* ,.lo ,g;s,\.[^.]*\$,.lo,"`
 AC_SUBST(LTLIBOBJS)
 
 AC_OUTPUT(replace/Makefile lib/Makefile Makefile)
 
 

There are checks for all of the features used by the sources in the project: `math.h' and either `string.h' or `strings.h'; the existence of strrchr (after the tests for string headers); adding `basename.o' to `LIBOBJS' if there is no system implementation; and the shell code to set `LTLIBOBJS'.

With all the files in place, you can now bootstrap the project:

 
$ ls -R
 .:
 Makefile.am  configure.in  error.c  error.h  lib  main.c  replace
 
 lib:
 Makefile.am  source.c  source.h
 
 replace:
 Makefile.am  basename.c
 $ aclocal
 $ autoheader
 $ automake --add-missing --copy
 automake: configure.in: installing ./install-sh
 automake: configure.in: installing ./mkinstalldirs
 automake: configure.in: installing ./missing
 configure.in: 7: required file ./ltconfig not found
 $ autoconf
 $ ls -R
 .:
 Makefile.am   config.h.in   error.c     ltconfig   mkinstalldirs
 Makefile.in   config.sub    error.h     ltmain.sh  replace
 aclocal.m4    configure     install-sh  main.c     
 config.guess  configure.in  lib         missing
 
 lib:
 Makefile.am  Makefile.in  source.c  source.h
 
 replace:
 Makefile.am  Makefile.in  basename.c
 

With these files in place, the package can now be configured:

 
$ ./configure
 ...
 checking how to run the C preprocessor... gcc -E
 checking for math.h... yes
 checking for string.h... yes
 checking for strrchr... yes
 checking for basename... yes
 updating cache ./config.cache
 creating ./config.status
 creating replace/Makefile
 creating lib/Makefile
 creating Makefile
 creating config.h
 

Notice that my host has an implementation of basename().

Here are the highlights of the compilation itself:

 
$ make
 Making all in replace
 make[1]: Entering directory /tmp/replace
 /bin/sh ../libtool --mode=link gcc  -g -O2  -o libreplace.la     
 rm -fr .libs/libreplace.la .libs/libreplace.* .libs/libreplace.*
 ar cru .libs/libreplace.al
 ranlib .libs/libreplace.al
 creating libreplace.la
 (cd .libs && rm -f libreplace.la && ln -s ../libreplace.la \
 libreplace.la)
 make[1]: Leaving directory /tmp/replace
 

Here the build descends into the `replace' subdirectory and creates `libreplace.la', which is empty on my host since I don't need an implementation of basename():

 
Making all in lib
 make[1]: Entering directory /tmp/lib
 /bin/sh ../libtool --mode=compile gcc -DHAVE_CONFIG_H  -I. -I. \
 -g -O2 -c source.c
 rm -f .libs/source.lo
 gcc -DHAVE_CONFIG_H -I. -I. -g -O2 -c -fPIC -DPIC source.c \
 -o .libs/source.lo
 gcc -DHAVE_CONFIG_H -I. -I. -g -O2 -c source.c \
 -o source.o >/dev/null 2>&1
 mv -f .libs/source.lo source.lo
 /bin/sh ../libtool --mode=link gcc  -g -O2  -o library.la source.lo -lm 
 rm -fr .libs/library.la .libs/library.* .libs/library.*
 ar cru .libs/library.al source.lo
 ranlib .libs/library.al
 creating library.la
 (cd .libs && rm -f library.la && ln -s ../library.la library.la)
 make[1]: Leaving directory /tmp/lib
 

Next, the build enters the `lib' subdirectory to build `library.la'. The `configure' preprocessor macros are passed on the command line, since no `config.h' was created by AC_CONFIG_HEADER:

Here, `main.c' is compiled (not to a Libtool object, since it is not compiled using libtool), and linked with the `liberror.la' Libtool library:

 
gcc -DHAVE_CONFIG_H -I. -I.  -I./lib  -g -O2 -c main.c
 /bin/sh ./libtool --mode=link gcc  -g -O2  -o convenience  main.o \
 liberror.la 
 gcc -g -O2 -o .libs/convenience main.o ./.libs/liberror.so -lm \
 -Wl,--rpath -Wl,/usr/local/lib
 creating convenience
 make[1]: Leaving directory /tmp/convenience
 

libtool calls gcc to link the convenience executable from `main.o' and the shared library component of `liberror.la'. libtool also links with `-lm', the propogated inter-library dependency of the `library.la' convenience library. Since `libreplace.la' and `library.la' were convenience libraries, their objects are already present in `liberror.la', so they are not listed again in the final link line -- the whole point of convenience archives.

This just shows that it all works:

 
$ ls
 Makefile      config.h       configure.in  install-sh   main.c
 Makefile.am   config.h.in    convenience   lib          main.o
 Makefile.in   config.log     error.c       liberror.la  missing
 aclocal.m4    config.status  error.h       libtool      mkinstalldirs
 config.cache  config.sub     error.lo      ltconfig     replace
 config.guess  configure      error.o       ltmain.sh
 $ libtool --mode=execute ldd convenience
         liberror.so.0 => /tmp/.libs/liberror.so.0 (0x40014000)
         libm.so.6 => /lib/libm.so.6 (0x4001c000)
         libc.so.6 => /lib/libc.so.6 (0x40039000)
         /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
 $ ./convenience
 cos (0) => 1
 lt-convenience: ERROR: This program does nothing!
 

Notice that you are running the uninstalled executable, which is in actual fact a wrapper script, See section 10.5 Executing Uninstalled Binaries. That is why you need to use libtool to run ldd on the real executable. The uninstalled executable called by the wrapper script is called lt-convenience, hence the output from basename().

12.1 Using Libtool Libraries

As you have seen, It is very easy to convert automake built static libraries to automake built Libtool libraries. In order to build `libsic' as a Libtool library, I have changed the name of the library from `libsic.a' (the old archive name in Libtool terminology) to `libsic.la' (the pseudo-library), and must use the LTLIBRARIES Automake primary:

 
lib_LTLIBRARIES         = libsic.la
 libsic_la_LIBADD        = $(top_builddir)/replace/libreplace.la
 libsic_la_SOURCES       = builtin.c error.c eval.c list.c sic.c \
                         syntax.c xmalloc.c xstrdup.c xstrerror.c
 
 
Notice the `la' in libsic_la_SOURCES is new too.

It is similarly easy to take advantage of Libtool convenience libraries. For the purposes of Sic, `libreplace' is an ideal candidate for this treatment -- I can create the library as a separate entity from selected sources in their own directory, and add those objects to `libsic'. This technique ensures that the installed library has all of the support functions it needs without having to link `libreplace' as a separate object.

In `replace/Makefile.am', I have again changed the name of the library from
`libreplace.a' to `libreplace.la', and changed the automake primary from `LIBRARIES' to `LTLIBRARIES'. Unfortunately, those changes alone are insufficient. Libtool libraries are compiled from Libtool objects (which have the `.lo' suffix), so I cannot use `LIBOBJS' which is a list of `.o' suffixed objects (22). See section 11.1.2 Extra Macros for Libtool, for more details. Here is `replace/Makefile.am':

 
MAINTAINERCLEANFILES    = Makefile.in
 
 noinst_LTLIBRARIES      = libreplace.la
 libreplace_la_SOURCES   = 
 libreplace_la_LIBADD    = @LTLIBOBJS@
 
 

And not forgetting to set and use the `LTLIBOBJS' configure substitution (see section 11.1.2 Extra Macros for Libtool):

 
Xsed="sed -e s/^X//"
 LTLIBOBJS=echo X"$LIBOBJS" | \
     [$Xsed -e s,\.[^.]* ,.lo ,g;s,\.[^.]*$,.lo,']
 AC_SUBST(LTLIBOBJS)
 
 

As a consequence of using libtool to build the project libraries, the increasing number of configuration files being added to the `config' directory will grow to include `ltconfig' and `ltmain.sh'. These files will be used on the installer's machine when Sic is configured, so it is important to distribute them. The naive way to do it is to give the `config' directory a `Makefile.am' of its own; however, it is not too difficult to distribute these files from the top `Makefile.am', and it saves clutter, as you can see here:

 
AUX_DIST                = $(ac_aux_dir)/config.guess \
                         $(ac_aux_dir)/config.sub \
                         $(ac_aux_dir)/install-sh \
                         $(ac_aux_dir)/ltconfig \
                         $(ac_aux_dir)/ltmain.sh \
                         $(ac_aux_dir)/mdate-sh \
                         $(ac_aux_dir)/missing \
                         $(ac_aux_dir)/mkinstalldirs
 AUX_DIST_EXTRA          = $(ac_aux_dir)/readline.m4 \
                         $(ac_aux_dir)/sys_errlist.m4 \
                         $(ac_aux_dir)/sys_siglist.m4
 EXTRA_DIST                = bootstrap
 
 MAINTAINERCLEANFILES         = Makefile.in aclocal.m4 configure config-h.in \
                         stamp-h.in $(AUX_DIST)
 
 dist-hook:
         (cd $(distdir) && mkdir $(ac_aux_dir))
         for file in $(AUX_DIST) $(AUX_DIST_EXTRA); do \
           cp $$file $(distdir)/$$file; \
         done
 
 

The `dist-hook' rule is used to make sure the `config' directory and the files it contains are correctly added to the distribution by the `make dist' rules, see section 13.1 Introduction to Distributions.

I have been careful to use the configure script's location for ac_aux_dir, so that it is defined (and can be changed) in only one place. This is achieved by adding the following macro to `configure.in':

 
AC_SUBST(ac_aux_dir)
 

There is no need to explicity set a macro in the `Makefile.am', because Automake automatically creates macros for every value that you `AC_SUBST' from `configure.in'.

I have also added the AC_PROG_LIBTOOL macro to `configure.in' in place of AC_PROG_RANLIB as described in 11. Using GNU Libtool with `configure.in' and `Makefile.am'.

Now I can upgrade the configury to use libtool -- the greater part of this is running the libtoolize script that comes with the Libtool distribution. The bootstrap script then needs to be updated to run libtoolize at the correct juncture:

 
#! /bin/sh
 
 set -x
 aclocal -I config
 libtoolize --force --copy
 autoheader
 automake --add-missing --copy
 autoconf
 
 

Now I can re-bootstrap the entire project so that it can make use of libtool:

 
$ ./bootstrap
 + aclocal -I config
 + libtoolize --force --copy
 Putting files in AC_CONFIG_AUX_DIR, config.
 + autoheader
 + automake --add-missing --copy
 automake: configure.in: installing config/install-sh
 automake: configure.in: installing config/mkinstalldirs
 automake: configure.in: installing config/missing
 + autoconf
 

The new macros are evident by the new output seen when the newly regenerated configure script is executed:

 
$ ./configure --with-readline
 ...
 checking host system type... i586-pc-linux-gnu
 checking build system type... i586-pc-linux-gnu
 checking for ld used by GCC... /usr/bin/ld
 checking if the linker (/usr/bin/ld) is GNU ld... yes
 checking for /usr/bin/ld option to reload object files... -r
 checking for BSD-compatible nm... /usr/bin/nm -B
 checking whether ln -s works... yes
 checking how to recognise dependent libraries... pass_all
 checking for object suffix... o
 checking for executable suffix... no
 checking for ranlib... ranlib
 checking for strip... strip
 ...
 checking if libtool supports shared libraries... yes
 checking whether to build shared libraries... yes
 checking whether to build static libraries... yes
 creating libtool
 ...
 $ make
 ...
 gcc -g -O2 -o .libs/sic sic.o sic_builtin.o sic_repl.o sic_syntax.o \
 ../sic/.libs/libsic.so -lreadline -Wl,--rpath -Wl,/usr/local/lib
 creating sic
 ...
 $ src/sic
 ] libtool --mode=execute ldd src/sic
     libsic.so.0 => /tmp/sic/sic/.libs/libsic.so.0 (0x40014000)
     libreadline.so.4 => /lib/libreadline.so.4 (0x4001e000)
     libc.so.6 => /lib/libc.so.6 (0x40043000)
     libncurses.so.5 => /lib/libncurses.so.5 (0x40121000)
     /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
 ] exit
 $
 

As you can see, sic is now linked against a shared library build of `libsic', but not directly against the convenience library, `libreplace'.

12.2 Removing `--foreign'

Now that I have the bulk of the project in place, I want it to adhere to the GNU standard layout. By removing the `--foreign' option from the call to automake in the bootstrap file, automake is able to warn me about missing, or in some cases (23), malformed files, as follows:

 
$ ./bootstrap
 + aclocal -I config
 + libtoolize --force --copy
 Putting files in AC_CONFIG_AUX_DIR, config.
 + autoheader
 + automake --add-missing --copy
 automake: Makefile.am: required file ./NEWS not found
 automake: Makefile.am: required file ./README not found
 automake: Makefile.am: required file ./AUTHORS not found
 automake: Makefile.am: required file ./THANKS not found
 + autoconf
 

The GNU standards book (24) describes the contents of these files in more detail. Alternatively, take a look at a few other GNU packages from ftp://ftp.gnu.org/gnu.

12.3 Installing Header Files

One of the more difficult problems with GNU Autotools driven projects is that each of them depends on `config.h' (or its equivalent) and the project specific symbols that it defines. The purpose of this file is to be #included from all of the project source files. The preprocessor can tailor then the code in these files to the target environment.

It is often difficult and sometimes impossible to not introduce a dependency on `config.h' from one of the project's installable header files. It would be nice if you could simply install the generated `config.h', but even if you name it carefully or install it to a subdirectory to avoid filename problems, the macros it defines will clash with those from any other GNU Autotools based project which also installs its `config.h'.

For example, if Sic installed its `config.h' as `/usr/include/sic/config.h', and had `#include <sic/config.h>' in the installed `common.h', when another GNU Autotools based project came to use the Sic library it might begin like this:

 
#if HAVE_CONFIG_H
 #  include <config.h>
 #endif
 
 #if HAVE_SIC_H
 #  include <sic.h>
 #endif
 
 static const char version_number[] = VERSION;
 

But, `sic.h' says `#include <sic/common.h>', which in turn says `#include <sic/config.h>'. Even though the other project has the correct value for `VERSION' in its own `config.h', by the time the preprocessor reaches the `version_number' definition, it has been redefined to the value in `sic/config.h'. Imagine the mess you could get into if you were using several libraries which each installed their own `config.h' definitions. GCC issues a warning when a macro is redefined to a different value which would help you to catch this error. Some compilers do not issue a warning, and perhaps worse, other compilers will warn even if the repeated definitions have the same value, flooding you with hundreds of warnings for each source file that reads multiple `config.h' headers.

The Autoconf macro AC_OUTPUT_COMMANDS(25) provides a way to solve this problem. The idea is to generate a system specific but installable header from the results of the various tests performed by configure. There is a 1-to-1 mapping between the preprocessor code that relied on the configure results written to `config.h', and the new shell code that relies on the configure results saved in `config.cache'.

The following code is a snippet from `configure.in', in the body of the AC_OUTPUT_COMMANDS macro:

 
    # Add the code to include these headers only if autoconf has
     # shown them to be present.
     if test x$ac_cv_header_stdlib_h = xyes; then
       echo '#include <stdlib.h>' >> $tmpfile
     fi
     if test x$ac_cv_header_unistd_h = xyes; then
       echo '#include <unistd.h>' >> $tmpfile
     fi
     if test x$ac_cv_header_sys_wait_h = xyes; then
       echo '#include <sys/wait.h>' >> $tmpfile
     fi
     if test x$ac_cv_header_errno_h = xyes; then
       echo '#include <errno.h>' >> $tmpfile
     fi
     cat >> $tmpfile << '_EOF_'
 #ifndef errno
 /* Some sytems #define this! */
 extern int errno;
 #endif
 _EOF_
     if test x$ac_cv_header_string_h = xyes; then
       echo '#include <string.h>' >> $tmpfile
     elif test x$ac_cv_header_strings_h = xyes; then
       echo '#include <strings.h>' >> $tmpfile
     fi
     if test x$ac_cv_header_assert_h = xyes; then
       cat >> $tmpfile << '_EOF_'
 
 #include <assert.h>
 #define SIC_ASSERT assert
 
 _EOF_
     else
         echo '#define SIC_ASSERT(expr)  ((void) 0)' >> $tmpfile
     fi
 
 

Compare this with the equivalent C pre-processor code from `sic/common.h', which it replaces:

 
#if STDC_HEADERS || HAVE_STDLIB_H
 #  include <stdlib.h>
 #endif
 
 #if HAVE_UNISTD_H
 #  include <unistd.h>
 #endif
 
 #if HAVE_SYS_WAIT_H
 #  include <sys/wait.h>
 #endif
 
 #if HAVE_ERRNO_H
 #  include <errno.h>
 #endif
 #ifndef errno
 /* Some systems #define this! */
 extern int errno;
 #endif
 
 #if HAVE_STRING_H
 #  include <string.h>
 #else
 #  if HAVE_STRING_H
 #    include <strings.h>
 #  endif
 #endif
 
 #if HAVE_ASSERT_H
 #  include <assert.h>
 #  define SIC_ASSERT assert
 #else
 #  define SIC_ASSERT(expr) ((void) 0)
 #endif
 

Apart from the mechanical process of translating the preprocessor code, there is some plumbing needed to ensure that the `common.h' file generated by the new code in `configure.in' is functionally equivalent to the old code, and is generated in a correct and timely fashion.

Taking my lead from some of the Automake generated make rules to regenerate `Makefile' from `Makefile.in' by calling `config.status', I have added some similar rules to `sic/Makefile.am' to regenerate `common.h' from `common-h.in'.

 
# Regenerate common.h with config.status whenever common-h.in changes.
 common.h: stamp-common
         @:
 stamp-common: $(srcdir)/common-h.in $(top_builddir)/config.status
         cd $(top_builddir) \
           && CONFIG_FILES= CONFIG_HEADERS= CONFIG_OTHER=sic/common.h \
           $(SHELL) ./config.status
         echo timestamp > $@
 
 

The way that AC_OUTPUT_COMMANDS works, is to copy the contained code into config.status (see section C. Generated File Dependencies). It is actually config.status that creates the generated files -- for example, automake generated
`Makefile's are able to regenerate themselves from corresponding `Makefile.in's by calling config.status if they become out of date. Unfortunately, this means that config.status doesn't have direct access to the cache values generated while configure was running (because it has finished its work by the time config.status is called). It is tempting to read in the cache file at the top of the code inside AC_OUTPUT_COMMANDS, but that only works if you know where the cache file is saved. Also the package installer can use the `--cache-file' option of configure to change the location of the file, or turn off caching entirely with `--cache-file=/dev/null'.

AC_OUTPUT_COMMANDS accepts a second argument which can be used to pass the variable settings discovered by configure into config.status. It's not pretty, and is a little error prone. In the first argument to AC_OUTPUT_COMMANDS, you must be careful to check that every single configure variable referenced is correctly set somewhere in the second argument.

A slightly stripped down example from the sic project `configure.in' looks like this:

 
# ----------------------------------------------------------------------
 # Add code to config.status to create an installable host dependent
 # configuration file.
 # ----------------------------------------------------------------------
 AC_OUTPUT_COMMANDS([
   if test -n "$CONFIG_FILES" && test -n "$CONFIG_HEADERS"; then
     # If both these vars are non-empty, then config.status wasn't run by
     # automake rules (which always set one or the other to empty).
     CONFIG_OTHER=${CONFIG_OTHER-sic/common.h}
   fi
   case "$CONFIG_OTHER" in
   *sic/common.h*)
     outfile=sic/common.h
     stampfile=sic/stamp-common
     tmpfile=${outfile}T
     dirname="sed s,^.*/,,g"
 
     echo creating $outfile
     cat > $tmpfile << _EOF_
 /*  -*- Mode: C -*-
  * --------------------------------------------------------------------
  * DO NOT EDIT THIS FILE!  It has been automatically generated
  * from:    configure.in and `echo $outfile|$dirname`.in
  * on host: `(hostname || uname -n) 2>/dev/null | sed 1q`
  * --------------------------------------------------------------------
  */
 
 #ifndef SIC_COMMON_H
 #define SIC_COMMON_H 1
 
 #include <stdio.h>
 #include <sys/types.h>
 _EOF_
 
     if test x$ac_cv_func_bzero = xno && \
        test x$ac_cv_func_memset = xyes; then
       cat >> $tmpfile << '_EOF_'
 #define bzero(buf, bytes) ((void) memset (buf, 0, bytes))
 _EOF_
     fi
     if test x$ac_cv_func_strchr = xno; then
       echo '#define strchr index' >> $tmpfile
     fi
     if test x$ac_cv_func_strrchr = xno; then
       echo '#define strrchr rindex' >> $tmpfile
     fi
 
     # The ugly but portable cpp stuff comes from here
     infile=$srcdir/sic/`echo $outfile | sed 's,.*/,,g;s,\..*$,,g'`-h.in
     sed '/^##.*$/d' $infile >> $tmpfile 
 
 ],[
   srcdir=$srcdir
   ac_cv_func_bzero=$ac_cv_func_bzero
   ac_cv_func_memset=$ac_cv_func_memset
   ac_cv_func_strchr=$ac_cv_func_strchr
   ac_cv_func_strrchr=$ac_cv_func_strrchr
 ])
 
 

You will notice that the contents of `common-h.in' are copied into `common.h' verbatim as it is generated. It's just an easy way of collecting together the code that belongs in `common.h', but which doesn't rely on configuration tests, without cluttering `configure.in' any more than necessary.

I should point out that, although this method has served me well for a number of years now, it is inherently fragile because it relies on undocumented internals of both Autoconf and Automake. There is a very real possibility that if you also track the latest releases of GNU Autotools, it may stop working. Future releases of GNU Autotools will address the interface problems that force us to use code like this, for the lack of a better way to do things.

12.4 Including Texinfo Documentation

Automake provides a few facilities to make the maintenance of Texinfo documentation within projects much simpler than it used to be. Writing a `Makefile.am' for Texinfo documentation is extremely straightforward:

 
## Process this file with automake to produce Makefile.in
 
 MAINTAINERCLEANFILES    = Makefile.in
 info_TEXINFOS           = sic.texi
 
 

The `TEXINFOS' primary will not only create rules for generating `.info' files suitable for browsing with the GNU info reader, but also for generating `.dvi' and `.ps' documentation for printing.

You can also create other formats of documentation by adding the appropriate make rules to `Makefile.am'. For example, because the more recent Texinfo distributions have begun to support generation of HTML documentation from the `.texi' format master document, I have added the appropriate rules to the `Makefile.am':

 
SUFFIXES                = .html
 
 html_docs               = sic.html
 
 .texi.html:
         $(MAKEINFO) --html $<
 
 .PHONY: html
 html: version.texi $(html_docs)
 
 

For ease of maintenance, these make rules employ a suffix rule which describes how to generate HTML from equivalent `.texi' source -- this involves telling make about the `.html' suffix using the automake SUFFIXES macro. I haven't defined `MAKEINFO' explicitly (though I could have done) because I know that Automake has already defined it for use in the `.info' generation rules.

The `html' target is for convenience; typing `make html' is a little easier than typng `make sic.html'. I have also added a .PHONY target so that featureful make programs will know that the `html' target doesn't actually generate a file called literally, `html'. As it stands, this code is not quite complete, since the toplevel `Makefile.am' doesn't know how to call the `html' rule in the `doc' subdirectory.

There is no need to provide a general solution here in the way Automake does for its `dvi' target, for example. A simple recursive call to `doc/Makefile' is much simpler:

 
docdir                        = $(top_builddir)/doc
 
 html:
         @echo Making $@ in $(docdir)
         @cd $(docdir) && make $@
 
 

Another useful management function that Automake can perform for you with respect to Texinfo documentation is to automatically generate the version numbers for your Texinfo documents. It will add make rules to generate a suitable `version.texi', so long as automake sees `@include version.texi' in the body of the Texinfo source:

 
\input texinfo   @c -*-texinfo-*-
 @c %**start of header
 @setfilename sic.info
 @settitle Dynamic Modular Interpreter Prototyping
 @setchapternewpage odd
 @c %**end of header
 @headings             double
 
 @include version.texi
 
 @dircategory Programming
 @direntry
 * sic: (sic).    The dynamic, modular, interpreter prototyping tool.
 @end direntry
 
 @ifinfo
 This file documents sic.
 
 @end ifinfo
 
 @titlepage
 @sp 10
 @title Sic
 @subtitle Edition @value{EDITION}, @value{UPDATED}
 @subtitle $Id: sic.texi,v 1.4 2000/05/23 09:07:00 bje Exp $
 @author Gary V. Vaughan
 @author @email{gvv@@techie.com}
 
 @page
 @vskip 0pt plus 1filll
 @end titlepage
 
 

`version.texi' sets Texinfo variables, `VERSION', `EDITION' and `UPDATE', which can be expanded elsewhere in the main Texinfo documentation by using @value{EDITION} for example. This makes use of another auxiliary file, mdate-sh which will be added to the scripts in the $ac_aux_dir subdirectory by Automake after adding the `version.texi' reference to `sic.texi':

 
$ ./bootstrap
 + aclocal -I config
 + libtoolize --force --copy
 Putting files in AC_CONFIG_AUX_DIR, config.
 + autoheader
 + automake --add-missing --copy
 doc/Makefile.am:22: installing config/mdate-sh
 + autoconf
 $ make html
 /bin/sh ./config.status --recheck
 ...
 Making html in ./doc
 make[1]: Entering directory /tmp/sic/doc
 Updating version.texi
 makeinfo --html sic.texi
 make[1]: Leaving directory /tmp/sic/doc
 

Hopefully, it now goes without saying that I also need to add the `doc' subdirectory to `AC_OUTPUT' in `configure.in' and to `SUBDIRS' in the top-level `Makefile.am'.

Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье