news 2026/9/11 18:13:44

Rust 编译器 rustc 编码规范与贡献指南:从 `./x fmt` 到 PR 审查的完整实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Rust 编译器 rustc 编码规范与贡献指南:从 `./x fmt` 到 PR 审查的完整实践

Rust 编译器 rustc 编码规范与贡献指南:从./x fmt到 PR 审查的完整实践

【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust

本文以 rustc-dev-guide 的 conventions.md 为核心,系统讲解 rustc 代码库的编码约定、格式化工具链(./x fmt、tidy 脚本)、正确性编码技巧、crates.io 依赖策略、PR 提交结构以及编译器特有命名约定。读完你将掌握为 rust-lang/rust 贡献代码时"怎么写、怎么验、怎么提交"的完整工作流,并了解这些规则在当前仓库中的具体落地实现。

一、整体脉络

rustc 是 Rust 语言的编译器本体,代码规模庞大、参与者众多,因此形成了一套既遵循 Rust 社区通用规范、又针对编译器开发场景量身定制的编码约定。这些约定主要覆盖四个维度:

  • 格式(Formatting):如何统一代码风格,如何被机器自动检查;
  • 正确性(Coding for correctness):如何写出不易出错、便于 review 的代码;
  • 依赖(crates.io 使用):编译器可以使用哪些第三方 crate、如何新增;
  • PR 结构与命名:如何组织提交让审查者轻松,以及编译器内部约定俗成的命名习惯。

文档原文见 src/doc/rustc-dev-guide/src/conventions.md,本文在其基础上结合仓库内 tidy 工具源码、rustfmt.toml 配置等实现细节展开。

二、格式化与 tidy 脚本

2.1 为什么不能直接cargo fmt

rustc 正在逐步向 Rust 标准代码风格 靠拢,但现阶段并不使用稳定版rustfmt,而是使用一个固定的(pinned)版本配合特殊配置运行。这意味着:

  • cargo fmt格式化本仓库可能产生与官方风格不同的结果,官方明确不推荐
  • 正确做法是使用./x fmt
  • 建议在每次提交前运行./x fmt,这能显著减少后续的合并冲突。

仓库根目录的 rustfmt.toml 展示了这份"特殊配置"的真实面貌:

style_edition = "2024" use_small_heuristics = "Max" merge_derives = false group_imports = "StdExternalCrate" imports_granularity = "Module" use_field_init_shorthand = true

可以看到它启用了style_edition = "2024"(新版风格版本)、imports_granularity = "Module"等不同于稳定版默认值的选项,这正是文档中"特殊配置"的落地点。

2.2 tidy 脚本如何检查格式

格式化由tidy 脚本统一把关,它会在你执行./x test时自动运行,也可以单独用./x fmt --check运行(只检查不修改)。

注意:格式与测试套件

tests/目录下的大部分 Rust 源文件不参与格式化,原因包括:对空白敏感(如 snapshot 测试)、注释位置敏感等。具体哪些文件被排除,见 rustfmt.toml 的ignore列表,例如/tests/ui//tests/pretty//tests/debuginfo//tests/incremental/等测试目录都在其中。

如果你希望在编辑器里使用"保存时自动格式化",pinned 版本的rustfmt二进制位于build/<target>/stage0/bin/rustfmt——即由构建系统生成的 stage0 工具链自带,无需依赖本机安装的 rustfmt。

从源码看,tidy 的样式检查逻辑位于 src/tools/tidy/src/style.rs,它实际执行的检查远不止格式化本身,包括(见该文件check_file_style函数):

  • 行长度超过 100 字符(COLS: usize = 100);
  • 非 CSS 文件中的 tab 字符;
  • 行尾空白(trailing whitespace);
  • CR 字符(\r);
  • TODO注释与todo!()宏;
  • 注释中句点后双空格;
  • 未解释的```ignoredoctest;
  • 文件行数超过 3000 行(LINES: usize = 3000)。

2.3 格式化 C++ 代码

rustc 编译器中含有少量 C++ 代码,用于与 LLVM 中尚无稳定 C API 的部分交互(集中在 compiler/rustc_llvm/llvm-wrapper 目录)。修改这些代码时使用:

./x test tidy --extra-checks cpp:fmt --bless

该命令使用pinned 版本的clang-format,避免依赖本地环境安装的版本差异。从 src/tools/tidy/src/extra_checks/mod.rs 的check_cpp_fmt实现可见:默认会遍历compiler/rustc_llvm/llvm-wrapper下的.h/.cpp文件,按根目录.clang-format配置执行--dry-run --Werror检查,加上--bless后则以-i模式直接改写文件。

2.4 格式化与 lint Python 代码

rust-lang/rust 仓库包含大量 Python 代码(构建脚本、CI 脚本、文档工具等),统一由ruff工具负责格式化和 lint:

# 格式化 Python 代码 ./x test tidy --extra-checks py:fmt --bless # 运行 Python lint ./x test tidy --extra-checks py:lint

同样使用 pinned 版本的ruff,避免依赖本地环境。从 extra_checks/mod.rs 的实现可以看到完整机制:

  • tidy 会在build/venv下创建虚拟环境(要求 Python ≥ 3.11,源码中MIN_PY_REV),并按 src/tools/tidy/config/requirements.txt 安装依赖;
  • ruff 的配置位于 src/tools/tidy/config/ruff.toml;
  • py:lint默认执行ruff check,带--bless时追加--fix自动修复;失败时会打印ruff check --diff的差异建议;
  • py:fmt默认执行ruff format --check,带--bless时直接格式化。

三、文件级格式约定

3.1 版权声明(Copyright notice)

过去 rustc 文件以版权与许可证声明开头,现在新文件如果采用标准许可(MIT OR Apache-2.0),应省略该声明。仓库中若仍残留旧版权通知,欢迎提交 PR 移除。对应地,tidy 在 style.rs 中专门检查包含 "Rust Project Developers" 字样的旧式版权行并报错。

3.2 行长度

  • 行最长100 字符,能控制在 80 以内更好;
  • 某些场景(尤其是测试)确实需要超长行时,可在文件顶部添加豁免注释:
// ignore-tidy-linelength

该指令与ignore-tidy-*系列指令由 tidy 的 directive 解析器统一处理(见 src/tools/tidy/src/style/directive.rs),整文件或单行均可豁免。

3.3 Tab 与空格

统一使用4 空格缩进,禁止 tab。

四、为正确性而编码

除了格式,文档还给出了一组提升代码质量、降低审查成本的编码建议,且多数建议在 tidy 中都有对应的自动化支撑。

4.1 优先穷尽匹配(Prefer exhaustive matches)

match中使用_通配固然方便,但代价是:当枚举新增变体时,落入_分支的代码可能得不到正确处理。写代码前先自问:如果这个枚举新增一个变体,它应该走_分支,还是需要专门处理?除非答案非常确定是前者,否则优先写穷尽匹配。同样的原则适用于if letwhile let——它们本质上只针对单一变体做测试。

4.2 用// TODO记录待办事项

在提交落地前,可以用// TODO注释标记需要回头处理的事:

fn do_something() { if something_else { unimplemented!(); // TODO write this } }

tidy 会对// TODO注释报错(见 style.rs 中"TODO is used for tasks that should be done before merging a PR"的检查),所以这段代码在 TODO 被修复或移除前无法合入。这种机制也被用来在 PR 的某个提交中故意留下一个 bug,并声明由后续提交修复:

if foo { return true; // TODO wrong, but will be fixed in a later commit }

如果只是想给代码库留一条说明性备注,请改用// FIXME(tidy 同样会检查并引导使用 FIXME 而非XXX)。

4.3 遵循周围代码的风格

复用已有的辅助函数(helpers),避免重复实现相同逻辑或重复校验——与现有代码保持一致,能显著降低审查者的认知负担。

4.4 避免重复的"真相来源"

试图在两个不同位置之间保持数据同步(duplicated sources of truth)是一种典型的代码坏味道(code smell),应尽量让数据只在一个地方维护,其他地方只读引用。

4.5 用类型强制不变量

在可行的情况下,让非法状态无法被表示(make invalid states unrepresentable),而不仅仅是在构造时做检查。例如用枚举/新类型替代布尔标志位,让编译器在类型层面就排除掉非法组合,而不是依赖运行时的assert

4.6 写有用的注释

注释应解释**"为什么"**而非"是什么"(write comments that saywhy, notwhat)。对于不直观的 bug 修复,值得在注释里详细说明来龙去脉——这类信息是后人排查问题的关键线索。

4.7 保留现有行为

修改代码时要考虑平台差异(platform differences)和错误处理路径,主动查找覆盖这些边界情况的既有测试,确保改动不破坏已承诺的行为。

4.8 小步前进

小步、可独立测试的方式推进工作,每次有意义的改动后都运行相关测试,这样一旦出错能第一时间定位到是哪一步引入的。

五、使用 crates.io 依赖

rustc 编译器支持引入部分来自 crates.io 的依赖,但并非随意添加。Rust Forge 制定了官方的新依赖审查政策(third-party crates vetting policy),并且tidy 工具维护着一张允许使用的 crate 清单(见 src/tools/tidy/src/deps.rs)。

要新增一个编译器尚未使用的依赖,必须先把该 crate 加入允许清单,否则 tidy 检查会失败。这是编译器供应链安全的重要防线,也意味着第三方依赖的引入是一个有明确流程、需要评审的决策,而非代码里的随手一行Cargo.toml。完整说明见 crates-io.md。

六、如何组织你的 PR

提交的组织方式直接影响审查体验,文档给出五条实战建议:

把"纯重构"独立成提交。例如重命名一个方法,应把该重命名连同所有调用点的改动放在单独一个提交里,避免与逻辑改动混在一起。

提交多一点通常更好。大型改动几乎总是应该拆成更小、可独立理解的步骤(atomic commits)。需要注意的反面情况是:如果某个提交先引入一种实现策略,后面又大幅改掉它(而非在它之上增量扩展),这种"来回折腾"会让人困惑。

保持每个提交都格式化。虽然只有 PR 的最终提交必须格式正确,但用./x fmt逐个提交单独格式化,既便于审查,也能减少噪音。

禁止 merge commits。除 bors(自动合入机器人)外,仓库历史不允许出现合并提交。遇到冲突应改用 rebase,例如:

git rebase --interactive rust-lang/main

(假设你的 remote 名为rust-lang。)

单个提交不必都能编译。官方不要求每个中间提交都构建成功——只需保证能在PR 级别做二分(bisect)定位问题即可。当然,如果能让每个提交单独构建通过,那永远是加分项。

七、命名约定

除了标准 Rust 命名规范外,编译器内部还有一套特有约定:

  • cx是 "context" 的常见缩写,常作为后缀使用。最典型的例子是tcx——Typing Context(类型上下文)的通用变量名,它是编译器类型检查阶段的核心数据结构;
  • 'tcx被用作 Typing Context 的生存期(lifetime)名称,贯穿整个类型系统代码;
  • 由于crate是关键字,当需要一个表示"与 crate 相关"的变量时,通常改写拼写为krate

关于tcx'tcx的详细语义,参见 ty.md。

八、实践小结

场景推荐命令/做法
格式化 Rust 代码./x fmt(每次提交前运行)
只检查不修改格式./x fmt --check
格式化 C++ 代码./x test tidy --extra-checks cpp:fmt --bless
格式化 Python 代码./x test tidy --extra-checks py:fmt --bless
lint Python 代码./x test tidy --extra-checks py:lint
编辑器 format-on-save使用build/<target>/stage0/bin/rustfmt
行长度≤ 100(理想 ≤ 80),豁免用// ignore-tidy-linelength
缩进4 空格,禁 tab
新文件版权声明标准许可(MIT OR Apache-2.0)下省略
待办标记合入前待办用// TODO(会被 tidy 拦截),代码库备注用// FIXME
新增 crates.io 依赖需先加入 src/tools/tidy/src/deps.rs 允许清单
PR 提交纯重构独立提交、每提交格式化、禁止 merge commits、冲突用 rebase

以上约定在仓库中均有对应实现可查:格式配置见 rustfmt.toml,tidy 样式检查见 src/tools/tidy/src/style.rs,Python/C++ 等额外检查见 src/tools/tidy/src/extra_checks/mod.rs。遵循这些约定,既是让 PR 顺利通过 CI 的前提,也是让 rustc 这个超大代码库在数十年演进中保持可维护性的基础。

【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 18:12:07

Prompt 事故档案(七):你以为你在和AI聊天,其实AI在审判你

&#xff08;本篇为「Prompt 事故档案」系列第&#xff08;七&#xff09;篇。没看过前几篇也没关系——这个系列的核心只有一句话&#xff1a;Prompt 是「自然语言编写的代码」&#xff0c;却在绝大多数团队里被允许「裸奔」上线&#xff0c;没有 Code Review、没有三审三校。…

作者头像 李华
网站建设 2026/9/11 18:11:04

【Rust入门知识点学与练】第2课:数据类型

知识点&#xff1a;Rust 的基本类型 下面展示一些 内联代码片。// 整数类型let a: i32 42; // 有符号32位整数let b: u64 100; // 无符号64位整数// 浮点类型let price: f64 9.9; // 64位浮点&#xff08;默认&#xff09;let rate: f32 0.85; // 32位…

作者头像 李华
网站建设 2026/9/11 18:08:40

基于Python+OpenCV+dlib的人脸识别考勤打卡系统实现与部署

简介&#xff1a;基于PythonOpenCVdlib库开发的人脸识别考勤打卡系统完整项目&#xff0c;面向计算机相关专业正在准备毕业设计、课程设计或期末大作业的学生&#xff0c;也适合需要人脸识别实战练习的开发者。项目实现人脸信息录入、人脸识别打卡、上下班时间设置、打卡日志导…

作者头像 李华
网站建设 2026/9/11 18:08:36

CSP-J2复赛‌每日1小时详细打卡表

这份适配四年级信奥选手的CSP-J2复赛每日1小时详细打卡表&#xff0c;完全贴合小学生的认知节奏&#xff0c;不占用过多校内学习时间&#xff0c;能稳步推进备赛进度。 一、基础筑牢阶段&#xff08;第1-4周&#xff0c;每天1小时&#xff09; 1、0-15分钟‌&#xff1a; C基…

作者头像 李华