Re: [PATCH 3/3] rust: doctest: generate Rust kunit test suites
From: David Gow
Date: Sat Jun 20 2026 - 07:09:22 EST
Le 16/06/2026 à 11:24 PM, Gary Guo a écrit :
> 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.
>
> Signed-off-by: Gary Guo <gary@xxxxxxxxxxx>
> ---
Thanks very much for this. It's been on the to-do list for a while, and
it's definitely much nicer than generating lots of C code.
Reviewed-by: David Gow <david@xxxxxxxxxxxx>
My feeling is that this series should go via the rust-for-linux tree,
rather than the KUnit tree, as there's lots of poking around in common
rust files, and no change to the KUnit C code. But if you'd rather it go
in via kselftest/kunit, that's possible too.
Cheers,
-- David
> rust/Makefile | 4 +--
> scripts/rustdoc_test_gen.rs | 69 ++++++---------------------------------------
> 2 files changed, 10 insertions(+), 63 deletions(-)
>
> diff --git a/rust/Makefile b/rust/Makefile
> index a870d1616c71..8c95dd4f6aee 100644
> --- a/rust/Makefile
> +++ b/rust/Makefile
> @@ -36,10 +36,8 @@ obj-$(CONFIG_RUST) += exports.o
> always-$(CONFIG_RUST) += libproc_macro2.rlib libquote.rlib 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
> @@ -387,7 +385,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
> diff --git a/scripts/rustdoc_test_gen.rs b/scripts/rustdoc_test_gen.rs
> index acc4debe8592..601f7a5b3672 100644
> --- a/scripts/rustdoc_test_gen.rs
> +++ b/scripts/rustdoc_test_gen.rs
> @@ -118,9 +118,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;
> @@ -165,10 +163,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 {{
> @@ -183,26 +181,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::*;
> @@ -231,14 +209,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()),
> @@ -246,34 +219,10 @@ macro_rules! assert_eq {{
>
> const __LOG_PREFIX: &[u8] = b"rust_doctests_kernel\0";
>
> -{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();
>