On aurait pu croire que permettre la compilation de binaires natifs pour Android et iOS via Go et Godot, sans toucher au moindre SDK propriétaire, était l'apogée technique du projet graphics.gd. C'était pourtant sous-estimer la ténacité du développeur derrière l'outil. Trouvant l'exercice presque trop facile, il s'est mis en tête de s'attaquer au véritable boss final du développement logiciel, la compatibilité binaire sous Linux.
Le paysage Linux est paradoxal. D'un côté, distribuer des outils en ligne de commande ou des serveurs écrits en Go est un jeu d'enfant. Une simple commande de build suffit pour générer un exécutable statique capable de tourner sur n'importe quelle distribution équipée d'un noyau post-2012. Mais dès que l'on souhaite afficher des pixels à l'écran et profiter de l'accélération matérielle, la mécanique s'enraye. Les pilotes GPU nécessitent l'accès à des bibliothèques dynamiques via l'ABI C, elles-mêmes liées à une libc spécifique. C'est là que la fracture se crée. Le monde est divisé entre la traditionnelle glibc et les distributions basées sur musl, comme Alpine ou Void Linux. Un binaire compilé pour l'un refusera catégoriquement de se lancer sur l'autre.
Le problème est devenu très concret lorsque le créateur du projet a décidé de migrer sa machine personnelle sous Void Linux, une distribution basée sur musl. Du jour au lendemain, compiler des projets comme l'éditeur Zed ou ses propres applications graphics.gd est devenu un véritable parcours du combattant. Go gérait mal les archives C dans cet environnement, brisant net le flux de travail. Pour s'en sortir, il a fallu patcher le runtime de Go et introduire une nouvelle cible de compilation. Mais cette solution partielle a engendré un nouveau dilemme, la nécessité de distribuer deux versions distinctes de chaque jeu ou application, une pour glibc et une pour musl. Une aberration en termes d'expérience utilisateur.
C'est alors que l'idée d'un binaire statique unique a refait surface. En théorie, musl excelle dans l'édition de liens statiques. Godot incluant déjà la majorité de ses dépendances, il suffisait de lier le tout statiquement, n'est-ce pas ? La tentative s'est soldée par un échec cuisant. Godot doit impérativement utiliser la fonction dlopen pour charger dynamiquement les interfaces avec X11, Wayland ou Vulkan. Or, musl refuse d'implémenter dlopen dans un binaire statique pour des raisons d'incompatibilité de gestion du stockage local des threads (TLS).
Face à cette impasse, une solution audacieuse, presque insolente, a vu le jour. S'inspirant de techniques de détournement utilisées par des projets comme Cosmopolitan, le développeur a mis au point une méthode pour "voler" le chargeur dynamique du système hôte. Le principe consiste à inclure un minuscule programme C qui s'exécute depuis le même processus pour récupérer le dlopen du système, puis à revenir dans le code de l'application. Pour que la magie opère, des trampolines en assembleur sont utilisés pour basculer vers le TLS du système le temps de l'appel, évitant ainsi les crashs.
Après des heures de débogage et quelques dialogues surréalistes avec des modèles de langage pour affiner l'assembleur, le résultat est là. Le mélange improbable de musl et de ce dlopen artisanal permet désormais de produire un binaire unique, totalement autonome, qui supporte l'accélération graphique sur n'importe quel Linux moderne. C'est la fin de la fragmentation pour les développeurs utilisant graphics.gd. Pour les curieux, une démo technique ("Dodge The Creeps") est déjà disponible pour tester cette prouesse, et la fonctionnalité est prête à être utilisée via une simple commande de cross-compilation.

Commentaires