Skip to content

Commit 7d47669

Browse files
committed
Implement per target swift version selection
Swift Forums pitch thread - https://forums.swift.org/t/pitch-swiftpm-swift-language-version-per-target/71067 Add a new Swift target setting API, similar to `enable{Upcoming, Experimental}Feature`, to specify a Swift language version that should be used to build the target, if such version is not specified, fallback to the current language version determination logic. Resolves: rdar://125732014
1 parent 8df1d14 commit 7d47669

File tree

10 files changed

+192
-20
lines changed

10 files changed

+192
-20
lines changed

Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,6 @@ package final class SwiftTargetBuildDescription {
477477
package func compileArguments() throws -> [String] {
478478
var args = [String]()
479479
args += try self.buildParameters.targetTripleArgs(for: self.target)
480-
args += ["-swift-version", self.swiftVersion.rawValue]
481480

482481
// pass `-v` during verbose builds.
483482
if self.buildParameters.outputParameters.isVerbose {
@@ -579,6 +578,11 @@ package final class SwiftTargetBuildDescription {
579578
// Add arguments from declared build settings.
580579
args += try self.buildSettingsFlags()
581580

581+
// Fallback to package wide setting if there is no target specific version.
582+
if args.firstIndex(of: "-swift-version") == nil {
583+
args += ["-swift-version", self.swiftVersion.rawValue]
584+
}
585+
582586
// Add the output for the `.swiftinterface`, if requested or if library evolution has been enabled some other
583587
// way.
584588
if self.buildParameters.driverParameters.enableParseableModuleInterfaces || args.contains("-enable-library-evolution") {

Sources/PackageDescription/BuildSettings.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,23 @@ public struct SwiftSetting {
387387
return SwiftSetting(
388388
name: "interoperabilityMode", value: [mode.rawValue], condition: condition)
389389
}
390+
391+
/// Defines a `-swift-version` to pass to the
392+
/// corresponding build tool.
393+
///
394+
/// - Since: First available in PackageDescription 6.0.
395+
///
396+
/// - Parameters:
397+
/// - version: The Swift language version to use.
398+
/// - condition: A condition that restricts the application of the build setting.
399+
@available(_PackageDescription, introduced: 6.0)
400+
public static func swiftLanguageVersion(
401+
_ version: SwiftVersion,
402+
_ condition: BuildSettingCondition? = nil
403+
) -> SwiftSetting {
404+
return SwiftSetting(
405+
name: "swiftLanguageVersion", value: [.init(describing: version)], condition: condition)
406+
}
390407
}
391408

392409
/// A linker build setting.

Sources/PackageLoading/ManifestJSONParser.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,21 @@ extension TargetBuildSettingDescription.Kind {
533533
return .enableExperimentalFeature(value)
534534
case "unsafeFlags":
535535
return .unsafeFlags(values)
536+
537+
case "swiftLanguageVersion":
538+
guard let rawVersion = values.first else {
539+
throw InternalError("invalid (empty) build settings value")
540+
}
541+
542+
if values.count > 1 {
543+
throw InternalError("invalid build settings value")
544+
}
545+
546+
guard let version = SwiftLanguageVersion(string: rawVersion) else {
547+
throw InternalError("unknown swift language version: \(rawVersion)")
548+
}
549+
550+
return .swiftLanguageVersion(version)
536551
default:
537552
throw InternalError("invalid build setting \(name)")
538553
}

Sources/PackageLoading/PackageBuilder.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,17 @@ public final class PackageBuilder {
11401140
}
11411141

11421142
values = ["-enable-experimental-feature", value]
1143+
1144+
case .swiftLanguageVersion(let version):
1145+
switch setting.tool {
1146+
case .c, .cxx, .linker:
1147+
throw InternalError("only Swift supports swift language version")
1148+
1149+
case .swift:
1150+
decl = .OTHER_SWIFT_FLAGS
1151+
}
1152+
1153+
values = ["-swift-version", version.rawValue]
11431154
}
11441155

11451156
// Create an assignment for this setting.

Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
/// A namespace for target-specific build settings.
1414
public enum TargetBuildSettingDescription {
15-
1615
/// The tool for which a build setting is declared.
1716
public enum Tool: String, Codable, Hashable, CaseIterable, Sendable {
1817
case c
@@ -40,12 +39,15 @@ public enum TargetBuildSettingDescription {
4039

4140
case unsafeFlags([String])
4241

42+
case swiftLanguageVersion(SwiftLanguageVersion)
43+
4344
public var isUnsafeFlags: Bool {
4445
switch self {
4546
case .unsafeFlags(let flags):
4647
// If `.unsafeFlags` is used, but doesn't specify any flags, we treat it the same way as not specifying it.
4748
return !flags.isEmpty
48-
case .headerSearchPath, .define, .linkedLibrary, .linkedFramework, .interoperabilityMode, .enableUpcomingFeature, .enableExperimentalFeature:
49+
case .headerSearchPath, .define, .linkedLibrary, .linkedFramework, .interoperabilityMode,
50+
.enableUpcomingFeature, .enableExperimentalFeature, .swiftLanguageVersion:
4951
return false
5052
}
5153
}

Sources/PackageModel/ManifestSourceGeneration.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,12 @@ fileprivate extension SourceCodeFragment {
525525
params.append(SourceCodeFragment(from: condition))
526526
}
527527
self.init(enum: setting.kind.name, subnodes: params)
528+
case .swiftLanguageVersion(let version):
529+
params.append(SourceCodeFragment(from: version))
530+
if let condition = setting.condition {
531+
params.append(SourceCodeFragment(from: condition))
532+
}
533+
self.init(enum: setting.kind.name, subnodes: params)
528534
}
529535
}
530536
}
@@ -677,6 +683,8 @@ extension TargetBuildSettingDescription.Kind {
677683
return "enableUpcomingFeature"
678684
case .enableExperimentalFeature:
679685
return "enableExperimentalFeature"
686+
case .swiftLanguageVersion:
687+
return "swiftLanguageVersion"
680688
}
681689
}
682690
}

0 commit comments

Comments
 (0)