Skip to content

teensy41 on Windows host: GCC LTO temp-file 'mv' strips backslashes from C:\ paths #261

Description

@zackees

Summary

When running bash compile teensy41 --examples Ports/PJRCSpectrumAnalyzer on a Windows host with fbuild 2.2.4, the teensy41 toolchain's GCC LTO post-link step shells out to MSYS mv with a Windows path whose backslashes have been stripped, causing mv to fail and collect2.exe to abort the link.

Symptom

End of the build (after compile + LTO):

/usr/bin/mv: cannot stat 'C:UsersniterisccfpQR27.ltrans0.o.tem': No such file or directory
make: [C:\Users\niteris\ccfpQR27.ltrans0.ltrans.o] Error 1 (ignored)
/usr/bin/mv: cannot stat 'C:UsersniterisccfpQR27.ltrans1.o.tem': No such file or directory
make: [C:\Users\niteris\ccfpQR27.ltrans1.ltrans.o] Error 1 (ignored)
collect2.exe: error: ld returned 1 exit status

Compilation finished in 03m:24s with 1 error(s):
  - Board teensy41 failed

The make rule target keeps the backslashes (C:\Users\niteris\ccfpQR27.ltrans0.ltrans.o), but the argument that reaches /usr/bin/mv has them dropped (C:UsersniterisccfpQR27.ltrans0.o.tem). Classic MSYS shell-escape collapse.

Environment

  • Host: Windows 10 Pro (10.0.19045)
  • Shell: Git Bash / MSYS-based mv
  • fbuild: 2.2.4
  • Board: teensy41
  • Example: Ports/PJRCSpectrumAnalyzer (exercises LTO across enough TUs that -flto partitions into 2+ ltrans pieces, which is what triggers the temp-file mv)

Why this matters

CI runs on Linux so the Linux GCC driver handles LTO temp files internally without shelling out to a separate mv. This bug is host-Windows-only and bites contributors developing locally. Pairs poorly with the otherwise-fixed CMSIS-DSP link (#257) — the prerequisite link errors are gone, so the build now gets all the way to LTO and falls over on the temp-file rename instead.

Root cause guess

GCC's LTO driver (lto-wrapper) generates a make rule like:

$(target): $(temp)
	mv $(temp) $(target)

When the temp path contains literal backslashes (C:\Users\...), passing it through $(temp) into a make recipe that's executed via MSYS bash loses the backslashes because make treats \ as a line-continuation/escape character inside recipe lines on POSIX shells. The build dir for LTO temps is %TEMP% or %USERPROFILE%, both of which are Windows-native paths.

Possible fixes (in fbuild's teensy41 toolchain config)

  1. Set TMPDIR to a POSIX-style path before invoking the link step so LTO temps land somewhere with forward slashes (e.g. /tmp/fbuild-lto). This is what arduino-cli does on Windows. Probably the lowest-effort fix.
  2. Quote temp paths in the LTO wrapper's emitted make rules. Out of scope for fbuild — would need an upstream GCC patch.
  3. Disable LTO for teensy41 on Windows hosts (workaround, would hurt binary size).

Option 1 is what I'd recommend — set TMPDIR=$(cygpath -u "$TEMP") (or equivalent POSIX-style override) in fbuild's teensy41 environment on Windows.

Reproduce

bash compile teensy41 --examples Ports/PJRCSpectrumAnalyzer

on a Windows host with Git Bash / MSYS shell. The example is large enough to force GCC to partition LTO; smaller examples may not trip the bug because they fit in a single ltrans partition that doesn't need the temp-file dance.

Not affected

  • Linux CI build (uses GCC's native temp-file rename, no shell-out to mv)
  • macOS host (same reason)

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions