在 Firefox 中包含 Rust 代码

此页面说明如何添加、构建、链接和进行 Rust crate 的版本控制。

代码文档 说明了如何在 Firefox 中编写和使用 Rust 代码。该 测试文档 说明了如何在 Firefox 中测试和调试 Rust 代码。

将 Rust crate 链接到 libxul

您希望链接到 libxul 的 Rust crate 应列在 toolkit/library/rust/shared/Cargo.tomldependencies 部分中。您还必须向 toolkit/library/rust/shared/lib.rs 添加一个 extern crate 引用。这确保了 Rust 代码将被正确链接到 libxul 以及用于 gtest 的 libxul 副本。(即使 Rust 2018 大多不需要 extern crate 声明,这些声明也是必要的,因为 gkrust 设置非常规。)

添加 crate 后,执行 cargo update -p gkrust-shared 以更新 Cargo.lock 文件。在您更改 Cargo.toml 文件中的依赖项时,也需要执行此操作。如果您不这样做,您将收到一个构建错误,提示 **“错误:锁定文件 /home/njn/moz/mc3/Cargo.lock 需要更新,但传递了 –frozen 以阻止此操作”**。

默认情况下,mozilla-central 存储库中的所有 Cargo 包都是同一个 工作区 的一部分,并将共享存储库根目录中的 Cargo.lock 文件和 target 目录。您可以通过在顶级 Cargo.toml 文件中添加路径到 exclude 列表来更改此行为。如果您的包的开发工作流程包含一般 Firefox 开发人员或测试基础设施不需要的 dev-dependencies,您可能希望执行此操作。

实际的构建机制如下。构建系统生成一个特殊的“Rust 统一库”crate,将其编译为静态库(libgkrust.a),并将该库链接到 libxul 中,因此所有公共符号都可用于 C++ 代码。构建链接到动态库的静态库比直接构建动态库更容易,并且还可以避免一些关于 mozalloc 如何工作以及使 Rust 动态库路径稍微有点奇怪的微妙问题。

将 Rust crate 链接到其他内容

要将 Rust 代码链接到 libxul 以外的库,请创建一个包含 crate 的 Cargo.toml 文件和包含以下内容的 moz.build 文件的目录

RustLibrary('crate_name')

其中 crate_nameCargo.toml[package] 部分中的名称匹配。您可以参考 moz.build 文件Cargo.toml 文件,它们用于 libxul。

然后,您可以将 USE_LIBS += ['crate_name'] 添加到定义二进制文件的 moz.build 文件中,就像处理树中的任何其他库一样。

重要

您不能将 Rust crate 链接到最终将链接到 libxul 的中间库。构建系统强制执行只能将单个 RustLibrary 链接到二进制文件。如果您需要执行此操作,则必须添加一个 RustLibrary 以链接到链接中间库的任何独立二进制文件,并将 Rust crate 添加到 libxul 依赖项中,如 将 Rust crate 链接到 libxul 中所示。

条件编译

编辑 tool/library/rust/gkrust-features.mozbuild 以将构建标志公开为 Cargo 特性。

独立 Rust 程序

也可以构建独立的 Rust 程序。首先,将 Rust 程序(包括 Cargo.toml 文件和 src 目录)放在其自己的目录中,并在同一目录中添加一个空的 moz.build 文件。

然后,如果独立 Rust 程序必须在编译目标上运行(例如,因为它与 Firefox 一起发布),则向 moz.build 文件添加以下规则

RUST_PROGRAMS = ['prog_name']

其中 prog_nameCargo.toml 中指定的可执行文件的名称(并且可能也与目录的名称匹配)。

否则,如果独立 Rust 程序必须在编译主机上运行(例如,因为它用于构建 Firefox 但不与 Firefox 一起发布),则执行相同的操作,但使用 HOST_RUST_PROGRAMS 而不是 RUST_PROGRAMS

我应该把我的 crate 放在哪里?

如果您的 crate 的规范位置是 mozilla-central,您可以将其放在相应目录中相关代码的旁边。

如果您的 crate 从另一个存储库镜像到 mozilla-central,并且不会在 mozilla-central 中积极开发,您可以简单地将其列为具有版本号的 crates.io 样式依赖项,并将其版本控制到 third_party/rust 目录中。

如果您的 crate 从另一个存储库镜像到 mozilla-central,但将在两个位置积极开发,则应向 dev-builds 邮件列表发送邮件,以开始讨论如何满足您的需求。

第三方 crate 依赖项

树内 Rust crate 的第三方依赖项会被版本控制到 mozilla-central 的 third_party/rust 目录中。这意味着每个第三方 crate 代码的副本都会提交到 mozilla-central。因此,构建 Firefox 不涉及下载任何第三方 crate。

如果您添加对新 crate 的依赖项,则必须运行 mach vendor rust 以将依赖项版本控制到该目录中。(请注意,mach vendor rust 在 Windows 上可能不如 在其他平台上那样有效。)

在检查第三方代码是否适合包含到 mozilla-central 时,请记住以下几点。

  • mach vendor rust 将检查所有 crate 的许可证是否合适。

  • mach vendor rust 将运行 cargo vet 以确保 crate 已被审核。如果没有,您将必须使用 mach cargo vet 对其进行审核,以检查代码是否合理(尤其是 unsafe 代码)以及是否存在合理的测试。所有版本控制的 crate 都必须经过审核。

  • 第三方 crate 测试不会运行,这意味着大型测试装置会使 mozilla-central 膨胀。考虑与上游合作,使用 [package] exclude = ... 标记这些测试装置,如 此处 所述。

  • 如果您指定对分支的依赖项,请将其固定到特定版本,否则,其他人将在每次分支更新时运行 ./mach vendor rust 时获得意外的更改。有关此问题已解决的情况,请参阅 错误 1612619

  • 除此之外,没有正式的签核程序,但将来可能会添加。

请注意,所有依赖项都将被版本控制,即使由于禁用了特性而未使用的依赖项也是如此。可能有多个版本的 crate 最终会被版本控制到 mozilla-central 中。

修补第三方 crate

有时您可能希望暂时修补第三方 crate,用于本地构建或 try 推送。

为此,首先在顶级 Cargo.toml[patch.crates-io] 部分添加一个条目,该条目指向 third_party 中的 crate。例如

bitflags = { path = "third_party/rust/bitflags" }

接下来,运行 cargo update -p $CRATE_NAME --precise $VERSION,其中 $CRATE_NAME 是已修补 crate 的名称,$VERSION 是其版本号。这将更新 Cargo.lock 文件。

然后,对 crate 进行本地更改。

最后,确保您不会意外地将对 crate 或 Cargo.lock 文件的更改合并到代码库中。

有关涉及第三方板条箱的更复杂工作流程的示例,请参阅mp4parse-rust/README.md。它描述了一个托管在 GitHub 上的板条箱的工作流程,以及通过 GitHub 拉取请求进行更改的工作流程,但所有拉取请求都必须在合并到 mozilla-central 之前进行测试。