在 Chromium 中引入第三方 Rust crate:以 uwuify 为例的完整实战指南

原创2026-09-09 17:16:291,741 阅读
文章标签:文档教程

在 Chromium 中引入第三方 Rust crate:以 uwuify 为例的完整实战指南

本篇指南基于 comprehensive-rust 课程中 Chromium 方向的第三道练习(将 uwuify crate 引入 Chromium 并关闭其默认特性),帮助读者掌握在 Chromium 中引入、配置并依赖一个第三方 Rust crate 的完整流程。读完后,你将能够:正确执行 gnrt vendor 拉取 crate 及其传递依赖、理解为何必须关闭默认特性、配置 gnrt_config.toml 的分组与安全约束,并在 BUILD.gn 中以 rust_static_library 正确依赖 :lib 目标。

练习任务:引入 uwuify 并关闭默认特性

课程给出的核心练习是:把 [uwuify][crates.io/crates/uwuify] 加入 Chromium,并关闭该 crate 的默认特性(default features)。题目还有一个关键前提:假设该 crate 会被用于正式发布的(shipping)Chromium,但不会用来处理不可信输入。

# 练习目标(概念性伪代码)
# 在 Cargo.toml / BUILD.gn 中引入 uwuify,
# 并且显式关闭其 default features。

这里有两个必须理解的技术要点:

  • 为什么必须关闭默认特性:Rust crate 经常通过 default feature 开启额外的可选功能,而这些功能往往又会引入更多的传递依赖。若不加关闭,你实际拉进 Chromium 的 crate 集合会比预期大得多。题目明确要求"关闭默认特性",正是为了保证引入的依赖集合是受控、最小化的。
  • 为什么强调"不处理不可信输入":这关系到后续在 gnrt_config.toml 中给 crate 分组时的安全定级(safe / sandbox / test),详见下文"安全分组"小节。

补充:练习中还提示,可以顺手新建一个 rust_executable 目标来使用 uwuify,或跳到下一道"集成使用"练习。下一道练习(见 bringing-it-together.md)会真正让 Chromium 的 UI 字符串经过 uwuify 转换,从而构成 "Chrome for Pixies"。

依赖清单:一次正确引入应恰好拉取哪些 crate

根据练习文档给出的标准答案,当你正确关闭默认特性后,uwuify 及其传递依赖的完整集合应当恰好是以下 8 个 crate:

  • instant
  • lock_api
  • parking_lot
  • parking_lot_core
  • redox_syscall
  • scopeguard
  • smallvec
  • uwuify

这是一个非常有用的自检信号:如果你在 vendor 后发现实际下载的 crate 数量明显超过这 8 个,几乎可以肯定是你忘记关闭默认特性了——默认特性会连带引入一批额外的依赖。把"依赖数量是否符合预期"作为一个可验证的检查项,是引入任何第三方 crate 时都适用的好习惯。

完整引入流程:从下载到依赖

下面把练习中隐含的操作,补全为可落地的完整流程。这些步骤与 adding-third-party-crates 章节中的说明一致。

第 1 步:用 gnrt vendor 下载 crate 及依赖

负责下载 crate 并生成 BUILD.gn 规则的工具有 gnrt:

cd chromium/src
vpython3 tools/crates/run_gnrt.py -- vendor

这个 vendor 命令可能下载三类内容(见 downloading-crates.md):

  • 你要引入的 crate(本例是 uwuify);
  • 它的直接依赖与传递依赖(上节的 8 个 crate);
  • 因 cargo 需要解析完整依赖集合而带来的其他 crate 的新版本。

安全提示:虽然 gnrt 工具本身是 Chromium 源码的一部分,但运行 vendor 命令时,你实际上是在从 crates.io 下载并运行它的依赖。这是 Chromium 做出的一个明确安全决策,理解这一点有助于评估引入新 crate 的攻击面。

此外,Chromium 会为部分 crate 维护补丁,保存在 //third_party/rust/chromium_crates_io/patches。这些补丁会被自动重新应用;若补丁应用失败,可能需要人工介入。

第 2 步:在集中式 Cargo.toml 中声明依赖并关闭默认特性

Chromium 通过单个集中管理的 Cargo.toml 维护所有直接 crate 依赖,而不是每个 crate 各自为政:

[dependencies]
bitflags = "1"
cfg-if = "1"
cxx = "1"
# lots more...

作为任何 Cargo.toml,你都可以为依赖指定更多细节(见 configuring-cargo-toml.md)。对本题而言,关键就是指定 features——具体来说是关闭 uwuify 的默认特性。用 cargo 的写法表达即:

# 关闭默认特性(示意)
uwuify = { version = "0_2", default-features = false }

注意:上面的 version = "0_2" 取值来自课程对 Chromium 目录结构的约定(crate 目录名用 v0_2 表示 major/minor semver 版本),实际版本号请以你在 gnrt_config.toml / Cargo.toml 中 vendor 得到的真实版本为准。核心要点始终是 default-features = false。

