Skip to content

Disable traits for imported runtime#878

Merged
simonjbeaumont merged 14 commits into
apple:mainfrom
madsodgaard:traits
Mar 19, 2026
Merged

Disable traits for imported runtime#878
simonjbeaumont merged 14 commits into
apple:mainfrom
madsodgaard:traits

Conversation

@madsodgaard
Copy link
Copy Markdown
Contributor

Disables the default traits for the openapi-runtime, to make sure that other packages depending on the generator can actually disable the traits if they want to.

@simonjbeaumont
Copy link
Copy Markdown
Collaborator

If we wait until 6.3 for this we can avoid the split manifest right @czechboy0?

If we really want to do it before I'd prefer we use compiler conditionals inside the package manifest.

@madsodgaard
Copy link
Copy Markdown
Contributor Author

@simonjbeaumont Yeah, traits were introduced in 6.1

It would be great if we could get this in before... we cannot disable the "FullFoundation" trait in packages where we depend on the generator and the runtime atm.

@simonjbeaumont
Copy link
Copy Markdown
Collaborator

I'm sympathetic to the motivation to get this over the line. Let's see how we can get it done with minimal fuss.

I triggered the CI. Looks like there's some issues. Might be worth experimenting locally with act.

I think sticking to the single package manifest might make this simpler to play around with a get it working locally.

@madsodgaard
Copy link
Copy Markdown
Contributor Author

@simonjbeaumont Thanks, will take a look at it locally.

Hm, I am not sure if #compiler is the right tool? And we don't have a tool-version directive. Are you suggesting we do something like, and keep a single Package manifest?

#if compiler(>=6.1)
let runtimePackage: Package.Dependency = .package(url: "https://github.com/apple/swift-openapi-runtime", from: "1.11.0", traits: [])
#else
let runtimePackage: Package.Dependency = .package(url: "https://github.com/apple/swift-openapi-runtime", from: "1.11.0")
    #endif

because that will still fail when parsing the package description:


Showing All Errors Only
Package: swift-openapi-generator

/Users/mads/dev/swift-openapi-generator/Package.swift:27:43: 'package(url:from:traits:)' is unavailable

/Users/mads/dev/swift-openapi-generator/Package.swift:27:43: error: 'package(url:from:traits:)' is unavailable
 25 | // Needed until we can drop Swift 6.0, to always disable the default traits
 26 | #if compiler(>=6.1)
 27 | let runtimePackage: Package.Dependency = .package(url: "https://github.com/apple/swift-openapi-runtime", from: "1.11.0", traits: [])
    |                                           `- error: 'package(url:from:traits:)' is unavailable
 28 | #else
 29 | let runtimePackage: Package.Dependency = .package(url: "https://github.com/apple/swift-openapi-runtime", from: "1.11.0")

PackageDescription.Package.Dependency.package:4:24: note: 'package(url:from:traits:)' was introduced in PackageDescription 6.1
2 |   class Dependency {
3 | @available(_PackageDescription 6.1)
4 |     public static func package(url: String, from version: PackageDescription.Version, traits: Set<PackageDescription.Package.Dependency.Trait> = [.defaults]) -> PackageDescription.Package.Dependency  }
  |                        `- note: 'package(url:from:traits:)' was introduced in PackageDescription 6.1
5 | }
6 |

@simonjbeaumont
Copy link
Copy Markdown
Collaborator

Hm. We've used compiler conditions in manifests before (https://github.com/swift-otel/swift-otel/blob/main/Package.swift) but I guess that was for the same compiler major version.

Have you tried with #if swift? If not then I guess we'll do multiple manifests.

@madsodgaard
Copy link
Copy Markdown
Contributor Author

madsodgaard commented Mar 16, 2026

@simonjbeaumont yeah, #if swift has the same error.

@simonjbeaumont
Copy link
Copy Markdown
Collaborator

simonjbeaumont commented Mar 16, 2026

@madsodgaard Could you look at this a bit more. I just managed to get this to compile.

I added this extension near the end of the Package.swift:

extension Package.Dependency {
    static func package(url: String, from version: Version, traitsIfAvailable traits: [String]) -> Package.Dependency {
        #if swift(>=6.1)
        .package(url: url, from: version, traits: Set(traits.map(Trait.init(stringLiteral:))))
        #else
        .package(url: url, from: version)
        #endif
    }
}

Then using this in the package dependencies:

        .package(url: "https://github.com/apple/swift-openapi-runtime", from: "1.8.2", traitsIfAvailable: []),

