Skip to content

fix(library-select): teensy41 — ssd1351/fontconvert/fontconvert.c host tool compiled (ft2build.h missing) #267

@zackees

Description

@zackees

Context

fbuild 2.2.5 fails to build any sketch (reproduced with FastLED examples/Blink/Blink.ino) for teensy41. The failure is not in the user sketch or in FastLED — it is in a host-only command-line tool that ships inside the Teensy framework's bundled ssd1351 library:

build error: build failed: compilation failed for
C:\Users\niteris\.fbuild\prod\cache\platforms\dl-framework-arduinoteensy-1.160.0\1b0675c97b0fd8d7\1.160.0\libraries\ssd1351\fontconvert\fontconvert.c:
C:/.../libraries/ssd1351/fontconvert/fontconvert.c:23:10:
fatal error: ft2build.h: No such file or directory
   23 | #include <ft2build.h>
      |          ^~~~~~~~~~~~
compilation terminated.

fontconvert.c is self-documented at the top as:

NOT AN ARDUINO SKETCH. This is a command-line tool for preprocessing fonts to be used with the Adafruit_GFX Arduino library.
REQUIRES FREETYPE LIBRARY. www.freetype.org

It ships with its own Makefile that links -lfreetype. It is a host build-time utility, never intended for ARM cross-compilation.

What Arduino IDE and PlatformIO do that fbuild doesn't

Per the Arduino library specification, the ssd1351 library is a 1.0 flat-layout library (no src/ directory). The spec says:

the source code is searched from the library root folder and the utility folder

Root is non-recursive; the only special subdirectory is literally utility/ (lowercase). Subdirectories like fontconvert/, util/, Fonts/, examples/, and extras/ are ignored for compilation. The ssd1351 author parked the host tool in fontconvert/ (not utility/) precisely so Arduino IDE would skip it.

PlatformIO is doubly protected:

  1. LDF — Blink does not #include <ssd1351.h>, so PIO never compiles ssd1351 at all.
  2. srcDir default = src — even if LDF picked it, PIO's default would skip the flat-layout root entirely.

Note: the ssd1351 library.json has "exclude": ["extras", "*.bmp"], but that is an export field governing pio pkg pack packaging — NOT a build filter. Honoring that field alone wouldn't fix this.

Two layered bugs in fbuild

Bug 1 — Library-selection leak. ssd1351 is being compiled even though the sketch never references it. This is the same shape as #204 (teensy30/LC FNET/Snooze/RadioHead/mbedtls), which the #205#214 LDF work was supposed to fix for the teensy orchestrator. Either teensy41 isn't going through resolve_framework_library_sources_cached, or the LDF transitively pulls in ssd1351 via some reachable header.

Bug 2 — Arduino library spec violation when scanning a selected library. Even after LDF correctly selects a library, fbuild recursively globs all .c/.cpp files inside it, including non-source subdirectories. Per the Arduino spec, 1.0 flat-layout libraries should only scan the root (non-recursive) + utility/ (literal); 1.5 recursive libraries should only scan src/ recursively. Anything else is ignored.

Bug 2 is the more general one — any library that ships a host-side tool in a non-utility/ subdirectory will hit it.

Reproduction

git clone https://github.com/FastLED/FastLED
cd FastLED
bash compile teensy41

Or, equivalently, any project that includes FastLED targeting teensy41 against framework-arduinoteensy 1.160.0.

Environment:

  • Windows 10
  • fbuild 2.2.5 (FastLED's pinned version)
  • Teensy 4.1 / IMXRT1062
  • arm-none-eabi-gcc 11.3.1
  • framework-arduinoteensy-1.160.0

Recent related teensy41 regressions

  • fbuild 2.2.4 — CMSIS-DSP link fix (FastLED#2500)
  • fbuild 2.2.5 — multiple-definition fix (FastLED#2501)
  • This is the third teensy41 issue in quick succession. Suggests teensy41's larger bundled-library set is exercising library-scanner bugs that other platforms hide.

Proposal

Two independent fixes; both should land.

Fix 1 — Investigate why ssd1351 is reaching the compile set on teensy41

Verify that crates/fbuild-build/src/teensy/orchestrator.rs actually goes through resolve_framework_library_sources_cached (the #214 wiring) for teensy41, not just teensy30/LC. If it does, trace why ssd1351 is being pulled in — most likely a transitive #include chain from a header that IS referenced. Dump compile_commands.json for a Blink+teensy41 build and audit the source-file origins, mirroring the #204 evidence table.

Fix 2 — Honor the Arduino library specification when scanning a selected library

When collecting source files inside a chosen Arduino library, dispatch on layout:

if library_dir/src exists:
    # 1.5 recursive layout
    sources = glob(library_dir/src/**/*.{c,cpp,cc,cxx,S,ino})
else:
    # 1.0 flat layout
    sources  = glob(library_dir/*.{c,cpp,cc,cxx,S,ino})          # non-recursive
    sources += glob(library_dir/utility/**/*.{c,cpp,cc,cxx,S})   # only this subdir, literally lowercase

This matches arduino-cli behavior exactly and makes fbuild safe against any well-formed Arduino library shipping companion tooling. It also speeds up scanning by skipping examples/, extras/, Fonts/, etc., which are never compiled in any sane build system.

The fix likely belongs in crates/fbuild-library-select/ (the scanner) and/or crates/fbuild-build/src/framework_libs.rs (where sources are collected per selected library).

Local workaround until fix lands

Delete C:\Users\niteris\.fbuild\prod\cache\platforms\dl-framework-arduinoteensy-1.160.0\1b0675c97b0fd8d7\1.160.0\libraries\ssd1351\fontconvert\fontconvert.c from the framework cache. Confirms whether Bug 2 is the only blocker (i.e. does the build succeed once that one file is gone, or does another ssd1351-internal file also fail).

Acceptance criteria

  • bash compile teensy41 (FastLED Blink) succeeds on a clean fbuild install with no manual cache surgery.
  • Regression test: a CI job builds Blink on teensy41 against framework-arduinoteensy-1.160.0 (or whatever is current) and asserts the build passes.
  • Audit table for teensy41 Blink (mirroring teensy30/LC: Teensy orchestrator compiles unreferenced framework libraries (FNET, Snooze, RadioHead, mbedtls) — causes .bss / .dmabuffers RAM overflow #204's table) shows ssd1351 is NOT in the compiled-TU set (Fix 1).
  • Unit test in the library-source scanner: given a fixture mimicking the ssd1351 1.0 flat layout (root files + fontconvert/fontconvert.c + util/x.c + examples/ + Fonts/), the scanner returns root files + utility/ content only — never reaches fontconvert/, util/, examples/, or Fonts/ (Fix 2).
  • Equivalent fixture test for a 1.5 recursive layout (src/foo.cpp compiled, src/sub/bar.cpp compiled, root-level baz.cpp NOT compiled).

Decisions

Related issues

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