通用信息¶
本文档包含在使用内核中的 Rust 支持时需要了解的有用信息。
no_std
¶
内核中的 Rust 支持只能链接 core,不能链接 std。要在内核中使用的 crate 必须使用 #![no_std]
属性选择此行为。
代码文档¶
Rust 内核代码使用 rustdoc
(其内置文档生成器)进行文档化。
生成的 HTML 文档包括集成的搜索、链接的项目(例如类型、函数、常量)、源代码等。它们可以在以下网址阅读:
对于 linux-next,请参阅
还有每个主要版本的标签,例如
这些文档也可以轻松地生成并在本地阅读。这非常快(与编译代码本身相同的数量级),并且不需要特殊的工具或环境。这还有一个额外的好处,它们将根据使用的特定内核配置进行定制。要生成它们,请使用与编译相同的调用使用的 rustdoc
目标,例如
make LLVM=1 rustdoc
要在 Web 浏览器中在本地阅读文档,请运行例如
xdg-open Documentation/output/rust/rustdoc/kernel/index.html
要了解如何编写文档,请参阅 编码准则。
额外的 lints¶
虽然 rustc
是一个非常有用的编译器,但一些额外的 lints 和分析可以通过 clippy
(Rust linter)获得。要启用它,请将 CLIPPY=1
传递给用于编译的相同调用,例如
make LLVM=1 CLIPPY=1
请注意,Clippy 可能会更改代码生成,因此在构建生产内核时不应启用它。
抽象 vs. 绑定¶
抽象是从 C 端包装内核功能的 Rust 代码。
为了使用 C 端的函数和类型,需要创建绑定。绑定是 C 端那些函数和类型的 Rust 声明。
例如,可以在 Rust 中编写一个 Mutex
抽象,它包装 C 端的 struct mutex
,并通过绑定调用其函数。
并非所有内核内部 API 和概念都提供抽象,但预计随着时间的推移,覆盖范围会扩大。“叶”模块(例如驱动程序)不应直接使用 C 绑定。相反,子系统应根据需要提供尽可能安全的抽象。
rust/bindings/
(rust/helpers/)
include/ -----+ <-+
| |
drivers/ rust/kernel/ +----------+ <-+ |
fs/ | bindgen | |
.../ +-------------------+ +----------+ --+ |
| Abstractions | | |
+---------+ | +------+ +------+ | +----------+ | |
| my_foo | -----> | | foo | | bar | | -------> | Bindings | <-+ |
| driver | Safe | | sub- | | sub- | | Unsafe | | |
+---------+ | |system| |system| | | bindings | <-----+
| | +------+ +------+ | | crate | |
| | kernel crate | +----------+ |
| +-------------------+ |
| |
+------------------# FORBIDDEN #--------------------------------+
主要思想是将与内核 C API 的所有直接交互封装到经过仔细审查和记录的抽象中。然后,只要满足以下条件,这些抽象的用户就不会引入未定义的行为 (UB):
抽象是正确的(“sound”)。
任何
unsafe
块都遵循调用块内操作所必需的安全约定。类似地,任何unsafe impl
都遵循实现 trait 所必需的安全约定。
绑定¶
通过将 include/
中的 C 头文件包含到 rust/bindings/bindings_helper.h
中,bindgen
工具将自动生成包含的子系统的绑定。构建后,在 rust/bindings/
目录中查看 *_generated.rs
输出文件。
对于 bindgen
未自动生成的 C 头文件的部分,例如 C inline
函数或非平凡的宏,可以向 rust/helpers/
添加一个小的包装函数,使其也可用于 Rust 端。
抽象¶
抽象是绑定和内核用户的层。它们位于 rust/kernel/
中,它们的作用是将对绑定的不安全访问封装到尽可能安全的 API 中,并将该 API 公开给其用户。抽象的用户包括用 Rust 编写的驱动程序或文件系统等。
除了安全性方面,抽象还应该是“符合人体工程学的”,因为它们将 C 接口转换为“惯用”的 Rust 代码。基本的例子是将 C 资源获取和释放转换为 Rust 构造函数和析构函数,或者将 C 整数错误代码转换为 Rust 的 Result
。
条件编译¶
Rust 代码可以基于内核配置进行条件编译
#[cfg(CONFIG_X)] // Enabled (`y` or `m`)
#[cfg(CONFIG_X="y")] // Enabled as a built-in (`y`)
#[cfg(CONFIG_X="m")] // Enabled as a module (`m`)
#[cfg(not(CONFIG_X))] // Disabled
对于 Rust 的 cfg
不支持的其他谓词,例如具有数值比较的表达式,可以定义一个新的 Kconfig 符号
config RUSTC_VERSION_MIN_107900
def_bool y if RUSTC_VERSION >= 107900