1 Punkte von GN⁺ 3 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • crustc ist eine Demo, die den gesamten rustc 1.98.0-nightly (c712ea946 2026-06-16) in 46 Millionen Zeilen C-Code übersetzt; mit GCC und make gebaut entsteht daraus ein funktionsfähiger Rust-Compiler
  • Das zugrunde liegende Tool cilly ist ein Rust-Compiler-Backend, das Rust nach C kompiliert; dieses Repository ist als besonders auffälliges Showcase dafür aufgebaut, dass der Compiler sich selbst kompiliert
  • cilly fragt über Witness-Programme Typ-Layouts, Größen, Ausrichtung, Zeichenkodierung, Integer-Formate usw. des Ziel-C-Compilers und der Plattform ab, um C-Code zu erzeugen, den ein bestimmter C-Compiler akzeptieren kann
  • Das Hauptziel ist, Rust auf alter oder ungewöhnlicher Hardware nutzbar zu machen, für die es keine LLVM-/GCC-Unterstützung, aber einen C-Compiler gibt; dazu gehört auch Netzwerktransparenz für die Kommunikation mit einem entfernten C-Compiler per TCP
  • Der derzeit erzeugte C-Code zielt auf die Workstation-ISA des Autors, ARM64 Linux; die komplette cilly-Toolchain ist noch nicht für die öffentliche Nutzung bereit, und Optimierungsfehler werden noch untersucht

Demo: rustc nach C übersetzt

  • crustc ist ein Repository, das rustc 1.98.0-nightly (c712ea946 2026-06-16) in 46 Millionen Zeilen C-Code übersetzt
  • Dieser C-Code kann mit GCC und make gebaut werden; das Ergebnis ist ein funktionsfähiger Rust-Compiler
  • Ein Ausführungsbeispiel setzt zunächst den Pfad zur LLVM-Bibliothek und führt dann ./rustc/rustc --version aus, was dieselbe Version rustc 1.98.0-nightly ausgibt
  • Der erzeugte Rust-Compiler kann Code kompilieren sowie core, alloc und std bauen
  • Neben C-Code enthält der Code auch einige C++-LLVM-Wrapper
    • Rust nutzt C++, um einige LLVM-Funktionen verfügbar zu machen
    • Diese Wrapper sind von der LLVM-Version abhängig und einzeln umständlich zu bauen, daher werden sie vorkompiliert bereitgestellt

Die Rolle von cilly

  • crustc ist eine Demo/ein Teaser für die neue Rust-to-C-Compiler-Toolchain cilly
  • Die vollständige cilly-Toolchain soll Rust-Code von Nutzern für beliebige Ziele nach C kompilieren
  • Dieses Repository ist dafür aufgebaut, zu zeigen, wie cilly den Compiler selbst kompiliert
  • cilly ist eine Rust-Bibliothek und ein Rust-Compiler-Backend, kompiliert Rust also als eine Art Plugin nach C
  • Der Autor sagt, er arbeite seit drei Jahren daran, Rust nach C zu kompilieren; nach öffentlichen Versuchen wie rustc_codegen_clr und mehreren nicht öffentlichen Versuchen sei cilly der 14. Versuch

Wie Code passend zum C-Compiler erzeugt wird

  • Ein zentrales Merkmal von cilly ist, dass es sich an den C-Compiler anpasst
  • Es kann Witness-Programme erzeugen, die prüfen, was ein bestimmter Compiler und eine Plattform unterstützen
    • Ein Beispiel ist _Thread_local int KEYWORD_TLS_SUPPORTED;; es kompiliert nur, wenn der jeweilige C-Compiler _Thread_local unterstützt
  • cilly versucht, C-Code zu erzeugen, den ein bestimmter C-Compiler akzeptieren kann
  • Typ-Layouts, Größen, Ausrichtung, Zeichenkodierung und Integer-Formate werden abgefragt
    • Bei der Zeichenkodierung wird geprüft, ob sie ASCII ist
    • Bei Integer-Formaten wird geprüft, ob sie Two's Complement verwenden
  • Wenn möglich, werden Fallbacks verwendet
  • Annahmen außerhalb von ANSI C sollen vermieden werden; auch für Verhalten moderner C-Standards wie strict aliasing gibt es Workarounds
  • In seltenen Fällen können vernünftige Annahmen nötig sein, etwa eine Roundtrip-Konvertierung wie (void*)(uintptr_t)(ptr)
    • Solche Annahmen werden dokumentiert, und wenn möglich werden Asserts wie CHAR_BIT = 8 hinzugefügt

Zielabhängiger C-Code und ABI-Einschränkungen

  • Der von cilly ausgegebene C-Code ist compiler-spezifisch
    • Für Arm64 erzeugter cilly-C-Code kann nicht unverändert auf riscv32 ausgeführt werden
    • Für riscv32 kann jedoch separat cilly-C-Code erzeugt werden
  • Der in diesem Repository erzeugte C-Code für rustc zielt wegen der ISA der Workstation des Autors auf ARM64 Linux
  • Von cilly erzeugter Code ist im Allgemeinen ABI-kompatibel mit Code, der von normalem rustc kompiliert wurde
  • Auf manchen Plattformen wählt rustc jedoch ABIs, die sich in C nicht ausdrücken lassen, sodass vollständige Kompatibilität schwierig ist
  • Auf Arm64 gibt es Einschränkungen wegen sret, dem Rückgabepointer für Strukturen
    • Auf den meisten Plattformen wird sret im selben Register wie das erste Argument übergeben, sodass der erste Parameter als Ausgabe-Pointer genutzt werden kann
    • Auf Arm64 wird der sret-Pointer in einem anderen Register übergeben
    • Laut Beschreibung müsste der native C-Compiler bei kleinen Strukturen return-by-sret wählen, tut dies bei kleinen Strukturen unter 16 Byte aber nicht

Unterstützung für alte oder ungewöhnliche Ziele

  • Das Hauptziel dieses Projekts ist, Rust auf alter oder ungewöhnlicher Hardware nutzbar zu machen, die keine LLVM-/GCC-Unterstützung hat, aber C unterstützt
  • Wenn ein Projekt von Rust nach C wechselt oder eine Rust-Alternative zu einem C-Projekt entsteht, kann fehlende Unterstützung für solche Ziele als Nachteil von Rust angeführt werden
  • cilly umhüllt rustc und den C-Compiler und wandelt Rust-Code on the fly nach C um
  • Aus Nutzersicht entspricht das in etwa dem Definieren eines C-Compilers für ein bestimmtes Ziel
  • Eine Beispielkonfiguration nutzt das Triple sdcc_z180-unknown-none sowie /usr/bin/sdcc, -mz180, --std-c89 und das Argument -c

Netzwerktransparenz und entfernte C-Compiler

  • cilly bietet Netzwerktransparenz und kann über TCP mit einem C-Compiler kommunizieren
  • Falls nötig, ließe sich das auf ungewöhnlichere Kommunikationswege wie UART erweitern
  • Dieser Ansatz soll das Bootstrap-Paradox für Plattformen lösen, für die es keinen C-Cross-Compiler gibt
  • Man kann auf dem Ziel-OS einen kleinen C-Server bauen und ausführen, auf einer üblichen Plattform wie Linux rustc starten und cilly über das Netzwerk kommunizieren lassen
  • Der Autor hat erfolgreich auf Arm64 Linux rustc ausgeführt und ein kleines Rust-Programm für eine x86-Plan-9-VM kompiliert
    • Die Ausgabe der Plan-9-Umgebung lautet gnot osversion 2000 cputype 386
    • Das Ergebnis von /tmp/hello_plan9 ist Hello, world!
    • Das Ergebnis von nm zeigt das Symbol rust_begin_unwind

Makefile-Erzeugung

  • cilly kann optional Marker in Objektdateien einfügen und IR in einem Cache-Verzeichnis speichern
  • Später kann es diese Marker lesen und Funktionen sowie Globals nach Definitionsort aufteilen
  • Auf Basis dieser Informationen erzeugt es ein Verzeichnis mit Makefile, sodass Rust nur mit einem C-Compiler und make gebaut werden kann

Build- und Ausführungsbedingungen

  • Das für den Demo-Build verwendete System ist ein Ubuntu-basiertes ARM64 Linux
    • Der Kernel-String lautet Linux spark-2773 6.17.0-1021-nvidia ... aarch64
  • Als C-Compiler wurden GCC 13.3.0 und Ubuntu LLD 18.1.3 verwendet
  • Zum Bauen wird die passende LLVM-Bibliothek benötigt; am einfachsten ist es, die entsprechende Nightly-Version mit rustup install nightly-2026-06-16 zu installieren
  • Der Build-Befehl setzt mit LLVM_LIB_DIR den Pfad zu libLLVM.so.22.1-rust-1.98.0-nightly und führt make -j20 aus
  • CFLAGS funktioniert, einige Flags können die Kompilierung jedoch verlangsamen
  • Optimierung wird nicht empfohlen
    • Die Demo ist noch roh, und Optimierung kann Probleme verursachen
    • In dieser Größenordnung dauert Optimierung sehr lange
  • Ohne Optimierung wird auf der Maschine des Autors innerhalb weniger Minuten gebaut
    • Die Messwerte sind 937.98s user, 123.77s system, 1352% cpu, 1:18.48 total
  • Mit eingeschalteter Optimierung läuft der Großteil des Codes schnell durch, kann aber bei einigen großen Rust-Dateien hängen bleiben

