diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index 4f5756a9d2d7a3..e85e4137c20f4a 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -26,17 +26,12 @@ running a Linux kernel. Also, not all tools are necessary on all systems; obviously, if you don't have any PC Card hardware, for example, you probably needn't concern yourself with pcmciautils. -Furthermore, note that newer versions of the Rust toolchain may or may not work -because, for the moment, we depend on some unstable features. Thus, unless you -know what you are doing, use the exact version listed here. Please see -:ref:`Documentation/rust/quick-start.rst ` for details. - ====================== =============== ======================================== Program Minimal version Command to check the version ====================== =============== ======================================== GNU C 5.1 gcc --version Clang/LLVM (optional) 10.0.1 clang --version -rustc (optional) 1.58.0 rustc --version +Rust (optional) 1.58.0 rustc --version bindgen (optional) 0.56.0 bindgen --version GNU make 3.81 make --version binutils 2.23 ld -v @@ -85,6 +80,27 @@ kernels. Older releases aren't guaranteed to work, and we may drop workarounds from the kernel that were used to support older versions. Please see additional docs on :ref:`Building Linux with Clang/LLVM `. +Rust (optional) +--------------- + +A particular version of the Rust toolchain is required. Newer versions may or +may not work because the kernel depends on some unstable Rust features, for +the moment. + +Each Rust toolchain comes with several "components", some of which are required +(like ``rustc``) and some that are optional. The ``rust-src`` component (which +is optional) needs to be installed to build the kernel. Other components are +useful for developing. + +Please see :ref:`Documentation/rust/quick-start.rst ` for +more information. + +bindgen (optional) +------------------ + +``bindgen`` is used to generate the Rust bindings to the C side of the kernel. +It depends on ``libclang``. + Make ---- @@ -369,6 +385,16 @@ Clang/LLVM - :ref:`Getting LLVM `. +Rust +---- + +- :ref:`Documentation/rust/quick-start.rst `. + +bindgen +------- + +- :ref:`Documentation/rust/quick-start.rst `. + Make ---- diff --git a/Documentation/rust/quick-start.rst b/Documentation/rust/quick-start.rst index 57fd3e0d5f60d7..9ecb171f711af7 100644 --- a/Documentation/rust/quick-start.rst +++ b/Documentation/rust/quick-start.rst @@ -13,7 +13,17 @@ This section explains how to fetch the tools needed for building. Some of these requirements might be available from Linux distributions under names like ``rustc``, ``rust-src``, ``rust-bindgen``, etc. However, -at the time of writing, they are likely not to be recent enough. +at the time of writing, they are likely not to be recent enough unless +the distribution tracks the latest releases. + +To easily check whether the requirements are met, the following target +can be used:: + + make LLVM=1 rustavailable + +This triggers the same logic used by Kconfig to determine whether +``RUST_IS_AVAILABLE`` should be enabled; but it also explains why not +if that is the case. rustc @@ -26,7 +36,7 @@ Rust features. If ``rustup`` is being used, enter the checked out source code directory and run:: - rustup override set 1.58.0 + rustup override set $(scripts/min-tool-version.sh rustc) Otherwise, fetch a standalone installer or install ``rustup`` from: @@ -43,10 +53,19 @@ If ``rustup`` is being used, run:: rustup component add rust-src +The components are installed per toolchain, thus upgrading the Rust compiler +version later on requires re-adding the component. + Otherwise, if a standalone installer is used, the Rust repository may be cloned into the installation folder of the toolchain:: - git clone --recurse-submodules https://github.com/rust-lang/rust $(rustc --print sysroot)/lib/rustlib/src/rust + git clone --recurse-submodules \ + --branch $(scripts/min-tool-version.sh rustc) \ + https://github.com/rust-lang/rust \ + $(rustc --print sysroot)/lib/rustlib/src/rust + +In this case, upgrading the Rust compiler version later on requires manually +updating this clone. libclang @@ -67,8 +86,8 @@ Otherwise, building LLVM takes quite a while, but it is not a complex process: https://llvm.org/docs/GettingStarted.html#getting-the-source-code-and-building-llvm -See Documentation/kbuild/llvm.rst for more information and further ways -to fetch pre-built releases and distribution packages. +See :ref:`Documentation/kbuild/llvm.rst ` for more information and +further ways to fetch pre-built releases and distribution packages. bindgen @@ -79,7 +98,7 @@ the ``bindgen`` tool. A particular version is required. Install it via (note that this will download and build the tool from source):: - cargo install --locked --version 0.56.0 bindgen + cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen Requirements: Developing @@ -167,8 +186,8 @@ Configuration ------------- ``Rust support`` (``CONFIG_RUST``) needs to be enabled in the ``General setup`` -menu. The option is only shown if the build system can locate ``rustc``. -In turn, this will make visible the rest of options that depend on Rust. +menu. The option is only shown if a suitable Rust toolchain is found (see +above). In turn, this will make visible the rest of options that depend on Rust. Afterwards, go to:: diff --git a/MAINTAINERS b/MAINTAINERS index b6c447439803ca..5f3816c713fc48 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16591,6 +16591,7 @@ F: rust/ F: samples/rust/ F: Documentation/rust/ F: lib/rust.h +F: scripts/*rust* K: \b(?i:rust)\b RXRPC SOCKETS (AF_RXRPC) diff --git a/Makefile b/Makefile index e521db8e29149c..a8eaba28db6b11 100644 --- a/Makefile +++ b/Makefile @@ -274,7 +274,7 @@ no-dot-config-targets := $(clean-targets) \ cscope gtags TAGS tags help% %docs check% coccicheck \ $(version_h) headers headers_% archheaders archscripts \ %asm-generic kernelversion %src-pkg dt_binding_check \ - outputmakefile rustfmt rustfmtcheck + outputmakefile rustavailable rustfmt rustfmtcheck # Installation targets should not require compiler. Unfortunately, vdso_install # is an exception where build artifacts may be updated. This must be fixed. no-compiler-targets := $(no-dot-config-targets) install dtbs_install \ @@ -809,7 +809,7 @@ KBUILD_CFLAGS += -O3 KBUILD_RUSTFLAGS_OPT_LEVEL_MAP := 3 else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE KBUILD_CFLAGS += -Os -KBUILD_RUSTFLAGS_OPT_LEVEL_MAP := z +KBUILD_RUSTFLAGS_OPT_LEVEL_MAP := s endif # Always set `debug-assertions` and `overflow-checks` because their default @@ -1696,6 +1696,8 @@ help: @echo ' kselftest to existing .config.' @echo '' @echo 'Rust targets:' + @echo ' rustavailable - Checks whether the Rust toolchain is' + @echo ' available and, if not, explains why.' @echo ' rustfmt - Reformat all the Rust code in the kernel' @echo ' rustfmtcheck - Checks if all the Rust code in the kernel' @echo ' is formatted, printing a diff otherwise.' @@ -1781,6 +1783,11 @@ $(DOC_TARGETS): # Rust targets # --------------------------------------------------------------------------- +# "Is Rust available?" target +PHONY += rustavailable +rustavailable: + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust-is-available.sh -v + # Documentation target # # Using the singular to avoid running afoul of `no-dot-config-targets`. diff --git a/init/Kconfig b/init/Kconfig index 03d3c21e28a3a3..c6497c816b2bae 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -60,14 +60,16 @@ config LLD_VERSION default $(ld-version) if LD_IS_LLD default 0 -config HAS_RUST - depends on ARM64 || CPU_32v6 || CPU_32v6K || (PPC64 && CPU_LITTLE_ENDIAN) || X86_64 || RISCV - def_bool $(success,$(RUSTC) --version) +config RUST_IS_AVAILABLE + def_bool $(success,$(srctree)/scripts/rust-is-available.sh) + help + This shows whether a suitable Rust toolchain is available (found). -config RUSTC_VERSION - depends on HAS_RUST - int - default $(shell,$(srctree)/scripts/rust-version.sh $(RUSTC)) + Please see Documentation/rust/quick-start.rst for instructions on how + to satify the build requirements of Rust support. + + In particular, the Makefile target 'rustavailable' is useful to check + why the Rust toolchain is not being detected. config CC_CAN_LINK bool @@ -2056,9 +2058,11 @@ config PROFILING config RUST bool "Rust support" - depends on HAS_RUST + depends on RUST_IS_AVAILABLE + depends on ARM64 || CPU_32v6 || CPU_32v6K || (PPC64 && CPU_LITTLE_ENDIAN) || X86_64 || RISCV depends on !COMPILE_TEST depends on !MODVERSIONS + depends on !GCC_PLUGIN_RANDSTRUCT default n help Enables Rust support in the kernel. @@ -2073,6 +2077,16 @@ config RUST If unsure, say N. +config RUSTC_VERSION_TEXT + depends on RUST + string + default $(shell,$(RUSTC) --version) + +config BINDGEN_VERSION_TEXT + depends on RUST + string + default $(shell,$(BINDGEN) --version) + # # Place an empty function call at each tracepoint site. Can be # dynamically changed for a probe function. diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index e61ae3ec3a53de..b9bc9ca74359ef 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2677,7 +2677,7 @@ config RUST_OVERFLOW_CHECKS Enables rustc's `-Coverflow-checks` codegen option. This flag allows you to control the behavior of runtime integer - overflow. When overflow-checks are enabled, a panic will occur + overflow. When overflow-checks are enabled, a Rust panic will occur on overflow. Note that this will apply to all Rust code, including `core`. diff --git a/rust/Makefile b/rust/Makefile index 390207593f60c6..3ab462eb381f5f 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -188,26 +188,24 @@ else # bindgen relies on libclang to parse C. Ideally, bindgen would support a GCC # plugin backend and/or the Clang driver would be perfectly compatible with GCC. # -# For the moment, here we are tweaking the flags on the fly. Some config -# options may not work (e.g. `GCC_PLUGIN_RANDSTRUCT` if we end up using one -# of those structs). +# For the moment, here we are tweaking the flags on the fly. This is a hack, +# and some kernel configurations may not work (e.g. `GCC_PLUGIN_RANDSTRUCT` +# if we end up using one of those structs). bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \ -mskip-rax-setup -mgeneral-regs-only -msign-return-address=% \ -mindirect-branch=thunk-extern -mindirect-branch-register -mrecord-mcount \ - -mabi=lp64 -mstack-protector-guard% -fconserve-stack -falign-jumps=% \ - -falign-loops=% -femit-struct-debug-baseonly \ - -fno-ipa-cp-clone -fno-ipa-sra -fno-partial-inlining \ - -fplugin-arg-arm_ssp_per_task_plugin-% \ + -mabi=lp64 -mstack-protector-guard% -mtraceback=no \ + -mno-pointers-to-nested-functions -mno-string -mno-strict-align \ + -fconserve-stack -falign-jumps=% -falign-loops=% \ + -femit-struct-debug-baseonly -fno-ipa-cp-clone -fno-ipa-sra \ + -fno-partial-inlining -fplugin-arg-arm_ssp_per_task_plugin-% \ -fno-reorder-blocks -fno-allow-store-data-races -fasan-shadow-offset=% \ -Wno-packed-not-aligned -Wno-format-truncation -Wno-format-overflow \ -Wno-stringop-truncation -Wno-unused-but-set-variable \ -Wno-stringop-overflow -Wno-restrict -Wno-maybe-uninitialized \ -Werror=designated-init -Wno-zero-length-bounds -Wimplicit-fallthrough=% \ - -Wno-alloc-size-larger-than --param=% --param asan-% - -# PowerPC -bindgen_skip_c_flags += -mtraceback=no -mno-pointers-to-nested-functions \ - -mno-string -mno-strict-align + -Wno-alloc-size-larger-than \ + --param=% --param asan-% # Derived from `scripts/Makefile.clang` BINDGEN_TARGET_arm := arm-linux-gnueabi diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include index 0496efd6e11794..83e850321eb6a7 100644 --- a/scripts/Kconfig.include +++ b/scripts/Kconfig.include @@ -36,12 +36,12 @@ ld-option = $(success,$(LD) -v $(1)) as-instr = $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -c -x assembler -o /dev/null -) # check if $(CC) and $(LD) exist -$(error-if,$(failure,command -v $(CC)),compiler '$(CC)' not found) +$(error-if,$(failure,command -v $(CC)),C compiler '$(CC)' not found) $(error-if,$(failure,command -v $(LD)),linker '$(LD)' not found) -# Get the compiler name, version, and error out if it is not supported. +# Get the C compiler name, version, and error out if it is not supported. cc-info := $(shell,$(srctree)/scripts/cc-version.sh $(CC)) -$(error-if,$(success,test -z "$(cc-info)"),Sorry$(comma) this compiler is not supported.) +$(error-if,$(success,test -z "$(cc-info)"),Sorry$(comma) this C compiler is not supported.) cc-name := $(shell,set -- $(cc-info) && echo $1) cc-version := $(shell,set -- $(cc-info) && echo $2) diff --git a/scripts/cc-version.sh b/scripts/cc-version.sh index f1952c52246624..2401c86fcf5331 100755 --- a/scripts/cc-version.sh +++ b/scripts/cc-version.sh @@ -1,13 +1,13 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 # -# Print the compiler name and its version in a 5 or 6-digit form. +# Print the C compiler name and its version in a 5 or 6-digit form. # Also, perform the minimum version check. set -e -# Print the compiler name and some version components. -get_compiler_info() +# Print the C compiler name and some version components. +get_c_compiler_info() { cat <<- EOF | "$@" -E -P -x c - 2>/dev/null #if defined(__clang__) @@ -32,7 +32,7 @@ get_canonical_version() # $@ instead of $1 because multiple words might be given, e.g. CC="ccache gcc". orig_args="$@" -set -- $(get_compiler_info "$@") +set -- $(get_c_compiler_info "$@") name=$1 @@ -52,7 +52,7 @@ ICC) min_version=$($min_tool_version icc) ;; *) - echo "$orig_args: unknown compiler" >&2 + echo "$orig_args: unknown C compiler" >&2 exit 1 ;; esac @@ -62,7 +62,7 @@ min_cversion=$(get_canonical_version $min_version) if [ "$cversion" -lt "$min_cversion" ]; then echo >&2 "***" - echo >&2 "*** Compiler is too old." + echo >&2 "*** C compiler is too old." echo >&2 "*** Your $name version: $version" echo >&2 "*** Minimum $name version: $min_version" echo >&2 "***" diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh index 4edc708baa6356..05c95710d7e3d2 100755 --- a/scripts/min-tool-version.sh +++ b/scripts/min-tool-version.sh @@ -31,6 +31,12 @@ llvm) echo 10.0.1 fi ;; +rustc) + echo 1.58.0 + ;; +bindgen) + echo 0.56.0 + ;; *) echo "$1: unknown tool" >&2 exit 1 diff --git a/scripts/rust-is-available-bindgen-libclang.h b/scripts/rust-is-available-bindgen-libclang.h new file mode 100644 index 00000000000000..0ef6db10d67413 --- /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__) diff --git a/scripts/rust-is-available.sh b/scripts/rust-is-available.sh new file mode 100755 index 00000000000000..5741dcf64bc984 --- /dev/null +++ b/scripts/rust-is-available.sh @@ -0,0 +1,153 @@ +#!/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=$("$RUSTC" --version | cut -f2 -d' ' | cut -f1 -d'-') +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=$("$BINDGEN" --version | cut -f2 -d' ' | cut -f1 -d'-') +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. +# +# There may be a better way to do this in the future, +# see https://github.com/rust-lang/rust-bindgen/issues/2138 +bindgen_libclang_full_version=$(\ + "$BINDGEN" $(dirname $0)/rust-is-available-bindgen-libclang.h 2>&1 >/dev/null \ + | grep -F 'clang version' \ + | sed -E 's:^.*(clang version .*) \[.*$:\1:' \ +) +bindgen_libclang_version=$(echo "$bindgen_libclang_full_version" | cut -f3 -d' ') +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 full version +# matches exactly the `libclang` used by the Rust bindings generator. +if [ "$1" = -v ]; then + cc_name=$($(dirname $0)/cc-version.sh "$CC" | cut -f1 -d' ') + if [ "$cc_name" = Clang ]; then + clang_full_version=$("$CC" --version | grep -F 'clang version') + if [ "$clang_full_version" != "$bindgen_libclang_full_version" ]; then + echo >&2 "***" + echo >&2 "*** libclang (used by the Rust bindings generator '$BINDGEN') full version does not match Clang's. This may be a problem." + echo >&2 "*** libclang: $bindgen_libclang_full_version" + echo >&2 "*** Clang: $clang_full_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="$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 + +# Success! +if [ "$1" = -v ]; then + echo >&2 "Rust is available!" +fi diff --git a/scripts/rust-version.sh b/scripts/rust-version.sh deleted file mode 100755 index 67b6d31688e24b..00000000000000 --- a/scripts/rust-version.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 -# -# rust-version rust-command -# -# Print the compiler version of `rust-command' in a 5 or 6-digit form -# such as `14502' for rustc-1.45.2 etc. -# -# Returns 0 if not found (so that Kconfig does not complain) -compiler="$*" - -if [ ${#compiler} -eq 0 ]; then - echo "Error: No compiler specified." >&2 - printf "Usage:\n\t$0 \n" >&2 - exit 1 -fi - -if ! command -v $compiler >/dev/null 2>&1; then - echo 0 - exit 0 -fi - -VERSION=$($compiler --version | cut -f2 -d' ') - -# Cut suffix if any (e.g. `-dev`) -VERSION=$(echo $VERSION | cut -f1 -d'-') - -MAJOR=$(echo $VERSION | cut -f1 -d'.') -MINOR=$(echo $VERSION | cut -f2 -d'.') -PATCHLEVEL=$(echo $VERSION | cut -f3 -d'.') -printf "%d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL