Skip to content

feat(cli): normalize compile-many under a PlatformIO-compatible fbuild ci command #242

@zackees

Description

@zackees

Follow-up to PR #241 (merged): the new fbuild compile-many primitive does the same job as PlatformIO's pio ci — compile one or more sketches against a board for CI. Today the two commands have the same intent but different surfaces, so any existing pio ci invocation in a library's CI scripts has to be rewritten to switch backends. We can make that switch a no-op.

What pio ci looks like

pio ci --board uno --lib . examples/Blink/Blink.ino [examples/Fire2012/Fire2012.ino ...]

Key shape:

  • --board <board> (-b) — required, repeatable across pio ci for multi-board, single-board per invocation otherwise.
  • Positional args — sketch source files or directories. Globs work in the shell, pio ci itself accepts paths.
  • --lib <path> (-l) — extra library roots to include in the build. Repeatable.
  • --project-conf <path> (-c) — point at a platformio.ini for build flags.
  • --keep-build-dir / --build-dir <path> — preserve / locate the build outputs.

Proposal

Add fbuild ci as the canonical CI command and treat compile-many as its in-tree backend. The two-stage execution model already shipped in #241; this issue is purely about the CLI surface.

Minimum surface to claim PlatformIO compatibility:

pio ci flag fbuild ci equivalent Notes
--board <b> / -b <b> --board <b> / -b <b> Already supported in compile-many.
positional sketch paths positional sketch paths Already supported.
--lib <path> / -l <path> --lib <path> (repeatable) Maps to extra include / library roots routed through the orchestrator. Today compile-many has no equivalent flag — needs wiring.
--project-conf <path> / -c <path> --project-conf <path> / -c <path> Points at platformio.ini. fbuild already parses platformio.ini in non-CI paths; route the same parser.
--keep-build-dir, --build-dir <path> same Optional. Useful for inspecting firmware.elf / firmware.hex after a CI run.

Two parallelism flags from #241 (--framework-jobs, --sketch-jobs) stay as fbuild-only extensions — they have no PIO equivalent and are fine to be additive.

Behavior decisions to pin down in the issue:

  1. Should fbuild ci and fbuild compile-many both exist? Recommendation: yes. ci is the canonical name (matches PIO + matches what most consumers will type); compile-many becomes a hidden alias or is documented as the fbuild-native name. Either way the underlying code path is one.
  2. Default behavior on flag absence. pio ci errors out if --board is missing; matching that errors-early behavior is safer than picking a default.
  3. --lib resolution semantics. PIO interprets --lib . as "include the current dir as a library root". The shape that matches today is to feed the path into the orchestrator's extra_include_dirs and let the existing LDF pick it up; document if there's a difference.

Why this matters

Every library currently running pio ci in GitHub Actions today is a near-zero-cost candidate for fbuild adoption — if the command swap is a one-line s/pio ci/fbuild ci/ in the workflow. If the surface diverges (different flag names, different positional semantics), each library has to rewrite its CI, which is friction we don't need given the primitive is already identical.

This is the same normalization story as fbuild deploy matching pio run --target upload semantically: drop-in switching is the path to broad adoption.

Acceptance

  • fbuild ci --board <b> [--lib <path>...] [--project-conf <path>] <sketch...> works end-to-end, producing the same artifacts as fbuild compile-many for the same inputs.
  • pio ci --board <b> examples/*/*.ino and fbuild ci --board <b> examples/*/*.ino produce equivalent firmware.elf/.hex outputs for at least one canonical FastLED-style library on uno (smoke test in crates/fbuild-cli/tests/).
  • A 1-paragraph doc section in docs/ (or crates/fbuild-cli/README.md) maps pio ci flags to fbuild ci flags so library maintainers know what to expect.
  • Exit codes match PIO convention: 0 on all-pass, non-zero on any-sketch-fail.

Out of scope

  • Anything that changes the two-stage execution model from feat(cli): #238 two-stage compile-many primitive #241. This is purely CLI surface + flag plumbing.
  • pio ci's --exclude filter and other low-traffic flags. Add them if a real consumer needs them; otherwise the four flags above cover the canonical shape.
  • Adopting pio ci's build directory layout. fbuild's .fbuild/build/... tree is fine; the build-dir flag governs where, not how.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions