@@ -26,6 +26,42 @@ RUST_APT_VERSION="1.85"
2626# https://launchpad.net/ubuntu/noble/arm64/bindgen-0.71
2727BINDGEN_APT_VERSION=" 0.71"
2828
29+ # LLVM/Clang version must match the libclang that bindgen links against.
30+ # Auto-detect by resolving the dependency chain:
31+ # bindgen-0.71 → libclang-20-dev (versioned, Ubuntu 24.04)
32+ # bindgen → libclang-dev → libclang-NN-dev (unversioned, Debian/newer Ubuntu)
33+ # Using mismatched versions (e.g. clang-18 + libclang-20) triggers a kernel
34+ # warning at "make rustavailable" time.
35+ _detect_llvm_version () {
36+ local bindgen_pkg ver candidate
37+ # Try versioned bindgen first (Ubuntu 24.04), then unversioned.
38+ # Only query real (installable) packages — virtual packages like
39+ # bindgen-0.71 on Trixie return provider lists that contain
40+ # "testing-only-libclang-16" strings, producing false matches.
41+ for bindgen_pkg in " bindgen-${BINDGEN_APT_VERSION} " " bindgen" ; do
42+ candidate=" $( apt-cache policy " ${bindgen_pkg} " 2> /dev/null \
43+ | sed -n ' s/.*Candidate: *//p' ) "
44+ [[ -n " ${candidate} " && " ${candidate} " != " (none)" ]] || continue
45+ # Parse only "Depends:" lines, not virtual package providers
46+ ver=" $( apt-cache depends " ${bindgen_pkg} " 2> /dev/null \
47+ | sed -n ' s/^[[:space:]]*Depends:.*libclang-\([0-9]\+\)-dev.*/\1/p' | head -1) "
48+ if [[ -n " ${ver} " ]]; then
49+ echo " ${ver} "
50+ return
51+ fi
52+ done
53+ # Unversioned libclang-dev → resolve to libclang-NN-dev
54+ ver=" $( apt-cache depends libclang-dev 2> /dev/null \
55+ | sed -n ' s/^[[:space:]]*Depends:.*libclang-\([0-9]\+\)-dev.*/\1/p' | head -1) "
56+ if [[ -n " ${ver} " ]]; then
57+ echo " ${ver} "
58+ return
59+ fi
60+ }
61+ LLVM_APT_VERSION=" $( _detect_llvm_version) " || true
62+ LLVM_APT_VERSION=" ${LLVM_APT_VERSION:- 20} " # fallback if apt-cache unavailable
63+ unset -f _detect_llvm_version
64+
2965# Enable Rust sample kernel modules for toolchain smoke testing.
3066# Set to "yes" to build rust_minimal, rust_print, rust_driver_faux as modules.
3167# Can also be set via command line: RUST_KERNEL_SAMPLES=yes
@@ -39,18 +75,34 @@ declare -g RUST_TOOL_BINDGEN=""
3975function add_host_dependencies__add_rust_compiler() {
4076 display_alert " Adding Rust kernel build dependencies" " ${EXTENSION} " " info"
4177
42- # --- Method 1: APT versioned packages (noble-security/noble-updates) ---
43- # Versioned packages install binaries under /usr/lib/rust-X.YY/bin/ or
44- # /usr/bin/tool-X.YY; we locate them via _find_rust_tool and pass
45- # explicit paths to make via custom_kernel_make_params.
46- EXTRA_BUILD_DEPS+=" rustc -${RUST_APT_VERSION} cargo- ${RUST_APT_VERSION} "
47- EXTRA_BUILD_DEPS+= " rust- ${RUST_APT_VERSION} -src rustfmt- ${RUST_APT_VERSION} "
48- EXTRA_BUILD_DEPS+=" bindgen -${BINDGEN_APT_VERSION} "
49- EXTRA_BUILD_DEPS+=" libclang-dev clang lld llvm "
78+ # Rust packages: try versioned first (Ubuntu 24.04), fall back to unversioned
79+ # (Debian trixie, Ubuntu >= 25.10). _apt_pick outputs the first available.
80+ local pkg
81+ for pkg in rustc cargo rustfmt ; do
82+ EXTRA_BUILD_DEPS+=" $( _apt_pick " ${pkg} -${RUST_APT_VERSION} " " ${pkg} " ) "
83+ done
84+ EXTRA_BUILD_DEPS+=" $( _apt_pick " rust -${RUST_APT_VERSION} -src " rust-src ) "
85+ EXTRA_BUILD_DEPS+=" $( _apt_pick " bindgen- ${BINDGEN_APT_VERSION} " bindgen ) "
5086
51- # --- Method 2: Rustup (commented out) ---
52- # Only libclang/llvm needed; rustc/cargo/bindgen come from rustup/cargo.
53- # EXTRA_BUILD_DEPS+=" libclang-dev clang lld llvm "
87+ # LLVM toolchain: versioned to match libclang used by bindgen
88+ EXTRA_BUILD_DEPS+=" clang-${LLVM_APT_VERSION} lld-${LLVM_APT_VERSION} llvm-${LLVM_APT_VERSION} "
89+ }
90+
91+ # Pick first installable APT package from candidates.
92+ # Uses apt-cache policy to distinguish real packages from virtual ones
93+ # (apt-cache show returns 0 for virtual packages like bindgen-0.71 on Trixie).
94+ _apt_pick () {
95+ local pkg candidate
96+ for pkg in " $@ " ; do
97+ candidate=" $( apt-cache policy " ${pkg} " 2> /dev/null \
98+ | sed -n ' s/.*Candidate: *//p' | head -1) "
99+ if [[ -n " ${candidate} " && " ${candidate} " != " (none)" ]]; then
100+ echo " ${pkg} "
101+ return
102+ fi
103+ done
104+ # None found — return first candidate and let apt fail with a clear error
105+ echo " $1 "
54106}
55107
56108# Find a versioned tool binary, returning its full path.
@@ -62,17 +114,15 @@ _find_rust_tool() {
62114 local tool_path=" "
63115 # 1. Try versioned command in PATH (e.g. rustc-1.85)
64116 if [[ -n " ${version} " ]]; then
65- tool_path=" $( command -v " ${base} -${version} " 2> /dev/null || true) "
117+ local versioned=" ${base} -${version} "
118+ tool_path=" $( command -v " ${versioned} " 2> /dev/null || true) "
66119 if [[ -n " ${tool_path} " ]]; then
67120 echo " ${tool_path} "
68121 return
69122 fi
70- fi
71- # 2. Locate binary via dpkg package file list
72- if [[ -n " ${version} " ]]; then
73- local pkg_name=" ${base} -${version} "
74- if dpkg -s " ${pkg_name} " > /dev/null 2>&1 ; then
75- tool_path=" $( dpkg -L " ${pkg_name} " 2> /dev/null | grep " /bin/${base} " | head -1 || true) "
123+ # 2. Locate binary via dpkg package file list
124+ if dpkg -s " ${versioned} " > /dev/null 2>&1 ; then
125+ tool_path=" $( dpkg -L " ${versioned} " 2> /dev/null | grep " /bin/${base} " | head -1 || true) "
76126 if [[ -n " ${tool_path} " && -x " ${tool_path} " ]]; then
77127 display_alert " Found ${base} via dpkg" " ${tool_path} " " info"
78128 echo " ${tool_path} "
@@ -97,16 +147,7 @@ function host_dependencies_ready__add_rust_compiler() {
97147 local tool_name tool_path
98148 for tool_name in RUST_TOOL_RUSTC RUST_TOOL_RUSTFMT RUST_TOOL_BINDGEN; do
99149 tool_path=" ${! tool_name} "
100- if [[ -z " ${tool_path} " ]]; then
101- display_alert " PATH" " ${PATH} " " wrn"
102- display_alert " dpkg -L rustfmt-${RUST_APT_VERSION} " \
103- " $( dpkg -L " rustfmt-${RUST_APT_VERSION} " 2>&1 | grep bin || echo ' N/A' ) " " wrn"
104- display_alert " dpkg -L rustc-${RUST_APT_VERSION} " \
105- " $( dpkg -L " rustc-${RUST_APT_VERSION} " 2>&1 | grep bin || echo ' N/A' ) " " wrn"
106- display_alert " dpkg -L bindgen-${BINDGEN_APT_VERSION} " \
107- " $( dpkg -L " bindgen-${BINDGEN_APT_VERSION} " 2>&1 | grep bin || echo ' N/A' ) " " wrn"
108- exit_with_error " Required Rust tool '${tool_name} ' not found" " ${EXTENSION} "
109- fi
150+ [[ -n " ${tool_path} " ]] || _missing_rust_tool_abort " ${tool_name} "
110151 done
111152
112153 display_alert " Rust toolchain ready" \
@@ -154,13 +195,55 @@ function host_dependencies_ready__add_rust_compiler() {
154195 # "rustc $(rustc --version | awk '{print $2}'), bindgen $(bindgen --version 2>&1 | awk '{print $2}')" "info"
155196}
156197
198+ _show_dpkg_bins () {
199+ local pkg
200+ for pkg in " $@ " ; do
201+ display_alert " dpkg -L ${pkg} " \
202+ " $( dpkg -L " ${pkg} " 2>&1 | grep bin || echo ' N/A' ) " " wrn"
203+ done
204+ }
205+
206+ _missing_rust_tool_abort () {
207+ local tool_name=" $1 "
208+ display_alert " PATH" " ${PATH} " " wrn"
209+ _show_dpkg_bins " rustfmt-${RUST_APT_VERSION} " " rustc-${RUST_APT_VERSION} " " bindgen-${BINDGEN_APT_VERSION} "
210+ exit_with_error " Required Rust tool '${tool_name} ' not found" " ${EXTENSION} "
211+ }
212+
213+ # Override the compiler version in artifact hash when using versioned clang.
214+ # kernel-version-toolchain (if enabled) sets _T from unversioned "clang" in PATH,
215+ # but this extension redirects the build to clang-VER via LLVM=-VER.
216+ # Runs after add_toolchain (alphabetically: "override" > "add").
217+ function artifact_kernel_version_parts__override_toolchain_version() {
218+ [[ " ${KERNEL_COMPILER} " == " clang" && -n " ${LLVM_APT_VERSION} " ]] || return 0
219+ local clang_bin=" clang-${LLVM_APT_VERSION} "
220+ command -v " ${clang_bin} " & > /dev/null || return 0
221+
222+ local full_version short_version
223+ full_version=" $( " ${clang_bin} " -dumpfullversion -dumpversion 2> /dev/null || echo " " ) "
224+ [[ -n " ${full_version} " ]] || return 0
225+ short_version=" $( echo " ${full_version} " | cut -d' .' -f1-2) "
226+
227+ artifact_version_parts[" _T" ]=" clang${short_version} "
228+ # Ensure the key is in the order array (kernel-version-toolchain may have added it,
229+ # but if that extension is not enabled, we need to add it ourselves)
230+ local found=0 entry
231+ for entry in " ${artifact_version_part_order[@]} " ; do
232+ [[ " ${entry} " == * " -_T" ]] && found=1 && break
233+ done
234+ if [[ " ${found} " -eq 0 ]]; then
235+ artifact_version_part_order+=(" 0085-_T" )
236+ fi
237+ }
238+
157239function custom_kernel_config__add_rust_compiler() {
158240 # https://docs.kernel.org/rust/quick-start.html
159241 opts_y+=(" RUST" )
160242
161243 # Build sample Rust modules for toolchain smoke testing
162244 if [[ " ${RUST_KERNEL_SAMPLES} " == " yes" ]]; then
163245 display_alert " Enabling Rust sample modules" " ${EXTENSION} " " info"
246+ opts_y+=(" SAMPLES" ) # Parent menu for all kernel samples
164247 opts_y+=(" SAMPLES_RUST" )
165248 opts_m+=(" SAMPLE_RUST_MINIMAL" )
166249 opts_m+=(" SAMPLE_RUST_PRINT" )
@@ -172,6 +255,30 @@ function custom_kernel_make_params__add_rust_compiler() {
172255 # run_kernel_make_internal uses "env -i" which clears all environment
173256 # variables, so we must pass Rust paths explicitly.
174257
258+ # When building with clang, replace LLVM=1 with LLVM=-VER so that the
259+ # kernel uses versioned LLVM tools (clang-20, ld.lld-20, llvm-ar-20, …)
260+ # matching the libclang version that bindgen links against.
261+ # Also update CC= to use versioned clang, because kernel-make.sh sets
262+ # CC=ccache clang (unversioned) which overrides the CC that LLVM=-VER
263+ # would derive in the kernel Makefile.
264+ # See: https://docs.kernel.org/kbuild/llvm.html#llvm-utility
265+ if [[ " ${KERNEL_COMPILER} " == " clang" && -n " ${LLVM_APT_VERSION} " ]]; then
266+ local i
267+ for i in " ${! common_make_params_quoted[@]} " ; do
268+ case " ${common_make_params_quoted[${i}]} " in
269+ LLVM=1)
270+ common_make_params_quoted[${i} ]=" LLVM=-${LLVM_APT_VERSION} "
271+ display_alert " Using versioned LLVM toolchain" " LLVM=-${LLVM_APT_VERSION} " " info"
272+ ;;
273+ CC=* clang)
274+ # Replace "CC=ccache clang" → "CC=ccache clang-20"
275+ common_make_params_quoted[${i} ]=" ${common_make_params_quoted[${i}]/% clang/ clang-${LLVM_APT_VERSION} } "
276+ display_alert " Using versioned clang" " clang-${LLVM_APT_VERSION} " " info"
277+ ;;
278+ esac
279+ done
280+ fi
281+
175282 # --- Method 1: APT versioned packages ---
176283 # Tell the kernel build system to use the discovered tool names.
177284 if [[ -n " ${RUST_TOOL_RUSTC} " ]]; then
0 commit comments