Skip to content

Implement per target swift version selection #7439

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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") {
Expand Down
17 changes: 17 additions & 0 deletions Sources/PackageDescription/BuildSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
17 changes: 17 additions & 0 deletions Sources/PackageDescription/LanguageStandardSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ enum Serialization {
case v4
case v4_2
case v5
case v6
case version(String)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
16 changes: 16 additions & 0 deletions Sources/PackageLoading/ManifestJSONParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)")
}
Expand Down
11 changes: 11 additions & 0 deletions Sources/PackageLoading/PackageBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
}
Expand Down
8 changes: 8 additions & 0 deletions Sources/PackageModel/ManifestSourceGeneration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
Expand Down Expand Up @@ -677,6 +683,8 @@ extension TargetBuildSettingDescription.Kind {
return "enableUpcomingFeature"
case .enableExperimentalFeature:
return "enableExperimentalFeature"
case .swiftLanguageVersion:
return "swiftLanguageVersion"
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion Sources/PackageModel/SwiftLanguageVersion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading