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.
Symptom
FastLED's
Ports/PJRCSpectrumAnalyzerexample fails to link on Teensy 3.x under fbuild:These symbols come from CMSIS-DSP (
libarm_cortexM4lf_math.afor Teensy 3.5/3.6, similarly for 3.0/3.1/3.2;libarm_cortexM7lfsp_math.afor Teensy 4.x).Reproducible: every FastLED
teensy36run 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.pyin 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 inlib_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 onPorts/PJRCSpectrumAnalyzer(FFT)teensy30— generic link failure; likely the same underlying class but a different example (verify separately)Audio.hFFT 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:libarm_cortexM0l_math.alibarm_cortexM4l_math.alibarm_cortexM4lf_math.alibarm_cortexM4lf_math.alibarm_cortexM0l_math.alibarm_cortexM7lfsp_math.aEither resolve via
BoardConfig.mcuand hardcode the table, or expose a board JSON field (e.g.build.lib_ldflagsorbuild.cmsis_dsp_lib) that the bundled JSONs can populate from the upstream Teensyboards.txt(build.fpu+recipe.c.combine.patterncarry 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/PJRCSpectrumAnalyzerhere — 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
teensy36greening up once this lands.Test plan
BoardConfig.cmsis_dsp_lib(or whatever the field is called) resolves tolibarm_cortexM4lf_math.a.teensy36workflow, confirmPorts/PJRCSpectrumAnalyzerlinks.Filed during a coordinated CI-green sweep; blocking PR-3 in that sweep.