Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Xcode 26.3 + xcodebuild CLI: builtin-SwiftDriver bypasses swift-frontend wrapper via swiftc symlink redirect

Open
#147 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
38/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Quiet
Tech stack
swift

Research direction

Start with the compiler patching and symlink setup described in the issue, then inspect InjectionLite/Sources/InjectionLite/LogParser.swift and the Xcode 26.3 CLI build behavior. Reproduce with the supplied xcodebuild flags and verify whether the build cache mtime advances and newly compiled files are captured. Done means the supported xcodeless flow captures current Swift compile commands without the misleading lookup failure.

Written by the indexing model from the issue text.

Description

Summary

On Xcode 26.3 + InjectionNext 2.0.0RC5, hot-reload from a pure xcodebuild-CLI workflow is broken at an architectural level. Even with Patch Compiler correctly applied AND all three documented build flags set, the feedcommands call inside the swift-frontend wrapper is never reached, so the compile-command cache (/tmp/InjectionNext_iPhoneSimulator_builds.json.gz) never updates for the current build. Saves never produce /tmp/injectionNext_*.o and the RC5 console reports Could not locate command for <file>. InjectionNext is not compatible with "Whole Module" Compilation Mode. (the warning text is misleading — SWIFT_COMPILATION_MODE is singlefile).

Environment

  • macOS 26.x (Darwin 25.3.0)
  • Xcode 26.3 (post-Feb-20 toolchain ship)
  • InjectionNext 2.0.0RC5 (build 14492)
  • Inject SPM 1.6.0 (@ObserveInjection + .enableInjection())
  • Workflow: xcodeless — builds via xcodebuild CLI, app launched on simulator with SIMCTL_CHILD_DYLD_INSERT_LIBRARIES pointing at iOSInjection.bundle.
  • Project: large iOS workspace with CocoaPods + SPM. SWIFT_ENABLE_EXPLICIT_MODULES=YES (required by targets).

Reproduction

  1. Apply "Patch Compiler" via RC5 menu → Settings → Compiler. Confirm "Compiler State: Intercepted".
  2. Verify on disk:
    ls -la "/Applications/Xcode 26.3.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend"*
    
    Yields:
    -rwxr-xr-x  swift-frontend       (374-byte bash wrapper)
    -rwxr-xr-x  swift-frontend.save  (169 MB original binary)
    
  3. Truncate /tmp/feedcommands.log and note the mtime/size of /tmp/InjectionNext_iPhoneSimulator_builds.json.gz.
  4. Run a clean xcodebuild with all three flags:
    xcodebuild -workspace … -scheme … -configuration Debug \
      -destination "platform=iOS Simulator,id=…" \
      EMIT_FRONTEND_COMMAND_LINES=YES \
      COMPILATION_CACHE_ENABLE_CACHING=NO \
      CLANG_CACHE_FINE_GRAINED_OUTPUTS=NO \
      build
    
  5. Build succeeds. 513 swift-frontend command lines emitted to log, ~358 of them -frontend -c -primary-file …. swift-frontend.save subprocesses are observable in ps during build.
  6. Result: json.gz mtime DID NOT advance. New .swift files (e.g. a freshly-created MyView.swift) are NOT in the cache. Saving any file produces no /tmp/injectionNext_*.o. RC5 console shows the "Could not locate command" warning.

Root cause (verified empirically)

RC5's "Patch Compiler" performs three actions:

  1. Renames swift-frontend (binary) → swift-frontend.save.
  2. Installs swift-frontend.sh as new swift-frontend.
  3. Re-points the swift- symlinks (swift, swiftc, swift-api-digester, swift-cache-tool, swift-symbolgraph-extract) to → swift-frontend.save* (the original), deliberately bypassing the wrapper.

Confirmed by ls -la:

swiftc -> swift-frontend.save
swift  -> swift-frontend.save
swift-api-digester -> swift-frontend.save
swift-cache-tool   -> swift-frontend.save
swift-symbolgraph-extract -> swift-frontend.save
swift-synthesize-interface -> swift-frontend

(That last one is the only symlink still routing through the wrapper.)

This was sensible pre-Xcode-26 when Xcode invoked swift-frontend directly. But Xcode 26.3 uses builtin-SwiftDriver, which invokes swiftc directly. Through the symlink, that resolves straight to swift-frontend.save — the wrapper is never executed and feedcommands is never called. The compile cache never learns about the current build.

The xcactivitylog fallback path in InjectionLite/Sources/InjectionLite/LogParser.swift also fails on this configuration: xcodebuild from CLI on Xcode 26.3 emits a ~479-byte effectively-empty xcactivitylog, with no -primary-file lines and no builtin-Swift-Compilation lines that the v26.3 fallback grep can match.

What I tried (didn't work)

  • SWIFT_USE_INTEGRATED_DRIVER=NO — Xcode rejects it on this project: "Enabling Swift explicit modules also requires: SWIFT_USE_INTEGRATED_DRIVER". Targets require explicit modules; circular dependency.
  • Setting all three documented flags (COMPILATION_CACHE_ENABLE_CACHING=NO, CLANG_CACHE_FINE_GRAINED_OUTPUTS=NO, EMIT_FRONTEND_COMMAND_LINES=YES) — flags applied successfully but the wrapper still isn't reached because the bypass is at symlink-resolution time, not at cache time.
  • Re-applying Patch Compiler (multiple times) — the wrapper is correctly installed each time; the symlink-bypass is by design.
  • Downgrading to InjectionNext 1.6.0 — same compile-discovery code (PR #125 shipped in both), so same gap.

feedcommands.log is not a useful diagnostic for this issue, by the way — feedcommands is silent on both success and most failure paths. The reliable diagnostic is /tmp/InjectionNext_iPhoneSimulator_builds.json.gz mtime: if it doesn't advance after a build, the wrapper isn't reaching feedcommands.

Question for maintainers

What's the intended xcodeless flow on Xcode 26.3? Specifically:

  1. Is the swiftc → swift-frontend.save symlink redirect intentional on Xcode 26+? If so, how is feedcommands supposed to capture commands when builtin-SwiftDriver invokes swiftc instead of swift-frontend?
  2. Would re-pointing swiftc → swift-frontend (the wrapper) and creating a swiftc.save → swift-frontend.save symlink be a viable patch shape, or does it break driver-mode invocations? (Specifically for cases where swiftc is invoked without -frontend.)
  3. Is the LogParser.swift xCode26_3 fallback expected to handle CLI xcodebuild builds? Empirically the xcactivitylog from CLI builds is ~479 bytes with no usable per-file lines — happy to attach a sample if useful.

I'm happy to test patch candidates on this project — it's a real-world large workspace (CocoaPods + SPM, ~500 swift-frontend invocations per clean build) and reliably reproduces the gap. cc @maatheusgois-dd @johnno1962

Dominant language
Swift
Stars
437
Forks
32
PR merge metrics
No merged PRs in 30d

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from johnno1962/InjectionNext

All issues in johnno1962/InjectionNext

Similar issues

More Swift issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.