Skip to content

fbuild deficiency vs PlatformIO+Teensyduino: CMSIS-DSP not auto-linked for Teensy 3.x/4.x #300

Description

@zackees

Symptom

FastLED's Ports/PJRCSpectrumAnalyzer example fails to link on Teensy 3.x under fbuild:

.lto-tmp/.../AudioAnalyzeFFT1024::update():
  undefined reference to `arm_cfft_radix4_q15'
.lto-tmp/...:
  undefined reference to `arm_cfft_radix4_init_q15'
collect2: error: ld returned 1 exit status

These symbols come from CMSIS-DSP (libarm_cortexM4lf_math.a for Teensy 3.5/3.6, similarly for 3.0/3.1/3.2; libarm_cortexM7lfsp_math.a for Teensy 4.x).

Reproducible: every FastLED teensy36 run on master (e.g. https://github.com/FastLED/FastLED/actions/runs/26684937829).

Root cause / delta

Under PlatformIO + Teensyduino, the framework's SCons builder script (teensy.py in the platform package) auto-appends the correct CMSIS-DSP library to the link command based on the MCU. The user doesn't have to list it in lib_deps.

Under fbuild, that SCons logic doesn't run. fbuild builds the project using its own link command, and CMSIS-DSP is not added — so any Teensy library that uses CMSIS-DSP (notably Audio.h's FFT classes) fails at link.

Since FastLED switched to fbuild as the default backend (f215b56b8), this regressed.

CI workflows blocked

  • teensy36 — fails on Ports/PJRCSpectrumAnalyzer (FFT)
  • teensy30 — generic link failure; likely the same underlying class but a different example (verify separately)
  • Any Teensy build that uses Audio.h FFT will share this failure.

Proposed shape

In fbuild-build (or wherever per-MCU link flags are assembled), add CMSIS-DSP auto-link for Teensy MCUs mirroring Teensyduino's matrix:

MCU Library
ATSAMD21 libarm_cortexM0l_math.a
MK20DX128/256 libarm_cortexM4l_math.a
MK64FX512 (3.5) libarm_cortexM4lf_math.a
MK66FX1M0 (3.6) libarm_cortexM4lf_math.a
MKL26Z64 (LC) libarm_cortexM0l_math.a
IMXRT1062 (4.x) libarm_cortexM7lfsp_math.a

Either resolve via BoardConfig.mcu and hardcode the table, or expose a board JSON field (e.g. build.lib_ldflags or build.cmsis_dsp_lib) that the bundled JSONs can populate from the upstream Teensy boards.txt (build.fpu + recipe.c.combine.pattern carry the info).

The library ships inside the Teensyduino toolchain (framework-arduinoteensy@.../cores/teensy*/), already on disk via the fbuild toolchain cache — no extra download needed.

Immediate FastLED unblock

I'm not adding a FastLED-side workaround for Ports/PJRCSpectrumAnalyzer here — the example is meant to work on Teensy 3.5/3.6/4.x per its own comment block. Filter syntax can't cleanly distinguish 3.x from 4.x on a single memory tier, and gutting the example with #ifdefs to compile to a no-op is worse than leaving the workflow red while this is in flight.

PR-3 in my coordinated sweep is being deferred to teensy36 greening up once this lands.

Test plan

  • Unit: extend the board JSON test to assert teensy36's BoardConfig.cmsis_dsp_lib (or whatever the field is called) resolves to libarm_cortexM4lf_math.a.
  • Integration: re-run FastLED teensy36 workflow, confirm Ports/PJRCSpectrumAnalyzer links.

Filed during a coordinated CI-green sweep; blocking PR-3 in that sweep.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions