fix(ldf): honor lib_deps on Teensy/STM32 and warn on inert lib_ldf_mode (#1214) - #1226
Conversation
…de (#1214) Scoped to asks #2/#3 only. The reporter explicitly WITHDREW ask #1 (deepen the LDF to scan library sources) after a maintainer pointed out that shallow, sketch-only resolution is the intended default — #1094's `inactive_local_library_header_cannot_select_framework_library` is a deliberate, tested invariant, and deepening the scan would also drag libraries' global constructors into every image. That invariant is untouched here and still passes; this adds an opt-in, it does not widen the scan. The actual gap was that a project had NO lever at all on the Teensy/STM32 path: `lib_deps`, `lib_ldf_mode`, `library.json` dependencies and header hints were all inert, so a dependency the finder cannot infer was unexpressible. - `lib_deps` now force-selects framework libraries on Teensy and STM32. `get_lib_deps()` was already parsed but only the ESP32 orchestrator ever consumed it. Declared libraries are selected in a new pass 0, BEFORE the scan, so they participate in the reconciliation passes and pull in their own transitive dependencies — PlatformIO's semantics for an explicit declaration, not a bolt-on. - Entry matching tolerates what `lib_deps` actually contains: case, owner prefixes, and version specs (`arduino/SPI@^1.0` matches `SPI`). URLs and local paths never match a framework library — they name something to fetch, and are left to the installer path. - `declared_deps` joins the library-select cache key. A `lib_deps` edit changes the selection without touching any scanned file, so without this a warm cache would silently serve the old selection — the same latent-until-cold-resolution failure mode the issue describes. The key sorts entries, so reordering ini lines does not throw away a valid entry. - `lib_ldf_mode` was never read anywhere in the workspace, so a project setting `deep` got a silent no-op. It now warns that the setting is inert and points at `lib_deps`. `chain`/`off` pass without noise since they match actual behavior. 8 new tests: the issue's exact shape (library-header-only reachability) stays unselected without a declaration and selected with one, entry-normalization cases, URL/path rejection, transitive pull-in of a declared library's own deps, and both cache-key properties. Co-Authored-By: Claude <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 35 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (8)
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 |
The bench lives outside crates/, which is where I searched for construction sites — Windows CI caught it. Whole-workspace check is clean now. Co-Authored-By: Claude <noreply@anthropic.com>
Closes #1214 — scoped to asks #2/#3, per the reporter's own follow-up.
Scope: ask #1 is deliberately NOT implemented
The issue originally asked for a deeper LDF, then the reporter withdrew it:
They're right, and the code says so out loud:
framework_libs.rscarries a regression test namedinactive_local_library_header_cannot_select_framework_library(#1094). Deepening the scan would undo that, and would also re-introduce the problem FastLED spent real effort escaping — libraries pulled in by default drag their global constructors into the image, making them unstrippable.That invariant is untouched here and still passes. The scan still seeds only from project translation units. This PR adds an opt-in.
The actual gap
On the Teensy/STM32 path a project had no lever at all. Per the issue's table,
lib_deps,lib_ldf_mode,library.jsondependencies, and header hints were all inert — including a plain unconditional#include <SPI.h>in a library header. So a dependency the finder cannot infer was simply unexpressible.Changes
1.
lib_depsforce-selects framework libraries on Teensy and STM32get_lib_deps()was already parsed (ini_parser/mod.rs:249) — only the ESP32 orchestrator ever consumed it. Now Teensy and STM32 do too.Declared libraries are selected in a new pass 0, before the scan, so they flow through the existing reconciliation loop and pull in their own transitive dependencies. That's PlatformIO's semantics for an explicit declaration, and it's why this isn't a bolt-on append at the end — a test covers exactly that (
declared_library_pulls_in_its_own_transitive_dependency).2. Entry matching tolerates real
lib_depssyntaxSPISPI,spiSPI@^1.0,arduino/SPI@1.2.3https://github.com/example/SPI.git./vendor/SPIURLs and local paths name something to fetch, so they're left to the installer path rather than being mangled into a bare name that accidentally matches.
3.
declared_depsis part of the cache keyThis one matters more than it looks. A
lib_depsedit changes the selection without touching any scanned file, so without it in the key a warm cache silently serves the old selection — the same latent-until-cold-resolution failure the issue describes ("a warm cache can hide it"). Entries are sorted before hashing, so reordering ini lines doesn't needlessly throw away a valid entry. Both properties are tested.4.
lib_ldf_modeno longer no-ops silentlyIt was never read anywhere in the workspace, so a project setting
deepgot nothing — which is how you lose an afternoon. It now warns that the setting is inert and points atlib_deps.chain/offpass without noise since they describe what fbuild actually does.Tests
8 new, all passing:
unreached_library_is_not_selected_without_a_declaration— the fix(ldf): avoid self-selecting Teensy framework libraries and their global state #1094 baseline, pinned so this PR can't quietly widen the scanlib_deps_declaration_selects_an_unreached_library— the issue's exact shapelib_deps_matching_ignores_case_owner_and_version,lib_deps_urls_and_paths_never_match_a_framework_library,declared_dep_name_normalizationdeclared_library_pulls_in_its_own_transitive_dependencyc04c_declared_deps_change_invalidates_key,c04d_declared_deps_order_does_not_affect_keyVerified locally:
-p fbuild-library-select -p fbuild-build-engine -p fbuild-configgreen, #1094'sinactive_local_library_header_cannot_select_framework_librarystill passes, clippy clean with-D warningsacross all four crates.Not in scope
The reporter notes the real fix for the FastLED breakage belongs on the FastLED side (the Teensy 4.x driver shouldn't depend on the Arduino SPI library at all) and has filed it there. This PR gives consumers the lever that was missing regardless.
library.jsondependenciesremains ESP32-install-path-only; it affects installation, not framework-library selection, so wiring it here would be a different change than the one asked for.🤖 Generated with Claude Code