Skip to content

Commit fb12219

Browse files
committed
scripts: port rustdoc_test_builder.rs to Rust
The KUnit doctest generation uses `rustdoc --test-builder` to fetch the doctests, which runs the test builder once per test. By porting `rustdoc_test_builder.py` to Rust as a hostprog, the overhead per test is reduced more than an order of magnitude (e.g. ~50ms to ~1 ms). Currently, there are about 100 doctests, which means the Python script is already responsible for a few seconds of build time. As more doctests continue to be added, this would become more and more painful. Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent 7100e46 commit fb12219

File tree

6 files changed

+57
-51
lines changed

6 files changed

+57
-51
lines changed

rust/Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,13 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
167167
--extern build_error --extern macros \
168168
--extern bindings \
169169
--no-run --crate-name kernel -Zunstable-options \
170-
--test-builder $(srctree)/scripts/rustdoc_test_builder.py \
170+
--test-builder $(objtree)/scripts/rustdoc_test_builder \
171171
$< $(rustdoc_test_kernel_quiet); \
172172
$(srctree)/scripts/rustdoc_test_gen.py
173173

174-
%/doctests_kernel_generated.rs %/doctests_kernel_generated_kunit.c: $(src)/kernel/lib.rs $(obj)/kernel.o FORCE
174+
%/doctests_kernel_generated.rs %/doctests_kernel_generated_kunit.c: \
175+
$(src)/kernel/lib.rs $(obj)/kernel.o \
176+
$(objtree)/scripts/rustdoc_test_builder FORCE
175177
$(call if_changed,rustdoc_test_kernel)
176178

177179
# We cannot use `-Zpanic-abort-tests` because some tests are dynamic,

scripts/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
/kallsyms
77
/module.lds
88
/recordmcount
9+
/rustdoc_test_builder
910
/sign-file
1011
/sorttable
1112
/unifdef

scripts/Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ hostprogs-always-$(CONFIG_BUILDTIME_TABLE_SORT) += sorttable
1010
hostprogs-always-$(CONFIG_ASN1) += asn1_compiler
1111
hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file
1212
hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert
13-
hostprogs-always-$(CONFIG_RUST) += generate_rust_target
13+
hostprogs-always-$(CONFIG_RUST) += \
14+
generate_rust_target \
15+
rustdoc_test_builder
1416

1517
generate_rust_target-rust := y
18+
rustdoc_test_builder-rust := y
1619

1720
HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
1821
HOSTLDLIBS_sorttable = -lpthread

scripts/rustdoc_test_builder.py

Lines changed: 0 additions & 42 deletions
This file was deleted.

scripts/rustdoc_test_builder.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Test builder for `rustdoc`-generated tests.
4+
5+
use std::fs::File;
6+
use std::io::{BufWriter, Read, Write};
7+
8+
fn main() {
9+
let mut stdin = std::io::stdin().lock();
10+
let mut body = String::new();
11+
stdin.read_to_string(&mut body).unwrap();
12+
13+
let name = body
14+
.lines()
15+
.find_map(|line| {
16+
Some(
17+
line.split_once("fn ")?
18+
.1
19+
.split_once("rust_kernel_")?
20+
.1
21+
.split_once("()")?
22+
.0,
23+
)
24+
.filter(|x| x.chars().all(|c| c.is_alphanumeric() || c == '_'))
25+
})
26+
.expect("No test name found.");
27+
28+
// Qualify `Result` to avoid the collision with our own `Result`
29+
// coming from the prelude.
30+
let body = body.replace(
31+
&format!("rust_kernel_{name}() -> Result<(), impl core::fmt::Debug> {{"),
32+
&format!("rust_kernel_{name}() -> core::result::Result<(), impl core::fmt::Debug> {{"),
33+
);
34+
35+
let name = format!("rust_kernel_doctest_{name}");
36+
let path = format!("rust/test/doctests/kernel/{name}");
37+
38+
write!(
39+
BufWriter::new(File::create(path).unwrap()),
40+
"{name}\n{body}"
41+
)
42+
.unwrap();
43+
}

scripts/rustdoc_test_gen.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
"""rustdoc_test_gen - Generates KUnit tests from saved `rustdoc`-generated tests.
44
"""
55

6-
import json
76
import os
87
import pathlib
98

@@ -136,16 +135,16 @@ def main():
136135
c_test_cases = ""
137136
for filename in sorted(os.listdir(TESTS_DIR)):
138137
with open(TESTS_DIR / filename, "r") as fd:
139-
test = json.load(fd)
138+
(test_name, test_body) = fd.read().split('\n', 1)
140139
rust_tests += RUST_TEMPLATE_TEST.format(
141-
test_name = test["name"],
142-
test_body = test["body"]
140+
test_name = test_name,
141+
test_body = test_body
143142
)
144143
c_test_declarations += C_TEMPLATE_TEST_DECLARATION.format(
145-
test_name = test["name"]
144+
test_name = test_name
146145
)
147146
c_test_cases += C_TEMPLATE_TEST_CASE.format(
148-
test_name = test["name"]
147+
test_name = test_name
149148
)
150149

151150
with open(RUST_FILE, "w") as fd:

0 commit comments

Comments
 (0)