Skip to content

Commit 5f80e7a

Browse files
committed
scripts: port rustdoc_test_gen.py to Rust
JSON is not being used now, and the other script is already ported, so it makes sense to port this one too. With this, `CONFIG_RUST` does not introduce a Python dependency (for building), and the remaining Python usage is in `generate_rust_analyzer.py` which is not needed when building. The performance difference is again more than an order of magnitude, but in this case it does not matter much since it runs only once compared to the builder. Nevertheless, at some point it is likely there will be many more doctests and shaving a tine bit of time never hurts. In fact, from a clean build, this happens to be slower, due to the compilation step of the script itself. Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent fb12219 commit 5f80e7a

File tree

4 files changed

+68
-61
lines changed

4 files changed

+68
-61
lines changed

rust/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,12 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
169169
--no-run --crate-name kernel -Zunstable-options \
170170
--test-builder $(objtree)/scripts/rustdoc_test_builder \
171171
$< $(rustdoc_test_kernel_quiet); \
172-
$(srctree)/scripts/rustdoc_test_gen.py
172+
$(objtree)/scripts/rustdoc_test_gen
173173

174174
%/doctests_kernel_generated.rs %/doctests_kernel_generated_kunit.c: \
175175
$(src)/kernel/lib.rs $(obj)/kernel.o \
176-
$(objtree)/scripts/rustdoc_test_builder FORCE
176+
$(objtree)/scripts/rustdoc_test_builder \
177+
$(objtree)/scripts/rustdoc_test_gen FORCE
177178
$(call if_changed,rustdoc_test_kernel)
178179

179180
# 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
@@ -7,6 +7,7 @@
77
/module.lds
88
/recordmcount
99
/rustdoc_test_builder
10+
/rustdoc_test_gen
1011
/sign-file
1112
/sorttable
1213
/unifdef

scripts/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file
1212
hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert
1313
hostprogs-always-$(CONFIG_RUST) += \
1414
generate_rust_target \
15-
rustdoc_test_builder
15+
rustdoc_test_builder \
16+
rustdoc_test_gen
1617

1718
generate_rust_target-rust := y
1819
rustdoc_test_builder-rust := y
20+
rustdoc_test_gen-rust := y
1921

2022
HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
2123
HOSTLDLIBS_sorttable = -lpthread

scripts/rustdoc_test_gen.py renamed to scripts/rustdoc_test_gen.rs

