crustc: 整个rustc编译器,已翻译成C语言

Lobsters Hottest 工具

摘要

一个名为cilly的Rust到C编译器工具链已成功将整个rustc编译器翻译成4600万行C代码,生成了一个可以用GCC构建的功能性Rust编译器。该项目旨在通过生成可移植的C代码,使Rust能够在老旧/冷门硬件上运行。

<p><a href="https://lobste.rs/s/ryny2c/crustc_entirety_rustc_translated_c">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/07/03 00:17

FractalFir/crustc

来源:https://github.com/FractalFir/crustc

crustc - 将 rustc 1.98.0-nightly (c712ea946 2026-06-16) 转换为 4600 万行 C 代码

这是一个功能完备的 Rust 编译器,可以用 GCCmake 来构建。

# 我们需要提供 LLVM 的路径(`libLLVM.so.22.1-rust-1.98.0-nightly`)
# 我 *可以* 在项目中包含预构建的 LLVM,但我更倾向于不把随机二进制文件嵌入项目。
make -j20 LLVM_LIB_DIR=~/.rustup/toolchains/nightly-2026-06-16-aarch64-unknown-linux-gnu/lib

它只是 C 代码[1],编译后可以得到一个功能完整的 Rust 编译器。

# 工作正常 —— (将库路径指向 libLLVM.so.22.1-rust-1.98.0-nightly —— rustc 使用 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)

这个 Rust 编译器可以编译代码 —— 构建 coreallocstd —— 你想到的它都能做!

这是什么?

这是我新的 Rust 到 C 编译器工具链的演示/预告。 完整的 cilly 工具链可以将你自己的 Rust 代码编译为 C,且 支持任意目标平台。 这个仓库只是展示了编译器编译自身,我认为这是我能做的最炫酷的展示。

这是如何做到的?

过去三年里,我一直在研究如何将 Rust 编译成 C。我做过几次公开尝试,比如 rustc_codegen_clr,还有很多私下的尝试。

按照我的计数,这已经是第 14 次尝试了:cilly。它是一个用于生成 C 代码的 Rust 库,也是一个 Rust 编译器后端(即插件),允许你将 Rust 编译为 C。

cilly 的主要创新在于它 能适应 C 编译器

它可以生成“见证”程序,用来检查给定的编译器和平台支持哪些特性:

/* 当且仅当我们使用的 C 编译器支持 _Thread_local 时,这段代码才能编译。 */
_Thread_local int KEYWORD_TLS_SUPPORTED;

这意味着 Cilly 生成的 C 代码,会让你的特定、奇怪的“用于 Blorbo OS 的 Shminky C 编译器” 满意

/* 在某些 C 编译器上可以通过。 */
assert(sizeof(float) == sizeof(double));

所有类型布局、大小、对齐方式、字符编码(ASCII)以及整数格式(补码)都是 按需查询 的。

在可能的情况下,会有后备方案。

我尽最大努力不对 ANSI C[2] 之外的任何东西做假设 —— 包括针对“现代”C 标准中某些特性的规避方案,比如严格别名。

可惜的是,这意味着 cilly 的输出是针对特定编译器的(也就是说,你不能把为 Arm64 生成的 cilly C 代码在 riscv32 上运行,但可以专门为 riscv32 生成 cilly C 代码)。

这个构建版本(生成的 C 代码)是针对 ARM64 Linux 的,因为这是我工作站的 ISA

为什么要做这个?

主要目标是支持那些没有 LLVM/GCC 支持的老旧或稀有硬件。 世界上仍然 有一些 系统不支持 Rust,但支持 C

每当某个项目从 Rust 迁移到 C,或者某个 C 项目的 Rust 替代品被创建时, 对这些目标平台的支持 合理 地被提出作为 Rust 的一个缺点[3]。

这个项目的目标就是消除那个问题。

cilly 包装了 rustc 和一个 C 编译器,并实时地将 Rust 代码转换为 C。 从用户的角度来看,这简单到只需要定义用于某个目标平台的 C 编译器是什么。

  "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 为了简洁而被截断。
        }
     }
  }

网络透明性

cilly 是网络透明的,可以通过 TCP(如果需要,可能会扩展到像 UART 这样奇怪的东西)与 C 编译器通信。

这是针对引导悖论/没有 C 交叉编译器的平台的解决方案。

你在你的 Blorbo OS 上构建一个小型的 C 服务器,在像 Linux 这样的普通平台上运行 rustc,然后让 cilly 通过网络进行通信。

我已经成功用这个方式为 x86 Plan9 虚拟机编译了小型 Rust 程序,同时 rustc 运行在 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

生成 Makefile

cilly 可以可选地在目标文件中嵌入标记,并将其 IR 保存到缓存目录中。 然后它可以读取这些标记,根据定义位置拆分函数/全局变量,并生成一个包含 makefile 的目录 —— 以便让你用 C 编译器和 make 来构建 Rust。

