2 points par GN⁺ 2025-10-05 | 1 commentaires | Partager sur WhatsApp
  • La sortie de Zig 0.15.1 améliore nettement la vitesse de compilation par rapport à la version précédente
  • Les mesures effectuées sur le projet Ghostty montrent une réduction globale des temps d’exécution
  • LLVM est encore partiellement utilisé, mais on attend de nouveaux gains de performance avec l’adoption du backend maison
  • La compilation incrémentale n’est pas encore entièrement implémentée, mais des avantages de performance apparaissent déjà sur les builds partiels
  • Il est très probable qu’un environnement de build encore plus rapide et une meilleure expérience de développement deviennent réalité à l’avenir

Aperçu

Partant de la remarque d’Andrew Kelley selon laquelle « le compilateur est tellement lent qu’il introduit des bugs », Zig poursuit depuis plusieurs années divers efforts structurels avec pour objectif des temps de compilation plus rapides

  • L’équipe Zig travaille à supprimer LLVM, à développer son propre backend de génération de code, à construire un linker maison, et à concrétiser à terme une compilation incrémentale
  • Les résultats de ce travail de long terme commencent à devenir visibles avec Zig 0.15.1, et l’évolution des temps de build a été mesurée et partagée sur un projet réel, Ghostty

Vitesse de compilation du script de build

  • Zig 0.14 : 7 secondes 167 ms
  • Zig 0.15 : 1 seconde 702 ms

Il s’agit du temps de build du script build.zig lui-même, un coût initial supporté à chaque fois dans un environnement de build à partir de sources vierges

  • La fréquence de recompilation du script de build reste faible, mais cela a un impact direct sur l’expérience d’un utilisateur qui build le projet lui-même pour la première fois

Build complet du binaire sans cache (Ghostty)

  • Zig 0.14 : 41 secondes
  • Zig 0.15 : 32 secondes

Il s’agit du temps total de build du binaire, y compris le temps de build du script de build

  • Avec Zig 0.15, on observe environ 2 secondes de gain supplémentaire, et la différence initiale est aussi clairement visible en temps réel
  • Le backend x86_64 maison n’est pas encore pleinement exploité, et la majorité du build continue d’utiliser LLVM
  • À l’avenir, lorsque Ghostty pourra être buildé entièrement avec le backend maison, le temps devrait descendre sous les 25 secondes (environ la moitié du niveau initial)

Build incrémental (exécutable Ghostty)

  • Zig 0.14 : 19 secondes
  • Zig 0.15 : 16 secondes

C’est le temps nécessaire pour relancer le build après une modification significative d’une ligne (ajout d’un appel de log dans le code d’émulation de terminal)

  • Il s’agit d’un build partiel dans une situation où le script de build et le graphe de dépendances sont déjà en cache
  • La compilation incrémentale n’est pas encore complètement implémentée, mais les gains de performance sont déjà clairement visibles
  • En excluant la part liée à LLVM, une réduction à environ 12 secondes semble possible
  • Une fois un véritable build incrémental implémenté, on peut même espérer des builds en quelques millisecondes

Build incrémental (libghostty-vt)

  • Zig 0.14 : 2 secondes 884 ms
  • Zig 0.15 : 975 ms

Mesure du temps nécessaire pour rebuild partiellement uniquement libghostty-vt après une modification d’une ligne

  • libghostty-vt peut être buildé entièrement avec le backend x86_64 maison, ce qui reflète directement les améliorations de Zig sans influence de LLVM
  • Même sans compilation incrémentale, atteindre un temps de build inférieur à une seconde représente déjà un progrès considérable
  • Dans le workflow des développeurs, cela améliore l’efficacité grâce à une expérience de retour immédiat
  • Les backends x86_64 et aarch64 gagnent progressivement en stabilité, et pourraient être appliqués à l’ensemble de Ghostty dans les prochains mois

Où en est l’amélioration des temps de build

  • Le build de Ghostty avec Zig 0.15.1 est clairement plus rapide dans toutes les mesures effectuées
  • Même si le backend maison et la compilation incrémentale ne sont pas encore finalisés, les résultats actuels sont déjà très impressionnants
  • Des améliorations de vitesse encore plus marquantes sont attendues dans les 1 à 2 prochaines années
  • Le choix de Zig apparaît de plus en plus pertinent du point de vue de la vitesse de build