Lines changed: 61 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,37 @@
1-
#!/usr/bin/env python3
2-
# SPDX-License-Identifier: GPL-2.0
3-
"""rustdoc_test_gen - Generates KUnit tests from saved `rustdoc`-generated tests.
4-
"""
5-
6-
import os
7-
import pathlib
8-
9-
RUST_DIR = pathlib.Path("rust")
10-
TESTS_DIR = RUST_DIR / "test" / "doctests" / "kernel"
11-
12-
RUST_FILE = RUST_DIR / "doctests_kernel_generated.rs"
13-
C_FILE = RUST_DIR / "doctests_kernel_generated_kunit.c"
14-
15-
RUST_TEMPLATE_TEST = """
16-
/// Generated `{test_name}` KUnit test case from a Rust documentation test.
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Generates KUnit tests from saved `rustdoc`-generated tests.
4+
5+
use std::io::{BufWriter, Read, Write};
6+
use std::{fs, fs::File};
7+
8+
fn main() {
9+
let mut dirs = fs::read_dir("rust/test/doctests/kernel")
10+
.unwrap()
11+
.map(|p| p.unwrap().path())
12+
.collect::<Vec<_>>();
13+
dirs.sort();
14+
15+
let mut rust_tests = String::new();
16+
let mut c_test_declarations = String::new();
17+
let mut c_test_cases = String::new();
18+
let mut content = String::new();
19+
for path in dirs {
20+
content.clear();
21+
22+
File::open(path)
23+
.unwrap()
24+
.read_to_string(&mut content)
25+
.unwrap();
26+
27+
let (name, body) = content.split_once("\n").unwrap();
28+
29+
use std::fmt::Write;
30+
write!(
31+
rust_tests,
32+
r#"/// Generated `{name}` KUnit test case from a Rust documentation test.
1733
#[no_mangle]
18-
pub fn {test_name}(__kunit_test: *mut kernel::bindings::kunit) {{
34+
pub fn {name}(__kunit_test: *mut kernel::bindings::kunit) {{
1935
/// Provides mutual exclusion (see `# Implementation` notes).
2036
static __KUNIT_TEST_MUTEX: kernel::sync::smutex::Mutex<()> =
2137
kernel::sync::smutex::Mutex::new(());
@@ -55,12 +71,26 @@
5571
use kernel::prelude::*;
5672
5773
{{
58-
{test_body}
74+
{body}
5975
main();
6076
}}
6177
}}
62-
"""
63-
RUST_TEMPLATE = """// SPDX-License-Identifier: GPL-2.0
78+
79+
"#
80+
)
81+
.unwrap();
82+
83+
write!(c_test_declarations, "void {name}(struct kunit *);\n").unwrap();
84+
write!(c_test_cases, " KUNIT_CASE({name}),\n").unwrap();
85+
}
86+
87+
let rust_tests = rust_tests.trim();
88+
let c_test_declarations = c_test_declarations.trim();
89+
let c_test_cases = c_test_cases.trim();
90+
91+
write!(
92+
BufWriter::new(File::create("rust/doctests_kernel_generated.rs").unwrap()),
93+
r#"// SPDX-License-Identifier: GPL-2.0
6494
6595
//! `kernel` crate documentation tests.
6696
@@ -98,14 +128,16 @@
98128
// an `AtomicPtr` to hold the context (though each test only writes once before
99129
// threads may be created).
100130
101-
const __LOG_PREFIX: &[u8] = b"rust_kernel_doctests\\0";
131+
const __LOG_PREFIX: &[u8] = b"rust_kernel_doctests\0";
102132
103133
{rust_tests}
104-
"""
134+
"#
135+
)
136+
.unwrap();
105137

106-
C_TEMPLATE_TEST_DECLARATION = "void {test_name}(struct kunit *);\n"
107-
C_TEMPLATE_TEST_CASE = " KUNIT_CASE({test_name}),\n"
108-
C_TEMPLATE = """// SPDX-License-Identifier: GPL-2.0
138+
write!(
139+
BufWriter::new(File::create("rust/doctests_kernel_generated_kunit.c").unwrap()),
140+
r#"// SPDX-License-Identifier: GPL-2.0
109141
/*
110142
* `kernel` crate documentation tests.
111143
*/
@@ -127,36 +159,7 @@
127159
kunit_test_suite(test_suite);
128160
129161
MODULE_LICENSE("GPL");
130-
"""
131-
132-
def main():
133-
rust_tests = ""
134-
c_test_declarations = ""
135-
c_test_cases = ""
136-
for filename in sorted(os.listdir(TESTS_DIR)):
137-
with open(TESTS_DIR / filename, "r") as fd:
138-
(test_name, test_body) = fd.read().split('\n', 1)
139-
rust_tests += RUST_TEMPLATE_TEST.format(
140-
test_name = test_name,
141-
test_body = test_body
142-
)
143-
c_test_declarations += C_TEMPLATE_TEST_DECLARATION.format(
144-
test_name = test_name
145-
)
146-
c_test_cases += C_TEMPLATE_TEST_CASE.format(
147-
test_name = test_name
148-
)
149-
150-
with open(RUST_FILE, "w") as fd:
151-
fd.write(RUST_TEMPLATE.format(
152-
rust_tests = rust_tests.strip(),
153-
))
154-
155-
with open(C_FILE, "w") as fd:
156-
fd.write(C_TEMPLATE.format(
157-
c_test_declarations=c_test_declarations.strip(),
158-
c_test_cases=c_test_cases.strip(),
159-
))
160-
161-
if __name__ == "__main__":
162-
main()
162+
"#
163+
)
164+
.unwrap();
165+
}

0 commit comments

Comments
 (0)