Hive Hive
Sign in

fix(cli): stop emitting -Xcc @resp into OTHER_SWIFT_FLAGS (Xcode 26 “expected exactly one compiler job”)

GitHub issue · Closed

Metadata
Source
tuist/tuist #11023
Updated
Jun 24, 2026
Domains
Generated projects
Details

What changed

In LinkGenerator.setupFrameworkSearchPath, the framework-search-path response file is now injected into OTHER_SWIFT_FLAGS as a bare @<resp> token instead of -Xcc @<resp>. OTHER_CFLAGS and OTHER_LDFLAGS are unchanged (they keep @<resp>).

Why

Users on Xcode 26 hit a hard build failure after the CLI starts consolidating framework search paths into a response file:

error: unable to handle compilation, expected exactly one compiler job in '...'
error: clang importer creation failed

Root cause

When a target has at least 20 unique precompiled framework search paths (the consolidation threshold introduced for ARG_MAX relief), Tuist writes those -F paths to Derived/FrameworkSearchPaths/<Target>.resp and references the file via @resp in the compiler/linker flags.

For OTHER_SWIFT_FLAGS the reference was emitted as -Xcc @resp. -Xcc forwards the next token verbatim to Swift’s ClangImporter. Under Xcode 26, ClangImporter’s createInvocation no longer expands @file response files, so the @resp path survives as a literal positional Objective-C input. clang then sees two inputs (the real translation unit plus @resp), produces two -cc1 jobs, and the importer asserts that it expected exactly one — surfacing as the two errors above.

Passing the response file as a bare @resp (no -Xcc) routes it through swift-driver instead, which does expand the response file and forwards the contained -F flags to the clang importer as proper search-path flags. clang never receives a @file token as an input, so only one -cc1 job is produced.

OTHER_CFLAGS (clang driver) and OTHER_LDFLAGS (ld) both expand @file correctly and still need it to stay under ARG_MAX, so those are left as-is.

When this regressed

The -Xcc @resp injection was introduced in #10228 (commit 319f3d8391, 2026-05-26), which added the whole framework-search-path consolidation — the threshold, the .resp file, and the OTHER_SWIFT_FLAGS line — in one change. It first shipped in CLI 4.195.7 and has been latent ever since.

It is not a regression in the generation code in the usual sense: setupFrameworkSearchPath is byte-identical across 4.195.7 → 4.195.12, and for a triggering project the generated pbxproj + resp + deps-modulemap are identical too. The defect only manifests under Xcode 26, whose ClangImporter stopped expanding @file; on earlier Xcode the same -Xcc @resp was harmless.

This also explains why per-version bisections do not point at this file — the only CLI commits in the relevant window are #10984 (cache content-hash change, 4.195.11) and #10996. The likely surfacing mechanism is that #10984 changed the cache content hash, which on upgrade invalidates and repopulates the binary cache (the source of the >= 20 precompiled frameworks), forcing cold rebuilds and shifting which targets cross the consolidation threshold, thereby re-exposing the latent Xcode 26 bug.

Validation

  • Unit test test_setupFrameworkSearchPath_consolidatesIntoResponseFile_whenManyPrecompiledPaths updated to assert OTHER_SWIFT_FLAGS references the bare @resp and contains no -Xcc; passes.
  • Built the CLI (xcodebuild -scheme tuist) — succeeds; lint clean.
  • End-to-end on a generated macOS app with 22 precompiled frameworks plus a SwiftPM external dependency (the exact trigger shape), regenerated with the patched CLI and built on Xcode 26.4.1 with a cold module cache:
    • OTHER_SWIFT_FLAGS now ends in the bare @.../App.resp (the only -Xcc left is the unrelated explicit-modules -fmodule-map-file flag).
    • Zero expected exactly one compiler job / clang importer creation failed errors, and the .resp path is never handed to a clang -cc1 invocation as an input. Swift compilation completes and the build proceeds past it.

Impact

Restores buildability for Xcode 26 projects that cross the framework-search-path consolidation threshold (commonly via Tuist binary caching, where each cached target contributes one search path).

Comments
TA
tuist-atlas[bot] Jun 3, 2026

The fix for the Xcode 26 “expected exactly one compiler job” error, by stopping the emission of -Xcc @resp into OTHER_SWIFT_FLAGS, is now available in 4.195.13. Update to get the fix.