```rustc:将整个 `rustc` 翻译为 C 语言```
crustc: entirety of `rustc`, translated to C

原始链接: https://github.com/FractalFir/crustc

**cilly** 是一个新的 Rust 编译器后端,它将 Rust 代码转换为 C 代码,从而使 Rust 能够在缺乏 LLVM 或 GCC 支持的硬件平台上进行开发。通过生成适应特定编译器环境的 C 代码(查询平台特定的类型布局、关键字支持和对齐方式),cilly 确保了与各种冷门系统的高度兼容性。 该项目作为一个 Rust 编译器插件运行,封装了 `rustc` 和选定的 C 编译器。它包含诸如网络透明编译等高级功能,允许用户通过将 C 编译步骤卸载到远程服务器来实现交叉编译。作者通过成功构建一个可运行的、自举的 Rust 编译器版本,证明了该项目的可行性。 尽管 cilly 目前仍是一个处于实验阶段的项目,但它旨在解决缺乏原生 Rust 支持的平台的“引导悖论”。通过生成与标准 `rustc` 输出在二进制接口(ABI)上基本兼容的 C 代码,它为将现代 Rust 引入传统上仅支持 C 的旧式或嵌入式硬件提供了一条实用途径。该项目目前正在完善中,以备未来公开发布。

Hacker News 最新 | 过往 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 rustc:整个 `rustc` 已被翻译为 C 语言 (github.com/fractalfir) 22 分,Philpax 发布于 32 分钟前 | 隐藏 | 过往 | 收藏 | 1 条评论 帮助 Tiberium 6 分钟前 [–] 我想知道性能表现如何,因为即使不是为了移植,这本身也很有趣 ;) 回复 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 加入 YC | 联系 搜索:
相关文章

原文

This is a functional Rust compiler you can build with GCC & make.

# We need to provide a path to LLVM(`libLLVM.so.22.1-rust-1.98.0-nightly`)
# I *could* include pre-built LLVM in the project, but I'd rather not embed random binaries in the project.
make -j20 LLVM_LIB_DIR=~/.rustup/toolchains/nightly-2026-06-16-aarch64-unknown-linux-gnu/lib

It is just C code [1], which, when compiled, gives you a functional Rust compiler.

# It works - (library path to point to libLLVM.so.22.1-rust-1.98.0-nightly - rustc uses llvm)
LD_LIBRARY_PATH=~/.rustup/toolchains/nightly-2026-06-16-aarch64-unknown-linux-gnu/lib:./rustc_driver ./rustc/rustc --version
rustc 1.98.0-nightly (c712ea946 2026-06-16)

That Rust compiler can compile code - build core, alloc, std - you name it!

This is a demo/teaser for my new Rust to C compiler toolchain. The full cilly toolchain compiles your own Rust to C for arbitrary targets. This repo just shows the compiler compiling itself, as I believe this is the flashiest showcase I could do.

For the past 3 years, I have been working on compiling Rust to C. I made a few public attempts, like rustc_codegen_clr, and a lot of private ones.

This is, by my count, the 14th attempt: cilly. It is a Rust library for generating C code and a Rust compiler backend (read: plugin) that allows you to compile Rust to C.

The main innovation behind cilly is that it adapts to C compilers.

It can generate "witness" programs, which check what a given compiler and platform support:

/* This compiles if and only if our C compiler supports _Thread_local. */
_Thread_local int KEYWORD_TLS_SUPPORTED;

This means Cilly will generate C code, which will make your specific, weird "Shminky C compiler for Blorbo OS" happy.

/* This will pass in some C compilers. */ 
assert(sizeof(float) == sizeof(double));

