Olivier Poncet
Directeur Technique · CTO

Les autotools - libtool

cover🔗 publié par Olivier Poncet le 28/01/2017 à 12:00

Nous avons vu précédemment que autotools est un terme générique utilisé pour désigner l’ensemble des outils de build du projet GNU, le GNU build system.

Dans ce billet, nous allons faire un focus sur l’outil libtool, qui est un outil permettant de produire des librairies de manière portable et de gérer correctement l’édition des liens quelque-soit la plateforme cible.

Cet outil aide à la création de bibliothèques statiques et dynamiques en proposant une interface totalement abstraite par rapport à la plate-forme visée, masquant ainsi les différences de comportement et d’implémentation (Linux, BSD, Solaris, AIX, …). Cet outil s’interface avec automake.

Exemple minimal complet

L’usage de libtool est en fait totalement transparent, ce qui donne un petit côté « magiciel » à tout ça. La seule contrainte étant de l’initialiser dans le fichier configure.ac à l’aide de la macro LT_INIT. Tout le reste se passera dans les fichier Makefile.am en déclanrant les librairies à l’aide de la variable lib_LTLIBRARIES. Pour le reste, tout sera automatique … Magique !

Plutôt de longs discours, je vais donner un exemple permettant de construire un projet « myproject » fournissant :

  • Une bibliothèque « mylibrary ».
  • Un programme « myprogram » qui sera lié à la bibliothèque « mylibrary ».
  • Une suite de tests unitaires « testsuite ».

Arborescence

myproject
  |
  |`-> configure.ac
  |`-> Makefile.am
  |`-> AUTHORS
  |`-> COPYING
  |`-> NEWS
  |`-> README
  |`-> ChangeLog
  |
  |`-> mylibrary
  |      |
  |      |`-> Makefile.am
  |      |`-> mylibrary.pc.in
  |      |`-> sources/headers
  |      `--> ...
  |
  |`-> myprogram
  |      |
  |      |`-> Makefile.am
  |      |`-> sources/headers
  |      `--> ...
  |
  `--> testsuite
         |
         |`-> Makefile.am
         |`-> sources/headers
         `--> ...

Fichier configure.ac

# configure.ac
AC_INIT([myproject], [1.0.0], [nobody@nohost.nodomain])
AM_INIT_AUTOMAKE
LT_INIT
AC_PROG_CC
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
	Makefile
	mylibrary/Makefile
	mylibrary/mylibrary.pc
	myprogram/Makefile
	testsuite/Makefile
])
AC_OUTPUT

Fichier Makefile.am

# Makefile.am
SUBDIRS = \
	mylibrary \
	myprogram \
	testsuite \
	$(NULL)

Fichier mylibrary/Makefile.am

# mylibrary/Makefile.am
lib_LTLIBRARIES = \
	libmylibrary.la \
	$(NULL)

libmylibrary_la_includedir = $(includedir)/mylibrary

libmylibrary_la_SOURCES = \
	mylibrary-priv.h \
	mylibrary.c \
	$(NULL)

libmylibrary_la_include_HEADERS = \
	mylibrary.h \
	$(NULL)

libmylibrary_la_CPPFLAGS = \
	-I$(top_srcdir) \
	$(NULL)

libmylibrary_la_LDFLAGS = \
	-L$(top_builddir) \
	-version-info 0:0:0 \
	$(NULL)

libmylibrary_la_LIBADD = \
	-lX11 -lXext \
	$(NULL)

pkgconfigdir = $(libdir)/pkgconfig

pkgconfig_DATA = \
	mylibrary.pc \
	$(NULL)

EXTRA_DIST = \
	mylibrary.pc.in \
	$(NULL)

Fichier mylibrary/mylibrary.pc.in

# mylibrary/mylibrary.pc.in
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@

Name: mylibrary
Description: my super useful library
Version: @PACKAGE_VERSION@
Requires:
Cflags: -I${includedir}
Libs: -L${libdir} -lmylibrary

Fichier myprogram/Makefile.am

# myprogram/Makefile.am
bin_PROGRAMS = \
	myprogram \
	$(NULL)

myprogram_SOURCES = \
	myprogram.c \
	myprogram.h \
	$(NULL)

myprogram_CPPFLAGS = \
	-I$(top_srcdir) \
	$(NULL)

myprogram_LDFLAGS = \
	-L$(top_builddir) \
	$(NULL)

myprogram_LDADD = \
	$(top_builddir)/mylibrary/libmylibrary.la \
	$(NULL)

Fichier testsuite/Makefile.am

# testsuite/Makefile.am
check_SCRIPTS = \
	testsuite.sh \
	$(NULL)

check_PROGRAMS = \
	testsuite \
	$(NULL)

testsuite_SOURCES = \
	testsuite.c \
	testsuite.h \
	$(NULL)

testsuite_CPPFLAGS = \
	-I$(top_srcdir) \
	-I$(top_srcdir)/mylibrary \
	$(NULL)

testsuite_LDFLAGS = \
	-L$(top_builddir) \
	$(NULL)

testsuite_LDADD = \
	$(top_builddir)/mylibrary/libmylibrary.la \
	$(NULL)

TESTS = \
	testsuite.sh \
	$(NULL)

EXTRA_DIST = \
	testsuite.sh \
	$(NULL)

MOSTLYCLEANFILES = \
	testsuite.log \
	$(NULL)

What else ?

Finalement, l’usage de libtool se révèle plutôt aisé. J’ai volontairement omis quelques détails techniques, mais j’y reviendrai une prochaine fois, promis.