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