Automatisation de la compilation
Introduction
Ce chapitre pose les bases pour utiliser les outils autoconf, automake et libtool. Nous avons vu que pour de petits et moyens projets nous pouvions utiliser l’outil make dans la recette "Automatiser la compilation avec make" (chapitre "Outils de compilation"). Cependant, dès lors que vous voulez automatiser la compilation tout en proposant des outils assez simples à l’utilisateur pour modifier quelques paramètres de compilation, ou capables de tenir compte des versions des composants logiciels pré-requis, make ne suffit plus. Plusieurs projets furent lancés dans ce but, et nous pouvons citer xmkmf, aujourd’hui tombé dans l’oubli car il nécessitait un serveur X11 dont il faisait partie de la suite logicielle. Son concurrent, l’ensemble autoconf, automake et libtool lui a survécu et est devenu un standard pour les développeurs de logiciels libres.
Les versions de ces logiciels sont assez compatibles entre elles à partir de la 2.50 pour autoconf, 1.6 pour automake et 1.4 pour libtool. Par conséquent, en fonction de la machine dont vous disposez, vous n’aurez pas forcément la version la plus récente de ces logiciels, mais cela n’est pas génant pour la lecture de ce chapitre. Les exemples ont été écrits avec les versions 2.59 d’autoconf, 1.8.5 d’automake et 1.5.14...
Démarrer un projet avec autoconf et automake
Problème
Vous disposez des sources d’un programme et vous souhaitez ajouter ou remplacer les scripts de compilation par ceux générés par autoconf et automake.
Solution
L’automatisation de la compilation avec autoconf et automake suit les étapes suivantes :
Mettre les sources dans src/.
Exécuter autoscan.
Créer configure.ac à partir de configure.scan ainsi généré.
Éditer Makefile.am et src/Makefile.am.
Ajouter les fichiers manquants (AUTHORS, NEWS...).
Exécuter aclocal, autoconf, autoheader, automake.
Tester l’ensemble.
make distcheck.
Tester à partir du résultat.
Discussion
Étape 1. La première étape consiste à créer un répertoire, initialement vide, que nous appelons racine, et un sous-répertoire généralement nommé src/. Déplacez les fichiers source (sans les scripts de compilation) dans ce répertoire src/. Pour l’exemple, nous supposerons que nos sources consistent en trois fichiers main.c, util.c et util.h.
Étape 2. Afin de créer un script nécessaire à autoconf, exécutez autoscan sans arguments. Un fichier configure.scan est ainsi créé.
Étape 3. Vous pouvez renommer ce fichier configure.scan en configure.ac...
Ajouter des tests de fonctions ou de bibliothèques
Problème
Lors de l’exécution du script configure, vous voulez tester si une fonction ou une bibliothèque est présente sur le système, puis modifier les options du compilateur et de l’éditeur de liens en fonction de l’emplacement de la bibliothèque concernée.
Solution
Ajoutez le nom de la fonction à tester à la macro AC_CHECK_FUNCS et le nom d’un fichier d’en-têtes à la macro AC_CHECK_HEADERS. Indiquez le nom d’une bibliothèque à AC_CHECK_LIB.
Discussion
Nous distinguons plusieurs cas et proposerons à chaque fois un extrait du script configure.ac.
Fonction de libc
Pour tester si une fonction se trouve dans la bibliothèque C standard, lisez la page de manuel correspondante et effectuez un test sur les fichiers d’en-têtes correspondants, puis sur la fonction elle-même. Voici un exemple pour pthread_create() :
AC_CHECK_HEADERS(pthread.h, [], [exit])
AC_CHECK_FUNC(pthread_create, [], [exit])
Le premier argument est, première ligne, l’en-tête à vérifier et, ligne suivante, la fonction dont la présence en standard est vérifiée. Le deuxième argument est l’instruction à exécuter si le test est concluant, donc ici, rien, puisqu’il n’y a rien à faire. Le troisième argument est l’instruction à exécuter si le test échoue. Ici, nous choisissons de nous arrêter avec exit.
Fonction d’une bibliothèque quelconque
Pour tester la présence d’une bibliothèque quelconque, et dans le cas favorable, ajuster les options de compilation et d’édition des liens...
Récupérer les variables de la commande ./configure
Problème
Vous souhaitez personnaliser la ligne de commande afin de paramétrer les options du compilateur ou de spécifier des macros à utiliser via la compilation conditionnelle.
Solution
Utilisez AC_ARG_WITH pour obtenir les options de type --with-[...] et AC_ARG_ENABLE pour celles de type --enable-[...].
Discussion
Lorsque vous exécutez le script configure, vous pouvez lui fournir plusieurs types d’arguments. Certains permettent de changer certaines variables. C’est le cas de l’option la plus connue --prefix qui change le contenu de la variable prefix. La liste de ces options est accessible avec configure --help.
D’autres options du type --with-option sont directement programmables avec AC_ARG_WITH. Le premier argument est l’option. Le second est un message d’aide, qui est affiché lorsque l’utilisateur exécute configure --help. Les deux derniers arguments sont les actions, si l’option est indiquée sur la ligne de commande et si elle ne l’est pas. Dans le premier cas, la variable withval contient ce que l’utilisateur a éventuellement spécifié après le signe = facultatif. Deux exemples dans la recette précédente illustrent l’utilisation de AC_ARG_WITH dans des conditions concrètes. L’exemple suivant montre d’autres possibilités :...
Passer des options supplémentaires au compilateur
Problème
Vous souhaitez ajouter des options supplémentaires au compilateur ou à l’éditeur de liens.
Solution
Utilisez les variables CFLAGS et LDFLAGS, et leurs dérivées.
Discussion
Dans la recette précédente nous avons vu que nous pouvions définir des variables avec AC_SUBST que vous retrouvez dans le fichier Makefile.am. Nous pouvons les utiliser pour ajouter des options de compilation ou d’édition des liens avec les variables de suffixe _CFLAGS et _LDADD. L’exemple suivant ajoute les options -Wall -O2 au compilateur dans le fichier Makefile.am :
exemple_CFLAGS=-Wall -O2
Vous pouvez aussi utiliser les variables CFLAGS et LDFLAGS qui sont prises en compte systématiquement par le compilateur et l’éditeur de liens. En indiquant CFLAGS=-Wall, tous les programmes compilés le seront avec cette option. Pour avoir un binaire statique, utilisez LDFLAGS=-static.
Vous pouvez définir ces variables de manière définitive dans le fichier configure.ac comme cela est conseillé pour l’option -Wall :
changequote(,)
if test "x$GCC" = "xyes"; then
case " $CFLAGS " in
*[\ \ ]-Wall[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wall" ;;
esac
fi
changequote([,])
Attention ! La quatrième ligne contient une tabulation avant le dernier crochet fermant...
Prendre en compte l’internationalisation d’un projet
Problème
Vous avez internationalisé votre projet avec gettext (chapitre "Internationalisation") et souhaitez intégrer l’automatisation de la gestion des langues dans le projet avec autoconf et automake.
Solution
Exécutez gettextize -c et effectuez les modifications nécessaires dans les différents fichiers configure.ac, Makefile.am, src/Makefile.am et po/POTFILES.in.
Discussion
Pour automatiser l’internationalisation, certains fichiers manquants sont créés en exécutant gettextize -c dans le répertoire qui contient configure.ac. Cela ajoute des répertoires, dont po/. Certaines versions de gettextize modifient elles-mêmes certains fichiers, puis affichent un texte indiquant la suite des opérations. Lorsque ce texte est affiché, suivez-le en parallèle avec cette recette.
Éditez le fichier Makefile.am afin d’ajouter les répertoires ainsi créés :
SUBDIRS=intl src po
Certaines versions de gettextize créent un répertoire m4/ dont il faut rajouter le nom à la liste. Certaines ne créent pas le répertoire intl/ que vous n’ajouterez pas dans ce cas.
Éditez aussi configure.ac afin d’y mettre la liste des langues supportées et un appel à la macro AM_GNU_GETTEXT :
ALL_LINGUAS="fr" ...
Utiliser autoconf, automake et libtool pour créer une bibliothèque
Problème
Vous souhaitez tirer profit de l’automatisation de la création des scripts de compilation et en particulier libtool afin de créer une bibliothèque.
Solution
Exécutez libtoolize -c et adaptez les fichiers configure.ac et Makefile.am pour prendre en compte l’utilisation de libtool.
Discussion
Pour adapter les scripts configure.ac et Makefile.am, nous commençons par exécuter libtoolize -c qui copie certains fichiers dont libtool dans le répertoire source racine du projet. Puis nous pouvons éditer configure.ac. Nous y ajoutons les lignes suivantes :
LIBTEST_CURRENT=0
LIBTEST_REVISION=0
LIBTEST_AGE=0
AC_SUBST(LIBTEST_CURRENT)
AC_SUBST(LIBTEST_REVISION)
AC_SUBST(LIBTEST_AGE)
AM_PROG_LIBTOOL
La dernière ligne indique aux différents utilitaires que nous utilisons libtool. Les autres permettent de centraliser la définition du numéro de version de la bibliothèque, sachant que le principe de numérotation peut varier d’un système à l’autre. Libtool nous propose donc ainsi un système uniforme et s’adapte ensuite au système sur lequel il est exécuté.
Libtool part du principe qu’un numéro de version est codé actuel:révision:ancienneté. Le numéro...
Créer une bibliothèque et l’utiliser dans un projet avec autoconf et automake
Problème
Votre projet contient une bibliothèque dans un répertoire et vous souhaiteriez l’utiliser dans un programme dont le code source se trouve dans un autre répertoire.
Solution
Programmez vos scripts de manière à compiler la bibliothèque en premier, puis indiquez les bons chemins pour les fichiers d’en-têtes à la compilation du programme et pour la bibliothèque lors de l’édition des liens.
Discussion
L’ordre de compilation des composants d’un projet correspond à l’ordre des répertoires listés dans la variable SUBDIRS dans le fichier Makefile.am du répertoire racine des sources. Pour un projet contenant une bibliothèque dans le répertoire libtest/ et un programme dans le répertoire src/, la bibliothèque sera compilée avant le programme avec un fichier Makefile.am contenant ceci :
SUBDIRS=libtest src
Dans le fichier Makefile.am dans le répertoire du programme, vous souhaitez indiquer au compilateur (option -I) et à l’éditeur de liens (option -L) le chemin de la bibliothèque. Ces chemins ne peuvent pas être relatifs au répertoire courant car dans certaines conditions (lors de l’exécution de make distcheck par exemple), l’emplacement...