Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 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
6 changes: 6 additions & 0 deletions Sources/CoreCommands/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,12 @@ public struct BuildOptions: ParsableArguments {
)
public var swiftSDKSelector: String?

@Option(
name: .customLong("experimental-swift-sdk-alias"),
help: "Alias for a compatible Swift SDK to build with."
)
public var swiftSDKAlias: String?

/// Which compile-time sanitizers should be enabled.
@Option(
name: .customLong("sanitize"),
Expand Down
9 changes: 8 additions & 1 deletion Sources/CoreCommands/SwiftCommandState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,13 @@ public final class SwiftCommandState {
outputHandler: { print($0.description) }
)

let swiftSDKSelector = if let swiftSDKAliasString = self.options.build.swiftSDKAlias {
try SwiftToolchainVersion(toolchain: hostToolchain, fileSystem: self.fileSystem)
.idForSwiftSDK(aliasString: swiftSDKAliasString)
} else {
self.options.build.swiftSDKSelector ?? self.options.build.deprecatedSwiftSDKSelector
}

swiftSDK = try SwiftSDK.deriveTargetSwiftSDK(
hostSwiftSDK: hostSwiftSDK,
hostTriple: hostToolchain.targetTriple,
Expand All @@ -953,7 +960,7 @@ public final class SwiftCommandState {
customCompileTriple: self.options.build.customCompileTriple,
customCompileToolchain: self.options.build.customCompileToolchain,
customCompileSDK: self.options.build.customCompileSDK,
swiftSDKSelector: self.options.build.swiftSDKSelector ?? self.options.build.deprecatedSwiftSDKSelector,
swiftSDKSelector: swiftSDKSelector,
architectures: self.options.build.architectures,
store: store,
observabilityScope: self.observabilityScope,
Expand Down
2 changes: 2 additions & 0 deletions Sources/PackageModel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,11 @@ add_library(PackageModel
SupportedLanguageExtension.swift
SwiftLanguageVersion.swift
SwiftSDKs/SwiftSDK.swift
SwiftSDKs/SwiftSDKAlias.swift
SwiftSDKs/SwiftSDKConfigurationStore.swift
SwiftSDKs/SwiftSDKBundle.swift
SwiftSDKs/SwiftSDKBundleStore.swift
SwiftToolchainVersion.swift
Toolchain.swift
ToolchainConfiguration.swift
Toolchain+SupportedFeatures.swift
Expand Down
92 changes: 92 additions & 0 deletions Sources/PackageModel/SwiftSDKs/SwiftSDKAlias.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

package struct SwiftSDKAlias {
init?(_ string: String) {
guard let kind = Kind(rawValue: string) else { return nil }
self.kind = kind
}

enum Kind: String, CaseIterable {
case staticLinux = "static-linux"
case wasi = "wasi"
case wasiEmbedded = "embedded-wasi"

var urlFileComponent: String {
switch self {
case .staticLinux, .wasi:
return self.rawValue
case .wasiEmbedded:
return Self.wasi.rawValue
}
}

var idComponent: String {
self.rawValue
}

var urlDirComponent: String {
switch self {
case .staticLinux:
"static-sdk"
case .wasi, .wasiEmbedded:
"wasi"
}
}
}

struct Version: CustomStringConvertible {
let rawValue = "0.0.1"

var description: String { self.rawValue }
}

let kind: Kind
let defaultVersion = Version()

var urlFileComponent: String {
"\(self.kind.urlFileComponent)-\(self.defaultVersion.rawValue)"
}
}

extension SwiftToolchainVersion {
package func urlForSwiftSDK(aliasString: String) throws -> String {
guard let swiftSDKAlias = SwiftSDKAlias(aliasString) else {
throw Error.unknownSwiftSDKAlias(aliasString)
}

return """
https://download.swift.org/\(
self.branch
)/\(
swiftSDKAlias.kind.urlDirComponent
)/\(
self.tag
)/\(
self.tag
)_\(swiftSDKAlias.urlFileComponent).artifactbundle.tar.gz
"""
}

package func idForSwiftSDK(aliasString: String) throws -> String {
guard let swiftSDKAlias = SwiftSDKAlias(aliasString) else {
throw Error.unknownSwiftSDKAlias(aliasString)
}

switch swiftSDKAlias.kind {
case .staticLinux:
return "\(self.tag)_\(swiftSDKAlias.kind.idComponent)-\(swiftSDKAlias.defaultVersion)"
case .wasi, .wasiEmbedded:
return "\(self.tag.replacing("swift-", with: ""))-wasm32-\(swiftSDKAlias.kind.idComponent)"
}
}
}
152 changes: 152 additions & 0 deletions Sources/PackageModel/SwiftToolchainVersion.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import Basics
import class Foundation.JSONDecoder
import struct Foundation.URL

package struct SwiftToolchainVersion: Equatable, Decodable {
package enum Error: Swift.Error, Equatable, CustomStringConvertible {
case versionMetadataNotFound(AbsolutePath)
case unknownSwiftSDKAlias(String)

package var description: String {
switch self {
case .versionMetadataNotFound(let absolutePath):
"""
Toolchain version metadata file not found at path `\(absolutePath.pathString)`. \
Install a newer version of the Swift toolchain that includes this file.
"""
case .unknownSwiftSDKAlias(let string):
"""
Unknown alias for a Swift SDK: `\(string)`. Supported aliases: \(
SwiftSDKAlias.Kind.allCases.map { "`\($0.rawValue)`" }.joined(separator: ", ")
).
"""
}
}
}

package init(
tag: String,
branch: String,
architecture: SwiftToolchainVersion.Architecture,
platform: SwiftToolchainVersion.Platform
) {
self.tag = tag
self.branch = branch
self.architecture = architecture
self.platform = platform
}

/// Since triples don't encode the platform, we use platform identifiers
/// that match swift.org toolchain distribution names.
package enum Platform: String, Decodable {
case macOS
case ubuntu2004
case ubuntu2204
case ubuntu2404
case debian12
case amazonLinux2
case fedora39
case fedora41
case ubi9

var urlDirComponent: String {
switch self {
case .macOS:
"xcode"
case .ubuntu2004:
"ubuntu2004"
case .ubuntu2204:
"ubuntu2204"
case .ubuntu2404:
"ubuntu2404"
case .debian12:
"debian12"
case .amazonLinux2:
"amazonlinux2"
case .fedora39:
"fedora39"
case .fedora41:
"fedora41"
case .ubi9:
"ubi9"
}
}

var urlFileComponent: String {
switch self {
case .macOS:
"osx"
case .ubuntu2004:
"ubuntu20.04"
case .ubuntu2204:
"ubuntu22.04"
case .ubuntu2404:
"ubuntu24.04"
case .debian12:
"debian12"
case .amazonLinux2:
"amazonlinux2"
case .fedora39:
"fedora39"
case .fedora41:
"fedora41"
case .ubi9:
"ubi9"
}
}
}

package enum Architecture: String, Decodable {
case aarch64
case x86_64

var urlFileComponent: String {
switch self {
case .aarch64:
"-aarch64"
case .x86_64:
""
}
}
}

/// A Git tag from which this toolchain was built.
package let tag: String

/// Branch from which this toolchain was built.
package let branch: String

/// CPU architecture on which this toolchain runs.
package let architecture: Architecture

/// Platform identifier on which this toolchain runs.
package let platform: Platform

package init(toolchain: some Toolchain, fileSystem: any FileSystem) throws {
let versionMetadataPath = try toolchain.swiftCompilerPath.parentDirectory.parentDirectory.appending(
RelativePath(validating: "lib/swift/version.json")
)
guard fileSystem.exists(versionMetadataPath) else {
throw Error.versionMetadataNotFound(versionMetadataPath)
}

self = try JSONDecoder().decode(
path: versionMetadataPath,
fileSystem: fileSystem,
as: Self.self
)
}
}

8 changes: 4 additions & 4 deletions Sources/SwiftSDKCommand/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ add_library(SwiftSDKCommand
Configuration/ResetConfiguration.swift
Configuration/SetConfiguration.swift
Configuration/ShowConfiguration.swift
ConfigureSwiftSDK.swift
SwiftSDKConfigure.swift
SwiftSDKSubcommand.swift
InstallSwiftSDK.swift
ListSwiftSDKs.swift
RemoveSwiftSDK.swift
SwiftSDKInstall.swift
SwiftSDKList.swift
SwiftSDKRemove.swift
SwiftSDKCommand.swift)
target_link_libraries(SwiftSDKCommand PUBLIC
ArgumentParser
Expand Down
10 changes: 5 additions & 5 deletions Sources/SwiftSDKCommand/SwiftSDKCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2022-2023 Apple Inc. and the Swift project authors
// Copyright (c) 2022-2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
Expand All @@ -20,11 +20,11 @@ package struct SwiftSDKCommand: AsyncParsableCommand {
abstract: "Perform operations on Swift SDKs.",
version: SwiftVersion.current.completeDisplayString,
subcommands: [
ConfigureSwiftSDK.self,
SwiftSDKConfigure.self,
DeprecatedSwiftSDKConfigurationCommand.self,
InstallSwiftSDK.self,
ListSwiftSDKs.self,
RemoveSwiftSDK.self,
SwiftSDKInstall.self,
SwiftSDKList.self,
SwiftSDKRemove.self,
],
helpNames: [.short, .long, .customLong("help", withSingleDash: true)]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Copyright (c) 2023-2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
Expand All @@ -18,7 +18,7 @@ import PackageModel

import var TSCBasic.stdoutStream

struct ConfigureSwiftSDK: AsyncParsableCommand {
struct SwiftSDKConfigure: AsyncParsableCommand {
static let configuration = CommandConfiguration(
commandName: "configure",
abstract: """
Expand Down
Loading