Skip to content

refactor(compilation): extract ccache into a swappable extension#9840

Open
iav wants to merge 5 commits into
armbian:mainfrom
iav:refactor/ccache-as-extension
Open

refactor(compilation): extract ccache into a swappable extension#9840
iav wants to merge 5 commits into
armbian:mainfrom
iav:refactor/ccache-as-extension

Conversation

@iav
Copy link
Copy Markdown
Contributor

@iav iav commented May 17, 2026

Goal

Move ccache out of core compilation into a swappable extension. After this PR a parallel cache backend (sccache, distcc-style, distributed cache) can ship as a sibling extension without touching core.

A concrete near-term motivation: a future extensions/sccache.sh would let CI workflows running on GitHub-hosted runners route their compile-cache straight into the native GitHub Actions cache (SCCACHE_GHA_ENABLED=on, via mozilla-actions/sccache-action) — 10 GB free per repository, low-latency on the runner's local region. The same extension framework also covers self-hosted runners (S3/R2/MinIO bucket, WebDAV endpoint, Redis-on-disk, ...) without core changes — backend choice is purely an env-var concern per workflow.

What changes (vs armbian/build:main)

New files

  • extensions/ccache.sh — implements compile_prepare_vars, compile_wrapper_pre/_post, and {kernel,uboot,atf,crust}_make_config hooks.
  • lib/functions/compilation/compile-wrapper.shdo_with_compile_wrapper + compile_wrapper_pre/_post hooks.

Removed

  • lib/functions/compilation/ccache.sh (logic moved into the extension).

Modified

  • lib/functions/compilation/atf.sh — adds atf_make_config hook; replaces hardcoded ccache with ${CCACHE} (latent bug: USE_CCACHE=no was still dragging ccache into ATF).
  • lib/functions/compilation/crust.sh — adds crust_make_config hook; drops dead binutils_flags_crust="" declaration (preexisting SC2034 since 2023).
  • lib/functions/compilation/{kernel,uboot}.sh — compile phase wrapped in do_with_compile_wrapper.
  • lib/functions/configuration/compilation-config.sh — dispatches compile_prepare_vars instead of inlining configure-ccache; resets stale CCACHE between artifacts; warns if USE_CCACHE is set in userpatches/lib.config (sourced too late for enable_extension).
  • lib/functions/configuration/main-config.sh — auto-enables the ccache extension when USE_CCACHE=yes, PRIVATE_CCACHE=yes, or ENABLE_EXTENSIONS=ccache-remote, before initialize_extension_manager.
  • lib/functions/general/extensions.sh — adds extension_list_normalized helper (used by the auto-enable shim and per-extension mutex checks).
  • lib/library-functions.sh — regenerated.

User-visible behavior

Unchanged. USE_CCACHE=yes (default for kernel/u-boot) and USE_CCACHE=no behave exactly as before; ENABLE_EXTENSIONS=ccache-remote implicitly pulls in ccache, matching the pre-refactor coupling.

Test plan

Built on a fresh DigitalOcean cloud builder (AMD EPYC 8c, Ubuntu 24.04), BOARD=helios64 BRANCH=edge:

# Configuration Runtime Marker
1 USE_CCACHE=yes kernel cold 77:45 min Ccache result hit=12 miss=14410
2 USE_CCACHE=no kernel 55:54 min no ccache markers (as expected)
3 USE_CCACHE=yes uboot+ATF cold 2:11 min Ccache result hit=8 miss=1002
4 ENABLE_EXTENSIONS=ccache-remote + CCACHE_REMOTE_STORAGE=http://m1:8088/ccache/ over WireGuard interrupted (~5 min of compile) Remote ccache result hit=4536 miss=2791 write=2740 err=0 (61%)

Logs: paste.armbian.com/{enaretezuc,noxayoyoni,vonuyajido}.

Known design choices

  • USE_CCACHE=yes in userpatches/lib.config does not auto-enable the
    ccache extension. lib.config is sourced after
    initialize_extension_manager, too late to enable extensions; the
    framework limitation is documented in main-config.sh (too late to define hook functions or add extensions in lib.config). The shim
    emits a warning at compile-vars phase nudging users to migrate to
    ENABLE_EXTENSIONS=ccache (the auto-enable code path).
  • Auto-enable triggers on three signals: USE_CCACHE=yes,
    PRIVATE_CCACHE=yes, or ENABLE_EXTENSIONS=ccache-remote (the only
    extension in-tree that sets USE_CCACHE=yes from its
    extension_prepare_config). Any future extension that also sets
    USE_CCACHE from its prepare hook will need to add itself to the
    same trigger list, since the shim runs before
    initialize_extension_manager.

