Resolves https://github.com/tuist/tuist/issues/11007
What
Reverts #10971 so Swift-only SwiftPM framework targets again let Xcode synthesize their modulemap, which always exposes the -Swift.h Objective-C compatibility header. Also drops the @objc/NSObject source-scan that earlier commits on this branch explored, which was the wrong approach.
Why
#10971 made Swift-only SwiftPM framework targets emit a headerless modulemap (framework module X { export * } with DEFINES_MODULE=NO) to avoid #10967, a crash where Xcode 26 beta’s explicit-modules dependency scanner read the synthesized modulemap’s X-Swift.h reference before Swift had emitted that header.
The headerless modulemap hides the target’s Swift @objc interface, so Objective-C @import can no longer see the Swift classes. Concretely, RollbarNotifier’s @import RollbarReport; fails to compile with unknown receiver 'RollbarCrashDiagnosticFilter' (#11007).
Root cause and why this approach
- A generate-time custom
MODULEMAP_FILE cannot reference the build-generated X-Swift.h. The header is produced inside the built framework, and a relative header "X-Swift.h" only resolves from Xcode’s synthesized in-framework modulemap, never from a modulemap stored at a derived path. Every custom variant tested (top-level header, separate and nested requires objc submodules) fails with Header 'X-Swift.h' not found. So restructuring the modulemap to expose the header to Objective-C while hiding it from the Swift scanner is not possible.
- The only way to expose the Swift interface to Objective-C is to let Xcode synthesize the modulemap. That is the pre-#10971 behavior and matches what SwiftPM does, which always emits the compatibility header for library targets.
- #10967 no longer reproduces on current Xcode. Building an EE
tuist and running the real tuist cache against a swift-log-as-framework project on Xcode 26.4.1, the single-arch simulator Binaries-Cache build (the exact #10967 scenario) succeeds with always-expose. The scanner ordering bug was specific to the Xcode 26 beta.
Validation
Real tuist cache on Xcode 26.4.1, simulator pass:
- swift-log framework cache build succeeds, no
Logging-Swift.h not found.
- Rollbar cache build with
--cache-profile only-external succeeds; RollbarCrashCollector.m consumes the Swift @objc classes through @import RollbarReport.
Caveats
- The cache device pass was not re-tested locally (no iOS device SDK on the test machine; device builds are multi-arch and not the #10967 trigger). Worth confirming on CI.
- Anyone still on an Xcode 26 beta where the scanner bug lives would regress to #10967. On release Xcode (26.4.1 and later) it is a non-issue.
🤖 Generated with Claude Code