Skip to content

feat(symbols): ingest toolchain paths from build_info.json#436

Merged
zackees merged 2 commits into
mainfrom
feat/issue-428-buildinfo-toolchain-paths
Jun 6, 2026
Merged

feat(symbols): ingest toolchain paths from build_info.json#436
zackees merged 2 commits into
mainfrom
feat/issue-428-buildinfo-toolchain-paths

Conversation

@zackees

@zackees zackees commented Jun 6, 2026

Copy link
Copy Markdown
Member

Summary

Closes #428 (Phase 1 of #434).

  • Extends BuildInfo with nm_path / cppfilt_path / readelf_path / objdump_path plus a PIO-shape aliases block that mirrors them onto short keys (nm, c++filt, etc.). PlatformIO consumers (FastLED ci/util/symbol_analysis.py, ci/inspect_binary.py) keep working drop-in against fbuild-built artifacts.
  • Derives the four paths centrally in BuildInfo::new from size_path using the GCC cross-tool naming convention (<prefix>-size<prefix>-{nm,c++filt,readelf,objdump}). All of fbuild's existing orchestrators (AVR, ESP32, RP2040, STM32, Teensy, ESP8266, NRF52, SAM, Renesas, Apollo3, LPC, Silabs, CH32V) ship GCC cross-toolchains, so no orchestrator surgery is needed.
  • Teaches fbuild symbols to auto-locate build_info.json by walking up from the ELF directory; adds a --build-info <path> explicit override. New resolution order:
    1. --nm / --cppfilt CLI flags (user wins).
    2. --build-info <path> if provided.
    3. Auto-discovery: walk up from ELF dir for build_info.json or build_info_<env>.json.
    4. PATH lookup of bare nm, with c++filt derived by stem.
    5. Hard error with a message pointing at all four sources.
  • Common case becomes flag-less:
    fbuild symbols .fbuild/build/uno/firmware.elf
    fbuild symbols .pio/build/esp32s3/firmware.elf
    
  • Adds docs/symbols.md walking through the resolution order, the aliases schema, and PIO/fbuild interop.

Test plan

  • soldr cargo check --workspace --all-targets
  • soldr cargo clippy -p fbuild-build -p fbuild-cli --all-targets -- -D warnings
  • soldr cargo test -p fbuild-build --lib — 627 passed, 0 failed
  • soldr cargo test -p fbuild-cli --bin fbuild — 25 passed, 0 failed
  • New tests:
    • derive_gcc_tool_path_avr_prefix / xtensa_with_exe_suffix / bare_size_falls_back — derivation rules
    • build_info_populates_new_toolchain_fields — the four new fields land
    • build_info_aliases_block_mirrors_paths — PIO-shape mirror
    • build_info_aliases_omit_empty_optional_tools — ESP8266 (no ar/objcopy) keeps consumers safe with key in aliases
    • emit_writes_aliases_into_json — round-trip via JSON
    • find_build_info_walks_up_from_elf_dir / prefers_env_specific / returns_none_when_absent — discovery walker
    • load_build_info_unwraps_single_env — single-env outer object contract
    • resolve_reads_nm_from_build_info_auto_discovery — CLI resolver: build_info auto-pickup
    • resolve_explicit_nm_wins_over_build_info — CLI resolver: explicit override precedence
    • resolve_explicit_build_info_path_is_honoured — CLI resolver: --build-info flag

🤖 Generated with Claude Code

Extends `BuildInfo` with `nm_path` / `cppfilt_path` / `readelf_path` /
`objdump_path` and mirrors them onto a PIO-shape `aliases` block so
existing PlatformIO consumers (FastLED `ci/util/symbol_analysis.py`,
`ci/inspect_binary.py`) read fbuild-built artifacts drop-in. Paths are
derived centrally in `BuildInfo::new` from `size_path` using the GCC
cross-tool naming convention — no orchestrator surgery needed.

Teaches `fbuild symbols` to auto-locate `build_info.json` by walking up
from the ELF directory; adds a `--build-info <path>` override. The
common case becomes flag-less:

  fbuild symbols .fbuild/build/uno/firmware.elf
  fbuild symbols .pio/build/esp32s3/firmware.elf

Adds `docs/symbols.md` walking through the resolution order, the
`aliases` schema, and PIO/fbuild interop.

Closes #428.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@zackees, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 48 minutes and 25 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1a97d28c-7b86-4989-9acf-78b0599c035c

📥 Commits

Reviewing files that changed from the base of the PR and between 619d6ca and e284f3f.

📒 Files selected for processing (9)
  • crates/fbuild-build/src/build_info.rs
  • crates/fbuild-build/src/symbol_analyzer.rs
  • crates/fbuild-cli/src/cli/args.rs
  • crates/fbuild-cli/src/cli/dispatch.rs
  • crates/fbuild-cli/src/cli/symbols_cmd.rs
  • crates/fbuild-core/src/symbol_analysis/mod.rs
  • crates/fbuild-core/src/symbol_analysis/tests.rs
  • docs/CLAUDE.md
  • docs/symbols.md
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-428-buildinfo-toolchain-paths

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.

`cargo fmt --all` flagged a stray blank line in `mod.rs` and a
short-line wrap in `tests.rs`. Both were left over from when the
file was split out — they pass locally only because rustfmt
default formatting matches them when they already exist. CI runs
`cargo fmt -- --check`, which doesn't.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@zackees
zackees merged commit 6eda97e into main Jun 6, 2026
83 of 84 checks passed
@fastled-project-sync fastled-project-sync Bot moved this to Triage in FastLED Tracker Jun 7, 2026
zackees added a commit that referenced this pull request Jun 29, 2026
…rdening (#833)

* dylint(826): port ban_std_pathbuf + ban_unrooted_tempdir from zccache

Adopt zccache's two PathBuf/tempdir lints into fbuild with allowlists
matching the fbuild source tree:

- ban_std_pathbuf: 193-entry allowlist of legacy PathBuf call sites;
  steers new code at fbuild_core::path::NormalizedPath.
- ban_unrooted_tempdir: 92-entry allowlist of legacy unrooted tempdir
  call sites; steers new code at fbuild_paths::get_cache_root() and
  the tempfile::*_in(...) variants.

Both lints are ON and deny-by-default for new code. Target state is
zero allowlist entries; the lists shrink as migrations land.

Add the dylint crate dirs to the crate_guard allowlist so future
edits to those Cargo.tomls aren't blocked by the monocrate hook.

Refs #826, #436, #437, #282.

* dylint(826): add 3 net-new fbuild-specific lints

Add three lints that enforce fbuild's own architectural rules:

- ban_direct_serialport: bans `serialport::*` references outside
  crates/fbuild-serial/ so the Windows USB-CDC contract stays in one
  place. Legacy allowlist covers fbuild-cli diagnostics, the daemon
  device manager, and the fbuild-deploy bootloader paths.

- ban_file_based_locks: bans `OpenOptions::create_new(true)`, the
  `fs2::FileExt` API, and `libc::flock` / `nix::flock`. Allowlist is
  empty — fbuild has no file-based locks per CLAUDE.md "Key
  Constraints"; this locks the invariant in.

- ban_deploy_tool_direct_invocation: bans `Command::new("esptool" |
  "esptool.py" | "avrdude" | "picotool" | "dfu-util" | "pyocd")`
  outside crates/fbuild-deploy/. Pattern-matches the binary-name
  string literal; complements ban_raw_subprocess (which scopes by
  spawn shape, not binary).

All three follow the ban_raw_subprocess skeleton: pinned nightly,
file-path scope (crates/*/src/), file-level allowlist via include_str!,
forward-slash normalized. Each carries unit tests for the scope/dir
helpers.

Refs #826, #694.

* fix(daemon/ws): replace 5 unwraps in error-reply paths with fallback

The WebSocket error-reply paths in `handle_serial_ws` previously panicked
via `serde_json::to_string(&err_msg).unwrap()` if the JSON serializer
ever failed. While `SerialServerMessage` always serializes cleanly today,
a panic in the cold error path tears down the entire WebSocket — exactly
the wrong failure mode for a code path whose only job is to surface an
error to the client.

Add a small `serialize_or_fallback` helper that returns a hardcoded
JSON error frame on serializer failure, and route the 5 affected
`Message::Text(...)` constructions through it (open_port failure,
unexpected-message-shape, parse-error, attach_reader=None,
attached-confirmation send).

The 3 remaining `to_string(...).unwrap()` calls at lines ~441/450/467
are on normal data-forwarding paths (not error-reply paths) and are
out of scope for this fix; #826 only flagged the
error-reply ones as a daemon-stability hazard.

Refs #826.

* build: add new dylint crates to workspace exclude

cargo metadata refuses to operate on dylint sub-crates that are
neither members nor excluded; add the 5 new lint crates from #826
to the existing exclude list (alongside ban_raw_subprocess).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

fbuild symbols: ingest toolchain paths from build_info.json + extend schema with nm/c++filt/readelf/objdump

1 participant