Merge tag 'rust-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux

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
  ...
This commit is contained in:
Linus Torvalds
2026-04-13 09:54:20 -07:00
78 changed files with 1396 additions and 826 deletions

View File

@@ -310,18 +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(slice_ptr_len)`.
# - 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.84.0: `feature(strict_provenance)`.
# - 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,lint_reasons,offset_of_nested,raw_ref_op,slice_ptr_len,strict_provenance,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
@@ -334,7 +329,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)
@@ -347,7 +341,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)

View File

@@ -10,8 +10,15 @@ import os
import pathlib
import subprocess
import sys
from typing import Dict, Iterable, List, Literal, Optional, TypedDict
def args_crates_cfgs(cfgs):
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:
crate, vals = cfg.split("=", 1)
@@ -19,54 +26,153 @@ 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 = []
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 -- dependencies need to come first.
#
# Avoid O(n^2) iterations by keeping a map of indexes.
crates = []
crates_indexes = {}
# Now fill the crates list.
crates: List[Crate] = []
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"):
crate = {
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,
deps: List[Dependency],
*,
cfg: Optional[List[str]],
is_workspace_member: Optional[bool],
edition: Optional[str],
) -> Crate:
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
)
edition = edition if edition is not None else "2021"
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],
"deps": deps,
"cfg": cfg,
"edition": edition,
"env": {
"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", "-"],
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)
def append_proc_macro_crate(
display_name: str,
root_module: pathlib.Path,
deps: List[Dependency],
*,
cfg: Optional[List[str]] = None,
is_workspace_member: Optional[bool] = None,
edition: Optional[str] = None,
) -> Dependency:
crate = build_crate(
display_name,
root_module,
deps,
cfg=cfg,
is_workspace_member=is_workspace_member,
edition=edition,
)
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,
"proc_macro_dylib_path": str(objtree / "rust" / proc_macro_dylib_name),
}
return register_crate(proc_macro_crate)
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[Dependency],
*,
cfg: Optional[List[str]] = None,
is_workspace_member: Optional[bool] = None,
edition: Optional[str] = None,
) -> Dependency:
return register_crate(
build_crate(
display_name,
root_module,
deps,
cfg=cfg,
is_workspace_member=is_workspace_member,
edition=edition,
)
)
def append_sysroot_crate(
display_name,
deps,
cfg=[],
):
append_crate(
display_name: str,
deps: List[Dependency],
*,
cfg: Optional[List[str]] = None,
) -> Dependency:
return append_crate(
display_name,
sysroot_src / display_name / "src" / "lib.rs",
deps,
cfg,
cfg=cfg,
is_workspace_member=False,
# Miguel Ojeda writes:
#
@@ -98,129 +204,146 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit
# 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", [])
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"],
cfg=crates_cfgs["proc_macro2"],
[core, alloc, std, proc_macro],
)
append_crate(
quote = append_crate(
"quote",
srctree / "rust" / "quote" / "lib.rs",
["core", "alloc", "std", "proc_macro", "proc_macro2"],
cfg=crates_cfgs["quote"],
[core, alloc, std, proc_macro, proc_macro2],
edition="2018",
)
append_crate(
syn = append_crate(
"syn",
srctree / "rust" / "syn" / "lib.rs",
["std", "proc_macro", "proc_macro2", "quote"],
cfg=crates_cfgs["syn"],
[std, proc_macro, proc_macro2, quote],
)
append_crate(
macros = append_proc_macro_crate(
"macros",
srctree / "rust" / "macros" / "lib.rs",
["std", "proc_macro", "proc_macro2", "quote", "syn"],
is_proc_macro=True,
[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_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"],
cfg=["kernel"],
is_proc_macro=True,
[std, proc_macro, proc_macro2, quote, syn],
)
append_crate(
pin_init = append_crate(
"pin_init",
srctree / "rust" / "pin-init" / "src" / "lib.rs",
["core", "compiler_builtins", "pin_init_internal", "macros"],
cfg=["kernel"],
[core, compiler_builtins, pin_init_internal, macros],
)
append_crate(
ffi = append_crate(
"ffi",
srctree / "rust" / "ffi.rs",
["core", "compiler_builtins"],
[core, compiler_builtins],
)
def append_crate_with_generated(
display_name,
deps,
):
append_crate(
display_name: str,
deps: List[Dependency],
) -> Dependency:
crate = build_crate(
display_name,
srctree / "rust"/ display_name / "lib.rs",
deps,
cfg=cfg,
cfg=generated_cfg,
is_workspace_member=True,
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: CrateWithGenerated = {
**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"])
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, target):
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()
contents = build_file.read_text()
except FileNotFoundError:
return False
return f"{target}.o" in contents
# 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:
for path in folder.rglob("*.rs"):
logging.info("Checking %s", path)
name = path.name.replace(".rs", "")
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=cfg,
[core, kernel, pin_init],
cfg=generated_cfg,
)
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=[])
@@ -230,7 +353,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",

View File

@@ -31,10 +31,10 @@ llvm)
fi
;;
rustc)
echo 1.78.0
echo 1.85.0
;;
bindgen)
echo 0.65.1
echo 0.71.1
;;
*)
echo "$1: unknown tool" >&2

View File

@@ -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 "***"
@@ -163,19 +157,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.
#
@@ -227,21 +208,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.
#

View File

@@ -1,2 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#define A "\0"

View File

@@ -1,3 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#define F(x) int x##x
F(foo);

View File

@@ -54,37 +54,23 @@ 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):
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:
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_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:
print({repr(version_stdout)})
""")
@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 +231,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 })
@@ -275,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 })