Copyright © 2005 Yves Mettier
L'article original se trouve sur http://ymettier.free.fr/articles_lmag/.
Article publié dans le numéro 75 (septembre 2005) de GNU/Linux France Magazine
Table des matières
Résumé
Ceux qui ont déjà installé un logiciel en recompilant ses sources ont probablement déjà rencontré la fameuse formule magique ./configure; make; make install
. L'art et la manière de générer le script configure
qui fait tout a fait l'objet d'un article dans le numéro 24 et est disponible sur internet. Depuis, autoconf a vu son numéro de version passer de 2.13 à 2.5X (2.59 lors de la rédaction de ces lignes) et automake est passé de 1.4 à 1.9. Si la compatibilité antérieure a été souhaitée par les développeurs, ceux-ci ont aussi suggéré de perdre les anciennes habitudes. Cet article a pour objectif de reprendre les chose en montrant, à partir d'un exemple trivial, comment générer les fichiers nécessaires à la commande magique.
Que sont et que font au juste les auto-tools ? Les auto-tools sont les outils autoconf, automake, libtool et ceux qui gravitent autour (nous évoquerons aclocal plus loin). Au premier abord, ils permettent de générer des fichiers Makefile que l'on peut paramétrer avec les options fournies au script configure
. Si leur intérêt se limitait à cela, les développeurs préféreraient faire leurs propres fichiers Makefile
et expliquer comment modifier les options par exemple dans un fichier que les Makefile
pourraient inclure.
Les auto-tools permettent de générer des fichiers Makefile
de façon portable, ce qui signifie qu'un programme, tant qu'il ne fait pas appel aux fonctionnalités propres de la plateforme sur laquelle il doit tourner, pourra être compilé partout où les auto-tools (et les dépendances de votre programme) fonctionnent. Notre exemple, conçu sur Darwin (Mac OS X) fonctionnera aussi bien sur Linux que sur Cygwin (MS Windows). Vous n'avez pas à tenir compte vous-même de la version de make
et implicitement du format des fichiers Makefile
et de leurs particularités par exemple.
Mieux, les auto-tools respectent les standards GNU et Unix, en particulier le FHS. Cela fait entre autre la joie des personnes qui créent des paquets pour nos distributions favorites lorsqu'elles respectent aussi le FHS. Ces personnes n'auront aucun mal à adapter les répertoires que votre programme utilise à l'arborescence du système.
Parmi les avantages des auto-tools par rapport à de simples fichiers Makefile
, nous citerons encore le fait que les cibles (pour make) clean
, distcheck
et d'autres sont systématiquement générées, sans le moindre paramétrage supplémentaire de votre part. Il est aussi possible de paramétrer la compilation avec des options --enable-fonctionnalité
ou --with-option
pour le script configure
de notre commande magique. Et j'en passe...
Qui fait quoi ? Nous avons trois commandes et deux types de fichiers (configure.ac
et les fichiers Makefile.am
). Au résultat, nous obtenons un fichier configure
et en l'exécutant, des fichiers Makefile
. C'est touffu !
Autoconf a pour but de générer un fichier configure
qui, lorsqu'on le lance, génère des fichiers à partir de fichiers modèles d'extension .in
. Ainsi, ce script transforme les fichiers Makefile.in
en fichiers Makefile
. Voici un mystère d'éclairci.
Mais d'où viennent ces fichiers Makefile.in
? C'est ici le rôle d'automake. Cet outil prend en compte des fichiers Makefile.am
et génère des fichiers Makefile.in
aux mêmes endroits.
Le rôle d'aclocal est de générer un fichier aclocal.m4
dont nous parlons peu. En effet, il contient des macros (écrites dans le langage m4), dont nous n'avons rarement besoin de connaître l'existence. Sachez cependant qu'elles sont utilisées par le script configure
pour effectuer certains tests et définir des variables dont les fichiers Makefile
auront l'usage.
Enfin, le fichier configure.ac
, fichier de configuration d'autoconf, est utilisé par celui-ci, par aclocal et indirectement par automake. Le premier génère le fichier configure
en fonction du contenu de configure.ac
. Le deuxième n'y fait que rechercher les noms des macros afin de copier celles nécessaires dans le fichier aclocal.m4
à partir de son dépôt (par exemple /usr/share/aclocal/*
). Le dernier prévoit des variables pour ses fichiers Makefile.in
en fonction des tests définis dans configure.ac
.
L'ordre d'exécution des commandes est donc aclocal
en premier, et ensuite indifféremment autoconf
ou automake
. Enfin, avant de compiler avec make
, lancez le configure
de la commande magique.
Afin d'aborder le sujet, nous allons nous servir d'un exemple simple, un programme qui affiche Bonjour le monde et prend fin, dont le code source est réparti sur deux fichiers plus celui des en-têtes. Voici ces trois fichiers :
/* main.c */ #include <stdio.h> #include <stdlib.h> #include "afficher.h" int main(int argc, char**argv) { afficher("Bonjour le monde"); exit(EXIT_SUCCESS); }
/* afficher.c */ #include <stdio.h> #include <stdlib.h> #include "afficher.h" int afficher(char*str) { printf("%s\n", str); return(0); }
/* afficher.h */ #ifndef AFFICHER_H #define AFFICHER_H int afficher(char*str); #endif
Le but de cet article est de compiler le programme bonjour à partir de ces sources.
Tout d'abord, démarrons dans un répertoire vide que nous appellerons racine, ou ${racine}
dans nos scripts.
En général, pour un projet simple, créez un répertoire ${racine}/src/
et mettez-y tous les fichiers sources. Si votre projet doit contenir deux exécutables indépendants, créez un répertoire pour chacun de ces exécutables dans le répertoire racine, à la place du répertoire src/
. Si par contre les deux exécutables partagent certains fichiers sources, vous devez les mettre dans le même répertoire à moins de créer une bibliothèque avec le code commun. Nous voici donc ici avec trois fichiers :
$ find . ./src ./src/afficher.c ./src/afficher.h ./src/main.c
Vous l'aurez compris, votre projet nécessite un fichier configure.ac
à la racine, et un fichier Makefile.am
à la racine ainsi que dans tous les sous-répertoires. Commençons par le fichier configure.ac
; Vous pouvez le générer en lançant la commande autoscan
. Vous obtiendriez un fichier configure.scan
à renommer configure.ac
. Voici ce fichier :
# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) AC_CONFIG_SRCDIR([src/afficher.c]) AC_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([stdlib.h]) # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_OUTPUT
Ce fichier fait appel à quelques notions que nous verrons dans des articles suivants. Aussi, nous allons nous limiter au fichier configure.ac
suivant :
AC_PREREQ(2.59) AC_INIT(bonjour, 0.1, ymettier@libertysurf.fr) AM_INIT_AUTOMAKE AC_PROG_CC AC_PROG_MAKE_SET AC_CONFIG_FILES([ Makefile src/Makefile ]) AC_OUTPUT
Pour insérer des commentaires, faites-les précéder d'un signe #
. Vous pouvez aussi écrire dnl
à la place, comme cela était le cas avec la version 2.13 d'autoconf.
La première ligne permet d'ôter toute ambiguité sur la version d'autoconf à utiliser. Cela est utile sur les machines où autoconf-2.5X cotoie encore l'ancienne version 2.13. La ligne AC_INIT
vous oblige à indiquer le nom de votre projet (notion différente du nom de l'exécutable que nous allons générer), son numéro de version et une adresse électronique que les utilisateurs pourront utiliser pour envoyer des rapports de bogues (pensez à utiliser une liste de diffusion dédiée lorsqu'elle existe). La troisième ligne indique à automake qu'il faut s'initialiser.
Les deux lignes en AC_PROG_*
testent la présence de programmes et définissent des variables. C'est grâce à elles que le script configure va vérifier la présence du compilateur, en général gcc, et définir la variable $CC
. Idem pour make
dont la version et l'implémentation (ce n'est pas toujours GNU Make) varient d'une plateforme à l'autre.
Enfin la ligne AC_CONFIG_FILES
indique les fichiers à générer (à partir des fichiers portant le même nom, mais avec l'extension supplémentaire .in
) et AC_OUTPUT
lance la génération de ces fichiers.
L'étape suivante consiste à éditer des fichiers Makefile.am
. Dans notre cas d'école, celui de la racine ne contient qu'une ligne définissant les sous-répertoires du projet (mettez une espace en guise de séparateur entre les différents sous-répertoires) :
SUBDIRS=src
Pour les autres fichiers Makefile.am
, définissez en premier la variable bin_PROGRAMS
qui doit contenir le nom des binaires à générer. Notre programme s'appelant bonjour, nous y mettons bonjour. La variable suivante définit les fichiers sources nécessaires à la compilation du programme bonjour. Le nom de la variable est constitué du nom du binaire, suivi de l'extension _SOURCES
. Le fichiers ${racine}/src/Makefile.am
est le suivant :
bin_PROGRAMS=bonjour bonjour_SOURCES= \ main.c \ afficher.c afficher.h
Nous verrons dans un article suivant des éléments de syntaxe pour une utilisation un peu plus poussée de ces fichiers Makefile.am
.
Maintenant que nous avons les fichiers en place, nous pouvons exécuter quelques commandes, dans l'ordre :
$ aclocal $ autoconf $ automake -a -c configure.ac: installing `./install-sh' configure.ac: installing `./missing' Makefile.am: installing `./INSTALL' Makefile.am: required file `./NEWS' not found Makefile.am: required file `./README' not found Makefile.am: required file `./AUTHORS' not found Makefile.am: required file `./ChangeLog' not found Makefile.am: installing `./COPYING' src/Makefile.am: installing `./depcomp'
La première fois que l'on invoque automake de la sorte, nous nous rendons compte qu'il manque certains fichiers. Vous pouvez les créer vides, mais il est préférable de mettre votre nom et/ou celui de l'auteur du logiciel dans le fichier AUTHORS
. Et quelques lignes dans le fichier README
ne feront de mal à personne. Pour la postérité, indiquez dans le fichier ChangeLog
la date de vos manipulations pour ajouter le support d'autoconf/automake ! Lorsque les fichiers manquants sont créés, invoquez automake -a -c
à nouveau : il ne devrait plus rouspéter. Et vous venez de finir de générer tout le nécessaire à la commande magique que vous pouvez lancer :
$ ./configure checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for gawk... gawk checking whether make sets $(MAKE)... yes checking for gcc... gcc [...] configure: creating ./config.status config.status: creating Makefile config.status: creating src/Makefile config.status: creating config.h config.status: executing depfiles commands $ make [...] $ make install
Le projet bonjour va probablement prendre de l'ampleur. Voici quelques cas simples et courants que vous pouvez être amenés à rencontrer.
Ajouter des options pour modifier le comportement du compilateur ou celui de l'éditeur de liens est chose courante. Vous pouvez ainsi compiler avec l'option -g
afin de pouvoir déboguer plus facilement avec gdb. Ce genre d'options ne doit pas apparaître dans le projet et c'est à la personne qui compile de les indiquer. Pour cela, elle profite des variables d'environnement CPPFLAGS
pour le préprocesseur, CFLAGS
pour le compilateur et LDFLAGS
pour l'éditeur de liens. Cela donne :
$ ./configure $ make CFLAGS="-O2" $ make install-strip
Nous générons ainsi un exécutable optimisé, et l'installons avec la cible install-strip
qui supprime tout ce qui est inutile dans la table des symboles. Pour en savoir plus sur cette opération, voyez la page de manuel de l'outil strip.
Il est néanmoins une option qu'il peut être souhaitable d'indiquer systématiquement au compilateur : l'option -Wall
. En présence de celle-ci, le compilateur affiche tous les messages d'avertissement qu'il peut (ou presque, voyez la page de manuel de gcc et les options commençant par -W
). Pour insérer cette option, nous modifions la variable CFLAGS
via le fichier configure.ac
et ajoutons ceci à la fin, avant la ligne AC_CONFIG_FILES
:
if test "x$GCC" = "xyes"; then CFLAGS="$CFLAGS -Wall" fi
Cette opération peut ajouter deux fois ou plus l'option -Wall
. Mais le compilateur gcc ne vous en tiendra pas rigueur. C'est pourquoi nous ne compliquons pas ces trois lignes avec un code qui teste la présence de l'option dans CFLAGS
.
Imaginons que nous ajoutions une nouvelle fonctionnalité, par exemple l'appel à la fonction plouff()
définie dans le fichier src/plouf.c
. Nous disposons aussi du fichier d'en-têtes src/plouf.h
. Pour prendre en compte ces deux nouveaux fichiers, éditez le fichier src/Makefile.am
et ajoutez les noms des deux nouveaux fichiers à ceux existant déjà, avant ou après, peu importe. Voici le nouveau fichier src/Makefile.am
:
bin_PROGRAMS=bonjour bonjour_SOURCES= \ main.c \ plouf.c plouf.h \ afficher.c afficher.h
Comme vous venez de modifier un fichier Makefile.am
, vous devez relancer automake. Avec les versions récentes d'automake, les fichiers Makefile
sont générés de telle manière qu'une modification dans un fichier Makefile.am
est détectée et en exécutant make
, vous regénérez tous les fichiers impactés par votre modification. La suppression d'un fichier source est similaire à celle d'un ajout : vous modifiez la variable bonjour_SOURCES
et la suite ne change pas.
Ajouter le support d'une bibliothèque est très simple lorsque celle-ci est placée dans un endroit standard. Il vous suffit d'ajouter une ligne dans le fichier configure.ac
. Voici celle qui vous permet d'utiliser la bibliothèque mathématique libm :
AC_SEARCH_LIBS(pow, m)
En général, l'absence d'une bibliothèque devrait provoquer l'arrêt du script configure
. Le troisième argument de AC_SEARCH_LIBS
est l'action à effectuer si le test est positif, et le quatrième celle si le test est négatif. Nous pouvons profiter de ce dernier ainsi :
AC_SEARCH_LIBS(pow, m, [], [exit])
Vous pouvez aussi afficher un message à la place d'une simple sortie. Pour cela, utilisez AC_MSG_ERROR
; Voici le résultat pour libz :
AC_SEARCH_LIBS(gzopen, z, [], [ AC_MSG_ERROR([zlib est manquante]) ])
Une modification de configure.ac
nécessite la relance d'aclocal
, d'autoconf
et d'automake
.
Qu'entendons-nous par nettoyage ? S'il s'agit de supprimer tout ce qui a été compilé, principalement les fichiers objets (dont extension est .o
), exécutez simplement make clean
. SI vous voulez par contre supprimer aussi les fichiers générés suite à l'exécution de configure
, lancez la commande make distclean
.
Vous pouvez aussi vouloir faire le grand nettoyage et ne garder que les fichiers sources, ainsi que le strict nécessaire à autoconf et automake. Dans ce cas, supprimez tout sauf :
les sources de votre code (typiquement les fichiers d'extension .c
et .h
; notez que le fichier ${racine}/config.h
est généré par configure
: vous pouvez le supprimer aussi) ;
les fichiers Makefile.am
;
le fichier configure.ac
;
les fichiers ChangeLog
, NEWS
, README
et AUTHORS
;
si vous les avez modifiés, les fichiers COPYING
et INSTALL
.
Après un tel ménage, il ne reste dans notre projet bonjour plus que les fichiers suivants :
$ find . . ./AUTHORS ./ChangeLog ./configure.ac ./Makefile.am ./NEWS ./README ./src ./src/afficher.c ./src/afficher.h ./src/main.c ./src/Makefile.am
Pour générer un tel paquet, nous pensons à la commande tar
du répertoire ${racine}
renommée au préalable bonjour-0.1
. Mais il y a beaucoup plus simple : exécutez make dist
. Vous obtenez votre paquet, avec pour nom et numéro de version ce que vous avez défini dans configure.ac
sur la ligne AC_INIT
.
Cela n'est pas encore la meilleure méthode. En effet, le plus propre est de lancer la commande make distcheck
. Ainsi, non seulement vous générez le paquet souhaité, mais il est aussi testé pour vous, dans un répertoire différent de celui de développement. Vous mettez ainsi en évidence s'il manque des fichiers, présents dans l'arborescence de développement, mais non déclarés dans les fichiers Makefile.am
.
Si vous voulez générer un fichier bonjour-0.1.tar.bz2
, exécutez la commande make dist-bzip2
. Vous pouvez obtenir les cibles possibles avec un simple grep "^dist-" Makefile
. Celles d'automake-1.8.5 sont les suivantes : dist-gzip
, dist-bzip2
, dist-tarZ
, dist-shar
et dist-zip
.
...mais ce sera pour une prochaine fois car il y a tant à dire sur autoconf, automake, et même libtool...
Merci à Guillaume Rousse pour ses précieux conseils lors de sa relecture.
Le manuel d'autoconfhttp://www.gnu.org/manual/autoconf/index.html ;
Le manuel d'automakehttp://www.gnu.org/manual/automake/index.html ;
C en action (O'Reilly).
© 2005 Yves Mettier