Développement Ada sous FreeBSD 13.1

Célèbre dessin XKCD d'un personnage qui s'énerve devant son
écran en disant « Quelqu'un a TORT sur internet ! »

Une fois n'est pas coutume, ce billet ne va contenir que des élucubrations profondément techniques (comme le signale son tag Geek) sur la façon de mettre en place ce qu'il faut pour programmer en Ada sous FreeBSD. Je présente toutes mes excuses à mon lectorat non-technique, qui peut sereinement arrêter la lecture de ce billet ici.

D'un autre côté, je me perds comme d'habitude en explications d'explications, et j'imagine que ce billet peut être accessible aux lecteurs un minimum familiers avec les problématiques techniques informatiques, même sans savoir rien de plus sur Ada et FreeBSD que ce sont respectivement un système d'exploitation et un langage de programmation.

Il y a quelque temps, Stéphane Carrez a publié sur son blog un article qui le même titre que celui-ci. Mon sang n'a fait qu'un tour avant que je sois submergée par l'appel du devoir et que je commence la conception du présent billet.

Je vais donc essayer d'expliquer pourquoi il y a un problème, pourquoi la solution de Stéphane ne me revient pas, la solution que j'aurais choisie à la place, et quelques avantages et inconvénients de chaque approche.

Le problème base : Ada sous FreeBSD

Le fond du problème, c'est qu'Ada est un langage un peu obscur, et FreeBSD est une plateforme un peu obscure aussi, et on ne peut pas espérer faire fonctionner l'un sur l'autre sans l'apparition spontanée de crottes de ragondin.

Pendant de nombreuses années, FreeBSD et DragonflyBSD étaient plutôt en avance sur les autres plateformes un peu obscures en ce qui concerne le support du langage Ada, grâce aux efforts de John Marino pour maintenir en conditions opérationnelles les logiciels nécessaires.

Étant moi-même utilisatrice de FreeBSD et d'Ada, j'étais aux premières loges pour constater l'étendue de ces efforts, et j'en suis encore pleine de reconnaissance.

Je n'ai pas trop suivi quel drama a mis fin aux efforts de John Marino dans l'infrastructure FreeBSD, et je n'ai aucune envie de rouvrir le dossier, mais le résultat est l'arrêt net de la maintenance l'infrastructure Ada dans FreeBSD en février 2017, avec un compilateur GCC 6.3.

Visiblement, il ne restait personne qui ait le niveau et le temps pour succéder à John Marino, GCC a continué d'évoluer de son côté, et FreeBSD du sien, les crottes de ragondin se sont accumulées au point de rendre le tout complètement impraticable.

La solution de Stéphane

Face à ce problème, Stéphane est parti de l'idée que puisqu'il n'y a plus de compilateur pour FreeBSD, il faut en refaire un.

Une difficulté majeure dans la fabrication d'un compilateur Ada pour une plateforme qui n'en a pas, c'est que le compilateur Ada est écrit lui-même en Ada, donc il faut un compilateur Ada pour avoir un compilateur Ada. Quand on n'en a pas, on doit généralement passer par de la compilation croisée, et ce n'est pas drôle du tout.

Si on retrouve quelque part dans une archive un vieux compilateur Ada, par exemple le dernier fait par John Marino, le problème est beaucoup moins imposant. J'imagine que c'est ce qui a permis à Stéphane de s'y mettre, et de finir avec quelque chose qui semble fonctionner.

Je n'aime pas cette solution, et je reste extrêmement réticente à compiler mon propre compilateur Ada pour deux raisons :

Donc d'accord pour recompiler un compilateur, mais seulement si on est dos au mur et qu'il n'y a aucune possibilité.

La solution de Natacha

De mon côté, l'idée est plutôt qu'en fait il y a encore un compilateur pour FreeBSD, il faut juste le retrouver.

Car la raison pour laquelle mon sang n'a fait qu'un tour, c'est que j'ai (un peu) suivi la suite de l'histoire de John Marino. Il a continué à entretenir un compilateur Ada pour des plateformes BSD, au travers de Ravenports. Donc en gros il fait la même chose qu'avant, juste hors de l'infrastructure FreeBSD.

Vu le débit intestinal des ragondins dans ces parages, il me semblait logique de compter sur Ravenports dès que j'en aurais marre des restes de GCC 6.3 dans les ports.

Pour diverses raisons, je ne programme plus trop dans mon temps libre, depuis à peu près l'automne 2017, donc les restes de GCC 6.3 ont eu le temps de bien pourrir et même de disparaître avant que je me bouge sérieusement.

Je me suis bougée sérieusement le 16 avril dernier, j'y ai passé une petite heure (dont un certain nombre de pauses twitter), et puis j'ai commencé à adapter mon code pour ce nouveau compilateur, et je n'ai pas eu le temps d'aller jusqu'au bout avant d'être appelée par d'autres aventures. Donc j'en étais restée à l'impression de « ça va, c'est facile ».

