Pull Rust updates from Miguel Ojeda: "Toolchain and infrastructure: - Bump the minimum Rust version to 1.85.0 (and 'bindgen' to 0.71.1). As proposed in LPC 2025 and the Maintainers Summit [1], we are going to follow Debian Stable's Rust versions as our minimum versions. Debian Trixie was released on 2025-08-09 with a Rust 1.85.0 and 'bindgen' 0.71.1 toolchain, which is a fair amount of time for e.g. kernel developers to upgrade. Other major distributions support a Rust version that is high enough as well, including: + Arch Linux. + Fedora Linux. + Gentoo Linux. + Nix. + openSUSE Slowroll and openSUSE Tumbleweed. + Ubuntu 25.10 and 26.04 LTS. In addition, 24.04 LTS using their versioned packages. The merged patch series comes with the associated cleanups and simplifications treewide that can be performed thanks to both bumps, as well as documentation updates. In addition, start using 'bindgen''s '--with-attribute-custom-enum' feature to set the 'cfi_encoding' attribute for the 'lru_status' enum used in Binder. Link: https://lwn.net/Articles/1050174/ [1] - Add experimental Kconfig option ('CONFIG_RUST_INLINE_HELPERS') that inlines C helpers into Rust. Essentially, it performs a step similar to LTO, but just for the helpers, i.e. very local and fast. It relies on 'llvm-link' and its '--internalize' flag, and requires a compatible LLVM between Clang and 'rustc' (i.e. same major version, 'CONFIG_RUSTC_CLANG_LLVM_COMPATIBLE'). It is only enabled for two architectures for now. The result is a measurable speedup in different workloads that different users have tested. For instance, for the null block driver, it amounts to a 2%. - Support global per-version flags. While we already have per-version flags in many places, we didn't have a place to set global ones that depend on the compiler version, i.e. in 'rust_common_flags', which sometimes is needed to e.g. tweak the lints set per version. Use that to allow the 'clippy::precedence' lint for Rust < 1.86.0, since it had a change in behavior. - Support overriding the crate name and apply it to Rust Binder, which wanted the module to be called 'rust_binder'. - Add the remaining '__rust_helper' annotations (started in the previous cycle). 'kernel' crate: - Introduce the 'const_assert!' macro: a more powerful version of 'static_assert!' that can refer to generics inside functions or implementation bodies, e.g.: fn f<const N: usize>() { const_assert!(N > 1); } fn g<T>() { const_assert!(size_of::<T>() > 0, "T cannot be ZST"); } In addition, reorganize our set of build-time assertion macros ('{build,const,static_assert}!') to live in the 'build_assert' module. Finally, improve the docs as well to clarify how these are different from one another and how to pick the right one to use, and their equivalence (if any) to the existing C ones for extra clarity. - 'sizes' module: add 'SizeConstants' trait. This gives us typed 'SZ_*' constants (avoiding casts) for use in device address spaces where the address width depends on the hardware (e.g. 32-bit MMIO windows, 64-bit GPU framebuffers, etc.), e.g.: let gpu_heap = 14 * u64::SZ_1M; let mmio_window = u32::SZ_16M; - 'clk' module: implement 'Send' and 'Sync' for 'Clk' and thus simplify the users in Tyr and PWM. - 'ptr' module: add 'const_align_up'. - 'str' module: improve the documentation of the 'c_str!' macro to explain that one should only use it for non-literal cases (for the other case we instead use C string literals, e.g. 'c"abc"'). - Disallow the use of 'CStr::{as_ptr,from_ptr}' and clean one such use in the 'task' module. - 'sync' module: finish the move of 'ARef' and 'AlwaysRefCounted' outside of the 'types' module, i.e. update the last remaining instances and finally remove the re-exports. - 'error' module: clarify that 'from_err_ptr' can return 'Ok(NULL)', including runtime-tested examples. The intention is to hopefully prevent UB that assumes the result of the function is not 'NULL' if successful. This originated from a case of UB I noticed in 'regulator' that created a 'NonNull' on it. Timekeeping: - Expand the example section in the 'HrTimer' documentation. - Mark the 'ClockSource' trait as unsafe to ensure valid values for 'ktime_get()'. - Add 'Delta::from_nanos()'. 'pin-init' crate: - Replace the 'Zeroable' impls for 'Option<NonZero*>' with impls of 'ZeroableOption' for 'NonZero*'. - Improve feature gate handling for unstable features. - Declutter the documentation of implementations of 'Zeroable' for tuples. - Replace uses of 'addr_of[_mut]!' with '&raw [mut]'. rust-analyzer: - Add type annotations to 'generate_rust_analyzer.py'. - Add support for scripts written in Rust ('generate_rust_target.rs', 'rustdoc_test_builder.rs', 'rustdoc_test_gen.rs'). - Refactor 'generate_rust_analyzer.py' to explicitly identify host and target crates, improve readability, and reduce duplication. And some other fixes, cleanups and improvements" * tag 'rust-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (79 commits) rust: sizes: add SizeConstants trait for device address space constants rust: kernel: update `file_with_nul` comment rust: kbuild: allow `clippy::precedence` for Rust < 1.86.0 rust: kbuild: support global per-version flags rust: declare cfi_encoding for lru_status docs: rust: general-information: use real example docs: rust: general-information: simplify Kconfig example docs: rust: quick-start: remove GDB/Binutils mention docs: rust: quick-start: remove Nix "unstable channel" note docs: rust: quick-start: remove Gentoo "testing" note docs: rust: quick-start: add Ubuntu 26.04 LTS and remove subsection title docs: rust: quick-start: update minimum Ubuntu version docs: rust: quick-start: update Ubuntu versioned packages docs: rust: quick-start: openSUSE provides `rust-src` package nowadays rust: kbuild: remove "dummy parameter" workaround for `bindgen` < 0.71.1 rust: kbuild: update `bindgen --rust-target` version and replace comment rust: rust_is_available: remove warning for `bindgen` < 0.69.5 && libclang >= 19.1 rust: rust_is_available: remove warning for `bindgen` 0.66.[01] rust: bump `bindgen` minimum supported version to 0.71.1 (Debian Trixie) rust: block: update `const_refs_to_static` MSRV TODO comment ...
Showing the changes to scripts (7 of 78 files). Show all
Unified · Split
| @@ -310,18 +310,13 @@ $(obj)/%.lst: $(obj)/%.c FORCE · 309 unmodified lines | |||
| 310 | 310 | ||
| 311 | # The features in this list are the ones allowed for non-`rust/` code. | 311 | # The features in this list are the ones allowed for non-`rust/` code. |
| 312 | # | 312 | # |
| 313 | # - Stable since Rust 1.79.0: `feature(slice_ptr_len)`. | ||
| 314 | # - Stable since Rust 1.81.0: `feature(lint_reasons)`. | ||
| 315 | # - Stable since Rust 1.82.0: `feature(asm_const)`, | ||
| 316 | # `feature(offset_of_nested)`, `feature(raw_ref_op)`. | ||
| 317 | # - Stable since Rust 1.84.0: `feature(strict_provenance)`. | ||
| 318 | # - Stable since Rust 1.87.0: `feature(asm_goto)`. | 313 | # - Stable since Rust 1.87.0: `feature(asm_goto)`. |
| 319 | # - Expected to become stable: `feature(arbitrary_self_types)`. | 314 | # - Expected to become stable: `feature(arbitrary_self_types)`. |
| 320 | # - To be determined: `feature(used_with_arg)`. | 315 | # - To be determined: `feature(used_with_arg)`. |
| 321 | # | 316 | # |
| 322 | # Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on | 317 | # Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on |
| 323 | # the unstable features in use. | 318 | # the unstable features in use. |
| 324 | rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,offset_of_nested,raw_ref_op,slice_ptr_len,strict_provenance,used_with_arg | 319 | rust_allowed_features := arbitrary_self_types,asm_goto,used_with_arg |
| 325 | 320 | ||
| 326 | # `--out-dir` is required to avoid temporaries being created by `rustc` in the | 321 | # `--out-dir` is required to avoid temporaries being created by `rustc` in the |
| 327 | # current working directory, which may be not accessible in the out-of-tree | 322 | # current working directory, which may be not accessible in the out-of-tree |
| @@ -334,7 +329,6 @@ rust_common_cmd = \ · 6 unmodified lines | |||
| 334 | -Zcrate-attr='feature($(rust_allowed_features))' \ | 329 | -Zcrate-attr='feature($(rust_allowed_features))' \ |
| 335 | -Zunstable-options --extern pin_init --extern kernel \ | 330 | -Zunstable-options --extern pin_init --extern kernel \ |
| 336 | --crate-type rlib -L $(objtree)/rust/ \ | 331 | --crate-type rlib -L $(objtree)/rust/ \ |
| 337 | --crate-name $(basename $(notdir $@)) \ | ||
| 338 | --sysroot=/dev/null \ | 332 | --sysroot=/dev/null \ |
| 339 | --out-dir $(dir $@) --emit=dep-info=$(depfile) | 333 | --out-dir $(dir $@) --emit=dep-info=$(depfile) |
| 340 | 334 | ||
| @@ -347,7 +341,12 @@ rust_common_cmd = \ · 6 unmodified lines | |||
| 347 | # would not match each other. | 341 | # would not match each other. |
| 348 | 342 | ||
| 349 | quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ | 343 | quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ |
| 350 | cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $< $(cmd_objtool) | 344 | cmd_rustc_o_rs = $(rust_common_cmd) --emit=$(if $(CONFIG_RUST_INLINE_HELPERS),llvm-bc=$(patsubst %.o,%.bc,$@),obj=$@) $< \ |
| 345 | $(if $(CONFIG_RUST_INLINE_HELPERS),;$(LLVM_LINK) --internalize --suppress-warnings $(patsubst %.o,%.bc,$@) \ | ||
| 346 | $(objtree)/rust/helpers/helpers$(if $(part-of-module),_module).bc -o $(patsubst %.o,%.m.bc,$@); \ | ||
| 347 | $(CC) $(CLANG_FLAGS) $(KBUILD_CFLAGS) -Wno-override-module -c $(patsubst %.o,%.m.bc,$@) -o $@ \ | ||
| 348 | $(cmd_ld_single)) \ | ||
| 349 | $(cmd_objtool) | ||
| 351 | 350 | ||
| 352 | define rule_rustc_o_rs | 351 | define rule_rustc_o_rs |
| 353 | $(call cmd_and_fixdep,rustc_o_rs) | 352 | $(call cmd_and_fixdep,rustc_o_rs) |
| @@ -10,8 +10,15 @@ import os · 9 unmodified lines | |||
| 10 | import pathlib | 10 | import pathlib |
| 11 | import subprocess | 11 | import subprocess |
| 12 | import sys | 12 | import sys |
| 13 | from typing import Dict, Iterable, List, Literal, Optional, TypedDict | ||
| 13 | 14 | ||
| 14 | def args_crates_cfgs(cfgs): | 15 | def invoke_rustc(args: List[str]) -> str: |
| 16 | return subprocess.check_output( | ||
| 17 | [os.environ["RUSTC"]] + args, | ||
| 18 | stdin=subprocess.DEVNULL, | ||
| 19 | ).decode('utf-8').strip() | ||
| 20 | |||
| 21 | def args_crates_cfgs(cfgs: List[str]) -> Dict[str, List[str]]: | ||
| 15 | crates_cfgs = {} | 22 | crates_cfgs = {} |
| 16 | for cfg in cfgs: | 23 | for cfg in cfgs: |
| 17 | crate, vals = cfg.split("=", 1) | 24 | crate, vals = cfg.split("=", 1) |
| @@ -19,54 +26,153 @@ def args_crates_cfgs(cfgs): · 1 unmodified line | |||
| 19 | 26 | ||
| 20 | return crates_cfgs | 27 | return crates_cfgs |
| 21 | 28 | ||
| 22 | def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edition): | 29 | class Dependency(TypedDict): |
| 30 | crate: int | ||
| 31 | name: str | ||
| 32 | |||
| 33 | |||
| 34 | class Source(TypedDict): | ||
| 35 | include_dirs: List[str] | ||
| 36 | exclude_dirs: List[str] | ||
| 37 | |||
| 38 | |||
| 39 | class Crate(TypedDict): | ||
| 40 | display_name: str | ||
| 41 | root_module: str | ||
| 42 | is_workspace_member: bool | ||
| 43 | deps: List[Dependency] | ||
| 44 | cfg: List[str] | ||
| 45 | edition: str | ||
| 46 | env: Dict[str, str] | ||
| 47 | |||
| 48 | |||
| 49 | class ProcMacroCrate(Crate): | ||
| 50 | is_proc_macro: Literal[True] | ||
| 51 | proc_macro_dylib_path: str # `pathlib.Path` is not JSON serializable. | ||
| 52 | |||
| 53 | |||
| 54 | class CrateWithGenerated(Crate): | ||
| 55 | source: Source | ||
| 56 | |||
| 57 | |||
| 58 | def generate_crates( | ||
| 59 | srctree: pathlib.Path, | ||
| 60 | objtree: pathlib.Path, | ||
| 61 | sysroot_src: pathlib.Path, | ||
| 62 | external_src: Optional[pathlib.Path], | ||
| 63 | cfgs: List[str], | ||
| 64 | core_edition: str, | ||
| 65 | ) -> List[Crate]: | ||
| 23 | # Generate the configuration list. | 66 | # Generate the configuration list. |
| 24 | cfg = [] | 67 | generated_cfg = [] |
| 25 | with open(objtree / "include" / "generated" / "rustc_cfg") as fd: | 68 | with open(objtree / "include" / "generated" / "rustc_cfg") as fd: |
| 26 | for line in fd: | 69 | for line in fd: |
| 27 | line = line.replace("--cfg=", "") | 70 | line = line.replace("--cfg=", "") |
| 28 | line = line.replace("\n", "") | 71 | line = line.replace("\n", "") |
| 29 | cfg.append(line) | 72 | generated_cfg.append(line) |
| 30 | 73 | ||
| 31 | # Now fill the crates list -- dependencies need to come first. | 74 | # Now fill the crates list. |
| 32 | # | 75 | crates: List[Crate] = [] |
| 33 | # Avoid O(n^2) iterations by keeping a map of indexes. | ||
| 34 | crates = [] | ||
| 35 | crates_indexes = {} | ||
| 36 | crates_cfgs = args_crates_cfgs(cfgs) | 76 | crates_cfgs = args_crates_cfgs(cfgs) |
| 37 | 77 | ||
| 38 | def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False, edition="2021"): | 78 | def get_crate_name(path: pathlib.Path) -> str: |
| 39 | crate = { | 79 | return invoke_rustc(["--print", "crate-name", str(path)]) |
| 80 | |||
| 81 | def build_crate( | ||
| 82 | display_name: str, | ||
| 83 | root_module: pathlib.Path, | ||
| 84 | deps: List[Dependency], | ||
| 85 | *, | ||
| 86 | cfg: Optional[List[str]], | ||
| 87 | is_workspace_member: Optional[bool], | ||
| 88 | edition: Optional[str], | ||
| 89 | ) -> Crate: | ||
| 90 | cfg = cfg if cfg is not None else crates_cfgs.get(display_name, []) | ||
| 91 | is_workspace_member = ( | ||
| 92 | is_workspace_member if is_workspace_member is not None else True | ||
| 93 | ) | ||
| 94 | edition = edition if edition is not None else "2021" | ||
| 95 | return { | ||
| 40 | "display_name": display_name, | 96 | "display_name": display_name, |
| 41 | "root_module": str(root_module), | 97 | "root_module": str(root_module), |
| 42 | "is_workspace_member": is_workspace_member, | 98 | "is_workspace_member": is_workspace_member, |
| 43 | "is_proc_macro": is_proc_macro, | 99 | "deps": deps, |
| 44 | "deps": [{"crate": crates_indexes[dep], "name": dep} for dep in deps], | ||
| 45 | "cfg": cfg, | 100 | "cfg": cfg, |
| 46 | "edition": edition, | 101 | "edition": edition, |
| 47 | "env": { | 102 | "env": { |
| 48 | "RUST_MODFILE": "This is only for rust-analyzer" | 103 | "RUST_MODFILE": "This is only for rust-analyzer" |
| 49 | } | 104 | } |
| 50 | } | 105 | } |
| 51 | if is_proc_macro: | 106 | |
| 52 | proc_macro_dylib_name = subprocess.check_output( | 107 | def append_proc_macro_crate( |
| 53 | [os.environ["RUSTC"], "--print", "file-names", "--crate-name", display_name, "--crate-type", "proc-macro", "-"], | 108 | display_name: str, |
| 54 | stdin=subprocess.DEVNULL, | 109 | root_module: pathlib.Path, |
| 55 | ).decode('utf-8').strip() | 110 | deps: List[Dependency], |
| 56 | crate["proc_macro_dylib_path"] = f"{objtree}/rust/{proc_macro_dylib_name}" | 111 | *, |
| 57 | crates_indexes[display_name] = len(crates) | 112 | cfg: Optional[List[str]] = None, |
| 113 | is_workspace_member: Optional[bool] = None, | ||
| 114 | edition: Optional[str] = None, | ||
| 115 | ) -> Dependency: | ||
| 116 | crate = build_crate( | ||
| 117 | display_name, | ||
| 118 | root_module, | ||
| 119 | deps, | ||
| 120 | cfg=cfg, | ||
| 121 | is_workspace_member=is_workspace_member, | ||
| 122 | edition=edition, | ||
| 123 | ) | ||
| 124 | proc_macro_dylib_name = invoke_rustc([ | ||
| 125 | "--print", | ||
| 126 | "file-names", | ||
| 127 | "--crate-name", | ||
| 128 | display_name, | ||
| 129 | "--crate-type", | ||
| 130 | "proc-macro", | ||
| 131 | "-", | ||
| 132 | ]) | ||
| 133 | proc_macro_crate: ProcMacroCrate = { | ||
| 134 | **crate, | ||
| 135 | "is_proc_macro": True, | ||
| 136 | "proc_macro_dylib_path": str(objtree / "rust" / proc_macro_dylib_name), | ||
| 137 | } | ||
| 138 | return register_crate(proc_macro_crate) | ||
| 139 | |||
| 140 | def register_crate(crate: Crate) -> Dependency: | ||
| 141 | index = len(crates) | ||
| 58 | crates.append(crate) | 142 | crates.append(crate) |
| 143 | return {"crate": index, "name": crate["display_name"]} | ||
| 144 | |||
| 145 | def append_crate( | ||
| 146 | display_name: str, | ||
| 147 | root_module: pathlib.Path, | ||
| 148 | deps: List[Dependency], | ||
| 149 | *, | ||
| 150 | cfg: Optional[List[str]] = None, | ||
| 151 | is_workspace_member: Optional[bool] = None, | ||
| 152 | edition: Optional[str] = None, | ||
| 153 | ) -> Dependency: | ||
| 154 | return register_crate( | ||
| 155 | build_crate( | ||
| 156 | display_name, | ||
| 157 | root_module, | ||
| 158 | deps, | ||
| 159 | cfg=cfg, | ||
| 160 | is_workspace_member=is_workspace_member, | ||
| 161 | edition=edition, | ||
| 162 | ) | ||
| 163 | ) | ||
| 59 | 164 | ||
| 60 | def append_sysroot_crate( | 165 | def append_sysroot_crate( |
| 61 | display_name, | 166 | display_name: str, |
| 62 | deps, | 167 | deps: List[Dependency], |
| 63 | cfg=[], | 168 | *, |
| 64 | ): | 169 | cfg: Optional[List[str]] = None, |
| 65 | append_crate( | 170 | ) -> Dependency: |
| 171 | return append_crate( | ||
| 66 | display_name, | 172 | display_name, |
| 67 | sysroot_src / display_name / "src" / "lib.rs", | 173 | sysroot_src / display_name / "src" / "lib.rs", |
| 68 | deps, | 174 | deps, |
| 69 | cfg, | 175 | cfg=cfg, |
| 70 | is_workspace_member=False, | 176 | is_workspace_member=False, |
| 71 | # Miguel Ojeda writes: | 177 | # Miguel Ojeda writes: |
| 72 | # | 178 | # |
| @@ -98,129 +204,146 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit · 25 unmodified lines | |||
| 98 | # NB: sysroot crates reexport items from one another so setting up our transitive dependencies | 204 | # NB: sysroot crates reexport items from one another so setting up our transitive dependencies |
| 99 | # here is important for ensuring that rust-analyzer can resolve symbols. The sources of truth | 205 | # here is important for ensuring that rust-analyzer can resolve symbols. The sources of truth |
| 100 | # for this dependency graph are `(sysroot_src / crate / "Cargo.toml" for crate in crates)`. | 206 | # for this dependency graph are `(sysroot_src / crate / "Cargo.toml" for crate in crates)`. |
| 101 | append_sysroot_crate("core", [], cfg=crates_cfgs.get("core", [])) | 207 | core = append_sysroot_crate("core", []) |
| 102 | append_sysroot_crate("alloc", ["core"]) | 208 | alloc = append_sysroot_crate("alloc", [core]) |
| 103 | append_sysroot_crate("std", ["alloc", "core"]) | 209 | std = append_sysroot_crate("std", [alloc, core]) |
| 104 | append_sysroot_crate("proc_macro", ["core", "std"]) | 210 | proc_macro = append_sysroot_crate("proc_macro", [core, std]) |
| 105 | 211 | ||
| 106 | append_crate( | 212 | compiler_builtins = append_crate( |
| 107 | "compiler_builtins", | 213 | "compiler_builtins", |
| 108 | srctree / "rust" / "compiler_builtins.rs", | 214 | srctree / "rust" / "compiler_builtins.rs", |
| 109 | ["core"], | 215 | [core], |
| 110 | ) | 216 | ) |
| 111 | 217 | ||
| 112 | append_crate( | 218 | proc_macro2 = append_crate( |
| 113 | "proc_macro2", | 219 | "proc_macro2", |
| 114 | srctree / "rust" / "proc-macro2" / "lib.rs", | 220 | srctree / "rust" / "proc-macro2" / "lib.rs", |
| 115 | ["core", "alloc", "std", "proc_macro"], | 221 | [core, alloc, std, proc_macro], |
| 116 | cfg=crates_cfgs["proc_macro2"], | ||
| 117 | ) | 222 | ) |
| 118 | 223 | ||
| 119 | append_crate( | 224 | quote = append_crate( |
| 120 | "quote", | 225 | "quote", |
| 121 | srctree / "rust" / "quote" / "lib.rs", | 226 | srctree / "rust" / "quote" / "lib.rs", |
| 122 | ["core", "alloc", "std", "proc_macro", "proc_macro2"], | 227 | [core, alloc, std, proc_macro, proc_macro2], |
| 123 | cfg=crates_cfgs["quote"], | ||
| 124 | edition="2018", | 228 | edition="2018", |
| 125 | ) | 229 | ) |
| 126 | 230 | ||
| 127 | append_crate( | 231 | syn = append_crate( |
| 128 | "syn", | 232 | "syn", |
| 129 | srctree / "rust" / "syn" / "lib.rs", | 233 | srctree / "rust" / "syn" / "lib.rs", |
| 130 | ["std", "proc_macro", "proc_macro2", "quote"], | 234 | [std, proc_macro, proc_macro2, quote], |
| 131 | cfg=crates_cfgs["syn"], | ||
| 132 | ) | 235 | ) |
| 133 | 236 | ||
| 134 | append_crate( | 237 | macros = append_proc_macro_crate( |
| 135 | "macros", | 238 | "macros", |
| 136 | srctree / "rust" / "macros" / "lib.rs", | 239 | srctree / "rust" / "macros" / "lib.rs", |
| 137 | ["std", "proc_macro", "proc_macro2", "quote", "syn"], | 240 | [std, proc_macro, proc_macro2, quote, syn], |
| 138 | is_proc_macro=True, | ||
| 139 | ) | 241 | ) |
| 140 | 242 | ||
| 141 | append_crate( | 243 | build_error = append_crate( |
| 142 | "build_error", | 244 | "build_error", |
| 143 | srctree / "rust" / "build_error.rs", | 245 | srctree / "rust" / "build_error.rs", |
| 144 | ["core", "compiler_builtins"], | 246 | [core, compiler_builtins], |
| 145 | ) | 247 | ) |
| 146 | 248 | ||
| 147 | append_crate( | 249 | pin_init_internal = append_proc_macro_crate( |
| 148 | "pin_init_internal", | 250 | "pin_init_internal", |
| 149 | srctree / "rust" / "pin-init" / "internal" / "src" / "lib.rs", | 251 | srctree / "rust" / "pin-init" / "internal" / "src" / "lib.rs", |
| 150 | ["std", "proc_macro", "proc_macro2", "quote", "syn"], | 252 | [std, proc_macro, proc_macro2, quote, syn], |
| 151 | cfg=["kernel"], | ||
| 152 | is_proc_macro=True, | ||
| 153 | ) | 253 | ) |
| 154 | 254 | ||
| 155 | append_crate( | 255 | pin_init = append_crate( |
| 156 | "pin_init", | 256 | "pin_init", |
| 157 | srctree / "rust" / "pin-init" / "src" / "lib.rs", | 257 | srctree / "rust" / "pin-init" / "src" / "lib.rs", |
| 158 | ["core", "compiler_builtins", "pin_init_internal", "macros"], | 258 | [core, compiler_builtins, pin_init_internal, macros], |
| 159 | cfg=["kernel"], | ||
| 160 | ) | 259 | ) |
| 161 | 260 | ||
| 162 | append_crate( | 261 | ffi = append_crate( |
| 163 | "ffi", | 262 | "ffi", |
| 164 | srctree / "rust" / "ffi.rs", | 263 | srctree / "rust" / "ffi.rs", |
| 165 | ["core", "compiler_builtins"], | 264 | [core, compiler_builtins], |
| 166 | ) | 265 | ) |
| 167 | 266 | ||
| 168 | def append_crate_with_generated( | 267 | def append_crate_with_generated( |
| 169 | display_name, | 268 | display_name: str, |
| 170 | deps, | 269 | deps: List[Dependency], |
| 171 | ): | 270 | ) -> Dependency: |
| 172 | append_crate( | 271 | crate = build_crate( |
| 173 | display_name, | 272 | display_name, |
| 174 | srctree / "rust"/ display_name / "lib.rs", | 273 | srctree / "rust"/ display_name / "lib.rs", |
| 175 | deps, | 274 | deps, |
| 176 | cfg=cfg, | 275 | cfg=generated_cfg, |
| 276 | is_workspace_member=True, | ||
| 277 | edition=None, | ||
| 177 | ) | 278 | ) |
| 178 | crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True)) | 279 | crate["env"]["OBJTREE"] = str(objtree.resolve(True)) |
| 179 | crates[-1]["source"] = { | 280 | crate_with_generated: CrateWithGenerated = { |
| 180 | "include_dirs": [ | 281 | **crate, |
| 181 | str(srctree / "rust" / display_name), | 282 | "source": { |
| 182 | str(objtree / "rust") | 283 | "include_dirs": [ |
| 183 | ], | 284 | str(srctree / "rust" / display_name), |
| 184 | "exclude_dirs": [], | 285 | str(objtree / "rust"), |
| 286 | ], | ||
| 287 | "exclude_dirs": [], | ||
| 288 | }, | ||
| 185 | } | 289 | } |
| 290 | return register_crate(crate_with_generated) | ||
| 291 | |||
| 292 | bindings = append_crate_with_generated("bindings", [core, ffi, pin_init]) | ||
| 293 | uapi = append_crate_with_generated("uapi", [core, ffi, pin_init]) | ||
| 294 | kernel = append_crate_with_generated( | ||
| 295 | "kernel", [core, macros, build_error, pin_init, ffi, bindings, uapi] | ||
| 296 | ) | ||
| 186 | 297 | ||
| 187 | append_crate_with_generated("bindings", ["core", "ffi", "pin_init"]) | 298 | scripts = srctree / "scripts" |
| 188 | append_crate_with_generated("uapi", ["core", "ffi", "pin_init"]) | 299 | makefile = (scripts / "Makefile").read_text() |
| 189 | append_crate_with_generated("kernel", ["core", "macros", "build_error", "pin_init", "ffi", "bindings", "uapi"]) | 300 | for path in scripts.glob("*.rs"): |
| 301 | name = path.stem | ||
| 302 | if f"{name}-rust" not in makefile: | ||
| 303 | continue | ||
| 304 | append_crate( | ||
| 305 | name, | ||
| 306 | path, | ||
| 307 | [std], | ||
| 308 | ) | ||
| 190 | 309 | ||
| 191 | def is_root_crate(build_file, target): | 310 | def is_root_crate(build_file: pathlib.Path, target: str) -> bool: |
| 192 | try: | 311 | try: |
| 193 | return f"{target}.o" in open(build_file).read() | 312 | contents = build_file.read_text() |
| 194 | except FileNotFoundError: | 313 | except FileNotFoundError: |
| 195 | return False | 314 | return False |
| 315 | return f"{target}.o" in contents | ||
| 196 | 316 | ||
| 197 | # Then, the rest outside of `rust/`. | 317 | # Then, the rest outside of `rust/`. |
| 198 | # | 318 | # |
| 199 | # We explicitly mention the top-level folders we want to cover. | 319 | # We explicitly mention the top-level folders we want to cover. |
| 200 | extra_dirs = map(lambda dir: srctree / dir, ("samples", "drivers")) | 320 | extra_dirs: Iterable[pathlib.Path] = ( |
| 321 | srctree / dir for dir in ("samples", "drivers") | ||
| 322 | ) | ||
| 201 | if external_src is not None: | 323 | if external_src is not None: |
| 202 | extra_dirs = [external_src] | 324 | extra_dirs = [external_src] |
| 203 | for folder in extra_dirs: | 325 | for folder in extra_dirs: |
| 204 | for path in folder.rglob("*.rs"): | 326 | for path in folder.rglob("*.rs"): |
| 205 | logging.info("Checking %s", path) | 327 | logging.info("Checking %s", path) |
| 206 | name = path.name.replace(".rs", "") | 328 | file_name = path.stem |
| 207 | 329 | ||
| 208 | # Skip those that are not crate roots. | 330 | # Skip those that are not crate roots. |
| 209 | if not is_root_crate(path.parent / "Makefile", name) and \ | 331 | if not is_root_crate(path.parent / "Makefile", file_name) and \ |
| 210 | not is_root_crate(path.parent / "Kbuild", name): | 332 | not is_root_crate(path.parent / "Kbuild", file_name): |
| 211 | continue | 333 | continue |
| 212 | 334 | ||
| 213 | logging.info("Adding %s", name) | 335 | crate_name = get_crate_name(path) |
| 336 | logging.info("Adding %s", crate_name) | ||
| 214 | append_crate( | 337 | append_crate( |
| 215 | name, | 338 | crate_name, |
| 216 | path, | 339 | path, |
| 217 | ["core", "kernel", "pin_init"], | 340 | [core, kernel, pin_init], |
| 218 | cfg=cfg, | 341 | cfg=generated_cfg, |
| 219 | ) | 342 | ) |
| 220 | 343 | ||
| 221 | return crates | 344 | return crates |
| 222 | 345 | ||
| 223 | def main(): | 346 | def main() -> None: |
| 224 | parser = argparse.ArgumentParser() | 347 | parser = argparse.ArgumentParser() |
| 225 | parser.add_argument('--verbose', '-v', action='store_true') | 348 | parser.add_argument('--verbose', '-v', action='store_true') |
| 226 | parser.add_argument('--cfgs', action='append', default=[]) | 349 | parser.add_argument('--cfgs', action='append', default=[]) |
| @@ -230,7 +353,18 @@ def main(): · 3 unmodified lines | |||
| 230 | parser.add_argument("sysroot", type=pathlib.Path) | 353 | parser.add_argument("sysroot", type=pathlib.Path) |
| 231 | parser.add_argument("sysroot_src", type=pathlib.Path) | 354 | parser.add_argument("sysroot_src", type=pathlib.Path) |
| 232 | parser.add_argument("exttree", type=pathlib.Path, nargs="?") | 355 | parser.add_argument("exttree", type=pathlib.Path, nargs="?") |
| 233 | args = parser.parse_args() | 356 | |
| 357 | class Args(argparse.Namespace): | ||
| 358 | verbose: bool | ||
| 359 | cfgs: List[str] | ||
| 360 | srctree: pathlib.Path | ||
| 361 | objtree: pathlib.Path | ||
| 362 | sysroot: pathlib.Path | ||
| 363 | sysroot_src: pathlib.Path | ||
| 364 | exttree: Optional[pathlib.Path] | ||
| 365 | core_edition: str | ||
| 366 | |||
| 367 | args = parser.parse_args(namespace=Args()) | ||
| 234 | 368 | ||
| 235 | logging.basicConfig( | 369 | logging.basicConfig( |
| 236 | format="[%(asctime)s] [%(levelname)s] %(message)s", | 370 | format="[%(asctime)s] [%(levelname)s] %(message)s", |
| @@ -31,10 +31,10 @@ llvm) · 30 unmodified lines | |||
| 31 | fi | 31 | fi |
| 32 | ;; | 32 | ;; |
| 33 | rustc) | 33 | rustc) |
| 34 | echo 1.78.0 | 34 | echo 1.85.0 |
| 35 | ;; | 35 | ;; |
| 36 | bindgen) | 36 | bindgen) |
| 37 | echo 0.65.1 | 37 | echo 0.71.1 |
| 38 | ;; | 38 | ;; |
| 39 | *) | 39 | *) |
| 40 | echo "$1: unknown tool" >&2 | 40 | echo "$1: unknown tool" >&2 |
| @@ -121,14 +121,8 @@ fi · 120 unmodified lines | |||
| 121 | # Check that the Rust bindings generator is suitable. | 121 | # Check that the Rust bindings generator is suitable. |
| 122 | # | 122 | # |
| 123 | # Non-stable and distributions' versions may have a version suffix, e.g. `-dev`. | 123 | # Non-stable and distributions' versions may have a version suffix, e.g. `-dev`. |
| 124 | # | ||
| 125 | # The dummy parameter `workaround-for-0.69.0` is required to support 0.69.0 | ||
| 126 | # (https://github.com/rust-lang/rust-bindgen/pull/2678) and 0.71.0 | ||
| 127 | # (https://github.com/rust-lang/rust-bindgen/pull/3040). It can be removed when | ||
| 128 | # the minimum version is upgraded past the latter (0.69.1 and 0.71.1 both fixed | ||
| 129 | # the issue). | ||
| 130 | rust_bindings_generator_output=$( \ | 124 | rust_bindings_generator_output=$( \ |
| 131 | LC_ALL=C "$BINDGEN" --version workaround-for-0.69.0 2>/dev/null | 125 | LC_ALL=C "$BINDGEN" --version 2>/dev/null |
| 132 | ) || rust_bindings_generator_code=$? | 126 | ) || rust_bindings_generator_code=$? |
| 133 | if [ -n "$rust_bindings_generator_code" ]; then | 127 | if [ -n "$rust_bindings_generator_code" ]; then |
| 134 | echo >&2 "***" | 128 | echo >&2 "***" |
| @@ -163,19 +157,6 @@ if [ "$rust_bindings_generator_cversion" -lt "$rust_bindings_generator_min_cvers · 28 unmodified lines | |||
| 163 | echo >&2 "***" | 157 | echo >&2 "***" |
| 164 | exit 1 | 158 | exit 1 |
| 165 | fi | 159 | fi |
| 166 | if [ "$rust_bindings_generator_cversion" -eq 6600 ] || | ||
| 167 | [ "$rust_bindings_generator_cversion" -eq 6601 ]; then | ||
| 168 | # Distributions may have patched the issue (e.g. Debian did). | ||
| 169 | if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_0_66.h >/dev/null; then | ||
| 170 | echo >&2 "***" | ||
| 171 | echo >&2 "*** Rust bindings generator '$BINDGEN' versions 0.66.0 and 0.66.1 may not" | ||
| 172 | echo >&2 "*** work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/2567)," | ||
| 173 | echo >&2 "*** unless patched (like Debian's)." | ||
| 174 | echo >&2 "*** Your version: $rust_bindings_generator_version" | ||
| 175 | echo >&2 "***" | ||
| 176 | warning=1 | ||
| 177 | fi | ||
| 178 | fi | ||
| 179 | 160 | ||
| 180 | # Check that the `libclang` used by the Rust bindings generator is suitable. | 161 | # Check that the `libclang` used by the Rust bindings generator is suitable. |
| 181 | # | 162 | # |
| @@ -227,21 +208,6 @@ if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then · 45 unmodified lines | |||
| 227 | exit 1 | 208 | exit 1 |
| 228 | fi | 209 | fi |
| 229 | 210 | ||
| 230 | if [ "$bindgen_libclang_cversion" -ge 1900100 ] && | ||
| 231 | [ "$rust_bindings_generator_cversion" -lt 6905 ]; then | ||
| 232 | # Distributions may have patched the issue (e.g. Debian did). | ||
| 233 | if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang_concat.h | grep -q foofoo; then | ||
| 234 | echo >&2 "***" | ||
| 235 | echo >&2 "*** Rust bindings generator '$BINDGEN' < 0.69.5 together with libclang >= 19.1" | ||
| 236 | echo >&2 "*** may not work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/2824)," | ||
| 237 | echo >&2 "*** unless patched (like Debian's)." | ||
| 238 | echo >&2 "*** Your bindgen version: $rust_bindings_generator_version" | ||
| 239 | echo >&2 "*** Your libclang version: $bindgen_libclang_version" | ||
| 240 | echo >&2 "***" | ||
| 241 | warning=1 | ||
| 242 | fi | ||
| 243 | fi | ||
| 244 | |||
| 245 | # If the C compiler is Clang, then we can also check whether its version | 211 | # If the C compiler is Clang, then we can also check whether its version |
| 246 | # matches the `libclang` version used by the Rust bindings generator. | 212 | # matches the `libclang` version used by the Rust bindings generator. |
| 247 | # | 213 | # |
| @@ -1,2 +0,0 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #define A "\0" | ||
| @@ -1,3 +0,0 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #define F(x) int x##x | ||
| 3 | F(foo); | ||
| @@ -54,37 +54,23 @@ else: · 53 unmodified lines | |||
| 54 | """) | 54 | """) |
| 55 | 55 | ||
| 56 | @classmethod | 56 | @classmethod |
| 57 | def generate_bindgen(cls, version_stdout, libclang_stderr, version_0_66_patched=False, libclang_concat_patched=False): | 57 | def generate_bindgen(cls, version_stdout, libclang_stderr): |
| 58 | if libclang_stderr is None: | 58 | if libclang_stderr is None: |
| 59 | libclang_case = f"raise SystemExit({cls.bindgen_default_bindgen_libclang_failure_exit_code})" | 59 | libclang_case = f"raise SystemExit({cls.bindgen_default_bindgen_libclang_failure_exit_code})" |
| 60 | else: | 60 | else: |
| 61 | libclang_case = f"print({repr(libclang_stderr)}, file=sys.stderr)" | 61 | libclang_case = f"print({repr(libclang_stderr)}, file=sys.stderr)" |
| 62 | 62 | ||
| 63 | if version_0_66_patched: | ||
| 64 | version_0_66_case = "pass" | ||
| 65 | else: | ||
| 66 | version_0_66_case = "raise SystemExit(1)" | ||
| 67 | |||
| 68 | if libclang_concat_patched: | ||
| 69 | libclang_concat_case = "print('pub static mut foofoo: ::std::os::raw::c_int;')" | ||
| 70 | else: | ||
| 71 | libclang_concat_case = "pass" | ||
| 72 | |||
| 73 | return cls.generate_executable(f"""#!/usr/bin/env python3 | 63 | return cls.generate_executable(f"""#!/usr/bin/env python3 |
| 74 | import sys | 64 | import sys |
| 75 | if "rust_is_available_bindgen_libclang.h" in " ".join(sys.argv): | 65 | if "rust_is_available_bindgen_libclang.h" in " ".join(sys.argv): |
| 76 | {libclang_case} | 66 | {libclang_case} |
| 77 | elif "rust_is_available_bindgen_0_66.h" in " ".join(sys.argv): | ||
| 78 | {version_0_66_case} | ||
| 79 | elif "rust_is_available_bindgen_libclang_concat.h" in " ".join(sys.argv): | ||
| 80 | {libclang_concat_case} | ||
| 81 | else: | 67 | else: |
| 82 | print({repr(version_stdout)}) | 68 | print({repr(version_stdout)}) |
| 83 | """) | 69 | """) |
| 84 | 70 | ||
| 85 | @classmethod | 71 | @classmethod |
| 86 | def generate_bindgen_version(cls, stdout, version_0_66_patched=False): | 72 | def generate_bindgen_version(cls, stdout): |
| 87 | return cls.generate_bindgen(stdout, cls.bindgen_default_bindgen_libclang_stderr, version_0_66_patched) | 73 | return cls.generate_bindgen(stdout, cls.bindgen_default_bindgen_libclang_stderr) |
| 88 | 74 | ||
| 89 | @classmethod | 75 | @classmethod |
| 90 | def generate_bindgen_libclang_failure(cls): | 76 | def generate_bindgen_libclang_failure(cls): |
| @@ -245,19 +231,6 @@ else: · 154 unmodified lines | |||
| 245 | result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen }) | 231 | result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen }) |
| 246 | self.assertIn(f"Rust bindings generator '{bindgen}' is too old.", result.stderr) | 232 | self.assertIn(f"Rust bindings generator '{bindgen}' is too old.", result.stderr) |
| 247 | 233 | ||
| 248 | def test_bindgen_bad_version_0_66_0_and_0_66_1(self): | ||
| 249 | for version in ("0.66.0", "0.66.1"): | ||
| 250 | with self.subTest(version=version): | ||
| 251 | bindgen = self.generate_bindgen_version(f"bindgen {version}") | ||
| 252 | result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen }) | ||
| 253 | self.assertIn(f"Rust bindings generator '{bindgen}' versions 0.66.0 and 0.66.1 may not", result.stderr) | ||
| 254 | |||
| 255 | def test_bindgen_bad_version_0_66_0_and_0_66_1_patched(self): | ||
| 256 | for version in ("0.66.0", "0.66.1"): | ||
| 257 | with self.subTest(version=version): | ||
| 258 | bindgen = self.generate_bindgen_version(f"bindgen {version}", True) | ||
| 259 | result = self.run_script(self.Expected.SUCCESS, { "BINDGEN": bindgen }) | ||
| 260 | |||
| 261 | def test_bindgen_libclang_failure(self): | 234 | def test_bindgen_libclang_failure(self): |
| 262 | bindgen = self.generate_bindgen_libclang_failure() | 235 | bindgen = self.generate_bindgen_libclang_failure() |
| 263 | result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen }) | 236 | result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen }) |
| @@ -275,31 +248,6 @@ else: · 11 unmodified lines | |||
| 275 | result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen }) | 248 | result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen }) |
| 276 | self.assertIn(f"libclang (used by the Rust bindings generator '{bindgen}') is too old.", result.stderr) | 249 | self.assertIn(f"libclang (used by the Rust bindings generator '{bindgen}') is too old.", result.stderr) |
| 277 | 250 | ||
| 278 | def test_bindgen_bad_libclang_concat(self): | ||
| 279 | for (bindgen_version, libclang_version, expected_not_patched) in ( | ||
| 280 | ("0.69.4", "18.0.0", self.Expected.SUCCESS), | ||
| 281 | ("0.69.4", "19.1.0", self.Expected.SUCCESS_WITH_WARNINGS), | ||
| 282 | ("0.69.4", "19.2.0", self.Expected.SUCCESS_WITH_WARNINGS), | ||
| 283 | |||
| 284 | ("0.69.5", "18.0.0", self.Expected.SUCCESS), | ||
| 285 | ("0.69.5", "19.1.0", self.Expected.SUCCESS), | ||
| 286 | ("0.69.5", "19.2.0", self.Expected.SUCCESS), | ||
| 287 | |||
| 288 | ("0.70.0", "18.0.0", self.Expected.SUCCESS), | ||
| 289 | ("0.70.0", "19.1.0", self.Expected.SUCCESS), | ||
| 290 | ("0.70.0", "19.2.0", self.Expected.SUCCESS), | ||
| 291 | ): | ||
| 292 | with self.subTest(bindgen_version=bindgen_version, libclang_version=libclang_version): | ||
| 293 | cc = self.generate_clang(f"clang version {libclang_version}") | ||
| 294 | libclang_stderr = f"scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version {libclang_version} [-W#pragma-messages], err: false" | ||
| 295 | bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr) | ||
| 296 | result = self.run_script(expected_not_patched, { "BINDGEN": bindgen, "CC": cc }) | ||
| 297 | if expected_not_patched == self.Expected.SUCCESS_WITH_WARNINGS: | ||
| 298 | self.assertIn(f"Rust bindings generator '{bindgen}' < 0.69.5 together with libclang >= 19.1", result.stderr) | ||
| 299 | |||
| 300 | bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr, libclang_concat_patched=True) | ||
| 301 | result = self.run_script(self.Expected.SUCCESS, { "BINDGEN": bindgen, "CC": cc }) | ||
| 302 | |||
| 303 | def test_clang_matches_bindgen_libclang_different_bindgen(self): | 251 | def test_clang_matches_bindgen_libclang_different_bindgen(self): |
| 304 | 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") | 252 | 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") |
| 305 | result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen }) | 253 | result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen }) |