Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | #!/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 if [ "$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 "***" warning=1 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_output=$( \ LC_ALL=C "$BINDGEN" --version 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" -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 "***" warning=1 fi # Check that the `libclang` used by the Rust bindings generator is suitable. # # 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=$( \ echo "$bindgen_libclang_output" \ | 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 # 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 |