第 3 步:在 gnrt_config.toml 中声明 Chromium 特有的配置

与 Cargo.toml 并列的 gnrt_config.toml 承载 Chromium 专属的 crate 处理扩展。引入新 crate 时,至少需要指定 group,其取值有明确的语义:

#   'safe': The library satisfies the rule-of-2 and can be used in any process.
#   'sandbox': The library does not satisfy the rule-of-2 and must be used in
#              a sandboxed process such as the renderer or a utility process.
#   'test': The library is only used in tests.

例如:

[crate.my-new-crate]
group = 'test' # only used in test code

把这三组语义与练习题的前提条件对应起来看,就理解了题目为何反复强调"shipping Chromium,但不处理不可信输入":

  • safe:满足 rule-of-2,可用于任意进程;
  • sandbox:不满足 rule-of-2,只能用于 renderer / utility 等沙箱进程;
  • test:仅用于测试代码。

对 uwuify 这类"用于正式产品但绝不接触不可信输入"的 crate,需要在审阅其源码后,依据它是否满足 rule-of-2 来判定应归入 safe 还是 sandbox。此外,若 crate 的源码布局特殊,你还可能需要在这个文件里额外指定其 LICENSE 文件的位置。

第 4 步:用 BUILD.gn 依赖该 crate 的 :lib 目标

vendor 完成、构建规则生成后,"依赖某个 crate"就变得很简单:找到你的 rust_static_library 目标,添加一个指向该 crate :lib 目标的 dep。

路径命名约定(见 depending-on-a-crate.md)为:

//third_party/rust/<crate 名>/v<major semver 版本>:lib

示例:

rust_static_library("my_rust_lib") {
  crate_root = "lib.rs"
  sources = [ "lib.rs" ]
  deps = [ "//third_party/rust/example_rust_crate/v1:lib" ]
}

对本题,uwuify 的依赖路径即为 //third_party/rust/uwuify/v0_2:lib(这一写法在下一道"集成"练习的提示中也被明确使用)。

第 5 步:把 crate 检入 Chromium 源码树

git status 应当显示两类变更(见 checking-in.md):

  • crate 本体代码,位于 //third_party/rust/chromium_crates_io;
  • 元数据(BUILD.gn 与 README.chromium),位于 //third_party/rust/<crate>/<version>。

还需要在后者目录下补一个 OWNERS 文件。把这些变更连同 Cargo.toml 与 gnrt_config.toml 的改动一起提交进 Chromium 仓库。

重点:必须使用 git add -f。否则 .gitignore 可能导致部分文件被跳过。另外,你可能会发现 presubmit 检查因"非包容性语言"而失败——因为 crate 数据常包含 git 分支名,而不少项目仍在使用非包容性术语。必要时可运行:

infra/update_inclusive_language_presubmit_exempt_dirs.sh > infra/inclusive_language_presubmit_exempt_dirs.txt
git add -p infra/inclusive_language_presubmit_exempt_dirs.txt # add whatever changes are yours

为什么"默认特性"是这类练习的关键考点

回到练习的本质:它表面是"加一个 crate",真正考查的是对 Rust 生态依赖特性的理解。Rust crate 之间依赖彼此非常容易,因此传递依赖常常很多(见 adding-third-party-crates.md 中的对比表:C++ 库通常传递依赖少、体积偏大;Rust crate 则构建系统统一为 Cargo.toml、体积小、但传递依赖多)。

在 Chromium 这种对依赖集合有严格审计与供应链管控的项目里,"关闭默认特性"不只是一个构建技巧,而是控制攻击面与依赖膨胀的第一道闸门。配合 gnrt_config.toml 的 group 安全分组、OWNERS 责任归属、以及对 crate 源码的安全性审阅(safety audit),共同构成了一套可审计、可追责的第三方引入规范。

小结与可验证检查清单

引入 uwuify(或任意第三方 crate)到 Chromium,可落地为以下清单,并附可验证依据:

  1. 执行 vendor:vpython3 tools/crates/run_gnrt.py -- vendor,拉取 crate、传递依赖及必要的新版本(downloading-crates.md)。
  2. 关闭默认特性:在集中式 Cargo.toml 中以 default-features = false 声明,确保最终依赖集合恰好为 instant、lock_api、parking_lot、parking_lot_core、redox_syscall、scopeguard、smallvec、uwuify 共 8 个 crate。若数量超过,说明默认特性未关闭。
  3. 声明分组:在 gnrt_config.toml 中按 rule-of-2 与使用场景指定 group(safe / sandbox / test)。
  4. 声明依赖:在 rust_static_library 的 deps 中加入 //third_party/rust/uwuify/v0_2:lib。
  5. 检入仓库:git add -f 提交 crate 代码与元数据,补齐 OWNERS,按需处理包容性语言的 presubmit 豁免。

完成本练习后,即可衔接下一道"集成使用"练习(bringing-it-together.md),把 uwuify 真正接进 Chromium 的本地化字符串处理,完成 "Chrome for Pixies" 的端到端实现。

登录后查看全文
comprehensive-rust