Skip to content

Latest commit

 

History

History
131 lines (97 loc) · 5.29 KB

File metadata and controls

131 lines (97 loc) · 5.29 KB

PlatformIO Compatibility

fbuild is designed to consume existing platformio.ini projects while using a Rust-native build, deploy, and monitor pipeline. This page owns compatibility notes that are too detailed for the root README.

.eh_frame Strip Policy

By default, fbuild strips GCC's .eh_frame exception-unwinding tables on release builds for platforms that do not use them: Teensy, STM32, RP2040, NRF52, and ESP8266. This can save 40-180 KB of flash on a typical FastLED sketch. PlatformIO does not strip these tables by default.

ESP32 with the stock Arduino sdkconfig preserves .eh_frame because esp32_exception_decoder and panic-print-backtrace consume it.

The decision is made per build by this precedence chain:

Condition Policy
FBUILD_STRIP_EH_FRAME=1 env var Strip
FBUILD_KEEP_EH_FRAME=1 env var Preserve
build_type = debug in platformio.ini Preserve
-fexceptions, -funwind-tables, or -fasynchronous-unwind-tables in build_flags Preserve
ESP32 with CONFIG_ESP_SYSTEM_PANIC_PRINT_BACKTRACE=y Preserve
Otherwise, on supported release platforms Strip

Opt Out Per Project

Add an unwind-tables flag to platformio.ini:

[env:teensy41]
platform = teensy
board = teensy41
framework = arduino
build_flags = -funwind-tables

Or set an environment variable:

FBUILD_KEEP_EH_FRAME=1 fbuild build

Why fbuild Deviates

GCC emits .eh_frame by default even when nothing consumes it. On the platforms above, toolchain JSON already ships -fno-exceptions, no runtime calls _Unwind_*, and no debugger or decoder reads the tables. In that case .eh_frame is dead metadata occupying flash.

A byte-level audit on an ESP32-S3 FastLED Blink build (FastLED/FastLED#2473) found .eh_frame accounted for 36% of firmware size. Stripping at the compiler level with -fno-asynchronous-unwind-tables -fno-unwind-tables is the reliable fix. Implementation details and the original decision matrix are in #245.

PlatformIO-Compatible CI

fbuild ci is a drop-in replacement for pio ci for supported workflows. See the fbuild ci reference for flag mapping and examples.

Multiple .ino Files

Arduino CLI documents sketch preprocessing as concatenating .ino and .pde files into one generated .cpp: the file matching the sketch folder name comes first, then the remaining files are appended alphabetically.

PlatformIO preprocesses top-level PROJECT_SRC_DIR/*.ino and *.pde files through its InoToCPPConverter. In PlatformIO projects this commonly makes src/main.ino the primary file; when there is no named primary, PlatformIO detects a file containing setup() or loop() and treats that file as the main input. The generated output name is based on the selected main .ino path.

fbuild follows that combined compatibility rule:

  • Arduino-style sketch folders use <sketch-folder>/<sketch-folder>.ino as the primary file when present.
  • PlatformIO-style src/ folders use src/main.ino as the primary file when present, then fall back to a file containing setup() or loop().
  • Additional .ino tabs are concatenated after the primary file in case-insensitive alphabetical order, with exact filename order as the tie breaker.
  • The generated file is named <primary>.ino.cpp, matching the chosen primary .ino stem.

References:

.ino Prototype Generation

Arduino-style .ino preprocessing inserts forward declarations for free functions so sketches can call functions before their definitions. fbuild uses an embedded tree-sitter C++ parser for this step instead of regex matching.

This keeps prototype generation structural enough to avoid control-flow blocks, lambdas, class methods, macro fragments, scoped Class::method definitions, and namespace-local definitions. It also handles common C++ signature syntax such as templates, attributes, references, and default arguments.

No clang or libclang runtime install is required for this preprocessing path.

Generated .ino.cpp Stability

fbuild writes generated .ino.cpp files with LF line endings and avoids rewriting the file when the generated bytes are unchanged. This preserves the file mtime for unchanged sketches so compiler caches do not see a fresh input only because preprocessing ran again.

Generated #line paths are normalized before writing:

  • Paths under the project root are emitted project-relative, for example src/main.ino.
  • Path separators are emitted as / on all hosts, including Windows.
  • Windows drive letters are lowercased when an absolute fallback path is needed.

main.cpp and .ino Files

When a project contains both main.cpp and one or more .ino files, fbuild uses main.cpp as the sketch source and skips automatic .ino preprocessing. This matches projects where main.cpp includes the .ino file manually and avoids duplicate symbols.

Because that behavior can otherwise hide ignored .ino files, fbuild prints a yellow warning before continuing the compile.