Skip to content

Disable traits for imported runtime#878

Open
madsodgaard wants to merge 4 commits intoapple:mainfrom
madsodgaard:traits
Open

Disable traits for imported runtime#878
madsodgaard wants to merge 4 commits intoapple:mainfrom
madsodgaard:traits

Conversation

@madsodgaard
Copy link

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
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
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
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
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
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
Author

madsodgaard commented Mar 16, 2026

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

@simonjbeaumont
Copy link
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
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
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
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
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
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.

@@ -0,0 +1,167 @@
// swift-tools-version:6.0
Copy link
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
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
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
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants