
|
|
gcc -c fonctions.c -o fonctions.o gcc -c main.c -o main.o gcc main.o fonctions.o -o Programme #Ceci est mon Makefile Programme : main.o fonctions.o gcc main.o fonctions.o -o Programme main.o : main.c fonctions.c gcc -c main.c -o main.o fonctions.o : fonctions.c gcc -c fonctions.c -o fonctions.o |
Ne pas oublier les tabulations avant les lignes de commandes
Pour créer l'exécutable Programme, on exécute la première dépendance (main.o).
Si le fichier main.c est plus récent que le fichier main.o, la commande est alors exécutée et main.o est construit, mais si main.o est plus récent que main.c ,la commande n'est pas exécutée. L'évalution de la règle main.o est terminée.
Les autres dépendances de la règle Programme (en l'ocurrence ici : fonctions.o) sont examinées de la même manière (si fonctions.c est plus récent que fonctions.o, la commande qui construit ce dernier est exécutée).
Enfin, si nécessaire (si un des objets est plus récent que Programme), la commande de la règle Programme est exécutée et Programme est construit.
En résumé, les règles seront exécutées dans l'ordre inverse de l'écriture du Makefile, selon que les dépendances soient ou non plus récentes que leur cible !
Et on le lance de la sorte :
make Programme
Si on veut ajouter d'autres fonctions à notre Makefile, comme par exemple une fonction clean qui permet de supprimer les fichiers temporaires, et une fonction mrproper qui permet un rebuild complet, on a
|
#création de l'exécutable 'Programme' all: main.o fonctions.o gcc main.o fonctions.o -o Programme main.o: main.c fonctions.h gcc -c main.c -o main.o fonctions.o: fonctions.c gcc -c fonctions.c -o fonctions.o #suppression des fichiers temporaires clean: rm -rf *.o #suppression de tous les fichiers, sauf les sources, #en vue d'une reconstruction complète mrproper: clean rm -rf hello * all: compile tous les fichiers source pour créer l'exécutable principal; * install: exécute all, 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 all; * info: génère un fichier info; * dvi: génère un fichier dvi; * dist: crée un fichier tar de distribution; |
Ensuite on continue avec
make all
make clean
pour supprimer les fichiers temporaires
make mrproper
pour préparer une reconstruction complète.
make && make clean
pour installer le programme sans laisser de fichiers temporaires.
make mrproper && make
fera une reconstruction complète du programme.
Dans certains cas, le Makefile tel que ci-dessus peut présenter quelques problèmes.
Reprenons la règle clean :
clean:
rm -rf *.o
Vous remarquerez que cette règle ne présente pas de dépendance.
make accepte ces règles, le fichier est alors considéré comme à jour s'il existe.
Mais il n'y a pas de fichiers clean ?
Justement, s'il y a dans le répertoire courant un fichier nommé clean, la commande ne sera jamais effectuée.
On définit alors clean comme étant une cible particulière avec la directive .PHONY !
On ajoutera simplement une ligne au Makefile avant clean, voire même en tête du fichier.
Dans notre exemple on définira clean et mrproper comme cibles spéciales :
.PHONY: clean, mrproper
Les règles implicites
Make est capable de générer certains fichiers même si on ne lui indique pas la commande !
Reprenons la règle all et ses dépendances :
|
all: main.o fonctions.o gcc main.o fonctions.o -o Programme main.o: main.c fonctions.h gcc -c main.c -o main.o fonctions.o: fonctions.c gcc -c fonctions.c -o fonctions.o |
Si on supprime la règle main.o make trouvera tout seul comme un grand comment créer main.o à partir de main.c !
On appelle cela les règles implicites. Ces règles - inexistantes dans le Makefile mais appliquées - peuvent poser des problèmes avec certains Makefile plus complexes.
On mettra alors la directive .SUFFIXES en tête du Makefile pour etre tranquille !
Mon Makefile devient alors :
|
#définition des cibles particulières .PHONY: clean, mrproper #désactivation des règles implicites .SUFFIXES #all all: main.o fonctions.o gcc main.o fonctions.o -o Programme main.o: main.c fonctions.h gcc -c main.c -o main.o fonctions.o: fonctions.c gcc -c fonctions.c -o fonctions.o #clean clean: rm -rf *.bak rm -rf *.o #mrproper mrproper: clean rm -rf hello Ces directives ne sont pas obligatoires, mais il vaut mieux prendre l'habitude de les mettre par sécurité. |
On peut introduire des variables dans Make.qui ressemblent aux macro-commandes #define en C !
On introduit une variable sous la forme NOM = VALEUR.
On appelle ensuite sa valeur avec $(NOM).
Un petit exemple pour être plus clair :
Définissons la variable CC pour définir le compilateur : CC = gcc.
on remplace alors gcc par $(CC) dans les commandes.
De même, imaginons qu'on veuille mettre des arguments à gcc pour la compilation.
Par exemple gcc -W -Wall -v.
On définit pareillement CFLAGS = -W -Wall -v.
On ajoute $(CFLAGS) aux commandes.
Mettons ça sur notre Makefile (toujours le même) :
|
#définition des cibles particulières .PHONY: clean, mrproper #désactivation des règles implicites .SUFFIXES #définition des variables CC = gcc CFLAGS = -W -Wall -v #all all: main.o fonctions.o $(CC) main.o fonctions.o -o Programme main.o: main.c fonctions.h $(CC) -c main.c -o main.o $(CFLAGS) fonctions.o: fonctions.c fonctions.h $(CC) -c fonctions.c -o fonctions.o $(CFLAGS) #clean clean: rm -rf *.bak rm -rf *.o #mrproper mrproper: clean rm -rf Programme Maintenant, si on veut utiliser d'autres arguments, il suffira de changer la valeur de CXFLAGS en tête du fichier ! |
* AR: programme de maintenance d'archive (ar);
* CC: compilateur C (gcc);
* CXX: compilateur C++ (g++);
* RM: commande pour effacer un fichier (rm);
* TEX: programme pour créer un fichier TeX dvi à partir d'un source TeX (tex);
* ARFLAGS: paramètres à passer au programme de maintenance d'archives;
* CFLAGS: paramètres à passer au compilateur C;
* CXXFLAGS: paramètres à passer au compilateur C++;
* LDFLAGS: paramètres à passer au compilateur pour l'éditions de liens;
Pour les noms de répertoires et les destinations :
* 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);
* manxdir: 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 sources (= $(prefix)/src);
Les variables automatiques
Makefile permet aussi l'utilisation de variables automatiques, calculées lors de l'exécution de chaque règle.
* $@: 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;
* $*: correspond au ' * ' simple dans le shell, i.e. représente n'importe quel nom;
On peut alors (encore!) remplacer notre Makefile par :
|
#all all: main.o fonctions.o $(CC) $^ -o Programme $(CFLAGS) main.o: main.c fonctions.h $(CC) -c $< -o $@ $(CFLAGS) fonctions.o: fonctions.c $(CC) -c $< -o $@ $(CFLAGS) |