Retrouvez cet article dans : Linux Magazine 79
Introduction
Le mois dernier, l’article qui aurait du paraître a montré une lacune en ce qui concerne les conventions de nommage des variables. Plutôt que de réparer cela à la dernière minute en effleurant le sujet, nous avons préféré prendre notre temps pour le traiter un peu plus en détail, en le limitant aux variables d’automake, ce qui est déjà pas mal. Vous verrez dans cet article que ces variables permettent de définir ce que vous voulez compiler et comment. Mais la réalisation de cette compilation passe par l’outil make et ses cibles, ce qui compose la seconde partie de l’article. Nous y développons les cibles principales, celles qui permettent de lancer la compilation, créer une archive ou faire le ménage.
Les variables dans Makefile.am
Les variables sont composées d’un radical et d’un suffixe, parfois d’un préfixe. A l’aide des différents suffixes, vous pouvez associer à un radical des fichiers sources, un répertoire d’installation, une liste de programmes ou bibliothèques à compiler ou lier...
La variable la plus connue est probablement
Notez que certains outils peuvent ajouter leurs propres suffixes primaires. C’est entre autres le cas de libtool qui amène LTLIBRARIES.

Lorsque ces variables à suffixe primaire ont permis de définir la liste des objets à construire, il nous faut, pour certains, indiquer à automake comment le faire. Pour un programme en C ou C++, vous devez indiquer les fichiers sources. Vous pouvez aussi ajouter quelques options au compilateur ou à l’éditeur de liens.
Dans tous les cas, le principe consiste à utiliser le nom de l’objet comme radical et à lui ajouter le suffixe adéquat. Si vous avez par exemple déclaré l’objet plouf avec bin_PROGRAMS=plouf, vous pouvez utiliser plouf comme radical et indiquer les fichiers sources avec le suffixe SOURCES ainsi : plouf_SOURCES=plouf1.c plouf2.c.
C’est ici l’occasion pour tenter de clarifier l’utilisation des suffixes servant à indiquer des options au compilateur et à l’éditeur de liens. Voyez les tableaux 2 et 3 à ce sujet.
Nous allons, pour l’exemple, compiler un programme avec l’option -ansi, l’option d’optimisation -O2, et le lier à libtruc dont les fichiers se trouvent dans /opt/libtruc/include et /opt/libtruc/lib. Voici à quoi pourrait bien ressembler notre fichier Makefile.am :
LIBTRUC_PREFIX=/opt/libtruc
bin_PROGRAMS=plouf
plouf_SOURCES=plouf1.c plouf2.c
plouf_CFLAGS=-ansi
plouf_CPPFLAGS=-I${LIBTRUC_PREFIX}/include
plouf_LDADD=-L${LIBTRUC_PREFIX}/lib -ltruc
Remarquez l’utilisation de la variable make CFLAGS=-O2
Sur la ligne de commande du compilateur, vous pourrez ainsi trouver, dans l’ordre, ceci : ${plouf_CFLAGS} ${CFLAGS}.
Vous savez maintenant conjuguer les radicaux et les suffixes. Nous allons garder les préfixes pour les paragraphes suivants car contrairement aux suffixes qui créent de nouvelles cibles spécifiques à ce que vous voulez générer, les préfixes influent directement sur les cibles génériques.
Les cibles générées par automake
Automake prépare plusieurs cibles dans le fichier Makefile.in (transformé en Makefile par le script configure). Parmi celles-ci, nous allons aborder plusieurs familles de cibles, celles de compilation (all), d’installation (install), de distribution (dist et distcheck) et de nettoyage (clean et distclean).
Cibles de compilation
Les cibles de compilation génériques sont all et all-am. La seconde est une dépendance de la première, ce qui permet d’ajouter éventuellement les vôtres (ce qui est rare, et déconseillé si vous n’avez pas atteint les limites d’automake).
La cible all-am sert à générer le fichier Makefile, puis tous les objets que vous avez pu définir à l’aide de suffixes primaires. En d’autres termes, avec cette cible, vous lancez la compilation de vos programmes (suffixe PROGRAMS), bibliothèques (suffixe LIBRARIES ou, avec libtool, LTLIBRARIES) et ainsi de suite. Automake s’occupe bien évidemment des dépendances telles que de compiler chaque fichier source pour pouvoir ensuite les lier dans un programme ou une bibliothèque.
Le fichier Makefile est une dépendance de all-am ce qui peut paraître surprenant. En l’absence de ce fichier, donc de l’indication de la dépendance, quel est l’intérêt de l’indiquer à make ? En l’absence de ce fichier, il est nul. Par contre, en sa présence, la date est testée, et make sait regénérer le fichier Makefile s’il est moins récent que Makefile.in ou config.status. En d’autres termes, si vous touchez aux fichiers relatifs aux auto-tools, make sait s’en apercevoir et faire le nécessaire avant de passer à vos objets.
Cibles d’installation
La cible la plus connue pour l’installation est install. Cette cible ne présente pas grand intérêt pour le programmeur, car c’est en général l’utilisateur qui en fait le plus grand usage. Néanmoins, le programmeur peut s’interroger sur ce qui sera installé. Normalement, tous les objets définis à l’aide des suffixes primaires et seulement ceux-ci sont installés. Si vous souhaitez installer des fichiers non cités via des variables à suffixes primaires, le plus simple est de... les citer dans une variable à suffixe primaire. Le meilleur exemple est le fichier d’en-tête proposé avec une bibliothèque, par exemple truc.h. Si vous l’indiquez via truc_SOURCES=truc1.c truc2.c truc.h, ce fichier ne sera pas installé. Au lieu d’écrire cela, indiquez include_HEADERS=truc.h. Mais où vont être installés mes fichiers ? Prenez le radical de la variable à suffixe primaire. Ajoutez-lui dir (sans le tiret bas), et si cette nouvelle variable est définie par défaut, vous savez où sera installé votre objet.
Appliquons cela à bin_PROGRAMS : extrayez le radical bin, ajoutez-lui dir et vous obtenez la variable bindir qui est définie ainsi : bindir=${exec_prefix}/bin, la variable exec_prefix étant par défaut égale à prefix, le répertoire d’installation. Les variables par défaut peuvent être consultées avec un configure –help :
--prefix=PREFIX install architecture-independent files in PREFIX
[/usr/local]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
[PREFIX]
[...]
--bindir=DIR user executables [EPREFIX/bin]
--sbindir=DIR system admin executables [EPREFIX/sbin]
--libexecdir=DIR program executables [EPREFIX/libexec]
--datadir=DIR read-only architecture-independent data [PREFIX/share]
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
--infodir=DIR info documentation [PREFIX/info]
--mandir=DIR man documentation [PREFIX/man]
L’interprétation en français donne le tableau 4. Nous y ajoutons trois répertoires que hopdocsdir=${pkgdatadir}/docs
hopdocs_DATA=hop.readme
Nous aurions pu utiliser icihopdocs_DATA=readme noinst_hopdocs_DATA=readme.tmpIl existe une autre cible d’installation intéressante :
Cibles de distribution
La distribution consiste en réalité à créer une archive au format .tar.gz (ou autre comme nous allons le voir ensuite) contenant tous les fichiers utiles à la compilation du projet. Pour un programme en C, cela revient à faire une archive contenant les fichiers sources et les scripts de compilation. La cible s’appelle
- Les fichiers de base pour les auto-tools (inclus :
configure, lesMakefile.am, lesMakefile.in,AUTHORS,LICENSE,README,ChangeLog...) ; - Les fichiers sources (déclarés dans un fichier
Makefile.amavec une variable à suffixe_SOURCES) ; - Les fichiers indiqués dans un fichier
Makefile.amavec la variableEXTRA_DIST; - Les fichiers indiqués dans un fichier
Makefile.amavec une variable que vous avez préfixée pardist_.
bin_PROGRAMS=plouf plouf_SOURCES=plouf1.c plouf2.c EXTRA_DIST=doc.html dist_man_MANS=plouf.1Ne seront pas distribués les fichiers indiqués avec une variable à suffixe primaire. Par exemple, si vous voulez utiliser la variable
make distcheck DISTCHECK_CONFIGURE_FLAGS=’--with-libP=/home/votre_compte/libP’Si maintenant la création de votre archive devait échouer, vous n’auriez plus à chercher du côté de
gzip -dc archive.tar.gz | bzip2 > archive.tar.bz2
Cependant, cela devient plus complexe pour d’autres types d’archives, et surtout, il existe ce qu’il faut avec les auto-tools ! Vous disposez des cibles indiquées dans le tableau 5. Ces cibles s’utilisent comme make dist.
Cibles de nettoyage
Nous terminons cet article avec les cibles de nettoyage. Vous connaissez probablement make clean qui supprime les fichiers issus de l’exécution de la commande make. Il existe aussi make distclean qui supprime également les fichiers générés lors de l’exécution du script configure, comme les fichiers Makefile.

