site-catium

Un site pour la promotion de catium - retour accueil

git clone git://bebou.netlib.re/site-catium
Log | Files | Refs | README |

construire.sh (25922B)


      1 #! page
      2 title: Construire catium
      3 description: "Comment construire catium de zéro"
      4 
      5 section: main
      6 
      7 # Comment vous aussi vous auriez pu construire catium
      8 
      9 Imaginez vouloir construire une site et être doté.e d’un outil qui traduit le
     10 format dans lequel vous préférez écrire en html. Peut-être que vous aimez
     11 écrire en markdown et utilisez pandoc, cmark[^1] ou même le [script initial de
     12 John Gruber](https://daringfireball.net/projects/markdown/). Peut-être que vous
     13 aimez écrire en asciidoc et utilisez asciidoctor.  Peut-être que vous avez
     14 votre propre format avec votre propre traducteur !  Comment, avec l’aide des
     15 outils Unix, créer votre propre générateur de sites statiques ?
     16 
     17 ## Générer une page
     18 
     19 ### Les gabarits html et les métadonnées
     20 
     21 Vous avez un fichier index.md comme ceci :
     22 
     23 	# Super document cool
     24 
     25 	Blablabla
     26 
     27 	  * super liste
     28 	  * trop cool
     29 
     30 et pouvez le convertir en faisant cmark index.md :
     31 
     32 	<h1>Super document cool</h1>
     33 	<p>Blablabla</p>
     34 	<ul>
     35 	<li>super liste</li>
     36 	<li>trop cool</li>
     37 	</ul>
     38 
     39 Premier problème, si vous avez pour ambition d’avoir un site décemment
     40 construit vous remarquerez qu’il manque de l’html. On pourrait vouloir ajouter
     41 la balise `<html>` et `<meta>` pour l’encodage utf-8 par exemple. Ici
     42 habituellement deux solutions s’offrent à vous. Soit vous comptez sur votre
     43 traducteur pour le faire. C’est le cas par exemple de lowdown avec son option
     44 `-s` (pour standalone) mais tous ne le font pas :
     45 
     46 	<<-. lowdown -s
     47 	# titre
     48 
     49 	[lien](katzele.netlib.re)
     50 	.
     51 
     52 qui donne
     53 
     54 	<!DOCTYPE html>
     55 	<html>
     56 	<head>
     57 	<meta charset="utf-8" />
     58 	<meta name="viewport" content="width=device-width,initial-scale=1" />
     59 	<title>Untitled article</title>
     60 	</head>
     61 	<body>
     62 
     63 	<h1 id="titre">titre</h1>
     64 
     65 	<p><a href="katzele.netlib.re">lien</a></p>
     66 	</body>
     67 	</html>
     68 
     69 soit vous utilisez un générateur de site existant. En réalité une troisième
     70 s’offre à vous ! Résoudre ce problème à l’aide d’un outil que vous avez déjà
     71 sous la main, le shell.
     72 
     73 Il existe en shell posix une syntaxe nommée here-document ou heredoc[^2]. Cette
     74 syntaxe permet de créer des sortes de gabarits (ou templates ou layouts) de la
     75 sorte :
     76 
     77 	title="machin"
     78 	<<delim cat
     79 	blabla
     80 	le titre : $title
     81 	blabla
     82 	delim
     83 
     84 donne
     85 
     86 	blabla
     87 	le titre : machin
     88 	blabla
     89 
     90 On notera que les variables shell appelées à l’intérieur sont étendues. Et bien
     91 c’est également le cas des captures de commandes type `$(pwd)` ! On peut donc
     92 imaginer l’utiliser pour insérer notre sortie de traducteur au sein d’un
     93 gabarit html :
     94 
     95 	title="Un article super"
     96 	<<delim cat
     97 	<!DOCTYPE html>
     98 	<html>
     99 	<head>
    100 	<meta charset="utf-8" />
    101 	<meta name="viewport" content="width=device-width,initial-scale=1" />
    102 	<title>$title</title>
    103 	</head>
    104 	<body>
    105 	$(cmark index.md)
    106 	</body>
    107 	</html>
    108 	delim
    109 
    110 qui donne
    111 
    112 	<!DOCTYPE html>
    113 	<html>
    114 	<head>
    115 	<meta charset="utf-8" />
    116 	<meta name="viewport" content="width=device-width,initial-scale=1" />
    117 	<title>Un article super</title>
    118 	</head>
    119 	<body>
    120 	<h1>Super document cool</h1>
    121 	<p>Blablabla</p>
    122 	<ul>
    123 	<li>super liste</li>
    124 	<li>trop cool</li>
    125 	</ul>
    126 	</body>
    127 	</html>
    128 
    129 Hop pas besoin d’outils extérieur.  
    130 Si l’on fait de ce code un script on pourrait l’exécuter pour générer l’html.
    131 Evidemment ce serait limité puisque l’on aurait toujours la sortie du fichier
    132 index.md. On peut donc décider de passer en argument le nom du fichier markdown
    133 et le titre tant qu’à faire. On aurait donc un script du type :
    134 
    135 	title="$1"
    136 	<<delim cat
    137 	[...]
    138 	$(cmark "$2")
    139 	[...]
    140 	delim
    141 
    142 Qu’on appelerait en faisant `./script "Un article super" ./index.md`. Si nos
    143 besoins ne vont pas plus loin nous avons déjà quelque chose d’à peu près
    144 fonctionnel. Pour rendre tout cela simple d’usage et mieux encapsuler
    145 l’information nous allons pousser plus loin.
    146 
    147 Vous remarquerez ici que l’information du titre réside dans votre tête, à
    148 l’écriture de la commande et non pas, comme il est préférable, dans le document
    149 lui-même. L’idéal serait qu’index.md puisse contenir toutes ses informations,
    150 le markdown du corps de l’article mais également les méta-données afférentes.
    151 C’est comme cela que fonctionnent la plupart des générateurs de site avec des
    152 syntaxes propres. On voudrait pouvoir, par exemple, écrire :
    153 
    154 	title: "Un super article"
    155 	----
    156 
    157 	# Super document cool
    158 	[...]
    159 
    160 et que la variable title de notre script prenne pour valeur “Un super article”.
    161 Pour ce faire on pourrait modifier notre script pour parser index.md et en
    162 récupérer l’info que l’on souhaite. Par exemle
    163 
    164 	title=$(grep '^title:' | cut -d':' -f2)
    165 
    166 donnerait la bonne valeur à la variable et
    167 
    168 	$(sed -n '/----/,$ p` "$1" | grep -v '^----' | cmark)
    169 
    170 parserait uniquement la partie markdown en ométtant les méta-données. C’est
    171 pourtant sur une autre solution que nous allons partir, une solution qui nous
    172 permettera plus de flexibilité par la suite et surtout la possibilité de
    173 dynamiquement créer certaines parties du contenu markdown.
    174 
    175 ### le format “à la catium” et la prolifération des scripts shell
    176 
    177 Cette autre solution consiste à faire du document index.md lui même un script. Et oui, dans catium, si c’est pas une makefile, c’est un script shell. Comme le dit le meme :
    178 
    179 	shshsh  shshsh  shshsh  sh   sh  shshsh  shshsh  sh  sh  sh  sh
    180 	sh      sh  sh  sh  sh  shsh sh  sh        sh    sh  sh  shshsh
    181 	shsh    shshsh  shshsh  sh shsh  sh        sh    sh  sh  sh  sh
    182 	sh      shsh    sh  sh  sh  shs  sh        sh    sh  sh  sh  sh
    183 	sh      sh  sh  sh  sh  sh   sh  shshsh  shshsh  shshsh  sh  sh
    184 
    185 																  Wait it's all shell scripts ?
    186 																 /
    187 																🚶🔫🚶 - Always has been
    188 
    189 A ce stade on peut renommer index.md en index.sh, ça fera plus sens. L’idée est
    190 dorénavant que notre script devienne une sorte d’interpréteur d’index.sh. On
    191 l’appelera dorénavant “page”. Il devra préparer le nécessaire pour que la
    192 syntaxe de la page index.sh instancie les bonnes variables et génère le
    193 nécessaire pour l’affichage final de l’html.
    194 
    195 Par exemple, on pourrait grâce à un alias, cacher derrière la syntaxe `title: "Un super article"` une fonction qui créé la variable title. Pour cela on peut écrire :
    196 
    197 	alias title:="title"
    198 	title() title="$*"
    199 
    200 Ainsi, dans index.sh :
    201 
    202 	title: "Un super article"
    203 	# devient
    204 	title "Un super article"
    205 	# devient
    206 	title="Un super article"
    207 
    208 index.sh a créé sa propre variable. Ce système est généralisable à n’importe
    209 quelle métadonnée. Si vous testez cette articulation tel quel vous rencontrerez
    210 un problème. En effet, l’alias déclaré dans l’interpréteur page n’est pas
    211 disponible dans le script index.sh si on l’exécute en écrivant `./$1` et en
    212 faisant `./page index.sh` par exemple. C’est parce que en le faisant de cette
    213 manière là, index.sh est exécuté dans un sub-shell, sur un processus différent
    214 ne partageant aucune variable, alias ou fonction en commun avec son parent.
    215 Pour contourner ce problème on peut utiliser le built-in shell .[^3] qui prend en
    216 argument le chemin d’un fichier. Cette fonction va dérouler le code du fichier
    217 dans le script courant et l’exécuter comme s’il y avait été écrit. Le code dans
    218 index.sh aura donc bien accès à ce qui a été déclaré dans l’interpréteur page.
    219 Ainsi `./page index.sh` fera :
    220 
    221 	alias title:="title"
    222 	title() title="$*"
    223 
    224 	. "$1"
    225 
    226 	<<delim cat
    227 	<!DOCTYPE html>
    228 	<html>
    229 	<head>
    230 	<meta charset="utf-8" />
    231 	<meta name="viewport" content="width=device-width,initial-scale=1" />
    232 	<title>$title</title>
    233 	[...]
    234 	delim
    235 
    236 deviendra
    237 
    238 	alias title:="title"
    239 	title() title="$*"
    240 
    241 	title: "Un super article"
    242 
    243 	[...]
    244 
    245 	<<delim cat
    246 	<!DOCTYPE html>
    247 	<html>
    248 	<head>
    249 	<meta charset="utf-8" />
    250 	<meta name="viewport" content="width=device-width,initial-scale=1" />
    251 	<title>$title</title>
    252 	[...]
    253 	delim
    254 
    255 et `title: "Un super article"` se déroulera comme décrit précedemment et ainsi
    256 de suite.
    257 
    258 Super ! On sait comment gérer les métadonnées. En réalité on vient d’inventer
    259 une sorte de [DSL](https://en.wikipedia.org/wiki/DSL) qui ressemble
    260 volontairement beaucoup à du [YAML](https://en.wikipedia.org/wiki/YAML) très
    261 simple.  Cette syntaxe est devenu très commune dans les générateurs de sites
    262 statiques.
    263 
    264 Maintenant qu’on a trouvé notre alternative à `title=$(grep '^title:' | cut
    265 -d':' -f2)` il nous faut trouver celle à `$(sed -n '/----/,$ p “$1” | grep -v
    266 ‘—-’ | cmark)`. Si on ne le fait pas l’exécution d’index.sh aura vite fait de
    267 nous faire remarquer que le premier mot de notre page n’est pas une commande.
    268 
    269 Pour cela utilisons la même logique que pour les métadonnées. Imaginons une
    270 syntaxe qui nous convienne et créons, en amont dans l’interpréteur le
    271 nécessaire pour que cette syntaxe soit comprise et génère le bon contenu. Pour
    272 pouvoir dire “attention, ce qui suit c’est du markdown” on peut réutiliser les
    273 heredoc. Quelque chose de la sorte devrait générer l’html :
    274 
    275 	title: "Un article super"
    276 
    277 	<<delim cmark
    278 	# Ceci est du markdown
    279 
    280 	blabla
    281 	delim
    282 
    283 Sauf qu’il nous faut capturer la sortie de cmark pour pouvoir ensuite
    284 l’afficher au bon endroit dans le heredoc template qui suit dans l’interpréteur
    285 page. On pourrait le mettre dans une variable en l’entourant d’une capture de
    286 commande :
    287 
    288 	corps=$(<<delim cmark
    289 	# Ceci est du markdown
    290 
    291 	blabla
    292 	delim
    293 	)
    294 
    295 et dans le template faire
    296 
    297 	<main>
    298 		$(echo "$corps")
    299 	</main>
    300 
    301 mais vous conviendrez que ça n’est pas très élégant (et peut-être sensible au
    302 quoting hell ?). On va donc opter pour mettre le résultat dans un fichier
    303 temporaire.
    304 
    305 	<<delim cmark > A
    306 	# Ceci est du markdown
    307 
    308 	blabla
    309 	delim
    310 	[..]
    311 	<main>
    312 		$(cat A)
    313 	</main>
    314 
    315 ce qui permet d’adopter une syntaxe plus sympathique à l’aide d’un nouvel alias :
    316 
    317 	section="<<endsection cmark > A"
    318 	[...]
    319 	section
    320 	# Ceci est du markdown
    321 
    322 	blabla
    323 	endsection
    324 
    325 En ajoutant un petit `rm` A à la fin du script page on peut générer notre page
    326 html en faisant `./page index.sh` sans souci. index.sh pourra se lire
    327 convenablement bien et contiendra les infos à son propos en son sein. La
    328 totalité du fichier jusqu’ici est :
    329 
    330 	title: "Un super titre"
    331 
    332 	section
    333 	# Ceci est du markdown
    334 
    335 	blabla
    336 	endsection
    337 
    338 Avec ces éléments nous avons, à mon avis, tous les éléments d’un générateur de
    339 site très simples. Afin d’organiser un peu les choses on pourrait déporter le
    340 heredoc du layout dans un fichier à part, déclarant une fonction `layout`,
    341 exécuté avec le builtin . et dont la fonction serait appelé à la fin. Cela
    342 permet de séparer le layout du reste, le “fond” et la “forme” d’une certaine
    343 manière.
    344 
    345 On a donc un fichier de layout, nommé html et dans le dossier layouts :
    346 
    347 	layout {
    348 	<<@@ cat
    349 	<!DOCTYPE html>
    350 	<html>
    351 		<head>
    352 			<meta charset="utf-8" />
    353 			<meta name="viewport" content="width=device-width,initial-scale=1" />
    354 			<title>$title</title>
    355 		</head>
    356 		<body>
    357 			$(cat A)
    358 		</body>
    359 	</html>
    360 	@@
    361 	}
    362 
    363 Le fichier index.sh comme décrit juste au dessus et le script page :
    364 
    365 	alias title:="title"
    366 	title() title="$*"
    367 
    368 	. "$1"
    369 
    370 	. layout/html
    371 	layout
    372 	rm A
    373 
    374 Si les sources sont dans contents et les fichiers cibles dans public il
    375 suffirait ensuite de créer un script qui appellerait `./page X.sh > X.html` sur
    376 toutes les pages sh nécessaires, avec `X` le nom du fichier pour, construire le
    377 site.
    378 
    379 Il nous reste quelques améliorations à apporter à notre générateur.
    380 
    381 ### L’encapsulation et les sections
    382 
    383 Premièrement, il manque une information dans le fichier index.sh, celle de son
    384 interpréteur. De fait, le fichier est un script ne s’exécutant correctement que
    385 s’il est passé en argument d’un autre[^4]. Il serait bon de renseigner cette
    386 information dans le fichier. Pour ce faire nous allons lui ajouter le shebang :
    387 
    388 	#! page
    389 
    390 Ainsi il est possible de l’exécuter en faisant directement `./index.sh` ce qui en
    391 réalité, du fait du fonctionnement du shebang, fera `./page ./index.sh` ce qui
    392 revient à ce que nous faisions à la main jusque là. Cette façon de faire est,
    393 selon moi, plus élégante, mais permet également de savoir que cette page a été
    394 écrite pour être interprétée par un script nommé page ce qui, à défaut de
    395 l’avoir, est toujours une bonne information à prendre. Ce système peut être
    396 utilisé pour créer des typologies de pages (article, notes etc) qui seraient
    397 générées de manières différentes.
    398 
    399 En réalité dans catium c’est le shebang
    400 
    401 	#! /usr/bin/env ./page
    402 
    403 qui est utilisé pour des raisons obscures de compatibilité avec les *BSD et les
    404 mac[^5].
    405 
    406 Deuxièmement, comment faire si l’on souhaite, sur une même page, écrire deux
    407 blocs de markdown qui doivent aller à deux endroits différents dans le layout.
    408 Ce besoin est très courant dans les pages avec une structure plus complexe, du
    409 type à avoir des div un peu partout, de façon à avoir une présentation moins
    410 linéaire à l’aide de css. Pour répondre à ce besoin que l’on a estimé être
    411 suffisamment important pour être intégré au générateur dans sa version la plus
    412 simple il faut ajouter un peu de complexité dans l’interpréteur page.
    413 
    414 On souhaiterait pouvoir écrire dans index.sh :
    415 
    416 	section: truc
    417 	## Ce markdown va aller dans la section truc du layout
    418 	endsection
    419 
    420 	section: bidule
    421 	## Ce markdown va aller dans la section bidule du layout
    422 	endsection
    423 
    424 et par exemple dans le layout :
    425 
    426 	layout {
    427 	<<@@ cat
    428 	[...]
    429 	<div id="joli-id-pour-du-css">
    430 		$(show truc)
    431 	</div>
    432 	[...]
    433 	<div id="autre-id-pour-du-css">
    434 		$(show bidule)
    435 	</div>
    436 	@@
    437 	}
    438 
    439 On sent intuitivement qu'il faut passer une sorte d’argument à notre alias
    440 section[^6]. Il faudrait pouvoir, sur la base de cet argument, stocker les données
    441 de chacune des sections pour pouvoir les appeler séparément dans le layout.
    442 Pour pouvoir traiter cette donnée comme un argument l’alias ne suffira plus, il
    443 faudra passer par une fonction qu’on pourrait par exemple nommer `save` :
    444 
    445 	alias section:="<<endsection save"
    446 	save() cat >> "$1"
    447 
    448 Ainsi dans index.sh :
    449 
    450 	section: truc
    451 	blabla
    452 	endsection
    453 
    454 	# Devient
    455 
    456 	<<endsection save truc
    457 	blabla
    458 	endsection
    459 
    460 	# Puis
    461 
    462 	<<endsection cat >> truc
    463 	blabla
    464 	endsection
    465 
    466 On peut ainsi ouvrir et fermer autant de sections que l’on veut, y compris
    467 plusieurs fois la même grâce à l’opérateur de redirection `>>` qui concatène
    468 plutôt que ne remplace.  
    469 Il faut dorénavant que la fonction que l’on appelle dans le layout pour
    470 “injecter” les données d’une section à un endroit particulier fasse la
    471 traduction du format vers de l’html. On écrit donc une fonction `show` comme ceci
    472 :
    473 
    474 	show() cmark "$1"
    475 
    476 Cette fonction va donner tout le contenu enregistré dans la section qu’on lui
    477 passe en argument (main, footer, comme vous voulez) à `cmark` et en ressortira de
    478 l’HTML.
    479 
    480 Afin d’éviter que les fichiers ne se marchent sur les pieds si l’on a plusieurs
    481 articles, de polluer l’espace de travail et de potentiellement engorger la
    482 mémoire de votre ordinateur on peut faire en sorte que tout cela se produise
    483 dans un dossier temporaire, sur des fichiers temporaires tous détruits une fois
    484 la génération finie. Pour cela on créé au début de page un dossier temporaire
    485 de travail avec `mktemp`, on dit au shell de le supprimer si le processus reçoit
    486 le signal `EXIT` (une fois qu’il termine quoi) :
    487 
    488 	tmpdir=$(mktemp -d)
    489 	trap "rm -rf $tmpdir" EXIT
    490 
    491 Il ne nous manque plus qu’à adapter `save` et `show` pour prendre en compte ce
    492 nouveau dossier :
    493 
    494 	save() cat >> "$tmpdir/$1"
    495 	show() cmark "$tmpdir/$1"
    496 
    497 Et voilà, à une exception près[^7] vous avez recréé absolument tout Catium dans
    498 sa version non étendue. Bravo !
    499 
    500 ## Automatiser la génération : le makefile
    501 
    502 Il y aurait pleins de manières de partir de cet existant et d’automatiser la
    503 création d’un site de plusieurs fichiers .sh. Un simple script shell pourrait
    504 faire l’affaire. Cependant, pour des raisons pédagogique et, potentiellement de
    505 performances, nous avons opté pour make.
    506 
    507 Make est un programme spécifiquement créé pour gérer la construction de
    508 logiciels. Initialement fait pour compiler des programmes en C à une époque où
    509 les ressources étaient assez rares, make permet à l’utilisateurice de déclarer
    510 les règles de dépendances entre les différents éléments de son logiciel. make
    511 créera avec ces règles un graph de dépendances lui permettant, lorsqu’il est
    512 appelé, de ne recréer que le strict nécessaire ainsi économisant du temps de
    513 calcul. Sur le principe la compilation de logiciels et la construction d’un
    514 site statique ne sont pas différents. On peut donc faire usage de make pour
    515 orchestrer la génération de notre site.
    516 
    517 Tout le nécessaire pour que make puisse fonctionner doit être inscrit dans un
    518 fichier nommé makefile à la racine du projet.
    519 
    520 Catium utilise Gnu Make et quelques syntaxes lui sont très spécifiques. A
    521 l’avenir un effort sera peut-être consenti pour génériciser la syntaxe.
    522 
    523 ### Le but
    524 
    525 Le but est que make fasse automatiquement les appels aux articles et place
    526 leurs sorties dans les bons fichiers de destinations. Par exemple,
    527 
    528 	./contents/index.sh > public/index.html
    529 
    530 Et ainsi pour tous les fichiers .sh qui existent dans l’arborescence à
    531 l’intérieur de contents.
    532 
    533 Dans un second temps on souhaite qu’il copie bêtement tous les autres fichiers
    534 présents dans l’arborescence comme les images :
    535 
    536 	cp contents/super_image.jpg public/super_image.jpg
    537 
    538 Dans notre cas tout simple les fichiers .css et le favicon seront gérés de la
    539 même manière que tous les images n’étant pas des .sh.
    540 
    541 ### Lister nos fichiers sources
    542 
    543 La première étape est de lister toutes les sources de notre site. On souhaite faire des choses différentes selon que le fichier soit un .sh ou pas alors on créé deux variables. Dans sources on met la liste des fichiers sh, dans annexes les autres :
    544 
    545 	sources != find contents -type f      -name '*.sh'
    546 	annexes != find contents -type f -not -name '*.sh'
    547 
    548 La syntaxe `!=` dit à make que ce qui suit est une commande à faire exécuter
    549 par le shell et non pas des fonctions make. On utilise donc ici le find que
    550 vous pourriez utiliser dans votre terminal en temps normal.
    551 
    552 ### Créer les cibles
    553 
    554 Une fois ces deux listes obtenues, on cherche à créer deux nouvelles listes
    555 contenant les chemins des fichiers correspondants à faire servir par le serveur
    556 web. On les appellera fichiers cibles. Par exemple, si l’on a le chemin
    557 “contents/blog/article.sh” dans la variable sources, il faudra créer le chemin
    558 “public/blog/article.html”. Autrement dit on remplace contents par public et
    559 l’extension .sh par l’extension .html. Pour les autres fichiers seul le premier
    560 dossier du chemin est à changer.
    561 
    562 Pour le faire on fait usage des “substitutions references” de GMake dont la
    563 syntaxe est :
    564 
    565 	variablecréée = ${variableinitiale:abc%uvw=efg%xyz}
    566 
    567 Ici, pour toutes les lignes dans la variableinitiale, make cherchera les
    568 caractères `abc` et `uvw` et attribuera tout ce qu’il y a entre à `%`. Il
    569 remplacera ensuite tous les `abc` par `efg` et les `uvw` par `xyz` en
    570 conservant la partie `%`. Ainsi, si l’on reprend notre exemple précédent on
    571 identifie que la partie commune (`%`) est `blog/article` et qu’il faut changer
    572 ce qu’il y a avant et après. On peut donc écrire :
    573 
    574 	pageshtml         = ${sources:contents/%.sh=public/%.html}
    575 	annexescibles     = ${annexfiles:contents/%=public/%}
    576 
    577 Vous voyez que pour les annexes pas besoin de modifier l’extension donc pas
    578 besoin de la partie après le `%`. On a donc dorénavant dans `pageshtml` et
    579 `annexescibles` la liste des chemins des cibles.
    580 
    581 ### Écrire les règles
    582 
    583 C’est maintenant que la partie intéressante de make commence, les règles ! La
    584 syntaxe générale d’une règle est la suivante :
    585 
    586 	cible : liste dépendances ; commandes
    587 
    588 ou
    589 
    590 	cible : liste dépendances
    591 	   commandes
    592 
    593 Pour chacun des chemins de cibles construits précédemment make va chercher une
    594 règle permettant de construire le fichier en question. Pour cela il cherche une
    595 règle ayant pour cible le même chemin. Une fois qu’il a trouvé une règle qui
    596 correspond, il vérifie si la cible existe.
    597 
    598   * Si elle n’existe pas il cherche à construire toutes ses dépendances puis
    599     exécute la commande.
    600   * Si la cible existe mais que certaines de ses dépendances n’existent pas il
    601     va les construire d’abord et passer au point suivant.
    602   * Si la cible existe déjà et que les dépendances existent il vérifie si ses
    603     dépendances ont été modifiées après la dernière modification de la cible.
    604     Si oui alors make suppose que la cible n’est pas à jour (ses sources sont
    605     plus récentes qu’elle même) et make relance la commande.
    606 
    607 A noter que tout cela se fait de façon récursive. Quand make tente de créer une
    608 dépendance il suit les mêmes règles. Si la dépendance n’existe pas il faut donc
    609 qu’il existe une règle pour la créer.
    610 
    611 Pour créer une page html la règle pourrait être la suivante :
    612 
    613 	public/blog/article.html : contents/blog/article.sh layouts/html
    614 		@mkdir -p public/blog
    615 		contents/blog/article.sh > public/blog/article.html
    616 
    617 Vous noterez que la cible dépend de layouts/html de façon à ce qu’elle soit
    618 reconstruite si le layout change. Ajouter un `@` devant une commande permet
    619 de ne pas l'afficher dans la sortie lorsqu'on lancera make.
    620 
    621 Vous pourriez penser “mais on ne va pas écrire les règles pour toutes les pages
    622 non ?” et vous auriez raison. Il est possible d’écrire des règles génériques
    623 pouvant matcher plusieurs chemins de plusieurs cibles. Par exemple, la règle
    624 suivante conviendra pour créer tous les fichiers html :
    625 
    626 	public/%.html : contents/%.sh layouts/html
    627 		@mkdir -p $(shell dirname $@)
    628 		$< > $@
    629 
    630 De la même manière qu’auparavant on généricise les chemins à l’aide de `%`. On
    631 récupère le chemin du dossier du fichier cible avec dirname et on fait usage
    632 des variables automatiques `$<` et `$@` faisant références respectivement à la
    633 première dépendance et la cible. Pour éviter que la commande de création du
    634 dossier de destination s’affiche dans la console lorsque l’on construira le
    635 site on peut la préfixer d’un `@`.
    636 
    637 Pour les autres fichiers, de façon similaire :
    638 
    639 	public/% : contents/%
    640 		@mkdir -p $(shell dirname $@)
    641 		cp $< $@
    642 
    643 Si vous écrivez un makefile de la sorte et tenter de l’exécuter vous vourrez
    644 qu’il ne créera pas tout le site. Make créé les cibles qu’on lui donne en
    645 argument. `make public/index.html` déclenchera la règle correspondant à cette
    646 cible si elle existe. Cela dit sans argument make créé uniquement la cible de
    647 la première règle qu’il rencontre dans le makefile, dans l’ordre du fichier.
    648 Comment, en sachant cela, forcer la création de toutes les cibles dans les
    649 variables pageshtml et annexescibles ?
    650 
    651 En utilisant les propriétés des règles décrites précédemment.
    652 
    653   * Si make n’a pas d’argument, la première règle du fichier est déclenchée.
    654   * Si la cible d’une règle n’existe pas, il va essayer de la créer. On peut
    655     donc en déduire que si la commande de la règle ne créer pas la cible, la
    656     règle sera toujours déclenchée.
    657   * Make cherche d’abord à créer toutes les dépendances d’une cible avant de
    658     créer la cible.
    659 
    660 On en conclu que si l’on écrit une règle qui ;
    661 
    662   * Précède toutes les autres
    663   * A une commande qui ne créé pas de fichier ayant pour chemin la cible
    664     (aucune commande fera très bien l’affaire)
    665   * A pour dépendances toutes les cibles que l’on souhaite construire.
    666 
    667 Alors lorsque l’on lancera make, il cherchera à construire toutes ces cibles à
    668 chaque fois.
    669 
    670 Cette règle est très courante dans les makefiles et est généralement nommée par
    671 convention “all”, mais elle pourrait s’appeler “toto”. Pour lister les
    672 dépendances on peut utiliser les variables déjà existantes :
    673 
    674 	all: ${pageshtml} ${annexescibles}
    675 
    676 En utilisant les mêmes propriétés nous allons écrire une règle qu’il faudra
    677 appeler volontairement en passant sa cible en argument à make, se déclenchera
    678 toujours, et exécutera une commande. Cette règle permettra de nettoyer le
    679 dossier de destination “public” :
    680 
    681 	clean:; rm -r public/*
    682 
    683 Si elle n’est pas première dans le fichier et que la cible clean n’est une
    684 dépendance d’aucune autre règle, elle ne se déclenchera qu’en faisant `make
    685 clean`. Puisque la commande ne créé pas de fichier ayant pour chemin la cible
    686 alors elle se déclenchera toujours. Cela dit, puisqu’elle n’a pas non plus de
    687 dépendances, s’il se trouve qu’un jour un fichier “clean” existe à la racine du
    688 projet, il sera considéré comme toujours à jour. Aucune dépendance ne pourra
    689 être potentiellement plus récente que lui et la règle ne se déclenchera plus.
    690 C’est pour palier ce genre de scénarios qu’il existe une directive `.PHONY` qui
    691 permet de lister ce genre de règles[^8]. Ainsi make saura qu’il faut, pour ces
    692 règles, ignorer la préexistence de la cible.
    693 
    694 Et voilà, vous avez réécrit le makefile de catium tel qu’il existe aujourd’hui !
    695 
    696 [^1]: que l’on utilisera pour les exemples dans ce document
    697 [^2]:  documentée ici https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04
    698 [^3]:  oui le nom de la fonction est un point final `.`.
    699 [^4]: quand bien même la syntaxe a été écrite de façon à ce qu’un·e humain·e puisse le comprendre
    700 [^5]:  Voir: https://www.in-ulm.de/~mascheck/various/shebang/#interpreter-script ou le commit 4bd895
    701 [^6]:  auquel on a ajouté un : pour ressemble aux autres déclarations
    702 [^7]:  la ligne [ "$1" ] || set - que je ne m’explique pas
    703 [^8]:  même s’il est très improbable qu’un fichier all ou clean se faufile dans votre projet, on sait jamais.
    704 
    705