Stale .o survives git checkout to a different branch — SCons decider misses the change, linker fails with undefined reference to removed code
#5,481 opened on Jul 23, 2026
Repository metrics
- Stars
- (7,329 stars)
- PR merge metrics
- (Avg merge 109d 16h) (5 merged PRs in 30d)
Description
Environment: PlatformIO Core, Windows, ESP32-C3 target (Xtensa/RISC-V toolchain), but the mechanism is toolchain-agnostic.
What happened: Built successfully on branch A, which added a function call in foo.cpp to a helper defined in bar.cpp. Checked out branch B (an ancestor without that helper) and ran pio run again. Link failed:
undefined reference to `helper()'
git grep helper at HEAD returns nothing — the symbol doesn't exist anywhere in the checked-out tree. foo.cpp.o's mtime matched foo.cpp's mtime exactly, both stale relative to the actual checkout time, meaning SCons's signature decider judged foo.cpp.o "unchanged" and skipped recompiling it, while bar.cpp.o did rebuild correctly (fresh, correctly missing the definition) — producing a link-time mismatch between two objects from two different source states.
Workaround: rm .pio/build/<env>/.sconsign311.dblite && pio run -e <env> forces a full re-derivation and fixes it.
Ask: Given SCons' own tracker has related reports of the MD5-timestamp decider missing changes (SCons/scons#2760, SCons/scons#2980), could PlatformIO either (a) default to a content-hash-only decider for .pio/build, or (b) detect a branch/HEAD change (e.g. via .git/HEAD mtime) and auto-invalidate .sconsign*.dblite? Related: #5348, #716.