Si vous souhaitez ajouter un fichier à la liste des fichiers à effacer avec make clean, le plus simple est de l’ajouter à la variable CLEANFILES. De la même façon, si make distclean ne parvient pas à supprimer un fichier, utilisez la variable DISTCLEANFILES.
Conclusion
Nous espérons que cette introduction à la grammaire des variables d’automake vous poussera à mieux tirer profit des fichiers Makefile.am pour vos projets.
Cet article ne pouvant pas être exhaustif, nous vous invitons à vous référer au manuel d’automake qui, si un exemple ne vous donne pas immédiatement la solution de votre problème, vous proposera au moins quelques pistes.
En ce qui concerne les cibles, nous n’avons abordé que les plus simples, en partant du principe qu’une variable pouvait les conditionner. Il en existe d’autres, et vous pouvez compléter avec les vôtres. Ceci fera probablement l’objet d’un article prochainement. Mais le mois prochain, nous repartirons à l’assaut des bibliothèques avec pour prétexte, la création d’une macro M4.
Remerciements
Remerciements à Guillaume Rousse pour sa relecture et ses avis éclairés.
Liens :
- Le manuel d’automake, http://www.gnu.org/manual/automake/index.html
- Recommandations du Filesystem Hierarchy Standard, http://www.pathname.com/fhs/
- C en action, (O’Reilly), Chapitre 20.
Retrouvez cet article dans : Linux Magazine 79





Donnez votre avis
Vous devez avoir ouvert une session pour écrire un commentaire.