crustc : conversion complète de `rustc` en C
(github.com/FractalFir)crustcest une démo qui convertit l’intégralité derustc 1.98.0-nightly (c712ea946 2026-06-16)en 46 millions de lignes de code C, et sa compilation avecGCCetmakeproduit un compilateur Rust fonctionnel- L’outil sous-jacent,
cilly, est un backend de compilateur Rust qui compile Rust vers C, et ce dépôt constitue sa vitrine la plus marquante en montrant un compilateur se compilant lui-même cillyinterroge le compilateur C cible et la plateforme sur la disposition des types, leur taille, leur alignement, l’encodage des caractères, les formats d’entiers, etc., au moyen de programmes witness, afin de générer du code C accepté par un compilateur C donné- L’objectif principal est de rendre Rust utilisable sur du matériel ancien ou atypique qui n’a pas de support LLVM/GCC mais dispose d’un compilateur C, avec en plus une transparence réseau permettant de communiquer avec un compilateur C distant via TCP
- Le C généré actuellement cible ARM64 Linux, l’ISA de la station de travail de l’auteur, et l’ensemble de la toolchain
cillyn’est pas encore prêt pour un usage public ; des bugs liés à l’optimisation sont encore en cours d’investigation
Démo de conversion de rustc en C
crustcest un dépôt qui convertitrustc 1.98.0-nightly (c712ea946 2026-06-16)en 46 millions de lignes de code C- Ce code C peut être compilé avec
GCCetmake, et le résultat est un compilateur Rust fonctionnel - L’exemple d’exécution consiste à indiquer le chemin de la bibliothèque LLVM puis à lancer
./rustc/rustc --version, qui affiche la même versionrustc 1.98.0-nightly - Le compilateur Rust généré peut compiler du code et construire
core,allocetstd - En plus du code C, le dépôt inclut quelques wrappers LLVM en C++
- Rust utilise du C++ pour exposer certaines fonctionnalités de LLVM
- Ces wrappers dépendent de la version de LLVM et sont pénibles à construire séparément ; ils sont donc fournis précompilés
Rôle de cilly
crustcest une démo / un teaser du nouvel ensemble d’outils Rust-vers-C qu’estcilly- La toolchain complète
cillyvise à compiler le code Rust de l’utilisateur vers du C adapté à n’importe quelle cible - Ce dépôt a été conçu pour montrer
cillyen train de compiler le compilateur lui-même cillyest à la fois une bibliothèque Rust et un backend de compilateur Rust, autrement dit un plugin qui compile Rust vers C- L’auteur explique travailler depuis trois ans sur la compilation de Rust vers C et indique que
cillyest sa 14e tentative, après des essais publics commerustc_codegen_clret plusieurs essais privés
Comment le code est généré pour s’adapter au compilateur C
- La principale caractéristique de
cillyest qu’il s’adapte au compilateur C - Il peut générer des programmes witness qui vérifient ce qu’un compilateur et une plateforme donnés prennent en charge
- Un exemple est
_Thread_local int KEYWORD_TLS_SUPPORTED;, qui ne compile que si le compilateur C prend en charge_Thread_local
- Un exemple est
cillycherche à produire du code C qu’un compilateur C précis est capable d’accepter- Il interroge notamment la disposition des types, leur taille, leur alignement, l’encodage des caractères et les formats d’entiers
- Pour l’encodage des caractères, il vérifie s’il s’agit d’ASCII
- Pour les formats d’entiers, il vérifie s’il s’agit de two's complement
- Il utilise des solutions de repli quand c’est possible
- Il essaie d’éviter les hypothèses hors ANSI C et prévoit aussi des contournements pour des comportements liés aux standards C modernes, comme strict aliasing
- Dans de rares cas, des hypothèses raisonnables peuvent être nécessaires, comme un aller-retour
(void*)(uintptr_t)(ptr)- Ces hypothèses sont documentées et, quand c’est possible, accompagnées d’assertions comme
CHAR_BIT = 8
- Ces hypothèses sont documentées et, quand c’est possible, accompagnées d’assertions comme
Code C spécifique à la cible et contraintes ABI
- Le code C produit par
cillyest spécifique au compilateur- Le C généré par
cillypour Arm64 ne peut pas être exécuté tel quel sur riscv32 - En revanche, il est possible de générer séparément du C
cillypour riscv32
- Le C généré par
- Dans ce dépôt, le C généré pour
rustccible ARM64 Linux en raison de l’ISA de la station de travail de l’auteur - Le code produit par
cillyest globalement compatible ABI avec celui compilé par unrustcclassique - Sur certaines plateformes,
rustcchoisit des ABI impossibles à exprimer en C, ce qui empêche une compatibilité complète - Sur Arm64, il existe une contrainte liée au pointeur de retour de structure
sret- Sur la plupart des plateformes,
sretest transmis dans le même registre que le premier argument, ce qui permet de placer le pointeur de sortie en premier argument - Sur Arm64, le pointeur
sretest transmis dans un autre registre - L’auteur explique qu’il faudrait qu’un compilateur C natif choisisse return-by-sret pour les petites structures, ce qu’il ne fait pas pour celles de moins de 16 octets
- Sur la plupart des plateformes,
Support des cibles anciennes ou atypiques
- L’un des objectifs majeurs du projet est de permettre l’usage de Rust sur du matériel ancien ou atypique qui n’a pas de support LLVM/GCC mais dispose de C
- Quand un projet passe de Rust à C, ou qu’une alternative Rust à un projet C est créée, l’absence de support de telles cibles peut être présentée comme un point faible de Rust
cillyencapsulerustcet le compilateur C et convertit à la volée le code Rust en C- Du point de vue de l’utilisateur, cela ressemble surtout à une manière de définir quel compilateur C utiliser pour une cible donnée
- Un exemple de configuration utilise le triple
sdcc_z180-unknown-noneavec/usr/bin/sdccet les arguments-mz180,--std-c89,-c
Transparence réseau et compilateur C distant
cillyoffre une transparence réseau et peut communiquer avec un compilateur C via TCP- Si nécessaire, cette approche pourrait être étendue à des moyens de communication plus atypiques, comme l’UART
- Cette méthode vise à résoudre le paradoxe du bootstrap sur les plateformes qui n’ont pas de compilateur C croisé
- Il est possible de compiler et lancer un petit serveur C sur l’OS cible, puis d’exécuter
rustcsur une plateforme classique comme Linux pendant quecillycommunique via le réseau - L’auteur indique avoir réussi à compiler un petit programme Rust pour une VM x86 Plan 9 tout en exécutant
rustcsur ARM64 Linux- La sortie de l’environnement Plan 9 est
gnot osversion 2000 cputype 386 - L’exécution de
/tmp/hello_plan9afficheHello, world! - La sortie de
nmmontre le symbolerust_begin_unwind
- La sortie de l’environnement Plan 9 est
Fonction de génération de makefile
cillypeut, en option, insérer des marqueurs dans les fichiers objets et stocker l’IR dans un répertoire de cache- Il peut ensuite relire ces marqueurs pour répartir fonctions et globales selon leur emplacement de définition
- À partir de ces informations, il génère un répertoire contenant un makefile, de sorte qu’on puisse construire du Rust avec seulement un compilateur C et
make
Conditions de build et d’exécution
- Le système utilisé pour construire la démo est un ARM64 Linux basé sur Ubuntu
- La chaîne du noyau est
Linux spark-2773 6.17.0-1021-nvidia ... aarch64
- La chaîne du noyau est
- Les informations sur le compilateur C utilisé sont GCC 13.3.0 et Ubuntu LLD 18.1.3
- Pour la compilation, il faut la bonne bibliothèque LLVM ; le plus simple est d’installer cette nightly avec
rustup install nightly-2026-06-16 - La commande de build consiste à définir
LLVM_LIB_DIRvers le chemin delibLLVM.so.22.1-rust-1.98.0-nightlypuis à lancermake -j20 CFLAGSfonctionne, mais certains drapeaux peuvent ralentir la compilation- L’optimisation n’est pas recommandée
- La démo est encore brute et l’optimisation peut provoquer des problèmes
- À cette échelle, l’optimisation prend aussi beaucoup de temps
- Sans optimisation, le build se fait en quelques minutes sur la machine de l’auteur
- Les mesures sont
937.98s user,123.77s system,1352% cpu,1:18.48 total
- Les mesures sont
- Avec l’optimisation activée, l’essentiel du code passe rapidement, mais certains gros fichiers Rust peuvent bloquer longtemps
Tests et problèmes connus
- Le test de build consiste à définir
LD_LIBRARY_PATHavec la bibliothèque LLVM de la nightly et./rustc_driver, puis à lancer./rustc/rustc --version - Pour construire des programmes ordinaires, il faut compiler
std- Sans
std, on obtient l’erreurerror[E0463]: can't find crate for std - Pour construire la bibliothèque standard, il faut consulter
BUILDING_STD.md
- Sans
- Un bug connu fait que
crustcpeut planter lorsqu’il est exécuté depuis le répertoire où il a été construit, c’est-à-dire la racine du dépôt, à cause d’un problème étrange de normalisation de chemin - Depuis un autre emplacement, il fonctionne normalement
État de publication de cilly
cillyn’est pas encore prêt pour un usage public- L’auteur dit prévoir de le publier dès que possible
- Il cite comme raisons du retard son travail, un mémoire universitaire et une blessure à la main
- L’une des raisons pour lesquelles la toolchain complète
cillyn’a pas encore été publiée est qu’il traque encore des bugs liés à l’optimisation
1 commentaires
Avis sur Lobste.rs
Le fait que les chaînes de build C
configuretraditionnelles fonctionnent globalement de cette manière paraît assez étrange, mais il est compréhensible que ce compilateur, ou transpileur, suive ce schéma.« 14e tentative : cilly », quelle persévérance impressionnante ; j’envie une telle ténacité.
Elle fait 4,6 millions de lignes, soit presque exactement un ordre de grandeur de moins que ce projet. Le code C généré varie selon la cible, mais pas selon le compilateur.
Parmi les avantages de Zig figurent la prise en charge de nombreuses cibles de compilation croisée, une toolchain auto-hébergée et une dépendance optionnelle à LLVM ; la promesse de compiler Rust en C pour des plateformes rares ressemble aussi à un signal envoyé en direction de Zig.
crustc. Le compilateur converti ne prend en charge que les mêmes cibles de compilation que le compilateur d’origine.En revanche, il est possible de convertir d’autres projets Rust en C pour les exécuter et les compiler sur des cibles qui ne prennent en charge que C.
Cela dit, il ne faut pas en surestimer l’impact. C’est plutôt une solution un peu lourde à un problème très de niche.
rustcprend déjà en charge un large éventail de cibles, et cela devrait encore s’étendre via le backendgcc.Les outils de compilation croisée de Zig sont chouettes, mais ils relèvent surtout d’un gain de confort, en particulier pour la partie C qui est plus pénible que Zig ou Rust ; l’idée qu’ils prendraient en charge davantage de cibles est relativement moins importante.
Au final, la prise en charge des cibles par Zig et Rust est déjà assez similaire pour ne pas être un facteur décisif, et il existe des différences bien plus importantes entre les deux langages.
crustcn’est qu’un exemple de ce que peut fairecilly, une toolchain qui transforme Rust en C.L’ensemble de la toolchain
cillycompile le code Rust de l’utilisateur en C pour une cible arbitraire. Ce dépôt montre le compilateur en train de se compiler lui-même, parce que c’est probablement la démonstration la plus spectaculaire.rustcen C.