Utilisation des Imakefiles
Article pour l'Echo de Linux (Octobre 1996)
Pierre Ficheux (pierre@rd.lectra.fr)Le système des Imakefiles permet de générer le fichier Makefile d'une application en tenant compte des particularités des diverses plate-formes de génération de cette application.
Le concept des Imakefiles a été introduit dans les distributions de X11. En effet, X étant supporté par un grand nombre d'implémentations d'UNIX, la gestion des particularités des systèmes deviendrait vite inextricable si l'on se limitait à l'utilisation des simples Makefiles. Les Imakefiles permettent de résoudre élégamment (et simplement !) le problème en fournissant en plus une procédure standard de génération d'une application X.
Le système des Imakefiles utilise 2 entités principales :
Le programme imake utilise les fichiers de configuration pour générer un fichier Makefile à partir du fichier Imakefile de l'application. Ce programme est basé sur le préprocesseur C (cpp). Les fichiers de configuration (ainsi que le fichier Imakefile) utiliseront la syntaxe du cpp (#define ,#include, commentaires = /* */, ...).
Les fichiers de configuration sont de 2 types :
Les fichiers généraux sont situés sur le répertoire de configuration qui pour XFree86 est /usr/X11R6/lib/X11/config. Les principaux fichiers sont :
#define HasGcc NO pas de gcc par défaut #define SystemV NO pas UNIX System V
AllTarget(xtest) dans l'Imakefilegénère le but :
all:: xtest dans le Makefile
sun.cf pour les Sun sgi.cf pour Silicon Graphics ibm.cf pour stations IBM lectra.cf devinez ! x386.cf pour Xfree86
#define DontBuildMotifDemos #define MTop /home2/devel/X11/Motif-2.0 #define UseLocalXpm YES #define XpmTop /usr/X11R6
Le fichier correspondant à la plate-forme est sélectionné lors de l'appel à imake car celui-ci définit un symbole caractéristique de l'architecture de la plate-forme (sun, lectra, sgi, ...). Le nom du fichier est associé au nom du symbole défini.
Ces fichiers permettent de surcharger les valeurs par défaut des fichiers Imake.tmpl et Imake.rules. Par exemple, dans le fichier lectra.cf, on pourra lire :
#define HasGcc YES #define SystemV YES #define StandardDefines -DSYSV -DUSG ...
Grace au fichier .cf, les spécificités du système seront prises en compte AUTOMATIQUEMENT lors de la génération du Makefile et ce sans AUCUNE intervention de l'utilisateur.
Le fichier Imakefile est une suite de macro-instructions dont la plupart sont définies dans le fichier Imake.rules. Il peut aussi contenir des affectations de variables ou bien des définitions #define .
Par exemple, pour générer le Makefile d'une application simple constituée d'un source C unique utilisant seulement la Xlib, on aura un Imakefile du type :
LDLIBS = $(XLIB) SimpleProgramTarget(xsimple)
Imake se charge d'ajouter les particularités de la plate-forme utilisée .
Pour générer le Makefile, on doit effectuer les opérations suivantes :
L'écriture d'un Imakefile peut s'avérer être une opération complexe si l'on ne prends pas de précautions élémentaires :
Le fichier doit être organisé de manière ordonnée, par exemple, définition des variables en tête de fichier, appel des macros ensuite.
Le Makefile généré contient un certain nombres de buts standards que l'on invoquera par un classique make nom_d_un_but :
Pour la création d'un Imakefile type, nous allons partir d'une hypothèse d'application simple :
En premier lieu, on peut définir les librairies utilisées soit:
LDLIBS = XawClientLibsou bien :
LDLIBS = $(XAWLIB) $(XMULIB) $(XTOOLLIB) $(XLIB) $(EXTRA_LIBRARIES)
Ensuite, la liste des fichier sources puis des objets soit:
SRCS = xtest1.c s1.c s2.c s3.c OBJS = xtest1.o s1.o s2.o s3.o
Les noms SRCS et OBJS sont imposés par la macro-instruction qui suit.
Ensuite, on utilise les macros suivantes pour créer les buts décrits ci-dessus soit:
ComplexProgramTarget (xtest1) InstallAppDefaults (XTest1)
Cette denière macro génère le but d'installation du fichier de ressources.
Pour créer le Makefile, il suffit de lancer :
xmkmfqui correspond en fait à l'appel :
imake -DUseInstalled -Irépertoire_de_config_X11
Le flag UseInstalled indique à imake que l'on travaille sur une arborescence X installée et non sur l'arborescence des sources. Le répertoire de config X11 contient les fichiers .cf et .rules.
L'option -I indique le chemin de recherche des fichiers de configuration.
L'appel au shell-script xmkmf (fourni dans la distribution MIT) évite à l'utilisateur de lancer imake directement.
Lorsque le Makefile est créé, vous pouvez lancer la séquence suivante :
make depend pour les dépendances make pour compiler make install pour installer
Si vous vouler générer un nouveau Makefile :
make Makefile
Si votre application utilise un sous-répertoire , vous devez ajouter en tête du fichier Imakefile :
#define IHaveSubdirs #define PassCDebugFlags 'CDEBUGFLAGS=$(CDEBUGFLAGS)'Puis au niveau des appels de macros :
MakeSubdirs(nom_répertoire) DependSubdirs(nom_répertoire)
La première macro crée le but Makefiles permettant la génération successive des Makefiles par:
make MakefilesLa deuxième fait de même pour le but depend.
Vous pouvez également avoir besoin de définir une règle de compilation particulière pour un fichier .c donné. Vous utiliserez alors la règle :
SpecialObjectRule(f.o, f.c, -DSPECIAL)
Le fichier f.o sera créé à partir du fichier f.c avec le flag SPECIAL défini à la compilation.
Pour le cas d'application constituée de plusieurs exécutables gérés par le même Imakefile, le fichier Imake.rules contient trois macros équivalentes à la macro ComplexProgramTarget. Il s'agit de:
ComplexProgramTarget_1 ComplexProgramTarget_2 ComplexProgramTarget_3
Ces macros créent les mêmes buts dans le fichier Makefile que ComplexProgramTarget sauf que les noms des listes des fichiers sources et objets seront respectivement: SRCS1, OBJS1, SRCS2, OBJS2, SRCS3, OBJS3.
Enfin, si votre application est trop complexe pour utiliser la règle simple :
ComplexProgramTarget (xtest1)Vous pouvez utiliser la macro générale :
NormalProgramTarget(program,objects,deplibs,locallibs,syslibs)Dans ce cas la, vous devez utiliser également les macros :
DependTarget() InstallProgram(program, bindir)
Respectivement pour générer les buts depend et d'installation de l'exécutable (but install) .
Comme nous l'avons vu précédemment, vous pouvez utiliser InstallProgram pour installer un exécutable sur le répertoire des binaires. Une version plus générale est :
InstallProgramWithFlags(program,bindir,instflags)
qui permet de passer des options à l'utilitaire d'installation (en général /etc/install).
La macro:
InstallManPage(manfile, mandir)
installe un fichier man sur le répertoire adéquat.
Enfin, vous pouvez installer un fichier quelconque (non exécutable) par la macro:
InstallNonExec (file,instdir)
Vous pouvez inclure dans un Imakefile un but Makefile directement sans passer par une macro. Par exemple, si votre application utilise un programme qui n'a rien à voir avec X, vous pouvez toujours écrire dans l'Imakefile:
prog: $(PROGOBJS) $(CC) -o prog $(PROGOBJS)
Les lignes seront incluses DIRECTEMENT dans le fichier Makefile. Notez bien que dans ce cas là, il convient de respecter la syntaxe du Makefile (les tabulations en particuliers).
L'utilisation des Imakefiles :
On peut donc regretter que ce système soit encore trop peu utilisé et que certaines distributions commerciales binaires ne le fournissent pas (ou fournissent une version érronée)...