With this patch, I have no problems compiling the package with swift:6.0 and swift:6.2 Docker images.

@madsodgaard
Copy link
Copy Markdown
Contributor Author

madsodgaard commented Mar 16, 2026

@simonjbeaumont Hm, I cannot get that to work when compiling on MacOS with just swift build

I am guessing you are also keeping // swift-tools-version:6.0, otherwise 6.0 support is dropped, right?

// swift-tools-version:6.0

// ...

.package(url: "https://github.com/apple/swift-openapi-runtime", from: "1.11.0", traitsIfAvailable: []),

// ...

extension Package.Dependency {
    static func package(url: String, from version: Version, traitsIfAvailable traits: [String]) -> Package.Dependency {
        #if swift(>=6.1)
        .package(url: url, from: version, traits: Set(traits.map(Trait.init(stringLiteral:))))
        #else
        .package(url: url, from: version)
        #endif
    }
}

results in:

error: 'swift-openapi-generator': Invalid manifest (compiled with: ["/Users/mads/Library/Developer/Toolchains/swift-6.2.3-RELEASE.xctoolchain/usr/bin/swiftc", "-vfsoverlay", "/var/folders/k2/6td8s_n90hsbgj3y20fdpjnr0000gn/T/TemporaryDirectory.yc9FjO/vfs.yaml", "-L", "/Users/mads/Library/Developer/Toolchains/swift-6.2.3-RELEASE.xctoolchain/usr/lib/swift/pm/ManifestAPI", "-lPackageDescription", "-Xlinker", "-rpath", "-Xlinker", "/Users/mads/Library/Developer/Toolchains/swift-6.2.3-RELEASE.xctoolchain/usr/lib/swift/pm/ManifestAPI", "-target", "arm64-apple-macosx13.0", "-I", "/Users/mads/Library/Developer/Toolchains/swift-6.2.3-RELEASE.xctoolchain/usr/lib/swift/macosx/testing", "-L", "/Users/mads/Library/Developer/Toolchains/swift-6.2.3-RELEASE.xctoolchain/usr/lib/swift/macosx/testing", "-plugin-path", "/Users/mads/Library/Developer/Toolchains/swift-6.2.3-RELEASE.xctoolchain/usr/lib/swift/host/plugins/testing", "-sdk", "/Applications/Xcode-26.3.0-release-candidate.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk", "-F", "/Applications/Xcode-26.3.0-release-candidate.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks", "-F", "/Applications/Xcode-26.3.0-release-candidate.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/PrivateFrameworks", "-I", "/Applications/Xcode-26.3.0-release-candidate.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib", "-L", "/Applications/Xcode-26.3.0-release-candidate.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib", "-swift-version", "6", "-I", "/Users/mads/Library/Developer/Toolchains/swift-6.2.3-RELEASE.xctoolchain/usr/lib/swift/pm/ManifestAPI", "-sdk", "/Applications/Xcode-26.3.0-release-candidate.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk", "-package-description-version", "6.0.0", "/Users/mads/dev/swift-openapi-generator/Package.swift", "-o", "/var/folders/k2/6td8s_n90hsbgj3y20fdpjnr0000gn/T/TemporaryDirectory.hPwYQr/swift-openapi-generator-manifest"])
/Users/mads/dev/swift-openapi-generator/Package.swift:172:10: error: 'package(url:from:traits:)' is unavailable
170 |     static func package(url: String, from version: Version, traitsIfAvailable traits: [String]) -> Package.Dependency {
171 |         #if swift(>=6.1)
172 |         .package(url: url, from: version, traits: Set(traits.map(Trait.init(stringLiteral:))))
    |          `- error: 'package(url:from:traits:)' is unavailable
173 |         #else
174 |         .package(url: url, from: version)

PackageDescription.Package.Dependency.package:4:24: note: 'package(url:from:traits:)' was introduced in PackageDescription 6.1
2 |   class Dependency {
3 | @available(_PackageDescription 6.1)
4 |     public static func package(url: String, from version: Version, traits: Set<Package.Dependency.Trait> = [.defaults]) -> Package.Dependency  }
  |                        `- note: 'package(url:from:traits:)' was introduced in PackageDescription 6.1
5 | }
6 |

