diff --git a/exemples/make/Makefile b/exemples/make/Makefile index 4389dc86e3e4757e8ddc10b3739d182f83e88cd5..b47513bccddde282bbece38c01d2daa79c01b0c4 100644 --- a/exemples/make/Makefile +++ b/exemples/make/Makefile @@ -1,26 +1,52 @@ +# galaxy: galaxy.o stars.o vec.o +# gcc -o galaxy galaxy.o stars.o vec.o + +# galaxy.o: galaxy.c stars.h +# gcc -c galaxy.c + +# stars.o: stars.c stars.h vec.h +# gcc -c stars.c + +# vec.o: vec.c vec.h +# gcc -c vec.c + +# clean: +# rm -f *.o galaxy + CC = gcc -CFLAGS = -g -Wall -O0 -std=c11 +CFLAGS = -g -Wall -Wextra -pedantic -O0 -std=c11 LDFLAGS = -lm -# SOURCES = main.c foo.c bar.c +x = foo +y = $(x) bar +x = later + +######### advanced v1 ############ +SOURCES = galaxy.c stars.c vec.c +################################## + +######### advanced v2 ############ +# SOURCES = $(wildcard *.c) # means *.c -SOURCES = $(wildcard *.c) +################################## + +# OK pour v1 et v2 # OBJECTS contient SOURCES avec .c -> .o OBJECTS = $(SOURCES:.c=.o) +######### advanced v3 ############ # OBJECTS := $(patsubst %.c,%.o,$(wildcard *.c)) +################################## # galaxy sera l'exécutable (galaxy.c contient le main) -TARGET = main +TARGET = galaxy $(TARGET) : $(OBJECTS) + @echo $(x) $(y) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) -# main: main.o foo.o bar.o -# cc -o $@ $^ $(CFLAGS) $(LDFLAGS) -# -# foo.o: foo.h -# bar.o: bar.h -# main.o: foo.h +# galaxy.o: stars.h vec.h +# stars.o: *.h +# vec.o: vec.h .PHONY: clean diff --git a/slides/make_avance.md b/slides/make_avance.md index a5a503e28491d1cd7e57bc241c1e88cf6cbdef67..035659e5ccee1ac341c37c3458bd2e582776f617 100644 --- a/slides/make_avance.md +++ b/slides/make_avance.md @@ -13,28 +13,28 @@ date: 2021-03-03 - Création du code objet à partir des sources. - Création de l'exécutable à partir du code objet. - Tout "gros" projet utilise `make` (pas uniquement en `C`). +- Un `Makefile` bien écrit ne recompile que ce qui est **nécessaire**![^1] - Il existe d'autres outils pour le `C` et d'autres langages (`cmake`, `meson`, `maven`, `cargo`, ...). -# Utilisation de `make` +[^1]: Par pitié arrêtez de faire un `rebuild` ou un `clean` à chaque compilation. -## `Makefile` simple +# Utilisation de `make` :::::::::::::: {.columns} ::: {.column width="60%"} +## `Makefile` simple + ```bash galaxy: galaxy.o stars.o vec.o - gcc -o galaxy galaxy.o stars.o vec.o - -galaxy.o: galaxy.c + gcc -o galaxy galaxy.o stars.o \ + vec.o +galaxy.o: galaxy.c stars.h gcc -c galaxy.c - stars.o: stars.c stars.h vec.h gcc -c galaxy.c - vec.o: vec.c vec.h gcc -c vec.c - clean: rm -f *.o galaxy ``` @@ -42,8 +42,6 @@ clean: ::: ::: {.column width="40%"} -**Dessinez le diagramme de dépendances de ce `Makefile`**. - ## Terminal ```bash @@ -51,13 +49,16 @@ $ make gcc -c galaxy.c gcc -c stars.c gcc -c vec.c -gcc -o galaxy galaxy.o stars.o vec.o +gcc -o galaxy galaxy.o + stars.o vec.o $ make clean rm -f *.o galaxy ``` ::: :::::::::::::: +**Dessinez le diagramme de dépendances de ce `Makefile`**. + # Diagramme de dépendances ~~~{.mermaid format=png} @@ -101,7 +102,7 @@ LDFLAGS = -lm # Définition des sources SOURCES = galaxy.c stars.c vec.c -# OBJECTS contient SOURCES avec .c -> .o +# OBJECTS contient SOURCES avec .c qui devient .o OBJECTS = $(SOURCES:.c=.o) # galaxy sera l'exécutable (galaxy.c contient le main) TARGET = galaxy @@ -111,15 +112,15 @@ TARGET = galaxy # `Makefile` plus complexe (3/3) ```makefile -# TARGET est la première cible et sera donc exécuté à l'invocation de `make` -# Elle dépend de OBJECTS +# TARGET est la première cible et sera donc exécuté à +# l'invocation de `make`. Elle dépend de OBJECTS $(TARGET) : $(OBJECTS) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) # $@ : la cible, $ˆ : la liste des dépendances -# PHONY signifie qu'on ne crée rien avec les cibles mentionnées -# Ici clean est la cible utilisée pour enlever tous les fichier .o -# et l'exécutable +# PHONY signifie qu'on ne crée rien avec les cibles +# mentionnées. Ici clean est la cible utilisée pour +# enlever tous les fichier .o et l'exécutable .PHONY: clean @@ -127,12 +128,11 @@ clean: # aucune dépendance rm -f $(TARGET) $(OBJECTS) ``` -# Gestion implicites (1/2) +# Gestion implicite (1/2) ## Question -Comment cela se fait-il qu'on ait pas besoin de générer les `OBJECTS` -dans le `Makefile` précédent? +Pourquoi n'a-t-on pas besoin de générer les `OBJECTS`? ## Réponse @@ -140,17 +140,17 @@ dans le `Makefile` précédent? ## Fonctionnement -Quand `make` rencontre une dépendance sans règle, il va voir dans sa liste de règles implicites pour la générer. +Si `make` rencontre une dépendance sans règle, il va voir dans sa liste de règles implicites pour la générer. Ainsi ```makefile -foo: foo.o bar.o - gcc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS) -# implicitement pour foo.c et bar.c - $(CC) -c $(CFLAGS) +galaxy: galaxy.o stars.o vec.o + gcc -o galaxy galaxy.o stars.o vec.o $(CFLAGS) $(LDFLAGS) +# implicitement pour galaxy.c, stars.c et vec.c + $(CC) -c $< $(CFLAGS) -o $@ ``` -# Gestion implicites (2/2) +# Gestion implicite (2/2) ## Question @@ -166,7 +166,91 @@ Quand `make` rencontre une dépendance sans règle, il va voir dans sa liste de Ainsi ```makefile -foo.o: foo.h -bar.o: foo.h bar.h +# pas besoin des .c qui sont implicites +galaxy.o: stars.h vec.h +stars.o: *.h +vec.o: vec.h ``` +# On peut faire mieux + +Il est possible de prendre **tous** les fichiers `.c` + +```makefile +SOURCES = $(wildcard *.c) +OBJECTS = $(SOURCES:.c=.o) +``` + +Ou encore mieux + +```makefile +OBJECTS := $(patsubst %.c,%.o,$(wildcard *.c)) +``` + +# That escalated quickly: `*`, `%`, `:=`, ... + +Let's take one step at a time: + +* Les `*`, +* Les `%`, et leurs différences. +* Les fonctions, ici `wildcard` et `patsubst`. +* Le symbole `:=` vs `=`. + +# Le symbole `*` + +## `make` peut "développer" (expand) des `wildcards` (`*`) + +* dans les recettes le `*` est géré par le shell + + ```makefile + clean: + rm -f *.o galaxy + ``` +* dans les dépendances + + ```makefile + galaxy.o: *.h + ``` + mais des fichiers `.h` doivent exister sinon il interprète `*.h` le nom du fichier. + +## Par contre ile ne peut pas + +```makefile +OBJECTS = *.o +# il faut utiliser +OBJECTS := $(wildcard *.o) # retourne tous les fichier .o +``` + +# Le symbole `:=` vs `=` (1/2) + +Deux façon (flavors) d'assigner des variables (voir [ce lien](https://www.gnu.org/software/make/manual/html_node/Flavors.html#Flavors)): + +## Le symbole `=` + +* Façon **récursive**: + + ```makefile + foo = $(bar) + bar = $(ugh) + ugh = Huh? + ``` + ici `foo` vaut `Huh?`. +* Valeurs remplacées "récursivement". +* Variables remplacées à chaque appel (lent + impredictible!). + +# Le symbole `:=` vs `=` (2/2) + +Deux façon (flavors) d'assigner des variables (voir [ce lien](https://www.gnu.org/software/make/manual/html_node/Flavors.html#Flavors)): + +## Le symbole `:=` + +* Façon **simplement développée** (`Simply expanded variable`): + + ```makefile + x := foo + y := $(x) bar + x := later + ``` + ici `y` vaut `foo bar` et `x` vaut `later` (avec des `=`, `y` vaudrait `later bar`). +* Les variables se comportent comme en `C`. +* En particulier dans les *longs* `Makefile` le comportement est plus prédictible.