Un générateur de site statique - retour accueil
git clone git://bebou.netlib.re/catium
Log | Files | Refs | README |
commit f351a8b7bb1e28b3fda42cbffa151c79c36b6420 parent 6bd4dd56dce8599f11e64785b3f76b03194ce541 Auterice: Arthur Pons <arthur.pons@unistra.fr> Date: Sun, 3 Mar 2024 21:02:18 +0100 Nouvel article qui explique tout Réécriture des commentaires du makefile qui étaient redondants Il va falloir revoir le README et l'USAGE en fonction Diffstat:
A | CONSTRUIRE | | | 701 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | makefile | | | 37 | +++++-------------------------------- |
2 files changed, 706 insertions(+), 32 deletions(-)
diff --git a/CONSTRUIRE b/CONSTRUIRE @@ -0,0 +1,701 @@ +# Comment vous aussi vous auriez pu construire francium + +Imaginez vouloir construire une site et être doté.e d'un outil qui traduit le +format dans lequel vous préférez écrire en html. Peut-être que vous aimez +écrire en markdown et utilisez pandoc, cmark[^1] ou même le [script initial de +John Gruber]. Peut-être que vous aimez écrire en asciidoc et utilisez +asciidoctor. Peut-être que vous avez votre propre format avec votre propre +traducteur ! Comment, avec l'aide des outils Unix, créer votre propre +générateur de sites statiques ? + +## Générer une page + +### Les gabarits html et les métadonnées + +Vous avez un fichier index.md comme ceci : + + # Super document cool + + Blablabla + + * super liste + * trop cool + +et pouvez le convertir en faisant `cmark index.md` : + + <h1>Super document cool</h1> + <p>Blablabla</p> + <ul> + <li>super liste</li> + <li>trop cool</li> + </ul> + +Premier problème, si vous avez pour ambition d'avoir un site décemment +construit vous remarquerez qu'il manque de l'html. On pourrait vouloir ajouter +la balise `<html>` et `<meta>` pour l'encodage utf-8 par exemple. Ici +habituellement deux solutions s'offrent à vous. Soit vous comptez sur votre +traducteur pour le faire. C'est le cas par exemple de lowdown avec son option +`-s` (pour standalone) mais tous ne le font pas : + + <<-. lowdown -s + # titre + + [lien](katzele.netlib.re) + . + +qui donne + + <!DOCTYPE html> + <html> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width,initial-scale=1" /> + <title>Untitled article</title> + </head> + <body> + + <h1 id="titre">titre</h1> + + <p><a href="katzele.netlib.re">lien</a></p> + </body> + </html> + +soit vous utilisez un générateur de site existant. En réalité une troisième +s'offre à vous ! Résoudre ce problème à l'aide d'un outil que vous avez déjà +sous la main, le shell. + +Il existe en shell posix une syntaxe nommé `here-document` ou `heredoc`[^2]. +Cette syntaxe permet de créer des sortes de gabarits (ou templates ou layouts) +de la sorte : + + title="machin" + <<delim cat + blabla + le titre : $title + blabla + delim + +donne + + blabla + le titre : machin + blabla + +On notera que les variables shell appelées à l'intérieur sont étendues. Et bien +c'est également le cas des captures de commandes type `$(pwd)` ! On peut donc +imaginer l'utiliser pour insérer notre sortie de traducteur au sein d'un +gabarit html : + + title="Un article super" + <<delim cat + <!DOCTYPE html> + <html> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width,initial-scale=1" /> + <title>$title</title> + </head> + <body> + $(cmark index.md) + </body> + </html> + delim + +qui donne + + <!DOCTYPE html> + <html> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width,initial-scale=1" /> + <title>Un article super</title> + </head> + <body> + <h1>Super document cool</h1> + <p>Blablabla</p> + <ul> + <li>super liste</li> + <li>trop cool</li> + </ul> + </body> + </html> + +Hop pas besoin d'outils extérieur.\ +Si l'on fait de ce code un script on pourrait l'exécuter pour générer l'html. +Evidemment ce serait limité puisque l'on aurait toujours la sortie du fichier +index.md. On peut donc décider de passer en argument le nom du fichier markdown +et le titre tant qu'à faire. +On aurait donc un script du type : + + title="$1" + <<delim cat + [...] + $(cmark "$2") + [...] + delim + +Qu'on appelerait en faisant `./script "Un article super" ./index.md`. Si nos +besoins ne vont pas plus loin nous avons déjà quelque chose d'à peu près +fonctionnel. Pour rendre tout cela simple d'usage et mieux encapsuler +l'information dans des documents qui se suffisent à eux même nous allons +pousser plus loin. + +Vous remarquerez ici que l'information du titre réside dans votre tête, +à l'écriture de la commande et non pas, comme il est préférable, dans +le document lui-même. L'idéal serait qu'index.md puisse contenir toutes +ses informations, le markdown du corps de l'article mais également +les méta-données afférentes. C'est comme cela que fonctionnent la plupart +des générateurs de site avec des syntaxes propres. On voudrait pouvoir, +par exemple, écrire : + + title: "Un super article" + ---- + + # Super document cool + [...] + +et que la variable title de notre script prenne pour valeur "Un super article". +Pour ce faire on pourrait modifier notre script pour parser index.md et +en récupérer l'info que l'on souhaite. Par exemle + + title=$(grep '^title:' | cut -d':' -f2) + +donnerait la bonne valeur à la variable et + + $(sed -n '/----/,$ p` "$1" | grep -v '^----' | cmark) + +Parserait uniquement la partie markdown en ométtant les méta-données. C'est +pourtant sur une autre solution que nous allons partir, une solution qui nous +permettera plus de flexibilité par la suite et surtout la possibilité de +dynamiquement créer certaines parties du contenu markdown. + +### le format "à la francium" et la prolifération des scripts shell + +Cette autre solution consiste à faire du document index.md lui même +un script. Et oui, dans francium, si c'est pas une makefile, c'est +un script shell. Comme le dit le meme : + + +``` +shshsh shshsh shshsh sh sh shshsh shshsh sh sh sh sh +sh sh sh sh sh shsh sh sh sh sh sh shshsh +shsh shshsh shshsh sh shsh sh sh sh sh sh sh +sh shsh sh sh sh shs sh sh sh sh sh sh +sh sh sh sh sh sh sh shshsh shshsh shshsh sh sh + + Wait it's all shell scripts ? + / + 🚶🔫🚶 - Always has been +``` + +A ce stade on peut renommer index.md en index.sh, ça fera plus sens. L'idée +est dorénavant que notre script devienne une sorte d'interpréteur d'index.sh. +On l'appelera dorénavant "page". Il devra préparer le nécessaire pour que la +syntaxe de la page index.sh instancie les bonnes variables et génère le +nécessaire pour l'affichage final de l'html. + +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 : + + alias title:="title" + title() title="$*" + +Ainsi, dans index.sh : + + title: "Un super article" + # devient + maketitle "Un super article" + # devient + title="Un super article" + +index.sh a créé sa propre variable. Ce système est généralisable à +n'importe quelle métadonnée. Si vous testez cette articulation tel quel +vous rencontrerez un problème. En effet, l'alias déclaré dans l'interpréteur +page n'est pas disponible dans le script index.sh si on l'appel en écrivant +`./$1` et en faisant `./page index.sh` par exemple. C'est parce que en le +faisant de cette manière là, index.sh est exécuté dans un sub-shell, sur un +processus différent ne partageant aucune variable, alias ou fonction +en commun avec son parent. Pour contourner ce problème on peut utiliser +le built-in shell `.`[^3] qui prend en argument le chemin d'un fichier. +Cette fonction va dérouler le code du fichier dans le script courant et +l'exécuter comme s'il y avait été écrit. Le code dans index.sh aura donc +bien accès à ce qui a été déclaré dans l'interpréteur page. Ainsi `./page +index.sh` fera : + + alias title:="title" + title() title="$*" + + . "$1" + + <<delim cat + <!DOCTYPE html> + <html> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width,initial-scale=1" /> + <title>$title</title> + [...] + delim + +deviendra + + alias title:="title" + title() title="$*" + + title: "Un super article" + ---- + + [...] + + <<delim cat + <!DOCTYPE html> + <html> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width,initial-scale=1" /> + <title>$title</title> + [...] + delim + +et `title: "Un super article"` se déroulera comme décrit précedemment et ainsi +de suite. Vous remarquerez peut-être que le `----` écrit ici paraît louche. A +priori tenter d'exécuter `----` dans le shell renverra une erreur puisqu'aucun +alias ou aucune[^4] commande ni fonction ne porte ce nom. Pour y remédier on +peut simplement créer un alias bidon `alias ----=":"` de façon à appeler le +builtin `:` qui, par définition, ne fait strictement rien. + +Super ! On sait comment gérer les métadonnées. En réalité on vient d'inventer une +sorte de [DSL] qui ressemble volontairement beaucoup à du [YAML] très simple. +Cette syntaxe est devenu très commune dans les générateurs de sites statiques. + +Maintenant qu'on a trouvé notre alternative à `title=$(grep '^title:' | cut +-d':' -f2)` il nous faut trouver celle à `$(sed -n '/----/,$ p` "$1" | grep -v +'^----' | cmark)`. Si on ne le fait pas l'exécution d'index.sh aura vite fait +de nous faire remarquer que le premier mot de notre page n'est pas une commande. + +Pour cela utilisons la même logique que pour les métadonnées, pensons à une +syntaxe qui nous convienne et créeons, en amont dans l'interpréteur le +nécessaire pour que cette syntaxe soit comprise et génère le bon contenu. +Pour pouvoir dire "attention, ce qui suit c'est du markdown" on peut +réutiliser les heredoc. Quelque de la sorte devrait générer l'html : + + title: "Un article super" + ---- + + <<delim cmark + # Ceci est du markdown + + blabla + delim + +Sauf qu'il nous faut capturer la sortie de lowdown pour pouvoir ensuite l'afficher +au bon endroit dans le heredoc template qui suit dans l'interpréteur page. On pourrait +le mettre dans une variable en l'entourant d'une capture de commande : + + corps=$(<<delim cmark + # Ceci est du markdown + + blabla + delim + ) + +et dans le template faire + + <main> + $(echo "$corps") + </main> + +mais vous conviendrez que ça n'est pas très élégant. On va donc opter pour +mettre le résultat dans un fichier temporaire. + + <<delim cmark > A + # Ceci est du markdown + + blabla + delim + [..] + <main> + $(cat A) + </main> + +ce qui permet d'adopter une syntaxe plus sympathique à l'aide d'un nouvel alias : + + section="<<endsection cmark > A" + [...] + section + # Ceci est du markdown + + blabla + endsection + +En ajoutant un petit `rm A` à la fin du script page on peut générer notre page +html en faisant `./page index.sh` sans souci. index.sh pourra se lire +convenablement bien et contiendra les infos à son propos en son sein. La +totalité du fichier jusqu'ici est : + + title: "Un super titre" + ---- + + section + # Ceci est du markdown + + blabla + endsection + +Avec ces éléments nous avons, à mon avis, tous les éléments d'un générateur de +site très simples. Afin d'organiser un peu les choses on pourrait déporter +le heredoc du layout dans un fichier à part, déclarant une fonction `layout`, +exécuté avec le builtin `.` et donc la fonction serait appelé à la fin. Cela +permet de séparer le layout du reste, le "fond" et la "forme" d'une certaine +manière. + +On a donc un fichier de layout, nommé html et dans le dossier layouts : + + layout { + <<@@ cat + <!DOCTYPE html> + <html> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width,initial-scale=1" /> + <title>$title</title> + </head> + <body> + $(cat A) + </body> + </html> + @@ + } + +Le fichier index.sh comme décrit juste au dessus et le scrit page : + + alias title:="title" + title() title="$*" + + . "$1" + + . layout/html + layout + rm A + +Si les sources sont dans contents et les fichiers cibles dans public il +suffirait ensuite de créer un script qui appelerait `./page X.sh > +X.html` sur toutes les pages sh nécessaires, avec `X` le nom du fichier pour, +construire le site. + +Il nous reste quelques améliorations à apporter à notre générateur. + +### L'encapsulation et les sections + +Premièrement, il manque une information dans le fichier index.sh, celle +de son interpréteur. De fait, le fichier est un script ne s'exécutant +correctement que s'il est passé en argument d'un autre[^5]. Il serait +bon de renseigner cette information dans le fichier. Pour ce faire nous +allons lui ajouter le shebang : + + #! page + +Ainsi il est possible de l'exécuter en faisant directement `./index.sh` ce qui +en réalité, du fait du fonctionnement du shebang, fera `./page ./index.sh` ce +qui revient à ce que nous faisions à la main jusque là. Cette façon de faire +est, selon moi, plus élégante, mais permet également de savoir que cette page +a été écrite pour être interprétée par un script nommé page ce qui, à défaut +de l'avoir, est toujours une bonne information à prendre. Ce système peut être +utilisé pour créer des typologies de pages (article, notes etc) qui seraient +générées de manières différentes. + +En réalité dans Francium c'est le shebang + + #! /usr/bin/env ./page + +qui est utilisé pour des raisons obscures de compatibilité avec les *bsd et les +mac[^7]. + +Deuxièmement, comment faire si l'on souhaite, sur une même page, écrire +du blocs de markdown qui doivent aller à deux endroits différents dans +le layout. Ce besoin est très courant dans les pages avec une structure plus +complexe, du type à avoir des div un peu partout, de façon à avoir une +présentation moins linéaire à l'aide de css par exemple. Pour répondre à ce +besoin que l'on a estimé être suffisament important pour être intégré au +générateur dans sa version la plus simple il faut ajouter un peu de complexité +dans l'interpréteur page. + +On souhaiterait pouvoir écrire dans index.sh : + + section: truc + ## Ce markdown va aller dans la section truc du layout + endsection + + section: bidule + ## Ce markdown va aller dans la section bidule du layout + endsection + +et par exemple dans le layout : + + layout { + <<@@ cat + [...] + <div id="joli-id-pour-du-css"> + $(cat truc) + </div> + [...] + <div id="autre-id-pour-du-css"> + $(cat bidule) + </div> + @@ + } + +On voit que intuitivement on passe une sorte d'argument à notre alias +section[^6]. Il faudrait pouvoir, sur la base de cet argument, stocker +l'html généré par chacune des sections pour pouvoir les appeler séparément +dans le layout. Pour pouvoir traiter cette donnée comme un argument +l'alias ne suffira plus, il faudra passer par une fonction qu'on pourrait +par exemple nommer `save_md` puisqu'on lui donne du markdown en entrée : + + alias section:="<<endsection save_md" + save_md() cmark >> "$1" + +Ainsi dans index.sh : + + section: truc + blabla + endsection + # Devient + <<endsection save_md truc + blabla + endsection + # Puis + <<endsection cmark >> truc + blabla + endsection + +Les captures de commandes que l'on a fait dans le layout vont donc +fonctionner d'elles mêmes. On peut ainsi ouvrir et fermer autant +de sections que l'on veut, y compris plusieurs fois la même grâce +à l'opérateur de redirection `>>` qui concatène plutôt que ne remplace. +Afin d'éviter que les fichiers ne se marchent sur les pieds si +l'on a plusieurs articles, de polluer l'espace de travail et de potentiellement +engorger la mémoire de votre ordinateur on peut faire en sorte que tout +cela se produise dans un dossier temporaire, sur des fichiers temporaires +tous détruits une fois la génération finie. Pour on créer au début de page +un dossier temporaire de travail avec `mktemp`, on dit au shell de le supprimer +si le processus reçoit le signal `EXIT` (une fois qu'il termine quoi) et on +fait une petite fonction pour le layout puisque l'on ne peut plus juste cat +les fichiers comme s'ils existaient à la racine de notre projet : + + the=$(mktemp -d) + trap "rm -rf $the" EXIT + + the() { + cd $the + cat "$@" + } + +Dans le layout on aura `$(the truc)` au lieu de `$(cat truc)`[^7]. + +Et voilà, à une exception près[^8] vous avez recréé absolument tout Francium +dans sa version non étendue. Bravo ! + +## Automatiser la génération, le makefile + +Il y aurait pleins de manières de partir de cet existant et d'automatiser +la création d'un site de plusieurs fichiers .sh. Un simple script shell +pourrait faire l'affaire. Cependant, pour des raisons pédagogique et, +potentiellement de performances, nous avons opté pour utiliser make. + +Make est un programme spécifiquement créé pour gérer la construction de +logiciels. Initialement fait pour compiler des programmes en C à une époque où +les ressources étaient assez rares, make permet à l'utilisateurice de déclarer +les règles de dépendances entre les différents éléments de son logiciel. make +créera avec ces règles un graph de dépendances lui permettant, lorsqu'il est +appelé, de ne recréer que le strict nécessaire ainsi économisant du temps de +calcul. Sur le principe la compilation de logiciels et la construction d'un +site statique ne sont pas différents. On peut donc faire usage de make pour +créer orchestrer la génération de notre site. + +Tous le nécessaire pour que make puisse fonctionner doit être inscrit +dans un fichier nommé `makefile` à la racine du projet. + +Francium utilise Gnu Make et quelques syntaxes lui sont très spécifiques. + +## Le but + +Le but est que make fasse automatiquement les appels aux articles +et place leurs sorties dans les bons fichiers de destinations. Par exemple, + + ./contents/index.sh > public/index.sh + +Et ainsi pour tous les fichiers .sh qui existent dans l'arborescence à +l'intérieur de contents. + +Dans un second temps on souhaite qu'il copie bêtement tous les autres +fichiers présents dans l'arborescence comme les images par exemple : + + cp contents/super_image.jpg public/super_image.jpg + +Dans notre cas tout simple les fichiers .css et le favicon seront +gérés de la même manière que tous les images n'étant pas des .sh. + +### Lister nos fichiers sources + +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 : + + sources != find contents -type f -name '*.sh' + annexes != find contents -type f -not -name '*.sh' + +La syntaxe `!=` dit à make que ce qui suit est une commande à faire exécuter +par le shell et non pas des fonctions make. On utilise donc ici le find +que vous pourriez utiliser dans votre terminal en temps normal. + +Une fois ces deux listes obtenues, on cherche à créer deux nouvelles listes +contenant les chemins des fichiers correspondants à faire servir par le +serveur web. On les appelera fichiers cibles. Par exemple, si l'on +a le chemin "contents/blog/article.sh" dans la variable sources, +il faudra créer le chemin "public/blog/article.html". Autrement dit on remplace +contents par public et l'extension .sh par l'extension .html. Pour les autres +fichiers seul le premier dossier du chemin est à changer. + +Pour le faire on fait usage des "substitutions references" de GMake dont la syntaxe est : + + variablecréé = ${variableinitiale:abc%uvw=efg%xyz} + +Ici, pour toutes les lignes dans la variableinitiale, make cherchera les +caractères `abc` et `uvw` et attribuera tout ce qu'il y a entre à `%`. Il +remplacera ensuite tous les `abc` par `efg` et les `uvw` par `xyz` en +conservant la partie `%`. Ainsi, si l'on reprend notre exemple précédent on +identifie que la partie commune est `blog/articl` et qu'il faut changer ce qu'il +y a avant et après. On peut donc écrire : + + pageshtml = ${sources:contents/%.sh=public/%.html} + annexescibles = ${annexfiles:contents/%=public/%} + +Vous voyez que pour les annexes pas besoin de modifier l'extension donc pas +besoin de la partie après le `%`. On a donc dorénavant dans `pageshtml` et +`annexescibles` la liste des chemins des cibles. + +C'est maintenant que la partie intéressante de make commence, les règles ! La +syntaxe générale d'une règle est la suivante : + + cible : liste dépendances ; commandes + +ou + + cible : liste dépendances + commandes + +Pour chacun des chemins de cibles construits précédemment make va chercher une +règle permettant de construire le fichier en question. Pour cela il cherche une +règle ayant pour cible le même chemin. Une fois qu'il a trouvé une règle qui +correspond, il vérifie si la cible existe. + + * Si elle n'existe pas il cherche à construire toutes ses dépendances puis + exécute la commande. + * Si la cible existe mais que certaines de ses dépendances n'existent pas il + va les construire d'abord et passer au point suivant. + * Si la cible existe déjà et que les dépendances existent il vérifie si ses + dépendances ont été modifiées après sa dernière modification. Si oui alors + make suppose que la cible n'est pas à jour (ses sources sont plus récentes + qu'elle même) et make relance la commande. + +A noter que tout cela ce fait de façon récursive. Quand make tente de créer une +dépendance il suit les mêmes règles. Si la dépendance n'existe pas il faut donc +qu'il existe une règle pour la créer. + +Pour créer une page html la règle pourrait la suivante : + + public/blog/article.html : contents/blog/article.sh layouts/html + mkdir -p public/blog; contents/blog/article.sh > public/blog/article.html + +Vous noterez que la cible dépend de layouts/html de façon à ce qu'elle +soit reconstruite si le layout change. + +Vous pourrez penser "mais on ne va pas écrire les règles pour toutes +les pages non ?" et vous auriez raison. Il est possible d'écrire des +règles génériques, pouvant matcher plusieurs chemins de plusieurs cibles. +Par exemple, la règle suivante conviendra pour créer tous les fichiers +html : + + public/%.html : contents/%.sh layouts/html + mkdir -p $(shell dirname $@); $< > $@ + +De la même manière qu'auparavant on généricise les chemins à l'aide de `%`. On +récupère le chemin du dossier du fichier cible avec dirname et on fait usage +des variables automatiques `$<` et `$@` faisant références respectivement à la +première dépendance et la cible. + +Pour les autres fichiers, de façon similaire : + + public/% : contents/% + mkdir -p $(shell dirname $@); cp $< $@ + +Si vous écrivez un makefile de la sorte et tenter de l'exécuter vous vourrez +qu'il ne créera pas tout le site. Make créé les cibles qu'on lui donne en +argument. `make public/index.html` déclenchera la règle correspondant à cette +cible si elle existe. Cela dit par défaut sans argument make créé uniquement la +cible de la première règle qu'il rencontre dans le makefile, dans l'ordre du +fichier. Comment en sachant cela, forcer la création de toutes les cibles dans +les variables pageshtml et annexescibles ? + +En utilisant les propriétés des règles décrites précédemment. + + 1. Si make n'a pas d'arguement, la première règle du fichier est déclenchée. + 2. Si la cible d'une règle n'existe pas, il va essayer de la créer. On peut + donc en déduire que si la commande de la règle ne créer pas la cible la règle + sera toujours déclenchée. + 3. Make cherche d'abord à créer toutes les dépendances d'une cible avant de + créer la cible. + +On en conclu que si l'on écrit une règle qui + + 1. Précède toutes les autres + 2. A une commande qui ne créé pas de fichier ayant pour chemin la cible. + Aucune commande fera très bien l'affaire. + 3. A pour dépendances toutes les cibles que l'on souhaite construire. + +Alors lorsque l'on lancera make, il cherchera à construire toutes +les cibles à chaque fois. + +Cette règle est très courante dans les makefiles et est généralement nommée +par convention "all", mais elle pourrait s'appeler "toto". Pour lister les +dépendances on peut utiliser les variables déjà existantes : + + all: ${pageshtml} ${annexescibles} + +En utilisant les mêmes propriétés nous allons écrire une règle qu'il faudra +appeler volontairement en passant sa cible en argument à make, se déclenchera +toujours, et exécutera une commande. Cette règle permettra de nettoyer le +dossier de destination "public" : + + clean:; rm -r public/* + +Si elle n'est pas première dans le fichier et que la cible clean n'est une +dépendance d'aucune autre règle, elle ne se déclenchera qu'en faisant `make +clean`. Puisque la commande ne créé pas de fichier ayant pour chemin la cible +alors elle se déclenchera toujours. Cela dit, puisqu'elle n'a pas non plus +de dépendances, s'il se trouve qu'un jour un fichier "clean" existe à la +racine du projet, il sera considéré comme toujours à jour. Aucune dépendance +ne pourra être potentiellement plus récente que lui et la règle ne se +déclenchera plus. C'est pour palier ce genre de scénarios qu'il existe une +directive `.PHONY` qui permet de lister ce genre de règles[^9]. Ainsi +make saura qu'il faut, pour ces règles, ignorer la préexistence de la cible. + +Et voilà, vous avez réécri le makefile de francium tel qu'il existe aujourd'hui +! + +[^1]: que l'on utilisera pour les exemples dans ce document +[^2]: documentée ici https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04 +[^3]: oui le nom de la fonction est simplement `.`. +[^4]: du moins très probablement aucune +[^5]: quand bien même la syntaxe a été écrite de façon à ce qu'un.e humain.e puisse le comprendre +[^6]: auquel on a ajouté un `:` pour ressemble aux autres déclarations +[^7]: Voir: https://www.in-ulm.de/~mascheck/various/shebang/#interpreter-script ou le commit 4bd895 +[^8]: la ligne `[ "$1" ] || set -` que je ne m'explique pas +[^9]: même s'il est très improbable qu'un fichier all ou clean se faufile dans votre projet, on sait jamais. +[script initial de John Gruber]: https://daringfireball.net/projects/markdown/ +[DSL]: https://en.wikipedia.org/wiki/DSL +[YAML]: https://en.wikipedia.org/wiki/YAML + diff --git a/makefile b/makefile @@ -39,35 +39,14 @@ annexescibles = ${annexfiles:contents/%=public/%} # Règles ######## -# Explication sommaire du fonctionnement de make - # Syntaxe générale d'une règle : # cible : liste dépendances ; commandes # ou -# cible : list dépendances +# cible : liste dépendances # commandes -# Pour chacun des chemins de cibles construits précédemment make va chercher -# une règle permettant de construire le fichier en question. Pour cela il -# cherche une règle ayant pour cible un chemin correspondant. -# Une fois qu'il a trouvé une règle qui correspond, il vérifie si la cible -# existe. -# Si elle n'existe pas il cherche à construire toutes ses dépendances puis -# exécute la commande. -# Si le cible existe déjà et que les dépendances existent il vérifie si ses -# dépendances ont été modifiées après sa dernière modification. Si oui alors on -# suppose que la cible n'est pas à jour (ses sources sont plus récentes qu'elle -# même) et make relance la commande. - -# Make cherche à créer les cibles qu'on lui passe en argument -# `make public/index.html` construira la cible `public/index.html`. -# Par défaut sans argument make cherche à construire la première règle qu'il -# trouve, d'où : - # On créer une "fausse" règle (phony en anglais) all pour qu'exécuter make sans -# argument construise tout le site. Puisque cette règle ne créer pas de fichier -# all, elle sera toujours exécutée et toutes ses dépendances avec. Si l'on liste -# toutes les cibles du site cela revient à créer tout le site. Par convention +# argument construise tout le site. # cette règle se nomme "all" mais elle pourrait s'appeler "toto". all: exec ${pageshtml} ${annexescibles} @@ -81,15 +60,9 @@ exec:; chmod +x ${sources} # Règles pour générer les fichiers # Ce que % match dans la cible sera substitué à la place de % dans les -# dépendances. make substitue la variable $@ avec le chemin de la cible et $< -# avec le chemin de la première dépendance de la règle. -# Ex: -# public/%.html : contents/%.sh -# $< > $@ -# -# matchera pour la cible public/index.html et la dépendance contents/index.sh -# et exécutera la commande -# contents/index.sh > public/index.html +# dépendances. +# $< = première dépendance +# $@ = cible # Règle pour la génération des pages html public/%.html : contents/%.sh page layouts/html