summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/rust_is_available.sh14
-rw-r--r--scripts/rust_is_available_bindgen_libclang_22.h5
-rwxr-xr-xscripts/rust_is_available_test.py46
-rw-r--r--scripts/rustdoc_test_gen.rs29
4 files changed, 89 insertions, 5 deletions
diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh
index 551f1ebd0dcb..c30983562a2f 100755
--- a/scripts/rust_is_available.sh
+++ b/scripts/rust_is_available.sh
@@ -208,6 +208,20 @@ if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then
exit 1
fi
+if [ "$bindgen_libclang_cversion" -ge 2200000 ] &&
+ [ "$rust_bindings_generator_cversion" -lt 7201 ]; then
+ # Distributions may have patched the issue.
+ if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang_22.h | grep -q 'pub foo'; then
+ echo >&2 "***"
+ echo >&2 "*** Rust bindings generator '$BINDGEN' < 0.72.1 together with libclang >= 22"
+ echo >&2 "*** may not work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/3278)."
+ 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_22.h b/scripts/rust_is_available_bindgen_libclang_22.h
new file mode 100644
index 000000000000..6b33544c14a8
--- /dev/null
+++ b/scripts/rust_is_available_bindgen_libclang_22.h
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+struct S;
+struct S {
+ int foo;
+};
diff --git a/scripts/rust_is_available_test.py b/scripts/rust_is_available_test.py
index d6d54b7ea42a..22bdff980c35 100755
--- a/scripts/rust_is_available_test.py
+++ b/scripts/rust_is_available_test.py
@@ -54,16 +54,23 @@ else:
""")
@classmethod
- def generate_bindgen(cls, version_stdout, libclang_stderr):
+ def generate_bindgen(cls, version_stdout, libclang_stderr, libclang_22_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 libclang_22_patched:
+ libclang_22_case = "print('pub foo: ::std::os::raw::c_int,')"
+ else:
+ libclang_22_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_22.h" in " ".join(sys.argv):
+ {libclang_22_case}
else:
print({repr(version_stdout)})
""")
@@ -177,7 +184,13 @@ else:
def test_rustc_nonexecutable(self):
result = self.run_script(self.Expected.FAILURE, { "RUSTC": self.nonexecutable })
- self.assertIn(f"Running '{self.nonexecutable}' to check the Rust compiler version failed with", result.stderr)
+ self.assertTrue(
+ # `dash`.
+ f"Running '{self.nonexecutable}' to check the Rust compiler version failed with" in result.stderr or
+ # `bash`.
+ f"Rust compiler '{self.nonexecutable}' could not be found." in result.stderr,
+ f"Unexpected `stderr`:\n{result.stderr}"
+ )
def test_rustc_unexpected_binary(self):
result = self.run_script(self.Expected.FAILURE, { "RUSTC": self.unexpected_binary })
@@ -205,7 +218,13 @@ else:
def test_bindgen_nonexecutable(self):
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": self.nonexecutable })
- self.assertIn(f"Running '{self.nonexecutable}' to check the Rust bindings generator version failed with", result.stderr)
+ self.assertTrue(
+ # `dash`.
+ f"Running '{self.nonexecutable}' to check the Rust bindings generator version failed with" in result.stderr or
+ # `bash`.
+ f"Rust bindings generator '{self.nonexecutable}' could not be found." in result.stderr,
+ f"Unexpected `stderr`:\n{result.stderr}"
+ )
def test_bindgen_unexpected_binary(self):
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": self.unexpected_binary })
@@ -248,6 +267,27 @@ 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_22(self):
+ for (bindgen_version, libclang_version, expected_not_patched) in (
+ ("0.71.1", "21.1.0", self.Expected.SUCCESS),
+ ("0.71.1", "22.0.0", self.Expected.SUCCESS_WITH_WARNINGS),
+ ("0.71.1", "22.1.0", self.Expected.SUCCESS_WITH_WARNINGS),
+
+ ("0.72.0", "22.0.0", self.Expected.SUCCESS_WITH_WARNINGS),
+
+ ("0.72.1", "22.0.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.72.1 together with libclang >= 22", result.stderr)
+
+ bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr, libclang_22_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 })
diff --git a/scripts/rustdoc_test_gen.rs b/scripts/rustdoc_test_gen.rs
index d61a77219a8c..d087c0d9fcb3 100644
--- a/scripts/rustdoc_test_gen.rs
+++ b/scripts/rustdoc_test_gen.rs
@@ -31,8 +31,15 @@
use std::{
fs,
fs::File,
- io::{BufWriter, Read, Write},
- path::{Path, PathBuf},
+ io::{
+ BufWriter,
+ Read,
+ Write, //
+ },
+ path::{
+ Path,
+ PathBuf, //
+ }, //
};
/// Find the real path to the original file based on the `file` portion of the test name.
@@ -232,6 +239,24 @@ pub extern "C" fn {kunit_name}(__kunit_test: *mut ::kernel::bindings::kunit) {{
const __LOG_PREFIX: &[u8] = b"rust_doctests_kernel\0";
+/// Dummy module type for doctest context.
+struct LocalModule;
+
+use kernel::{{
+ str::CStr,
+ ModuleMetadata,
+ ThisModule, //
+}};
+use core::ptr::null_mut;
+
+impl ModuleMetadata for LocalModule {{
+ const NAME: &'static CStr = c"rust_doctests_kernel";
+ const THIS_MODULE: ThisModule = {{
+ // SAFETY: `try_module_get`/`module_put` handle null module pointers gracefully.
+ unsafe {{ ThisModule::from_ptr(null_mut()) }}
+ }};
+}}
+
{rust_tests}
"#
)