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') 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') 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') 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') 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') 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') 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') 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 --- scripts/generate_rust_analyzer.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'scripts') 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 560a7a9b9267fbe31a68270ca0ad22b6a4db44a5 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 19 Mar 2026 12:16:46 +0000 Subject: rust: add `const_assert!` macro The macro is a more powerful version of `static_assert!` for use inside function contexts. This is powered by inline consts, so enable the feature for old compiler versions that does not have it stably. While it is possible already to write `const { assert!(...) }`, this provides a short hand that is more uniform with other assertions. It also formats nicer with rustfmt where it will not be formatted into multiple lines. Two users that would route via the Rust tree are converted. Reviewed-by: Yury Norov Signed-off-by: Gary Guo Reviewed-by: Alexandre Courbot Reviewed-by: Alice Ryhl Reviewed-by: Danilo Krummrich Link: https://patch.msgid.link/20260319121653.2975748-3-gary@kernel.org [ Rebased. Fixed period typo. - Miguel ] Signed-off-by: Miguel Ojeda --- scripts/Makefile.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 32e209bc7985..0328afd5ee96 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -310,6 +310,7 @@ $(obj)/%.lst: $(obj)/%.c FORCE # The features in this list are the ones allowed for non-`rust/` code. # +# - Stable since Rust 1.79.0: `feature(inline_const)`. # - Stable since Rust 1.81.0: `feature(lint_reasons)`. # - Stable since Rust 1.82.0: `feature(asm_const)`, # `feature(offset_of_nested)`, `feature(raw_ref_op)`. @@ -319,7 +320,7 @@ $(obj)/%.lst: $(obj)/%.c FORCE # # Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on # the unstable features in use. -rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,offset_of_nested,raw_ref_op,used_with_arg +rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,inline_const,lint_reasons,offset_of_nested,raw_ref_op,used_with_arg # `--out-dir` is required to avoid temporaries being created by `rustc` in the # current working directory, which may be not accessible in the out-of-tree -- cgit v1.2.3 From 3a2486cc1da5cf637fe5da4540929d67c4540022 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 3 Feb 2026 11:34:10 +0000 Subject: kbuild: rust: provide an option to inline C helpers into Rust A new experimental Kconfig option, `RUST_INLINE_HELPERS` is added to allow C helpers (which were created to allow Rust to call into inline/macro C functions without having to re-implement the logic in Rust) to be inlined into Rust crates without performing global LTO. If the option is enabled, the following is performed: * For helpers, instead of compiling them to an object file to be linked into vmlinux, they're compiled to LLVM IR bitcode. Two versions are generated: one for built-in code (`helpers.bc`) and one for modules (`helpers_module.bc`, with -DMODULE defined). This ensures that C macros/inlines that behave differently for modules (e.g. static calls) function correctly when inlined. * When a Rust crate or object is compiled, instead of generating an object file, LLVM bitcode is generated. * llvm-link is invoked with --internalize to combine the helper bitcode with the crate bitcode. This step is similar to LTO, but this is much faster since it only needs to inline the helpers. * clang is invoked to turn the combined bitcode into a final object file. * Since clang may produce LLVM bitcode when LTO is enabled, and objtool requires ELF input, $(cmd_ld_single) is invoked to ensure the object is converted to ELF before objtool runs. The --internalize flag tells llvm-link to treat all symbols in helpers.bc using `internal` linkage [1]. This matches the behavior of `clang` on `static inline` functions, and avoids exporting the symbol from the object file. To ensure that RUST_INLINE_HELPERS is not incompatible with BTF, we pass the -g0 flag when building helpers. See commit 5daa0c35a1f0 ("rust: Disallow BTF generation with Rust + LTO") for details. We have an intended triple mismatch of `aarch64-unknown-none` vs `aarch64-unknown-linux-gnu`, so we pass --suppress-warnings to llvm-link to suppress it. I considered adding some sort of check that KBUILD_MODNAME is not present in helpers_module.bc, but this is actually not so easy to carry out because .bc files store strings in a weird binary format, so you cannot just grep it for a string to check whether it ended up using KBUILD_MODNAME anywhere. [ Andreas writes: For the rnull driver, enabling helper inlining with this patch gives an average speedup of 2% over the set of 120 workloads that we publish on [2]. Link: https://rust-for-linux.com/null-block-driver [2] This series also uncovered a pre-existing UB instance thanks to an `objtool` warning which I noticed while testing the series (details in the mailing list). - Miguel ] Link: https://github.com/llvm/llvm-project/pull/170397 [1] Co-developed-by: Boqun Feng Signed-off-by: Boqun Feng Co-developed-by: Matthew Maurer Signed-off-by: Matthew Maurer Signed-off-by: Gary Guo Co-developed-by: Alice Ryhl Signed-off-by: Alice Ryhl Reviewed-by: Nathan Chancellor Tested-by: Nathan Chancellor Tested-by: Andreas Hindborg Reviewed-by: Andreas Hindborg Link: https://patch.msgid.link/20260203-inline-helpers-v2-3-beb8547a03c9@google.com [ Some changes, apart from the rebase: - Added "(EXPERIMENTAL)" to Kconfig as the commit mentions. - Added `depends on ARM64 || X86_64` and `!UML` for now, since this is experimental, other architectures may require other changes (e.g. the issues I mentioned in the mailing list for ARM and UML) and they are not really tested so far. So let arch maintainers pick this up if they think it is worth it. - Gated the `cmd_ld_single` step also into the new mode, which also means that any possible future `objcopy` step is done after the translation, as expected. - Added `.gitignore` for `.bc` with exception for existing script. - Added `part-of-*` for helpers bitcode files as discussed, and dropped `$(if $(filter %_module.bc,$@),-DMODULE)` since `-DMODULE` is already there (would be duplicated otherwise). - Moved `LLVM_LINK` to keep binutils list alphabetized. - Fixed typo in title. - Dropped second `cmd_ld_single` commit message paragraph. - Miguel ] Signed-off-by: Miguel Ojeda --- scripts/Makefile.build | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 0328afd5ee96..a6d1a2b210aa 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -346,7 +346,12 @@ rust_common_cmd = \ # would not match each other. quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ - cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $< $(cmd_objtool) + cmd_rustc_o_rs = $(rust_common_cmd) --emit=$(if $(CONFIG_RUST_INLINE_HELPERS),llvm-bc=$(patsubst %.o,%.bc,$@),obj=$@) $< \ + $(if $(CONFIG_RUST_INLINE_HELPERS),;$(LLVM_LINK) --internalize --suppress-warnings $(patsubst %.o,%.bc,$@) \ + $(objtree)/rust/helpers/helpers$(if $(part-of-module),_module).bc -o $(patsubst %.o,%.m.bc,$@); \ + $(CC) $(CLANG_FLAGS) $(KBUILD_CFLAGS) -Wno-override-module -c $(patsubst %.o,%.m.bc,$@) -o $@ \ + $(cmd_ld_single)) \ + $(cmd_objtool) define rule_rustc_o_rs $(call cmd_and_fixdep,rustc_o_rs) -- 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') 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 From f32fb9c58a5bd436f082dfa12639177b9da87680 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 6 Apr 2026 01:52:41 +0200 Subject: rust: bump Rust minimum supported version to 1.85.0 (Debian Trixie) As proposed in the past in e.g. LPC 2025 and the Maintainers Summit [1], we are going to follow Debian Stable's Rust versions as our minimum supported version. Debian Trixie was released with a Rust 1.85.0 toolchain [2], which it still uses to this day [3] (i.e. no update to Rust 1.85.1). Debian Trixie's release happened on 2025-08-09 [4], which means that a fair amount of time has passed since its release for kernel developers to upgrade. Thus bump the minimum to the new version. Then, in later commits, clean up most of the workarounds and other bits that this upgrade of the minimum allows us. pin-init was left as-is since the patches come from upstream. And the vendored crates are unmodified, since we do not want to change those. Note that the minimum LLVM major version for Rust 1.85.0 is LLVM 18 (the Rust upstream binaries use LLVM 19.1.7), thus e.g. `RUSTC_LLVM_VERSION` tests can also be updated, but there are no suitable ones to simplify. Ubuntu 25.10 also has a recent enough Rust toolchain [5], and they also provide versioned packages with a Rust 1.85.1 toolchain even back to Ubuntu 22.04 LTS [6]. Link: https://lwn.net/Articles/1050174/ [1] Link: https://www.debian.org/releases/trixie/release-notes/whats-new.en.html#desktops-and-well-known-packages [2] Link: https://packages.debian.org/trixie/rustc [3] Link: https://www.debian.org/releases/trixie/ [4] Link: https://packages.ubuntu.com/search?suite=all&searchon=names&keywords=rustc [5] Link: https://launchpad.net/ubuntu/+source/rustc-1.85 [6] Acked-by: Tamir Duberstein Acked-by: Benno Lossin Acked-by: Gary Guo Acked-by: Danilo Krummrich Acked-by: Alice Ryhl Link: https://patch.msgid.link/20260405235309.418950-6-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- scripts/min-tool-version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh index 99b5575c1ef7..a270ec761f64 100755 --- a/scripts/min-tool-version.sh +++ b/scripts/min-tool-version.sh @@ -31,7 +31,7 @@ llvm) fi ;; rustc) - echo 1.78.0 + echo 1.85.0 ;; bindgen) echo 0.65.1 -- cgit v1.2.3 From d1aa40daa777c74439eebf8aed17392e23685768 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 6 Apr 2026 01:52:48 +0200 Subject: rust: kbuild: remove `feature(...)`s that are now stable Now that the Rust minimum version is 1.85.0, there is no need to enable certain features that are stable. Thus clean them up. Reviewed-by: Tamir Duberstein Reviewed-by: Gary Guo Link: https://patch.msgid.link/20260405235309.418950-13-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- scripts/Makefile.build | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'scripts') diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 0b0245106d01..57cff77c2897 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -310,17 +310,13 @@ $(obj)/%.lst: $(obj)/%.c FORCE # The features in this list are the ones allowed for non-`rust/` code. # -# - Stable since Rust 1.79.0: `feature(inline_const)`. -# - Stable since Rust 1.81.0: `feature(lint_reasons)`. -# - Stable since Rust 1.82.0: `feature(asm_const)`, -# `feature(offset_of_nested)`, `feature(raw_ref_op)`. # - Stable since Rust 1.87.0: `feature(asm_goto)`. # - Expected to become stable: `feature(arbitrary_self_types)`. # - To be determined: `feature(used_with_arg)`. # # Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on # the unstable features in use. -rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,inline_const,lint_reasons,offset_of_nested,raw_ref_op,used_with_arg +rust_allowed_features := arbitrary_self_types,asm_goto,used_with_arg # `--out-dir` is required to avoid temporaries being created by `rustc` in the # current working directory, which may be not accessible in the out-of-tree -- cgit v1.2.3 From c3a00a3f31fffc7adcd81b66de3fb2c2f0b11558 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 6 Apr 2026 01:52:53 +0200 Subject: rust: bump `bindgen` minimum supported version to 0.71.1 (Debian Trixie) As proposed in the past in e.g. LPC 2025 and the Maintainers Summit [1], we are going to follow Debian Stable's `bindgen` versions as our minimum supported version. Debian Trixie was released with `bindgen` 0.71.1, which it still uses to this day [2]. Debian Trixie's release happened on 2025-08-09 [3], which means that a fair amount of time has passed since its release for kernel developers to upgrade. Thus bump the minimum to the new version. Then, in later commits, clean up most of the workarounds and other bits that this upgrade of the minimum allows us. Ubuntu 25.10 also has a recent enough `bindgen` [4] (even the already unsupported Ubuntu 25.04 had it), and they also provide versioned packages with `bindgen` 0.71.1 back to Ubuntu 24.04 LTS [5]. Link: https://lwn.net/Articles/1050174/ [1] Link: https://packages.debian.org/trixie/bindgen [2] Link: https://www.debian.org/releases/trixie/ [3] Link: https://packages.ubuntu.com/search?suite=all&searchon=names&keywords=bindgen [4] Link: https://launchpad.net/ubuntu/+source/rust-bindgen-0.71 [5] Acked-by: Tamir Duberstein Reviewed-by: Gary Guo Link: https://patch.msgid.link/20260405235309.418950-18-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- scripts/min-tool-version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh index a270ec761f64..b96ec2d379b6 100755 --- a/scripts/min-tool-version.sh +++ b/scripts/min-tool-version.sh @@ -34,7 +34,7 @@ rustc) echo 1.85.0 ;; bindgen) - echo 0.65.1 + echo 0.71.1 ;; *) echo "$1: unknown tool" >&2 -- cgit v1.2.3 From 41cfbb4295cf9fcdffa6c89ddc84dca2fa392c98 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 6 Apr 2026 01:52:54 +0200 Subject: rust: rust_is_available: remove warning for `bindgen` 0.66.[01] It is not possible anymore to fall into the issue that this warning was alerting about given the `bindgen` version bump. Thus simplify by removing the machinery behind it, including tests. Reviewed-by: Tamir Duberstein Link: https://patch.msgid.link/20260405235309.418950-19-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- scripts/rust_is_available.sh | 13 ------------- scripts/rust_is_available_bindgen_0_66.h | 2 -- scripts/rust_is_available_test.py | 26 +++----------------------- 3 files changed, 3 insertions(+), 38 deletions(-) delete mode 100644 scripts/rust_is_available_bindgen_0_66.h (limited to 'scripts') diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh index d2323de0692c..77896e31dab5 100755 --- a/scripts/rust_is_available.sh +++ b/scripts/rust_is_available.sh @@ -163,19 +163,6 @@ if [ "$rust_bindings_generator_cversion" -lt "$rust_bindings_generator_min_cvers echo >&2 "***" exit 1 fi -if [ "$rust_bindings_generator_cversion" -eq 6600 ] || - [ "$rust_bindings_generator_cversion" -eq 6601 ]; then - # Distributions may have patched the issue (e.g. Debian did). - if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_0_66.h >/dev/null; then - echo >&2 "***" - echo >&2 "*** Rust bindings generator '$BINDGEN' versions 0.66.0 and 0.66.1 may not" - echo >&2 "*** work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/2567)," - echo >&2 "*** unless patched (like Debian's)." - echo >&2 "*** Your version: $rust_bindings_generator_version" - echo >&2 "***" - warning=1 - fi -fi # Check that the `libclang` used by the Rust bindings generator is suitable. # diff --git a/scripts/rust_is_available_bindgen_0_66.h b/scripts/rust_is_available_bindgen_0_66.h deleted file mode 100644 index c0431293421c..000000000000 --- a/scripts/rust_is_available_bindgen_0_66.h +++ /dev/null @@ -1,2 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#define A "\0" diff --git a/scripts/rust_is_available_test.py b/scripts/rust_is_available_test.py index 4fcc319dea84..b66fa5933844 100755 --- a/scripts/rust_is_available_test.py +++ b/scripts/rust_is_available_test.py @@ -54,17 +54,12 @@ else: """) @classmethod - def generate_bindgen(cls, version_stdout, libclang_stderr, version_0_66_patched=False, libclang_concat_patched=False): + def generate_bindgen(cls, version_stdout, libclang_stderr, libclang_concat_patched=False): if libclang_stderr is None: libclang_case = f"raise SystemExit({cls.bindgen_default_bindgen_libclang_failure_exit_code})" else: libclang_case = f"print({repr(libclang_stderr)}, file=sys.stderr)" - if version_0_66_patched: - version_0_66_case = "pass" - else: - version_0_66_case = "raise SystemExit(1)" - if libclang_concat_patched: libclang_concat_case = "print('pub static mut foofoo: ::std::os::raw::c_int;')" else: @@ -74,8 +69,6 @@ else: import sys if "rust_is_available_bindgen_libclang.h" in " ".join(sys.argv): {libclang_case} -elif "rust_is_available_bindgen_0_66.h" in " ".join(sys.argv): - {version_0_66_case} elif "rust_is_available_bindgen_libclang_concat.h" in " ".join(sys.argv): {libclang_concat_case} else: @@ -83,8 +76,8 @@ else: """) @classmethod - def generate_bindgen_version(cls, stdout, version_0_66_patched=False): - return cls.generate_bindgen(stdout, cls.bindgen_default_bindgen_libclang_stderr, version_0_66_patched) + def generate_bindgen_version(cls, stdout): + return cls.generate_bindgen(stdout, cls.bindgen_default_bindgen_libclang_stderr) @classmethod def generate_bindgen_libclang_failure(cls): @@ -245,19 +238,6 @@ else: result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen }) self.assertIn(f"Rust bindings generator '{bindgen}' is too old.", result.stderr) - def test_bindgen_bad_version_0_66_0_and_0_66_1(self): - for version in ("0.66.0", "0.66.1"): - with self.subTest(version=version): - bindgen = self.generate_bindgen_version(f"bindgen {version}") - result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen }) - self.assertIn(f"Rust bindings generator '{bindgen}' versions 0.66.0 and 0.66.1 may not", result.stderr) - - def test_bindgen_bad_version_0_66_0_and_0_66_1_patched(self): - for version in ("0.66.0", "0.66.1"): - with self.subTest(version=version): - bindgen = self.generate_bindgen_version(f"bindgen {version}", True) - result = self.run_script(self.Expected.SUCCESS, { "BINDGEN": bindgen }) - def test_bindgen_libclang_failure(self): bindgen = self.generate_bindgen_libclang_failure() result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen }) -- cgit v1.2.3 From ae64324ad5c1fdefe479d77ecee975bc6b37467b Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 6 Apr 2026 01:52:55 +0200 Subject: rust: rust_is_available: remove warning for `bindgen` < 0.69.5 && libclang >= 19.1 It is not possible anymore to fall into the issue that this warning was alerting about given the `bindgen` version bump. Thus simplify by removing the machinery behind it, including tests. Reviewed-by: Tamir Duberstein Link: https://patch.msgid.link/20260405235309.418950-20-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- scripts/rust_is_available.sh | 15 ---------- .../rust_is_available_bindgen_libclang_concat.h | 3 -- scripts/rust_is_available_test.py | 34 +--------------------- 3 files changed, 1 insertion(+), 51 deletions(-) delete mode 100644 scripts/rust_is_available_bindgen_libclang_concat.h (limited to 'scripts') diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh index 77896e31dab5..cefc456c2503 100755 --- a/scripts/rust_is_available.sh +++ b/scripts/rust_is_available.sh @@ -214,21 +214,6 @@ if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then exit 1 fi -if [ "$bindgen_libclang_cversion" -ge 1900100 ] && - [ "$rust_bindings_generator_cversion" -lt 6905 ]; then - # Distributions may have patched the issue (e.g. Debian did). - if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang_concat.h | grep -q foofoo; then - echo >&2 "***" - echo >&2 "*** Rust bindings generator '$BINDGEN' < 0.69.5 together with libclang >= 19.1" - echo >&2 "*** may not work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/2824)," - echo >&2 "*** unless patched (like Debian's)." - echo >&2 "*** Your bindgen version: $rust_bindings_generator_version" - echo >&2 "*** Your libclang version: $bindgen_libclang_version" - echo >&2 "***" - warning=1 - fi -fi - # If the C compiler is Clang, then we can also check whether its version # matches the `libclang` version used by the Rust bindings generator. # diff --git a/scripts/rust_is_available_bindgen_libclang_concat.h b/scripts/rust_is_available_bindgen_libclang_concat.h deleted file mode 100644 index efc6e98d0f1d..000000000000 --- a/scripts/rust_is_available_bindgen_libclang_concat.h +++ /dev/null @@ -1,3 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#define F(x) int x##x -F(foo); diff --git a/scripts/rust_is_available_test.py b/scripts/rust_is_available_test.py index b66fa5933844..d6d54b7ea42a 100755 --- a/scripts/rust_is_available_test.py +++ b/scripts/rust_is_available_test.py @@ -54,23 +54,16 @@ else: """) @classmethod - def generate_bindgen(cls, version_stdout, libclang_stderr, libclang_concat_patched=False): + def generate_bindgen(cls, version_stdout, libclang_stderr): if libclang_stderr is None: libclang_case = f"raise SystemExit({cls.bindgen_default_bindgen_libclang_failure_exit_code})" else: libclang_case = f"print({repr(libclang_stderr)}, file=sys.stderr)" - if libclang_concat_patched: - libclang_concat_case = "print('pub static mut foofoo: ::std::os::raw::c_int;')" - else: - libclang_concat_case = "pass" - return cls.generate_executable(f"""#!/usr/bin/env python3 import sys if "rust_is_available_bindgen_libclang.h" in " ".join(sys.argv): {libclang_case} -elif "rust_is_available_bindgen_libclang_concat.h" in " ".join(sys.argv): - {libclang_concat_case} else: print({repr(version_stdout)}) """) @@ -255,31 +248,6 @@ else: result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen }) self.assertIn(f"libclang (used by the Rust bindings generator '{bindgen}') is too old.", result.stderr) - def test_bindgen_bad_libclang_concat(self): - for (bindgen_version, libclang_version, expected_not_patched) in ( - ("0.69.4", "18.0.0", self.Expected.SUCCESS), - ("0.69.4", "19.1.0", self.Expected.SUCCESS_WITH_WARNINGS), - ("0.69.4", "19.2.0", self.Expected.SUCCESS_WITH_WARNINGS), - - ("0.69.5", "18.0.0", self.Expected.SUCCESS), - ("0.69.5", "19.1.0", self.Expected.SUCCESS), - ("0.69.5", "19.2.0", self.Expected.SUCCESS), - - ("0.70.0", "18.0.0", self.Expected.SUCCESS), - ("0.70.0", "19.1.0", self.Expected.SUCCESS), - ("0.70.0", "19.2.0", self.Expected.SUCCESS), - ): - with self.subTest(bindgen_version=bindgen_version, libclang_version=libclang_version): - cc = self.generate_clang(f"clang version {libclang_version}") - libclang_stderr = f"scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version {libclang_version} [-W#pragma-messages], err: false" - bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr) - result = self.run_script(expected_not_patched, { "BINDGEN": bindgen, "CC": cc }) - if expected_not_patched == self.Expected.SUCCESS_WITH_WARNINGS: - self.assertIn(f"Rust bindings generator '{bindgen}' < 0.69.5 together with libclang >= 19.1", result.stderr) - - bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr, libclang_concat_patched=True) - result = self.run_script(self.Expected.SUCCESS, { "BINDGEN": bindgen, "CC": cc }) - def test_clang_matches_bindgen_libclang_different_bindgen(self): bindgen = self.generate_bindgen_libclang("scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version 999.0.0 [-W#pragma-messages], err: false") result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen }) -- cgit v1.2.3 From 93553d9922b07555344095b5d9202a3f5b84541c Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 6 Apr 2026 01:52:57 +0200 Subject: rust: kbuild: remove "dummy parameter" workaround for `bindgen` < 0.71.1 Until the version bump of `bindgen`, we needed to pass a dummy parameter to avoid failing the `--version` call. Thus remove it. Reviewed-by: Tamir Duberstein Reviewed-by: Gary Guo Link: https://patch.msgid.link/20260405235309.418950-22-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- scripts/rust_is_available.sh | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'scripts') diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh index cefc456c2503..551f1ebd0dcb 100755 --- a/scripts/rust_is_available.sh +++ b/scripts/rust_is_available.sh @@ -121,14 +121,8 @@ fi # Check that the Rust bindings generator is suitable. # # Non-stable and distributions' versions may have a version suffix, e.g. `-dev`. -# -# The dummy parameter `workaround-for-0.69.0` is required to support 0.69.0 -# (https://github.com/rust-lang/rust-bindgen/pull/2678) and 0.71.0 -# (https://github.com/rust-lang/rust-bindgen/pull/3040). It can be removed when -# the minimum version is upgraded past the latter (0.69.1 and 0.71.1 both fixed -# the issue). rust_bindings_generator_output=$( \ - LC_ALL=C "$BINDGEN" --version workaround-for-0.69.0 2>/dev/null + LC_ALL=C "$BINDGEN" --version 2>/dev/null ) || rust_bindings_generator_code=$? if [ -n "$rust_bindings_generator_code" ]; then echo >&2 "***" -- cgit v1.2.3