perf(build): compile ESP32 framework libs workspace-relative (cross-project cache stability, #952)#965
Conversation
…s-project cache stability Relocates the three zccache workspace-relativization helpers (compile_cwd_from_output / path_arg_for_compile_cwd / normalize_flags_for_compile_cwd) from fbuild-build/zccache.rs to fbuild_core::path (re-exported from zccache.rs so existing call sites are unchanged) so fbuild-packages' library compiler can use them too. Adds an opt-in compile_cwd to compile_library_with_jobs: when Some, the per-lib compiles run from the project workspace with source/-o/project-I relativized, so their zccache keys are stable across project directories (#952) — the same treatment sketch/core compiles already get. Only the ESP32 fw-libs caller opts in; every other caller passes None and is byte-identical to before. Measured (#942 Docker harness, clean cold->warm, vs post-#951 baseline): warm fw-libs 185s -> 141s, warm total 473s -> 376s. The remaining fw-libs cost is the deeper firmware-compile zccache cross-project key-stability gap (sketch/core don't fully hit cross-project either) — tracked separately. All fbuild-packages (715) + fbuild-build (452) + fbuild-core lib tests pass; the relocated helpers' tests moved with them. Part of #952 / #942. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughAdds workspace-relative compile CWD path helpers in fbuild-core, threads an optional ChangesCompile CWD normalization for zccache keys
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Orchestrator
participant library_compiler
participant path_helpers
participant CompilerProcess
Orchestrator->>library_compiler: compile_library_with_jobs(compile_cwd)
library_compiler->>path_helpers: normalize_flags_for_compile_cwd(flags, compile_cwd)
path_helpers-->>library_compiler: workspace-relative flags
library_compiler->>path_helpers: path_arg_for_compile_cwd(source/obj, compile_cwd)
path_helpers-->>library_compiler: relative source/obj args
library_compiler->>CompilerProcess: run_command(args, cwd=compile_cwd)
CompilerProcess-->>library_compiler: compile result
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
crates/fbuild-core/src/path.rs (1)
385-402: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win
strip_prefixis case-sensitive — confirm cwd/path casing always matches.On case-insensitive filesystems (Windows, macOS),
stable_path.strip_prefix(&stable_cwd)at Line 392 will fail ifcwdandpathdiffer only in case, silently falling back to the absolute path and re-introducing a project-dependent compile arg (defeating cache stability). In practice both come throughcanonicalize_lexical/compile_cwd_from_outputso casing should agree, but this relies on canonicalization returning byte-identical case for the shared prefix.Worth verifying that both the
cwdproduced bycompile_cwd_from_outputand the source/include paths canonicalize to identical casing on Windows/macOS.🤖 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 `@crates/fbuild-core/src/path.rs` around lines 385 - 402, `path_arg_for_compile_cwd` relies on `stable_path.strip_prefix(&stable_cwd)` being case-identical, which can fail on case-insensitive platforms and fall back to an absolute arg. Verify the casing produced by `compile_cwd_from_output` and the paths passed through `canonicalize_lexical`/`strip_unc_prefix` in `path_arg_for_compile_cwd`, and adjust the normalization so `cwd` and `path` share the same canonical casing before calling `strip_prefix`.
🤖 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 `@crates/fbuild-core/src/path.rs`:
- Around line 385-402: `path_arg_for_compile_cwd` relies on
`stable_path.strip_prefix(&stable_cwd)` being case-identical, which can fail on
case-insensitive platforms and fall back to an absolute arg. Verify the casing
produced by `compile_cwd_from_output` and the paths passed through
`canonicalize_lexical`/`strip_unc_prefix` in `path_arg_for_compile_cwd`, and
adjust the normalization so `cwd` and `path` share the same canonical casing
before calling `strip_prefix`.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 0bcf1e48-0d91-460f-87a8-8bdef8a3f032
📒 Files selected for processing (7)
crates/fbuild-build/src/esp32/orchestrator/framework_libs.rscrates/fbuild-build/src/esp32/orchestrator/local_libs.rscrates/fbuild-build/src/pipeline/library.rscrates/fbuild-build/src/zccache.rscrates/fbuild-core/src/path.rscrates/fbuild-packages/src/library/library_compiler.rscrates/fbuild-packages/src/library/library_manager.rs
Summary
The #942 profiling showed framework built-in libs (
fw-libs) as the dominant warm-scenario cost (~185 s), and the root cause (posted on #952) was that fw-lib compiles pass absolute source/-o/-Ipaths withcwd = None, so their zccache keys embed the project directory and don't stay stable across project dirs — unlike sketch/core compiles, which relativize to the workspace root.This aligns fw-libs with the sketch/core path:
compile_cwd_from_output,path_arg_for_compile_cwd,normalize_flags_for_compile_cwd) fromfbuild-build/src/zccache.rstofbuild_core::path, sofbuild-packages' library compiler can use them.zccache.rsre-exports them, so every existingcrate::zccache::…call site (andcompiler.rs) is unchanged. Their tests moved with them.compile_cwdtocompile_library_with_jobs:Some(workspace)relativizes source/-o/project--Iand runs the compiler from the workspace;None(every other caller: local libs, pipeline libs, library manager) is byte-identical to before. Only the ESP32 fw-libs orchestrator opts in.Results
#942 Docker harness, clean cold→warm, vs the post-#951 baseline:
A real ~24% fw-libs improvement, and fw-libs is now workspace-relative like the rest of the compile pipeline (which also makes its keys portable for cross-runner CI caching). It is not the full 150 s→seconds win: the remaining cost is a deeper firmware-compile zccache cross-project key-stability gap — sketch/core don't fully hit cross-project in a clean run either — which I'll file as a follow-up. This PR is the necessary, non-regressing first step and a correctness alignment.
Validation
fbuild-packages715 +fbuild-build452 +fbuild-core(incl. the 6 relocated helper tests) all pass on Linux.env:demobuilds end-to-end (firmware produced) in the harness.None→ unchanged; CI covers the cross-platform library compile paths.Part of #952 / #942.
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes