Skip to content

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

@zackees

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
    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