Développement Ada sous FreeBSD 13.1
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 :
- c'est un très gros programme, qui est très long à compiler (surtout sur mes machines sans ventilateur), avec autant d'occasions que ça se passe mal ;
- une fois que ça compile, rien ne dit que ça fonctionne correctement, et vu le temps qu'à l'époque John Marino avait passé à courir après des bugs subtils de la runtime, pour moi le compilateur est présumé pourri s'il n'y a pas au moins tous les tests standard qui passent.
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 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 :
- un système de ports, qui contient les références et les instructions de génération de différents logiciels ;
- un système de paquets binaires, qui organise les résultats de la génération à l'étape précédente pour les lister, les rechercher, les télécharger, et les installer sur une machine.
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 projets, 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 pas 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
Autour de cette page
Autour de cet article
Weblog
- …
- Le vélo et moi
- Eovolt City X
- En vrac 7
- Je ne suis pas écologiste, mais…
- Développement Ada sous FreeBSD 13.1
- Fiat Lux
- Le bonheur fermier
- Mon premier go bag
- En vrac 6
- …
Derniers commentaires
- Natacha dans Blogoversaire
- Jean Abou Samra dans Blogoversaire
- Jean Abou Samra dans Blogoversaire
- Natacha dans Blogoversaire
- Gro-Tsen dans Blogoversaire
- Balise dans Blogoversaire
- Gro-Tsen dans Mon deuxième carton
- Barakoma dans Requiescat
- joanna dans Évolution des commentaires
- Natacha dans Évolution des commentaires
Tags
- (Sans tag) (6)
- Appel au public (17)
- Autoexploration (60)
- BSD (6)
- Boulot (30)
- Création (12)
- En vrac (11)
- Évènement (58)
- Geek (47)
- Goûts (9)
- Humeur (18)
- Inventaire (9)
- Jeux (7)
- Jouets (36)
- Lecture (10)
- Réflexion (23)
- Site (22)
- Social (26)
- Société (14)
- Suite (15)
- Vision atypique (30)
- Vœux (8)
Archives
- 2024 (11)
- 2023 (14)
- 2022 (14)
- Décembre 2022 (1)
- Novembre 2022 (1)
- Octobre 2022 (2)
- Septembre 2022 (1)
- Août 2022 (1)
- Juillet 2022 (1)
- Juin 2022 (1)
- Mai 2022 (2)
- Avril 2022 (1)
- Mars 2022 (1)
- Février 2022 (1)
- Janvier 2022 (1)
- 2021 (15)
- 2020 (14)
- 2019 (12)
- 2018 (12)
- 2017 (13)
- 2016 (16)
- 2015 (12)
- 2014 (13)
- 2013 (15)
- 2012 (18)
- 2011 (18)
- 2010 (20)
- 2009 (45)