rust: doctest: generate Rust kunit test suites

For doctest, instead of generating C FFI functions, generate a Rust test
suite with `#[kunit_tests]` and `#[test]` attributes. This makes the C glue
no longer needed.

Reviewed-by: David Gow <david@davidgow.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260902-kunit-v2-3-eda3ed6c00c5@garyguo.net
[ Removed generated file from `rust/.gitignore` and added it to
  `scripts/remove-stale-files`. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
Gary Guo 2026-09-02 23:00:01 +01:00 committed by Miguel Ojeda
parent e9a35442ef
commit a41ec2936d
4 changed files with 12 additions and 64 deletions

1
rust/.gitignore vendored
View File

@ -3,7 +3,6 @@
bindings_generated.rs
bindings_helpers_generated.rs
doctests_kernel_generated.rs
doctests_kernel_generated_kunit.c
uapi_generated.rs
exports_*_generated.h
doc/

View File

@ -39,10 +39,8 @@ obj-$(CONFIG_RUST) += exports.o
always-$(CONFIG_RUST) += host/libproc_macro2.rlib host/libquote.rlib host/libsyn.rlib
always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.rs
always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.o
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o
always-$(subst y,$(CONFIG_RUST),$(CONFIG_JUMP_LABEL)) += kernel/generated_arch_static_branch_asm.rs
ifndef CONFIG_UML
@ -402,7 +400,7 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
$< $(rustdoc_test_kernel_quiet); \
$(objtree)/scripts/rustdoc_test_gen
%/doctests_kernel_generated.rs %/doctests_kernel_generated_kunit.c: \
%/doctests_kernel_generated.rs: \
$(src)/kernel/lib.rs $(obj)/kernel.o \
$(objtree)/scripts/rustdoc_test_builder \
$(objtree)/scripts/rustdoc_test_gen FORCE

View File

@ -26,3 +26,5 @@ rm -f scripts/selinux/genheaders/genheaders
rm -f *.spec
rm -f lib/test_fortify.log
rm -f rust/doctests_kernel_generated_kunit.c

View File

@ -125,9 +125,7 @@ fn main() {
// Sort paths.
paths.sort();
let mut rust_tests = String::new();
let mut c_test_declarations = String::new();
let mut c_test_cases = String::new();
let mut tests = String::new();
let mut body = String::new();
let mut last_file = String::new();
let mut number = 0;
@ -172,10 +170,10 @@ fn main() {
use std::fmt::Write;
write!(
rust_tests,
tests,
r#"/// Generated `{name}` KUnit test case from a Rust documentation test.
#[no_mangle]
pub extern "C" fn {kunit_name}(__kunit_test: *mut ::kernel::bindings::kunit) {{
#[test]
fn {kunit_name}() {{
/// Overrides the usual [`file!`] macro with one that expands to the real path.
#[allow(unused)]
macro_rules! file {{
@ -190,26 +188,6 @@ macro_rules! line {{
() => {{ const {{ ::core::line!() - __DOCTEST_ANCHOR + {line} }} }}
}}
/// Overrides the usual [`assert!`] macro with one that calls KUnit instead.
#[allow(unused)]
macro_rules! assert {{
($cond:expr $(,)?) => {{{{
::kernel::kunit_assert!(
"{kunit_name}", $cond
);
}}}}
}}
/// Overrides the usual [`assert_eq!`] macro with one that calls KUnit instead.
#[allow(unused)]
macro_rules! assert_eq {{
($left:expr, $right:expr $(,)?) => {{{{
::kernel::kunit_assert_eq!(
"{kunit_name}", $left, $right
);
}}}}
}}
// Many tests need the prelude, so provide it by default.
#[allow(unused)]
use ::kernel::prelude::*;
@ -238,14 +216,9 @@ macro_rules! assert_eq {{
"#
)
.unwrap();
write!(c_test_declarations, "void {kunit_name}(struct kunit *);\n").unwrap();
write!(c_test_cases, " KUNIT_CASE({kunit_name}),\n").unwrap();
}
let rust_tests = rust_tests.trim();
let c_test_declarations = c_test_declarations.trim();
let c_test_cases = c_test_cases.trim();
let tests = tests.trim();
write!(
BufWriter::new(File::create("rust/doctests_kernel_generated.rs").unwrap()),
@ -271,34 +244,10 @@ impl ModuleMetadata for LocalModule {{
}};
}}
{rust_tests}
"#
)
.unwrap();
write!(
BufWriter::new(File::create("rust/doctests_kernel_generated_kunit.c").unwrap()),
r#"/*
* `kernel` crate documentation tests.
*/
#include <kunit/test.h>
{c_test_declarations}
static struct kunit_case test_cases[] = {{
{c_test_cases}
{{ }}
}};
static struct kunit_suite test_suite = {{
.name = "rust_doctests_kernel",
.test_cases = test_cases,
}};
kunit_test_suite(test_suite);
MODULE_LICENSE("GPL");
#[kernel::macros::kunit_tests(rust_doctests_kernel)]
mod tests {{
{tests}
}}
"#
)
.unwrap();