Repository navigation
Description
Summary
fbuild test-emu --emulator qemu fails at emulator startup because the QEMU that fbuild downloads and owns cannot resolve libslirp.so.0:
/home/runner/.fbuild/prod/cache/toolchains/qemu-xtensa/be7f2fb0c3ab00a9/esp-develop-9.2.2-20250817/qemu/bin/qemu-system-xtensa:
error while loading shared libraries: libslirp.so.0: cannot open shared object file: No such file or directory
QEMU ESP32S3 test-emu failed: failed: QEMU exited with code 127
Observed in FastLED CI: https://github.com/FastLED/FastLED/actions/runs/31091411573/job/92583052211
Why this is an fbuild bug, not a consumer bug
fbuild downloads, caches, extracts and invokes this QEMU binary — the consumer never sees the toolchain. A consumer cannot know which shared objects a given esp-develop-* build needs, and pinning that knowledge in each consumer's CI is exactly the kind of workaround that goes stale the moment fbuild bumps the QEMU revision.
FastLED currently carries one such workaround already — .github/workflows/qemu_template.yml installs libsdl2-2.0-0 "because the Espressif QEMU binary that fbuild downloads is dynamically linked against libSDL2-2.0.so.0". I opened FastLED/FastLED#3865 to add libslirp0 alongside it and am closing it unmerged, because both belong here instead.
The interesting part: it is probably not simply a missing system package
In the failing run, esp32s3_qemu_lcd passed while esp32s3_qemu_rmt failed — same workflow file, same reusable template, same ubuntu-latest image, same qemu-system-xtensa. A missing distro package would have failed both identically.
The Espressif QEMU tarball ships its own lib/libslirp.so.0 and resolves it via rpath ($ORIGIN/../lib). An asymmetric failure across two concurrent jobs points at fbuild's toolchain cache — a raced or partial extract leaving one job's tree missing the bundled library while another job's cache entry is intact. Both jobs ran concurrently against the same qemu-xtensa/be7f2fb0c3ab00a9 cache key.
I could not confirm the extract race directly (no xtensa QEMU in my local Windows cache to inspect), so treat that as the leading hypothesis rather than a diagnosis.
Suggested fix, in preference order
- Make toolchain extraction atomic — extract to a temp dir and rename into place, so a concurrent or interrupted extract can never expose a partial tree under the final cache key. This fixes the whole class, not just libslirp.
- Verify the toolchain after extract — check the expected binaries and their bundled
lib/payload are present before declaring the cache entry valid; re-extract if not. - Preflight the emulator — before launching, confirm the binary's dynamic deps resolve and fail with an actionable message instead of a bare exit 127.
- Optionally, have fbuild declare/provision the QEMU runtime deps it needs so consumers can drop their
libsdl2-2.0-0workarounds too.
Acceptance criteria
- Two concurrent
fbuild test-emuinvocations sharing one cold QEMU toolchain cache key both start the emulator successfully. - A partial/corrupt cached toolchain is detected and repaired rather than invoked.
- Emulator startup failure due to unresolved shared libraries produces a diagnostic naming the missing library and the toolchain path, not just
exited with code 127. - FastLED can delete the
libsdl2-2.0-0install step fromqemu_template.yml.
Related
- fix(ci): install libslirp0 for QEMU jobs FastLED#3865 (closing unmerged in favour of this)
- chore(rp2350w): hand off final #3832 hardware validation FastLED#3864
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTriage
Activity
zackees commentedon Aug 10, 2026
Fixed by #1296 (squash-merged as 067732d).
Three stacked defenses:
PackageBase::is_cached()now requires the.install_completesentinel. Partial/legacy cache entries are rejected and re-extracted.lib/directory exists alongside the binary.resolve_executable()probes the binary via contained subprocess before returning. Exit-127 (missing shared lib) produces a diagnostic naming the library and toolchain path.