apple / apple/swift-openapi-generator

Build-tool plugin breaks swift-collections module resolution during xcodebuild archive

Open
#890 2 comments 1 reaction 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.