-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
extensions: add kernel-rust for Rust support in kernel builds #9386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a new extension script that integrates Rust toolchains into the kernel build flow: apt-based dependency selection (rustup flow commented), multi-step tool discovery, LLVM/libclang version detection and toolchain override, host readiness checks, kernel config/make hooks, and propagation of explicit Rust tool paths and options. (≤50 words) Changes
Sequence Diagram(s)sequenceDiagram
participant Build as Build System
participant Ext as Rust Extension
participant Apt as APT/Package Manager
participant Finder as Tool Discoverer
participant Kernel as Kernel Build
Build->>Ext: Request Rust capability
Ext->>Apt: Select/install Rust/LLVM/bindgen packages (apt flow)
Apt-->>Ext: Packages installed / available
Ext->>Finder: _find_rust_tool (versioned PATH, dpkg lists, unversioned PATH)
Finder-->>Ext: rustc, rustfmt, bindgen paths
Ext->>Ext: detect libclang/LLVM version -> override toolchain version
Ext->>Kernel: Inject RUST config flags and make params (RUSTC, RUSTFMT, BINDGEN, RUST_LIB_SRC, LLVM/CC)
Kernel-->>Build: Kernel config and make params updated
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
tested against #9381 just for fun. Seems to work: https://paste.armbian.com/javugatico No clue if this is an issue. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@extensions/kernel-rust.sh`:
- Around line 314-319: The element added to common_make_envs sets RUST_LIB_SRC
with embedded single quotes which will be preserved when passed to env -i;
update the construction so quoting is consistent by either removing the embedded
single quotes in the value added to common_make_envs (i.e., push
RUST_LIB_SRC=${rust_lib_src} instead) or ensure the caller that expands
common_make_envs uses the bash array expansion with the `@Q` operator
(common_make_envs[@]@Q) like common_make_params_quoted does; modify the code
that builds/expands common_make_envs or the element insertion for RUST_LIB_SRC
so the final env invocation receives a properly quoted value rather than literal
single quotes.
🧹 Nitpick comments (5)
extensions/kernel-rust.sh (5)
124-131: Loose grep pattern may match unintended binaries from dpkg file list.
grep "/bin/${base}"is a substring match. Forbase="rustc", it would also match paths like/usr/lib/rust-1.85/bin/rustc-wrapperor/usr/lib/rust-1.85/bin/rustc-demangler. Combined withhead -1, the result depends ondpkg -Loutput order, which could non-deterministically pick the wrong binary.Anchor the grep to match the exact binary name:
Proposed fix
- tool_path="$(dpkg -L "${versioned}" 2> /dev/null | grep "/bin/${base}" | head -1 || true)" + tool_path="$(dpkg -L "${versioned}" 2> /dev/null | grep -E "/bin/${base}\$" | head -1 || true)"
265-279: CC glob pattern could be tightened slightly.
CC=*clang)matches any value ending inclang, including hypotheticalCC=somethingclang. A more precise pattern likeCC=*[[:space:]]clang|CC=clangwould be safer. However, in practice the only values set upstream areCC=ccache clangorCC=clang, so this is a minor robustness nit.
296-304: Consider a fallback for RUST_LIB_SRC discovery.The path
/usr/src/rustc-${rustc_full_version}/libraryis the only APT convention checked. If a future Debian/Ubuntu ships rust-src with a different layout (e.g.,rust-srcinstead ofrust-X.YY-src), this silently falls through to the warning on line 318. A secondary glob ordpkg -Llookup on the rust-src package could improve robustness.
156-196: Large commented-out block adds noise.~40 lines of commented-out rustup code. While it's useful as documentation of the alternative method, consider moving it to a separate file or a doc comment/README section to keep the active code clean.
75-89: LLVM packages don't use_apt_pickfallback, unlike Rust/bindgen packages.Lines 82–85 use
_apt_pickfor graceful fallback, but line 88 hardcodes versionedclang-${LLVM_APT_VERSION}/lld-${LLVM_APT_VERSION}/llvm-${LLVM_APT_VERSION}without fallback to unversioned. If auto-detection returns a version that isn't packaged, apt will fail with a less helpful error. This is likely intentional since the version is auto-detected, but worth noting for cross-distro robustness.
This is strange. Ubuntu 24.04 noble bindgen-0.71 is in the noble-updates repository. |
|
@coderabbitai Regarding the "Actionable" comment about This is not a bug — it's the established pattern used throughout the framework. All elements in common_make_envs=(
"CCACHE_BASEDIR='$(pwd)'" # line 21
"CCACHE_TEMPDIR='${CCACHE_TEMPDIR:?}'" # line 22
"CCACHE_DIR='${CCACHE_DIR}'" # line 34
"RUST_LIB_SRC='${rust_lib_src}'" # our addition - same format
)Why this works correctly:
Why changing it would be wrong:
The logged command output ( |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 1289
I've now verified Your implementation of I appreciate you providing this context—it helps me better understand the framework's conventions going forward. ✏️ Learnings added
🧠 Learnings used |
|
Noble-updates is present and used. packages were mostly up to date before trying. Nothing rust-related after updating. |
| # Rust version for APT method. Available in noble-security/noble-updates. | ||
| # Kernel >= 6.12 requires rustc >= 1.78. See: | ||
| # https://launchpad.net/ubuntu/noble/+package/cargo-1.85 | ||
| RUST_APT_VERSION="1.85" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these will need to [be able to] be overridden in LINUXFAMILY [unless we start having config files per LINUX_MAJOR_MINOR]
at which point we may also need a build-distro check vs these versions.
@coderabbitai
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for how family.conf files set version-related variables
echo "=== Searching for version variables in family configs ==="
rg -n -C2 'APT_VERSION|KERNEL_MAJOR_MINOR|VERSION=' --type=sh config/sources/families/ | head -80
echo -e "\n=== Searching for examples of variables overridden in family configs ==="
rg -n -C2 'LINUXFAMILY.*override|family.*override' --type=sh lib/ | head -40
echo -e "\n=== Check how extensions access LINUXFAMILY or kernel version ==="
rg -n -C2 '\$LINUXFAMILY|\$KERNEL_MAJOR_MINOR' --type=sh extensions/ | head -60
echo -e "\n=== Look for distro-dependent package selection patterns ==="
rg -n -C3 'DISTRIB|distro.*version|release.*version' --type=sh lib/functions/host/ | head -60
Length of output: 3209
🏁 Script executed:
#!/bin/bash
# Find KERNEL_MAJOR_MINOR definition and usage
echo "=== KERNEL_MAJOR_MINOR definition and usage ==="
rg -n -C3 'KERNEL_MAJOR_MINOR=' --type=sh lib/ | head -80
echo -e "\n=== Check the full kernel-rust.sh extension to see all version variables ==="
fd -t f 'kernel-rust.sh' extensions/ --exec cat {} | head -100
echo -e "\n=== Look for how extensions can access board/family variables ==="
rg -n -C3 'declare.*BOARD|declare.*FAMILY' --type=sh extensions/ | head -60
echo -e "\n=== Search for patterns of conditional version handling ==="
rg -n -C2 'if.*version|case.*version' --type=sh extensions/*.sh | head -80
Length of output: 12299
🏁 Script executed:
#!/bin/bash
# Check extension initialization order and how they interact with family configs
echo "=== Extension hook execution order and family config interaction ==="
rg -n -C5 'extension.*hook|call_extension' --type=sh lib/functions/configuration/main-config.sh | head -100
echo -e "\n=== Search for family.conf examples that might set extension-related variables ==="
rg -n -C3 'ENABLE_EXTENSIONS|extension' --type=sh config/sources/families/*.conf config/sources/families/*.inc 2>/dev/null | head -80
echo -e "\n=== Check if extensions can be conditionally configured based on variables ==="
rg -n -C5 'KERNEL_MAJOR_MINOR|if.*BRANCH|if.*FAMILY' --type=sh extensions/*.sh | head -100
echo -e "\n=== Look for examples of variable defaults that can be overridden ==="
rg -n -C2 ':-.*}.*#.*override|:=.*}.*#.*override|\${.*:-' --type=sh extensions/*.sh | head -80
Length of output: 15687
🏁 Script executed:
#!/bin/bash
# Fixed regex: Look for variable defaults that can be overridden
echo "=== Variable defaults in extensions (:-) pattern ==="
rg -n '\$\{[A-Z_]+:-' --type=sh extensions/ | head -80
echo -e "\n=== Check extension_prepare_config hooks for variable handling ==="
rg -n -A10 'function extension_prepare_config' --type=sh extensions/ | head -100
echo -e "\n=== Look for how variables are preserved if pre-set ==="
rg -n -C3 'preserve|pre-set|override' --type=sh extensions/ | head -80
echo -e "\n=== Check the kernel-rust.sh extension fully to see all variable declarations ==="
cat extensions/kernel-rust.sh | grep -n -E '^[A-Z_]+=' | head -30
Length of output: 19955
@tabrisnet, you're absolutely right to flag this. The hardcoded RUST_APT_VERSION and BINDGEN_APT_VERSION values would prevent family-specific or kernel-version-specific overrides.
Looking at the code, I can see that:
-
LLVM_APT_VERSIONalready uses the override pattern (line 62):LLVM_APT_VERSION="${LLVM_APT_VERSION:-20}"This allows it to be pre-set before the extension runs.
-
RUST_APT_VERSIONandBINDGEN_APT_VERSIONare hardcoded (lines 21, 27), which prevents overriding. -
Extensions run AFTER family configs are sourced, so family configs can set variables that extensions will see.
-
Other extensions already handle version-dependent requirements - for example,
v4l2loopback-dkmsandradxa-aic8800checkKERNEL_MAJOR_MINORand skip installation for incompatible kernel versions.
Suggested changes:
# Lines 21 and 27 should become:
RUST_APT_VERSION="${RUST_APT_VERSION:-1.85}"
BINDGEN_APT_VERSION="${BINDGEN_APT_VERSION:-0.71}"This would allow:
- Family-level overrides: Family configs could set these before the extension runs
- Build-distro checks: The extension could conditionally set defaults based on
HOSTRELEASE - Kernel-version-specific logic: Could add checks like
if linux-version compare "${KERNEL_MAJOR_MINOR}" ge 6.19to adjust versions
For build-distro compatibility, the extension could also add logic similar to what exists in lib/functions/host/prepare-host.sh to handle distro-specific package availability.
🧠 Learnings used
Learnt from: EvilOlaf
Repo: armbian/build PR: 0
File: :0-0
Timestamp: 2025-08-02T05:46:10.664Z
Learning: In the Armbian build system, the modern recommended approach for kernel configuration is to use the kernel-config command via "./compile.sh BOARD=boardname BRANCH=branchname kernel-config" instead of the deprecated KERNEL_CONFIGURE=yes flag. This provides a two-step workflow: configure using menuconfig, then build, with better transparency and control over configuration changes.
Learnt from: Grippy98
Repo: armbian/build PR: 8152
File: lib/functions/configuration/interactive.sh:209-266
Timestamp: 2025-05-05T12:35:07.143Z
Learning: For the interactive kernel selection in Armbian, KERNEL_MAJOR_MINOR and KERNEL_DESCRIPTION are parsed from family.conf but deliberately not set as environment variables to avoid potential interference with other parts of the build system.
Learnt from: EvilOlaf
Repo: armbian/build PR: 0
File: :0-0
Timestamp: 2025-07-21T04:12:02.439Z
Learning: In the Armbian build system, for recurring maintenance tasks like kernel version bumping, TODO comments should use generic version formats (e.g., "MAJOR.MINOR-rc1") rather than specific version numbers (e.g., "6.17-rc1") to avoid the need for frequent comment updates that would create unnecessary maintenance overhead.
Learnt from: tabrisnet
Repo: armbian/build PR: 8913
File: config/sources/families/k3-beagle.conf:16-16
Timestamp: 2025-11-10T22:05:40.490Z
Learning: In the Armbian build system, kernel branches using non-mainline/vendor forks (like BeagleBoard's linux repository) should be named "vendor" or "vendor-rt" rather than "current" or "edge". The "current" and "edge" naming is reserved for mainline kernel branches. This affects both the case statement in family config files (e.g., `vendor | vendor-rt)` instead of `current | current-rt)`) and the corresponding KERNEL_TARGET declarations in board config files.
Learnt from: EvilOlaf
Repo: armbian/build PR: 8330
File: config/sources/families/sun55iw3.conf:32-36
Timestamp: 2025-06-25T03:40:52.109Z
Learning: In Armbian build system configuration files like config/sources/families/*.conf, when KERNELSOURCE is not explicitly declared in a case branch, the system falls back to a default KERNELSOURCE value, so missing KERNELSOURCE declarations are not critical issues.
Learnt from: igorpecovnik
Repo: armbian/build PR: 8849
File: config/boards/radxa-e54c.csc:14-28
Timestamp: 2025-11-02T20:49:56.719Z
Learning: In Armbian board configuration files (config/boards/*.conf, *.csc, etc.), do not use kernel_config_set, kernel_config_set_m, kernel_config_set_y, or custom_kernel_config__* functions to modify kernel configuration. Kernel configuration is associated with LINUXFAMILY/BOARDFAMILY, not individual BOARD. Board-specific kernel modifications cause inconsistency in kernel packages published to the apt repository because boards within a family share the same kernel packages. Kernel configuration changes must be made in the appropriate kernel config file (e.g., config/kernel/linux-*-*.config) or in family configuration files (config/sources/families/*.conf, *.inc) instead.
Learnt from: EvilOlaf
Repo: armbian/build PR: 8330
File: config/sources/families/sun55iw3.conf:32-36
Timestamp: 2025-06-25T03:42:09.086Z
Learning: In Armbian build system configuration files like config/sources/families/*.conf, KERNELSOURCE is explicitly declared when using unofficial or 3rd party kernel repositories (like the "dev" branch using https://github.com/apritzel/linux), but can be omitted when using the standard mainline kernel (like the "edge" branch) since it will fall back to the default mainline source.
|
We all knew this was coming, but I wonder if it's too soon for Rust stuff. We've enough on our plates without it. Any practical use-case already? (Otherwise it's a lot of work, which will invariably change, for little benefit). I don't oppose, just wonder. |
|
No, there was no immediate, specific goal; it was an attempt to "prepare for the future." Well, and I wanted to see what it would be like there, in the future. You're probably right. Nothing bad will happen if we wait another 2-3 months, but there will almost certainly be more certainty and clarity. |
|
Yeah, maybe the "exciting" Rust stuff is still out of tree (eg Ref the complexity, maybe it is more related to |
|
tyr there, I build it already. But have no way to run it. |
|
During the implementation of this extension, almost all the complexity was related to coordinating rustc versions, packages, and libraries, taking into account what could be installed from the repositories available on the build machine. And even then, in the end, everything fell into place in the correct chain for me, but for some reason for you it didn’t. |
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>
bindgen-0.71 links against libclang-20, but the extension was installing unversioned clang (18 on noble). This caused: - kernel "libclang version does not match Clang's" warning - CC=ccache clang (18) overriding LLVM=-20 on make command line Changes: - Auto-detect LLVM version from bindgen's dependency chain, resolving versioned (bindgen-0.71 → libclang-20-dev) and unversioned (bindgen → libclang-dev → libclang-NN-dev) paths. Tested on Ubuntu 24.04, Debian Trixie, Ubuntu 25.10, 26.04. - Install clang-VER/lld-VER/llvm-VER instead of unversioned. - Replace LLVM=1 → LLVM=-VER and CC=ccache clang → CC=ccache clang-VER in make params so the entire toolchain is consistent. - Use _apt_pick() to prefer versioned packages (rustc-1.85) on noble, falling back to unversioned (rustc) on Debian/newer Ubuntu. - Override artifact hash _T key with actual clang version, without modifying kernel-version-toolchain extension. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Add
kernel-rustextension that enablesCONFIG_RUSTin kernel builds, with automatic LLVM version matching across distros.Core functionality:
CONFIG_RUSTin kernel menuconfig and configures the build environmentRUSTC,RUSTFMT,BINDGEN) and env vars (RUST_LIB_SRC) to work withenv -iinrun_kernel_make_internal_find_rust_tool()helper withdpkg -Lfallback for non-standard binary locations (versioned packages install to/usr/lib/rust-X.YY/bin/, not/usr/bin/)RUST_KERNEL_SAMPLES=yesbuilds sample Rust modules for toolchain smoke testingLLVM/clang version matching (the tricky part):
bindgenlinks against a specificlibclangversion at build time. If the systemclangdiffers from thatlibclang, the kernel emits a warning atmake rustavailableand may produce incorrect bindings. The dependency chain is:However, on Ubuntu 24.04 (noble), the default unversioned
clangpackage is version 18, whilebindgen-0.71(from noble-updates) pulls inlibclang-20. This mismatch causes:libclang version (20.1.2) does not match Clang's (18.1.3)KERNEL_COMPILER=clang:kernel-make.shsets explicitCC=ccache clang(18) which overridesCCderived fromLLVM=-20in the kernel MakefileHow the extension solves this:
_detect_llvm_version()auto-detects the required LLVM version by resolvingbindgen's dependency chain tolibclang-NN-devclang-20/lld-20/llvm-20instead of unversionedclang/lld/llvmKERNEL_COMPILER=clangbuilds: replacesLLVM=1→LLVM=-20andCC=ccache clang→CC=ccache clang-20in make params_Tkey viaartifact_kernel_version_partshook (runs afterkernel-version-toolchainalphabetically, does not modify that extension)Cross-distro package availability:
Package naming differs significantly across distros — tested and handled:
rustc-1.85rustc(unversioned)rustc-1.85rustc-1.85bindgen-0.71bindgen0.71.1bindgen0.71.1bindgen0.72.1libclang-20-devlibclang-19-devlibclang-20-devlibclang-21-dev_apt_pick()selects the first installable package from versioned/unversioned candidates, usingapt-cache policyto filter out virtual packages (e.g.bindgen-0.71on Trixie is a virtual package whose providers contain misleadinglibclang-16in their names).To update for new distros, only
RUST_APT_VERSIONandBINDGEN_APT_VERSIONneed manual adjustment —LLVM_APT_VERSIONis auto-detected.Usage
Implementation details
rustc-1.85(noble-security),bindgen-0.71(noble-updates since 2026-02-02). Basebindgen0.66.1 panics on kernel >= 6.19 headers (FromBytesWithNulError)./usr/lib/rust-1.85/bin/rustfmt), so_find_rust_tool()tries: versioned name in PATH →dpkg -Llookup → unversioned fallback.env -ipassthrough:run_kernel_make_internal()clears environment; Rust paths are passed viacommon_make_params_quoted(RUSTC,RUSTFMT,BINDGEN) andcommon_make_envs(RUST_LIB_SRC).rustc(won't fix since 2019). The kernel has noRUSTC_WRAPPERmechanism, so Rust code is always compiled from scratch. Only C compilation benefits from ccache.Test plan
KERNEL_COMPILER=clang— Rust compiles,LLVM=-20appliedmodprobe rust_minimal🤖 Generated with Claude Code
Summary by CodeRabbit