Skip to content

Commit cf00942

Browse files
committed
rust: rework Rust toolchain detection
The name of the `HAS_RUST` option has been renamed to `RUST_IS_AVAILABLE`, and now encompasses more checks to see whether a suitable Rust toolchain is available for compiling the kernel. This will allow us later to remove the `!COMPILE_TEST` bound, which, in turn, will allow to e.g. eventually start testing the Rust support in places that do `all{yes,mod}config`. This also provides an easy way for users/developers to understand why the Rust toolchain might not be available: a Makefile target is provided which explains why that is the case, using the same logic that Kbuild/Kconfig use; which addresses some of the feedback we got. Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent 1292114 commit cf00942

7 files changed

Lines changed: 198 additions & 43 deletions

File tree

Documentation/rust/quick-start.rst

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,17 @@ This section explains how to fetch the tools needed for building.
1313

1414
Some of these requirements might be available from Linux distributions
1515
under names like ``rustc``, ``rust-src``, ``rust-bindgen``, etc. However,
16-
at the time of writing, they are likely not to be recent enough.
16+
at the time of writing, they are likely not to be recent enough unless
17+
the distribution tracks the latest releases.
18+
19+
To easily check whether the requirements are met, the following target
20+
can be used::
21+
22+
make LLVM=1 rustavailable
23+
24+
This triggers the same logic used by Kconfig to determine whether
25+
``RUST_IS_AVAILABLE`` should be enabled; but it also explains why not
26+
if that is the case.
1727

1828

1929
rustc
@@ -176,8 +186,8 @@ Configuration
176186
-------------
177187

178188
``Rust support`` (``CONFIG_RUST``) needs to be enabled in the ``General setup``
179-
menu. The option is only shown if the build system can locate ``rustc``.
180-
In turn, this will make visible the rest of options that depend on Rust.
189+
menu. The option is only shown if a suitable Rust toolchain is found (see
190+
above). In turn, this will make visible the rest of options that depend on Rust.
181191

