diff --git a/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift b/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift index cbb9a1d446b..7a7572aa1f0 100644 --- a/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift +++ b/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift @@ -477,7 +477,6 @@ package final class SwiftTargetBuildDescription { package func compileArguments() throws -> [String] { var args = [String]() args += try self.buildParameters.targetTripleArgs(for: self.target) - args += ["-swift-version", self.swiftVersion.rawValue] // pass `-v` during verbose builds. if self.buildParameters.outputParameters.isVerbose { @@ -579,6 +578,11 @@ package final class SwiftTargetBuildDescription { // Add arguments from declared build settings. args += try self.buildSettingsFlags() + // Fallback to package wide setting if there is no target specific version. + if args.firstIndex(of: "-swift-version") == nil { + args += ["-swift-version", self.swiftVersion.rawValue] + } + // Add the output for the `.swiftinterface`, if requested or if library evolution has been enabled some other // way. if self.buildParameters.driverParameters.enableParseableModuleInterfaces || args.contains("-enable-library-evolution") { diff --git a/Sources/PackageDescription/BuildSettings.swift b/Sources/PackageDescription/BuildSettings.swift index d28b298ec64..239f150d53f 100644 --- a/Sources/PackageDescription/BuildSettings.swift +++ b/Sources/PackageDescription/BuildSettings.swift @@ -387,6 +387,23 @@ public struct SwiftSetting { return SwiftSetting( name: "interoperabilityMode", value: [mode.rawValue], condition: condition) } + + /// Defines a `-swift-version` to pass to the + /// corresponding build tool. + /// + /// - Since: First available in PackageDescription 6.0. + /// + /// - Parameters: + /// - version: The Swift language version to use. + /// - condition: A condition that restricts the application of the build setting. + @available(_PackageDescription, introduced: 6.0) + public static func swiftLanguageVersion( + _ version: SwiftVersion, + _ condition: BuildSettingCondition? = nil + ) -> SwiftSetting { + return SwiftSetting( + name: "swiftLanguageVersion", value: [.init(describing: version)], condition: condition) + } } /// A linker build setting. diff --git a/Sources/PackageDescription/LanguageStandardSettings.swift b/Sources/PackageDescription/LanguageStandardSettings.swift index 23bf688277a..c1346f67a87 100644 --- a/Sources/PackageDescription/LanguageStandardSettings.swift +++ b/Sources/PackageDescription/LanguageStandardSettings.swift @@ -167,8 +167,25 @@ public enum SwiftVersion { @available(_PackageDescription, introduced: 5) case v5 + /// The identifier for the Swift 6 language version. + @available(_PackageDescription, introduced: 6) + case v6 + /// A user-defined value for the Swift version. /// /// The value is passed as-is to the Swift compiler's `-swift-version` flag. case version(String) } + +extension SwiftVersion: CustomStringConvertible { + public var description: String { + switch self { + case .v3: "3" + case .v4: "4" + case .v4_2: "4.2" + case .v5: "5" + case .v6: "6" + case .version(let version): version + } + } +} diff --git a/Sources/PackageDescription/PackageDescriptionSerialization.swift b/Sources/PackageDescription/PackageDescriptionSerialization.swift index a16cc995b81..ad852b9d859 100644 --- a/Sources/PackageDescription/PackageDescriptionSerialization.swift +++ b/Sources/PackageDescription/PackageDescriptionSerialization.swift @@ -99,6 +99,7 @@ enum Serialization { case v4 case v4_2 case v5 + case v6 case version(String) } diff --git a/Sources/PackageDescription/PackageDescriptionSerializationConversion.swift b/Sources/PackageDescription/PackageDescriptionSerializationConversion.swift index 26459c345a9..e85d9c0cd1f 100644 --- a/Sources/PackageDescription/PackageDescriptionSerializationConversion.swift +++ b/Sources/PackageDescription/PackageDescriptionSerializationConversion.swift @@ -112,6 +112,7 @@ extension Serialization.SwiftVersion { case .v4: self = .v4 case .v4_2: self = .v4_2 case .v5: self = .v5 + case .v6: self = .v6 case .version(let version): self = .version(version) } } diff --git a/Sources/PackageLoading/ManifestJSONParser.swift b/Sources/PackageLoading/ManifestJSONParser.swift index ad1322668ea..564e5991982 100644 --- a/Sources/PackageLoading/ManifestJSONParser.swift +++ b/Sources/PackageLoading/ManifestJSONParser.swift @@ -150,6 +150,7 @@ enum ManifestJSONParser { case .v4: languageVersionString = "4" case .v4_2: languageVersionString = "4.2" case .v5: languageVersionString = "5" + case .v6: languageVersionString = "6" case .version(let version): languageVersionString = version } guard let languageVersion = SwiftLanguageVersion(string: languageVersionString) else { @@ -533,6 +534,21 @@ extension TargetBuildSettingDescription.Kind { return .enableExperimentalFeature(value) case "unsafeFlags": return .unsafeFlags(values) + + case "swiftLanguageVersion": + guard let rawVersion = values.first else { + throw InternalError("invalid (empty) build settings value") + } + + if values.count > 1 { + throw InternalError("invalid build settings value") + } + + guard let version = SwiftLanguageVersion(string: rawVersion) else { + throw InternalError("unknown swift language version: \(rawVersion)") + } + + return .swiftLanguageVersion(version) default: throw InternalError("invalid build setting \(name)") } diff --git a/Sources/PackageLoading/PackageBuilder.swift b/Sources/PackageLoading/PackageBuilder.swift index a1c13034e67..c81ccb1fadd 100644 --- a/Sources/PackageLoading/PackageBuilder.swift +++ b/Sources/PackageLoading/PackageBuilder.swift @@ -1140,6 +1140,17 @@ public final class PackageBuilder { } values = ["-enable-experimental-feature", value] + + case .swiftLanguageVersion(let version): + switch setting.tool { + case .c, .cxx, .linker: + throw InternalError("only Swift supports swift language version") + + case .swift: + decl = .OTHER_SWIFT_FLAGS + } + + values = ["-swift-version", version.rawValue] } // Create an assignment for this setting. diff --git a/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift b/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift index a0eb9be2575..e535c1c9b16 100644 --- a/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift +++ b/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift @@ -12,7 +12,6 @@ /// A namespace for target-specific build settings. public enum TargetBuildSettingDescription { - /// The tool for which a build setting is declared. public enum Tool: String, Codable, Hashable, CaseIterable, Sendable { case c @@ -40,12 +39,15 @@ public enum TargetBuildSettingDescription { case unsafeFlags([String]) + case swiftLanguageVersion(SwiftLanguageVersion) + public var isUnsafeFlags: Bool { switch self { case .unsafeFlags(let flags): // If `.unsafeFlags` is used, but doesn't specify any flags, we treat it the same way as not specifying it. return !flags.isEmpty - case .headerSearchPath, .define, .linkedLibrary, .linkedFramework, .interoperabilityMode, .enableUpcomingFeature, .enableExperimentalFeature: + case .headerSearchPath, .define, .linkedLibrary, .linkedFramework, .interoperabilityMode, + .enableUpcomingFeature, .enableExperimentalFeature, .swiftLanguageVersion: return false } } diff --git a/Sources/PackageModel/ManifestSourceGeneration.swift b/Sources/PackageModel/ManifestSourceGeneration.swift index 8d630deb9cc..f2a31e932fd 100644 --- a/Sources/PackageModel/ManifestSourceGeneration.swift +++ b/Sources/PackageModel/ManifestSourceGeneration.swift @@ -525,6 +525,12 @@ fileprivate extension SourceCodeFragment { params.append(SourceCodeFragment(from: condition)) } self.init(enum: setting.kind.name, subnodes: params) + case .swiftLanguageVersion(let version): + params.append(SourceCodeFragment(from: version)) + if let condition = setting.condition { + params.append(SourceCodeFragment(from: condition)) + } + self.init(enum: setting.kind.name, subnodes: params) } } } @@ -677,6 +683,8 @@ extension TargetBuildSettingDescription.Kind { return "enableUpcomingFeature" case .enableExperimentalFeature: return "enableExperimentalFeature" + case .swiftLanguageVersion: + return "swiftLanguageVersion" } } } diff --git a/Sources/PackageModel/SwiftLanguageVersion.swift b/Sources/PackageModel/SwiftLanguageVersion.swift index 2aabc03c138..e7a1870c3a6 100644 --- a/Sources/PackageModel/SwiftLanguageVersion.swift +++ b/Sources/PackageModel/SwiftLanguageVersion.swift @@ -31,9 +31,12 @@ public struct SwiftLanguageVersion: Hashable, Sendable { /// Swift language version 5. public static let v5 = SwiftLanguageVersion(uncheckedString: "5") + /// Swift language version 6. + public static let v6 = SwiftLanguageVersion(uncheckedString: "6") + /// The list of known Swift language versions. public static let knownSwiftLanguageVersions = [ - v3, v4, v4_2, v5, + v3, v4, v4_2, v5, v6 ] /// The raw value of the language version. diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index a68d4429e4d..0fbbab8b6c9 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -769,7 +769,6 @@ final class BuildPlanTests: XCTestCase { XCTAssertMatch( exe, [ - "-swift-version", "4", "-enable-batch-mode", "-Onone", "-enable-testing", @@ -778,6 +777,7 @@ final class BuildPlanTests: XCTestCase { "-DDEBUG", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, + "-swift-version", "4", "-g", .anySequence, ] @@ -787,7 +787,6 @@ final class BuildPlanTests: XCTestCase { XCTAssertMatch( lib, [ - "-swift-version", "4", "-enable-batch-mode", "-Onone", "-enable-testing", @@ -796,6 +795,7 @@ final class BuildPlanTests: XCTestCase { "-DDEBUG", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, + "-swift-version", "4", "-g", .anySequence, ] @@ -1205,12 +1205,12 @@ final class BuildPlanTests: XCTestCase { XCTAssertMatch( exe, [ - "-swift-version", "4", "-O", .equal(self.j), "-DSWIFT_PACKAGE", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, + "-swift-version", "4", "-g", ] ) @@ -1296,12 +1296,12 @@ final class BuildPlanTests: XCTestCase { XCTAssertMatch( exe, [ - "-swift-version", "4", "-O", .equal(self.j), "-DSWIFT_PACKAGE", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, + "-swift-version", "4", "-g", ] ) @@ -1795,7 +1795,6 @@ final class BuildPlanTests: XCTestCase { exe, [ .anySequence, - "-swift-version", "4", "-enable-batch-mode", "-Onone", "-enable-testing", @@ -1807,6 +1806,7 @@ final class BuildPlanTests: XCTestCase { "-Xcc", "-I", "-Xcc", "\(Pkg.appending(components: "Sources", "lib", "include"))", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, + "-swift-version", "4", "-g", .anySequence, ] @@ -2017,7 +2017,6 @@ final class BuildPlanTests: XCTestCase { foo, [ .anySequence, - "-swift-version", "4", "-enable-batch-mode", "-Onone", "-enable-testing", @@ -2026,6 +2025,7 @@ final class BuildPlanTests: XCTestCase { "-DDEBUG", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, + "-swift-version", "4", "-g", .anySequence, ] @@ -2036,7 +2036,6 @@ final class BuildPlanTests: XCTestCase { fooTests, [ .anySequence, - "-swift-version", "4", "-enable-batch-mode", "-Onone", "-enable-testing", @@ -2045,6 +2044,7 @@ final class BuildPlanTests: XCTestCase { "-DDEBUG", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, + "-swift-version", "4", "-g", .anySequence, ] @@ -2149,12 +2149,12 @@ final class BuildPlanTests: XCTestCase { exe, [ .anySequence, - "-swift-version", "4", "-O", .equal(self.j), "-DSWIFT_PACKAGE", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, + "-swift-version", "4", "-g", .anySequence, ] @@ -2510,7 +2510,6 @@ final class BuildPlanTests: XCTestCase { XCTAssertMatch( try result.target(for: "exe").swiftTarget().compileArguments(), [ - "-swift-version", "4", "-enable-batch-mode", "-Onone", "-enable-testing", @@ -2520,6 +2519,7 @@ final class BuildPlanTests: XCTestCase { "-Xcc", "-fmodule-map-file=\(Clibgit.appending(components: "module.modulemap"))", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, + "-swift-version", "4", "-g", .anySequence, ] @@ -2810,7 +2810,6 @@ final class BuildPlanTests: XCTestCase { XCTAssertMatch( exe, [ - "-swift-version", "4", "-enable-batch-mode", "-Onone", "-enable-testing", @@ -2819,6 +2818,7 @@ final class BuildPlanTests: XCTestCase { "-DDEBUG", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, + "-swift-version", "4", "-g", .anySequence, ] @@ -2828,7 +2828,6 @@ final class BuildPlanTests: XCTestCase { XCTAssertMatch( lib, [ - "-swift-version", "4", "-enable-batch-mode", "-Onone", "-enable-testing", @@ -2837,6 +2836,7 @@ final class BuildPlanTests: XCTestCase { "-DDEBUG", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, + "-swift-version", "4", "-g", .anySequence, ] @@ -3447,7 +3447,6 @@ final class BuildPlanTests: XCTestCase { let exe = try result.target(for: "exe").swiftTarget().compileArguments() XCTAssertMatch(exe, [ - "-swift-version", "4", "-enable-batch-mode", "-Onone", "-enable-testing", @@ -3457,6 +3456,7 @@ final class BuildPlanTests: XCTestCase { "-Xcc", "-I", "-Xcc", "\(Pkg.appending(components: "Sources", "lib", "include"))", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, + "-swift-version", "4", "-g", "-use-ld=lld", "-Xcc", "-gdwarf", @@ -3954,6 +3954,16 @@ final class BuildPlanTests: XCTestCase { kind: .interoperabilityMode(.Cxx), condition: .init(platformNames: ["macos"]) ), + .init( + tool: .swift, + kind: .swiftLanguageVersion(.v4), + condition: .init(platformNames: ["macos"]) + ), + .init( + tool: .swift, + kind: .swiftLanguageVersion(.v5), + condition: .init(platformNames: ["linux"]) + ), .init(tool: .linker, kind: .linkedLibrary("sqlite3")), .init( tool: .linker, @@ -3984,6 +3994,8 @@ final class BuildPlanTests: XCTestCase { name: "t1", settings: [ .init(tool: .swift, kind: .define("DEP")), + .init(tool: .swift, kind: .swiftLanguageVersion(.v4), condition: .init(platformNames: ["linux"])), + .init(tool: .swift, kind: .swiftLanguageVersion(.v5), condition: .init(platformNames: ["macos"])), .init(tool: .linker, kind: .linkedLibrary("libz")), ] ), @@ -4018,6 +4030,7 @@ final class BuildPlanTests: XCTestCase { let dep = try result.target(for: "t1").swiftTarget().compileArguments() XCTAssertMatch(dep, [.anySequence, "-DDEP", .anySequence]) + XCTAssertMatch(dep, [.anySequence, "-swift-version", "4", .anySequence]) let cbar = try result.target(for: "cbar").clangTarget().basicArguments(isCXX: false) XCTAssertMatch( @@ -4048,6 +4061,7 @@ final class BuildPlanTests: XCTestCase { "-cxx-interoperability-mode=default", "-Xcc", "-std=c++17", "-enable-upcoming-feature", "BestFeature", + "-swift-version", "5", "-g", "-Xcc", "-g", "-Xcc", "-fno-omit-frame-pointer", @@ -4056,7 +4070,7 @@ final class BuildPlanTests: XCTestCase { ) let exe = try result.target(for: "exe").swiftTarget().compileArguments() - XCTAssertMatch(exe, [.anySequence, "-DFOO", "-g", "-Xcc", "-g", "-Xcc", "-fno-omit-frame-pointer", .end]) + XCTAssertMatch(exe, [.anySequence, "-DFOO", "-swift-version", "5", "-g", "-Xcc", "-g", "-Xcc", "-fno-omit-frame-pointer", .end]) let linkExe = try result.buildProduct(for: "exe").linkArguments() XCTAssertMatch(linkExe, [.anySequence, "-lsqlite3", "-llibz", "-Ilfoo", "-L", "lbar", "-g", .end]) @@ -4113,6 +4127,7 @@ final class BuildPlanTests: XCTestCase { "-Xcc", "-std=c++17", "-enable-upcoming-feature", "BestFeature", + "-swift-version", "5", "-g", "-Xcc", "-g", "-Xcc", "-fomit-frame-pointer", @@ -4121,7 +4136,7 @@ final class BuildPlanTests: XCTestCase { ) let exe = try result.target(for: "exe").swiftTarget().compileArguments() - XCTAssertMatch(exe, [.anySequence, "-DFOO", "-g", "-Xcc", "-g", "-Xcc", "-fomit-frame-pointer", .end]) + XCTAssertMatch(exe, [.anySequence, "-DFOO", "-swift-version", "5", "-g", "-Xcc", "-g", "-Xcc", "-fomit-frame-pointer", .end]) } // omit frame pointers explicitly set to false @@ -4169,6 +4184,7 @@ final class BuildPlanTests: XCTestCase { "-Xcc", "-std=c++17", "-enable-upcoming-feature", "BestFeature", + "-swift-version", "5", "-g", "-Xcc", "-g", "-Xcc", "-fno-omit-frame-pointer", @@ -4177,7 +4193,7 @@ final class BuildPlanTests: XCTestCase { ) let exe = try result.target(for: "exe").swiftTarget().compileArguments() - XCTAssertMatch(exe, [.anySequence, "-DFOO", "-g", "-Xcc", "-g", "-Xcc", "-fno-omit-frame-pointer", .end]) + XCTAssertMatch(exe, [.anySequence, "-DFOO", "-swift-version", "5", "-g", "-Xcc", "-g", "-Xcc", "-fno-omit-frame-pointer", .end]) } do { @@ -4212,6 +4228,7 @@ final class BuildPlanTests: XCTestCase { "-Xcc", "-std=c++17", "-enable-upcoming-feature", "BestFeature", "-enable-upcoming-feature", "WorstFeature", + "-swift-version", "5", "-g", "-Xcc", "-g", .end, @@ -4226,6 +4243,7 @@ final class BuildPlanTests: XCTestCase { "-DFOO", "-cxx-interoperability-mode=default", "-Xcc", "-std=c++17", + "-swift-version", "4", "-g", "-Xcc", "-g", .end, diff --git a/Tests/BuildTests/CrossCompilationBuildPlanTests.swift b/Tests/BuildTests/CrossCompilationBuildPlanTests.swift index 028ea94f3cd..65ac52d9076 100644 --- a/Tests/BuildTests/CrossCompilationBuildPlanTests.swift +++ b/Tests/BuildTests/CrossCompilationBuildPlanTests.swift @@ -165,12 +165,12 @@ final class CrossCompilationBuildPlanTests: XCTestCase { XCTAssertMatch( exe, [ - "-swift-version", "4", "-enable-batch-mode", "-Onone", "-enable-testing", + "-enable-batch-mode", "-Onone", "-enable-testing", "-j3", "-DSWIFT_PACKAGE", "-DDEBUG", "-Xcc", "-fmodule-map-file=\(buildPath.appending(components: "lib.build", "module.modulemap"))", "-Xcc", "-I", "-Xcc", "\(pkgPath.appending(components: "Sources", "lib", "include"))", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, - "-g", .anySequence, + "-swift-version", "4", "-g", .anySequence, ] ) diff --git a/Tests/PackageLoadingTests/PackageBuilderTests.swift b/Tests/PackageLoadingTests/PackageBuilderTests.swift index 587439049b1..4b24f5779bf 100644 --- a/Tests/PackageLoadingTests/PackageBuilderTests.swift +++ b/Tests/PackageLoadingTests/PackageBuilderTests.swift @@ -3022,6 +3022,69 @@ final class PackageBuilderTests: XCTestCase { } } } + + func testSwiftLanguageVesionPerTarget() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/foo/foo.swift", + "/Sources/bar/bar.swift" + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + toolsVersion: .v5, + targets: [ + try TargetDescription( + name: "foo", + settings: [ + .init(tool: .swift, kind: .swiftLanguageVersion(.v5)) + ] + ), + try TargetDescription( + name: "bar", + settings: [ + .init(tool: .swift, kind: .swiftLanguageVersion(.v3), condition: .init(platformNames: ["linux"])), + .init(tool: .swift, kind: .swiftLanguageVersion(.v4), condition: .init(platformNames: ["macos"], config: "debug")) + ] + ), + ] + ) + + PackageBuilderTester(manifest, in: fs) { package, _ in + package.checkModule("foo") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + XCTAssertEqual(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS), ["-swift-version", "5"]) + + let macosReleaseScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .release) + ) + XCTAssertEqual(macosReleaseScope.evaluate(.OTHER_SWIFT_FLAGS), ["-swift-version", "5"]) + } + + package.checkModule("bar") { package in + let linuxDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .linux, configuration: .debug) + ) + XCTAssertEqual(linuxDebugScope.evaluate(.OTHER_SWIFT_FLAGS), ["-swift-version", "3"]) + + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + XCTAssertEqual(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS), ["-swift-version", "4"]) + + let macosReleaseScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .release) + ) + XCTAssertEqual(macosReleaseScope.evaluate(.OTHER_SWIFT_FLAGS), []) + } + } + } } final class PackageBuilderTester { diff --git a/Tests/WorkspaceTests/ManifestSourceGenerationTests.swift b/Tests/WorkspaceTests/ManifestSourceGenerationTests.swift index 88652873d23..a1643f75595 100644 --- a/Tests/WorkspaceTests/ManifestSourceGenerationTests.swift +++ b/Tests/WorkspaceTests/ManifestSourceGenerationTests.swift @@ -589,4 +589,38 @@ class ManifestSourceGenerationTests: XCTestCase { let contents = try manifest.generateManifestFileContents(packageDirectory: manifest.path.parentDirectory) try await testManifestWritingRoundTrip(manifestContents: contents, toolsVersion: .v5_9) } + + func testManifestGenerationWithSwiftLanguageVersion() async throws { + let manifest = Manifest.createRootManifest( + displayName: "pkg", + path: "/pkg", + toolsVersion: .v6_0, + dependencies: [], + targets: [ + try TargetDescription( + name: "v5", + type: .executable, + settings: [ + .init(tool: .swift, kind: .swiftLanguageVersion(.v6)) + ] + ), + try TargetDescription( + name: "custom", + type: .executable, + settings: [ + .init(tool: .swift, kind: .swiftLanguageVersion(.init(string: "5.10")!)) + ] + ), + try TargetDescription( + name: "conditional", + type: .executable, + settings: [ + .init(tool: .swift, kind: .swiftLanguageVersion(.v5), condition: .init(platformNames: ["linux"])), + .init(tool: .swift, kind: .swiftLanguageVersion(.v4), condition: .init(platformNames: ["macos"], config: "debug")) + ] + ) + ]) + let contents = try manifest.generateManifestFileContents(packageDirectory: manifest.path.parentDirectory) + try await testManifestWritingRoundTrip(manifestContents: contents, toolsVersion: .v6_0) + } }