Donc forcément, en lisant le billet de Stéphane, j'ai éructé comme une twitta qui se respecte (pas), et j'ai ressorti quelques lignes sorties de mon historique. Heureusement, le filtre anti-éructation que constitue son bouton Login pour atteindre les commentaires de son blog a permis de calmer la pulsion.

Et tant qu'à répondre à un billet de blog par un billet de blog, autant faire les choses proprement, avec une séquence pas à pas. Et je ne vais pas publier une séquence sans l'avoir vérifiée moi-même sur une machine propre.

Et fatalement, j'ai constaté par moi-même que ce n'est pas si facile.

Ravenports pas à pas

Il y a une première chose qui prête à confusion, c'est que ravenports rassemble deux systèmes qui sont habituellement distincts :

Je ne sais pas trop à quel point le système de ports est difficile à déployer, mais j'ai eu plusieurs échos indépendants plutôt négatifs, donc je peux comprendre qu'en suivant le HowTo qui enchaîne les deux on se retrouve face à une erreur impressionnante qui fasse laisser tomber.

Pourtant en se limitant à l'infrastructure binaire de ravenports, on peut rapidement avoir un compilateur Ada en parfait état de marche. Voici ce que j'ai fait en tant que root :

fetch http://www.ravenports.com/repository/ravensw-freebsd64-bootstrap.tar.gz
tar xvf ravensw-freebsd64-bootstrap.tar.gz -C /
cat >|/raven/etc/ravensw.conf <<-EOF
ABI = "FreeBSD:12:amd64";
ALTABI = "freebsd:12:x86:64";
EOF
/raven/sbin/ravensw upgrade
/raven/sbin/ravensw install gprbuild-primary-standard gcc11-ada_run-standard gcc11-compilers-standard

Pour l'instant ce n'est pas encore difficile, les seules subtilités que j'ai relevées sont la distinction entre le système de ports et le système de paquets binaires, et se retrouver dans la nomenclature des ports et des paquets.

C'est à l'utilisation que les choses sont devenues un peu plus délicates, au point que je me suis embrouillée plusieurs fois. Il y a d'autres gens qui rantent mieux que moi sur les systèmes de build, mais je me suis fait avoir à plusieurs reprises par gprbuild qui utilise des outils incompatibles entre eux, par exemple le compilateur de Ravenports et l'éditeur de lien du système de base de FreeBSD. La confusion est d'autant plus facile qu'on s'est embrouillé à l'étape précédente entre les différents paquets de compilateur qui peuvent être installés simultanément.

Avec les commandes ci-dessus, qui m'ont l'air propres et minimales, on peut utiliser gcc11 et seulement celui-ci au moyen des variables d'environnement PATH et LIBRARY_PATH, en y ajoutant la variable LD_LIBRARY_PATH pour que les outils retrouvent leurs propres bibliothèques.

Imaginons que je veuille télécharger, compiler, et tester un de mes prochets, avec un petit patch ad-hoc pour s'adapter aux compilateurs aussi récents. Ça peut donner ça :

mkdir ~/code
cd ~/code
git clone https://github.com/faelys/natools.git
cd natools
git checkout -b demo 947c004e6f69ca144942c6af40e102d089223cf8
fetch -o- https://instinctive.eu/weblog/0E7/947c004e.patch | patch -p1
PATH=/raven/toolchain/gcc11/bin:/raven/toolchain/x86_64-raven-freebsd12/bin:/raven/toolchain/bin:/raven/bin LIBRARY_PATH=/raven/toolchain/gcc11/lib:/raven/toolchain/x86_64-raven-freebsd12/lib:/raven/toolchain/lib LD_LIBRARY_PATH=/raven/toolchain/gcc11/lib:/raven/toolchain/x86_64-raven-freebsd12/lib:/raven/toolchain/lib /raven/bin/gprbuild -p -XTASK_SAFETY=Intel -P tests
./bin/test_all

J'ai mis les variables dans la ligne de commande pour garantir la minimalité des modifications ; pour une utilisation quotidienne il est logique de les mettre dans un script ou dans son environnement de shell, et LD_LIBRARY_PATH peut probablement être remplacé par une utilisation adéquate de ldconfig(8).

J'ai exécuté ces commandes sur une machine FreeBSD 13.1 vierge (sur le plan Ada), et si ça peut être utile à quelqu'un en voici la transcription.

Les limites de ma solution

Le premier indice que tout n'est pas au mieux, est que la suite de tests de mon projet échoue sur le système cron :

  Section: Cron
    Basic black-box usage                                               SUCCESS
    Delete entry while callback is running                              FAIL
