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:
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:
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:
-
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.
-
If the interface has changed, then current must be incremented,
and revision reset to `0'. This is the first revision
of a new interface.
-
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.
-
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.
- `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.
- `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
#include ed, 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':
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 #include d 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'.
|