Hive Hive
Sign in

fix(cli): always expose -Swift.h for Swift-only SPM frameworks (#11007)

GitHub issue · Closed

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

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

Comments
PS
przemyslaw-szurmak Jun 3, 2026

yeah, thanks guys!