linux-next/scripts/rust_is_available.sh

278 lines
10 KiB
Bash
Raw Normal View History

#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
#
# Tests whether a suitable Rust toolchain is available.
set -e
min_tool_version=$(dirname $0)/min-tool-version.sh
# Convert the version string x.y.z to a canonical up-to-7-digits form.
#
# Note that this function uses one more digit (compared to other
# instances in other version scripts) to give a bit more space to
# `rustc` since it will reach 1.100.0 in late 2026.
get_canonical_version()
{
IFS=.
set -- $1
echo $((100000 * $1 + 100 * $2 + $3))
}
# Print a reference to the Quick Start guide in the documentation.
print_docs_reference()
{
echo >&2 "***"
echo >&2 "*** Please see Documentation/rust/quick-start.rst for details"
echo >&2 "*** on how to set up the Rust support."
echo >&2 "***"
}
# Print an explanation about the fact that the script is meant to be called from Kbuild.
print_kbuild_explanation()
{
echo >&2 "***"
echo >&2 "*** This script is intended to be called from Kbuild."
echo >&2 "*** Please use the 'rustavailable' target to call it instead."
echo >&2 "*** Otherwise, the results may not be meaningful."
exit 1
}
# If the script fails for any reason, or if there was any warning, then
# print a reference to the documentation on exit.
warning=0
trap 'if [ $? -ne 0 ] || [ $warning -ne 0 ]; then print_docs_reference; fi' EXIT
# Check that the expected environment variables are set.
if [ -z "${RUSTC+x}" ]; then
echo >&2 "***"
echo >&2 "*** Environment variable 'RUSTC' is not set."
print_kbuild_explanation
fi
if [ -z "${BINDGEN+x}" ]; then
echo >&2 "***"
echo >&2 "*** Environment variable 'BINDGEN' is not set."
print_kbuild_explanation
fi
if [ -z "${CC+x}" ]; then
echo >&2 "***"
echo >&2 "*** Environment variable 'CC' is not set."
print_kbuild_explanation
fi
# Check that the Rust compiler exists.
if ! command -v "$RUSTC" >/dev/null; then
echo >&2 "***"
echo >&2 "*** Rust compiler '$RUSTC' could not be found."
echo >&2 "***"
exit 1
fi
# Check that the Rust bindings generator exists.
if ! command -v "$BINDGEN" >/dev/null; then
echo >&2 "***"
echo >&2 "*** Rust bindings generator '$BINDGEN' could not be found."
echo >&2 "***"
exit 1
fi
# Check that the Rust compiler version is suitable.
#
# Non-stable and distributions' versions may have a version suffix, e.g. `-dev`.
rust_compiler_output=$( \
LC_ALL=C "$RUSTC" --version 2>/dev/null
) || rust_compiler_code=$?
if [ -n "$rust_compiler_code" ]; then
echo >&2 "***"
echo >&2 "*** Running '$RUSTC' to check the Rust compiler version failed with"
echo >&2 "*** code $rust_compiler_code. See output and docs below for details:"
echo >&2 "***"
echo >&2 "$rust_compiler_output"
echo >&2 "***"
exit 1
fi
rust_compiler_version=$( \
echo "$rust_compiler_output" \
| sed -nE '1s:.*rustc ([0-9]+\.[0-9]+\.[0-9]+).*:\1:p'
)
if [ -z "$rust_compiler_version" ]; then
echo >&2 "***"
echo >&2 "*** Running '$RUSTC' to check the Rust compiler version did not return"
echo >&2 "*** an expected output. See output and docs below for details:"
echo >&2 "***"
echo >&2 "$rust_compiler_output"
echo >&2 "***"
exit 1
fi
rust_compiler_min_version=$($min_tool_version rustc)
rust_compiler_cversion=$(get_canonical_version $rust_compiler_version)
rust_compiler_min_cversion=$(get_canonical_version $rust_compiler_min_version)
if [ "$rust_compiler_cversion" -lt "$rust_compiler_min_cversion" ]; then
echo >&2 "***"
echo >&2 "*** Rust compiler '$RUSTC' is too old."
echo >&2 "*** Your version: $rust_compiler_version"
echo >&2 "*** Minimum version: $rust_compiler_min_version"
echo >&2 "***"
exit 1
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). It can be removed when
# the minimum version is upgraded past that (0.69.1 already fixed the issue).
rust_bindings_generator_output=$( \
LC_ALL=C "$BINDGEN" --version workaround-for-0.69.0 2>/dev/null
) || rust_bindings_generator_code=$?
if [ -n "$rust_bindings_generator_code" ]; then
echo >&2 "***"
echo >&2 "*** Running '$BINDGEN' to check the Rust bindings generator version failed with"
echo >&2 "*** code $rust_bindings_generator_code. See output and docs below for details:"
echo >&2 "***"
echo >&2 "$rust_bindings_generator_output"
echo >&2 "***"
exit 1
fi
rust_bindings_generator_version=$( \
echo "$rust_bindings_generator_output" \
| sed -nE '1s:.*bindgen ([0-9]+\.[0-9]+\.[0-9]+).*:\1:p'
)
if [ -z "$rust_bindings_generator_version" ]; then
echo >&2 "***"
echo >&2 "*** Running '$BINDGEN' to check the bindings generator version did not return"
echo >&2 "*** an expected output. See output and docs below for details:"
echo >&2 "***"
echo >&2 "$rust_bindings_generator_output"
echo >&2 "***"
exit 1
fi
rust_bindings_generator_min_version=$($min_tool_version bindgen)
rust_bindings_generator_cversion=$(get_canonical_version $rust_bindings_generator_version)
rust_bindings_generator_min_cversion=$(get_canonical_version $rust_bindings_generator_min_version)
if [ "$rust_bindings_generator_cversion" -lt "$rust_bindings_generator_min_cversion" ]; then
echo >&2 "***"
echo >&2 "*** Rust bindings generator '$BINDGEN' is too old."
echo >&2 "*** Your version: $rust_bindings_generator_version"
echo >&2 "*** Minimum version: $rust_bindings_generator_min_version"
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.
kbuild: rust_is_available: add check for `bindgen` invocation `scripts/rust_is_available.sh` calls `bindgen` with a special header in order to check whether the `libclang` version in use is suitable. However, the invocation itself may fail if, for instance, `bindgen` cannot locate `libclang`. This is fine for Kconfig (since the script will still fail and therefore disable Rust as it should), but it is pretty confusing for users of the `rustavailable` target given the error will be unrelated: ./scripts/rust_is_available.sh: 21: arithmetic expression: expecting primary: "100000 * + 100 * + " make: *** [Makefile:1816: rustavailable] Error 2 Instead, run the `bindgen` invocation independently in a previous step, saving its output and return code. If it fails, then show the user a proper error message. Otherwise, continue as usual with the saved output. Since the previous patch we show a reference to the docs, and the docs now explain how `bindgen` looks for `libclang`, thus the error message can leverage the documentation, avoiding duplication here (and making users aware of the setup guide in the documentation). Reported-by: Nick Desaulniers <ndesaulniers@google.com> Link: https://lore.kernel.org/rust-for-linux/CAKwvOdm5JT4wbdQQYuW+RT07rCi6whGBM2iUAyg8A1CmLXG6Nw@mail.gmail.com/ Reported-by: François Valenduc <francoisvalenduc@gmail.com> Closes: https://github.com/Rust-for-Linux/linux/issues/934 Reported-by: Alexandru Radovici <msg4alex@gmail.com> Closes: https://github.com/Rust-for-Linux/linux/pull/921 Reported-by: Matthew Leach <dev@mattleach.net> Closes: https://lore.kernel.org/rust-for-linux/20230507084116.1099067-1-dev@mattleach.net/ Fixes: 78521f3399ab ("scripts: add `rust_is_available.sh`") Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com> Reviewed-by: Masahiro Yamada <masahiroy@kernel.org> Reviewed-by: Nathan Chancellor <nathan@kernel.org> Link: https://lore.kernel.org/r/20230616001631.463536-6-ojeda@kernel.org Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2023-06-16 00:16:25 +00:00
#
# In order to do that, first invoke `bindgen` to get the `libclang` version
# found by `bindgen`. This step may already fail if, for instance, `libclang`
# is not found, thus inform the user in such a case.
bindgen_libclang_output=$( \
LC_ALL=C "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang.h 2>&1 >/dev/null
) || bindgen_libclang_code=$?
if [ -n "$bindgen_libclang_code" ]; then
echo >&2 "***"
echo >&2 "*** Running '$BINDGEN' to check the libclang version (used by the Rust"
echo >&2 "*** bindings generator) failed with code $bindgen_libclang_code. This may be caused by"
echo >&2 "*** a failure to locate libclang. See output and docs below for details:"
echo >&2 "***"
echo >&2 "$bindgen_libclang_output"
echo >&2 "***"
exit 1
fi
# `bindgen` returned successfully, thus use the output to check that the version
# of the `libclang` found by the Rust bindings generator is suitable.
#
# Unlike other version checks, note that this one does not necessarily appear
# in the first line of the output, thus no `sed` address is provided.
bindgen_libclang_version=$( \
kbuild: rust_is_available: add check for `bindgen` invocation `scripts/rust_is_available.sh` calls `bindgen` with a special header in order to check whether the `libclang` version in use is suitable. However, the invocation itself may fail if, for instance, `bindgen` cannot locate `libclang`. This is fine for Kconfig (since the script will still fail and therefore disable Rust as it should), but it is pretty confusing for users of the `rustavailable` target given the error will be unrelated: ./scripts/rust_is_available.sh: 21: arithmetic expression: expecting primary: "100000 * + 100 * + " make: *** [Makefile:1816: rustavailable] Error 2 Instead, run the `bindgen` invocation independently in a previous step, saving its output and return code. If it fails, then show the user a proper error message. Otherwise, continue as usual with the saved output. Since the previous patch we show a reference to the docs, and the docs now explain how `bindgen` looks for `libclang`, thus the error message can leverage the documentation, avoiding duplication here (and making users aware of the setup guide in the documentation). Reported-by: Nick Desaulniers <ndesaulniers@google.com> Link: https://lore.kernel.org/rust-for-linux/CAKwvOdm5JT4wbdQQYuW+RT07rCi6whGBM2iUAyg8A1CmLXG6Nw@mail.gmail.com/ Reported-by: François Valenduc <francoisvalenduc@gmail.com> Closes: https://github.com/Rust-for-Linux/linux/issues/934 Reported-by: Alexandru Radovici <msg4alex@gmail.com> Closes: https://github.com/Rust-for-Linux/linux/pull/921 Reported-by: Matthew Leach <dev@mattleach.net> Closes: https://lore.kernel.org/rust-for-linux/20230507084116.1099067-1-dev@mattleach.net/ Fixes: 78521f3399ab ("scripts: add `rust_is_available.sh`") Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com> Reviewed-by: Masahiro Yamada <masahiroy@kernel.org> Reviewed-by: Nathan Chancellor <nathan@kernel.org> Link: https://lore.kernel.org/r/20230616001631.463536-6-ojeda@kernel.org Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2023-06-16 00:16:25 +00:00
echo "$bindgen_libclang_output" \
kbuild: rust_is_available: fix confusion when a version appears in the path `bindgen`'s output for `libclang`'s version check contains paths, which in turn may contain strings that look like version numbers [1][2]: .../6.1.0-dev/.../rust_is_available_bindgen_libclang.h:2:9: warning: clang version 11.1.0 [-W#pragma-messages], err: false which the script will pick up as the version instead of the latter. It is also the case that versions may appear after the actual version (e.g. distribution's version text), which was the reason behind `head` [3]: .../rust-is-available-bindgen-libclang.h:2:9: warning: clang version 13.0.0 (Fedora 13.0.0-3.fc35) [-W#pragma-messages], err: false Thus instead ask for a match after the `clang version` string. Reported-by: Jordan Isaacs <mail@jdisaacs.com> Closes: https://github.com/Rust-for-Linux/linux/issues/942 [1] Reported-by: "Ethan D. Twardy" <ethan.twardy@gmail.com> Closes: https://lore.kernel.org/rust-for-linux/20230528131802.6390-2-ethan.twardy@gmail.com/ [2] Reported-by: Tiago Lam <tiagolam@gmail.com> Closes: https://github.com/Rust-for-Linux/linux/pull/789 [3] Fixes: 78521f3399ab ("scripts: add `rust_is_available.sh`") Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com> Reviewed-by: Ethan Twardy <ethan.twardy@gmail.com> Tested-by: Ethan Twardy <ethan.twardy@gmail.com> Reviewed-by: Nathan Chancellor <nathan@kernel.org> Link: https://lore.kernel.org/r/20230616001631.463536-8-ojeda@kernel.org Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2023-06-16 00:16:27 +00:00
| sed -nE 's:.*clang version ([0-9]+\.[0-9]+\.[0-9]+).*:\1:p'
)
if [ -z "$bindgen_libclang_version" ]; then
echo >&2 "***"
echo >&2 "*** Running '$BINDGEN' to check the libclang version (used by the Rust"
echo >&2 "*** bindings generator) did not return an expected output. See output"
echo >&2 "*** and docs below for details:"
echo >&2 "***"
echo >&2 "$bindgen_libclang_output"
echo >&2 "***"
exit 1
fi
bindgen_libclang_min_version=$($min_tool_version llvm)
bindgen_libclang_cversion=$(get_canonical_version $bindgen_libclang_version)
bindgen_libclang_min_cversion=$(get_canonical_version $bindgen_libclang_min_version)
if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then
echo >&2 "***"
echo >&2 "*** libclang (used by the Rust bindings generator '$BINDGEN') is too old."
echo >&2 "*** Your version: $bindgen_libclang_version"
echo >&2 "*** Minimum version: $bindgen_libclang_min_version"
echo >&2 "***"
exit 1
fi
rust: warn on bindgen < 0.69.5 and libclang >= 19.1 When testing a `clang` upgrade with Rust Binder, Alice encountered [1] a build failure caused by `bindgen` not translating some symbols related to tracepoints. This was caused by commit 2e770edd8ce1 ("[libclang] Compute the right spelling location") changing the behavior of a function exposed by `libclang`. `bindgen` fixed the regression in commit 600f63895f73 ("Use clang_getFileLocation instead of clang_getSpellingLocation"). However, the regression fix is only available in `bindgen` versions 0.69.5 or later (it was backported for 0.69.x). This means that when older bindgen versions are used with new versions of `libclang`, `bindgen` may do the wrong thing, which could lead to a build failure. Alice encountered the bug with some header files related to tracepoints, but it could also cause build failures in other circumstances. Thus, always emit a warning when using an old `bindgen` with a new `libclang` so that other people do not have to spend time chasing down the same bug. However, testing just the version is inconvenient, since distributions do patch their packages without changing the version, so I reduced the issue into the following piece of code that can trigger the issue: #define F(x) int x##x F(foo); In particular, an unpatched `bindgen` will ignore the macro expansion and thus not provide a declaration for the exported `int`. Thus add a build test to `rust_is_available.sh` using the code above (that is only triggered if the versions appear to be affected), following what we did for the 0.66.x issue. Moreover, I checked the status in the major distributions we have instructions for: - Fedora 41 was affected but is now OK, since it now ships `bindgen` 0.69.5. Thanks Ben for the quick reply on the updates that were ongoing. Fedora 40 and earlier are OK (older `libclang`, and they also now carry `bindgen` 0.69.5). - Debian Sid was affected but is now OK, since they now ship a patched `bindgen` binary (0.66.1-7+b3). The issue was reported to Debian by email and then as a bug report [2]. Thanks NoisyCoil and Matthias for the quick replies. NoisyCoil handled the needed updates. Debian may upgrade to `bindgen` 0.70.x, too. Debian Testing is OK (older `libclang` so far). - Ubuntu non-LTS (oracular) is affected. The issue was reported to Ubuntu by email and then as a bug report [3]. Ubuntu LTS is not affected (older `libclang` so far). - Arch Linux, Gentoo Linux and openSUSE should be OK (newer `bindgen` is provided). Nix as well (older `libclang` so far). This issue was also added to our "live list" that tracks issues around distributions [4]. Cc: Ben Beasley <code@musicinmybrain.net> Cc: NoisyCoil <noisycoil@tutanota.com> Cc: Matthias Geiger <werdahias@riseup.net> Link: https://lore.kernel.org/rust-for-linux/20241030-bindgen-libclang-warn-v1-1-3a7ba9fedcfe@google.com/ [1] Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1086510 [2] Link: https://bugs.launchpad.net/ubuntu/+source/rust-bindgen-cli/+bug/2086639 [3] Link: https://github.com/Rust-for-Linux/linux/issues/1127 [4] Co-developed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20241111201607.653149-1-ojeda@kernel.org Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-11-11 20:16:07 +00:00
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.
#
# In the future, we might be able to perform a full version check, see
# https://github.com/rust-lang/rust-bindgen/issues/2138.
cc_name=$($(dirname $0)/cc-version.sh $CC | cut -f1 -d' ')
if [ "$cc_name" = Clang ]; then
clang_version=$( \
LC_ALL=C $CC --version 2>/dev/null \
| sed -nE '1s:.*version ([0-9]+\.[0-9]+\.[0-9]+).*:\1:p'
)
if [ "$clang_version" != "$bindgen_libclang_version" ]; then
echo >&2 "***"
echo >&2 "*** libclang (used by the Rust bindings generator '$BINDGEN')"
echo >&2 "*** version does not match Clang's. This may be a problem."
echo >&2 "*** libclang version: $bindgen_libclang_version"
echo >&2 "*** Clang version: $clang_version"
echo >&2 "***"
warning=1
fi
fi
# Check that the source code for the `core` standard library exists.
#
# `$KRUSTFLAGS` is passed in case the user added `--sysroot`.
rustc_sysroot=$("$RUSTC" $KRUSTFLAGS --print sysroot)
rustc_src=${RUST_LIB_SRC:-"$rustc_sysroot/lib/rustlib/src/rust/library"}
rustc_src_core="$rustc_src/core/src/lib.rs"
if [ ! -e "$rustc_src_core" ]; then
echo >&2 "***"
echo >&2 "*** Source code for the 'core' standard library could not be found"
echo >&2 "*** at '$rustc_src_core'."
echo >&2 "***"
exit 1
fi