首页
/ Rust 编译器 Cranelift 代码生成后端:rustc_codegen_cranelift 安装、构建与实战指南

Rust 编译器 Cranelift 代码生成后端:rustc_codegen_cranelift 安装、构建与实战指南

2026-09-06 20:17:01作者:咎岭娴Homer

本文基于仓库内 rustc_codegen_cranelift 官方 README 展开,系统讲解如何用 Cranelift 替代默认的 LLVM 后端为 Rust 项目做代码生成:包括通过 nightly 工具链组件安装、y.sh 构建系统与测试流程、cargo-clif 的即插即用用法、JIT 模式、平台支持矩阵,以及当前尚未支持的 SIMD 与 panic 展开(unwinding)等限制。读完本文,你可以独立完成后端的安装、源码构建、测试与替换使用,并理解其在 rustc 中的加载机制。

项目定位:LLVM 之外的第二条代码生成路径

rustc_codegen_cranelift(通常简称 cg_clif)的目标是为 Rust 编译器创建一个基于 Cranelift(Wasmtime 项目中的代码生成库)的替代代码生成后端。与传统 LLVM 后端相比,它的核心卖点是显著缩短 debug 模式下的编译时间——因为 LLVM 的优化管线是 rustc 编译耗时的主要部分之一,而 Cranelift 走的是"简单直接"的生成路径。

README 给出了一个明确的使用预期:如果你的项目没有用到"尚未支持"清单里的特性(见后文),它应当可以正常工作;否则建议向项目提交 issue。

从源码结构看,该后端在当前仓库中位于 compiler/rustc_codegen_cranelift/,其核心实现包含若干关键模块(见 src/lib.rs):

  • src/driver/:AOT 与 JIT 两种驱动入口;
  • src/abi/src/vtable.rssrc/unsize.rs:调用约定、vtable 与非规范大小(unsized)类型支持;
  • src/intrinsics/(含 simd.rsllvm_x86.rsllvm_aarch64.rs):内建函数实现;
  • src/debuginfo/:DWARF 调试信息与展开表输出;
  • src/optimize/peephole.rs:窥孔优化。

依赖方面,Cargo.toml 显示其使用 cranelift-codegen / cranelift-frontend / cranelift-module 等 0.134.0 版本 crate,且以 dylib 形式编译——这正是它作为"热插拔"后端被 rustc 动态加载的前提。

快速安装:Rustup nightly 组件方式

官方推荐的分发渠道是 nightly 构建。Cranelift 代码生成后端以组件形式随 nightly 发布,覆盖 Linux、macOS 与 x86_64 Windows。安装命令为:

rustup component add rustc-codegen-cranelift-preview --toolchain nightly

安装完成后,README 提供三种启用方式(三者任选其一):

  1. 临时环境变量 + unstable 标志(一次性使用):

    CARGO_PROFILE_DEV_CODEGEN_BACKEND=cranelift cargo +nightly build -Zcodegen-backend
    
  2. 写入 .cargo/config.toml(项目级固定配置):

    [unstable]
    codegen-backend = true
    
    [profile.dev]
    codegen-backend = "cranelift"
    
  3. 写入 Cargo.toml(把后端声明直接放进清单文件):

    # This line needs to come before anything else in Cargo.toml
    cargo-features = ["codegen-backend"]
    
    [profile.dev]
    codegen-backend = "cranelift"
    

    注意 cargo-features 这一行必须位于 Cargo.toml 的最前面,Cargo 对 unstable 特性声明位置有硬性要求。

预编译构建(Precompiled builds)

如果不想依赖 nightly 组件,也可以下载预编译版本:从上游仓库的 releases 页面(dev 标签)下载归档包,把其中的 dist 目录解压到任意位置即可使用。

如果希望直接用 cargo clif build 而不必每次写全路径,可以把解压后 dist 目录下的 bin 子目录加入 PATH(Linux/macOS 与 Windows 的 PATH 配置方法属于常规 shell 操作,此处从略)。

源码构建与测试:y.sh 构建系统

cg_clif 拥有独立的构建系统。在当前仓库中,入口脚本 y.sh 非常薄——它只是转交给构建系统 crate:

#!/bin/sh
set -e
echo "[BUILD] build system" 1>&2
exec cargo run --manifest-path build_system/Cargo.toml -- "$@"

test.sh 则等价于 ./y.sh test。构建系统的真实逻辑位于 build_system/main.rs,支持 preparebuildtestabi-cafebenchcheck-todo 六类子命令。

基本构建流程

按 README 的说明(以下假设 $cg_clif_dir 为后端仓库检出目录):

cd $cg_clif_dir
./y.sh build

运行测试套件:

./y.sh prepare # 只需要首次运行
./test.sh

更完整的构建系统文档在 build_system/usage.txt./y.sh 的帮助信息也会输出同样的内容)。其中值得注意的参数包括:

参数 作用
--sysroot none|clif|llvm 选择 sysroot 策略:none 不带标准库;clif 用 Cranelift 编译标准库;llvm 使用 rustc 预编译(LLVM 编译)的标准库
--keep-sysroot 不清理 sysroot 目录,源码未变时复用旧编译产物,适合未修改后端本身的迭代开发
--out-dir DIR / --download-dir DIR 指定构建与下载目录位置,默认是工作目录
--no-unstable-features 禁用尚未生产就绪的特性,包括 JIT 模式和内联汇编支持
--panic-unwind-support 启用 -Cpanic=unwind 时的展开支持,目前会拖累构建性能
--frozen 要求 Cargo.lock 与缓存保持最新
--skip-test TESTNAME 跳过指定测试,测试名格式与 config.txt 一致
--use-backend NAME 使用 rustc 内置的 Cranelift(或其他)后端,官方注明仅用于 Rust 项目 CI

构建系统的环境依赖(见同一文件的 REQUIREMENTS 部分):默认通过 rustup 安装正确版本的 nightly(当前仓库锁定的工具链为 rust-toolchain.toml 中的 nightly-2026-08-19,并要求 rust-srcrustc-devllvm-tools 组件);Git 用于下载测试仓库与打补丁;hyperfine 用于 ./y.sh bench 基准测试。若不想用 rustup,可手动安装对应 nightly 并用 CARGORUSTCRUSTDOC 环境变量指向相应可执行文件。

测试套件组成

测试项由 config.txt 配置,注释掉的行即跳过对应测试。从该文件可以读出三层测试结构:

  • no_sysroot 层build.mini_corebuild.exampleaot.mini_core_hello_world 等,不依赖标准库,验证核心构建链路;
  • base_sysroot 层aot.neonaot.issue-72793test.sysroot 等,使用基础标准库并覆盖若干回归问题(example/ 目录下有对应的测试源码,如 example/neon.rsexample/std_example.rs);
  • extended_sysroot 层test.rust-random/randtest.regextest.graviolatest.portable-simd,用真实第三方 crate 验证标准库之上的生态兼容性。

使用方式:cargo-clif、rustc-clif 与 JIT 模式

rustc_codegen_cranelift 可以作为现有项目的 cargo build / cargo run近替换(near-drop-in replacement)。构建完成后,在你的项目目录(即平时可以执行 cargo build 的目录)中运行:

$cg_clif_dir/dist/cargo-clif build

即可用 Cranelift 后端代替 LLVM 后端编译整个项目。更多用法细节记录在 docs/usage.md

  • Cargo 方式(推荐):上面的 cargo-clif build
  • Rustc 方式(次选):直接编译单个文件 $cg_clif_dir/dist/rustc-clif my_crate.rs
  • JIT 模式(高度实验性)$cg_clif_dir/dist/cargo-clif jit$cg_clif_dir/dist/rustc-clif -Cllvm-args=jit-mode -Cprefer-dynamic my_crate.rs。JIT 模式不产生可执行文件、直接执行代码,因此可能比 AOT 慢(缺少增量编译),且要求所有依赖都可用动态库形式获得。该模式在 src/config.rs 中通过 -Cllvm-argsjit-mode 开关解析,程序参数可经环境变量 CG_CLIF_JIT_ARGS 传入。
  • Shell 快捷函数:文档还提供了基于 JIT 的 jit / jit_calc shell 函数示例,可在终端里直接执行一行 Rust 表达式,适合快速实验。

后端在 rustc 中的加载机制

从源码结构看,后端以动态库形式被 rustc 加载:src/lib.rs 暴露了热插拔入口 __rustc_codegen_backend(),返回 CraneliftCodegenBackend 实例。该实例在 init() 中会做若干硬校验——LTO(Thin/Fat)不支持(直接 fatal),-Cinstrument-coverage 被判定为 LLVM 专属选项而拒绝;codegen_crate() 则根据配置分流到 driver::jit::run_jit(需编译时启用 jit feature)或 rustc_codegen_ssa::base::codegen_crate(driver::aot::AotDriver) 的常规 AOT 路径。此外 build_isa() 还负责把 rustc 的会话选项(优化级别、frame pointer、TLS 模型、target cpu 等)翻译成 Cranelift 的 ISA 配置,例如 Windows 目标会显式启用 enable_multi_ret_implicit_sret 以贴合 Rust ABI。

平台支持矩阵

README 给出的完整支持矩阵如下(✅ 完全支持并有测试;❓ 可能支持但未测试;❌ 完全不支持):

OS \ 架构 x86_64 AArch64 Riscv64 s390x (System-Z)
Linux ✅ ¹ ✅ ¹
FreeBSD ✅ ¹²
AIX ❌ ³ N/A N/A ❌ ³
其他 Unix
macOS N/A N/A
Windows N/A N/A
  • ¹ 这些目标不随 nightly rustup 组件分发,需要自行构建(y.sh 流程)。
  • ² FreeBSD 构建 cg_clif 需要设置 LD_STATIC_TLS_EXTRA=4096,且至少需要 FreeBSD 14。
  • ³ 不支持的原因是 XCOFF 对象文件格式不受支持。

尚未支持的特性与已知限制

README 的 "Not yet supported" 一节列出了两大空白,这也是选型前必须核对的清单:

  1. SIMDstd::simd(portable SIMD)可以完整工作,而 std::arch 仅部分支持。从源码看,src/intrinsics/simd.rssrc/intrinsics/llvm_*.rs 正在逐步补齐内建函数,example/neon.rs 则是 AArch64 NEON 路径的测试样例。
  2. panic 展开(Unwinding):默认情况下后端以 -Cpanic=abort 方式处理 panic;跨栈展开目前是实验性能力,且在 Windows 与 macOS 上不受支持。构建系统侧对应 --panic-unwind-support 开关(见前文参数表),Cargo.toml 中的 unwinding feature 也注明"因性能原因暂未并入 unstable-features"。

另外从源码可以确认两条硬性限制(README 未展开,属于实现层面的事实):LTO 完全不支持(init() 中 fatal),-Cinstrument-coverage 覆盖率插桩为 LLVM 专属。这些对"debug 模式快速编译"的主场景没有影响,但做发布版优化或覆盖率统计时仍需切回 LLVM 后端。

与 rustc 源码改动联动的构建/测试流程

如果你是在 Rust 主仓库中修改 rustc_codegen_cranelift(例如实现新的编译器内建函数,需要 rustc 侧配合),docs/rustc_testing.md 给出了完整的 8 步流程(以 $RustCheckoutDir 表示 Rust 仓库检出目录):

  1. cd $RustCheckoutDir
  2. 运行 python x.py setup 并选择 compiler(b)选项;
  3. 构建编译器与必要工具:python x.py build --stage=2 compiler library/std src/tools/rustdoc src/tools/rustfmt(可选:追加 src/tools/cargo 一并构建 cargo);
  4. 从 nightly 工具链复制 cargo:cp $(rustup +nightly which cargo) ./build/host/stage2/bin/cargo(每次重建 rust 仓库后需重做);
  5. 将新构建的 rustc 链接进工具链:rustup toolchain link stage2 ./build/host/stage2/
  6. 仅 Windows 需要编译构建系统:rustc +stage2 -O build_system/main.rs -o y.exe
  7. 之后所有 ./y.sh 命令都要加 rustup run stage2 前缀,让 cg_clif 使用你本地的 rustc 改动,例如 rustup run stage2 ./y.sh preparerustup run stage2 ./y.sh build,可选 rustup run stage2 ./y.sh test
  8. 用产出的 dist/cargo-clif 编译其他 Rust 程序验证,例如 $RustCheckoutDir/compiler/rustc_codegen_cranelift/dist/cargo-clif build --release

文档还提示:可以把 rust-analyzer 的 rustc.source 指向你的 Rust 工作区,让编辑器理解本地改动。

许可证

项目采用 Apache-2.0 与 MIT 双许可(见 LICENSE-APACHELICENSE-MIT)。按贡献约定,除非另有声明,有意提交并入项目的贡献代码将默认同时以这两种许可证授权。

小结

rustc_codegen_cranelift 在当前仓库中既是"独立可构建的构建系统工程"(y.sh + build_system/),又是随 nightly 分发的 rustc 可插拔组件。对于 debug 编译耗时敏感、且不依赖 SIMD 与跨栈展开的项目,cargo-clif build 提供了几乎零改动的替换路径;而 build_system/usage.txt 的参数集与 config.txt 的分层测试结构,则为深入理解其行为边界提供了直接入口。

登录后查看全文
热门项目推荐
相关项目推荐