All type layouts, sizes, alignments, character encodings (ASCII), and integer formats (two's complement) are queried for.

With fallbacks, where possible.

I try my very best not to assume anything outside of ANSI C[2] - including workarounds for things in "modern" C standards, like strict aliasing.

Sadly, this means the output of cilly is compiler-specific (i.e., you can't take the cilly C generated for Arm64 and run it on riscv32, but you can generate cilly C specifically for riscv32).

This build of rustc (the generated C) is "targeting" ARM64 Linux because that is the ISA of my workstation.

The primary goal of this is support for old/obscure hardware with no LLVM/GCC support. There are still some systems out there that don't support Rust but support C.

Whenever some project moves from Rust to C, or a Rust alternative of a C project is made, support for those targets is validly raised as a downside of Rust [3].

The goal of this project is to remove that problem.

cilly wraps rustc and a C compiler and translates the Rust code to C on the fly. From the user perspective, this is as simple as defining what C compiler to use for a given target.

  "triple": [
    "sdcc_z180-unknown-none"
  ],
  "tool_def": {
    "kind": "local",
    "compile": {
      "base": {
        "executable": "/usr/bin/sdcc",
        "base_args": [
          "-mz180",
          "--std-c89",
          "-c"
        ],
        "input_arg_template": [
          "{input}"
        ],
        // JSON cut off for brevity. 
        }
     }
  }

cilly is network transparent, and can talk to C compilers over TCP (may be extended to weird things like UART if need be).

This is a solution to the bootstrap paradox / platforms without C cross compilers.

You build a small C server on your Blorbo OS, run rustc on some normal platform like Linux, and let cilly talk over the wire.

I have successfully used this to compile small Rust programs for x86 Plan9 VMs, while running rustc on Arm64 linux.

term% echo `{cat /dev/sysname} osversion `{cat /dev/osversion} cputype $cputype
gnot osversion 2000 cputype 386
term% /tmp/hello_plan9
Hello, world!
term% nm /tmp/hello_plan9 | grep rust_begin_unwind
    1020 T _RNvCshfEkAwg4zv6_7___rustc17rust_begin_unwind

cilly can optionally embed markers within its object files, and save its IR to a cache directory. It can then read those markers, split functions / globals by their definition location, and generate a directory with makefiles - to allow you to build Rust with a C compiler and make.

cilly generated code is mostly ABI compatible with normal rustc compiled code. I say mostly, because on some platforms(... like arm64) rustc choose an ABI not representable from C[4].

This rust compiler was built on:

uname -a
Linux spark-2773 6.17.0-1021-nvidia #21-Ubuntu SMP PREEMPT_DYNAMIC Wed May 27 19:14:05 UTC 2026 aarch64 aarch64 aarch64 GNU/Linux

This is the C compiler I used:

readelf -p .comment ./rustc/rustc                                                           
String dump of section '.comment':
  [     1]  GCC: (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
  [    2e]  Linker: Ubuntu LLD 18.1.3

In order to build the demo, you will need to provide it with the right LLVM libs. The easies way to do so is to just use the LLVM rustc ships:

rustup install nightly-2026-06-16

With the right GCC(more modern GCC versions should work too, untested), right LLVM version, and GNU make installed, run:

# We need to provide a path to LLVM(`libLLVM.so.22.1-rust-1.98.0-nightly`)
# I *could* include pre-built LLVM in the project, but I'd rather not embed random binaries in the project.
make -j20 LLVM_LIB_DIR=~/.rustup/toolchains/nightly-2026-06-16-aarch64-unknown-linux-gnu/lib
# CFLAGS work(CAVEAT: some flags will slow compilation down)
make -j20 CFLAGS=-g

And... voilà!

I strongly recommend not enabling optimizations: both because the may break stuff(this is just a demo, and it's... ee... rough around the edges[5]) AND because optimizations take time at this scale.

Without opts, my machine builds the project in a few minutes:

make -j20   937.98s user 123.77s system 1352% cpu 1:18.48 total

With opts, expect to choke on some specific larger rust files. You will blitz through most code, and then get stuck on those behemoths.

Run:

LD_LIBRARY_PATH=~/.rustup/toolchains/nightly-2026-06-16-aarch64-unknown-linux-gnu/lib:./rustc_driver ./rustc/rustc --version

You should see the rustc version printed.

For building programs, you will need to build std.

LD_LIBRARY_PATH=~/.rustup/toolchains/nightly-2026-06-16-aarch64-unknown-linux-gnu/lib:./rustc_driver ./rustc/rustc main.rs
error[E0463]: can't find crate for `std`
  |
  = note: the `aarch64-unknown-linux-gnu` target may not be installed
  = help: consider downloading the target with `rustup target add aarch64-unknown-linux-gnu`
  = help: consider building the standard library from source with `cargo build -Zbuild-std`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0463`.

Read BUILDING_STD.md for that.

For some weird path-canonicalization-reasons, crustc can crash when run in the directory it was built in(repo root, crustc). Works fine in other places.

...

I am confused too.

Nah, not yet. It is not ready for public consumption. I will release it as soon as possible - but

  1. I got a job(which means I no longer write code on a laptop with it's G & C keys broken, yay!)
  2. I got uni(well I am on summer break, but thesis-s don't tend to write themselves).
  3. I put my left hand in a blender. The blender won. (Still have all my fingers, just some stitches). I will not elaborate further.

1 - well, C code + some C++ LLVM wrappers. Rust uses a bit of C++ to expose some more LLVM knobs. They are shipped pre-compiled because they are LLVM-version-specific and a pain to build standalone.

2 - rarely, I have to make "reasonable assumptions" which would be goal stoppers. E.g. (void*)(uintptr_t)(ptr) roundtrips. I document those AND add asserts for them (CHAR_BIT = 8) if possible.

3 - the weight of "Rust does not support Plan 9" as an argument against Rust depends on personal preferences, and evaluating that argument is left as an exercise to the reader.

4 - The issue is the struct return pointer(sret). On most platforms, it is passed in the same reg as the first arg, so we can always force to return-by-sret(out pointer) by just having the first arg be the out pointer. Not on Arm64. There, sret pointer is passed in a different register, meaning the native C compiler has to chose to do a return-by-sret for us. Which it does not do for small structs(<16 bytes afaik). Annoying.

5 - I am chasing some optimization related bugs - part of the reason full cilly toolchain is not out.

联系我们 contact @ memedata.com