稍微了解一下Rust的编译细节就会发现,Rust没有从零自己完整实现一个编译后端(codegen + 优化器 + 多架构支持),而是选择直接使用LLVM(默认),稍微正式地支持gcc也是最近才有的事儿。那么问题来了,Rust既然都这么能耐了,为什么不自己写一个编译器(编译后端)呢?看看隔壁家的go语言,从前到后全靠自己能力搞定。
其实这个问题在Rust早期设计阶段(2006–2010年Graydon Hoare个人项目到后来由Mozilla接手)就已经被反复讨论过。但之所以没有选择自研为主,主要有下面几个现实且当时非常合理的考量。
开发资源严重不足
Rust起步时只是Graydon Hoare的个人业余项目,后来Mozilla投入也只是一个小团队(最初几年核心开发者也就几个人到十几个人)。从零写一个能媲美现代工业级后端的代码生成器、优化器以及支持十几个架构(x86_64, aarch64, riscv, wasm, powerpc…)的编译工具链,工作量是几十人年到上百人年级别。
而LLVM当时已经存在了好几年(2003年启动),已经积累了大量优化和后端支持,直接用就能跳过绝大部分最苦最累的部分。
追求高性能代码输出是Rust的核心目标之一
Rust的定位是“匹及甚至取代C++的系统级语言”,这意味着生成的机器码性能必须接近或达到C/C++水平。
自己写后端在短期内达到LLVM已经拥有的优化水平(向量化、循环展开、inline、寄存器分配、profile-guided optimization等等)是极其不现实的。LLVM当时已经是Clang的后端,性能已经被苹果、Google等大厂反复打磨验证,Rust直接“站上巨人肩膀”能让语言早期版本就拥有足够的竞争力。
跨平台 / 多架构支持几乎免费获得
LLVM支持的目标平台三元组(target triple)非常丰富,而且持续有人维护(Apple、Google、ARM、RISC-V基金会等都在投)。用LLVM的话,只要LLVM支持,Rust基本就能跟上(加上一点glue code)。但如果Rust自己写后端,每增加一个新架构(比如后来加Riscv64、Loongarch64)就要自己从头实现代码生成逻辑及测试,成本就极其高昂。
编译器开发本身的自举(bootstrapping)难度
早期Rust编译器(rustc)是用OCaml写的,后来自己用Rust重写(自托管,self-host)。而如果后端也自己写,意味着你得先用很差的后端bootstrap出能用的编译器,再逐步替换优化——这条路极其痛苦。Rust语言复杂的类型系统也让自举编译后端上升了很多级别的难度。用LLVM就像有了一个“逃生舱”,可以让语言设计和前端快速迭代,不被后端拖垮。

那隔壁的Go为何能从前到后自己写?
Go的编译器后端本质上是Plan 9工具链的现代化移植和演化,所以他们团队能够做到两年内快速搭建出一个全自研的后端,而不用从零开始。而且Go语言本身核心诉求跟Rust有明显的差别,相比性能言,他们更优先看重编译速度、简化二进制依赖、可控的运行时等。总结对比下来如下表所示:
维度 | Rust(用LLVM) | Go(自研后端) |
|---|---|---|
设计目标 | 极致性能、零成本抽象、取代C++ | 编译超快、部署简单、Google内部大规模使用 |
性能优先级 | 非常高(必须打败C++) | 中等(够用就好,1.5–2× C也接受) |
团队资源(早期) | 个人 → 小团队 | Google内部大团队 |
优化复杂度接受度 | 需要工业级优化 | 可以接受简单优化 |
架构支持策略 | 尽可能多、跟进前沿 | 主流几个就够(早期amd64/arm为主) |
编译速度 | 可以牺牲(早期很慢,现在仍不算快) | 必须极快(设计核心目标之一) |
Go的后端故意写得非常简单(几乎没有复杂的全局优化),所以才能快速实现并保持极快的编译速度,在性能上能够做到覆盖大多数性能需求场景。但Rust如果也这么做,就违背了“高性能系统语言”的根本承诺。
难道没有想过或尝试过换掉LLVM?不得不说的是,Rust现在有一流的性能多多少少还是依赖了LLVM的优化能力。但是如果有核心竞争优势是建立在对外部工具依赖上的话,Rust长期的发展显然是重大风险的,备受诟病的编译慢就是受LLVM所累。所以实际是,Rust一方面在发展自己的编译器,增加可能的选择,另一方面也一直在尝试减轻对LLVM的依赖。
这里就不得不提及Cranelift项目了。2015–2016年左右Rust引入Cretonne(后来改名Cranelift)作为可选后端,由Rust实现,主要目标是debug模式输出,再加上极快编译(能比LLVM快几倍到十几倍)。
现在Cranelift已经是比较成熟的状态,主要用于wasm目标和-C debuginfo=0 -C opt-level=0的场景。 但release模式(-O2/-O3)Rust仍然默认用LLVM,因为性能差距仍然明显(尤其向量化、Profile-Guided Optimization等重度优化场景)。
同时,Rustc架构设计上支持可配置后端(pluggable backend),所以理论上未来可以逐渐把更多场景迁移到Cranelift或其他后端选择。
结论
Rust没自己写后端,不是因为“写不出来”,而是因为写出来性价比太低——时间、人员、优化水平、跨平台支持的综合成本,完全不如直接站在LLVM肩膀上,让社区把精力集中在语言本身的安全性、并发、类型系统和生态上。
这其实也是现代很多新语言(Swift、Julia、Carbon尝试、很多ML框架语言)的共同选择:
先用LLVM站稳脚跟,再看有没有必要/有足够资源自研后端。