arthur.bebou

Le site arthur.bebou.netlib.re - retour accueil

git clone git://bebou.netlib.re/arthur.bebou
Log | Files | Refs |

index.sh (9767B)


      1 #! page
      2 title: Rendre catium portable
      3 author: Arthur Pons
      4 description: Faisons des efforts pour rendre catium fonctionnel sur macos et les *bsd
      5 publication: 2024-01-12
      6 
      7 sectionmd: main
      8 
      9 A Katzele on écrit souvent du shell. On (je du moins) aime bien dire que ce que
     10 l'on écrit est POSIX ou presque et que ça fonctionne donc sur tous les dérivés
     11 d'Unix[^1]. De fait, une majorité d'entre nous utilise des systèmes Debian ou
     12 basés sur Debian (Ubuntu) et nous testons rarement nos créations sur autre chose.
     13 Même si l'on essaye d'énoncer clairement les dépendances d'un projet, la
     14 portabilité vers d'autres systèmes ne prend qu'assez peu de notre temps pour
     15 quatre raisons :
     16 
     17   1. La faible demande d'adaptation vers d'autres distributions
     18   2. Le manque de temps
     19   3. Le manque de matériel (nous n'avons pas facilement accès à un mac)
     20   4. La croyance que puisque l'on fait du shell simple alors ce sera portable de toute façon
     21 
     22 En profitant d'une rare exception à la première raison, je propose de tester
     23 les deux dernières raisons en portant Catium sur MacOs version 10.x et
     24 supérieure ainsi qu'OpenBSD 7.4.
     25 
     26 Merci à mon frère qui m'a prêté son mac pour faire des tests.
     27 
     28 ## La demande
     29 
     30 [Timothée Goguely], designer et dev web basé à Strasbourg, souhaite tester
     31 Catium pour la création d'un site pour l'un de ses clients soucieux de faire
     32 très simple. Timothée utilise un mac, le client utilise un mac, il est donc
     33 opportun de tester Catium sur un mac.
     34 
     35 Par la suite j'ai profité de la gentillesse de Victor Hoffner pour tester
     36 la version modifiée sur OpenBSD.
     37 
     38 ## Les tests
     39 
     40 ### Construire le projet (make)
     41 
     42 Première chose à faire, cloner le projet. Mac vient avec git (en tout cas je
     43 n'ai pas eu à l'installer sur les deux macs que j'ai utilisé), il suffit donc
     44 de faire :
     45 
     46     git clone git://katzele.netlib.re/catium
     47 
     48 En théorie, si tout fonctionne bien il suffit ensuite d'installer lowdown, de
     49 créer le dossier root dans lequel on génère le site et de lancer `make`.  Pas
     50 de souci à l'installation de lowdown via le gestionnaire de paquet
     51 communautaire [homebrew]. Pas de souci pour créer le dossier mais en lançant
     52 `make` on constate que seules les copies du favicon et de la feuille de style css
     53 se font. Pas d'exécution de l'unique page de démo du projet. Il se trouve que
     54 le make fourni par défaut par Apple sur les Mac (du moins ceux que j'ai testé)
     55 est GNU Make version 3.8[^8]. Elle ne supporte manifestement pas la syntaxe
     56 suivante, présente dans notre makefile :
     57 
     58     pages = ${sources:src/%.md=root/%.html}
     59 
     60 Or cette syntaxe "traduit" le chemin du fichier source vers le chemin du
     61 fichier de destination. Si cette ligne ne fonctionne pas, le makefile ne
     62 cherchera jamais à créer le fichier de destination et n'appellera jamais la
     63 règle correspondante. Pour y remédier il faut installer GNU Make via brew en
     64 faisant `brew install make`. Brew package une version plus récente de GNU Make
     65 (4.1.1) qui supporte cette syntaxe. Après l'installation, brew nous informe
     66 que l'on peut appeler cette version de GNU Make en lançant la commande `gmake`
     67 mais qu'une opération sur le `PATH` peut rendre cette version là disponible en
     68 tapant `make`.
     69 
     70 > GNU "make" has been installed as "gmake".
     71 > If you need to use it as "make", you can add a "gnubin" directory
     72 > to your PATH from your bashrc like:
     73 >
     74 >      PATH="$HOMEBREW_PREFIX/opt/make/libexec/gnubin:$PATH"
     75 
     76 J'en conviens, cette solution est quelque peu
     77 confuse puisqu'elle a pour résultat d'avoir deux version différentes
     78 de GNU Make installées sur son ordi, l'une appelée make et l'autre
     79 gmake mais ça fait l'affaire.
     80 
     81 Lançons maintenant `gmake`. On constate que la génération de la page html
     82 essaye bien d'avoir lieu mais qu'un message d'erreur (parmi d'autres) indique
     83 que `-D` n'est pas une option pour la commande install. Il se trouve que
     84 d'après le standard POSIX[^2], install n'est pas POSIX. Cela ne veut pas dire
     85 qu'il ne faut jamais l'utiliser ni qu'il ne se trouvera sur aucun *nix mais que
     86 l'on en a pas la garantie et surtout que l'on ne peut pas prédire son
     87 comportement et ses options. La preuve, la version disponible sur MacOs ne
     88 comporte pas l'option `-D` qui existe pourtant dans l'install des GNU core
     89 utils. Ne trouvant pas d'équivalent commun aux deux versions j'ai préféré le
     90 remplacer par :
     91 
     92 	mkdir -p $(dirname $@)
     93 	$< > $@
     94 
     95 Qui créé d'abord le dossier de destination à l'aide d'mkdir et dirname qui
     96 sont tous les deux POSIX puis exécute le script en redirigeant la sortie vers
     97 le fichier de destination.
     98 
     99 Si vous exécutiez `gmake` vous verriez une nouvelle erreur informant qu'il
    100 manque une quelque chose à mkdir pour bien fonctionner. En effet la capture
    101 de commande `$(dirname $@)` ne fonctionnera pas tel quel dans le makefile.  Il
    102 faut faire appel à la fonction `shell`[^3] pour exécuter `dirname` avant que le
    103 makefile n'exécute le `mkdir`. Cela donne donc
    104 
    105 	mkdir -p $(shell dirname $@)
    106 	$< > $@
    107 
    108 Avec cette modification nous avons un makefile parfaitement fonctionnel sur MacOs à
    109 condition d'avoir mis jour make.
    110 
    111 ### Exécuter les scripts
    112 
    113 Si vous suivez l'article vous aurez remarqué qu'il y a d'autres erreurs que
    114 nous avons jusque là ignoré. Le "préprocesseur" des pages et le fichier common
    115 associé, les fichiers page et common ont été écrit pour [Dash], le shell POSIX
    116 de Debian par défaut. Il est disponible sur d'autres systèmes.
    117 
    118 Les shebang utilisés sur ces deux scripts sont `#! /bin/sh`. Sous Debian
    119 `/bin/sh` est un lien symbolique vers `dash` mais ce n'est pas le cas
    120 sous tous les systèmes. En l'occurence sur MacOs `/bin/sh` est un lien
    121 symbolique vers le shell de login par défaut du système, c'est à dire zsh.
    122 Il fallait donc être plus explicite. J'ai initialement changé les shebang en
    123 `#! /bin/dash`, ce qui fonctionne sous MacOs, mais pour des raisons de
    124 meilleure portabilité je l'ai ensuite changé en `#! /usr/bin/env dash` au
    125 cas-où `dash` soit installé ailleurs qu'à `/bin/dash`[^9].
    126 
    127 Ce changement corrige une partie des problèmes, lorsque bash n'interprètent pas
    128 les scripts comme dash mais certaines erreurs subsistent du type :
    129 
    130     src/index.md: ligne 2 : fg: pas de contrôle de tâche
    131     src/index.md: ligne 3 : fg: pas de contrôle de tâche
    132     src/index.md: ligne 4 : fg: pas de contrôle de tâche
    133     src/index.md: ligne 5 : fg: pas de contrôle de tâche
    134     src/index.md: ligne 9: Cette : commande introuvable
    135     src/index.md: ligne 13: bin : commande introuvable
    136 
    137 Ces erreurs pointent vers le fait que les alias présents dans common ne sont
    138 pas instanciés correctement. Si l'on vérifie quel processus se lance lorsque
    139 l'on exécute "à la main" la page en faisant `src/index.md`, on constate que le
    140 script est lancé avec le shell par défaut du système (`bash src/index.md` par
    141 exemple). Or, le shebang de `src/index.md` est `#! page`. Ce que l'on souhaite
    142 c'est qu'en exécutant une page, elle soit passée en argument au script page
    143 qui lui même sera exécutée par dash et fera tourner le code dans common.
    144 Pour une raison ou pour une autre le shebang est ignoré, page et common non
    145 exécutés, le nécessaire n'est pas créé et l'on obtient des erreurs.
    146 
    147 Avec Timothée nous avons cherché un moment pourquoi nous constations ce
    148 comportement. Il se trouve que MacOs et *BSD ne supportent pas l'utilisation
    149 d'un script contenant lui même un shebang[^4][^5][^6].  Le shebang doit pointer
    150 sur un binaire. Un contournement est d'utiliser `/usr/bin/env` et de lui donner
    151 en argument notre interpréteur perso[^7] :
    152 
    153     #! /usr/bin/env ./page
    154 
    155 Je n'aime pas trop cette solution que je trouve bien moins sympathique pour
    156 l'utilisateurice que d'écrire `#! page` ou `#! page` mais c'est le prix
    157 de la portabilité. Cela n'empêche évidemment pas d'utiliser la forme courte
    158 sur les systèmes Linux.
    159 
    160 Avec cette dernière modification on devrait pouvoir faire
    161 
    162     gmake
    163 
    164 et constater la bonne génération de `root.index.html`.
    165 
    166 ## Conclusion
    167 
    168 J'avais tort en disant "On fait du shell POSIX simple, ça fonctionne
    169 partout !". Je n'aurais pas eu tort si j'avais dit "On fait du shell
    170 à peu près POSIX et simple, ça devrait pas être très compliqué à faire
    171 fonctionner ailleurs".
    172 
    173 J'en retire qu'il faut être encore plus clair sur les dépendances. Par exemple
    174 ne pas dire "make" mais "GNU Make testé en version >4.3", ne pas dire
    175 "interpréteur shell POSIX" mais "Dash". Cela dit, nous avons testé et
    176 Catium fonctionne avec zsh et ksh, pas bash.
    177 
    178 La totalité de ce travail, y compris la rédaction de cet article, aura pris
    179 quelque part entre 6h et 8h, ce que je trouve raisonnable. La quantité de code
    180 modifié est petite, l'esprit du projet n'a pas changé. Je pense que l'on a fait
    181 la démonstration qu'à défaut d'avoir été portable directement en faisant des
    182 choses simples et en essayant de garder, ne serait-ce qu'un peu, la portabilité
    183 en tête on se facilite la tâche pour le jour où il faudra réellement le faire.
    184 
    185 [^1]: Linux, *BSD, MacOs notamment
    186 [Timothée Goguely]: https://timothee.goguely.com/
    187 [homebrew]: https://brew.sh/
    188 [^2]: https://pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html
    189 [^3]: https://www.gnu.org/software/make/manual/html_node/Shell-Function.html
    190 [Dash]: https://fr.wikipedia.org/wiki/Debian_Almquist_shell
    191 [^4]: https://stackoverflow.com/questions/9988125/shebang-pointing-to-script-also-having-shebang-is-effectively-ignored
    192 [^5]: https://en.wikipedia.org/wiki/Shebang_(Unix)
    193 [^6]: https://www.in-ulm.de/~mascheck/various/shebang/#interpreter-script
    194 [^7]: https://theinfocentric.com/bash-shebang/
    195 [^8]: Vieille de 21 ans !
    196 [^9]: Im me semble qu'env peut se retrouver ailleurs que /usr/bin/env mais bon. Je pense pas que l'on puisse faire beaucoup mieux.