Thursday, November 22, 2007

Building C/C++ libraries with Automake and Autoconf

Building C/C++ libraries with Automake and Autoconf
Contents
* Introduction.
* libtool
* Directory structure
* Installing headers
* Version numbers
* Making your library easy to use
* C++ namespaces
* Example Files
* Recommended Reading
Introduction
If you have read Using Automake and Autoconf with C++ then you
should already know how to use automake and autoconf to build
your C++ programs. This document will show you how to use the
same tools to build a reusable library. I have included an
example which demonstrates these ideas.

You may also wish to read Using C/C++ libraries with automake
and autoconf to see what users of your library will expect.

libtool
Why use libtool?
Each platform has its own way of implementing the shared
(or 'dynamic') library idea, and there are various tools
needed to build these libraries. Libtool delegates to
these platform-specific tools and presents the developer
with a simpler set of options. Automake and autoconf can
use libtool to build libraries for many OS and
development environments using the same build files.

Libtool also makes it easy to build a static library or
a dynamic library from the same project.

libtoolize
When you start your project files you need to issue the
'libtoolize' command to add libtool support files to
your project.

AM_LIBTOOL
You need to call AM_PROG_LIBTOOL in your configure.ac
file.

libtool variables
When building an executable you use something like this
in your Makefile.am:

PROGRAMS = someapp
someapp_SOURCES = main.cc

To build a library you use the LTLIBRARIES set of
variables instead:

lib_LTLIBRARIES = something-1.0.la
something_la_SOURCES = something.h something.cc
Parallel installs
Notice that the library is called
something-1.0.la, including the version number
in its name. This will allow the next version,
libsomething-2.0, to be installed alongside,
without preventing use of the previous version.

Directory structure
Don't use 'src'
When the library is installed, its headers will be
installed in their own directory in the 'include'
directory. Code that uses the library should #include
them like so:

#include <something/something.h>
#include <something/extrabits.h>

If you put your source files in a 'src' directory then
the #include lines in your own headers will not work
when they are installed, and the #includes in your
examples (in the 'examples' directory') will be
misleading. At best, they will include like so:

#include <something.h>
#include <extrabits.h>

I suggest that you put your sources in a directory that
has the same name as your library. Then the examples
inside your distribution and any external examples will
use the same path in their #include directives.

Sources in sub directories
In Using automake and autoconf with C++ I explained how
to build intermediate static libraries in each sub
directory. The idea is very similar when building a
library, but the syntax is slightly different.

* Libtool libraries have the .la suffix, instead
of .a
* We need to use _LIBADD instead of_ LDADD.

For instance

lib_LTLIBRARIES = something.la
something_la_SOURCES = main.cc
something_la_LIBADD = sub/libsubstuff.la
This technique is demonstrated in the downloadable example.

Note that, at the time of writing, there are two
problems with libtool that you should be aware of:

* Libtool will not add libtool libraries
recursively. Therefore you need to list all of
the convenience libraries in one place. For
instance:
something_la_LIBADD = sub/libsub.la
sub/subsub/libsubsub.la
* Libtool will not differentiate between two
libraries with the same name in different
directories. Therefore you should probably
include the full path in the name of your
convenience libraries. For instance:
something_la_LIBADD = foo/libfoo.la
foo/sub/libfoo_sub.la goo/libgoo.la
goo/sub/libgoo_sub.la

Hopefully these problems will be fixed in the next
version of libtool. Please tell me when they have been
fixed, so that I can update this page.

Installing headers
When the user types 'make install' the library's header files
should be installed as well as the library itself. You can make
this happen by using these variables in your Makefile.am files:

library_includedir=$(includedir)/something-1.0/something
library_include_HEADERS = something.h foo.h

This will put something.h and foo.h in
include/something-1.0/something/
Users of the library would then #include your headers like so:

#include <something/something.h>
Parallel installs
Notice that the headers should be installed in a
version-specific directory. This will allow the next
version's headers to be installed alongside in
something-2.0, without preventing use of the previous
version's headers.

config.h
The generated config.h header should be installed in the
lib directory, because it is architecture-dependent.
Actually, I'd like a better explanation than that to put
here.

For example, in your Makefile,am file:

something_configdir = $(libdir)/something-1.0/include
something_config_DATA = config.h
Version numbers
Your library should have two numbers - the 'release number' and
the 'version number'.

The release number uses a scheme of your own devising. Generally
it indicates how much functionality has been added since the
last version, and how many bugs were fixed.

The version number uses an established scheme to indicate what
type of changes happened to your library's interface. The
following diagram can be found in many configure.ac files:

EXAMPLE_RELEASE=2:1:3
EXAMPLE_LIBRARY_VERSION=3:0:0
| | |
+------+ | +---+
| | |
current:revision:age
| | |
| | +- increment if interfaces have been added
| | set to zero if interfaces have been removed
| | or changed
| +- increment if source code has changed
| set to zero if current is incremented
+- increment if interfaces have been added, removed or changed

Use this version number in your Makefile.am file:

libsomething_la_LDFLAGS= -version-info $(EXAMPLE_LIBRARY_VERSION) -release $(EXAMPLE_RELEASE)
Making your library easy to use
Experts can use your library if they are given just the headers
and the library, but you can make life much easier for people
who are using automake and autoconf. In my opinion, your library
will appear more complete, and will be used by more people if
you use pkg-config. This tool was created relatively recently to
improve upon the old method, described here. It allows you to
install details about your library, specifically the linker and
include options that should be used with it. Developers can add
a line to their configure.ac files that reads this infomation
back, along with the options required for your library's
dependencies.


The .pc.in file
Your library should install a .pc file, describing the
linker and include options for your library. But those
are dependent on the --prefix given to the configure
script, so you'll need to crate a .pc.in file. For
instance:

prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@

Name: something
Description: Some library.
Requires: somethingelse-2.0 somethingmore-1.0
Version: @VERSION@
Libs: -L${libdir} -lsomething-1.0
Cflags: -I${includedir}/something-1.0 -I${libdir}/something-1.0/include

You'll need to mention this new .in file in your
configure.ac script, like so:

AC_OUTPUT( Makefile \
something/Makefile \
something/sub/Makefile \
something-1.0.pc
)

And you'll need to mention it in your Makefile.am file,
so that it gets installed and distributed. For instance:

pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = something-1.0.pc
Read Using C/C++ libraries with automake and autoconf to
see how this pkg-config file would be used.

Parallel Installs
The .pc.in file should include the version number in its
name. For instance, something-1.0.pc.in. This will allow
the next version of the library to install its own
something-2.0.pc file alongside, without preventing use
of the previous version.

C++ namespaces
If you are writing a C++ library, I strongly suggest that you
put all the classes in a namespace. For instance, in the header
file:

namespace Something
{
class Example
{
Example();
...
};
} /* namespace Something */

And in the implementation file:

namespace Something
{
Example::Example()
{
...
}

...
} /* namespace Something */

This will prevent name clashes and make it more obvious when
other code is using the library.

Example Files
You may download this example which demonstrates how to put all
these ideas together.

This example uses some 'generic' variables instead of repeating
the library name several times. This should make the project
files easier to maintain, and it is used to generate the
examplelib-config script automatically. Thanks to Cedric Gustin
for this idea.

The document Using C/C++ libraries with automake and autoconf
contains an example which links to this library.

Recommended Reading
* Using Automake and Autoconf with C++
* GNU's automake, autoconf, and libtool manuals

No comments:

Blog Archive