/*
 * Accueil; tout; à propos + @ + FAQ;
 * => Lire cette page via gemini (gemini?);
 */

Comprendre le Makefile de graphos

Après avoir corrigé quelques détails concernant le générateur de ce site, pour m'amuser un peu avec l'apparence, corriger de petits bugs et simplifier la gestion des mises en ligne, j'ai pensé qu'il serait intéressant d'expliquer un peu comment le Makefile est construit. C'est en effet grâce à "make" que seules les pages qui en ont besoin sont générées, et dans le bon ordre en plus :).

Démystifions donc ensemble ce fichier.

On commence par importer le contenu du fichier "config.mk". Ce dernier n'est qu'une liste de variables utilisées ensuites.

include config.mk

Cela permet de pouvoir appeler les variables ensuite sous la forme "${VARIABLE}".

Maintenant, on liste les diverses extensions de fichier que le Makefile devra apprendre à traiter pour passer de l'une à l'autre:

.SUFFIXES: .${SRCEXT} .${HTMLEXT} .${GEMINIEXT} .${TXTEXT}

On enregistre dans la variable PAGES la liste des pages qu'il faudra convertir. Ce sont nos "sources".

Pour cela, on appelle la commande "find" qui liste dans le dossier "${SRCDIR}" (définit dans config.mk) les fichiers dont l'extension est ".${SRCEXT}".

PAGES != find ${SRCDIR} -type f -name \*.${SRCEXT}

Vous noterez l'utilisation de "!=" : PAGES contient ainsi le retour de la commande find, et non la chaîne de caractère constituant la commande elle-même.

Désormais, on peut établir la liste des fichiers que l'ont veut obtenir. Il s'agit juste de modifier l'extension. On utilise ":=" pour enregistrer nos variables : cela veut dire que c'est le contenu des variables qui est enregistré.

Autrement dit, écrire "VAR = ${VARIABLE}" met la chaîne "${VARIABLE}" dans VAR. Écrire "VAR := ${VARIABLE}" met le contenu de VARIABLE dans VAR.

HTMLPAGES := ${PAGES:.${SRCEXT}=.${HTMLEXT}}
GEMINIPAGES := ${PAGES:.${SRCEXT}=.${GEMINIEXT}}
TXTPAGES := ${PAGES:.${SRCEXT}=.${TXTEXT}}

Ici les substitutions sont écrites à l'ancienne. Les règles de substitutions avec le make d'OpenBSD sont plus lisibles et ressemblent à la syntaxe de la commande "sed". Cependant, je voulais proposer graphos aussi pour un système linux.

En gros, on peut résumer les choses ainsi : HTMLPAGES contiendra la même chose que PAGES après avoir remplacé les extensions SRCEXT par les extensions HTMLEXT.

On peut utiliser le caractère "%" pour désigner "tous les caractères" et le recopier ensuite. On s'en servira plus loin ;).

Dans tous les cas, nous avons ainsi la liste des fichiers à construire. S'ils sont absent, ou si les prérequis pour les obtenir ont été modifiés, alors ils seront construits selon les règles définies plus loin.

On arrive à la principale utilité du Makefile : définir des cibles et des dépendances.

Ça se présente ainsi : "cible: dépendance1 dépendance2 ...".

Cela signifie que lorsqu'on va construire "cible" avec "make cible", alors il faudra d'abord avoir construire "dépendance1" et "dépendance2".

Ici, on indique que la cible "all" (celle appelée par "make" sans arguments) a besoin des cibles "listall" et "${ENABLEDTARGETS}" (définies dans le config.mk):

all: listall ${ENABLEDTARGETS}

Parmi les valeurs que peut contenir ENABLEDTARGETS, il y a "html". On indique donc comment construire cette cible en précisant qu'il faut avoir auparavant construit les HTMLPAGES :

html: ${HTMLPAGES}

Cependant, pour l'instant, make ne sait pas comment fabriquer un fichier ".html" (.${HTMLEXT}) à partir d'un fichier ".md" (.${SRCEXT}).

C'est ce qu'on va lui expliquer maintenant avec une cible du type ".md.html:". C'est pour cela qu'on a indiqué plus tôt une ligne avec ".SUFFIXES":

