This script tests whether the Rust toolchain requirements are in place
to enable Rust support.
The build system will call it to set `CONFIG_RUST_IS_AVAILABLE` in
a later patch.
It also has an option (`-v`) to explain what is missing, which is
useful to set up the development environment. This is used via
the `make rustavailable` target added in a later patch.
Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Miguel Cano <macanroj@gmail.com>
Signed-off-by: Miguel Cano <macanroj@gmail.com>
Co-developed-by: Tiago Lam <tiagolam@gmail.com>
Signed-off-by: Tiago Lam <tiagolam@gmail.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
scripts/rust_is_available.sh | 160 +++++++++++++++++++
scripts/rust_is_available_bindgen_libclang.h | 2 +
2 files changed, 162 insertions(+)
create mode 100755 scripts/rust_is_available.sh
create mode 100644 scripts/rust_is_available_bindgen_libclang.h
diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh
new file mode 100755
index 000000000000..aebbf1913970
--- /dev/null
+++ b/scripts/rust_is_available.sh
@@ -0,0 +1,160 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# Tests whether a suitable Rust toolchain is available.
+#
+# Pass `-v` for human output and more checks (as warnings).
+
+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))
+}
+
+# Check that the Rust compiler exists.
+if ! command -v "$RUSTC" >/dev/null; then
+ if [ "$1" = -v ]; then
+ echo >&2 "***"
+ echo >&2 "*** Rust compiler '$RUSTC' could not be found."
+ echo >&2 "***"
+ fi
+ exit 1
+fi
+
+# Check that the Rust bindings generator exists.
+if ! command -v "$BINDGEN" >/dev/null; then
+ if [ "$1" = -v ]; then
+ echo >&2 "***"
+ echo >&2 "*** Rust bindings generator '$BINDGEN' could not be found."
+ echo >&2 "***"
+ fi
+ 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_version=$( \
+ LC_ALL=C "$RUSTC" --version 2>/dev/null \
+ | head -n 1 \
+ | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \
+)
+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
+ if [ "$1" = -v ]; 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 "***"
+ fi
+ exit 1
+fi
+if [ "$1" = -v ] && [ "$rust_compiler_cversion" -gt "$rust_compiler_min_cversion" ]; then
+ echo >&2 "***"
+ echo >&2 "*** Rust compiler '$RUSTC' is too new. This may or may not work."
+ echo >&2 "*** Your version: $rust_compiler_version"
+ echo >&2 "*** Expected version: $rust_compiler_min_version"
+ echo >&2 "***"
+fi
+
+# Check that the Rust bindings generator is suitable.
+#
+# Non-stable and distributions' versions may have a version suffix, e.g. `-dev`.
+rust_bindings_generator_version=$( \
+ LC_ALL=C "$BINDGEN" --version 2>/dev/null \
+ | head -n 1 \
+ | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \
+)
+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
+ if [ "$1" = -v ]; 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 "***"
+ fi
+ exit 1
+fi
+if [ "$1" = -v ] && [ "$rust_bindings_generator_cversion" -gt "$rust_bindings_generator_min_cversion" ]; then
+ echo >&2 "***"
+ echo >&2 "*** Rust bindings generator '$BINDGEN' is too new. This may or may not work."
+ echo >&2 "*** Your version: $rust_bindings_generator_version"
+ echo >&2 "*** Expected version: $rust_bindings_generator_min_version"
+ echo >&2 "***"
+fi
+
+# Check that the `libclang` used by the Rust bindings generator is suitable.
+bindgen_libclang_version=$( \
+ LC_ALL=C "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang.h 2>&1 >/dev/null \
+ | grep -F 'clang version ' \
+ | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \
+ | head -n 1 \
+)
+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
+ if [ "$1" = -v ]; 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 "***"
+ fi
+ exit 1
+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.
+if [ "$1" = -v ]; then
+ 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 "***"
+ fi
+ 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
+ if [ "$1" = -v ]; then
+ echo >&2 "***"
+ echo >&2 "*** Source code for the 'core' standard library could not be found"
+ echo >&2 "*** at '$rustc_src_core'."
+ echo >&2 "***"
+ fi
+ exit 1
+fi
diff --git a/scripts/rust_is_available_bindgen_libclang.h b/scripts/rust_is_available_bindgen_libclang.h
new file mode 100644
index 000000000000..0ef6db10d674
--- /dev/null
+++ b/scripts/rust_is_available_bindgen_libclang.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#pragma message("clang version " __clang_version__)
--
2.37.1
On Fri, Aug 5, 2022 at 8:46 AM Miguel Ojeda <ojeda@kernel.org> wrote: > > This script tests whether the Rust toolchain requirements are in place > to enable Rust support. With this, I get: $ make LLVM=1 rustavailable *** *** libclang (used by the Rust bindings generator 'bindgen') *** version does not match Clang's. This may be a problem. *** libclang version: 15.0.0 *** Clang version: 16.0.0 *** Rust is available! because I'm using clang built from source from ToT. Is this supposed to mean that I can't use clang-16, clang-14, clang-13, clang-12, or clang-11 (in the kernel we support clang-11+) in order to use rust? I'm guessing that's going to hinder adoption. Is there a way to specify which libclang version bindgen should be using? I have libclang built in my clang sources, llvm-project/llvm/build/lib/libclang.so. I also tried: $ CLANG_PATH=/android0/llvm-project/llvm/build/lib/libclang.so.15 make LLVM=1 -j72 rustavailable $ CLANG_PATH=/android0/llvm-project/llvm/build/lib/libclang.so make LLVM=1 -j72 rustavailable -- Thanks, ~Nick Desaulniers
On Mon, Aug 22, 2022 at 10:09 PM Nick Desaulniers
<ndesaulniers@google.com> wrote:
>
> because I'm using clang built from source from ToT. Is this supposed
> to mean that I can't use clang-16, clang-14, clang-13, clang-12, or
> clang-11 (in the kernel we support clang-11+) in order to use rust?
> I'm guessing that's going to hinder adoption. Is there a way to
No, it is only a warning, so you can proceed if you want to risk it.
However, is there a reason you would like to mix the versions?
If not, please point `bindgen` to your newer libclang (see below).
> specify which libclang version bindgen should be using?
Yes, see below.
> I have libclang built in my clang sources,
> llvm-project/llvm/build/lib/libclang.so. I also tried:
>
> $ CLANG_PATH=/android0/llvm-project/llvm/build/lib/libclang.so.15 make
> LLVM=1 -j72 rustavailable
`CLANG_PATH` is for pointing to a `clang` executable, not `libclang`.
Instead, please try `LIBCLANG_PATH` (note the `LIB` there).
For instance, using the test header to print the libclang version,
this works for me:
$ bindgen scripts/rust_is_available_bindgen_libclang.h
... clang version 14.0.6 (https://github.com/llvm/llvm-project.git ...
$ LIBCLANG_PATH=.../libclang-6.0.so.1 \
bindgen scripts/rust_is_available_bindgen_libclang.h
... clang version 6.0.0 (tags/RELEASE_600/final) ...
If the above does not work, for details on how the dependency is
resolved, please see:
https://github.com/KyleMayes/clang-sys#linking
https://github.com/KyleMayes/clang-sys#dependencies
https://github.com/KyleMayes/clang-sys#environment-variables
https://github.com/rust-lang/rust-bindgen#environment-variables
I will add a note about this to the docs.
Cheers,
Miguel
On Tue, Aug 23, 2022 at 2:12 PM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> For instance, using the test header to print the libclang version,
> this works for me:
>
> $ bindgen scripts/rust_is_available_bindgen_libclang.h
> ... clang version 14.0.6 (https://github.com/llvm/llvm-project.git ...
>
> $ LIBCLANG_PATH=.../libclang-6.0.so.1 \
> bindgen scripts/rust_is_available_bindgen_libclang.h
> ... clang version 6.0.0 (tags/RELEASE_600/final) ...
By the way, a while ago I requested an easier way to check the
libclang version directly from bindgen, and Emilio quickly added it
(thanks a lot!): since `bindgen` 0.60.0 you can do:
$ bindgen --version --verbose
bindgen 0.60.0
Clang: clang version 14.0.6 (https://github.com/llvm/ ...
Cheers,
Miguel
On Fri, Aug 05, 2022 at 05:42:05PM +0200, Miguel Ojeda wrote:
> This script tests whether the Rust toolchain requirements are in place
> to enable Rust support.
>
> The build system will call it to set `CONFIG_RUST_IS_AVAILABLE` in
> a later patch.
>
> It also has an option (`-v`) to explain what is missing, which is
> useful to set up the development environment. This is used via
> the `make rustavailable` target added in a later patch.
>
> Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
> Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
> Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
> Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
> Co-developed-by: Finn Behrens <me@kloenk.de>
> Signed-off-by: Finn Behrens <me@kloenk.de>
> Co-developed-by: Miguel Cano <macanroj@gmail.com>
> Signed-off-by: Miguel Cano <macanroj@gmail.com>
> Co-developed-by: Tiago Lam <tiagolam@gmail.com>
> Signed-off-by: Tiago Lam <tiagolam@gmail.com>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> ---
> scripts/rust_is_available.sh | 160 +++++++++++++++++++
> scripts/rust_is_available_bindgen_libclang.h | 2 +
> 2 files changed, 162 insertions(+)
> create mode 100755 scripts/rust_is_available.sh
> create mode 100644 scripts/rust_is_available_bindgen_libclang.h
>
> diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh
> new file mode 100755
> index 000000000000..aebbf1913970
> --- /dev/null
> +++ b/scripts/rust_is_available.sh
> @@ -0,0 +1,160 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Tests whether a suitable Rust toolchain is available.
> +#
> +# Pass `-v` for human output and more checks (as warnings).
> +
> +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))
> +}
> +
> +# Check that the Rust compiler exists.
> +if ! command -v "$RUSTC" >/dev/null; then
> + if [ "$1" = -v ]; then
> + echo >&2 "***"
> + echo >&2 "*** Rust compiler '$RUSTC' could not be found."
> + echo >&2 "***"
> + fi
> + exit 1
> +fi
> +
> +# Check that the Rust bindings generator exists.
> +if ! command -v "$BINDGEN" >/dev/null; then
> + if [ "$1" = -v ]; then
> + echo >&2 "***"
> + echo >&2 "*** Rust bindings generator '$BINDGEN' could not be found."
> + echo >&2 "***"
> + fi
> + 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_version=$( \
> + LC_ALL=C "$RUSTC" --version 2>/dev/null \
> + | head -n 1 \
> + | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \
> +)
> +rust_compiler_min_version=$($min_tool_version rustc)
I think the min-tool-version.sh changes from patch 23 should be moved
into this patch.
With that:
Reviewed-by: Kees Cook <keescook@chromium.org>
-Kees
> +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
> + if [ "$1" = -v ]; 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 "***"
> + fi
> + exit 1
> +fi
> +if [ "$1" = -v ] && [ "$rust_compiler_cversion" -gt "$rust_compiler_min_cversion" ]; then
> + echo >&2 "***"
> + echo >&2 "*** Rust compiler '$RUSTC' is too new. This may or may not work."
> + echo >&2 "*** Your version: $rust_compiler_version"
> + echo >&2 "*** Expected version: $rust_compiler_min_version"
> + echo >&2 "***"
> +fi
> +
> +# Check that the Rust bindings generator is suitable.
> +#
> +# Non-stable and distributions' versions may have a version suffix, e.g. `-dev`.
> +rust_bindings_generator_version=$( \
> + LC_ALL=C "$BINDGEN" --version 2>/dev/null \
> + | head -n 1 \
> + | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \
> +)
> +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
> + if [ "$1" = -v ]; 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 "***"
> + fi
> + exit 1
> +fi
> +if [ "$1" = -v ] && [ "$rust_bindings_generator_cversion" -gt "$rust_bindings_generator_min_cversion" ]; then
> + echo >&2 "***"
> + echo >&2 "*** Rust bindings generator '$BINDGEN' is too new. This may or may not work."
> + echo >&2 "*** Your version: $rust_bindings_generator_version"
> + echo >&2 "*** Expected version: $rust_bindings_generator_min_version"
> + echo >&2 "***"
> +fi
> +
> +# Check that the `libclang` used by the Rust bindings generator is suitable.
> +bindgen_libclang_version=$( \
> + LC_ALL=C "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang.h 2>&1 >/dev/null \
> + | grep -F 'clang version ' \
> + | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \
> + | head -n 1 \
> +)
> +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
> + if [ "$1" = -v ]; 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 "***"
> + fi
> + exit 1
> +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.
> +if [ "$1" = -v ]; then
> + 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 "***"
> + fi
> + 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
> + if [ "$1" = -v ]; then
> + echo >&2 "***"
> + echo >&2 "*** Source code for the 'core' standard library could not be found"
> + echo >&2 "*** at '$rustc_src_core'."
> + echo >&2 "***"
> + fi
> + exit 1
> +fi
> diff --git a/scripts/rust_is_available_bindgen_libclang.h b/scripts/rust_is_available_bindgen_libclang.h
> new file mode 100644
> index 000000000000..0ef6db10d674
> --- /dev/null
> +++ b/scripts/rust_is_available_bindgen_libclang.h
> @@ -0,0 +1,2 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#pragma message("clang version " __clang_version__)
> --
> 2.37.1
>
--
Kees Cook
On Wed, Aug 17, 2022 at 10:18 PM Kees Cook <keescook@chromium.org> wrote: > > I think the min-tool-version.sh changes from patch 23 should be moved > into this patch. Yeah, it calls into that script with a "rustc" argument, which doesn't work if somebody happened to run it by hand, so this makes sense. However, the intention was to move each "big" new file into their own patch to make a smaller Kbuild one (and only do that "new file" additions in each patch), and then finally do all the modifications and enable the Rust support in the Kbuild patch (which has the callers into this script). Also the script is not intended to be called directly anyway (since you need the Make environment, but you definitely can), there is a Make target to help with that. Hopefully that explains the logic behind the arrangement of the patches, which was to make the patches as simple as possible. I am happy to rearrange if you think it is more understandable that way. Cheers, Miguel
© 2016 - 2026 Red Hat, Inc.