L utilitaire "make" et son inséparable Makefile
Compilation et exécution Programme source Analyse lexicale (scaning) Optimisation du code Programme abstrait (optimisé) Génération du code Séquence d unités lexicales Table de symboles Programme abstrait (code intermédiaire) Code exécutable (object code) compilateur Analyse syntaxique (parsing) Arbre syntaxique Analyse sémantique Chargeur/Éditeur de liens (Loader/Linker) Programme résultant Données d entré Ordinateur Données de sortie
Qu est-ce qu un Makefile? Makefile : fichier utilisable par la commande make «Makefile» (avec majuscule) est le nom utilisé par convention, attendu par make Suit un format et une syntaxe spécifiques Permet l exécution séquentielle de scripts conditionnée par des dépendances
Intérets de l utilisation de Makefile Développement == nombreuses tâches répétitives (compilation, sauvegarde, ) Dans le cas d un développement modulaire, l ordre de compilation devient crucial gestion de dépendances Permet de délivrer un logiciel sous forme de sources accompagnées d un makefile permettant la compilation sur la machine cible./configure && make && make install
Structure du Makefile Composé de deux parties: Déclaration des variables Déclaration des cibles
Les variables Une variable est identifiée par un nom unique «En majuscule» par convention Non typées Substituées par leur valeur Rend le Makefile plus lisible portable
Déclaration, affectation et utilisation d une variable <VARIABLE> = <VALEUR> $(<VARIABLE>) Ex: CC = gcc MYFILE = myprog.c myprog.o : $(MYFILE) $(CC) c $(MYFILE) NB : il existe plusieurs variables prédéfinies comme $^, $@, $<
Les cibles (target) Indiquent à make les parties «à atteindre» <CIBLE> : <DEPENDANCE> <ACTION> <CIBLE1> <CIBLE2> : <DEP1> <DEP2> <ACTION1> <ACTION2> NB : Tabulation devant l action! Si aucune cible n est donnée à make, il prendra la première cible du fichier Makefile Vérifie la «mise à jour» de la dépendance pour déterminer s il faut déclencher l action
Rappels sur la compilation Schéma habituel Fich1.c gcc -c Fich1.o gcc a.out Compilation Ou directement Édition de liens Fich1.c gcc Fich1.c -o monexec monexec
Bon_Fichier.c /* Bon_Fichier.c */ /* Description: */ /* Entrées/Paramètres: */ /* Sorties: */ #include <stdlib.h> #include "Bon_Fichier.h" int main(int argc, char **argv){ exit(exit_failure); return 0; }
Good_File.c /* Good_File.c */ /* Description: */ /* Inputs/Parms: */ /* Outputs: */ #include <stdio.h> #include <stdlib.h> #include <assert.h> #include "Good_File.h" #define RCOK 0 int main(int argc, char **argv){ int parm1; parm1=rcok; parm1=checkifok(); assert (0<parm1); /*Suppose parm1 is positive*/ if (RCOK<>parm1) exit(exit_failure); exit(exit_success); }
Rappels sur les options de compilation -c supprime l édition de lien. Le code objet compilé se trouve dans le fichier d extension.o. -o renomme le traditionnel a.out avec le nom d exécutable de votre choix -g ajoute les informations pour déboguer à l aide de gdb ; on peut aussi utiliser l option ggdb (mais elle est légèrement différente, cf. man). -Wall (Warning all ) ajoute tous les messages d avertissements. Cette option ralentit la compilation mais accélère la mise au point du programme. -O2 optimise le code en taille et vitesse. Cette option accélère la vitesse d exécution.
Développement modulaire gcc -c Fich1.c Fich1.o gcc -c Fich2.c Fich2.o gcc -o monexec gcc -c Fich3.c Fich3.o
Comment le traduire sous forme de commandes gcc gcc c Fich1.c gcc c Fich2.c gcc c Fich3.c gcc Fich1.o Fich2.o Fich3.o o monexec Si l un des fichiers.c est «mis à jour», il faudra le recompiler (et lui seulement, cela suffit) et refaire l édition de lien complète pour atteindre notre cible. Et les.h? Peut-on automatiser et empêcher les erreurs?
Comment le traduire sous forme de Makefile CC = gcc PROGNAME = monexec SOURCE = Fich1.c Fich2.c Fich3.c all : $(PROGNAME) Fich1.o : Fich1.c $(CC) c Fich1.c Fich2.o : Fich2.c $(CC) c Fich2.c Fich3.o : Fich3.c $(CC) c Fich3.c Fich1.c Fich2.c Fich3.c gcc -c gcc -c gcc -c Fich1.o Fich2.o Fich3.o $(PROGNAME) : $(SOURCE:.c=.o) $(CC) $(SOURCE:.c=.o) o $(PROGNAME) gcc -o monexec
Augmenter la lisibilité et quelques astuces Mettez des commentaires # Ceci est un commentaire Indiquez les étapes de votre compilation en rajoutant des actions d affichage @echo Début édition de lien $(CC) $(SOURCE:.c=.o) o $(PROGNAME) @echo Fin édition de lien
Utilisez les variables prédéfinies cible : dep1 dep2 dep3 @echo $@ @echo $^ @echo $< Produira: cible dep1 dep2 dep3 dep1 $@ : Cible en cours $^ : Ensemble des dépendances $< : Première dépendance
Makefile avancé Généralisation des cibles Cible générique particulière.suffixes.suffixes :.c.h.o.c.o : $(CC) c $< Fonctionnera pour Fich1.c, Fich2.c,
Makefile # Insérer ici votre cartouche habituel # CC = gcc PROGNAME = monexec SOURCE = Fich1.c Fich2.c Fich3.c all : $(PROGNAME).SUFFIXES :.c.h.o.c.o : @echo Compilation de $< $(CC) c $< $(PROGNAME) : $(SOURCE:.c=.o) @echo Edition de liens pour générer $@ $(CC) $^ o $@ mrproper: clean : @echo Fait le menage rm f *.o $(PROGNAME) >make clean >make >make all >make CC=xlc