/Users/mads/dev/swift-openapi-generator/Package.swift:172:66: error: 'Trait' is unavailable
170 |     static func package(url: String, from version: Version, traitsIfAvailable traits: [String]) -> Package.Dependency {
171 |         #if swift(>=6.1)
172 |         .package(url: url, from: version, traits: Set(traits.map(Trait.init(stringLiteral:))))
    |                                                                  `- error: 'Trait' is unavailable
173 |         #else
174 |         .package(url: url, from: version)

PackageDescription.Package.Dependency.Trait:4:19: note: 'Trait' was introduced in PackageDescription 6.1
 2 |   class Dependency {
 3 | @available(_PackageDescription 6.1)
 4 |     public struct Trait : Hashable, Sendable, ExpressibleByStringLiteral {
   |                   `- note: 'Trait' was introduced in PackageDescription 6.1
 5 |     public static let defaults: Package.Dependency.Trait
 6 |     public struct Condition : Hashable, Sendable {

with

Apple Swift version 6.2.3 (swift-6.2.3-RELEASE)
Target: arm64-apple-macosx26.0
Build config: +assertions

@simonjbeaumont
Copy link
Copy Markdown
Collaborator

I left it as it was (swift-tools-version: 5.10) and it's building fine for me on macOS also, with:

% xcodebuild -version
Xcode 26.3

% swift --version
swift-driver version: 1.127.15 Apple Swift version 6.2.4 (swiftlang-6.2.4.1.4 clang-1700.6.4.2)
Target: arm64-apple-macosx26.0

Seems that bumping the minimum tools version to 6.0 is causing problems. Why don't we split that out so that you can land this patch?

@madsodgaard
Copy link
Copy Markdown
Contributor Author

@simonjbeaumont Just to make sure I understood. You were suggesting to keep 5.10 in this PR and use the #if swift to enable/disable the traits, right?

@simonjbeaumont
Copy link
Copy Markdown
Collaborator

Yes. If you're in a rush to land this PR before 6.3 is released, we can do it that way. Once 6.3 is released this workaround is moot but I'd really rather avoid multiple manifests.

@madsodgaard
Copy link
Copy Markdown
Contributor Author

@simonjbeaumont Unfortunately it does not seem that trick actually works when you build.

swift build -v --target PetstoreConsumerTestCore 2>&1 | grep "OpenAPIRuntime.build" | grep -o "\-DFullFoundation" | head -3

shows that -DFullFoundation is being passed, meaning that the trait is enabled.

This does not happen when we use multiple manifests versions, so I guess we are forced to do that.

Comment thread Package@swift-6.0.swift Outdated
@@ -0,0 +1,167 @@
// swift-tools-version:6.0
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main currently supports 5.10+, but I guess this PR drops support for 5.10 and moves to 6.0. #867 does this as well.

Do you want me to revert this to 5.10?

@simonjbeaumont
Copy link
Copy Markdown
Collaborator

@simonjbeaumont Unfortunately it does not seem that trick actually works when you build.

swift build -v --target PetstoreConsumerTestCore 2>&1 | grep "OpenAPIRuntime.build" | grep -o "\-DFullFoundation" | head -3

shows that -DFullFoundation is being passed, meaning that the trait is enabled.

This does not happen when we use multiple manifests versions, so I guess we are forced to do that.

What version did you build this on?

root@946be1992f3c:/pwd# swift --version
Swift version 6.2.4 (swift-6.2.4-RELEASE)
Target: aarch64-unknown-linux-gnu

root@946be1992f3c:/pwd# rm -rf .build && swift build -v --target PetstoreConsumerTestCore 2>&1 | grep "OpenAPIRuntime.build" | grep -o "\-DFullFoundation" | head -3

root@946be1992f3c:/pwd# echo $?
0
root@223d66ebbf84:/pwd# swift --version
Swift version 6.0.3 (swift-6.0.3-RELEASE)
Target: aarch64-unknown-linux-gnu

root@223d66ebbf84:/pwd# rm -rf .build && swift build -v --target PetstoreConsumerTestCore 2>&1 | grep "OpenAPIRuntime.build" | grep -o "\-DFullFoundation" | head -3

root@223d66ebbf84:/pwd# echo $?
0
% swift --version
swift-driver version: 1.127.15 Apple Swift version 6.2.4 (swiftlang-6.2.4.1.4 clang-1700.6.4.2)
Target: arm64-apple-macosx26.0

% rm -rf build && swift build -v --target PetstoreConsumerTestCore 2>&1 | grep "OpenAPIRuntime.build" | grep -o "\-DFullFoundation" | head -3

% echo $?
0

@madsodgaard
Copy link
Copy Markdown
Contributor Author

@simonjbeaumont Not sure if it was a typo, but in your Mac terminal you have rm -rf build instead .build.

I am seeing the issue on 6.2.4 as well.

╰─❯ swift --version
Apple Swift version 6.2.4 (swift-6.2.4-RELEASE)
Target: arm64-apple-macosx26.0
Build config: +assertions

╰─❯ rm -rf .build && swift build -v --target PetstoreConsumerTestCore 2>&1 | grep "OpenAPIRuntime.build" | grep -o "\-DFullFoundation" | head -3
-DFullFoundation

@simonjbeaumont
Copy link
Copy Markdown
Collaborator

Heh, I had removed the build directory, but... what I hadn't done (facepalm) is updated the swift-openapi-runtime dependency.

I'm very surprised this cannot be done in the package manifest since I have already linked a concrete example where we do use compiler conditionals to change behaviour. I played around some more and agree this isn't feasible. Even with some runtime checks, it seems that PackageDescription is "special":

error: PackageDescription version checks not allowed in #available(...)

Well, thanks for at least entertaining the idea. Let me kick the CI on the current state of the PR and we can go from there.

I guess this additional manifest will have a short shelf-life anyway.

@madsodgaard
Copy link
Copy Markdown
Contributor Author

@simonjbeaumont I reverted the minimum version to 5.10 and set the language mode to v5 for 6.0+, this is to match what is currently in main. And I am assuming that #867 will be merged later to upgrade 6.0+

@simonjbeaumont
Copy link
Copy Markdown
Collaborator

and set the language mode to v5 for 6.0+

Is this missing from the commit?

@madsodgaard
Copy link
Copy Markdown
Contributor Author

@simonjbeaumont 🤦 sorry, forgot to push

Comment thread Package.swift Outdated
madsodgaard and others added 2 commits March 18, 2026 11:34
Co-authored-by: Si Beaumont <simonjbeaumont@gmail.com>
@simonjbeaumont simonjbeaumont added the 🆕 semver/minor Adds new public API. label Mar 18, 2026
Comment thread Plugins/PluginsShared/PluginError.swift Outdated
Copy link
Copy Markdown
Collaborator

@simonjbeaumont simonjbeaumont left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM now, if we can get all the CI to pass.

Thanks @madsodgaard for humouring me on this one—I am very aware I led you on a wild goose chase, so thank you for trying to get it done without the additional manifest, and sorry for the extra time that investigation caused.

@madsodgaard
Copy link
Copy Markdown
Contributor Author

@simonjbeaumont No problem! Thanks for the quick feedback and turnaround:)

The remaining CI failures look Windows deamon related?

@simonjbeaumont simonjbeaumont merged commit 9ed8313 into apple:main Mar 19, 2026
97 of 99 checks passed
simonjbeaumont added a commit that referenced this pull request Mar 23, 2026
### Motivation

In #878 we split the manifest for this project so we could have the 6.1+
manifest declare a dependency on swift-openapi-runtime without default
traits to support projects that want to avoid linking the full
Foundation transitive dependency.

The consequence of this is that the newer manifest lifted the
`swift-tools-version`. There was an attempt to mitigate that by marking
the Swift language version as v5 to decouple it from moving to 6.
However, what this meant was we started getting warnings in the plugin
code because plugin targets cannot have `swiftSettings` applied to them
so they started complaining about the use of the deprecated
`PackagePlugin.Path` APIs.

We previously could not move to URL, as requested by the deprecation
warning, because we were still supporting Swift 5.10. But 5.10 dropped
out of our support window 6 months ago. We haven't been CI'ing it, but
we never lifted the tools version in the package manifest.

We can do that now, and then move to using `URL` in the plugin code,
which should get rid of the warnings.

### Modifications

Bump the minimum version of Swift to 6.0. However, we still retain a
split manifest because traits are only supported in 6.1+.

Then move to using URL instead of PackagePlugin.Path APIs.

### Result

Plugin should stop generating warnings for adopters on 6.1+.

### Test Plan

Integration tests still pass. Built locally and no longer see the
warnings.

### Related

Expect this to fix #881
simonjbeaumont added a commit to apple/swift-openapi-urlsession that referenced this pull request Apr 8, 2026
Disables the default traits for OpenAPIRuntime, so that anyone that
depends on urlsession transport, can choose disable the default. runtime
traits

Related: 
*
swift-server/swift-openapi-async-http-client#59
* apple/swift-openapi-generator#878

---------

Co-authored-by: Si Beaumont <beaumont@apple.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🆕 semver/minor Adds new public API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants