[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
RFC: Building a Shared Library
From: |
Alexandre Duret-Lutz |
Subject: |
RFC: Building a Shared Library |
Date: |
Wed, 30 Jul 2003 02:17:05 +0200 |
User-agent: |
Gnus/5.1002 (Gnus v5.10.2) Emacs/21.3 (gnu/linux) |
This is an attempt to rewrite the "Building a Shared Library"
section of the manual, in order to answer some recent questions
about Libtool libraries (notably "gathering convenience
libraries", "conditional compilation using .lo files", and
"foo.lo build both with libtool and without").
All these examples ought be backed up with test cases, but I
haven't yet got around to do it. By the meantime, comments and
corrections (related to English or to Automake...) are greatly
welcome.
------------------------------
Building a Shared Library
=========================
Building shared libraries is a relatively complex matter. For this
reason, GNU Libtool (*note Introduction: (libtool)Top.) was created to
help build shared libraries in a platform-independent way.
Presentation of Libtool
-----------------------
Actually, Libtool abstracts shared and static libraries into an unified
concept henceforth called "Libtool libraries". Libtool libraries are
files using the `.la' suffix, and can designate a static library, a
shared library, or maybe both. What exactly it is, you cannot know
before `./configure'-time: not all platforms support all kinds of
libraries, and users can explicitly select which libraries should be
built. (However the package's maintainers can tune the default, *Note
The `AC_PROG_LIBTOOL' macro: (Libtool)AC_PROG_LIBTOOL.)
Because object files for shared and static libraries must be compiled
differently, Libtool also uses its own abstraction: "Libtool objects".
These are files ending with the `.lo' suffix. Libtool libraries are
built with Libtool objects.
People considering writing a plug-in system, with dynamically loaded
modules, should look into `libltdl': Libtool's dlopening library (*note
Using libltdl: (libtool)Using libltdl.). This offers a portable
dlopening facility to load Libtool libraries dynamically, and can also
achieve static linking where unavoidable.
Before we discuss how to use Libtool with Automake in details, it
should be noted that the Libtool manual also has a section about how to
use Automake with Libtool (*note Using Automake with Libtool:
(libtool)Using Automake.).
Building Libtool libraries
--------------------------
Automake uses Libtool to build libraries declared with the
`LTLIBRARIES' primary. Each `_LTLIBRARIES' variable is a list of
Libtool library to build. For instance, to create a Libtool library
named `libgettext.la', and install it in `libdir', write:
lib_LTLIBRARIES = libgettext.la
libgettext_la_SOURCES = gettext.c gettext.h ...
Automake predefines the variable `pkglibdir', so you can use
`pkglib_LTLIBRARIES' to install libraries in `$(libdir)/@PACKAGE@/'.
Building conditional Libtool libraries
--------------------------------------
As for conditional programs (*note Conditional Programs::), there are
two main ways to build conditonal libraries: using Automake
conditionals or using Autoconf `AC_SUBST'itutions.
The important implementation detail you have to know is that the
place where a library will be installed matters to Libtool: it needs to
be indicated _at link-time_ using the `-rpath' option.
For libraries whose destinations directory is known by the time
Automake runs, Automake will automatically supply the appropriate
`-rpath' option to Libtool. This is the case for libraries listed
explicitly in some `DIR_LTLIBRARIES' variable.
However, for libraries determined at configure time (and thus
mentioned in `EXTRA_LTLIBRARIES'), Automake does not know the eventual
installation directory. For such libraries you must add the `-rpath'
option to the appropriate `_LDFLAGS' variable by hand.
You can see this difference by comparing these two ways to build
Libtool libraries conditionally.
Here is an example where `$(WANTEDLIBS)' is an `AC_SUBST'ed variable
set at `./configure'-time to either `libfoo.la', `libbar.la', both, or
none. Although `$(WANTEDLIBS)' appears in the `lib_LTLIBRARIES',
Automake cannot guess it relates to `libfoo.la' or `libbar.la' by the
time it creates the link rule for these two libraries. Therefore the
`-rpath' argument must be explicitly supplied.
EXTRA_LTLIBRARIES = libfoo.la libbar.la
lib_LTLIBRARIES = $(WANTEDLIBS)
libfoo_la_SOURCES = foo.c ...
libfoo_LDFLAGS = -rpath '$(libdir)'
libbar_la_SOURCES = bar.c ...
libbar_LDFLAGS = -rpath '$(libdir)'
Here is how the same `Makefile.am' would look using Automake
conditionals named `WANT_LIBFOO' and `WANT_LIBBAR'. Now Automake is
able to compute the `-rpath' setting itself, because it's clear that
both libraries will end up in `$(libdir)' if they are installed.
lib_LTLIBRARIES =
if WANT_LIBFOO
lib_LTLIBRARIES += libfoo.la
endif
if WANT_LIBBAR
lib_LTLIBRARIES += libbar.la
endif
libfoo_la_SOURCES = foo.c ...
libbar_la_SOURCES = bar.c ...
Libtool libraries with conditional sources
------------------------------------------
Conditional compilation of sources in a library can be achieved in the
same way as conditional compilation of sources in a program (*note
Conditional Sources::). The only difference is that `_LIBADD' should
be used instead of `_LDADD' and that it should mention Libtool objects
(`.lo' files).
So, to mimic the `hello' example from *Note Conditional Sources::,
we could build a `libhello.la' library using either `hello-linux.c' or
`hello-generic.c' with the following `Makefile.am'.
lib_LTLIBRARIES = libhello.la
libhello_la_SOURCES = hello-common.c
EXTRA_libhello_la_SOURCES = hello-linux.c hello-generic.c
libhello_la_LIBADD = $(HELLO_SYSTEM)
libhello_la_DEPENDENCIES = $(HELLO_SYSTEM)
And make sure `$(HELLO_SYSTEM)' is set to either `hello-linux.lo' or
`hello-generic.lo' in `./configure'.
Or we could simply use an Automake conditional as follows.
lib_LTLIBRARIES = libhello.la
if LINUX
libhello_la_SOURCES = hello-linux.c hello-common.c
else
libhello_la_SOURCES = hello-generic.c hello-common.c
endif
Libtool convenience libraries
-----------------------------
Sometime you want to build Libtool libraries which are not to be
installed. These are called "Libtool convenience libraries" and are
usually used to encapsulate many sublibraries, latter gathered into one
big installed library.
Libtool convenience libraries are declared by `noinst_LTLIBRARIES',
`check_LTLIBRARIES', or even `EXTRA_LTLIBRARIES'. Unlike installed
Libtool libraries they do not need an `-rpath' flag at link time
(actually this is the only difference).
Convenience libraries listed in `noinst_LTLIBRARIES' are always
built. Those listed in `check_LTLIBRARIES' are built only upon `make
check'. Finally, libraries listed in `EXTRA_LTLIBRARIES' are never
built explicitely: Automake outputs rules to build them, but if the
library does not appears as a Makefile dependency anywhere it won't be
built (this is why `EXTRA_LTLIBRARIES' is used for conditional
compilation).
Here is an sample setup merging Libtool convenience libraries from
subdirectories into one main `libtop.la' library.
# -- Top-level Makefile.am --
SUBDIRS = sub1 sub2 ...
lib_LTLIBRARIES = libtop.la
libtop_la_SOURCES =
libtop_la_LIBADD = \
sub1/libsub1.la \
sub2/libsub2.la \
...
# -- sub1/Makefile.am --
noinst_LTLIBRARIES = libsub1.la
libsub1_la_SOURCES = ...
# -- sub2/Makefile.am --
# showing nested convenience libraries
SUBDIRS = sub2.1 sub2.2 ...
noinst_LTLIBRARIES = libsub2.la
libsub2_la_SOURCES =
libsub2_la_LIBADD = \
sub2.1/libsub1.2.la \
sub2.2/libsub2.2.la \
...
Libtool modules
---------------
These are Libtool libraries meant to be dlopened. They are indicated
to Libtool by passing `-module' at link-time.
pkglib_LTLIBRARIES = mymodule.la
mymodule_la_SOURCES = doit.c
mymodule_LDFLAGS = -module
Ordinarily, Automake requires that a Library's name starts with
`lib'. However, when building a dynamically loadable module you might
wish to use a "nonstandard" name.
_LIBADD and _LDFLAGS
--------------------
As shown in previous sections, the `LIBRARY_LIBADD' variable should be
used to list extra Libtool objects (`.lo' files) or Libtool libraries
(`.la') to add to LIBRARY.
The `LIBRARY_LDFLAGS' variable is the place to list additional
libtool flags, such as `-version-info', `-static', and a lot more. See
*Note Using libltdl: (libtool)Link mode.
`LTLIBOBJS'
-----------
Where an ordinary library might include `$(LIBOBJS)', a libtool library
must use `$(LTLIBOBJS)'. This is required because the object files
that libtool operates on do not necessarily end in `.o'.
Nowadays, the computation of `LTLIBOBJS' for `LIBOBJS' is performed
automatically by Autoconf (*note `AC_LIBOBJ' vs. `LIBOBJS':
(autoconf)AC_LIBOBJ vs LIBOBJS.).
The `created with both libtool and without' issue
-------------------------------------------------
Sometimes, the same source file is used both to build a Libtool library
and to build a program or another (non Libtool) library.
Let's consider the following `Makefile.am'.
bin_PROGRAMS = prog
prog_SOURCES = prog.c foo.c ...
lib_LTLIBRARIES = libfoo.la
libfoo_la_SOURCES = foo.c ...
(In this trivial case the issue could be avoided by linking `libfoo.la'
with `prog' instead of listing `foo.c' in `prog_SOURCES'. But let's
assume we really want to keep these program and library separate.)
Technically, it means that we should build `foo.$(OBJEXT)' for
`prog', and `foo.lo' for `libfoo.la'. The problem is that when Libtool
creates `foo.lo' it can erase `foo.$(OBJEXT)', and we really cannot
help it.
Therefore, when Automake detects this situation it will complain
with a message such as
object `foo.lo' created both with libtool and without
A work around to this issue is to ensure that these two objects get
different basenames. As explained in *note renamed objects::, this
happens automatically when per-targets flags are used.
bin_PROGRAMS = prog
prog_SOURCES = prog.c foo.c ...
prog_CFLAGS = $(AM_CFLAGS)
lib_LTLIBRARIES = libfoo.la
libfoo_la_SOURCES = foo.c ...
Adding `prog_CFLAGS = $(AM_CFLAGS)' is almost a no-op, because when the
`prog_CFLAGS' is defined, it is used instead of `AM_CFLAGS'. However
as a side effect it will cause `prog.c' and `foo.c' to be compiled as
`prog-prog.$(OBJEXT)' and `prog-foo.$(OBJEXT)' which solves the issue.
--
Alexandre Duret-Lutz