extensions: add kernel-rust extension for Rust support in kernel builds
Add extension that enables CONFIG_RUST in kernel menuconfig and configures the build environment (rustc, rustfmt, bindgen, rust-src) using versioned APT packages from noble-security/noble-updates. Handles env -i in run_kernel_make_internal by passing tool paths via RUSTC, RUSTFMT, BINDGEN make params and RUST_LIB_SRC env var. Includes optional RUST_KERNEL_SAMPLES=yes for building sample Rust modules (rust_minimal, rust_print, rust_driver_faux) as a toolchain smoke test. Tested: kernel 6.19 build for rockchip64 on aarch64, both with and without Docker. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9b2497deb6
commit
4222417736
219
extensions/kernel-rust.sh
Normal file
219
extensions/kernel-rust.sh
Normal file
@ -0,0 +1,219 @@
|
||||
# Enable Rust support for Linux kernel compilation.
|
||||
#
|
||||
# Installs Rust toolchain via rustup into ${SRC}/cache/tools/rustup/ and
|
||||
# configures the build environment so that CONFIG_RUST appears in kernel
|
||||
# menuconfig and gets enabled automatically.
|
||||
#
|
||||
# The toolchain is cached by a hash of (RUST_VERSION, BINDGEN_VERSION, arch,
|
||||
# RUST_EXTRA_COMPONENTS, RUST_EXTRA_CARGO_CRATES). Changing any of these
|
||||
# triggers a full reinstall on the next build.
|
||||
#
|
||||
# Other extensions can request additional rustup components or cargo crates:
|
||||
# RUST_EXTRA_COMPONENTS+=("clippy" "llvm-tools")
|
||||
# RUST_EXTRA_CARGO_CRATES+=("mdbook" "cargo-deb@2.11.0")
|
||||
#
|
||||
# Usage: ./compile.sh kernel-config BOARD=... BRANCH=... ENABLE_EXTENSIONS="kernel-rust"
|
||||
#
|
||||
# References:
|
||||
# https://docs.kernel.org/rust/quick-start.html
|
||||
# https://docs.kernel.org/rust/general-information.html
|
||||
# https://rust-for-linux.com/rust-version-policy
|
||||
# https://rust-lang.github.io/rustup/installation/index.html
|
||||
|
||||
# Rust toolchain version installed via rustup.
|
||||
# Kernel >= 6.12 requires rustc >= 1.78. See rust-version-policy above.
|
||||
RUST_VERSION="${RUST_VERSION:-1.85.0}"
|
||||
|
||||
# bindgen-cli version installed via cargo.
|
||||
# APT bindgen 0.66.1 panics on kernel >= 6.19 headers (FromBytesWithNulError
|
||||
# in codegen/mod.rs). Fixed in >= 0.69.
|
||||
BINDGEN_VERSION="${BINDGEN_VERSION:-0.71.1}"
|
||||
|
||||
# Enable Rust sample kernel modules for toolchain smoke testing.
|
||||
# Set to "yes" to build rust_minimal, rust_print, rust_driver_faux as modules.
|
||||
# Can also be set via command line: RUST_KERNEL_SAMPLES=yes
|
||||
RUST_KERNEL_SAMPLES="${RUST_KERNEL_SAMPLES:-no}"
|
||||
|
||||
# Extra rustup components to install (e.g. clippy, llvm-tools).
|
||||
# Other extensions can append: RUST_EXTRA_COMPONENTS+=("clippy")
|
||||
declare -g -a RUST_EXTRA_COMPONENTS=()
|
||||
|
||||
# Extra cargo crates to install. Supports "name" or "name@version" syntax.
|
||||
# Other extensions can append: RUST_EXTRA_CARGO_CRATES+=("mdbook" "cargo-deb@2.11.0")
|
||||
declare -g -a RUST_EXTRA_CARGO_CRATES=()
|
||||
|
||||
# Resolved tool paths, set by host_dependencies_ready, used by custom_kernel_make_params.
|
||||
declare -g RUST_TOOL_RUSTC=""
|
||||
declare -g RUST_TOOL_RUSTFMT=""
|
||||
declare -g RUST_TOOL_BINDGEN=""
|
||||
declare -g RUST_TOOL_SYSROOT=""
|
||||
|
||||
function add_host_dependencies__add_rust_compiler() {
|
||||
display_alert "Adding Rust kernel build dependencies" "${EXTENSION}" "info"
|
||||
# bindgen needs libclang for dlopen; available on all target distros.
|
||||
EXTRA_BUILD_DEPS+=" libclang-dev "
|
||||
}
|
||||
|
||||
# Download rustup-init binary for the current architecture.
|
||||
# Follows the project pattern: curl → .tmp → mv → chmod.
|
||||
_download_rustup_init() {
|
||||
local target_dir="$1"
|
||||
local target_triple
|
||||
case "${BASH_VERSINFO[5]}" in
|
||||
*aarch64*) target_triple="aarch64-unknown-linux-gnu" ;;
|
||||
*x86_64*) target_triple="x86_64-unknown-linux-gnu" ;;
|
||||
*riscv64*) target_triple="riscv64gc-unknown-linux-gnu" ;;
|
||||
*) exit_with_error "Unsupported architecture for rustup" "${BASH_VERSINFO[5]}" ;;
|
||||
esac
|
||||
|
||||
local url="https://static.rust-lang.org/rustup/dist/${target_triple}/rustup-init"
|
||||
local dest="${target_dir}/rustup-init"
|
||||
|
||||
display_alert "Downloading rustup-init" "${target_triple}" "info"
|
||||
curl --proto '=https' --tlsv1.2 -sSf -o "${dest}.tmp" "${url}"
|
||||
mv "${dest}.tmp" "${dest}"
|
||||
chmod +x "${dest}"
|
||||
}
|
||||
|
||||
# Install or reuse cached Rust toolchain in ${SRC}/cache/tools/rustup/.
|
||||
_prepare_rust_toolchain() {
|
||||
local rust_cache_dir="${SRC}/cache/tools/rustup"
|
||||
mkdir -p "${rust_cache_dir}"
|
||||
|
||||
local rustup_home="${rust_cache_dir}/rustup-home"
|
||||
local cargo_home="${rust_cache_dir}/cargo-home"
|
||||
|
||||
# Content-addressable cache: hash of version config + architecture + extras
|
||||
local cache_key="${RUST_VERSION}|${BINDGEN_VERSION}|${BASH_VERSINFO[5]}"
|
||||
cache_key+="|${RUST_EXTRA_COMPONENTS[*]}|${RUST_EXTRA_CARGO_CRATES[*]}"
|
||||
local cache_hash
|
||||
cache_hash="$(echo -n "${cache_key}" | sha256sum | cut -c1-16)"
|
||||
local marker="${rust_cache_dir}/.marker-${cache_hash}"
|
||||
|
||||
if [[ -f "${marker}" ]]; then
|
||||
display_alert "Rust toolchain cache hit" "${cache_hash}" "cachehit"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Remove stale markers from previous versions
|
||||
rm -f "${rust_cache_dir}"/.marker-*
|
||||
|
||||
display_alert "Installing Rust toolchain" "rustc ${RUST_VERSION}, bindgen ${BINDGEN_VERSION}" "info"
|
||||
|
||||
# Download rustup-init
|
||||
do_with_retries 3 _download_rustup_init "${rust_cache_dir}"
|
||||
|
||||
# Install minimal toolchain; SKIP_PATH_CHECK suppresses warnings about
|
||||
# system rustc in /usr/bin (e.g. from mtkflash in Docker images).
|
||||
RUSTUP_HOME="${rustup_home}" CARGO_HOME="${cargo_home}" \
|
||||
RUSTUP_INIT_SKIP_PATH_CHECK=yes \
|
||||
"${rust_cache_dir}/rustup-init" -y \
|
||||
--profile minimal \
|
||||
--default-toolchain "${RUST_VERSION}" \
|
||||
--no-modify-path
|
||||
|
||||
# Components: rustfmt (not in minimal profile) + rust-src (kernel needs it) + extras
|
||||
local -a components=(rustfmt rust-src "${RUST_EXTRA_COMPONENTS[@]}")
|
||||
display_alert "Installing rustup components" "${components[*]}" "info"
|
||||
RUSTUP_HOME="${rustup_home}" CARGO_HOME="${cargo_home}" \
|
||||
"${cargo_home}/bin/rustup" component add "${components[@]}"
|
||||
|
||||
# Cargo crates: bindgen-cli (kernel needs it) + extras
|
||||
# Supports "name" or "name@version" syntax.
|
||||
local -a crates=("bindgen-cli@${BINDGEN_VERSION}" "${RUST_EXTRA_CARGO_CRATES[@]}")
|
||||
local crate
|
||||
for crate in "${crates[@]}"; do
|
||||
display_alert "Installing cargo crate" "${crate}" "info"
|
||||
RUSTUP_HOME="${rustup_home}" CARGO_HOME="${cargo_home}" \
|
||||
"${cargo_home}/bin/cargo" install --locked "${crate}"
|
||||
done
|
||||
|
||||
# Mark cache as valid only after everything succeeds
|
||||
touch "${marker}"
|
||||
display_alert "Rust toolchain installed" "${cache_hash}" "info"
|
||||
}
|
||||
|
||||
# Resolve absolute paths to Rust tool binaries.
|
||||
# Uses direct paths into the toolchain (not rustup proxies), so that
|
||||
# env -i in run_kernel_make_internal() does not need RUSTUP_HOME set.
|
||||
_resolve_rust_tool_paths() {
|
||||
local rustup_home="${SRC}/cache/tools/rustup/rustup-home"
|
||||
local cargo_home="${SRC}/cache/tools/rustup/cargo-home"
|
||||
|
||||
RUST_TOOL_SYSROOT="$(RUSTUP_HOME="${rustup_home}" CARGO_HOME="${cargo_home}" \
|
||||
"${cargo_home}/bin/rustc" --print sysroot)"
|
||||
|
||||
# Direct binaries inside the toolchain, bypassing rustup proxy
|
||||
RUST_TOOL_RUSTC="${RUST_TOOL_SYSROOT}/bin/rustc"
|
||||
RUST_TOOL_RUSTFMT="${RUST_TOOL_SYSROOT}/bin/rustfmt"
|
||||
RUST_TOOL_BINDGEN="${cargo_home}/bin/bindgen"
|
||||
}
|
||||
|
||||
function host_dependencies_ready__add_rust_compiler() {
|
||||
_prepare_rust_toolchain
|
||||
_resolve_rust_tool_paths
|
||||
|
||||
# Verify all tools are executable
|
||||
local tool_name tool_path
|
||||
for tool_name in RUST_TOOL_RUSTC RUST_TOOL_RUSTFMT RUST_TOOL_BINDGEN; do
|
||||
tool_path="${!tool_name}"
|
||||
[[ -x "${tool_path}" ]] || exit_with_error "Required Rust tool '${tool_name}' not found at ${tool_path}" "${EXTENSION}"
|
||||
done
|
||||
|
||||
display_alert "Rust toolchain ready" \
|
||||
"rustc $(${RUST_TOOL_RUSTC} --version | awk '{print $2}'), bindgen $(${RUST_TOOL_BINDGEN} --version 2>&1 | awk '{print $2}')" "info"
|
||||
}
|
||||
|
||||
function artifact_kernel_version_parts__add_rust_version() {
|
||||
# Include Rust toolchain version in artifact hash so that changing
|
||||
# RUST_VERSION or BINDGEN_VERSION triggers a kernel rebuild.
|
||||
local cache_key="${RUST_VERSION}|${BINDGEN_VERSION}"
|
||||
local short
|
||||
short="$(echo -n "${cache_key}" | sha256sum | cut -c1-4)"
|
||||
|
||||
artifact_version_parts["_R"]="rust${short}"
|
||||
|
||||
# Add to order array if not already present
|
||||
local found=0 entry
|
||||
for entry in "${artifact_version_part_order[@]}"; do
|
||||
[[ "${entry}" == *"-_R" ]] && found=1 && break
|
||||
done
|
||||
if [[ "${found}" -eq 0 ]]; then
|
||||
artifact_version_part_order+=("0086-_R")
|
||||
fi
|
||||
}
|
||||
|
||||
function custom_kernel_config__add_rust_compiler() {
|
||||
# https://docs.kernel.org/rust/quick-start.html
|
||||
opts_y+=("RUST")
|
||||
|
||||
# Build sample Rust modules for toolchain smoke testing
|
||||
if [[ "${RUST_KERNEL_SAMPLES}" == "yes" ]]; then
|
||||
display_alert "Enabling Rust sample modules" "${EXTENSION}" "info"
|
||||
opts_y+=("SAMPLES") # Parent menu for all kernel samples
|
||||
opts_y+=("SAMPLES_RUST")
|
||||
opts_m+=("SAMPLE_RUST_MINIMAL")
|
||||
opts_m+=("SAMPLE_RUST_PRINT")
|
||||
opts_m+=("SAMPLE_RUST_DRIVER_FAUX")
|
||||
fi
|
||||
}
|
||||
|
||||
function custom_kernel_make_params__add_rust_compiler() {
|
||||
# run_kernel_make_internal uses "env -i" which clears all environment
|
||||
# variables, so we pass Rust paths explicitly via make parameters.
|
||||
# Using direct toolchain binaries (not rustup proxies) avoids needing
|
||||
# RUSTUP_HOME in the env -i context.
|
||||
|
||||
common_make_params_quoted+=("RUSTC=${RUST_TOOL_RUSTC}")
|
||||
common_make_params_quoted+=("RUSTFMT=${RUST_TOOL_RUSTFMT}")
|
||||
common_make_params_quoted+=("BINDGEN=${RUST_TOOL_BINDGEN}")
|
||||
|
||||
# Rust standard library source path for kernel build
|
||||
local rust_lib_src="${RUST_TOOL_SYSROOT}/lib/rustlib/src/rust/library"
|
||||
if [[ -d "${rust_lib_src}" ]]; then
|
||||
display_alert "Rust library source" "${rust_lib_src}" "info"
|
||||
common_make_envs+=("RUST_LIB_SRC='${rust_lib_src}'")
|
||||
else
|
||||
display_alert "Rust library source not found" "CONFIG_RUST will not appear in menuconfig" "wrn"
|
||||
fi
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user