Rust to C: Bootstrapping the Compiler Without LLVM
By translating rustc into 46 million lines of C, the cilly backend opens new paths for legacy architectures.
Rust's biggest strength is its modern type system and safety guarantees, but its biggest deployment bottleneck is its hard dependency on LLVM. If you are targeting a niche, legacy, or highly specialized processor that lacks an LLVM backend, you are out of luck. You either write in C or you do not write at all.
While projects like C2Rust have spent years translating legacy C code into Rust, going the other direction has remained a difficult challenge. Enter crustc, a fully functional build of the Rust compiler (specifically rustc 1.98.0-nightly) translated entirely into 46 million lines of C.
This is not an academic stunt. It is a demonstration of cilly, a new compiler backend plugin designed to solve the bootstrapping paradox and bring Rust to platforms that only speak C. By targeting the lowest common denominator of systems programming, this approach changes how we think about Rust's portability.
The Mechanics of Cilly: The Witness Pattern
crustc is a showcase for cilly, a Rust compiler backend that has been through 14 iterations over three years. Instead of generating generic, hand-waving C that assumes a modern POSIX environment, cilly adapts dynamically to the target environment using "witness" programs.
Before generating code, the toolchain compiles small test programs on the target C compiler to probe its capabilities. For example, it checks for thread-local storage support by attempting to compile:
_Thread_local int KEYWORD_TLS_SUPPORTED;
If the target compiler rejects this, cilly falls back to alternative implementations. It queries type layouts, alignments, character encodings, and integer formats (such as two's complement) directly from the target. It targets ANSI C and includes workarounds for modern C features like strict aliasing.
This probing mechanism means the generated C code is highly compiler-specific. You cannot take the C code generated for an ARM64 Linux target and compile it on a RISC-V machine. However, you can run cilly on your host machine, target RISC-V, and generate C code tailored specifically for that target's compiler.
Solving the Bootstrapping Paradox
For developers working on alternative operating systems or obscure hardware, the biggest hurdle to adopting Rust is bootstrapping. To compile the Rust compiler, you need an existing Rust compiler. If your platform does not have one, you must cross-compile, which requires a working cross-compiler toolchain for your target. If LLVM does not support your target architecture, you are stuck.
cilly bypasses this entirely through network transparency. The backend can communicate with remote C compilers over TCP or even raw serial connections like UART.
flowchart TD
Host[Host Machine: Runs rustc + cilly]
Target[Target Machine: Runs C Server]
Host -- 1. Translates Rust to C --> Host
Host -- 2. Sends C code over TCP/UART --> Target
Target -- 3. Compiles C locally via GCC/Clang --> Target
Target -- 4. Runs native binary --> Target
In practice, a developer can run rustc on an ARM64 Linux workstation, let cilly translate the code to C, send it over the network to a lightweight C server running on an x86 Plan9 VM, and compile it there using the local C compiler. The resulting binary runs natively on the target, complete with Rust's standard library (std, core, and alloc).
The Catch: ABI Limits and LLVM Dependencies
While the prospect of compiling Rust to ANSI C is exciting, developers looking to adopt this toolchain need to understand the practical trade-offs.
First, the sheer scale of the output is massive. Translating rustc yields 46 million lines of C. This is not code you can easily debug, audit, or read. It is an intermediate representation designed for consumption by GCC or Clang, not humans.
Second, there are ABI compatibility limitations. On certain architectures like ARM64, Rust uses internal ABIs that cannot be cleanly represented in standard C. While cilly is mostly ABI-compatible, edge cases exist where the generated C code might not match the native Rust ABI calling conventions perfectly.
Finally, the crustc demo itself is not entirely free of LLVM. Because rustc relies heavily on LLVM for its internal query engine and optimization passes, the compiled crustc binary still needs to link against the LLVM shared library (libLLVM.so.22.1-rust-1.98.0-nightly). To run the compiled binary, you must point your dynamic linker to the LLVM library:
LD_LIBRARY_PATH=~/.rustup/toolchains/nightly-2026-06-16-aarch64-unknown-linux-gnu/lib:./rustc_driver ./rustc/rustc --version
For target platforms that cannot run LLVM at all, this means you cannot run the compiler itself on the target. However, you can still use cilly on a host machine to cross-compile your own Rust applications into standalone C code that runs on the target without any LLVM dependency.
The Verdict
cilly is a major milestone for the systems programming community. It provides a pragmatic, escape-hatch compiler backend for environments where LLVM is a non-starter.
If you are building standard web services, CLI tools, or targeting mainstream architectures like x86_64 or AArch64, you should stick to the standard LLVM-based compiler. The performance, optimization passes, and tooling integration of the official compiler remain unmatched.
But if you are targeting embedded systems, legacy enterprise platforms, or hobbyist operating systems, cilly is the most promising bridge to Rust we have seen yet. It proves that Rust's safety guarantees do not have to be locked behind LLVM's hardware support list.
Sources & further reading
- crustc: entirety of `rustc`, translated to C — github.com
- Live trending GitHub repositories — daily momentum ranking | Trendshift — trendshift.io
- A little C with your Rust - The Embedded Rust Book — docs.rust-embedded.org
Priya covers AI frameworks, developer productivity tooling, and the startup ecosystem across South and Southeast Asia, bringing a researcher's rigour and a practitioner's empathy to every story. She is deeply sceptical of benchmarks and asks hard questions so her readers don't have to.
Discussion 2
where are the tests for this massive c translation?
i'm curious to see how this affects cross platform development, especially for mobile - will we see rust on older android devices or ios versions without llvm support? 🤔