Before wait: expected "(", found ""
After wait: expected "().", found ".."
    Insert entry while callback is running                              SUCCESS
    Simultaneous activation of events                                   FAIL
Expected "12312123", found ""
    Delete entry while callback list is running                         FAIL
Expected "()<>", found "()<"
    Fusion of synchronized callbacks                                    FAIL
Expected "()ABb()A", found "()ABb("
Expected "()ABb()AB()", found "()ABb()ABb"
Expected "()ABb()AB()", found "()ABb()ABb"
    Extension of synchronized callbacks                                 FAIL
Expected "()MTE()T", found "()MTE()TE("
Expected "()MTE()T", found "()MTE()TE("

J'ai essayé d'expliquer ces tests dans leur code source, en résumé le système cron exécute du code à certaines heures, et le test y met du code qui ajoute ponctuellement un caractère à une chaîne commune ou ajoute successivement deux caractères avec une temporisation entre.

Par exemple, quand le test trouve ()ABb( au lieu de ()ABb()A, ça veut dire que le test s'est terminé pendant la deuxième temporisation du motif () alors qu'on devrait être entre le deuxième A et le deuxième B.

Or les temporisations et les synchronisations entre tâches font partie des coins les plus propices aux crottes de ragondins.

Je n'ai pas encore pris le temps d'analyser ces échecs, il peut s'agir de bizarreries de la machine ou de bugs dans mon code, mais vu le passif du compilateur Ada sous FreeBSD, un bug de la runtime n'est pas du tout improbable.

D'autant plus qu'avec certains frankencompilateurs que j'ai produits pendant la préparation de ce billet, j'avais reproductiblement des résultats bien meilleurs sur ce test. Donc les lignes que je présente ci-dessus ne sont peut-être idéales.

Au passage, on peut remarquer que je lance ma suite de tests avec les bibliothèques du système de base, et non pas les bibliothèques de Ravenports. Comme la tradition de GNAT est de faire une édition de liens statique, ce binaire ne dépend que de libc et libthr, mais c'est justement des subtilités dans cette dernière qui peuvent poser ce genre de problèmes.

Un autre détail qui n'aura probablement pas échappé au lecteur attentif, est que je suis loin d'avoir les dernières versions. Au moment de l'écriture de ces lignes, Ravenports propose GCC 11.2.0 pour FreeBSD 12, alors que Stéphane construit son GCC 12 sur FreeBSD 13.

La compatibilité binaire de FreeBSD permet en théorie de faire fonctionner sans problème les paquets binaires FreeBSD 12 sur une base FreeBSD 13, et le retard dans la version de GCC est tout à fait explicable par la chasse aux crottes de ragondin, donc ça ne me pose aucun problème. Je comprends cependant ceux qui voudraient les toutes dernières versions, quitte à les chercher à la source.

Conclusion

Je garde quand même une certaine appréhension envers la régénération d'un compilateur sur une nouvelle plateforme, et je continue de faire plus confiance à John Marino qu'à Ada Core et l'équipe de GCC pour fournir une runtime Ada complètement fonctionnelle sous FreeBSD.

Je reconnais quand même que la solution simple et directe que j'avais en tête était d'un optimisme béat.

D'un autre côté, la mise en place de Ravenports ne m'a pris que 5h20, en comptant les différentes pauses pendant que ça télécharge ou que ça compile, et en comptant toutes les fausses pistes et tous les tests avec les différents compilateurs de Ravenports (mais sans compter les deux heures de rédaction du présent texte, et deux autres heures pour sa traduction). Je soupçonne que ce soit compétitif avec le contenu du billet de Stéphane.

Reste à reprendre toutes mes suites de tests et faire la part entre ce qui est dû à l'évolution du langage, les bugs dans mon code, les incohérences de génération, et les bugs de compilateur ou de runtime.

Commentaires

Pas de commentaire pour le moment.

Poster un commentaire

Mise en forme historique : pour mettre en valeur un mot ou un groupe de mot, tapez une étoile de part et d'autre, sans mettre d'espace entre l'étoile et le mot, comme ceci : *mise en valeur*. Pour insérer un lien, mettez le entre crochets, comme ceci : [http://instinctive.eu/].

Mise en forme markdown : voir le guide détaillé, en résumé c'est le Markdown traditionnel, sans HTML ni titres, mais avec les tables PHP-Markdown-Extra.

Attention : les balises HTML entrées dans les commentaires seront affichées telles quelles, et non pas interprétées.

Autour de cette page

 

Autour de cet article

  • Publié le 28 août 2022 à 19h55
  • État de la bête : en croisade
  • Pas de commentaire
  • Tag : BSD
  • Tag : Geek

Tags

Archives

Site-level navigation and features

 

Instinctive.eu

Contact

Sections

Validation

Copyright © 2008-2022 Natacha Kerensikova

Butterfly images are copyright © 2008 Shoofly