.${SRCEXT}.${HTMLEXT}:
	@echo "$< -> ${@}"
	-@test -f templates/head.${HTMLEXT} && \
	    cat templates/head.${HTMLEXT} > $@
	@${TOHTML} $< >> $@
	-@test -f templates/foot.${HTMLEXT} && \
	    cat templates/foot.${HTMLEXT} >> $@
	@tools/vars.sh $@
	@mkdir -p $$(dirname ${@:${SRCDIR}%=${HTMLDIR}%})
	@cp -v $@ ${@:${SRCDIR}%=${HTMLDIR}%}

Comme vous pouvez le voir, la cible est suivie de lignes indentées avec une tabulation (c'est important ce tab).

Il s'agit des commandes à exécuter pour fabriquer un fichier .html à partir d'un fichier .md.

On remarque tout de suite que les commandes commencent souvent par un "@". C'est juste du confort, ça évite de voir la commande affichée dans la sortie de "make".

La première ligne affiche deux variables particulières :

La ligne suivant est précédée d'un "-". Cela permet de ne pas stopper make même si cette commande échoue. Puisqu'ici on teste la présence d'un fichier avant d'en mettre le contenu dans le fichier ciblé, et qu'on veut garder facultatif cette fonctionnalité, le "-" est tout adapté :)

Remarquez aussi qu'on peut enregistrer dans des variables la commande à appeler. Ici ${TOHTML} contient la commande qui permet de convertir le fichier d'entrée en html.

À la toute fin, on crée un dossier avec mkdir et on copie le fichier html obtenu dans un autre dossier. Ces lignes sont un peu particulières, plusieurs choses sont à noter:

Parmi les instructions, on peut voir "$$(dirname ...)". Cela permet d'obtenir le retour de "dirname $@" et connaître le chemin du dossier du fichier que l'on veut copier pour le créer. Le fait d'avoir 2 "$" permet d'éviter que make confonde cette instruction avec une variable, puisqu'on peut les écrire "$(VAR)" ou "${VAR}" (ce que je faisais jusqu'à présent).

En plus, on fait une substitution : on remplace SRCDIR par HTMLDIR : en effet, on veut copier notre page html dans le répertoire de sortie.

Vous remarquerez l'utilisation du caractère "%" qui signifie "n'importe quelle chaîne". C'est intéressant à utiliser car on peut placer ladite chaîne du côté droit du "=" à l'emplacement que l'on veut :)

Autrement dit, par exemple si j'ai une variable "VAR = prx boit trop de bière", alors si je fais "${VAR:%trop=%trop peu}", alors j'obtiens "prx boit trop peu de bière". \o/

On continue.

J'avance un peu dans le fichier vers ce segment :

atom: ${ATOMS}
${ATOMS}: ${ATOM}
	@mkdir -p $$(dirname $@)
	@cp -v ${ATOM} $@

On a la cible "atom" qui dépend des fichiers contenus dans la variable ${ATOMS}.

On indique ensuite comment construire ces fichiers. Eh oui, on peut utiliser une variable comme cible :)

Pour constuire ${ATOMS}, j'ai besoin du fichier ${ATOM} (les instructions pour l'obtenir sont plus loin.

On va encore un peu plus loin pour observer cette partie :

sitemap: ${HTMLPAGES} ${SITEMAP}
${SITEMAP}:
	@DOMAIN="${DOMAIN}" tools/sitemap.sh \
		${HTMLPAGES:${SRCDIR}/%=%} > ${SITEMAP}

Ici je fais le choix de passer les options au script "tools/sitemap.sh" via des variables d'environnement. C'est plus facile que de devoir gérer des options.

Ce script prend en argument ce truc : "${HTMLPAGES:${SRCDIR}/%=%}".

Il s'agit de la liste des pages html HTMLPAGES, mais légèrement modifiée. On remplace ici le dossier source "${SRCDIR}/" situé avant tout ce qui suit "%" par seulement tout ce qui suit "=%". Autrement dit, on retire des chemins "{SRCDIR}".

Utiliser "%" permet donc de "matcher" sur n'importe quoi, et de garder ce contenu en mémoire pour le réutiliser de l'autre côté du "=".

Enfin, on inclus un autre fichier pour que chacun puisse ajouter son petit bout de Makefile :

include custom.mk

J'espère que ces détails vous auront donné envie d'en apprendre davantage sur les Makefiles.

Pour consulter le code complet :

/code/graphos/

Et bien entendu :

https://man.openbsd.org/make

Une réaction?

Envoyez votre commentaire par mail.
Mode d'emploi de la liste de diffusion pour recevoir les réponses.