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 <[email protected]>
Signed-off-by: Alex Gaynor <[email protected]>
Co-developed-by: Wedson Almeida Filho <[email protected]>
Signed-off-by: Wedson Almeida Filho <[email protected]>
Co-developed-by: Finn Behrens <[email protected]>
Signed-off-by: Finn Behrens <[email protected]>
Co-developed-by: Miguel Cano <[email protected]>
Signed-off-by: Miguel Cano <[email protected]>
Co-developed-by: Tiago Lam <[email protected]>
Signed-off-by: Tiago Lam <[email protected]>
Signed-off-by: Miguel Ojeda <[email protected]>
---
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 Wed, Aug 17, 2022 at 10:18 PM Kees Cook <[email protected]> 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
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 <[email protected]>
> Signed-off-by: Alex Gaynor <[email protected]>
> Co-developed-by: Wedson Almeida Filho <[email protected]>
> Signed-off-by: Wedson Almeida Filho <[email protected]>
> Co-developed-by: Finn Behrens <[email protected]>
> Signed-off-by: Finn Behrens <[email protected]>
> Co-developed-by: Miguel Cano <[email protected]>
> Signed-off-by: Miguel Cano <[email protected]>
> Co-developed-by: Tiago Lam <[email protected]>
> Signed-off-by: Tiago Lam <[email protected]>
> Signed-off-by: Miguel Ojeda <[email protected]>
> ---
> 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 <[email protected]>
-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 Fri, Aug 5, 2022 at 8:46 AM Miguel Ojeda <[email protected]> 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
<[email protected]> 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
<[email protected]> 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