ABI 兼容性

cilly 生成的代码 大部分 与普通 rustc 编译的代码 ABI 兼容。我说大部分,是因为在某些平台上(……比如 arm64),rustc 选择的 ABI 在 C 中无法表示[4]。

复现

先决条件

这个 Rust 编译器是在以下环境中构建的:

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

这是我使用的 C 编译器:

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

为了构建这个演示,你需要提供正确的 LLVM 库。最简单的方法是直接使用 rustc 附带的 LLVM:

rustup install nightly-2026-06-16

构建

安装好合适的 GCC(应该也可以使用更新版本的 GCC,但未测试)、正确的 LLVM 版本和 GNU make 后,运行:

# 我们需要提供 LLVM 的路径(`libLLVM.so.22.1-rust-1.98.0-nightly`)
# 我 *可以* 在项目中包含预构建的 LLVM,但我更倾向于不把随机二进制文件嵌入项目。
make -j20 LLVM_LIB_DIR=~/.rustup/toolchains/nightly-2026-06-16-aarch64-unknown-linux-gnu/lib
# CFLAGS 可以正常工作(警告:某些标志会减慢编译速度)
make -j20 CFLAGS=-g

然后……大功告成!

编译速度

我强烈建议不要启用优化:一方面因为它可能会破坏一些内容(这只是一个演示,而且……呃……还有点粗糙[5]),另一方面因为在这种规模下优化非常耗时。

不开启优化的情况下,我的机器在几分钟内就能完成构建:

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

如果开启优化,预计会在某些特别大的 Rust 文件上卡住。大多数代码会快速通过,然后在这些庞然大物上卡死。

测试构建

运行:

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

你应该会看到打印出的 rustc 版本。

要构建程序,你需要先构建 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`.

请阅读 BUILDING_STD.md 以了解如何构建。

已知 Bug

由于某些奇怪的路径规范化原因,crustc 在它被构建的目录(仓库根目录,crustc)中运行时可能会崩溃。在其他地方运行正常。

……

我也很困惑。

我能试试 cilly 吗?

现在不行。它还没有准备好公开使用。我会尽快发布它——但是:

  1. 我找到工作了(这意味着我不再在一台 G 键和 C 键坏了的笔记本电脑上写代码了,耶!)
  2. 我还在上大学(虽然我现在在放暑假,但论文不会自己写完)。
  3. 我把左手伸进了搅拌机。搅拌机赢了。(手指都还在,就是缝了几针)。细节我就不说了。

注释

1 - 准确来说,是 C 代码加上一些 C++ LLVM 封装。Rust 使用了一点 C++ 来暴露更多 LLVM 控制接口。这些封装是预编译的,因为它们与 LLVM 版本绑定,而且单独构建很麻烦。

2 - 极少数情况下,我不得不做出“合理的假设”,而这些假设可能会成为目标障碍。例如 (void*)(uintptr_t)(ptr) 往返。我会记录这些假设,并在可能的情况下添加断言(例如 CHAR_BIT = 8)。

3 - “Rust 不支持 Plan 9” 这个论点作为反对 Rust 的理由有多重要,取决于个人偏好,评估这个论点的任务留给读者完成。

4 - 问题在于结构体返回指针(sret)。在大多数平台上,它通过第一个参数相同的寄存器传递,因此我们可以通过让第一个参数是输出指针来强制使用返回-by-sret(输出指针)。但在 Arm64 上不行。在那里,sret 指针是通过不同的寄存器传递的,这意味着原生的 C 编译器必须 选择 为我们做返回-by-sret。但它不会为小的结构体(小于 16 字节?)这样做。烦人。

5 - 我正在追踪一些与优化相关的 Bug —— 这也是完整 cilly 工具链尚未发布的部分原因。

相似文章

Cpp2Rust: 从C++到安全Rust的自动翻译

Lobsters Hottest

Cpp2Rust 是一个开源工具,利用 clang 的 AST 和一个运行时库,自动将 C++ 代码转换为安全的 Rust 代码,支持安全和 unsafe 两种输出模式,实现安全的内存安全转换。

使用gccrs编译Linux内核的进展

Lobsters Hottest

gccrs项目致力于为GCC开发Rust前端,近期在编译Linux内核方面取得进展,解决了属性处理、名称解析和资源管理中的问题,并重新组织了开发里程碑。

Crubit,C++/Rust 双向互操作工具

Lobsters Hottest

Crubit 是 Google 的双向绑定生成器,它实现了 C++ 和 Rust 之间的无缝互操作,使两种语言能够相互调用对方的函数。文档包括示例、演练教程和支持功能的状态页面。

使用并行Claude团队构建C编译器

Anthropic Engineering

Anthropic研究员展示了如何使用16个并行Claude实例自主构建一个基于Rust的C编译器,该编译器能够编译Linux内核。文章详细介绍了这一多智能体自主编码实验的架构、成本和经验教训。