Vaccari's Code

crustc: complete `rustc` in C

7/6/2026

In the world of software development, portability and support for different architectures are topics that frequently generate heated debates. Rust, with its promise of safety and performance, has been gaining ground, but a recurring criticism is its dependence on modern toolchains and, in particular, LLVM. What if I told you that there's now a Rust compiler that can be built with GCC and make, and that is, surprisingly, written entirely in C?

crustc: The Rust Compiler in C

That's right, you didn't misread. crustc is the entirety of rustc — the official Rust compiler — translated into C. It's not a rewrite, but a direct translation of the source code. The result? A functional Rust compiler that you can compile with classic tools like GCC and make. It has been demonstrated compiling essential Rust libraries like core, alloc, and std, and the resulting crustc is a rustc 1.98.0-nightly version.

The idea of having rustc in C is fascinating in itself, but crustc is, in fact, a showcase, a "teaser" for a larger, more ambitious tool: the cilly toolchain. The cilly project is the culmination of three years of work, several public and private attempts, and represents the 14th iteration of an effort to compile Rust to C.

cilly: The Tool Behind the Magic

cilly is a Rust library for C code generation and a backend (or plugin) for the Rust compiler, which allows compiling your Rust code to C for arbitrary targets. The big insight behind cilly is its ability to adapt to existing C compilers. Instead of making assumptions, it generates "witness programs" that verify what a given compiler and platform actually support. This includes everything from the presence of _Thread_local to the sizeof basic types like float and double.

This approach ensures that cilly can generate C code that works even with more exotic C compilers or those specific to unusual operating systems. It queries type layouts, sizes, alignments, character encodings (ASCII), and integer formats (two's complement), with fallbacks when possible. The goal is to assume nothing beyond ANSI C, including implementing workarounds for "modern" C standard functionalities like strict aliasing.

An important caveat is that the C code generated by cilly is specific to the compiler and platform. That is, C generated for Arm64 will not run on riscv32; however, cilly can generate C code specifically for riscv32. The crustc serving as a demo, for example, was generated for Arm64 Linux, the developer's workstation architecture, using GCC 13.3.0 and LLD 18.1.3.

The main goal of cilly is to extend Rust's support to old or obscure hardware that lacks LLVM or GCC support, but still runs C. This addresses a legitimate criticism of Rust: the difficulty of porting projects to certain targets where C is still king.

How cilly Works in Practice

From the user's perspective, cilly integrates with rustc and a C compiler, translating Rust code to C "on the fly". Configuration is done via a JSON file where you define the C compiler to be used for a given target, specifying the executable, base arguments, and other details.

An ingenious feature is cilly's network transparency. It can communicate with C compilers via TCP (and potentially UART), which is an elegant solution for the "bootstrap paradox" on platforms without C cross-compilers. You can run a small C server on your exotic operating system (e.g., Plan9), and cilly on your Arm64 Linux communicates with it to compile Rust. This has already been successfully demonstrated, compiling small Rust programs for x86 Plan9 VMs from an Arm64 Linux.

For greater flexibility, cilly can optionally embed markers in its object files and save its Intermediate Representation (IR) to a cache directory. From these markers, it can generate a directory with makefiles, allowing you to build your Rust project with a C compiler and make, in the most traditional way possible.

In terms of ABI compatibility, the code generated by cilly is "mostly" compatible with code compiled by the standard rustc. I say "mostly" because, on some platforms (like Arm64), rustc chooses an ABI that is not directly representable from C.

Why This Matters?

The crustc initiative and, more broadly, the cilly toolchain, represent a significant advancement for the Rust community. By allowing Rust to be compiled to C, the project removes a considerable barrier to the language's adoption in scenarios where modern toolchain support is limited or non-existent. This means developers can now consider Rust for legacy embedded systems, specialized hardware, or obscure platforms that were previously out of reach. It's a bold step to make Rust even more ubiquitous, proving that the language can be as adaptable and "down-to-earth" as C, without sacrificing its safety and performance advantages.

Sources

← all posts · listen to the episode →