Skip to content

fix: escape response-file backslashes for driver linkers - #1853

Merged
ghaith merged 1 commit into
masterfrom
fix/response-file-driver-escaping
Aug 12, 2026
Merged

fix: escape response-file backslashes for driver linkers#1853
ghaith merged 1 commit into
masterfrom
fix/response-file-driver-escaping

Conversation

@ghaith

@ghaith ghaith commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Problem

On Windows, linking a real-sized project through the clang driver fails with no such file or directory for every object:

clang: error: no such file or directory: 'C:bachmannSolutionCenterworkspace...mainProg.st.o'

Every backslash has been stripped: C:\build\obj\mainProg.st.o arrives as C:buildobjmainProg.st.o.

Cause

write_response_file assumed a single tokenizer for all linkers. Its comment stated "an unquoted backslash is literal in this format" — true for lld and binutils, but a compiler driver treats a backslash as an escape. Object paths were written bare, so the driver consumed the separators.

The defect needed two conditions that could not co-occur on Windows until recently:

  1. A command line over the 30,000-byte threshold, routing args through a response file. Small projects never reach it.
  2. A driver linker consuming that file. Windows always fell back to a direct ld.lld link, which reads backslashes literally — so the existing behaviour was correct for the only linker that could be selected.

Including the sysroot in the driver probe (#1852) made clang selectable on Windows and switched on condition 2, exposing the writer's assumption. The bug was latent in the writer the whole time; nothing on Windows could reach it.

Fix

Choose the escaping from the linker family where the file is written:

Linker family Style Backslash
clang, cc, gcc EscapedBackslash doubled
ld.lld, ld.bfd, gold LiteralBackslash literal

Quoted arguments (those carrying whitespace) already double backslashes under both families, so that path is unchanged.

Verification

Forcing a response file with PLC_LINKER_RESPONSE_FILE=1 on a Windows host:

Linker Before After
clang (driver) fails on every object links
ld.lld (direct) links links

Tests

30 linker unit tests pass, three of them new and each failing without this change:

  • response_file_quoting_escapes_backslashes_for_driver_linkers
  • write_response_file_escapes_object_paths_for_driver_linkers — asserts the emitted lines and that each unescapes back to the original argument
  • driver_linker_response_file_round_trips_windows_paths — goes through CcLinker so the style is derived the way finalize derives it, rather than asserted against a hand-passed constant

No lit test. A lit case could force a response file with a driver linker, but lit runs on Linux where paths carry no backslashes, so the defect cannot reproduce — it would pass for the wrong reason. The unit tests are the real guard.

🤖 Generated with Claude Code

`write_response_file` assumed one tokenizer for every linker. Its comment
claimed an unquoted backslash is literal in the response-file format; that
holds for lld and binutils, but a compiler driver treats a backslash as an
escape. Object paths were therefore written bare, and clang received
`C:buildobjmainProg.st.o` for `C:\build\obj\mainProg.st.o`, failing the link
with "no such file or directory" for every object.

The defect needed two conditions that could not co-occur on Windows until
now: a command line over the 30,000-byte threshold, so the args are routed
through a response file, and a driver linker consuming it. Windows always
fell back to a direct ld.lld link, which reads backslashes literally, so the
existing behaviour was correct for the only linker that could be selected.
Including the sysroot in the driver probe made clang selectable on Windows
and exposed the writer's assumption.

Pick the escaping from the linker family at the point the file is written:
drivers get doubled backslashes, direct linkers keep them literal. Quoted
arguments already double backslashes under both, so that path is unchanged.

Verified by forcing a response file with PLC_LINKER_RESPONSE_FILE=1: clang
now links where it previously failed on every object, and a direct ld.lld
link is unaffected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

Build Artifacts

🐧 Linux

Artifact Link Size
deb-x86_64 Download 38.4 MB
schema Download 0.0 MB
stdlib Download 32.4 MB
plc-x86_64 Download 43.5 MB
deb-aarch64 Download 30.8 MB
plc-aarch64 Download 43.3 MB

From workflow run

🪟 Windows

Artifact Link Size
stdlib.lib Download 4.0 MB
stdlib.dll Download 0.1 MB
plc.exe Download 38.3 MB

From workflow run

@ghaith
ghaith added this pull request to the merge queue Aug 12, 2026
Merged via the queue into master with commit 73f6261 Aug 12, 2026
22 checks passed
@ghaith
ghaith deleted the fix/response-file-driver-escaping branch August 12, 2026 06:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants