- Zig, dans la continuité de la séparation de
build.ziget du système de build en processus distincts, déplace la logique de gestion des paquets vers le processus maker, en dehors de l’exécutable du compilateur - Avec le déplacement de
zig build,zig fetch,zig initetzig libccôté maker, le code de gestion de HTTP, TLS, Git, de la compression et debuild.zig.zonest distribué sous forme de source - Avec cette architecture, les fonctionnalités de gestion des paquets peuvent être corrigées sans reconstruire le compilateur, et le maker étant compilé en
ReleaseSafe, les vérifications de sûreté sont aussi activées pour les opérations réseau - L’objectif initial est d’exposer le build server protocol afin de résoudre le problème lié à la modification de
--build-runnerqui bloquait ZLS ; dans la nouvelle arborescence de processus, le maker reste le parent du configurer, ce qui permet de gérer plus fiablement les réexécutions de configuration - L’impact pour les utilisateurs est limité, mais l’exécutable Zig passe de 14,1 Mio à 13,5 Mio, soit une baisse de 4 %, et
--maker-optainsi que--zig-lib-dirsont remplacés respectivement par les variables d’environnementZIG_DEBUG_MAKERetZIG_LIB_DIR
Déplacement de la logique de gestion des paquets
- Zig modifie son architecture : après la séparation du script utilisateur
build.ziget du système de build lui-même en processus distincts, la logique de gestion des paquets est elle aussi placée du côté du système de build - Les sous-commandes déplacées vers le processus maker sont les suivantes
zig buildzig fetchzig initzig libc
Code retiré de l’exécutable du compilateur
- De grands pans de code auparavant présents dans l’exécutable du compilateur sont désormais distribués sous forme de source
- Logique de récupération des paquets
- Client HTTP et réseau
- Chiffrement lié à TLS
- Protocole Git
xz,gzip,zstd,flate,zip- Analyse, validation et autres traitements des fichiers
build.zig.zon
- Ces fonctionnalités peuvent être corrigées sans reconstruire le compilateur, ce qui facilite l’expérimentation pour les utilisateurs et les contributeurs
- L’exécutable maker étant compilé en mode
ReleaseSafe, les vérifications de sûreté sont activées pour les opérations réseau de la gestion des paquets - Le code cryptographique utilisé pour le réseau et le hachage de fichiers peut exploiter les instructions CPU spécialisées disponibles sur l’hôte
Structure des processus et build server
- La motivation initiale était d’exposer le build server protocol afin de lever un blocage pour ZLS
- Dans l’ancienne architecture,
zig buildgérait à la fois le compilateur et le gestionnaire de paquets, tandis que le builder en dessous contenait la logique utilisateur debuild.ziget l’implémentation du système de build - Après la séparation maker/configurer, l’architecture était la suivante
zig build: compilateur + gestionnaire de paquetsconfigurer: logique utilisateur debuild.zigmaker: système de build
- Dans cette architecture, un
zig build --watchde longue durée devait réexécuter le configurer lorsqu’il détectait des modifications debuild.zigou de fichiers associés ; pour cela, le maker devait se terminer afin de redonner àzig buildl’occasion de répéter la logique de gestion des paquets - Dans la nouvelle architecture,
zig buildne s’occupe que du compilateur, tandis que le maker en dessous prend en charge le système de build et le gestionnaire de paquets, et le configurer devient un processus enfant du maker - Même lorsqu’il faut relancer la configuration, le maker peut rester en vie en tant que processus parent
- Dans le build server prévu, au lieu que le client se reconnecte après l’arrêt du serveur, il devient possible d’avoir une architecture où le client est informé des changements de configuration
Changements observables
- La plupart ne sont pas des changements incompatibles, mais certaines différences seront visibles par les utilisateurs
- Taille du binaire exécutable Zig : avec
ReleaseSmallsans LLVM, elle passe de 14,1 Mio à 13,5 Mio, soit une réduction de 4 % - Le flag
--maker-optest remplacé par la variable d’environnementZIG_DEBUG_MAKER - Le flag
--zig-lib-direst remplacé par la variable d’environnementZIG_LIB_DIR
- Taille du binaire exécutable Zig : avec
Derniers blocages avant Zig 0.17.0
- Après cet ensemble de changements, les principaux blocages restants constituent le travail clé avant le tag Zig 0.17.0
- MVP du build server protocol : nécessaire pour lever le blocage de ZLS
- Introduction du concept d’ajout de path dependency pour le build script lui-même
- Faire en sorte que
zig build --watchdétecte les changements du build script et se relance lui-même - Cache miss du build script dû à un cwd différent
- En juillet, deux conférences et la préparation de présentations sont prévues ; il est donc réaliste de s’attendre à ce que ces travaux soient finalisés début août
- Techatrix, de l’équipe ZLS, a pris contact et collaboré sur le build server protocol, et recherche des sponsors
1 commentaires
Avis sur Hacker News
Les développeurs de Zig, Go et Python annoncent parfois qu’ils ont retiré le liquide de refroidissement du réservoir de carburant, et leurs partisans s’en réjouissent en disant que ce sera bon pour le langage et que les performances s’amélioreront fortement.
Mais je me demande surtout pourquoi on avait mis du liquide de refroidissement dans le réservoir de carburant au départ.
Mettre la gestion des paquets dans le compilateur était pratique, mais quand le langage et les outils commencent à être largement utilisés, une fonctionnalité avantageuse pour une personne devient une dette qui freine l’adoption.
Dans beaucoup de projets, les développeurs choisissent la solution facile pour éviter « le travail difficile nécessaire pour bien faire les choses », et comme les autres n’ont pas envie de faire ce travail difficile non plus, cela finit par devenir la norme.
Si l’on implémente un gestionnaire de paquets dans le système de build tout en voulant le conserver aussi dans le compilateur, il faut d’abord décider quelle abstraction placer entre le compilateur et le système de build.
Cela touche aussi au système d’import et à des éléments fondamentaux du langage ; ces parties doivent être bien conçues et sont difficiles à modifier plus tard.
Au début, on peut fortement coupler la gestion des paquets et le compilateur, concevoir à rebours à partir de l’expérience développeur souhaitée, puis changer l’implémentation plus tard avec moins d’impact pour les utilisateurs.
Je pense en particulier que le système d’import de Python est devenu très complexe et imparfait parce qu’il a dû accepter plusieurs façons de faire de la gestion de paquets.
À l’inverse, Go a été conçu dès le départ avec la gestion des paquets en tête, ce qui rend sa syntaxe liée aux imports relativement petite et propre. Bien sûr, je ne suis pas d’accord avec toutes les décisions de conception.
Même pour un petit produit, il est difficile de prévoir comment chaque composant interagira avec les autres, et il faut sans cesse corriger.
Imagine maintenant créer un langage autohébergé destiné à remplacer C.
Plus les gains de vitesse sont importants, plus on s’en réjouit, mais la plupart des optimisations ne sont pas des techniques ingénieuses : c’est le profiler qui permet de trouver « ah, le liquide de refroidissement ne devrait pas être dans le réservoir de carburant ».
La plupart des goulots d’étranglement de performance ne sont pas des limites intrinsèques du matériel ou du problème lui-même.
Il existe une quantité minimale de travail nécessaire pour obtenir le résultat, mais si une application est lente, c’est presque toujours à cause du bric-à-brac ajouté par-dessus.
Le développement de Zig donne vraiment une impression d’ambiance saine.
J’utilise des LLM tous les jours et je reconnais qu’ils sont étonnamment bons sur plusieurs types de problèmes, mais je ne veux pas d’un langage de programmation créé par un LLM.
Chaque ligne de code, chaque décision et chaque compromis d’un langage de programmation compte.
Un langage conçu et codé uniquement à l’intuition serait un désastre.
Aucun modèle ne m’a jamais montré de code qui me convainque du contraire. Même Fable, qui est nettement meilleur que les meilleurs modèles précédents, n’y échappe pas.
Un modèle n’a pas de désirs, pas d’opinions significatives, et ne sait pas ce qui est confortable ou inconfortable dans un langage. C’est pareil pour des interfaces GUI ou CLI suffisamment complexes.
Un langage comme Zig ne peut pas sortir d’un LLM, sauf à simplement copier Zig ; et même dans ce cas, ce serait une moins bonne copie.
Ici, copier avec un LLM ne veut pas dire faire littéralement
cpsur l’arborescence source, mais plutôt qu’un LLM rédige une spécification et qu’un autre LLM implémente le langage à partir de cette spécification.J’ai créé un bootloader et travaillé avec UEFI, et personnellement j’ai trouvé ça beaucoup plus facile qu’en C.
Cela dit, je suis aussi biaisé par le plaisir d’apprendre quelque chose de nouveau et brillant.
Je me demande si ce changement est celui qui a conduit à retirer
@cImportde Zig pour le déplacer vers le système de build.C’est purement une question d’expérience utilisateur, et je comprends que séparer le système de build et le compilateur soit important pour les mainteneurs, mais je trouve quand même un peu dommage que la stabilité du développement passe avant l’expérience utilisateur.
C’est la bonne décision, mais c’est triste, et je considère que
@cImportétait une fonctionnalité phare très puissante de ce langage.Ce changement concerne le code qui télécharge et décompresse des paquets tiers.
Le changement autour de
@cImportfaisait partie du travail visant à rendre un jour la dépendance de Zig à LLVM/libclang optionnelle, puis éventuellement à l’extraire en paquet tiers, mais cela ne semble pas directement lié.J’ai lu quelque part que l’objectif à long terme était de déplacer le système de build dans une VM WebAssembly.
Si c’est le cas, c’est impressionnant.
C’est une bonne évolution pour Zig.
J’ai assez envie de passer de Go à Zig, mais pour l’instant j’aime aussi regarder ça de côté.
Chaque fois qu’un langage crée son propre système de paquets, j’ai juste l’impression que nous avons raté une grande occasion.
La seule exception est C/C++, où, pour le meilleur ou pour le pire, rien ne s’est vraiment imposé.
Ce choix peut créer des procédures très complexes plus tard, quand il faut mélanger plusieurs langages.
Les systèmes de packaging simplifient les choses, mais dès qu’il faut utiliser un autre langage, ils compliquent toute la suite.
Est-ce que tu veux un seul système de build pour tous les langages ? Des systèmes comme Bazel existent et sont souvent utilisés dans des projets multilangages, mais en pratique, il semble démontré que les systèmes de build dotés de connaissances propres à chaque langage sont beaucoup plus faciles à manier.
Cela oblige à réfléchir soigneusement avant d’ajouter une dépendance.
Ces dépendances ont souvent des coûts cachés, comme des failles de sécurité.
Une part importante des systèmes critiques étant écrite en C++, il serait beaucoup trop risqué de dépendre de dizaines de paquets tiers facilement accessibles sans auditer correctement chacun d’eux.
Zig est en train de combler ce vide.
En pratique, les seuls systèmes de build de ce type sont Buck et Bazel, mais tous deux traînent trop de baggage hérité des grandes organisations qui les portent.
C’est dommage.
La séparation des responsabilités a été réalisée de façon très convaincante.