1 commentaires

 
GN⁺ 2025-10-05
Avis Hacker News
  • En 1995, quand j’ai obtenu mon diplôme de fin de lycée, recompiler "Borland Pascal version Turbo Vision for DOS" sur un Intel 486 allait à peu près à cette vitesse ; on retrouve enfin aujourd’hui des temps de compilation vraiment aussi rapides
    Turbo Vision est un framework de fenêtres TUI, utilisé pour le développement des IDE Borland Pascal et C++
    On peut le voir comme un mode texte réalisant l’équivalent d’un IDE JetBrains en 10 Mo au lieu de 1000 Mo
    Turbo Vision sur Wikipédia

  • LLVM est une sorte de piège
    Le bootstrap est vraiment rapide et on obtient gratuitement toutes sortes de passes d’optimisation et la prise en charge de nombreuses plateformes, mais on perd la capacité de régler finement les performances lors de la dernière étape d’optimisation ou de l’édition de liens
    Je pense que Cranelift sera bientôt activé dans Rust
    Mais si Rust a atteint sa place actuelle, c’est aussi parce qu’il a choisi LLVM au départ
    Go a décidé depuis longtemps de ne pas déléguer la génération de code et l’édition de liens à des outils externes, et profite largement de ce choix

    • J’ai du mal à être d’accord avec l’idée qu’LLVM soit un piège, et Rust est plutôt un bon contre-exemple
      En pratique, la partie génération de code via LLVM représente une très petite portion du compilateur, et on peut la remplacer par codegen_cranelift ou codegen_gcc
      La dépendance aux intrinsics SIMD spécifiques aux fournisseurs est bien un problème de lock-in, mais c’est un problème de conception du langage
      Pour la plupart des langages, commencer avec un backend LLVM est raisonnable
      Pour les langages proches de C/C++, le pipeline par défaut de LLVM optimise déjà bien, mais plus un langage a des caractéristiques différentes, plus il faut écrire soi-même son pipeline d’optimisation
      Le cas de Go, qui a intégré son propre backend dès le début, semble effectivement être une réussite, mais ce n’est pas un facteur de différenciation particulier, et l’implémentation maison a un coût d’opportunité assez élevé

    • Les compilateurs de Go et d’Ocaml sont vraiment rapides
      Ils ont correctement construit leurs propres bibliothèques dès le départ, et n’ont plus rien à perdre côté vitesse maintenant
      Je n’ai plus envie de travailler dans un environnement où une compilation prend plus d’une minute
      J’aimerais que chaque projet ait un compilateur dédié au mode dev, et qu’on n’utilise quelque chose de lourd comme llvm que pour le build final

    • Si un langage basé sur LLVM vise à remplacer C++, il reste malgré tout dépendant de C++
      Un langage doit pouvoir se bootstrapper lui-même
      Au début, ces outils pratiques existent, mais ce ne sont que des moyens de gagner du temps, pas des éléments indispensables
      Je comprends totalement le choix fait par l’équipe Go

    • J’espère que Cranelift continuera à progresser
      Aujourd’hui, LLVM est fragmenté par une avalanche de forks propres aux différents fournisseurs de CPU, chacun liant ses améliorations spécifiques dans des paquets privés
      Dès qu’on utilise un autre frontend de langage ou qu’un bug du compilateur apparaît, la situation devient très pénible

    • Quelqu’un se demande comment cela peut être un piège si les langages peuvent librement migrer vers d’autres backends

  • Si la vitesse de compilation gêne le développement, pourquoi ne pas faire un interpréteur ?
    La vitesse d’exécution et la vitesse de compilation sont fondamentalement indépendantes
    Avec un interpréteur, il devient aussi facile de créer des outils de développement supplémentaires, comme l’instrumentation du code ou le contrôle du runtime
    Il existe quelques rares cas où il faut déboguer uniquement un binaire RELEASE optimisé, mais dans la plupart des situations un interpréteur ou un build DEBUG suffit

    • J’ai entendu dire que Rust se classe par ordre de priorité sécurité, performance, ergonomie, tandis que Zig se classe performance, ergonomie, sécurité
      Sous cet angle, améliorer la vitesse de build est cohérent, mais un interpréteur est une alternative plus adaptée quand l’ergonomie passe avant tout

    • J’aime bien l’approche de Julia
      Dans un environnement pleinement interactif, l’interpréteur compile en réalité le code puis l’exécute immédiatement
      C’est aussi le cas d’environnements Common Lisp comme SBCL

    • Si on pousse à l’extrême, vitesse d’exécution et vitesse de compilation sont indépendantes
      Entre les deux, il existe une « zone de compromis » où l’on peut rendre un compilateur plus rapide sans perte de performance du binaire

    • Quelqu’un affirme que le domaine du jeu n’est pas un cas particulier

  • Jusqu’à présent, la meilleure vitesse de compilateur reste celle de TCC, l’œuvre de Fabrice Bellard
    Même sans multithreading ni optimisations complexes, il est incroyablement rapide
    J’utilise Clang pour les releases, mais les performances de génération de code de TCC ne sont pas mauvaises non plus

    • Je pense que Delphi offre une expressivité et une sécurité bien supérieures, tout en gardant une compilation très rapide

    • Le compilateur Go est lui aussi assez rapide

    • Je considérais que DMD, capable de compiler à la fois C et D, était le « gold standard »

    • Quelqu’un espère que TCC prendra en charge C23

    • Il n’existe pas de « vrai gold standard » unique
      vlang est lui aussi assez rapide pour terminer une recompilation en quelques secondes, et le compilateur Go est également extrêmement rapide
      Il existe aussi des techniques comme le cache de build pour éviter complètement les recompilations ; ce n’est donc l’apanage de personne

  • En construisant une application avec zig, j’ai été très satisfait des builds incrémentaux
    On peut construire un binaire statique unique utilisant diverses bibliothèques comme SQLite ou luau aussi vite qu’en Go
    Cela dit, le compilateur self-hosted contient encore pas mal de bugs
    Par exemple, SQLite nécessite encore llvm ; voir le ticket ici

  • Je me demande si Zig peut bien s’intégrer à des systèmes de build comme Bazel ou Buck2
    Les scripts de build Zig sont Turing-complets, donc j’ai peur que cela complique le caching et l’automatisation du build dans ce type de systèmes
    C’est la même raison pour laquelle, en Rust, on préfère les bibliothèques utilisables sans build.rs
    Je me demande si les bibliothèques Zig reposent elles aussi souvent sur des builds personnalisés

    • Les scripts de build de Zig sont totalement optionnels
      On peut compiler ou exécuter directement des fichiers source individuels sans build.zig
      On peut intégrer Zig dans n’importe quel workflow où GCC ou Clang interviennent
      À noter que Zig fonctionne aussi comme remplaçant de compilateur C
      Article lié

    • Exemple d’intégration entre Bazel et Zig avec rules_zig
      Le projet réel ZML l’utilise également
      Projet ZML

  • Je me demande comment se comparent la compilation et la génération de code de Zig face à TPDE
    On dit que c’est 10 à 20 fois plus rapide que LLVM -O0, mais il semble y avoir des limites

  • Je trouve la stratégie de Zig audacieuse
    Mais je me demande toujours s’il est vraiment judicieux de continuer à utiliser le backend LLVM
    LLVM reste compétitif sur la vitesse de compilation et le support des plateformes, mais personne ne le rattrape pour produire le meilleur code machine

    • Le backend LLVM n’est utilisé que pour les builds Release, et pour les builds debug, l’approche self-hosted est la valeur par défaut sur les plateformes prises en charge
      Comme les builds debug sont répétés de nombreuses fois pendant les tests, cette approche est plus rationnelle

    • Je ne partage pas cette obsession des performances du compilateur
      Au fond, c’est un compromis entre les passes d’optimisation — inlining, élimination du code mort, etc. — et le temps de compilation
      Un compilateur sans optimisation ne peut être qu’un peu plus rapide de façon linéaire ; pour aller au-delà, les optimisations coûtent forcément du temps

    • Une « excellente sortie assembleur » n’est pas vraiment un enjeu important
      Selon la loi de Proebsting, les progrès des compilateurs sont bien plus lents que l’augmentation des performances matérielles
      La conclusion est que des optimisations simples et rapides suffisent largement en pratique
      LLVM n’a rien d’absolu en matière d’optimisation, et atteint lui aussi vite ses limites face au temps de compilation

  • Je crée une bibliothèque Java qui encapsule une bibliothèque C via JNI, et comme le build de bibliothèques dynamiques par plateforme est trop pénible, j’envisage Zig pour du build multiplateforme

    • Pour un simple shim, il vaudrait mieux utiliser Panama et jextract sur les versions récentes de Java

    • Zig embarque les headers, les sources de libc et son propre LLVM, et la compilation croisée est vraiment très simple
      Au point qu’on n’a pratiquement plus rien à gérer

  • Quelqu’un demande pourquoi Ghostty ne se build pas actuellement avec le backend self-hosted x86_64

    • Le compilateur Zig plante à cause d’un bug
      C’est encore une technologie récente, donc c’est complexe, mais ce sera sans doute corrigé bientôt

    • La plupart des utilisateurs de Ghostty sont sur des plateformes aarch64