Skip to content

Fix Bazel hot-reload: handle .swift-suffixed include paths and stale -o flags#130

Merged
johnno1962 merged 1 commit intojohnno1962:Xcode26.3from
maatheusgois-dd:Xcode26.3
Apr 16, 2026
Merged

Fix Bazel hot-reload: handle .swift-suffixed include paths and stale -o flags#130
johnno1962 merged 1 commit intojohnno1962:Xcode26.3from
maatheusgois-dd:Xcode26.3

Conversation

@maatheusgois-dd
Copy link
Copy Markdown
Contributor

@maatheusgois-dd maatheusgois-dd commented Apr 12, 2026

Summary

Fixes three issues that prevent hot-reload injection from working in Bazel monorepos (particularly with rules_xcodeproj):

1. .swift-suffixed include paths misclassified as source files

FrontendServer.swiftCompilationArgParser.process

SPM packages with names ending in .swift (e.g. ulid.swift) produce include paths like -I/path/to/swiftpkg_ulid.swift. The arg parser checks hasSuffix(".swift") and only excluded -F as a predecessor flag. This caused the path to be added to swiftFiles instead of args, breaking compilation.

Fix: Expanded the guard to check for -I, -iquote, -isystem in addition to -F. Also handles the concatenated form (-I/path/...) where the flag and path are a single token, by checking hasPrefix("-I") and hasPrefix("-F").

2. Stale -o flag from original build causes object file to be written to wrong path

NextCompiler.swiftrecompile

The stored compilation arguments contain the original -o /path/to/bazel/output.o from the Bazel build. NextCompiler appends its own -o eval1.o, but swift-frontend uses the first -o it encounters, so the .o file is written to the Bazel path instead of the expected temp path. The linker then fails with no such file or directory: eval1.o.

Fix: Filter out any existing -o <value> pair from stored.arguments before appending the new output path. Uses a skipNext flag to consume the value token after -o.

Also re-adds WMO flag filtering (-whole-module-optimization, -internalize-at-link, -no-serialize-debugging-options) that was removed in the Xcode26.3 branch — these flags prevent single-file recompilation.

3. Restored local tmpbase for NextCompiler

The Xcode26.3 branch switched NextCompiler to use Reloader.tmpbase (which resolves to NSTemporaryDirectory() + "eval\(N)"), but the link() method in NextCompiler expects the object at /tmp/injectionNext_N.o. Restored the local let tmpbase = "/tmp/injectionNext" to keep the two paths consistent.

4. Updated BAZEL.md documentation

Replaced the "rules_xcodeproj Limitation" warning (which stated hot-reload doesn't work with rules_xcodeproj) with documentation explaining how InjectionNext now handles rules_xcodeproj output bases.

Impact on other Bazel implementations

These changes are backwards-compatible and should not break existing Bazel workflows:

  • The -I/-F prefix check in FrontendServer is strictly additive — it only prevents misclassification of paths that were previously incorrectly treated as source files. Standard .swift source files are unaffected since they don't start with -I or -F.
  • The -o stripping in NextCompiler only affects the stored args before the injection-specific -o is appended. The original build is never modified.
  • WMO flag filtering was already present on the main branch — this just restores it to Xcode26.3.
  • The tmpbase change only affects NextCompiler's internal temp file paths and doesn't touch any Bazel build artifacts.

Testing

Tested on Bazel project with rules_xcodeproj:

  • Compilation args correctly exclude ulid.swift include paths from source file list
  • Object file written to correct temp path
  • Linking proceeds with correct .o path

Related Pull Request: johnno1962/InjectionLite#23
Made with Cursor

@maatheusgois-dd maatheusgois-dd marked this pull request as ready for review April 12, 2026 15:21
@johnno1962 johnno1962 merged commit 00f4620 into johnno1962:Xcode26.3 Apr 16, 2026
johnno1962 added a commit that referenced this pull request Apr 17, 2026
* Streamline DLKit.appImages.

* Xcode 26.3

* Bump version for log parsing changes.

* Restructure.

* Fallback to builtin swiftc.

* Afterthoughts.

* Simplify, simplify.

* feat(Xcode26.3): Fix The Bazel ✏️ (#130)

* Add MCP server for AI-driven control of InjectionNext (#129)

* Add MCP server for AI-driven control of InjectionNext

- ControlServer: local TCP server (localhost:8919) that exposes app
  actions as JSON commands (watch project, enable devices, get status, etc.)
- LogBuffer: ring buffer capturing injection logs, compilation errors,
  and file watcher activity for AI consumption
- MCP server (Node.js): 13 tools exposing InjectionNext to AI agents
  via the Model Context Protocol (get_status, watch_project, get_logs, etc.)
- Hook log() and InjectionServer.log/error into LogBuffer for real-time
  debug console access

Made-with: Cursor

* Update README.md

* Address review: opt-in mcpServer default, harden ControlServer

- Add Defaults.mcpServer boolean (set via `defaults write`); ControlServer
  and LogBuffer only start when enabled.
- Make LogBuffer.shared optional; all call sites use optional chaining.
- Clamp get_logs limit to 0...500 to prevent negative/overflow traps.
- Add 64KB max request size guard on TCP read loop.
- Add zod as direct dependency and engines field in package.json.
- Update README with enable step and correct Node.js version.

Made-with: Cursor

* Bump InjectionLite.

---------

Co-authored-by: Matheus Gois <matheus.gois@doordash.com>
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