Summary by CodeRabbit

  • New Features

    • Extensible compile-wrapper that runs pre/post build hooks and guarantees post-hook execution on interruption.
    • ccache compile-cache backend with shared/private modes, configurable cache dir, optional pre/post-build reporting, and umask preservation across clean environments.
    • Automatic activation of the compile-cache backend when requested in config.
  • Refactor

    • Compilation cache handling moved to the extension system and integrated with ATF/Crust/kernel/uboot build steps while preserving legacy post-build reporting.

Review Change Stack

@iav iav requested review from a team and igorpecovnik as code owners May 17, 2026 01:29
@iav iav requested review from Tearran and removed request for a team May 17, 2026 01:29
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 17, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a388aede-dc62-4c21-9487-84dedbbe221d

📥 Commits

Reviewing files that changed from the base of the PR and between d3170e8 and 6dd6a7c.

📒 Files selected for processing (11)
  • extensions/ccache.sh
  • lib/functions/compilation/atf.sh
  • lib/functions/compilation/ccache.sh
  • lib/functions/compilation/compile-wrapper.sh
  • lib/functions/compilation/crust.sh
  • lib/functions/compilation/kernel.sh
  • lib/functions/compilation/uboot.sh
  • lib/functions/configuration/compilation-config.sh
  • lib/functions/configuration/main-config.sh
  • lib/functions/general/extensions.sh
  • lib/library-functions.sh
💤 Files with no reviewable changes (1)
  • lib/functions/compilation/ccache.sh
🚧 Files skipped from review as they are similar to previous changes (10)
  • lib/functions/compilation/uboot.sh
  • lib/functions/compilation/crust.sh
  • lib/functions/compilation/kernel.sh
  • lib/functions/configuration/compilation-config.sh
  • lib/functions/compilation/compile-wrapper.sh
  • lib/functions/configuration/main-config.sh
  • lib/functions/compilation/atf.sh
  • lib/functions/general/extensions.sh
  • lib/library-functions.sh
  • extensions/ccache.sh

📝 Walkthrough

Walkthrough

Replaces ccache-specific compilation wiring with a generic do_with_compile_wrapper, implements ccache as an extension (config, env wiring, pre/post hooks, and helpers), auto-enables ccache when requested, and updates build targets and make-config hooks to use the new wrapper and extension points.

Changes

Compilation Wrapper Refactoring

Layer / File(s) Summary
Generic Backend-Agnostic Wrapper Framework
lib/functions/compilation/compile-wrapper.sh, lib/library-functions.sh
Adds do_with_compile_wrapper and a guaranteed cleanup-invoked post-hook; library aggregation now sources the wrapper.
ccache Extension Module
extensions/ccache.sh
Implements ccache as an extension: validation (conflicts with sccache), compile_prepare_vars__ccache (exports CCACHE, adjusts PATH, conditionally sets CCACHE_DIR and CCACHE_UMASK), make-env UMASK injection for env -i cases, compile_wrapper_pre__ccache/compile_wrapper_post__ccache for stats and size reporting, and helpers ccache_get_stat() and ccache_hit_pct().
Configuration & Extension List Helper
lib/functions/configuration/compilation-config.sh, lib/functions/configuration/main-config.sh, lib/functions/general/extensions.sh
Removes in-function ccache initialization from prepare_compilation_vars and delegates to compile_prepare_vars hook; adds extension_list_normalized() and auto-enables ccache when USE_CCACHE/PRIVATE_CCACHE or ccache-remote are requested; minor extension discovery stderr redirection tweak.
Compilation Target Migration
lib/functions/compilation/atf.sh, lib/functions/compilation/crust.sh, lib/functions/compilation/kernel.sh, lib/functions/compilation/uboot.sh
Kernel and u-boot use do_with_compile_wrapper; ATF and Crust gain *_make_config hooks; ATF build command uses ${CCACHE} for the compiler invocation.

Sequence Diagram

