From e33d58ee0c081c4468d0ea4f03fcb93c6cb5e21a Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 22 Jan 2026 12:30:45 -0500 Subject: scripts: generate_rust_analyzer.py: extract `{build,register}_crate` Extract helpers from `append_crate` to avoid the need to peek into `crates[-1]`. This improves readability. Change default parameters to `None` with true defaults applied in `build_crate` to avoid repeating the defaults in wrapper functions such as `append_crate`. Suggested-by: Trevor Gross Reviewed-by: Daniel Almeida Tested-by: Daniel Almeida Reviewed-by: Fiona Behrens Reviewed-by: Trevor Gross Reviewed-by: Jesung Yang Tested-by: Jesung Yang Link: https://patch.msgid.link/20260122-rust-analyzer-types-v1-1-29cc2e91dcd5@kernel.org Signed-off-by: Tamir Duberstein --- scripts/generate_rust_analyzer.py | 74 ++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 13 deletions(-) (limited to 'scripts/generate_rust_analyzer.py') diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index f9b545104f21..a650689c7da4 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -35,7 +35,22 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit crates_indexes = {} crates_cfgs = args_crates_cfgs(cfgs) - def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False, edition="2021"): + def build_crate( + display_name, + root_module, + deps, + *, + cfg, + is_workspace_member, + is_proc_macro, + edition, + ): + cfg = cfg if cfg is not None else [] + is_workspace_member = ( + is_workspace_member if is_workspace_member is not None else True + ) + is_proc_macro = is_proc_macro if is_proc_macro is not None else False + edition = edition if edition is not None else "2021" crate = { "display_name": display_name, "root_module": str(root_module), @@ -54,19 +69,45 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit stdin=subprocess.DEVNULL, ).decode('utf-8').strip() crate["proc_macro_dylib_path"] = f"{objtree}/rust/{proc_macro_dylib_name}" - crates_indexes[display_name] = len(crates) + return crate + + def register_crate(crate): + crates_indexes[crate["display_name"]] = len(crates) crates.append(crate) + def append_crate( + display_name, + root_module, + deps, + *, + cfg=None, + is_workspace_member=None, + is_proc_macro=None, + edition=None, + ): + return register_crate( + build_crate( + display_name, + root_module, + deps, + cfg=cfg, + is_workspace_member=is_workspace_member, + is_proc_macro=is_proc_macro, + edition=edition, + ) + ) + def append_sysroot_crate( display_name, deps, - cfg=[], + *, + cfg=None, ): - append_crate( + return append_crate( display_name, sysroot_src / display_name / "src" / "lib.rs", deps, - cfg, + cfg=cfg, is_workspace_member=False, # Miguel Ojeda writes: # @@ -169,20 +210,27 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit display_name, deps, ): - append_crate( + crate = build_crate( display_name, srctree / "rust"/ display_name / "lib.rs", deps, cfg=cfg, + is_workspace_member=True, + is_proc_macro=False, + edition=None, ) - crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True)) - crates[-1]["source"] = { - "include_dirs": [ - str(srctree / "rust" / display_name), - str(objtree / "rust") - ], - "exclude_dirs": [], + crate["env"]["OBJTREE"] = str(objtree.resolve(True)) + crate_with_generated = { + **crate, + "source": { + "include_dirs": [ + str(srctree / "rust" / display_name), + str(objtree / "rust"), + ], + "exclude_dirs": [], + }, } + return register_crate(crate_with_generated) append_crate_with_generated("bindings", ["core", "ffi", "pin_init"]) append_crate_with_generated("uapi", ["core", "ffi", "pin_init"]) -- cgit v1.2.3 From 4079cf049cb265c15c3c7349d85943462ba054d5 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 22 Jan 2026 12:30:46 -0500 Subject: scripts: generate_rust_analyzer.py: drop `"is_proc_macro": false` Add a dedicated `append_proc_macro_crate` function to reduce overloading in `append_crate`. This has the effect of removing `"is_proc_macro": false` from the output; this field is interpreted as false if absent[1] so this doesn't change the behavior of rust-analyzer. Use the `/` operator on `pathlib.Path` rather than directly crafting a string. This is consistent with all other path manipulation in this script. Link: https://github.com/rust-lang/rust-analyzer/blob/8d01570b5e812a49daa1f08404269f6ea5dd73a1/crates/project-model/src/project_json.rs#L372-L373 [1] Tested-by: Daniel Almeida Reviewed-by: Daniel Almeida Reviewed-by: Trevor Gross Reviewed-by: Jesung Yang Tested-by: Jesung Yang Link: https://patch.msgid.link/20260122-rust-analyzer-types-v1-2-29cc2e91dcd5@kernel.org Signed-off-by: Tamir Duberstein --- scripts/generate_rust_analyzer.py | 60 ++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 17 deletions(-) (limited to 'scripts/generate_rust_analyzer.py') diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index a650689c7da4..3fdb90dd278b 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -42,20 +42,17 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit *, cfg, is_workspace_member, - is_proc_macro, edition, ): cfg = cfg if cfg is not None else [] is_workspace_member = ( is_workspace_member if is_workspace_member is not None else True ) - is_proc_macro = is_proc_macro if is_proc_macro is not None else False edition = edition if edition is not None else "2021" - crate = { + return { "display_name": display_name, "root_module": str(root_module), "is_workspace_member": is_workspace_member, - "is_proc_macro": is_proc_macro, "deps": [{"crate": crates_indexes[dep], "name": dep} for dep in deps], "cfg": cfg, "edition": edition, @@ -63,13 +60,47 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit "RUST_MODFILE": "This is only for rust-analyzer" } } - if is_proc_macro: - proc_macro_dylib_name = subprocess.check_output( - [os.environ["RUSTC"], "--print", "file-names", "--crate-name", display_name, "--crate-type", "proc-macro", "-"], + + def append_proc_macro_crate( + display_name, + root_module, + deps, + *, + cfg=None, + is_workspace_member=None, + edition=None, + ): + crate = build_crate( + display_name, + root_module, + deps, + cfg=cfg, + is_workspace_member=is_workspace_member, + edition=edition, + ) + proc_macro_dylib_name = ( + subprocess.check_output( + [ + os.environ["RUSTC"], + "--print", + "file-names", + "--crate-name", + display_name, + "--crate-type", + "proc-macro", + "-", + ], stdin=subprocess.DEVNULL, - ).decode('utf-8').strip() - crate["proc_macro_dylib_path"] = f"{objtree}/rust/{proc_macro_dylib_name}" - return crate + ) + .decode("utf-8") + .strip() + ) + proc_macro_crate = { + **crate, + "is_proc_macro": True, + "proc_macro_dylib_path": str(objtree / "rust" / proc_macro_dylib_name), + } + return register_crate(proc_macro_crate) def register_crate(crate): crates_indexes[crate["display_name"]] = len(crates) @@ -82,7 +113,6 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit *, cfg=None, is_workspace_member=None, - is_proc_macro=None, edition=None, ): return register_crate( @@ -92,7 +122,6 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit deps, cfg=cfg, is_workspace_member=is_workspace_member, - is_proc_macro=is_proc_macro, edition=edition, ) ) @@ -172,11 +201,10 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit cfg=crates_cfgs["syn"], ) - append_crate( + append_proc_macro_crate( "macros", srctree / "rust" / "macros" / "lib.rs", ["std", "proc_macro", "proc_macro2", "quote", "syn"], - is_proc_macro=True, ) append_crate( @@ -185,12 +213,11 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit ["core", "compiler_builtins"], ) - append_crate( + append_proc_macro_crate( "pin_init_internal", srctree / "rust" / "pin-init" / "internal" / "src" / "lib.rs", ["std", "proc_macro", "proc_macro2", "quote", "syn"], cfg=["kernel"], - is_proc_macro=True, ) append_crate( @@ -216,7 +243,6 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit deps, cfg=cfg, is_workspace_member=True, - is_proc_macro=False, edition=None, ) crate["env"]["OBJTREE"] = str(objtree.resolve(True)) -- cgit v1.2.3 From 94a3b2d9877eee2f8b5b41a51d99b7860efbd34d Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 22 Jan 2026 12:30:47 -0500 Subject: scripts: generate_rust_analyzer.py: add type hints Python type hints allow static analysis tools like mypy to detect type errors during development, improving the developer experience. Python type hints have been present in the kernel since 2019 at the latest; see commit 6ebf5866f2e8 ("kunit: tool: add Python wrappers for running KUnit tests"). Add a subclass of `argparse.Namespace` to get type checking on the CLI arguments. Run `mypy --strict scripts/generate_rust_analyzer.py --python-version 3.9` to verify. Note that `mypy` no longer supports python < 3.9. Tested-by: Daniel Almeida Reviewed-by: Daniel Almeida Reviewed-by: Trevor Gross Reviewed-by: Jesung Yang Tested-by: Jesung Yang Link: https://patch.msgid.link/20260122-rust-analyzer-types-v1-3-29cc2e91dcd5@kernel.org Signed-off-by: Tamir Duberstein --- scripts/generate_rust_analyzer.py | 128 ++++++++++++++++++++++++++------------ 1 file changed, 89 insertions(+), 39 deletions(-) (limited to 'scripts/generate_rust_analyzer.py') diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index 3fdb90dd278b..68c0579c3eae 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -10,8 +10,9 @@ import os import pathlib import subprocess import sys +from typing import Dict, Iterable, List, Literal, Optional, TypedDict -def args_crates_cfgs(cfgs): +def args_crates_cfgs(cfgs: List[str]) -> Dict[str, List[str]]: crates_cfgs = {} for cfg in cfgs: crate, vals = cfg.split("=", 1) @@ -19,7 +20,43 @@ def args_crates_cfgs(cfgs): return crates_cfgs -def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edition): +class Dependency(TypedDict): + crate: int + name: str + + +class Source(TypedDict): + include_dirs: List[str] + exclude_dirs: List[str] + + +class Crate(TypedDict): + display_name: str + root_module: str + is_workspace_member: bool + deps: List[Dependency] + cfg: List[str] + edition: str + env: Dict[str, str] + + +class ProcMacroCrate(Crate): + is_proc_macro: Literal[True] + proc_macro_dylib_path: str # `pathlib.Path` is not JSON serializable. + + +class CrateWithGenerated(Crate): + source: Source + + +def generate_crates( + srctree: pathlib.Path, + objtree: pathlib.Path, + sysroot_src: pathlib.Path, + external_src: Optional[pathlib.Path], + cfgs: List[str], + core_edition: str, +) -> List[Crate]: # Generate the configuration list. cfg = [] with open(objtree / "include" / "generated" / "rustc_cfg") as fd: @@ -31,19 +68,19 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit # Now fill the crates list -- dependencies need to come first. # # Avoid O(n^2) iterations by keeping a map of indexes. - crates = [] - crates_indexes = {} + crates: List[Crate] = [] + crates_indexes: Dict[str, int] = {} crates_cfgs = args_crates_cfgs(cfgs) def build_crate( - display_name, - root_module, - deps, + display_name: str, + root_module: pathlib.Path, + deps: List[str], *, - cfg, - is_workspace_member, - edition, - ): + cfg: Optional[List[str]], + is_workspace_member: Optional[bool], + edition: Optional[str], + ) -> Crate: cfg = cfg if cfg is not None else [] is_workspace_member = ( is_workspace_member if is_workspace_member is not None else True @@ -62,14 +99,14 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit } def append_proc_macro_crate( - display_name, - root_module, - deps, + display_name: str, + root_module: pathlib.Path, + deps: List[str], *, - cfg=None, - is_workspace_member=None, - edition=None, - ): + cfg: Optional[List[str]] = None, + is_workspace_member: Optional[bool] = None, + edition: Optional[str] = None, + ) -> None: crate = build_crate( display_name, root_module, @@ -95,26 +132,26 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit .decode("utf-8") .strip() ) - proc_macro_crate = { + proc_macro_crate: ProcMacroCrate = { **crate, "is_proc_macro": True, "proc_macro_dylib_path": str(objtree / "rust" / proc_macro_dylib_name), } return register_crate(proc_macro_crate) - def register_crate(crate): + def register_crate(crate: Crate) -> None: crates_indexes[crate["display_name"]] = len(crates) crates.append(crate) def append_crate( - display_name, - root_module, - deps, + display_name: str, + root_module: pathlib.Path, + deps: List[str], *, - cfg=None, - is_workspace_member=None, - edition=None, - ): + cfg: Optional[List[str]] = None, + is_workspace_member: Optional[bool] = None, + edition: Optional[str] = None, + ) -> None: return register_crate( build_crate( display_name, @@ -127,11 +164,11 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit ) def append_sysroot_crate( - display_name, - deps, + display_name: str, + deps: List[str], *, - cfg=None, - ): + cfg: Optional[List[str]] = None, + ) -> None: return append_crate( display_name, sysroot_src / display_name / "src" / "lib.rs", @@ -234,9 +271,9 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit ) def append_crate_with_generated( - display_name, - deps, - ): + display_name: str, + deps: List[str], + ) -> None: crate = build_crate( display_name, srctree / "rust"/ display_name / "lib.rs", @@ -246,7 +283,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit edition=None, ) crate["env"]["OBJTREE"] = str(objtree.resolve(True)) - crate_with_generated = { + crate_with_generated: CrateWithGenerated = { **crate, "source": { "include_dirs": [ @@ -262,7 +299,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit append_crate_with_generated("uapi", ["core", "ffi", "pin_init"]) append_crate_with_generated("kernel", ["core", "macros", "build_error", "pin_init", "ffi", "bindings", "uapi"]) - def is_root_crate(build_file, target): + def is_root_crate(build_file: pathlib.Path, target: str) -> bool: try: return f"{target}.o" in open(build_file).read() except FileNotFoundError: @@ -271,7 +308,9 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit # Then, the rest outside of `rust/`. # # We explicitly mention the top-level folders we want to cover. - extra_dirs = map(lambda dir: srctree / dir, ("samples", "drivers")) + extra_dirs: Iterable[pathlib.Path] = ( + srctree / dir for dir in ("samples", "drivers") + ) if external_src is not None: extra_dirs = [external_src] for folder in extra_dirs: @@ -294,7 +333,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit return crates -def main(): +def main() -> None: parser = argparse.ArgumentParser() parser.add_argument('--verbose', '-v', action='store_true') parser.add_argument('--cfgs', action='append', default=[]) @@ -304,7 +343,18 @@ def main(): parser.add_argument("sysroot", type=pathlib.Path) parser.add_argument("sysroot_src", type=pathlib.Path) parser.add_argument("exttree", type=pathlib.Path, nargs="?") - args = parser.parse_args() + + class Args(argparse.Namespace): + verbose: bool + cfgs: List[str] + srctree: pathlib.Path + objtree: pathlib.Path + sysroot: pathlib.Path + sysroot_src: pathlib.Path + exttree: Optional[pathlib.Path] + core_edition: str + + args = parser.parse_args(namespace=Args()) logging.basicConfig( format="[%(asctime)s] [%(levelname)s] %(message)s", -- cgit v1.2.3 From 75c0fb25b56dc3ef122b1ac2dbb7bc9b31937408 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 22 Jan 2026 12:30:48 -0500 Subject: scripts: generate_rust_analyzer.py: identify crates explicitly Use the return of `append_crate` to declare dependency on that crate. This removes the need to build an index of crates and allows multiple crates with the same display_name be defined, which allows e.g. host crates to be defined separately from target crates. Reviewed-by: Fiona Behrens Reviewed-by: Daniel Almeida Tested-by: Daniel Almeida Reviewed-by: Trevor Gross Reviewed-by: Jesung Yang Tested-by: Jesung Yang Link: https://patch.msgid.link/20260122-rust-analyzer-types-v1-4-29cc2e91dcd5@kernel.org Signed-off-by: Tamir Duberstein --- scripts/generate_rust_analyzer.py | 84 +++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 42 deletions(-) (limited to 'scripts/generate_rust_analyzer.py') diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index 68c0579c3eae..7becc2698c14 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -65,17 +65,14 @@ def generate_crates( line = line.replace("\n", "") cfg.append(line) - # Now fill the crates list -- dependencies need to come first. - # - # Avoid O(n^2) iterations by keeping a map of indexes. + # Now fill the crates list. crates: List[Crate] = [] - crates_indexes: Dict[str, int] = {} crates_cfgs = args_crates_cfgs(cfgs) def build_crate( display_name: str, root_module: pathlib.Path, - deps: List[str], + deps: List[Dependency], *, cfg: Optional[List[str]], is_workspace_member: Optional[bool], @@ -90,7 +87,7 @@ def generate_crates( "display_name": display_name, "root_module": str(root_module), "is_workspace_member": is_workspace_member, - "deps": [{"crate": crates_indexes[dep], "name": dep} for dep in deps], + "deps": deps, "cfg": cfg, "edition": edition, "env": { @@ -101,12 +98,12 @@ def generate_crates( def append_proc_macro_crate( display_name: str, root_module: pathlib.Path, - deps: List[str], + deps: List[Dependency], *, cfg: Optional[List[str]] = None, is_workspace_member: Optional[bool] = None, edition: Optional[str] = None, - ) -> None: + ) -> Dependency: crate = build_crate( display_name, root_module, @@ -139,19 +136,20 @@ def generate_crates( } return register_crate(proc_macro_crate) - def register_crate(crate: Crate) -> None: - crates_indexes[crate["display_name"]] = len(crates) + def register_crate(crate: Crate) -> Dependency: + index = len(crates) crates.append(crate) + return {"crate": index, "name": crate["display_name"]} def append_crate( display_name: str, root_module: pathlib.Path, - deps: List[str], + deps: List[Dependency], *, cfg: Optional[List[str]] = None, is_workspace_member: Optional[bool] = None, edition: Optional[str] = None, - ) -> None: + ) -> Dependency: return register_crate( build_crate( display_name, @@ -165,10 +163,10 @@ def generate_crates( def append_sysroot_crate( display_name: str, - deps: List[str], + deps: List[Dependency], *, cfg: Optional[List[str]] = None, - ) -> None: + ) -> Dependency: return append_crate( display_name, sysroot_src / display_name / "src" / "lib.rs", @@ -205,75 +203,75 @@ def generate_crates( # NB: sysroot crates reexport items from one another so setting up our transitive dependencies # here is important for ensuring that rust-analyzer can resolve symbols. The sources of truth # for this dependency graph are `(sysroot_src / crate / "Cargo.toml" for crate in crates)`. - append_sysroot_crate("core", [], cfg=crates_cfgs.get("core", [])) - append_sysroot_crate("alloc", ["core"]) - append_sysroot_crate("std", ["alloc", "core"]) - append_sysroot_crate("proc_macro", ["core", "std"]) + core = append_sysroot_crate("core", [], cfg=crates_cfgs.get("core", [])) + alloc = append_sysroot_crate("alloc", [core]) + std = append_sysroot_crate("std", [alloc, core]) + proc_macro = append_sysroot_crate("proc_macro", [core, std]) - append_crate( + compiler_builtins = append_crate( "compiler_builtins", srctree / "rust" / "compiler_builtins.rs", - ["core"], + [core], ) - append_crate( + proc_macro2 = append_crate( "proc_macro2", srctree / "rust" / "proc-macro2" / "lib.rs", - ["core", "alloc", "std", "proc_macro"], + [core, alloc, std, proc_macro], cfg=crates_cfgs["proc_macro2"], ) - append_crate( + quote = append_crate( "quote", srctree / "rust" / "quote" / "lib.rs", - ["core", "alloc", "std", "proc_macro", "proc_macro2"], + [core, alloc, std, proc_macro, proc_macro2], cfg=crates_cfgs["quote"], edition="2018", ) - append_crate( + syn = append_crate( "syn", srctree / "rust" / "syn" / "lib.rs", - ["std", "proc_macro", "proc_macro2", "quote"], + [std, proc_macro, proc_macro2, quote], cfg=crates_cfgs["syn"], ) - append_proc_macro_crate( + macros = append_proc_macro_crate( "macros", srctree / "rust" / "macros" / "lib.rs", - ["std", "proc_macro", "proc_macro2", "quote", "syn"], + [std, proc_macro, proc_macro2, quote, syn], ) - append_crate( + build_error = append_crate( "build_error", srctree / "rust" / "build_error.rs", - ["core", "compiler_builtins"], + [core, compiler_builtins], ) - append_proc_macro_crate( + pin_init_internal = append_proc_macro_crate( "pin_init_internal", srctree / "rust" / "pin-init" / "internal" / "src" / "lib.rs", - ["std", "proc_macro", "proc_macro2", "quote", "syn"], + [std, proc_macro, proc_macro2, quote, syn], cfg=["kernel"], ) - append_crate( + pin_init = append_crate( "pin_init", srctree / "rust" / "pin-init" / "src" / "lib.rs", - ["core", "compiler_builtins", "pin_init_internal", "macros"], + [core, compiler_builtins, pin_init_internal, macros], cfg=["kernel"], ) - append_crate( + ffi = append_crate( "ffi", srctree / "rust" / "ffi.rs", - ["core", "compiler_builtins"], + [core, compiler_builtins], ) def append_crate_with_generated( display_name: str, - deps: List[str], - ) -> None: + deps: List[Dependency], + ) -> Dependency: crate = build_crate( display_name, srctree / "rust"/ display_name / "lib.rs", @@ -295,9 +293,11 @@ def generate_crates( } return register_crate(crate_with_generated) - append_crate_with_generated("bindings", ["core", "ffi", "pin_init"]) - append_crate_with_generated("uapi", ["core", "ffi", "pin_init"]) - append_crate_with_generated("kernel", ["core", "macros", "build_error", "pin_init", "ffi", "bindings", "uapi"]) + bindings = append_crate_with_generated("bindings", [core, ffi, pin_init]) + uapi = append_crate_with_generated("uapi", [core, ffi, pin_init]) + kernel = append_crate_with_generated( + "kernel", [core, macros, build_error, pin_init, ffi, bindings, uapi] + ) def is_root_crate(build_file: pathlib.Path, target: str) -> bool: try: @@ -327,7 +327,7 @@ def generate_crates( append_crate( name, path, - ["core", "kernel", "pin_init"], + [core, kernel, pin_init], cfg=cfg, ) -- cgit v1.2.3 From 36c619f6bd793493294becb10a02fea370b67a91 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 22 Jan 2026 11:53:28 -0500 Subject: scripts: generate_rust_analyzer.py: define scripts Add IDE support for host-side scripts written in Rust. This support has been missing since these scripts were initially added in commit 9a8ff24ce584 ("scripts: add `generate_rust_target.rs`"), thus add it. Change the existing instance of extension stripping to `pathlib.Path.stem` to maintain code consistency. Fixes: 9a8ff24ce584 ("scripts: add `generate_rust_target.rs`") Cc: stable@vger.kernel.org Reviewed-by: Daniel Almeida Reviewed-by: Fiona Behrens Reviewed-by: Trevor Gross Link: https://patch.msgid.link/20260122-rust-analyzer-scripts-v1-1-ff6ba278170e@kernel.org Signed-off-by: Tamir Duberstein --- scripts/generate_rust_analyzer.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'scripts/generate_rust_analyzer.py') diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index 7becc2698c14..38e834bd209e 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -299,6 +299,18 @@ def generate_crates( "kernel", [core, macros, build_error, pin_init, ffi, bindings, uapi] ) + scripts = srctree / "scripts" + makefile = (scripts / "Makefile").read_text() + for path in scripts.glob("*.rs"): + name = path.stem + if f"{name}-rust" not in makefile: + continue + append_crate( + name, + path, + [std], + ) + def is_root_crate(build_file: pathlib.Path, target: str) -> bool: try: return f"{target}.o" in open(build_file).read() @@ -316,7 +328,7 @@ def generate_crates( for folder in extra_dirs: for path in folder.rglob("*.rs"): logging.info("Checking %s", path) - name = path.name.replace(".rs", "") + name = path.stem # Skip those that are not crate roots. if not is_root_crate(path.parent / "Makefile", name) and \ -- cgit v1.2.3 From 9b4744d8eda2824041064a5639ccbb079850914d Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 27 Jan 2026 11:35:43 -0500 Subject: scripts: generate_rust_analyzer.py: avoid FD leak Use `pathlib.Path.read_text()` to avoid leaking file descriptors. Fixes: 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") Cc: stable@vger.kernel.org Reviewed-by: Daniel Almeida Reviewed-by: Fiona Behrens Reviewed-by: Trevor Gross Link: https://patch.msgid.link/20260127-rust-analyzer-fd-leak-v2-1-1bb55b9b6822@kernel.org Signed-off-by: Tamir Duberstein --- scripts/generate_rust_analyzer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'scripts/generate_rust_analyzer.py') diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index 38e834bd209e..024e71a742e0 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -313,9 +313,10 @@ def generate_crates( def is_root_crate(build_file: pathlib.Path, target: str) -> bool: try: - return f"{target}.o" in open(build_file).read() + contents = build_file.read_text() except FileNotFoundError: return False + return f"{target}.o" in contents # Then, the rest outside of `rust/`. # -- cgit v1.2.3 From dc6b431f18cfb1e8cc7da45c16ccf371bcd636d5 Mon Sep 17 00:00:00 2001 From: Eliot Courtney Date: Tue, 20 Jan 2026 17:52:50 +0900 Subject: scripts: generate_rust_analyzer.py: rename cfg to generated_cfg This variable is for the cfg from generated files. It's also easy to confuse with the `cfg` parameter in append_crate(), so rename it. [ Changed title to include script extension. - Tamir ] Signed-off-by: Eliot Courtney Reviewed-by: Tamir Duberstein Link: https://patch.msgid.link/20260120-ra-fix-v1-1-829e4e92818c@nvidia.com Signed-off-by: Tamir Duberstein --- scripts/generate_rust_analyzer.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'scripts/generate_rust_analyzer.py') diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index 024e71a742e0..2977dfff76b3 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -58,12 +58,12 @@ def generate_crates( core_edition: str, ) -> List[Crate]: # Generate the configuration list. - cfg = [] + generated_cfg = [] with open(objtree / "include" / "generated" / "rustc_cfg") as fd: for line in fd: line = line.replace("--cfg=", "") line = line.replace("\n", "") - cfg.append(line) + generated_cfg.append(line) # Now fill the crates list. crates: List[Crate] = [] @@ -276,7 +276,7 @@ def generate_crates( display_name, srctree / "rust"/ display_name / "lib.rs", deps, - cfg=cfg, + cfg=generated_cfg, is_workspace_member=True, edition=None, ) @@ -341,7 +341,7 @@ def generate_crates( name, path, [core, kernel, pin_init], - cfg=cfg, + cfg=generated_cfg, ) return crates -- cgit v1.2.3 From 5c8d16ac49405c5b77c955684849528f7d4d6b81 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 27 Jan 2026 08:55:51 -0500 Subject: scripts: generate_rust_analyzer.py: reduce cfg plumbing Pass `pin_init{,_internal}-cfgs` from rust/Makefile to scripts/generate_rust_analyzer.py. Remove hardcoded `cfg`s in scripts/generate_rust_analyzer.py for `pin-init{,-internal}` now that these are passed from `rust/Makefile`. Centralize `cfg` lookup in scripts/generate_rust_analyzer.py in `append_crate` to avoid having to do so for each crate. Reviewed-by: Jesung Yang Acked-by: Benno Lossin Acked-by: Miguel Ojeda Link: https://patch.msgid.link/20260127-rust-analyzer-pin-init-duplication-v3-2-118c48c35e88@kernel.org Signed-off-by: Tamir Duberstein --- rust/Makefile | 2 ++ scripts/generate_rust_analyzer.py | 9 ++------- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'scripts/generate_rust_analyzer.py') diff --git a/rust/Makefile b/rust/Makefile index 629b3bdd2b20..061a4e7af3b8 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -592,6 +592,8 @@ rust-analyzer: --cfgs='proc_macro2=$(proc_macro2-cfgs)' \ --cfgs='quote=$(quote-cfgs)' \ --cfgs='syn=$(syn-cfgs)' \ + --cfgs='pin_init_internal=$(pin_init_internal-cfgs)' \ + --cfgs='pin_init=$(pin_init-cfgs)' \ $(realpath $(srctree)) $(realpath $(objtree)) \ $(rustc_sysroot) $(RUST_LIB_SRC) $(if $(KBUILD_EXTMOD),$(srcroot)) \ > rust-project.json diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index 2977dfff76b3..b4a55344688d 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -78,7 +78,7 @@ def generate_crates( is_workspace_member: Optional[bool], edition: Optional[str], ) -> Crate: - cfg = cfg if cfg is not None else [] + cfg = cfg if cfg is not None else crates_cfgs.get(display_name, []) is_workspace_member = ( is_workspace_member if is_workspace_member is not None else True ) @@ -203,7 +203,7 @@ def generate_crates( # NB: sysroot crates reexport items from one another so setting up our transitive dependencies # here is important for ensuring that rust-analyzer can resolve symbols. The sources of truth # for this dependency graph are `(sysroot_src / crate / "Cargo.toml" for crate in crates)`. - core = append_sysroot_crate("core", [], cfg=crates_cfgs.get("core", [])) + core = append_sysroot_crate("core", []) alloc = append_sysroot_crate("alloc", [core]) std = append_sysroot_crate("std", [alloc, core]) proc_macro = append_sysroot_crate("proc_macro", [core, std]) @@ -218,14 +218,12 @@ def generate_crates( "proc_macro2", srctree / "rust" / "proc-macro2" / "lib.rs", [core, alloc, std, proc_macro], - cfg=crates_cfgs["proc_macro2"], ) quote = append_crate( "quote", srctree / "rust" / "quote" / "lib.rs", [core, alloc, std, proc_macro, proc_macro2], - cfg=crates_cfgs["quote"], edition="2018", ) @@ -233,7 +231,6 @@ def generate_crates( "syn", srctree / "rust" / "syn" / "lib.rs", [std, proc_macro, proc_macro2, quote], - cfg=crates_cfgs["syn"], ) macros = append_proc_macro_crate( @@ -252,14 +249,12 @@ def generate_crates( "pin_init_internal", srctree / "rust" / "pin-init" / "internal" / "src" / "lib.rs", [std, proc_macro, proc_macro2, quote, syn], - cfg=["kernel"], ) pin_init = append_crate( "pin_init", srctree / "rust" / "pin-init" / "src" / "lib.rs", [core, compiler_builtins, pin_init_internal, macros], - cfg=["kernel"], ) ffi = append_crate( -- cgit v1.2.3 From 7e9535ebd05d7e8de155164b7c97a370d4646e06 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Thu, 2 Apr 2026 10:55:33 +0000 Subject: rust: support overriding crate_name Currently you cannot filter out the crate-name argument RUSTFLAGS_REMOVE_stem.o because the Rust filter-out invocation does not include that particular argument. Since --crate-name is an argument that can't be passed multiple times, this means that it's currently not possible to override the crate name. Thus, remove the --crate-name argument for drivers. This allows them to override the crate name using the #![crate_name] annotation. This affects symbol names, but has no effect on the filenames of object files and other things generated by the build, as we always use --emit with a fixed output filename. The --crate-name argument is kept for the crates under rust/ for simplicity and to avoid changing many of them by adding #![crate_name]. The rust analyzer script is updated to use rustc to obtain the crate name of the driver crates, which picks up the right name whether it is configured via #![crate_name] or not. For readability, the logic to invoke 'rustc' is extracted to its own function. Note that the crate name in the python script is not actually that important - the only place where the name actually affects anything is in the 'deps' array which specifies an index and name for each dependency, and determines what that dependency is called in *this* crate. (The same crate may be called different things in each dependency.) Since driver crates are leaf crates, this doesn't apply and the rustc invocation only affects the 'display_name' parameter. Acked-by: Gary Guo Signed-off-by: Alice Ryhl Reviewed-by: Jesung Yang Acked-by: Tamir Duberstein Link: https://patch.msgid.link/20260402-binder-crate-name-v4-1-ec3919b87909@google.com [ Applied Python type hints. - Miguel ] Signed-off-by: Miguel Ojeda --- scripts/Makefile.build | 1 - scripts/generate_rust_analyzer.py | 46 ++++++++++++++++++++------------------- 2 files changed, 24 insertions(+), 23 deletions(-) (limited to 'scripts/generate_rust_analyzer.py') diff --git a/scripts/Makefile.build b/scripts/Makefile.build index a6d1a2b210aa..0b0245106d01 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -333,7 +333,6 @@ rust_common_cmd = \ -Zcrate-attr='feature($(rust_allowed_features))' \ -Zunstable-options --extern pin_init --extern kernel \ --crate-type rlib -L $(objtree)/rust/ \ - --crate-name $(basename $(notdir $@)) \ --sysroot=/dev/null \ --out-dir $(dir $@) --emit=dep-info=$(depfile) diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index b4a55344688d..d5f9a0ca742c 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -12,6 +12,12 @@ import subprocess import sys from typing import Dict, Iterable, List, Literal, Optional, TypedDict +def invoke_rustc(args: List[str]) -> str: + return subprocess.check_output( + [os.environ["RUSTC"]] + args, + stdin=subprocess.DEVNULL, + ).decode('utf-8').strip() + def args_crates_cfgs(cfgs: List[str]) -> Dict[str, List[str]]: crates_cfgs = {} for cfg in cfgs: @@ -69,6 +75,9 @@ def generate_crates( crates: List[Crate] = [] crates_cfgs = args_crates_cfgs(cfgs) + def get_crate_name(path: pathlib.Path) -> str: + return invoke_rustc(["--print", "crate-name", str(path)]) + def build_crate( display_name: str, root_module: pathlib.Path, @@ -112,23 +121,15 @@ def generate_crates( is_workspace_member=is_workspace_member, edition=edition, ) - proc_macro_dylib_name = ( - subprocess.check_output( - [ - os.environ["RUSTC"], - "--print", - "file-names", - "--crate-name", - display_name, - "--crate-type", - "proc-macro", - "-", - ], - stdin=subprocess.DEVNULL, - ) - .decode("utf-8") - .strip() - ) + proc_macro_dylib_name = invoke_rustc([ + "--print", + "file-names", + "--crate-name", + display_name, + "--crate-type", + "proc-macro", + "-", + ]) proc_macro_crate: ProcMacroCrate = { **crate, "is_proc_macro": True, @@ -324,16 +325,17 @@ def generate_crates( for folder in extra_dirs: for path in folder.rglob("*.rs"): logging.info("Checking %s", path) - name = path.stem + file_name = path.stem # Skip those that are not crate roots. - if not is_root_crate(path.parent / "Makefile", name) and \ - not is_root_crate(path.parent / "Kbuild", name): + if not is_root_crate(path.parent / "Makefile", file_name) and \ + not is_root_crate(path.parent / "Kbuild", file_name): continue - logging.info("Adding %s", name) + crate_name = get_crate_name(path) + logging.info("Adding %s", crate_name) append_crate( - name, + crate_name, path, [core, kernel, pin_init], cfg=generated_cfg, -- cgit v1.2.3