diff --git a/slides/Makefile b/slides/Makefile index 46d7e37eef2751e0c2e3f8ef7d34d6700fe75ff9..04617fb38881009e1351c1f5452eb7b493966019 100644 --- a/slides/Makefile +++ b/slides/Makefile @@ -27,8 +27,8 @@ all: puppeteer $(PDF) # La cible par défaut (all) exécute les cibles %.html et puppeteer: @echo "Setting chromium to $(CHROMIUM) for puppeteer" - @echo "{\n\"executablePath\":" \"$(CHROMIUM)\" ",\n\"args\": [\"--no-sandbox\"]\n}" > .puppeteer.json - # @echo -e "{\n\"executablePath\":" \"$(CHROMIUM)\" ",\n\"args\": [\"--no-sandbox\"]\n}" > .puppeteer.json + # @echo "{\n\"executablePath\":" \"$(CHROMIUM)\" ",\n\"args\": [\"--no-sandbox\"]\n}" > .puppeteer.json + @echo -e "{\n\"executablePath\":" \"$(CHROMIUM)\" ",\n\"args\": [\"--no-sandbox\"]\n}" > .puppeteer.json markdown: $(MARKDOWN) # La markdown les cibles %.markdown diff --git a/slides/make_avance.md b/slides/make_avance.md new file mode 100644 index 0000000000000000000000000000000000000000..89f406c4484474db4d22291baa26cdb11e63811c --- /dev/null +++ b/slides/make_avance.md @@ -0,0 +1,328 @@ +--- +title: "Makefile++" +date: "2024-12-17" +--- + +# make avancé + +## Rappel: utilité + +- Automatiser le processus de conversion d'un type de fichier à un autre, en *gérant les dépendances*. +- Effectue la conversion des fichiers qui ont changé uniquement. +- Utilisé pour la compilation: + - 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**! +- Il existe d'autres outils pour le `C` et d'autres langages (`cmake`, `meson`, `maven`, `cargo`, ...). + +# Utilisation de `make` + +:::::::::::::: {.columns} +::: {.column width="60%"} + +## `Makefile` simple + +```makefile +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 galaxy.c +vec.o: vec.c vec.h + gcc -c vec.c +clean: + rm -f *.o galaxy +``` + +::: +::: {.column width="40%"} + +## Terminal + +```console +$ make +gcc -c galaxy.c +gcc -c stars.c +gcc -c vec.c +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} +graph TD; + galaxy.o --> galaxy + stars.o --> galaxy + vec.o --> galaxy + galaxy.c --> galaxy.o + stars.c --> stars.o + stars.h --> stars.o + stars.h --> galaxy.o + vec.h --> stars.o + vec.h --> vec.o + vec.c --> vec.o +~~~ + +# Variables + +\footnotesize + +## Variables utilisateur + +- Déclaration + + ```makefile + id = valeur + id = valeur1 valeur2 valeur3 + ``` + +- Utilisation + + ```makefile + $(id) + ``` + +- Déclaration à la ligne de commande + + ```console + make CFLAGS="-O3 -Wall" + ``` + +## Variables internes + +- `$@` : la cible +- `$^` : la liste des dépendances +- `$<` : la première dépendance +- `$*` : le nom de la cible sans extension + +# `Makefile` plus complexe (1/3) + +```makefile +# Un Makefile typique + +# Le compilateur +CC = gcc + +# La variable CFLAGS contient les flags de compilation: +# -g compile avec les infos de debug +# -Wall Plein de warning +# -Wextra Encore plus de warnings +# -pedantic Warning lvl archimage +# -O0 Option d'optimisation (0,1,2,3) +# -std=c11 Utilisation du standard c11 +# -fsanitize=address Utilisation des sanitizers +CFLAGS = -g -Wall -Wextra -pedantic -O0 -std=c11 -fsanitize=address +``` + +# `Makefile` plus complexe (2/3) + +```makefile +# La variable LDFLAGS contient les flags pour l'éditeur +# de liens: +# -lm dit d'éditer les liens avec la lib math +# -lSDL2 dit d'éditer les liens avec la lib SDL2 +LDFLAGS = -lm -lSDL2 + +# Définition des sources +SOURCES = galaxy.c stars.c vec.c +# OBJECTS contient SOURCES avec .c qui devient .o +OBJECTS = $(SOURCES:.c=.o) +# galaxy sera l'exécutable (galaxy.c contient le main) +TARGET = galaxy +# Jusqu'ici on a aucune cible. +``` + +# `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) : $(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 +# exécute toujours clean, même si un ficher `clean` existe + +.PHONY: clean + +clean: # aucune dépendance + rm -f $(TARGET) $(OBJECTS) +``` + +# Gestion implicite (1/2) + +## Question + +Pourquoi n'a-t-on pas besoin de générer les `OBJECTS`? + +## Réponse + +`make` possède une série de règles implicites (voir [ce lien](https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC95) pour une liste). + +## Fonctionnement + +Si `make` rencontre une dépendance sans règle, il va voir dans sa liste de règles implicites pour la générer. + +```makefile +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 implicite (2/2) + +## Question + +Et pour les dépendances des cibles implicites ça se passe comment? + +## Réponse + +On peut définir individuellement les dites dépendances! + +## 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. + +```makefile +# pas besoin des .c qui sont implicites +galaxy.o: stars.h vec.h +stars.o: *.h +vec.o: vec.h +``` + +# 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 + imprédictible!). + +# 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. + +# Pour aller plus loin (pas ici...) + +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: `*`, `%`, `:=` + +```makefile +# version "longue" +SOURCES = $(wildcard *.c) +OBJECTS = $(SOURCES:.c=.o) +# version "courte" +OBJECTS := $(patsubst %.c,%.o,$(wildcard *.c)) +``` + +Let's take one step at a time: + +- Les `*`, +- Les `%`, et leurs différences. +- Les fonctions, ici `wildcard` et `patsubst` (voir respectivement [ce lien](https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html) et [ce lien](https://www.gnu.org/software/make/manual/html_node/Text-Functions.html)). +- 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 +``` + +# La différence entre `*` et `%` + +- Le symbole `*` sert à générer une *liste* d'objets. +- Le symbole `%` sert comme *emplacement* (placeholder). + +## Exemple + +```makefile +%.o: %.c # % est la partie avant .c + $(CC) -o $@ -c $< $(CFLAGS) # la règle pour chaque `%.c` +# équivalent à +galaxy.o: galaxy.c +stars.o: stars.c +vec.o: vec.c + +``` + +## Application + +```makefile +$(patsubst # Substitution de texte pour chaque + %.c,\ # Le pattern "avant" le .c + %.o,\ # Le pattern "avant" le .o + $(wildcard *.c)\ # Tous les fichiers .c + ) +```