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

  • 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
  • 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 variable SOURCES
SOURCES=$(wildcard *.txt)
DESTS=$(SOURCES:.txt=.html)

all: $(DESTS)
        @echo Terminé

%.html: %.txt
        @crock $< >$@



Salut Make

  • make clean
  • make all
  • make install