Compilation séparée et Make Benjamin Drieu (drieu@bocal.cs.univ-paris8.fr) v1.0 - 30 Avril 1997 Cette documentation explique comment utiliser make pour la compilation séparée: comment écrire un fichier Makefile, l'utiliser, et quelles sont les conventions utilisées dans les fichiers Makefile. La version de make à laquelle je ferais référence au cours de ce document est Gnu Make. ______________________________________________________________________ Table of Contents: 1. Introduction 1.1. Comment marche la compilation 1.2. Compilation séparée 1.2.1. Utilité 1.2.2. Ce que fait make 1.3. Makefile ? 2. Règles 2.1. Qu'est-ce qu'une règle ? 2.2. Cible 2.3. Dépendances 2.4. Commandes 3. Mon premier Makefile ! 3.1. Fichier exemple Makefile 3.2. Et maintenant ? 4. Macro-commandes et variables 4.1. Déclaration 4.2. Appel 4.3. Exemple 5. Un Makefile un peu plus complexe et commenté 6. Caractères jokers 7. Patterns et variables automatiques 7.1. Pattern 7.2. Exemple idiot 7.3. Liste des variables automatiques 8. Conventions d'appellation 8.1. Noms d'exécutables et d'arguments 8.2. Noms de répertoires de destination 8.3. Noms de cibles 9. Copyright ______________________________________________________________________ 11.. IInnttrroodduuccttiioonn 11..11.. CCoommmmeenntt mmaarrcchhee llaa ccoommppiillaattiioonn ______________________________________________________________________ *.c *.h (Fichiers source) | COMPILATEUR | *.o (Fichier objet) | Librairies --> LIEUR <-- Fichiers objet | Fichier executable ______________________________________________________________________ 11..22.. CCoommppiillaattiioonn ssééppaarrééee 11..22..11.. UUttiilliittéé L'utilité est triple: · La programmation est modulaire, donc plus compréhensible · La séparation en plusieurs fichiers produit des listings plus lisibles · La maintenance est plus facile car seule une partie du code est recompilée 11..22..22.. CCee qquuee ffaaiitt mmaakkee · _m_a_k_e assure la compilation séparée grâce à gcc · _m_a_k_e utilise des macro-commandes et des variables · _m_a_k_e permet de ne recompiler que le code modifié · _m_a_k_e permet d'utiliser des commandes _s_h_e_l_l, et ainsi d'effectuer une installation Make est essentiel lorsque l'on veut effectuer un portage, car la plupart des logiciels libres UNIX (c'est-à-dire des logiciels qui sont fournis avec le code source) l'utilisent pour leur installation. 11..33.. MMaakkeeffiillee ?? Le fichier Makefile est un fichier nécessaire à _m_a_k_e. Un fichier Makefile indique à _m_a_k_e comment exécuter les instructions nécessaires à l'installation d'un logiciel ou d'une librairie. Le fichier Makefile doit se trouver dans le répertoire courant lorsqu'on appelle _m_a_k_e à l'invite du shell. Les instructions contenues dans un fichier Makefile obéissent à une syntaxe particulière un peu stupide. 22.. RRèègglleess Les fichiers Makefile sont structurés grâce aux _r_è_g_l_e_s. Ce sont elles qui définissent ce qui doit être exécuté ou non, et qui permettent de compiler un programme de différentes façons. 22..11.. QQuu''eesstt--ccee qquu''uunnee rrèèggllee ?? Une _r_è_g_l_e est une suite d'instructions qui seront exécutées pour construire une _c_i_b_l_e, mais uniquement si des _d_é_p_e_n_d_a_n_c_e_s sont plus récentes. La syntaxe d'une règle est la suivante: ______________________________________________________________________ cible: dependances commandes ... ______________________________________________________________________ 22..22.. CCiibbllee La cible est généralement le nom d'un fichier qui va être généré par les commandes qui vont suivre, ou une action gérée par ces mêmes commandes, par exemple clean ou install (Voir chapitre IX [Cibles] pour plus de détails sur les conventions utilisées dans l'attribution d'un nom à une règle). 22..33.. DDééppeennddaanncceess Les dépendances sont les fichiers ou les règles nécessaires à la création de la cible. Par exemple un fichier en-tête ou un fichier source dans le cas d'une compilation C. Dans le cas d'un fichier, la cible n'est construite que si ce fichier est plus récent que la cible. 22..44.. CCoommmmaannddeess C'est une suite de commandes shell qui seront exécutées au moment de la création de la cible. Une étrangeté de la syntaxe des fichiers Makefile oblige l'utilisateur de _m_a_k_e à insérer une tabulation au début de chaque ligne, faute de quoi _m_a_k_e affichera une erreur au moment de son exécution. La syntaxe de _m_a_k_e oblige aussi l'utilisateur à ajouter une caractère "_b_a_c_k_s_l_a_s_h" ('\') à la fin de chaque ligne dès que les commandes à exécuter dépassent une ligne de texte. 33.. MMoonn pprreemmiieerr MMaakkeeffiillee !! Maintenant que nous connaissons la syntaxe d'un fichier Makefile, nous allons en créer un pour apprendre à les utiliser. 33..11.. FFiicchhiieerr eexxeemmppllee MMaakkeeffiillee ______________________________________________________________________ # Mon premier Makefile all: foobar.o main.c gcc -o main foobar.o main.c foobar.o: foobar.c foobar.h gcc -c foobar.c -o foobar.o ______________________________________________________________________ 33..22.. EEtt mmaaiinntteennaanntt ?? Si vous avez enregistré l'exemple ci-dessus dans un fichier Makefile, il ne nous reste plus qu'a exécuter _m_a_k_e dans le même répertoire que celui où vous avez enregistré le fichier. Make s'exécute tout simplement en lançant la commande: $ make all Make va alors interpréter le fichier Makefile et exécuter les commandes contenues dans la règle _a_l_l, une fois que les dépendances _f_o_o_b_a_r_._o et _m_a_i_n_._c seront vérifiées. C'est à dire dire que si foobar.o ou main.c sont plus récents que le fichier main, _m_a_k_e recompilera main. Notez que si j'avais simplement tapé: "make" le résultat serait le même car quand _m_a_k_e est exécuté sans argument, _m_a_k_e exécute la première règle recontrée. 44.. MMaaccrroo--ccoommmmaannddeess eett vvaarriiaabblleess Les habitué(e)s de la programmation C ne seront pas dépaysé(e)s par le concept des variables de _m_a_k_e. En fait, il faut plutôt considérer les variables comme des macro-commandes (#define en C). 44..11.. DDééccllaarraattiioonn La déclaration se fait tout simplement avec la syntaxe ci-dessous: NOM = VALEUR Les espaces insérés ici ne sont pas obligatoires, mais facilitent la lisibilité du Makefile. La valeur affectée à la variable peut comme pour les macro-commandes du C comporter n'importe quels caractères, elle peut aussi être une autre variable. 44..22.. AAppppeell La syntaxe de l'appel de la macro-commande est la suivante: $(NOM) 44..33.. EExxeemmppllee prefix = /usr/local bindir = $(prefix)/bin 55.. UUnn MMaakkeeffiillee uunn ppeeuu pplluuss ccoommpplleexxee eett ccoommmmeennttéé ______________________________________________________________________ # $(BIN) est la nom du binaire généré BIN = foo # $(OBJECTS) sont les objets qui seront générés après la compilation OBJECTS = main.o foo.o # $(CC) est le compilateur utilisé CC = gcc # all est la première règle à être exécutée car elle est la première # dans le fichier Makefile. Notons que les dépendances peuvent être # remplacées par une variable, ainsi que n'importe quel chaine de # caractères des commandes all: $(OBJECTS) $(CC) $(OBJECTS) -o $(BIN) # ensuite les autres règles main.o: main.c main.h $(CC) -c mainc foo.o: foo.c foo.h main.h $(CC) -c foo.c ______________________________________________________________________ 66.. CCaarraaccttèèrreess jjookkeerrss Les caractères jokers s'utilisent comme sous _s_h_e_l_l. Les caractères valides sont * ? [...]. Par exemple, toto?.c représente tous les fichiers commençant par toto, finissant par .c, avec une lettre entre ces deux chaînes. Comme sous shell, le caractère '\' permet d'inhiber l'action des caractères jokers. Par exemple 's.c' fait référence à st*r.c et non pas à tous les fichiers commençant par st et finissant par r.c. Exemples: ______________________________________________________________________ clean: # ici le caractère joker * est géré par le shell et non pas # par make rm -f *.o print: *.c # le $? est une variable automatique (Voir chapitre VII # [Patterns et variables automatiques]) lpr -Php $? ______________________________________________________________________ 77.. PPaatttteerrnnss eett vvaarriiaabblleess aauuttoommaattiiqquueess 77..11.. PPaatttteerrnn Un pattern s'utilise un peu comme un caractère joker, mais uniquement dans le cas des cibles. Le caractère faisant office de joker est le caractère pourcent ('%'). L'intérêt est d'avoir plusieurs cibles. Les patterns permettent de filtrer les cibles pour savoir pour lesquelles d'entre elles les commandes qui suivent seront exécutées. 77..22.. EExxeemmppllee iiddiioott Pourquoi cet exemple est-il idiot ? Tout simplement parcequ'on met pèle-mêle tous les fichiers à compiler dans la même variable OBJECTS. Le plus simple aurait été d'utiliser plusieurs variables et de faire des règles différentes pour chaque type de compilation (normale, x11, athena). ______________________________________________________________________ # Notons que les objets sont à la fois des fichiers objets à lier et # des exécutables à compiler OBJECTS = text/main.o text/foo.o x11/main x11/bar athena/main # Le compilateur est bien sûr gcc CC = gcc # Les dépendances sont tous les objets all: $(OBJECTS) # On va quand même faire quelque chose dans cette règle echo DONE # Ici les règles pour tous les fichiers .o se trouvant dans le # répertoire 'text' text/%.o: text/%.c $(CC) -c text/$*.c # Ici les règles pour tous les fichiers se trouvant dans le répertoire # 'x11' x11/%: x11/%.c $(CC) -lX11 x11/$*.c # Ici les règles pour les fichiers se trouvant dans le répertoire # 'athena' athena/%: athena/%.c $(CC) -lXaw -lXext -lXmu -lXt -lX11 athena/$*.c ______________________________________________________________________ 77..33.. LLiissttee ddeess vvaarriiaabblleess aauuttoommaattiiqquueess Les variables automatiques sont des variables qui sont actualisées au moment de l'exécution de chaque règle, en fonction de la cible et des dépendances. · $@: nom de la cible · $<: première dépendance de la liste des dépendances · $?: les dépendances plus récentes que la cible · $^: toutes les dépendances · $*: dans le cas de l'utilisation des patterns, la chaine correspondant au % 88.. CCoonnvveennttiioonnss dd''aappppeellllaattiioonn 88..11.. NNoommss dd''eexxééccuuttaabblleess eett dd''aarrgguummeennttss Entre parenthèses les valeurs par défaut · AR: programme de maintenance d'archive (_a_r) · CC: compilateur C (_c_c) · CXX: compilateur C++ (_c_+_+) · RM: commande pour effacer un fichier (_r_m) · TEX: programme pour créer un fichier TeX dvi à partir d'un source TeX (_t_e_x) · ARFLAGS: paramètres à passer au programme de maintenance d'archives () · CFLAGS: paramètres à passer au compilateur C () · CXXFLAGS: paramètres à passer au compilateur C++ () 88..22.. NNoommss ddee rrééppeerrttooiirreess ddee ddeessttiinnaattiioonn Entre parenthèses les valeurs usuelles · prefix: racine du répertoire d'installation (/usr/local) · exec_prefix: racine pour les binaires ($(prefix)) · bindir: répertoire d'installation des binaires ($(exec_prefix)/bin) · libdir: répertoire d'installation des librairies ($(exec_prefix)/lib) · datadir: répertoire d'installation des données statiques pour le programme ($(exec_prefix)/lib) · statedir: répertoire d'installation des données modifiables par le programme ($(prefix)/lib) · includedir: répertoire d'installation des en-têtes ($(prefix)/include) · mandir: répertoire d'installation des fichiers de manuel ($(prefix)/man) · man_xdir: répertoire d'installation des fichiers de la section _x du manuel ($(prefix)/manx) · infodir: répertoire d'installation des fichiers info ($(prefix)/info) · srcdir: répertoire d'installation des fichiers source ($(prefix)/src) 88..33.. NNoommss ddee cciibblleess Un utilisateur de _m_a_k_e peut donner à ses cibles le nom qu'il désire. Mais pour des raisons de lisibilité, on donne toujours un nom standard à ses cibles selon leur comportement. Quelques exemples de cibles standard: · all: compile tous les fichiers source pour créer l'exécutable principal · install: exécute _a_l_l, et copie l'exécutable, les librairies, les datas, et les fichiers en-tête s'il y en a dans les répertoires de destination · uninstall: détruit les fichiers créés lors de l'installation, mais pas les fichiers du répertoire d'installation (où se trouvent les fichiers source et le Makefile) · clean: détruit tout les fichiers créés par _a_l_l · info: génère un fichier _i_n_f_o · dvi: génère un fichier _d_v_i · dist: crée un fichier _t_a_r de distribution 99.. CCooppyyrriigghhtt Ce document est placé sous copyright © 1997 de Benjamin Drieu, association APRIL. Ce document peut être reproduit et distribué dans son intégralité ou partiellement, par quelque moyen physique que ce soit. Il reste malgré tout sujet aux conditions suivantes : · La mention du copyright doit être conservée, et la présente section préservée dans son intégralité sur toute copie intégrale ou partielle. · Si vous distribuez ce travail en partie, vous devez mentionner comment obtenir une version intégrale de ce document et être en mesure de la fournir.