关注了就能看到更多这么棒的文章哦~
How to write Rust in the kernel: part 1
By Daroc Alden
June 20, 2025
Rust in the kernel
Gemini flash translation
https://lwn.net/Articles/1024202/
Linux 内核中 Rust 代码的数量正在稳步增长。随着 Rust 代码变得越来越普遍,维护者们可能希望了解如何阅读、审查和测试与其专业领域相关的 Rust 代码。正如内核 C 代码与用户空间 C 代码有所不同一样,内核 Rust 代码也与用户空间 Rust 代码有些许不同。这一事实使得 Rust 详尽的文档的作用不如预期,并意味着具有用户空间经验的潜在贡献者将需要一些额外的指导。本文是系列文章的第一部分,旨在帮助现有内核贡献者熟悉 Rust,并帮助现有 Rust 程序员了解内核与典型 Rust 项目的不同之处。
为了为本系列其余文章奠定基础,本文将对 Rust 工具的安装和配置进行高层次概述,并解释 Rust 如何融入内核现有的构建系统。未来的文章将涵盖 Rust 如何融入内核的维护模式,用 Rust 编写驱动程序需要考虑什么,Rust 接口与内核其余部分的设计,以及审查 Rust 代码时需要注意的具体事项。
前提准备
尽管 GCC 上对 Rust 的支持正在迎头赶上,并且 `rustc_codegen_gcc` 代码生成后端现在能够编译内核的 Rust 组件,但 Rust for Linux 项目目前仅支持使用纯粹的 `rustc` 进行构建。由于 `rustc` 使用 LLVM,该项目还建议在处理 Rust 代码时,整个内核都使用 Clang 进行构建(尽管在 C 侧使用 GCC 而在 Rust 侧使用 LLVM 也是可行的)。构建过程还需要 bindgen 来生成 C/Rust API 绑定,以及一份 Rust 标准库的副本,以便能够使用内核所需的标志进行构建。因此,以推荐方式构建内核至少需要 Clang、lld、LLVM、Rust 编译器、Rust 标准库的源代码形式以及 bindgen。
许多 Linux 发行版都提供了这些工具足够新的版本;Rust 快速启动文档提供了针对不同发行版的安装说明。所需的 `rustc` 最低版本是 2024 年 5 月发布的 1.78.0。Rust for Linux 项目已承诺不会不必要地提高最低要求版本。根据 Miguel Ojeda 的说法,目前的非正式计划是,一旦 Debian stable 中的版本赶上目前的最低要求(很可能在今年晚些时候),就将沿用该版本。
Rust 开发者可能还应该安装 Clippy(Rust 的代码 Lint 工具),rustdoc(Rust 的文档构建工具)和 rust-analyzer(Rust 的 语言服务器),但这些并非严格必需。Rust for Linux 项目力求代码没有 Lint 警告,因此引入新警告的补丁可能会被维护者不看好。在内核源码根目录运行 `make rustavailable` 命令会检查所需的工具是否安装了兼容的版本。实际上,这里讨论的所有命令都应该在仓库的根目录运行。`make rust-analyzer` 命令将为 rust-analyzer 设置配置文件,使其能够与支持语言服务器的编辑器(如 Emacs 或 Vim)无缝协作。
Rust 代码由两个独立的内核配置值控制。当兼容的工具可用时,`CONFIG_RUST_IS_AVAILABLE` 会自动设置;而 `CONFIG_RUST`(可在“General Setup → Rust support”下找到)则控制是否实际构建任何 Rust 代码,并依赖于第一个选项。与绝大多数用户空间 Rust 项目不同,内核不使用 Cargo(Rust 的包管理器和构建工具)。相反,内核的 makefile 会直接调用 Rust 编译器,其方式与调用 C 编译器相同。因此,只需将对象添加到正确的 make 目标即可构建 Rust 模块:
obj-$(CONFIG_RUST) += object_name.o
由 `CONFIG_RUST` 直接启用的代码主要是 C 和 Rust 之间的支持代码和绑定,因此它并不能代表大多数 Rust 驱动代码的实际样子。启用 Rust 示例代码(在“Kernel hacking → Sample kernel code → Rust samples”下)可能会提供更具代表性的示例。
Testing
Rust 的测试和 Lint 工具也已集成到内核现有的构建系统中。要运行 Clippy,请在 `make` 调用中添加 `CLIPPY=1`;这将执行一次特殊的内核构建,启用调试选项,使其不适合生产使用,因此应谨慎操作。`make rustdoc` 将构建一份 Rust 文档的本地副本,同时也会检查一些文档警告,例如缺少文档注释或格式错误的文档内部链接。测试可以使用 kunit.py 运行,它是内核的白盒单元测试工具。该工具确实需要额外的参数来设置 Rust 构建所需的配置变量:
./tools/testing/kunit/kunit.py run --make_options LLVM=1 \ --kconfig_add CONFIG_RUST=y --arch=<host architecture>
实际定位失败的测试用例可能会让熟悉 KUnit 测试的人感到困惑。与内核的 C 代码通常将 KUnit 测试写在单独文件中不同,Rust 代码的测试往往与其测试的代码位于同一文件中。惯例是使用独立的 Rust 模块 来将测试代码与主命名空间隔离(并启用条件编译,这样它就不会包含在发布内核中)。这个模块通常(富有想象力地)被称为“test”,并且必须使用 `#[kunit_tests(test_name)]` 宏进行注解。该宏实现在 rust/macros/kunit.rs 中;它会遍历被注解的模块,查找用 `#[test]` 标记的函数,并设置 KUnit 自动识别测试用例所需的 C 声明。
然而,Rust 还有另一种测试,它不直接对应于 C 单元测试。“Doctest”(文档测试)是嵌入在函数文档中的测试,通常展示了如何使用该函数。因为它是一个真实的测试,所以 Doctest 可以被信赖地保持最新,而仅仅是示例则可能无法做到。此外,Doctest 会作为自动生成的 Rust API 文档的一部分进行渲染。Doctest 也会作为 KUnit 测试套件的一部分运行,但必须明确启用(在“Kernel hacking → Rust hacking → Doctests for the `kernel` crate”下)。
一个包含 Doctest 的函数示例(从 Rust 字符串辅助函数中稍作修改)如下所示:
/// Strip a prefix from `self`. Delegates to [`slice::strip_prefix`].////// # Examples////// ```/// # use kernel::b_str;/// assert_eq!(/// Some(b_str!("bar")),/// b_str!("foobar").strip_prefix(b_str!("foo"))/// );/// assert_eq!(/// None,/// b_str!("foobar").strip_prefix(b_str!("bar"))/// );/// assert_eq!(/// Some(b_str!("foobar")),/// b_str!("foobar").strip_prefix(b_str!("")));/// assert_eq!(/// Some(b_str!("")),/// b_str!("foobar").strip_prefix(b_str!("foobar"))/// );/// ```pubfnstrip_prefix(&self, pattern: implAsRef<Self>) -> Option<&BStr>{self.deref().strip_prefix(pattern.as_ref().deref()).map(Self::from_bytes)}
Rust 代码中正常的注释以 `//` 开头。文档注释则由各种工具处理,以 `///`(用于注释后续项)或 `//!`(用于注释包含项)开头。它们是等效的:
/// DocumentationstructName{ ...}structName{//! Documentation ...}
文档注释类似于内核 C 代码中使用的特殊格式 `/**` 注释。在这个 Doctest 中,`assert_eq!()` 宏(这是 Rust 中另一种宏调用的示例)用于比较 `.strip_prefix()` 方法的返回值与其预期值。
Quick reference
# Check Rust tools are installedmake rustavailable# Build kernel with Rust enabled# (After customizing .config)make LLVM=1# Run tests./tools/testing/kunit/kunit.py \ run \ --make_options LLVM=1 \ --kconfig_add CONFIG_RUST=y \ --arch=<host architecture># Run lintermake LLVM=1 CLIPPY=1# Check documentationmake rustdoc# Format codemake rustfmt
最后,Rust 代码还可以包含 内核自测试(kernel selftests),这是内核编写测试的第三种方式。这些测试需要单独配置,使用 `tools/testing/selftests/rust` 目录中的内核配置片段。Kselftests 旨在在已启动相应内核的机器上运行,并可通过 `make TARGETS="rust" kselftest` 命令运行。
Formatting
Rust 的语法很复杂。这是该语言推广过程中的几个症结之一,因为人们常常觉得它让语言难以阅读。这个问题不能完全通过格式化工具解决,但它们确实有帮助。Rust 的标准格式化工具名为 `rustfmt`,如果安装了该工具,则可以使用 `make rustfmt` 命令来重新格式化内核中的所有 Rust 代码。
Next
构建和测试 Rust 代码是审查 Rust 代码的必要条件,但并非充分条件。然而,这可能足以让人们开始尝试内核中现有的 Rust 代码。接下来,我们将深入比较一个简单的驱动模块及其 Rust 等效实现,以此作为内核 Rust 驱动抽象的介绍。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
欢迎分享、转载及基于现有协议再创作~
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

1133

被折叠的 条评论
为什么被折叠?