sequenceDiagram
  participant Build as BuildTarget
  participant Wrapper as do_with_compile_wrapper
  participant PreExt as compile_wrapper_pre__ccache
  participant Make as make
  participant PostExt as compile_wrapper_post__ccache
  Build->>Wrapper: start build under wrapper
  Wrapper->>Wrapper: register post-hook cleanup
  Wrapper->>PreExt: call_extension_method compile_wrapper_pre
  PreExt->>PreExt: clear stats, report cache dir/size
  Wrapper->>Make: run make (compiler wrapped by CCACHE)
  Make->>Make: compile
  Wrapper->>PostExt: explicit post-hook call
  PostExt->>PostExt: parse stats, compute hit%, report
  Wrapper->>Build: return exit code
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hop through scripts with a careful shim,
I make a wrapper generic, neat and trim,
Ccache now lives out in its own small nest,
Pre and post hooks tally, then they rest,
Builders hum along — the cache does the rest.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: refactoring ccache from core compilation into a swappable extension backend.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added 05 Milestone: Second quarter release size/large PR with 250 lines or more Needs review Seeking for review Framework Framework components labels May 17, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a 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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@extensions/ccache.sh`:
- Around line 109-117: When SHOW_CCACHE is enabled, guard the probes that
compute sizes by validating __ext_ccache_dir_actual before running du and
numfmt: ensure __ext_ccache_dir_actual is non-empty and a directory (e.g., test
-n and -d) and only then set __ext_ccache_dir_size_before and compute
ccache_dir_size_before_human; otherwise set __ext_ccache_dir_size_before to a
safe default (0) and ccache_dir_size_before_human to a fallback like "unset" or
"N/A". Update the logic around __ext_ccache_dir_size_before, the du call, and
the numfmt call so they are conditional on the existence check to keep the
post-hook best-effort and avoid aborting on empty/invalid
__ext_ccache_dir_actual.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f98c058c-d6d2-44e4-be35-f0577a0cfeeb

📥 Commits

Reviewing files that changed from the base of the PR and between be62dc5 and f32ac58.

📒 Files selected for processing (11)
  • extensions/ccache.sh
  • lib/functions/compilation/atf.sh
  • lib/functions/compilation/ccache.sh
  • lib/functions/compilation/compile-wrapper.sh
  • lib/functions/compilation/crust.sh
  • lib/functions/compilation/kernel.sh
  • lib/functions/compilation/uboot.sh
  • lib/functions/configuration/compilation-config.sh
  • lib/functions/configuration/main-config.sh
  • lib/functions/general/extensions.sh
  • lib/library-functions.sh
💤 Files with no reviewable changes (1)
  • lib/functions/compilation/ccache.sh

Comment thread extensions/ccache.sh Outdated
@iav iav force-pushed the refactor/ccache-as-extension branch from f32ac58 to f1138ac Compare May 17, 2026 01:47
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
lib/library-functions.sh (1)

288-300: ⚡ Quick win

Remove duplicate compile-wrapper.sh sourcing.

Line 288-Line 290 and Line 297-Line 299 source the same file twice. Please keep a single inclusion to avoid duplicate top-level execution and keep the generated aggregation deterministic.

Proposed fix
-# no errors tolerated. invoked before each sourced file to make sure.
-#set -o pipefail  # trace ERR through pipes - will be enabled "soon"
-#set -o nounset   ## set -u : exit the script if you try to use an uninitialised variable - one day will be enabled
-set -o errtrace # trace ERR through - enabled
-set -o errexit  ## set -e : exit the script if any statement returns a non-true return value - enabled
-### lib/functions/compilation/compile-wrapper.sh
-# shellcheck source=lib/functions/compilation/compile-wrapper.sh
-source "${SRC}"/lib/functions/compilation/compile-wrapper.sh
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/library-functions.sh` around lines 288 - 300, Remove the duplicate
sourcing of compile-wrapper.sh: locate the two identical source statements
referencing source "${SRC}"/lib/functions/compilation/compile-wrapper.sh (the
top-level include around the set -o errtrace/errexit block) and delete one of
them so the file is only sourced once; ensure the remaining block preserves the
intended shell options (set -o errtrace and set -o errexit) and any comments,
leaving a single source line for compile-wrapper.sh to avoid duplicate
execution.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@lib/library-functions.sh`:
- Around line 288-300: Remove the duplicate sourcing of compile-wrapper.sh:
locate the two identical source statements referencing source
"${SRC}"/lib/functions/compilation/compile-wrapper.sh (the top-level include
around the set -o errtrace/errexit block) and delete one of them so the file is
only sourced once; ensure the remaining block preserves the intended shell
options (set -o errtrace and set -o errexit) and any comments, leaving a single
source line for compile-wrapper.sh to avoid duplicate execution.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 57a7c283-8c3e-43ed-9f3f-5ecb69277112

📥 Commits

Reviewing files that changed from the base of the PR and between f32ac58 and f1138ac.

📒 Files selected for processing (8)
  • extensions/ccache.sh
  • lib/functions/compilation/ccache.sh
  • lib/functions/compilation/kernel.sh
  • lib/functions/compilation/uboot.sh
  • lib/functions/configuration/compilation-config.sh
  • lib/functions/configuration/main-config.sh
  • lib/functions/general/extensions.sh
  • lib/library-functions.sh
💤 Files with no reviewable changes (1)
  • lib/functions/compilation/ccache.sh
🚧 Files skipped from review as they are similar to previous changes (5)
  • lib/functions/compilation/uboot.sh
  • lib/functions/general/extensions.sh
  • lib/functions/compilation/kernel.sh
  • extensions/ccache.sh
  • lib/functions/configuration/compilation-config.sh

@iav iav force-pushed the refactor/ccache-as-extension branch 2 times, most recently from f9a751c to d3170e8 Compare May 17, 2026 02:07
iav added 5 commits May 17, 2026 22:43
The variable has been declared but never assigned or used since
8278dc5 (2023-06-20, 'allwinner: Enable crust compilation'), which
copy-pasted the binutils_version + binutils_flags skeleton from atf.sh
but did not bring along the gcc/ld probe block that conditionally
populates the flag, nor the TF_LDFLAGS-style use site. Crust is or1k-elf
firmware where --no-warn-rwx-segment is not relevant, so the absence
of the probe is by design; the leftover empty declaration is just dead.

Removes a pre-existing SC2034 'appears unused' warning that surfaced
when the file is touched by other refactors.

Assisted-by: Claude:claude-opus-4.7
CROSS_COMPILE and CC were hard-coded to 'ccache' which:
  - breaks when USE_CCACHE=no (CCACHE='' but 'ccache' still tried)
  - prevents wrapper substitution by extensions (sccache, distcc)

Match the established kernel/uboot convention where the cache wrapper
is parameterised via ${CCACHE} (set by configure-ccache based on
USE_CCACHE). Default value '' means no wrapper.

Assisted-by: Claude:claude-opus-4.7
…le_wrapper

Adds three new extension points to the compilation pipeline:

  - atf_make_config: called right before invoking 'make' for ATF (TF-A).
    Receives env that will be passed to make; extensions can mutate
    CCACHE / CC / CROSS_COMPILE to inject wrappers.
  - crust_make_config: same for the or1k Crust firmware (defconfig +
    target make).
  - do_with_compile_wrapper / compile_wrapper_pre / compile_wrapper_post:
    high-level wrapper that bookends an arbitrary compilation block
    with pre/post hooks. Lets extensions observe a compile pass
    end-to-end (clear stats / dump stats / mount caches / etc) without
    having to patch each artifact's compile.sh.

Pure addition: no existing call site is wired yet (kernel/uboot
migration follows in subsequent commits). The hooks are no-ops until
an extension implements them.

Assisted-by: Claude:claude-opus-4.7
Extracts ccache-specific logic from lib/functions/compilation/ccache.sh
into a new opt-out extension extensions/ccache.sh. The extension wires
itself into the compilation pipeline through the new hook points:

  - compile_prepare_vars: dispatched from prepare_compilation_vars
    (early). Computes CCACHE / CCACHE_DIR / CCACHE_UMASK / PATH and
    exports them so subsequent make-quoted-params arrays expand
    correctly. Runs before any artifact's make invocation.
  - compile_wrapper_pre/_post: zeros / reports per-build stats around
    each artifact's compile pass.
  - {kernel,uboot,atf,crust}_make_config: ensures CCACHE_DIR /
    CCACHE_UMASK are visible to the make subshell on each artifact.

This is an additive change: nothing yet calls call_extension_method
"compile_prepare_vars" — that wiring lands in the next refactor commit.

Assisted-by: Claude:claude-opus-4.7
…che.sh

Wires the new ccache extension (extensions/ccache.sh) into the
compilation pipeline, replacing the in-core lib/functions/compilation/
ccache.sh module that was sourced unconditionally.

Changes:
  - lib/functions/compilation/kernel.sh, uboot.sh: wrap the compile
    pass with do_with_compile_wrapper so the new compile_wrapper_pre/
    _post hooks fire around it.
  - lib/functions/configuration/compilation-config.sh: dispatch
    compile_prepare_vars (early phase, before any make-quoted-params
    array is built) instead of inlining configure-ccache. Also clears
    stale CCACHE export from a previous artifact iteration so a
    second uboot/kernel call in the same shell can't reuse a now-
    disabled cache. Keeps a one-shot deprecation warning if any
    user-patch still sources the legacy lib.config.
  - lib/functions/configuration/main-config.sh: if USE_CCACHE=yes
    (or the ccache-remote extension is enabled) auto-enable the
    'ccache' extension before initialize_extension_manager runs.
    Honours both EXT alias and the legacy space-separated
    ENABLE_EXTENSIONS form.
  - lib/functions/general/extensions.sh: extract
    extension_list_normalized helper used by the auto-enable shim.
  - lib/functions/compilation/ccache.sh: removed (logic moved to
    extensions/ccache.sh).

Behaviour is preserved for USE_CCACHE=yes (default-on for kernel/uboot
builds) and USE_CCACHE=no callers. ENABLE_EXTENSIONS=ccache-remote
implicitly pulls in ccache, matching pre-refactor coupling.

Assisted-by: Claude:claude-opus-4.7
@iav iav force-pushed the refactor/ccache-as-extension branch from d3170e8 to 6dd6a7c Compare May 17, 2026 20:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

05 Milestone: Second quarter release Framework Framework components Needs review Seeking for review size/large PR with 250 lines or more

Development

Successfully merging this pull request may close these issues.

1 participant