apple / apple/swift-openapi-generator
Build-tool plugin breaks swift-collections module resolution during xcodebuild archive
- Dominant language
- Swift
- Stars
- 2k
- Forks
- 182
- Avg merge
- 13h 28m
- Merged PRs (30d)
- 5
Description
## Description
When archiving an iOS project that uses `swift-openapi-generator` as a build-tool plugin, `xcodebuild archive` fails with:
```
swift-collections/Sources/ContainersPreview/Extensions/OutputSpan+Extras.swift:17:8:
error: Unable to find module dependency: 'InternalCollectionsUtilities'
```
The same project builds and archives successfully when the OpenAPI generator plugin is removed from `Package.swift` and the generated sources (Types.swift, Client.swift) are committed directly.
## Environment
- Xcode 26.2 (Swift 6.2.3) and Xcode 26.4 (Swift 6.3)
- swift-openapi-generator 1.10.4
- swift-openapi-runtime 1.11.0
- swift-collections 1.4.0 (transitive dependency via openapi-runtime)
- macOS 26 (Tahoe), both local and GitHub Actions CI (macos-26 runner)
- `SWIFT_ENABLE_EXPLICIT_MODULES=NO` does not resolve the issue
## Reproduction
1. Create an Xcode project with a local SPM package that uses `OpenAPIGenerator` as a build plugin
2. The package depends on `swift-openapi-runtime` which transitively pulls `swift-collections` 1.4.0
3. Run: `xcodebuild archive -scheme -sdk iphoneos -configuration Release -derivedDataPath /tmp/clean-dd -skipPackagePluginValidation`
4. Archive fails with the `InternalCollectionsUtilities` module not found error
**Key observation:** The error does NOT occur when:
- Building for simulator (`-sdk iphonesimulator`)
- Building Debug configuration
- The plugin is removed and generated sources are committed directly
- Using incremental builds with cached DerivedData
It ONLY fails with a clean DerivedData + archive + iphoneos SDK, suggesting the plugin's execution interferes with SPM's build graph ordering for device archives.
## Workaround
Pre-generate the OpenAPI sources using the CLI tool, then strip the plugin from Package.swift before archiving:
```bash
# 1. Resolve packages
xcodebuild -resolvePackageDependencies -scheme MyApp -derivedDataPath /tmp/bootstrap
# 2. Generate sources via CLI
swift run --package-path /tmp/bootstrap/SourcePackages/checkouts/swift-openapi-generator swift-openapi-generator generate openapi.json --config openapi-generator-config.yaml --output-directory Sources/MyOpenAPIClient/ --plugin-source build
# 3. Strip plugin from Package.swift
# Remove .package(url: "swift-openapi-generator", ...) and plugins: [...]
# 4. Archive without plugin
xcodebuild archive -scheme MyApp -sdk iphoneos ...
```
This is what we use in CI, but it adds significant complexity to the workflow.
## Related issues
- apple/swift-collections#546 (Archive fails when building XCFramework)
- apple/swift-async-algorithms#376 (same InternalCollectionsUtilities error)
- Swift Forums: [Xcode 26 - Unable to find module dependency](https://forums.swift.org/t/xcode-26-unable-to-find-module-dependency/80516)
## Expected behavior
`xcodebuild archive` should succeed with the OpenAPI generator build-tool plugin present, same as it does for Debug/Simulator builds.
Contributor guide
Research direction
Start by reproducing the clean-DerivedData device archive with the OpenAPI build-tool plugin and compare it with the simulator, Debug, and committed-source cases described here. Read the linked swift-collections and swift-async-algorithms issues and the Swift Forums report for related module-resolution behavior; done means xcodebuild archive succeeds with the plugin present.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- build-system, mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100