From: Gary Guo <[email protected]> Quite often when updating abstractions there will be some documentation that needs updating, but the build process is not very developer friendly as it just gives out something like "rust/doctests_kernel_generated.rs:12345:42" and it is a hassle to find where the documentation actually is.
Add a script as rustc wrapper, which translates the error message by appending a "(generated from original_file:original_line:col)" message to the original source info emitted by rustc. Signed-off-by: Gary Guo <[email protected]> --- I made this a rustc wrapper instead of trying to pipe rustc output to it, as Kbuild is too complex for me to understand how to do it :) --- rust/Makefile | 4 ++ scripts/rustdoc_test_build_sourcemap.py | 71 +++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 scripts/rustdoc_test_build_sourcemap.py diff --git a/rust/Makefile b/rust/Makefile index 63b1e355321d..d133d4fe1f2d 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -393,6 +393,10 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $< $(objtree)/scripts/rustdoc_test_gen FORCE +$(call if_changed,rustdoc_test_kernel) +ACTUAL_RUSTC := $(RUSTC_OR_CLIPPY) +%/doctests_kernel_generated.o: private RUSTC_OR_CLIPPY = \ + PYTHONDONTWRITEBYTECODE=1 ACTUAL_RUSTC=$(ACTUAL_RUSTC) $(PYTHON3) $(srctree)/scripts/rustdoc_test_build_sourcemap.py + # We cannot use `-Zpanic-abort-tests` because some tests are dynamic, # so for the moment we skip `-Cpanic=abort`. quiet_cmd_rustc_test = $(RUSTC_OR_CLIPPY_QUIET) T $< diff --git a/scripts/rustdoc_test_build_sourcemap.py b/scripts/rustdoc_test_build_sourcemap.py new file mode 100644 index 000000000000..afabcd061567 --- /dev/null +++ b/scripts/rustdoc_test_build_sourcemap.py @@ -0,0 +1,71 @@ +import sys +import re +import os +import subprocess + +LOCATION_REGEX = re.compile(r"\.location: (.*):(\d+)") +ANCHOR_REGEX = re.compile(r"static __DOCTEST_ANCHOR: i32 = .* \+ (\d+) \+ (\d+);") +SOURCE_INFO_REGEX = re.compile(r"(rust/[\w/.-]+\.rs):(\d+):(\d+)") + + +def transform(file, line): + with open(file, "r") as f: + lines = f.readlines() + + line_idx = line - 1 + + # Find the last location and anchor before the erroring line + real_path = None + orig_line = None + anchor_line = None + + for i in range(line_idx, -1, -1): + if real_path is None: + match = LOCATION_REGEX.search(lines[i]) + if match: + real_path = match.group(1) + orig_line = int(match.group(2)) + + if anchor_line is None: + match = ANCHOR_REGEX.search(lines[i]) + if match: + anchor_line = i + int(match.group(1)) + int(match.group(2)) + + if real_path is not None and anchor_line is not None: + break + + new_line = orig_line + (line_idx - anchor_line) + return real_path, new_line + + +def main(): + actual_rustc = os.environ.get("ACTUAL_RUSTC") + args = sys.argv[1:] + + # We redirected Rust output so it is not TTY anymore. + # Add `--color=always` back to preserve the color behaviour. + if sys.stdout.isatty() and not any(arg.startswith("--color") for arg in args): + args.append("--color=always") + + result = subprocess.run([actual_rustc] + args, stderr=subprocess.PIPE, text=True) + + def replacer(match): + orig = match.group(0) + file = match.group(1) + line = int(match.group(2)) + col = int(match.group(3)) + + if file != "rust/doctests_kernel_generated.rs": + return orig + + new_file, new_line = transform(file, line) + return f"{orig} (generated from {new_file}:{new_line}:{col})" + + if result.stderr: + sys.stderr.write(SOURCE_INFO_REGEX.sub(replacer, result.stderr)) + + sys.exit(result.returncode) + + +if __name__ == "__main__": + main() base-commit: 3782319656f65f0bf020d4c058058c23c3e16679 -- 2.54.0

