Make Mayday
Par Jean-Seb le vendredi 3 octobre 2008, 19:03 - Tools - Lien permanent
On ne présente plus Make, le gestionnaire de projets.
D'ailleurs, je ne vais pas le présenter.
Sans plus attendre, le livre de cuisine de Make
Mise à jour 14 oct. : ajout d'une rêgle de génération de
noms de fichiers.
Les points sur les i
en guise d'introduction
- Ce texte ne reprend pas les explications de base.
- Prenez le comme un condensé de rêgles et d'astuces utiles, découvertes au fur et à mesure de mes développements.
- La doc complète se trouve ici
- Comme d'habitude, j' enrichirai ce billet à mesure de mes découvertes et de vos nombreux commentaires.
Rêgles génériques
- La plus courante: compiler les fichiers *.c.
- %.o: %.c : définition de la boucle de compilation
- $< : substituer avec le fichier à droite des deux
points de la rêgle (ici:
%.c
)
%.o: %.c
gcc -c $<
- Quelques autres variables internes à Make:
- $@ = cible (valeur à gauche des deux points de la rêgle).
- $^ = affiche la valeur source avec tout ses prérequis (peut servir à obtenir le path complet d'un fichier)
- Pour les autres: 10.5.3 Automatic Variables dans la page info de Make.
La cible .PHONY
- La cible .PHONY sert à spécifier une rêgle qui ne correspond pas à la génération d'un fichier.
- Elle correspond à une commande à exécuter quand on le demande
explicitement.
- Les rêgles PHONY sont généralement utilisées pour les opérations de nettoyage et d'installation.
- Corollaire: elles permettent donc d'exécuter une rêgle Make si un fichier porte le même nom.
- Exemple (avec les rêgles all et clean) :
.PHONY: all clean- Dans l'exemple précédent, on déclare deux cibles all et clean. Si des fichiers de même nom existent, il n'y aura pas conflit.
Détection d'une plateforme
- Utiliser la commande shell qui permet de lancer des commandes.
- Une fois la variable win32 positionnée (ou non), on peut faire un test avec ifdef / else / endif
OS=$(shell uname | cut -f1 -d'_') ifeq ($(OS),MINGW32) win32=1 endif
Fonction d'affichage coloré
- Définition d'une fonction print colorée (Fred adore).
- Définir les codes couleurs au format ANSI.
info=\033[40;33;01m
warn=\033[41;36;01m
help=\033[41;33;01m
rem=\033[40;34;01m
define print
@echo -e "$($(2)) $(1) \033[0m"
endef
- Utilisation de la fonction print
$(call print,"all done",warn): une chaine toute simple.$(call print,Construction de $(exe),info): on peut également substituer des variables.
Génération des dépendances
- J'en parle dans un autre post de ce blog :
- En bref:
deps:
@echo génération des dépendances
@rm -f mes_deps
@$(CC) -MM *.c* >>mes_deps
-include mes_deps
Fichiers sources situés dans plusieurs répertoires
- On peut éviter de préfixer chaque fichier source par son répertoire.
- VPATH permet d'indiquer où chercher les fichiers sources.
- Syntaxe:
VPATH=foo:bar:baz
- Syntaxe:
- Comment utiliser un fichier qui n'est pas dans le répertoire courant ?
- Il faut utiliser la variable automatique $^
- Pour la compilation, nous allons donc utiliser cette variable automatique.
%.o : %.c
$(CC) -c $^ -o $@ $(CFLAGS)
- pour linker , même principe:
$(exe): $(obj)
$(CC) $^ -o $@ $(LDFLAGS) $(libs)
- Et pour générer les dépendances:
deps:
@rm -f mes_deps
@$(CC) -I$(VPATH) -MM *.c* $(VPATH)/*.c* >>mes_deps
Fichiers sources dispersés, objets dans un répertoire spécifique
- Dans le cas précédent, les objets vont se retrouver dans le répertoire racine de Make.
- Il est plus agréable de les regrouper dans un répertoire dédié.
- On utilise toujours la variable VPATH pour indiquer les répertoires.
- Préparation des variables:
- path_obj est le répertoire où les obj seront placés
- objets_avec_chemin sera utilisé par le linker (ce sont les objets préfixés par leur chemin complet)
OBJS=morph_dots.o cglfw.o memory.o path_obj=./objets objets_avec_chemin=$(patsubst %,$(path_obj)/%,$(OBJS))
- Vous pouvez insérer cette rêgle dans votre makefile, pour créer le
répertoire des objets si il n'existe pas.
__dummy := $(shell mkdir -p $(path_obj))
- Pour compiler et linker:
- Notez que pour linker, on peut utiliser la variable automatique $< , car les fichiers objets sont préfixés par leur répertoire dans la définition de la cible.
$(exe): $(objets_avec_chemin)
$(CC) $^ $(libs) -o $(exe)
$(path_obj)/%.o: %.cpp
$(CC) $(CXXFLAGS) -c $< -o $@
- Pour générer les dépendances, on utilisera toujours la même méthode.
- Il faut juste insérer le répertoire de destination des objets. Il faut le faire à la main avec sed
deps:
@rm -f mes_deps
@$(CC) -I$(VPATH) -MM *.c* $(VPATH)/*.c* >>mes_deps
#rajoute $(path_obj) sur les lignes qui ne commencent pas par \t ou space
@sed 's:^\([^\t\ ]\):$(path_obj)/\1:g' < mes_deps >mes_deps.tmp
@mv mes_deps.tmp mes_deps
Quelques fonctions.
- La fonction wildcard permet de récupérer les noms de fichiers
satisfaisants à une rêgle.
- ex: SOURCES=$(wildcard *.c)
- La fonction basename récupère la racine d'un nom de fichier.
$(basename toto.c): renvoie toto
- Vous voulez compiler tous les fichiers d'un répertoire, mais vous ne savez
pas à l'avance leur nom.
- Ici, j'utilise un fichier texte qui va être transformé en fichier html après un petit traitement.
SOURCES
utilise un wildcard pour ramener tous les fichiers avec l'extension txt.DESTS
est le résultat d'une substitution de chaine sur la variableSOURCES
SOURCES=$(wildcard *.txt)
DESTS=$(SOURCES:.txt=.html)
all: $(DESTS)
@echo Terminé
%.html: %.txt
@crock $< >$@
Salut Make
- make clean
- make all
- make install