Tests und bekannte Probleme

  • Der Build-Test besteht darin, in LD_LIBRARY_PATH die nightly-LLVM-Bibliothek und ./rustc_driver anzugeben und ./rustc/rustc --version auszuführen
  • Um normale Programme zu bauen, muss std gebaut werden
    • Ohne std tritt der Fehler error[E0463]: can't find crate for std auf
    • Für den Build der Standardbibliothek soll BUILDING_STD.md herangezogen werden
  • Ein bekannter Bug ist, dass crustc wegen eines merkwürdigen Problems bei der Pfadnormalisierung abstürzen kann, wenn es aus dem Verzeichnis ausgeführt wird, in dem es gebaut wurde, also aus dem Repository-Root
  • Von anderen Orten aus funktioniert es normal

Veröffentlichungsstatus von cilly

  • cilly ist noch nicht für die öffentliche Nutzung bereit
  • Der Autor erklärt, er plane eine Veröffentlichung so bald wie möglich
  • Als Gründe für die Verzögerung nennt er Arbeit, eine Hochschularbeit und eine Handverletzung
  • Einer der Gründe, warum die vollständige cilly-Toolchain noch nicht veröffentlicht wurde, ist, dass noch Optimierungsfehler untersucht werden

1 Kommentare

 
GN⁺ 3 시간 전
Kommentare auf Lobste.rs
  • Interessant ist, dass ein Witness-Programm erzeugt wird, das prüft, was der gegebene Compiler und die Plattform unterstützen.
    Dass die traditionelle C-configure-Build-Chain im Großen und Ganzen so funktioniert, wirkt ziemlich seltsam, aber dass dieser Compiler bzw. Transpiler diesem Muster folgt, ist nachvollziehbar.
    „14. Versuch: cilly“ – das ist beeindruckende Beharrlichkeit, und um solche Ausdauer kann man neidisch werden.
  • Zum Vergleich: Es gibt eine vollständig nach C übersetzte Version des Zig-Compilers; sie ist Teil des normalen Verfahrens zum Build aus dem Quellcode.
    Mit 4,6 Millionen Zeilen ist sie fast genau um eine Größenordnung kleiner als dieses Projekt. Der erzeugte C-Code unterscheidet sich je nach Ziel, aber nicht je nach Compiler.
  • Ich bin kein Systemprogrammierer, frage mich aber, ob solche Projekte Einfluss darauf haben könnten, ob man Rust oder Zig einsetzt.
    Zu den Stärken von Zig gehören die Unterstützung vieler Cross-Compilation-Ziele, eine selbst gehostete Toolchain und eine optionale Abhängigkeit von LLVM; das Versprechen, Rust für seltene Plattformen nach C kompilieren zu können, wirkt auch wie ein Signal in Richtung Zig.
    • Allein durch die Nutzung von crustc ist das nicht der Fall. Denn der übersetzte Compiler unterstützt nur dieselben Compilation-Ziele wie der ursprüngliche Compiler.
      Es ist allerdings möglich, andere Rust-Projekte nach C zu übersetzen und sie auf Zielen auszuführen und zu kompilieren, die nur C unterstützen.
      Trotzdem sollte man den Effekt nicht überschätzen. Es ist eher eine etwas umständliche Lösung für ein sehr spezielles Problem. rustc unterstützt bereits viele Ziele, und über das gcc-Backend sollen es noch mehr werden.
      Zigs Cross-Compilation-Werkzeuge sind beeindruckend, erhöhen aber vor allem den Komfort – insbesondere bei C, das heikler ist als Zig oder Rust –, und bedeuten nur in geringerem Maße, dass mehr Ziele unterstützt werden.
      Letztlich ist die Zielunterstützung von Zig und Rust bereits ziemlich ähnlich und dürfte kaum der entscheidende Faktor sein; zwischen den beiden Sprachen gibt es weit wichtigere Unterschiede.
  • Cool ist es schon, aber ist man am Ende nicht durch die Fähigkeiten von LLVM begrenzt?
    • Ich sehe nicht, warum das so sein sollte. crustc ist nur ein Beispiel dafür, was cilly, eine Toolchain zur Übersetzung von Rust nach C, leisten kann.
      Die gesamte cilly-Toolchain kompiliert den Rust-Code des Nutzers zu C für beliebige Ziele. Dieses Repository zeigt den Compiler, der sich selbst kompiliert, weil das wohl die spektakulärste Demonstration ist.
  • Auch mrustc (https://github.com/thepowersgang/mrustc) ist einen Blick wert. Das ist ein in C++ geschriebener Rust-Compiler, der nach C transpiliert und den Code dann an GCC übergibt; damit kann auch rustc nach C übersetzt werden.