RUST_VERSION="${RUST_VERSION:-1.85.0}"
BINDGEN_VERSION="${BINDGEN_VERSION:-0.71.1}"
RUST_KERNEL_SAMPLES="${RUST_KERNEL_SAMPLES:-no}"
declare -g -a RUST_EXTRA_COMPONENTS=()
declare -g -a RUST_EXTRA_CARGO_CRATES=()
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"
EXTRA_BUILD_DEPS+=("clang::libclang-dev")
}
_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}"
}
_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"
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
rm -f "${rust_cache_dir}"/.marker-*
display_alert "Installing Rust toolchain" "rustc ${RUST_VERSION}, bindgen ${BINDGEN_VERSION}" "info"
do_with_retries 3 _download_rustup_init "${rust_cache_dir}"
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
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[@]}"
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
touch "${marker}"
display_alert "Rust toolchain installed" "${cache_hash}" "info"
}
_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)"
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
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() {
local cache_key="${RUST_VERSION}|${BINDGEN_VERSION}"
local short
short="$(echo -n "${cache_key}" | sha256sum | cut -c1-4)"
artifact_version_parts["_R"]="rust${short}"
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() {
opts_y+=("RUST")
if [[ "${RUST_KERNEL_SAMPLES}" == "yes" ]]; then
display_alert "Enabling Rust sample modules" "${EXTENSION}" "info"
opts_y+=("SAMPLES")
opts_y+=("SAMPLES_RUST")
opts_m+=("SAMPLE_RUST_MINIMAL")
opts_m+=("SAMPLE_RUST_PRINT")
opts_m+=("SAMPLE_RUST_DRIVER_FAUX")
fi
}
function pre_package_kernel_headers__add_rust_artifacts() {
if ! grep -q "^CONFIG_RUST=y" "${kernel_work_dir}/include/config/auto.conf" 2> /dev/null; then
display_alert "Kernel built without CONFIG_RUST, not adding Rust artifacts to headers" "${EXTENSION}" "debug"
return 0
fi
declare -a rust_artifacts=()
local f
for f in "${kernel_work_dir}/rust/"*.rmeta "${kernel_work_dir}/rust/"*.so "${kernel_work_dir}/rust/helpers/"*.bc; do
if [[ -f "${f}" ]]; then
rust_artifacts+=("${f#"${kernel_work_dir}/"}")
fi
done
if [[ ${#rust_artifacts[@]} -eq 0 ]]; then
exit_with_error "CONFIG_RUST=y but no rust/*.rmeta artifacts found in kernel tree" "${EXTENSION}"
fi
local host_arch target_arch_pattern
host_arch="$(uname -m)"
case "${ARCH}" in
arm64) target_arch_pattern="aarch64" ;;
amd64) target_arch_pattern="x86_64" ;;
armhf) target_arch_pattern="armv[6-8]l" ;;
riscv64) target_arch_pattern="riscv64" ;;
*) target_arch_pattern="${ARCH}" ;;
esac
case "${host_arch}" in
${target_arch_pattern}) : ;;
*)
display_alert "Rust proc-macro .so in headers are ${host_arch} binaries" \
"${EXTENSION}: Rust DKMS on ${ARCH} target requires natively-built headers" "wrn"
;;
esac
display_alert "Adding Rust artifacts to linux-headers" "${EXTENSION}: ${#rust_artifacts[@]} files" "info"
tar -c -f - -C "${kernel_work_dir}" "${rust_artifacts[@]}" | tar -xf - -C "${headers_target_dir}"
if [[ "${PIPESTATUS[0]}" -ne 0 || "${PIPESTATUS[1]}" -ne 0 ]]; then
exit_with_error "Failed to copy Rust artifacts into headers package" "${EXTENSION}"
fi
}
function custom_kernel_make_params__add_rust_compiler() {
common_make_params_quoted+=("RUSTC=${RUST_TOOL_RUSTC}")
common_make_params_quoted+=("RUSTFMT=${RUST_TOOL_RUSTFMT}")
common_make_params_quoted+=("BINDGEN=${RUST_TOOL_BINDGEN}")
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
}