182192
Afterwards, go to::
183193

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16591,6 +16591,7 @@ F: rust/
1659116591
F: samples/rust/
1659216592
F: Documentation/rust/
1659316593
F: lib/rust.h
16594+
F: scripts/*rust*
1659416595
K: \b(?i:rust)\b
1659516596

1659616597
RXRPC SOCKETS (AF_RXRPC)

Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ no-dot-config-targets := $(clean-targets) \
274274
cscope gtags TAGS tags help% %docs check% coccicheck \
275275
$(version_h) headers headers_% archheaders archscripts \
276276
%asm-generic kernelversion %src-pkg dt_binding_check \
277-
outputmakefile rustfmt rustfmtcheck
277+
outputmakefile rustavailable rustfmt rustfmtcheck
278278
# Installation targets should not require compiler. Unfortunately, vdso_install
279279
# is an exception where build artifacts may be updated. This must be fixed.
280280
no-compiler-targets := $(no-dot-config-targets) install dtbs_install \
@@ -1696,6 +1696,8 @@ help:
16961696
@echo ' kselftest to existing .config.'
16971697
@echo ''
16981698
@echo 'Rust targets:'
1699+
@echo ' rustavailable - Checks whether the Rust toolchain is'
1700+
@echo ' available and, if not, explains why.'
16991701
@echo ' rustfmt - Reformat all the Rust code in the kernel'
17001702
@echo ' rustfmtcheck - Checks if all the Rust code in the kernel'
17011703
@echo ' is formatted, printing a diff otherwise.'
@@ -1781,6 +1783,11 @@ $(DOC_TARGETS):
17811783
# Rust targets
17821784
# ---------------------------------------------------------------------------
17831785

1786+
# "Is Rust available?" target
1787+
PHONY += rustavailable
1788+
rustavailable:
1789+
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust-is-available.sh -v
1790+
17841791
# Documentation target
17851792
#
17861793
# Using the singular to avoid running afoul of `no-dot-config-targets`.

init/Kconfig

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,16 @@ config LLD_VERSION
6060
default $(ld-version) if LD_IS_LLD
6161
default 0
6262

63-
config HAS_RUST
64-
depends on ARM64 || CPU_32v6 || CPU_32v6K || (PPC64 && CPU_LITTLE_ENDIAN) || X86_64 || RISCV
65-
def_bool $(success,$(RUSTC) --version)
63+
config RUST_IS_AVAILABLE
64+
def_bool $(success,$(srctree)/scripts/rust-is-available.sh)
65+
help
66+
This shows whether a suitable Rust toolchain is available (found).
6667

67-
config RUSTC_VERSION
68-
depends on HAS_RUST
69-
int
70-
default $(shell,$(srctree)/scripts/rust-version.sh $(RUSTC))
68+
Please see Documentation/rust/quick-start.rst for instructions on how
69+
to satify the build requirements of Rust support.
70+
71+
In particular, the Makefile target 'rustavailable' is useful to check
72+
why the Rust toolchain is not being detected.
7173

7274
config CC_CAN_LINK
7375
bool
@@ -2056,7 +2058,8 @@ config PROFILING
20562058

20572059
config RUST
20582060
bool "Rust support"
2059-
depends on HAS_RUST
2061+
depends on RUST_IS_AVAILABLE
2062+
depends on ARM64 || CPU_32v6 || CPU_32v6K || (PPC64 && CPU_LITTLE_ENDIAN) || X86_64 || RISCV
20602063
depends on !COMPILE_TEST
20612064
depends on !MODVERSIONS
20622065
depends on !GCC_PLUGIN_RANDSTRUCT
@@ -2074,6 +2077,16 @@ config RUST
20742077

20752078
If unsure, say N.
20762079

2080+
config RUSTC_VERSION_TEXT
2081+
depends on RUST
2082+
string
2083+
default $(shell,$(RUSTC) --version)
2084+
2085+
config BINDGEN_VERSION_TEXT
2086+
depends on RUST
2087+
string
2088+
default $(shell,$(BINDGEN) --version)
2089+
20772090
#
20782091
# Place an empty function call at each tracepoint site. Can be
20792092
# dynamically changed for a probe function.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#pragma message("clang version " __clang_version__)

scripts/rust-is-available.sh

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#!/bin/sh
2+
# SPDX-License-Identifier: GPL-2.0
3+
#
4+
# Tests whether a suitable Rust toolchain is available.
5+
#
6+
# Pass `-v` for human output and more checks (as warnings).
7+
8+
set -e
9+
10+
min_tool_version=$(dirname $0)/min-tool-version.sh
11+
12+
# Convert the version string x.y.z to a canonical up-to-7-digits form.
13+
#
14+
# Note that this function uses one more digit (compared to other
15+
# instances in other version scripts) to give a bit more space to
16+
# `rustc` since it will reach 1.100.0 in late 2026.
17+
get_canonical_version()
18+
{
19+
IFS=.
20+
set -- $1
21+
echo $((100000 * $1 + 100 * $2 + $3))
22+
}
23+
24+
# Check that the Rust compiler exists.
25+
if ! command -v "$RUSTC" >/dev/null; then
26+
if [ "$1" = -v ]; then
27+
echo >&2 "***"
28+
echo >&2 "*** Rust compiler '$RUSTC' could not be found."
29+
echo >&2 "***"
30+
fi
31+
exit 1
32+
fi
33+
34+
# Check that the Rust bindings generator exists.
35+
if ! command -v "$BINDGEN" >/dev/null; then
36+
if [ "$1" = -v ]; then
37+
echo >&2 "***"
38+
echo >&2 "*** Rust bindings generator '$BINDGEN' could not be found."
39+
echo >&2 "***"
40+
fi
41+
exit 1
42+
fi
43+
44+
# Check that the Rust compiler version is suitable.
45+
#
46+
# Non-stable and distributions' versions may have a version suffix, e.g. `-dev`.
47+
rust_compiler_version=$("$RUSTC" --version | cut -f2 -d' ' | cut -f1 -d'-')
48+
rust_compiler_min_version=$($min_tool_version rustc)
49+
rust_compiler_cversion=$(get_canonical_version $rust_compiler_version)
50+
rust_compiler_min_cversion=$(get_canonical_version $rust_compiler_min_version)
51+
if [ "$rust_compiler_cversion" -lt "$rust_compiler_min_cversion" ]; then
52+
if [ "$1" = -v ]; then
53+
echo >&2 "***"
54+
echo >&2 "*** Rust compiler '$RUSTC' is too old."
55+
echo >&2 "*** Your version: $rust_compiler_version"
56+
echo >&2 "*** Minimum version: $rust_compiler_min_version"
57+
echo >&2 "***"
58+
fi
59+
exit 1
60+
fi
61+
if [ "$1" = -v ] && [ "$rust_compiler_cversion" -gt "$rust_compiler_min_cversion" ]; then
62+
echo >&2 "***"
63+
echo >&2 "*** Rust compiler '$RUSTC' is too new. This may or may not work."
64+
echo >&2 "*** Your version: $rust_compiler_version"
65+
echo >&2 "*** Expected version: $rust_compiler_min_version"
66+
echo >&2 "***"
67+
fi
68+
69+
# Check that the Rust bindings generator is suitable.
70+
#
71+
# Non-stable and distributions' versions may have a version suffix, e.g. `-dev`.
72+
rust_bindings_generator_version=$("$BINDGEN" --version | cut -f2 -d' ' | cut -f1 -d'-')
73+
rust_bindings_generator_min_version=$($min_tool_version bindgen)
74+
rust_bindings_generator_cversion=$(get_canonical_version $rust_bindings_generator_version)
75+
rust_bindings_generator_min_cversion=$(get_canonical_version $rust_bindings_generator_min_version)
76+
if [ "$rust_bindings_generator_cversion" -lt "$rust_bindings_generator_min_cversion" ]; then
77+
if [ "$1" = -v ]; then
78+
echo >&2 "***"
79+
echo >&2 "*** Rust bindings generator '$BINDGEN' is too old."
80+
echo >&2 "*** Your version: $rust_bindings_generator_version"
81+
echo >&2 "*** Minimum version: $rust_bindings_generator_min_version"
82+
echo >&2 "***"
83+
fi
84+
exit 1
85+
fi
86+
if [ "$1" = -v ] && [ "$rust_bindings_generator_cversion" -gt "$rust_bindings_generator_min_cversion" ]; then
87+
echo >&2 "***"
88+
echo >&2 "*** Rust bindings generator '$BINDGEN' is too new. This may or may not work."
89+
echo >&2 "*** Your version: $rust_bindings_generator_version"
90+
echo >&2 "*** Expected version: $rust_bindings_generator_min_version"
91+
echo >&2 "***"
92+
fi
93+
94+
# Check that the `libclang` used by the Rust bindings generator is suitable.
95+
#
96+
# There may be a better way to do this in the future,
97+
# see https://github.com/rust-lang/rust-bindgen/issues/2138
98+
bindgen_libclang_full_version=$(\
99+
"$BINDGEN" $(dirname $0)/rust-is-available-bindgen-libclang.h 2>&1 >/dev/null \
100+
| grep -F 'clang version' \
101+
| sed -E 's:^.*(clang version .*) \[.*$:\1:' \
102+
)
103+
bindgen_libclang_version=$(echo "$bindgen_libclang_full_version" | cut -f3 -d' ')
104+
bindgen_libclang_min_version=$($min_tool_version llvm)
105+
bindgen_libclang_cversion=$(get_canonical_version $bindgen_libclang_version)
106+
bindgen_libclang_min_cversion=$(get_canonical_version $bindgen_libclang_min_version)
107+
if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then
108+
if [ "$1" = -v ]; then
109+
echo >&2 "***"
110+
echo >&2 "*** libclang (used by the Rust bindings generator '$BINDGEN') is too old."
111+
echo >&2 "*** Your version: $bindgen_libclang_version"
112+
echo >&2 "*** Minimum version: $bindgen_libclang_min_version"
113+
echo >&2 "***"
114+
fi
115+
exit 1
116+
fi
117+
118+
# If the C compiler is Clang, then we can also check whether its full version
119+
# matches exactly the `libclang` used by the Rust bindings generator.
120+
if [ "$1" = -v ]; then
121+
cc_name=$($(dirname $0)/cc-version.sh "$CC" | cut -f1 -d' ')
122+
if [ "$cc_name" = Clang ]; then
123+
clang_full_version=$("$CC" --version | grep -F 'clang version')
124+
if [ "$clang_full_version" != "$bindgen_libclang_full_version" ]; then
125+
echo >&2 "***"
126+
echo >&2 "*** libclang (used by the Rust bindings generator '$BINDGEN') full version does not match Clang's. This may be a problem."
127+
echo >&2 "*** libclang: $bindgen_libclang_full_version"
128+
echo >&2 "*** Clang: $clang_full_version"
129+
echo >&2 "***"
130+
fi
131+
fi
132+
fi
133+
134+
# Check that the source code for the `core` standard library exists.
135+
#
136+
# `$KRUSTFLAGS` is passed in case the user added `--sysroot`.
137+
rustc_sysroot=$("$RUSTC" $KRUSTFLAGS --print sysroot)
138+
rustc_src="$rustc_sysroot/lib/rustlib/src/rust/library"
139+
rustc_src_core="$rustc_src/core/src/lib.rs"
140+
if [ ! -e "$rustc_src_core" ]; then
141+
if [ "$1" = -v ]; then
142+
echo >&2 "***"
143+
echo >&2 "*** Source code for the 'core' standard library could not be found"
144+
echo >&2 "*** at '$rustc_src_core'."
145+
echo >&2 "***"
146+
fi
147+
exit 1
148+
fi
149+
150+
# Success!
151+
if [ "$1" = -v ]; then
152+
echo >&2 "Rust is available!"
153+
fi

scripts/rust-version.sh

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)