From 0756787dfaf61276be03803e1792dfdb42100187 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Thu, 4 Dec 2025 09:09:22 -0500 Subject: [PATCH 01/18] Swift SDK for WASM using the run destination The client can provide a Swift SDK manifest path along with a triple in the run destination to synthesize a Swift Build SDK. This serves as a fallback for cases where Swift Build cannot match an SDK for it. Note that in this first implementation the platform is hard coded to webassembly, and so only SDK's that align with WASM, such as static linking of compiler runtime pieces, and some Unix semantics will work. --- Sources/SWBCore/SDKRegistry.swift | 108 +++++++++++++++++- Sources/SWBCore/Settings/Settings.swift | 2 +- Sources/SWBCore/SwiftSDK.swift | 52 +++++++-- Sources/SWBProtocol/MessageSupport.swift | 6 +- Sources/SWBUniversalPlatform/Specs/Ld.xcspec | 31 ++++- .../Specs/WebAssembly.xcspec | 6 + Sources/SwiftBuild/SWBBuildParameters.swift | 8 +- .../SwiftBuild/SWBBuildServiceSession.swift | 2 +- 8 files changed, 188 insertions(+), 27 deletions(-) diff --git a/Sources/SWBCore/SDKRegistry.swift b/Sources/SWBCore/SDKRegistry.swift index 3a8dc465..40082e8c 100644 --- a/Sources/SWBCore/SDKRegistry.swift +++ b/Sources/SWBCore/SDKRegistry.swift @@ -997,12 +997,15 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send // Construct the SDK and add it to the registry. let sdk = SDK(canonicalName, canonicalNameComponents: try? parseSDKName(canonicalName), aliases, cohortPlatforms, displayName, path, version, productBuildVersion, defaultSettings, overrideSettings, variants, defaultDeploymentTarget, defaultVariant, (headerSearchPaths, frameworkSearchPaths, librarySearchPaths), directoryMacros.elements, isBaseSDK, fallbackSettingConditionValues, toolchains, versionMap, maximumDeploymentTarget) - if let duplicate = sdksByCanonicalName[canonicalName] { - delegate.error(path, "SDK '\(canonicalName)' already registered from \(duplicate.path.str)") + + platform?.registerSDK(sdk) + + if let duplicate = sdksByCanonicalName[sdk.canonicalName] { + delegate.error(path, "SDK '\(sdk.canonicalName)' already registered from \(duplicate.path.str)") return nil } - sdksByCanonicalName[canonicalName] = sdk + sdksByCanonicalName[sdk.canonicalName] = sdk for alias in sdk.aliases { self.sdksByAlias[alias] = (self.sdksByAlias[alias] ?? []) + [sdk] @@ -1011,8 +1014,6 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send sdksByPath[path] = sdk sdksByPath[pathResolved] = sdk - platform?.registerSDK(sdk) - return sdk } @@ -1111,8 +1112,103 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send } } - // Xcode has special logic so that if there's no match here, and we'e *not* looking for a suffixed SDK, but we have an suffixed SDK which would otherwise match, then we use that. c.f. But we haven't needed that logic yet in Swift Build, so maybe we never will. + // Let's check the active run destination to see if there's an SDK path that we should be using + if matchedSDK == nil, + let sdkManifestPath = activeRunDestination?.sdkManiftestPath, + let triple = activeRunDestination?.triple, + case let llvmTriple = try LLVMTriple(triple) { + + // TODO choose the platform based on the triple, and fallback to a default one in the default case + guard let platform = delegate.platformRegistry?.lookup(name: "webassembly") else { + return nil + } + + let host = hostOperatingSystem + + // Don't allow re-registering the same SDK + if let existing = sdksByCanonicalName[sdkManifestPath] { + return existing + } + if let swiftSDK = try SwiftSDK(identifier: sdkManifestPath, version: "1.0.0", path: Path(sdkManifestPath), fs: localFS) { + let defaultProperties: [String: PropertyListItem] = [ + "SDK_STAT_CACHE_ENABLE": "NO", + + "GENERATE_TEXT_BASED_STUBS": "NO", + "GENERATE_INTERMEDIATE_TEXT_BASED_STUBS": "NO", + + // TODO check how this impacts operation on Windows + "CHOWN": "/usr/bin/chown", + + // TODO are these going to be appropriate for all kinds of SDK's? + // SwiftSDK _could_ have tool entries for these, so use them if they are available + "LIBTOOL": .plString(host.imageFormat.executableName(basename: "llvm-lib")), + "AR": .plString(host.imageFormat.executableName(basename: "llvm-ar")), + ] + + for (sdkTriple, tripleProperties) in swiftSDK.targetTriples { + guard triple == sdkTriple else { + continue + } + + let toolsets = try tripleProperties.loadToolsets(sdk: swiftSDK, fs: localFS) + + let sysroot = swiftSDK.path.join(tripleProperties.sdkRootPath) + + // TODO support dynamic resources path + let swiftResourceDir = swiftSDK.path.join(tripleProperties.swiftStaticResourcesPath) + let clangResourceDir = swiftSDK.path.join(tripleProperties.clangStaticResourcesPath) + + let tripleSystem = llvmTriple.system + (llvmTriple.systemVersion?.description ?? "") + + // TODO handle tripleProperties.toolSearchPaths + + let extraSwiftCompilerSettings = Array(toolsets.map( { $0.swiftCompiler?.extraCLIOptions ?? [] }).flatMap( { $0 })) + let headerSearchPaths: [PropertyListItem] = ["$(inherited)"] + (tripleProperties.includeSearchPaths ?? []).map( { PropertyListItem.plString($0) } ) + let librarySearchPaths: [PropertyListItem] = ["$(inherited)"] + (tripleProperties.librarySearchPaths ?? []).map( { PropertyListItem.plString($0) } ) + + let sdk = registerSDK(sysroot, sysroot, platform, .plDict([ + "Type": .plString("SDK"), + "Version": .plString(swiftSDK.version), + "CanonicalName": .plString(swiftSDK.identifier), + "Aliases": [], + "IsBaseSDK": .plBool(true), + "DefaultProperties": .plDict([ + "PLATFORM_NAME": .plString(platform.name), + ].merging(defaultProperties, uniquingKeysWith: { _, new in new })), + "CustomProperties": .plDict([ + "LIBRARY_SEARCH_PATHS": .plArray(librarySearchPaths), + "HEADER_SEARCH_PATHS": .plArray(headerSearchPaths), + "OTHER_SWIFT_FLAGS": .plArray(["$(inherited)"] + extraSwiftCompilerSettings.map( {.plString($0)} )), + "SWIFTC_RESOURCE_DIR": .plString(swiftResourceDir.str), // Resource dir for linking Swift + "SWIFT_RESOURCE_DIR": .plString(swiftResourceDir.str), // Resource dir for compiling Swift + "CLANG_RESOURCE_DIR": .plString(clangResourceDir.str), // Resource dir for linking C/C++/Obj-C + "SDKROOT": .plString(sysroot.str), + "OTHER_LDFLAGS": .plArray(["$(OTHER_SWIFT_FLAGS)"]), // The extra swift compiler settings in JSON are intended to go to the linker driver too + ]), + "SupportedTargets": .plDict([ + "webassembly": .plDict([ + "Archs": .plArray([.plString(llvmTriple.arch)]), + "LLVMTargetTripleEnvironment": .plString(llvmTriple.environment ?? ""), + "LLVMTargetTripleSys": .plString(tripleSystem), + "LLVMTargetTripleVendor": .plString(llvmTriple.vendor), + ]) + ]), + // TODO: Leave compatible toolchain information in Swift SDKs + // "Toolchains": .plArray([]) + ])) + + // FIXME why do we need to do this to avoid initialization errors on the SDK's default properties table? + if let sdk { + try sdk.loadExtendedInfo(delegate.namespace) + + return sdk + } + } + } + } + + // Xcode has special logic so that if there's no match here, and we'e *not* looking for a suffixed SDK, but we have an suffixed SDK which would otherwise match, then we use that. c.f. But we haven't needed that logic yet in Swift Build, so maybe we never will. return matchedSDK?.sdk } diff --git a/Sources/SWBCore/Settings/Settings.swift b/Sources/SWBCore/Settings/Settings.swift index cc6f3283..bafe0fa8 100644 --- a/Sources/SWBCore/Settings/Settings.swift +++ b/Sources/SWBCore/Settings/Settings.swift @@ -3504,7 +3504,7 @@ private class SettingsBuilder: ProjectMatchLookup { // If the target supports specialization and it already has an SDK, then we need to use that instead of attempting to override the SDK with the run destination information. This is very important in scenarios where the destination is Mac Catalyst, but the target is building for iphoneos. The target will be re-configured for macosx/iosmac. do { let scope = createScope(sdkToUse: nil) - let sdk = try sdkRegistry.lookup(scope.evaluate(BuiltinMacros.SDKROOT).str, activeRunDestination: nil) + let sdk = try sdkRegistry.lookup(scope.evaluate(BuiltinMacros.SDKROOT).str, activeRunDestination: parameters.activeRunDestination) if Settings.targetPlatformSpecializationEnabled(scope: scope) && sdk != nil { return } diff --git a/Sources/SWBCore/SwiftSDK.swift b/Sources/SWBCore/SwiftSDK.swift index c8f7f43f..7edbb71b 100644 --- a/Sources/SWBCore/SwiftSDK.swift +++ b/Sources/SWBCore/SwiftSDK.swift @@ -25,22 +25,53 @@ public struct SwiftSDK: Sendable { public var sdkRootPath: String public var swiftResourcesPath: String? public var swiftStaticResourcesPath: String? + public var clangResourcesPath: String? { + guard let swiftResourcesPath = self.swiftResourcesPath else { + return nil + } + + // The clang resource path is conventionally the clang subdirectory of the swift resource path + return Path(swiftResourcesPath).join("clang").str + } + public var clangStaticResourcesPath: String? { + guard let swiftResourcesPath = self.swiftStaticResourcesPath else { + return nil + } + + // The clang resource path is conventionally the clang subdirectory of the swift resource path + return Path(swiftResourcesPath).join("clang").str + } public var includeSearchPaths: [String]? public var librarySearchPaths: [String]? public var toolsetPaths: [String]? + + public func loadToolsets(sdk: SwiftSDK, fs: any FSProxy) throws -> [Toolset] { + var toolsets: [Toolset] = [] + + for toolsetPath in self.toolsetPaths ?? [] { + let metadataData = try Data(fs.read(sdk.path.join(toolsetPath))) + + let schema = try JSONDecoder().decode(SchemaVersionInfo.self, from: metadataData) + guard schema.schemaVersion == "1.0" else { return [] } // FIXME throw an error + + let toolset = try JSONDecoder().decode(Toolset.self, from: metadataData) + toolsets.append(toolset) + } + + return toolsets + } } struct MetadataV4: Codable { let targetTriples: [String: TripleProperties] } - struct Toolset: Codable { - struct ToolProperties: Codable { - var path: String? - var extraCLIOptions: [String] + public struct Toolset: Codable { + public struct Tool: Codable { + public let extraCLIOptions: [String]? } - var knownTools: [String: ToolProperties] = [:] - var rootPaths: [String] = [] + public let rootPath: String + public let swiftCompiler: Tool? } /// The identifier of the artifact bundle containing this SDK. @@ -55,12 +86,11 @@ public struct SwiftSDK: Sendable { init?(identifier: String, version: String, path: Path, fs: any FSProxy) throws { self.identifier = identifier self.version = version - self.path = path + self.path = path.dirname - let metadataPath = path.join("swift-sdk.json") - guard fs.exists(metadataPath) else { return nil } + guard fs.exists(path) else { return nil } - let metadataData = try Data(fs.read(metadataPath)) + let metadataData = try Data(fs.read(path)) let schema = try JSONDecoder().decode(SchemaVersionInfo.self, from: metadataData) guard schema.schemaVersion == "4.0" else { return nil } @@ -118,7 +148,7 @@ public struct SwiftSDK: Sendable { } /// Find Swift SDKs in an artifact bundle supporting one of the given targets. - private static func findSDKs(artifactBundle: Path, targetTriples: [String]?, fs: any FSProxy) throws -> [SwiftSDK] { + public static func findSDKs(artifactBundle: Path, targetTriples: [String]?, fs: any FSProxy) throws -> [SwiftSDK] { // Load info.json from the artifact bundle let infoPath = artifactBundle.join("info.json") guard try fs.isFile(infoPath) else { return [] } diff --git a/Sources/SWBProtocol/MessageSupport.swift b/Sources/SWBProtocol/MessageSupport.swift index 65e79bfc..5d0c1950 100644 --- a/Sources/SWBProtocol/MessageSupport.swift +++ b/Sources/SWBProtocol/MessageSupport.swift @@ -325,14 +325,18 @@ public struct RunDestinationInfo: SerializableCodable, Hashable, Sendable { public var supportedArchitectures: OrderedSet public var disableOnlyActiveArch: Bool public var hostTargetedPlatform: String? + public var sdkManiftestPath: String? + public var triple: String? - public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: OrderedSet, disableOnlyActiveArch: Bool, hostTargetedPlatform: String?) { + public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: OrderedSet, sdkManiftestPath: String? = nil, triple: String? = nil, disableOnlyActiveArch: Bool, hostTargetedPlatform: String?) { self.platform = platform self.sdk = sdk self.sdkVariant = sdkVariant self.targetArchitecture = targetArchitecture self.supportedArchitectures = supportedArchitectures self.disableOnlyActiveArch = disableOnlyActiveArch + self.sdkManiftestPath = sdkManiftestPath + self.triple = triple self.hostTargetedPlatform = hostTargetedPlatform } } diff --git a/Sources/SWBUniversalPlatform/Specs/Ld.xcspec b/Sources/SWBUniversalPlatform/Specs/Ld.xcspec index 40022fee..b6e9e04d 100644 --- a/Sources/SWBUniversalPlatform/Specs/Ld.xcspec +++ b/Sources/SWBUniversalPlatform/Specs/Ld.xcspec @@ -127,7 +127,7 @@ Values = ( { Value = "mh_execute"; - CommandLineFlag = "-emit-executable"; + CommandLineFlag = ""; }, { Value = "mh_dylib"; @@ -173,6 +173,27 @@ CommandLineFlag = "-sdk"; IsInputDependency = Yes; }, + { + Name = CLANG_RESOURCE_DIR; + Type = Path; + Condition = "$(LINKER_DRIVER) == clang"; + CommandLineFlag = "-resource-dir"; + IsInputDependency = Yes; + }, + { + Name = CLANG_RESOURCE_DIR; + Type = Path; + Condition = "$(LINKER_DRIVER) == swiftc"; + CommandLineArgs = ("-Xclang-linker", "-resource-dir", "-Xclang-linker", "$(CLANG_RESOURCE_DIR)"); + IsInputDependency = Yes; + }, + { + Name = SWIFTC_RESOURCE_DIR; + Type = Path; + Condition = "$(LINKER_DRIVER) == swiftc"; + CommandLineArgs = ("-resource-dir", "$(SWIFTC_RESOURCE_DIR)"); + IsInputDependency = Yes; + }, { Name = "LD_OPTIMIZATION_LEVEL"; Type = String; @@ -415,10 +436,10 @@ Type = StringList; DefaultValue = ""; CommandLineArgs = ( - "-Xlinker", - "-rpath", - "-Xlinker", - "$(value)", + //"-Xlinker", + //"-rpath", + //"-Xlinker", + //"$(value)", ); }, { diff --git a/Sources/SWBWebAssemblyPlatform/Specs/WebAssembly.xcspec b/Sources/SWBWebAssemblyPlatform/Specs/WebAssembly.xcspec index b7cfeaf8..5a30bd12 100644 --- a/Sources/SWBWebAssemblyPlatform/Specs/WebAssembly.xcspec +++ b/Sources/SWBWebAssemblyPlatform/Specs/WebAssembly.xcspec @@ -23,4 +23,10 @@ ); SortNumber = 0; }, + { + Domain = webassembly; + Type = ProductType; + Identifier = org.swift.product-type.common.object; + BasedOn = com.apple.product-type.library.static; + }, ) diff --git a/Sources/SwiftBuild/SWBBuildParameters.swift b/Sources/SwiftBuild/SWBBuildParameters.swift index 11d07745..914a89bf 100644 --- a/Sources/SwiftBuild/SWBBuildParameters.swift +++ b/Sources/SwiftBuild/SWBBuildParameters.swift @@ -43,17 +43,21 @@ public struct SWBRunDestinationInfo: Codable, Sendable { public var supportedArchitectures: [String] public var disableOnlyActiveArch: Bool public var hostTargetedPlatform: String? + public var sdkManifestPath: String? + public var triple: String? - public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], disableOnlyActiveArch: Bool) { + public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], sdkManifestPath: String? = nil, triple: String? = nil, disableOnlyActiveArch: Bool) { self.platform = platform self.sdk = sdk self.sdkVariant = sdkVariant self.targetArchitecture = targetArchitecture self.supportedArchitectures = supportedArchitectures self.disableOnlyActiveArch = disableOnlyActiveArch + self.sdkManifestPath = sdkManifestPath + self.triple = triple } - public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], disableOnlyActiveArch: Bool, hostTargetedPlatform: String?) { + public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], sdkManifestPath: String? = nil, triple: String? = nil, disableOnlyActiveArch: Bool, hostTargetedPlatform: String?) { self.init(platform: platform, sdk: sdk, sdkVariant: sdkVariant, targetArchitecture: targetArchitecture, supportedArchitectures: supportedArchitectures, disableOnlyActiveArch: disableOnlyActiveArch) self.hostTargetedPlatform = hostTargetedPlatform } diff --git a/Sources/SwiftBuild/SWBBuildServiceSession.swift b/Sources/SwiftBuild/SWBBuildServiceSession.swift index b86e3a52..525a0aa8 100644 --- a/Sources/SwiftBuild/SWBBuildServiceSession.swift +++ b/Sources/SwiftBuild/SWBBuildServiceSession.swift @@ -838,7 +838,7 @@ extension SWBBuildParameters { fileprivate extension RunDestinationInfo { init(_ x: SWBRunDestinationInfo) { - self.init(platform: x.platform, sdk: x.sdk, sdkVariant: x.sdkVariant, targetArchitecture: x.targetArchitecture, supportedArchitectures: OrderedSet(x.supportedArchitectures), disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) + self.init(platform: x.platform, sdk: x.sdk, sdkVariant: x.sdkVariant, targetArchitecture: x.targetArchitecture, supportedArchitectures: OrderedSet(x.supportedArchitectures), sdkManiftestPath: x.sdkManifestPath, triple: x.triple, disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) } } From 222f639fd100cc10ef7066439b83201288223da0 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 9 Dec 2025 12:27:01 -0500 Subject: [PATCH 02/18] Restore the emit executable argument in Ld.xcspec --- Sources/SWBUniversalPlatform/Specs/Ld.xcspec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/SWBUniversalPlatform/Specs/Ld.xcspec b/Sources/SWBUniversalPlatform/Specs/Ld.xcspec index b6e9e04d..614b5d03 100644 --- a/Sources/SWBUniversalPlatform/Specs/Ld.xcspec +++ b/Sources/SWBUniversalPlatform/Specs/Ld.xcspec @@ -127,7 +127,7 @@ Values = ( { Value = "mh_execute"; - CommandLineFlag = ""; + CommandLineFlag = "-emit-executable"; }, { Value = "mh_dylib"; @@ -436,6 +436,7 @@ Type = StringList; DefaultValue = ""; CommandLineArgs = ( + // FIXME: the wasm linker doesn't understand the rpath argument //"-Xlinker", //"-rpath", //"-Xlinker", From 0211f9ae3678848439e86bdc61d905c6263df0cb Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 9 Dec 2025 12:31:40 -0500 Subject: [PATCH 03/18] Override the rpath argument to the linker in the webassembly ld xcspec instead of the base ld xcspec --- Sources/SWBUniversalPlatform/Specs/Ld.xcspec | 9 ++++----- Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec | 8 ++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Sources/SWBUniversalPlatform/Specs/Ld.xcspec b/Sources/SWBUniversalPlatform/Specs/Ld.xcspec index 614b5d03..362585fc 100644 --- a/Sources/SWBUniversalPlatform/Specs/Ld.xcspec +++ b/Sources/SWBUniversalPlatform/Specs/Ld.xcspec @@ -436,11 +436,10 @@ Type = StringList; DefaultValue = ""; CommandLineArgs = ( - // FIXME: the wasm linker doesn't understand the rpath argument - //"-Xlinker", - //"-rpath", - //"-Xlinker", - //"$(value)", + "-Xlinker", + "-rpath", + "-Xlinker", + "$(value)", ); }, { diff --git a/Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec b/Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec index ba106172..985dfc97 100644 --- a/Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec +++ b/Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec @@ -52,6 +52,14 @@ DefaultValue = ""; Condition = "NO"; }, + { + // Wasm doesn't have search paths + Name = "LD_RUNPATH_SEARCH_PATHS"; + //Note: Cannot be of type 'PathList' as value is used with relative '../' paths + Type = StringList; + Condition = "NO"; + CommandLineArgs = (); + }, { Name = GOLD_BUILDID; Type = Boolean; From 7a136b5c8a813942d22a100bc0e9739004b21eea Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 9 Dec 2025 12:34:04 -0500 Subject: [PATCH 04/18] Move the platform registerSDK call to its original position --- Sources/SWBCore/SDKRegistry.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SWBCore/SDKRegistry.swift b/Sources/SWBCore/SDKRegistry.swift index 40082e8c..79485ea3 100644 --- a/Sources/SWBCore/SDKRegistry.swift +++ b/Sources/SWBCore/SDKRegistry.swift @@ -998,8 +998,6 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send // Construct the SDK and add it to the registry. let sdk = SDK(canonicalName, canonicalNameComponents: try? parseSDKName(canonicalName), aliases, cohortPlatforms, displayName, path, version, productBuildVersion, defaultSettings, overrideSettings, variants, defaultDeploymentTarget, defaultVariant, (headerSearchPaths, frameworkSearchPaths, librarySearchPaths), directoryMacros.elements, isBaseSDK, fallbackSettingConditionValues, toolchains, versionMap, maximumDeploymentTarget) - platform?.registerSDK(sdk) - if let duplicate = sdksByCanonicalName[sdk.canonicalName] { delegate.error(path, "SDK '\(sdk.canonicalName)' already registered from \(duplicate.path.str)") return nil @@ -1014,6 +1012,8 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send sdksByPath[path] = sdk sdksByPath[pathResolved] = sdk + platform?.registerSDK(sdk) + return sdk } From ae502088f06e56d1cb6ce438a40c270869026cfd Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 9 Dec 2025 12:45:42 -0500 Subject: [PATCH 05/18] Undo use of sdk.canonicalName instead of the provided canonical name --- Sources/SWBCore/SDKRegistry.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/SWBCore/SDKRegistry.swift b/Sources/SWBCore/SDKRegistry.swift index 79485ea3..42dfdecf 100644 --- a/Sources/SWBCore/SDKRegistry.swift +++ b/Sources/SWBCore/SDKRegistry.swift @@ -998,12 +998,12 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send // Construct the SDK and add it to the registry. let sdk = SDK(canonicalName, canonicalNameComponents: try? parseSDKName(canonicalName), aliases, cohortPlatforms, displayName, path, version, productBuildVersion, defaultSettings, overrideSettings, variants, defaultDeploymentTarget, defaultVariant, (headerSearchPaths, frameworkSearchPaths, librarySearchPaths), directoryMacros.elements, isBaseSDK, fallbackSettingConditionValues, toolchains, versionMap, maximumDeploymentTarget) - if let duplicate = sdksByCanonicalName[sdk.canonicalName] { - delegate.error(path, "SDK '\(sdk.canonicalName)' already registered from \(duplicate.path.str)") + if let duplicate = sdksByCanonicalName[canonicalName] { + delegate.error(path, "SDK '\(canonicalName)' already registered from \(duplicate.path.str)") return nil } - sdksByCanonicalName[sdk.canonicalName] = sdk + sdksByCanonicalName[canonicalName] = sdk for alias in sdk.aliases { self.sdksByAlias[alias] = (self.sdksByAlias[alias] ?? []) + [sdk] From 07993ad0f5e4e21fc1e30939dc342cf781c8b6b1 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 9 Dec 2025 13:06:47 -0500 Subject: [PATCH 06/18] Fix compile error in tests --- Sources/SwiftBuild/SWBBuildParameters.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/SwiftBuild/SWBBuildParameters.swift b/Sources/SwiftBuild/SWBBuildParameters.swift index 914a89bf..17af2cac 100644 --- a/Sources/SwiftBuild/SWBBuildParameters.swift +++ b/Sources/SwiftBuild/SWBBuildParameters.swift @@ -46,20 +46,20 @@ public struct SWBRunDestinationInfo: Codable, Sendable { public var sdkManifestPath: String? public var triple: String? - public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], sdkManifestPath: String? = nil, triple: String? = nil, disableOnlyActiveArch: Bool) { + public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], disableOnlyActiveArch: Bool) { self.platform = platform self.sdk = sdk self.sdkVariant = sdkVariant self.targetArchitecture = targetArchitecture self.supportedArchitectures = supportedArchitectures self.disableOnlyActiveArch = disableOnlyActiveArch - self.sdkManifestPath = sdkManifestPath - self.triple = triple } public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], sdkManifestPath: String? = nil, triple: String? = nil, disableOnlyActiveArch: Bool, hostTargetedPlatform: String?) { self.init(platform: platform, sdk: sdk, sdkVariant: sdkVariant, targetArchitecture: targetArchitecture, supportedArchitectures: supportedArchitectures, disableOnlyActiveArch: disableOnlyActiveArch) self.hostTargetedPlatform = hostTargetedPlatform + self.sdkManifestPath = sdkManifestPath + self.triple = triple } } From d6bce255c8976b9f03fda218d60f6145bcc02116 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 9 Dec 2025 13:10:42 -0500 Subject: [PATCH 07/18] Formatting --- Sources/SWBCore/SDKRegistry.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SWBCore/SDKRegistry.swift b/Sources/SWBCore/SDKRegistry.swift index 42dfdecf..4eaf4c96 100644 --- a/Sources/SWBCore/SDKRegistry.swift +++ b/Sources/SWBCore/SDKRegistry.swift @@ -1152,7 +1152,7 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send } let toolsets = try tripleProperties.loadToolsets(sdk: swiftSDK, fs: localFS) - + let sysroot = swiftSDK.path.join(tripleProperties.sdkRootPath) // TODO support dynamic resources path From 87af09f1619253b60827ae4bb17f850695f4d884 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Wed, 10 Dec 2025 10:11:13 -0500 Subject: [PATCH 08/18] Base the OTHER_LDFLAGS on the extra swift compiler settings Add the missing sdk parameter to swiftc linker driver in UnixLD.xcpsec --- Sources/SWBCore/SDKRegistry.swift | 2 +- Sources/SWBGenericUnixPlatform/Specs/UnixLd.xcspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SWBCore/SDKRegistry.swift b/Sources/SWBCore/SDKRegistry.swift index 4eaf4c96..65ec992b 100644 --- a/Sources/SWBCore/SDKRegistry.swift +++ b/Sources/SWBCore/SDKRegistry.swift @@ -1184,7 +1184,7 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send "SWIFT_RESOURCE_DIR": .plString(swiftResourceDir.str), // Resource dir for compiling Swift "CLANG_RESOURCE_DIR": .plString(clangResourceDir.str), // Resource dir for linking C/C++/Obj-C "SDKROOT": .plString(sysroot.str), - "OTHER_LDFLAGS": .plArray(["$(OTHER_SWIFT_FLAGS)"]), // The extra swift compiler settings in JSON are intended to go to the linker driver too + "OTHER_LDFLAGS": .plArray(["$(inherited)"] + extraSwiftCompilerSettings.map( {.plString($0)} )), // The extra swift compiler settings in JSON are intended to go to the linker driver too ]), "SupportedTargets": .plDict([ "webassembly": .plDict([ diff --git a/Sources/SWBGenericUnixPlatform/Specs/UnixLd.xcspec b/Sources/SWBGenericUnixPlatform/Specs/UnixLd.xcspec index b408bd89..17cb0952 100644 --- a/Sources/SWBGenericUnixPlatform/Specs/UnixLd.xcspec +++ b/Sources/SWBGenericUnixPlatform/Specs/UnixLd.xcspec @@ -63,7 +63,7 @@ Type = Path; DefaultValue = "$(SYSROOT:default=$(SDKROOT))"; Condition = "$(LINKER_DRIVER) == swiftc"; - CommandLineFlag = "-sysroot"; + CommandLineArgs = ("-sysroot", "$(SWIFTC_SDKROOT_LINKER_INPUT)", "-sdk", "$(SWIFTC_SDKROOT_LINKER_INPUT)"); IsInputDependency = Yes; }, { From 66cfd6ceff6c1950dddb1b6e260c2edfb7103f9f Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Wed, 10 Dec 2025 10:16:31 -0500 Subject: [PATCH 09/18] Fix typo --- Sources/SWBCore/SDKRegistry.swift | 2 +- Sources/SWBProtocol/MessageSupport.swift | 6 +++--- Sources/SwiftBuild/SWBBuildServiceSession.swift | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/SWBCore/SDKRegistry.swift b/Sources/SWBCore/SDKRegistry.swift index 65ec992b..e88d138e 100644 --- a/Sources/SWBCore/SDKRegistry.swift +++ b/Sources/SWBCore/SDKRegistry.swift @@ -1114,7 +1114,7 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send // Let's check the active run destination to see if there's an SDK path that we should be using if matchedSDK == nil, - let sdkManifestPath = activeRunDestination?.sdkManiftestPath, + let sdkManifestPath = activeRunDestination?.sdkManifestPath, let triple = activeRunDestination?.triple, case let llvmTriple = try LLVMTriple(triple) { diff --git a/Sources/SWBProtocol/MessageSupport.swift b/Sources/SWBProtocol/MessageSupport.swift index 5d0c1950..3e75a80f 100644 --- a/Sources/SWBProtocol/MessageSupport.swift +++ b/Sources/SWBProtocol/MessageSupport.swift @@ -325,17 +325,17 @@ public struct RunDestinationInfo: SerializableCodable, Hashable, Sendable { public var supportedArchitectures: OrderedSet public var disableOnlyActiveArch: Bool public var hostTargetedPlatform: String? - public var sdkManiftestPath: String? + public var sdkManifestPath: String? public var triple: String? - public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: OrderedSet, sdkManiftestPath: String? = nil, triple: String? = nil, disableOnlyActiveArch: Bool, hostTargetedPlatform: String?) { + public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: OrderedSet, sdkManifestPath: String? = nil, triple: String? = nil, disableOnlyActiveArch: Bool, hostTargetedPlatform: String?) { self.platform = platform self.sdk = sdk self.sdkVariant = sdkVariant self.targetArchitecture = targetArchitecture self.supportedArchitectures = supportedArchitectures self.disableOnlyActiveArch = disableOnlyActiveArch - self.sdkManiftestPath = sdkManiftestPath + self.sdkManifestPath = sdkManifestPath self.triple = triple self.hostTargetedPlatform = hostTargetedPlatform } diff --git a/Sources/SwiftBuild/SWBBuildServiceSession.swift b/Sources/SwiftBuild/SWBBuildServiceSession.swift index 525a0aa8..c080a2c2 100644 --- a/Sources/SwiftBuild/SWBBuildServiceSession.swift +++ b/Sources/SwiftBuild/SWBBuildServiceSession.swift @@ -838,7 +838,7 @@ extension SWBBuildParameters { fileprivate extension RunDestinationInfo { init(_ x: SWBRunDestinationInfo) { - self.init(platform: x.platform, sdk: x.sdk, sdkVariant: x.sdkVariant, targetArchitecture: x.targetArchitecture, supportedArchitectures: OrderedSet(x.supportedArchitectures), sdkManiftestPath: x.sdkManifestPath, triple: x.triple, disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) + self.init(platform: x.platform, sdk: x.sdk, sdkVariant: x.sdkVariant, targetArchitecture: x.targetArchitecture, supportedArchitectures: OrderedSet(x.supportedArchitectures), sdkManifestPath: x.sdkManifestPath, triple: x.triple, disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) } } From 6bdaeeff82ef37062bbfc88f4253c9efc612d0b1 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Wed, 10 Dec 2025 11:28:50 -0500 Subject: [PATCH 10/18] Introduce a new synthesizedSDK method for SDK registries that specializes in producing one from run destination information --- Sources/SWBCore/SDKRegistry.swift | 201 +++++++++++++----------- Sources/SWBCore/Settings/Settings.swift | 9 +- Sources/SWBCore/WorkspaceContext.swift | 8 + 3 files changed, 120 insertions(+), 98 deletions(-) diff --git a/Sources/SWBCore/SDKRegistry.swift b/Sources/SWBCore/SDKRegistry.swift index e88d138e..a413f17a 100644 --- a/Sources/SWBCore/SDKRegistry.swift +++ b/Sources/SWBCore/SDKRegistry.swift @@ -515,6 +515,9 @@ public protocol SDKRegistryLookup: Sendable { /// - returns: The found `SDK`, or `nil` if no SDK with the given name could be found or `name` was in an invalid format. func lookup(_ name: String, activeRunDestination: RunDestinationInfo?) throws -> SDK? + /// Synthesize an SDK with the given manifest JSON file path + func synthesizedSDK(sdkManifestPath: String, triple: String) throws -> SDK? + /// Look up the SDK with the given path. If the registry is immutable, then this will only return the SDK if it was loaded when the registry was created; only mutable registries can discover and load new SDKs after that point. /// - parameter path: Absolute path of the SDK to look up. /// - returns: The found `SDK`, or `nil` if no SDK was found at the given path. @@ -1112,102 +1115,6 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send } } - // Let's check the active run destination to see if there's an SDK path that we should be using - if matchedSDK == nil, - let sdkManifestPath = activeRunDestination?.sdkManifestPath, - let triple = activeRunDestination?.triple, - case let llvmTriple = try LLVMTriple(triple) { - - // TODO choose the platform based on the triple, and fallback to a default one in the default case - guard let platform = delegate.platformRegistry?.lookup(name: "webassembly") else { - return nil - } - - let host = hostOperatingSystem - - // Don't allow re-registering the same SDK - if let existing = sdksByCanonicalName[sdkManifestPath] { - return existing - } - - if let swiftSDK = try SwiftSDK(identifier: sdkManifestPath, version: "1.0.0", path: Path(sdkManifestPath), fs: localFS) { - let defaultProperties: [String: PropertyListItem] = [ - "SDK_STAT_CACHE_ENABLE": "NO", - - "GENERATE_TEXT_BASED_STUBS": "NO", - "GENERATE_INTERMEDIATE_TEXT_BASED_STUBS": "NO", - - // TODO check how this impacts operation on Windows - "CHOWN": "/usr/bin/chown", - - // TODO are these going to be appropriate for all kinds of SDK's? - // SwiftSDK _could_ have tool entries for these, so use them if they are available - "LIBTOOL": .plString(host.imageFormat.executableName(basename: "llvm-lib")), - "AR": .plString(host.imageFormat.executableName(basename: "llvm-ar")), - ] - - for (sdkTriple, tripleProperties) in swiftSDK.targetTriples { - guard triple == sdkTriple else { - continue - } - - let toolsets = try tripleProperties.loadToolsets(sdk: swiftSDK, fs: localFS) - - let sysroot = swiftSDK.path.join(tripleProperties.sdkRootPath) - - // TODO support dynamic resources path - let swiftResourceDir = swiftSDK.path.join(tripleProperties.swiftStaticResourcesPath) - let clangResourceDir = swiftSDK.path.join(tripleProperties.clangStaticResourcesPath) - - let tripleSystem = llvmTriple.system + (llvmTriple.systemVersion?.description ?? "") - - // TODO handle tripleProperties.toolSearchPaths - - let extraSwiftCompilerSettings = Array(toolsets.map( { $0.swiftCompiler?.extraCLIOptions ?? [] }).flatMap( { $0 })) - let headerSearchPaths: [PropertyListItem] = ["$(inherited)"] + (tripleProperties.includeSearchPaths ?? []).map( { PropertyListItem.plString($0) } ) - let librarySearchPaths: [PropertyListItem] = ["$(inherited)"] + (tripleProperties.librarySearchPaths ?? []).map( { PropertyListItem.plString($0) } ) - - let sdk = registerSDK(sysroot, sysroot, platform, .plDict([ - "Type": .plString("SDK"), - "Version": .plString(swiftSDK.version), - "CanonicalName": .plString(swiftSDK.identifier), - "Aliases": [], - "IsBaseSDK": .plBool(true), - "DefaultProperties": .plDict([ - "PLATFORM_NAME": .plString(platform.name), - ].merging(defaultProperties, uniquingKeysWith: { _, new in new })), - "CustomProperties": .plDict([ - "LIBRARY_SEARCH_PATHS": .plArray(librarySearchPaths), - "HEADER_SEARCH_PATHS": .plArray(headerSearchPaths), - "OTHER_SWIFT_FLAGS": .plArray(["$(inherited)"] + extraSwiftCompilerSettings.map( {.plString($0)} )), - "SWIFTC_RESOURCE_DIR": .plString(swiftResourceDir.str), // Resource dir for linking Swift - "SWIFT_RESOURCE_DIR": .plString(swiftResourceDir.str), // Resource dir for compiling Swift - "CLANG_RESOURCE_DIR": .plString(clangResourceDir.str), // Resource dir for linking C/C++/Obj-C - "SDKROOT": .plString(sysroot.str), - "OTHER_LDFLAGS": .plArray(["$(inherited)"] + extraSwiftCompilerSettings.map( {.plString($0)} )), // The extra swift compiler settings in JSON are intended to go to the linker driver too - ]), - "SupportedTargets": .plDict([ - "webassembly": .plDict([ - "Archs": .plArray([.plString(llvmTriple.arch)]), - "LLVMTargetTripleEnvironment": .plString(llvmTriple.environment ?? ""), - "LLVMTargetTripleSys": .plString(tripleSystem), - "LLVMTargetTripleVendor": .plString(llvmTriple.vendor), - ]) - ]), - // TODO: Leave compatible toolchain information in Swift SDKs - // "Toolchains": .plArray([]) - ])) - - // FIXME why do we need to do this to avoid initialization errors on the SDK's default properties table? - if let sdk { - try sdk.loadExtendedInfo(delegate.namespace) - - return sdk - } - } - } - } - // Xcode has special logic so that if there's no match here, and we'e *not* looking for a suffixed SDK, but we have an suffixed SDK which would otherwise match, then we use that. c.f. But we haven't needed that logic yet in Swift Build, so maybe we never will. return matchedSDK?.sdk } @@ -1249,6 +1156,101 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send return sdk } + public func synthesizedSDK(sdkManifestPath: String, triple: String) throws -> SDK? { + // Let's check the active run destination to see if there's an SDK path that we should be using + let llvmTriple = try LLVMTriple(triple) + + // TODO choose the platform based on the triple, and fallback to a default one in the default case + guard let platform = delegate.platformRegistry?.lookup(name: "webassembly") else { + return nil + } + + let host = hostOperatingSystem + + // Don't allow re-registering the same SDK + if let existing = sdksByPath[Path(sdkManifestPath)] { + return existing + } + + if let swiftSDK = try SwiftSDK(identifier: sdkManifestPath, version: "1.0.0", path: Path(sdkManifestPath), fs: localFS) { + let defaultProperties: [String: PropertyListItem] = [ + "SDK_STAT_CACHE_ENABLE": "NO", + + "GENERATE_TEXT_BASED_STUBS": "NO", + "GENERATE_INTERMEDIATE_TEXT_BASED_STUBS": "NO", + + // TODO check how this impacts operation on Windows + "CHOWN": "/usr/bin/chown", + + // TODO are these going to be appropriate for all kinds of SDK's? + // SwiftSDK _could_ have tool entries for these, so use them if they are available + "LIBTOOL": .plString(host.imageFormat.executableName(basename: "llvm-lib")), + "AR": .plString(host.imageFormat.executableName(basename: "llvm-ar")), + ] + + for (sdkTriple, tripleProperties) in swiftSDK.targetTriples { + guard triple == sdkTriple else { + continue + } + + let toolsets = try tripleProperties.loadToolsets(sdk: swiftSDK, fs: localFS) + + let sysroot = swiftSDK.path.join(tripleProperties.sdkRootPath) + + // TODO support dynamic resources path + let swiftResourceDir = swiftSDK.path.join(tripleProperties.swiftStaticResourcesPath) + let clangResourceDir = swiftSDK.path.join(tripleProperties.clangStaticResourcesPath) + + let tripleSystem = llvmTriple.system + (llvmTriple.systemVersion?.description ?? "") + + // TODO handle tripleProperties.toolSearchPaths + + let extraSwiftCompilerSettings = Array(toolsets.map( { $0.swiftCompiler?.extraCLIOptions ?? [] }).flatMap( { $0 })) + let headerSearchPaths: [PropertyListItem] = ["$(inherited)"] + (tripleProperties.includeSearchPaths ?? []).map( { PropertyListItem.plString($0) } ) + let librarySearchPaths: [PropertyListItem] = ["$(inherited)"] + (tripleProperties.librarySearchPaths ?? []).map( { PropertyListItem.plString($0) } ) + + let sdk = registerSDK(sysroot, sysroot, platform, .plDict([ + "Type": .plString("SDK"), + "Version": .plString(swiftSDK.version), + "CanonicalName": .plString(swiftSDK.identifier), + "Aliases": [], + "IsBaseSDK": .plBool(true), + "DefaultProperties": .plDict([ + "PLATFORM_NAME": .plString(platform.name), + ].merging(defaultProperties, uniquingKeysWith: { _, new in new })), + "CustomProperties": .plDict([ + "LIBRARY_SEARCH_PATHS": .plArray(librarySearchPaths), + "HEADER_SEARCH_PATHS": .plArray(headerSearchPaths), + "OTHER_SWIFT_FLAGS": .plArray(["$(inherited)"] + extraSwiftCompilerSettings.map( {.plString($0)} )), + "SWIFTC_RESOURCE_DIR": .plString(swiftResourceDir.str), // Resource dir for linking Swift + "SWIFT_RESOURCE_DIR": .plString(swiftResourceDir.str), // Resource dir for compiling Swift + "CLANG_RESOURCE_DIR": .plString(clangResourceDir.str), // Resource dir for linking C/C++/Obj-C + "SDKROOT": .plString(sysroot.str), + "OTHER_LDFLAGS": .plArray(["$(inherited)"] + extraSwiftCompilerSettings.map( {.plString($0)} )), // The extra swift compiler settings in JSON are intended to go to the linker driver too + ]), + "SupportedTargets": .plDict([ + platform.name: .plDict([ + "Archs": .plArray([.plString(llvmTriple.arch)]), + "LLVMTargetTripleEnvironment": .plString(llvmTriple.environment ?? ""), + "LLVMTargetTripleSys": .plString(tripleSystem), + "LLVMTargetTripleVendor": .plString(llvmTriple.vendor), + ]) + ]), + // TODO: Leave compatible toolchain information in Swift SDKs + // "Toolchains": .plArray([]) + ])) + + if let sdk { + try sdk.loadExtendedInfo(delegate.namespace) + sdksByPath[Path(sdkManifestPath)] = sdk + return sdk + } + } + } + + return nil + } + public func lookup(nameOrPath key: String, basePath: Path, activeRunDestination: RunDestinationInfo?) throws -> SDK? { #if !os(Windows) // TODO: Turn this validation back on once our path handling is cleaned up a bit more @@ -1266,6 +1268,13 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send return self.lookup(keyPath.isAbsolute ? keyPath : basePath.join(key)) } + // Next try to synthesize an SDK using a provided manifest path and triple + if let sdkManifestPath = activeRunDestination?.sdkManifestPath, let triple = activeRunDestination?.triple { + if let sdk = try self.synthesizedSDK(sdkManifestPath: sdkManifestPath, triple: triple) { + return sdk + } + } + // Otherwise, attempt to resolve the SDK as a canonical name. if let sdk = try lookup(key, activeRunDestination: activeRunDestination) { return sdk diff --git a/Sources/SWBCore/Settings/Settings.swift b/Sources/SWBCore/Settings/Settings.swift index bafe0fa8..199e78be 100644 --- a/Sources/SWBCore/Settings/Settings.swift +++ b/Sources/SWBCore/Settings/Settings.swift @@ -3518,11 +3518,16 @@ private class SettingsBuilder: ProjectMatchLookup { } let destinationSDK: SDK do { - guard let sdk = try sdkRegistry.lookup(runDestination.sdk, activeRunDestination: runDestination) else { + if let sdk = try sdkRegistry.lookup(runDestination.sdk, activeRunDestination: runDestination) { + destinationSDK = sdk + } else if let sdkManifestPath = runDestination.sdkManifestPath, + let triple = runDestination.triple, + let sdk = try sdkRegistry.synthesizedSDK(sdkManifestPath: sdkManifestPath, triple: triple) { + destinationSDK = sdk + } else { self.errors.append("unable to resolve run destination SDK: '\(runDestination.sdk)'") return } - destinationSDK = sdk } catch let error as AmbiguousSDKLookupError { self.diagnostics.append(error.diagnostic) return diff --git a/Sources/SWBCore/WorkspaceContext.swift b/Sources/SWBCore/WorkspaceContext.swift index 5f0e4f6b..46dd3fe8 100644 --- a/Sources/SWBCore/WorkspaceContext.swift +++ b/Sources/SWBCore/WorkspaceContext.swift @@ -213,6 +213,10 @@ public struct WorkspaceContextSDKRegistry: SDKRegistryLookup, Sendable { public func lookup(nameOrPath: String, basePath: Path, activeRunDestination: RunDestinationInfo?) throws -> SDK? { return try lookupInEach { try $0.lookup(nameOrPath: nameOrPath, basePath: basePath, activeRunDestination: activeRunDestination) } } + + func synthesizedSDK(sdkManifestPath: String, triple: String) throws -> SDK? { + return try lookupInEach { try $0.synthesizedSDK(sdkManifestPath: sdkManifestPath, triple: triple) } + } } @_spi(Testing) public init(coreSDKRegistry: SDKRegistry, delegate: any SDKRegistryDelegate, userNamespace: MacroNamespace, overridingSDKsDir: Path?) { @@ -246,6 +250,10 @@ public struct WorkspaceContextSDKRegistry: SDKRegistryLookup, Sendable { public func lookup(nameOrPath: String, basePath: Path, activeRunDestination: RunDestinationInfo?) throws -> SDK? { return try underlyingLookup.lookup(nameOrPath: nameOrPath, basePath: basePath, activeRunDestination: activeRunDestination) } + + public func synthesizedSDK(sdkManifestPath: String, triple: String) throws -> SDK? { + return try underlyingLookup.synthesizedSDK(sdkManifestPath: sdkManifestPath, triple: triple) + } } /// Wrapper for information needed to use a workspace. From 6b5f572dadb6029e1a2d5a304d4415f3cb2af288 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Wed, 10 Dec 2025 12:07:30 -0500 Subject: [PATCH 11/18] Formatting and remove active run destination qualifier --- Sources/SWBCore/SDKRegistry.swift | 2 +- Sources/SWBCore/Settings/Settings.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SWBCore/SDKRegistry.swift b/Sources/SWBCore/SDKRegistry.swift index a413f17a..393c1e24 100644 --- a/Sources/SWBCore/SDKRegistry.swift +++ b/Sources/SWBCore/SDKRegistry.swift @@ -1000,7 +1000,6 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send // Construct the SDK and add it to the registry. let sdk = SDK(canonicalName, canonicalNameComponents: try? parseSDKName(canonicalName), aliases, cohortPlatforms, displayName, path, version, productBuildVersion, defaultSettings, overrideSettings, variants, defaultDeploymentTarget, defaultVariant, (headerSearchPaths, frameworkSearchPaths, librarySearchPaths), directoryMacros.elements, isBaseSDK, fallbackSettingConditionValues, toolchains, versionMap, maximumDeploymentTarget) - if let duplicate = sdksByCanonicalName[canonicalName] { delegate.error(path, "SDK '\(canonicalName)' already registered from \(duplicate.path.str)") return nil @@ -1116,6 +1115,7 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send } // Xcode has special logic so that if there's no match here, and we'e *not* looking for a suffixed SDK, but we have an suffixed SDK which would otherwise match, then we use that. c.f. But we haven't needed that logic yet in Swift Build, so maybe we never will. + return matchedSDK?.sdk } diff --git a/Sources/SWBCore/Settings/Settings.swift b/Sources/SWBCore/Settings/Settings.swift index 199e78be..66494ffa 100644 --- a/Sources/SWBCore/Settings/Settings.swift +++ b/Sources/SWBCore/Settings/Settings.swift @@ -3504,7 +3504,7 @@ private class SettingsBuilder: ProjectMatchLookup { // If the target supports specialization and it already has an SDK, then we need to use that instead of attempting to override the SDK with the run destination information. This is very important in scenarios where the destination is Mac Catalyst, but the target is building for iphoneos. The target will be re-configured for macosx/iosmac. do { let scope = createScope(sdkToUse: nil) - let sdk = try sdkRegistry.lookup(scope.evaluate(BuiltinMacros.SDKROOT).str, activeRunDestination: parameters.activeRunDestination) + let sdk = try sdkRegistry.lookup(scope.evaluate(BuiltinMacros.SDKROOT).str, activeRunDestination: nil) if Settings.targetPlatformSpecializationEnabled(scope: scope) && sdk != nil { return } From 4237bf4336d818dd38a0e4b1b585f7fbc863fc95 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Fri, 12 Dec 2025 09:18:44 -0500 Subject: [PATCH 12/18] Make explicit build target in run destination with both Apple and Swift SDK cases --- Sources/SWBCore/SDKRegistry.swift | 18 +--- Sources/SWBCore/Settings/Settings.swift | 91 ++++++++++++++----- Sources/SWBCore/WorkspaceContext.swift | 8 +- Sources/SWBProtocol/MessageSupport.swift | 29 ++++-- Sources/SwiftBuild/SWBBuildParameters.swift | 65 +++++++++++-- .../SwiftBuild/SWBBuildServiceSession.swift | 7 +- 6 files changed, 161 insertions(+), 57 deletions(-) diff --git a/Sources/SWBCore/SDKRegistry.swift b/Sources/SWBCore/SDKRegistry.swift index 393c1e24..0777dc4d 100644 --- a/Sources/SWBCore/SDKRegistry.swift +++ b/Sources/SWBCore/SDKRegistry.swift @@ -515,8 +515,8 @@ public protocol SDKRegistryLookup: Sendable { /// - returns: The found `SDK`, or `nil` if no SDK with the given name could be found or `name` was in an invalid format. func lookup(_ name: String, activeRunDestination: RunDestinationInfo?) throws -> SDK? - /// Synthesize an SDK with the given manifest JSON file path - func synthesizedSDK(sdkManifestPath: String, triple: String) throws -> SDK? + /// Synthesize an SDK for the given platform with the given manifest JSON file path + func synthesizedSDK(platform: Platform, sdkManifestPath: String, triple: String) throws -> SDK? /// Look up the SDK with the given path. If the registry is immutable, then this will only return the SDK if it was loaded when the registry was created; only mutable registries can discover and load new SDKs after that point. /// - parameter path: Absolute path of the SDK to look up. @@ -1156,15 +1156,10 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send return sdk } - public func synthesizedSDK(sdkManifestPath: String, triple: String) throws -> SDK? { + public func synthesizedSDK(platform: Platform, sdkManifestPath: String, triple: String) throws -> SDK? { // Let's check the active run destination to see if there's an SDK path that we should be using let llvmTriple = try LLVMTriple(triple) - // TODO choose the platform based on the triple, and fallback to a default one in the default case - guard let platform = delegate.platformRegistry?.lookup(name: "webassembly") else { - return nil - } - let host = hostOperatingSystem // Don't allow re-registering the same SDK @@ -1268,13 +1263,6 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send return self.lookup(keyPath.isAbsolute ? keyPath : basePath.join(key)) } - // Next try to synthesize an SDK using a provided manifest path and triple - if let sdkManifestPath = activeRunDestination?.sdkManifestPath, let triple = activeRunDestination?.triple { - if let sdk = try self.synthesizedSDK(sdkManifestPath: sdkManifestPath, triple: triple) { - return sdk - } - } - // Otherwise, attempt to resolve the SDK as a canonical name. if let sdk = try lookup(key, activeRunDestination: activeRunDestination) { return sdk diff --git a/Sources/SWBCore/Settings/Settings.swift b/Sources/SWBCore/Settings/Settings.swift index 66494ffa..24c20d7b 100644 --- a/Sources/SWBCore/Settings/Settings.swift +++ b/Sources/SWBCore/Settings/Settings.swift @@ -1803,11 +1803,24 @@ private class SettingsBuilder: ProjectMatchLookup { } do { - sdk = try project.map { try sdkRegistry.lookup(nameOrPath: sdkroot, basePath: $0.sourceRoot, activeRunDestination: parameters.activeRunDestination) } ?? nil + sdk = try project.map { + switch parameters.activeRunDestination?.buildTarget { + case let .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple): + // FIXME platform should be decided by the triple + guard let platform = core.platformRegistry.lookup(name: "webassembly") else { + errors.append("unable to find platform 'webassembly'") + return nil + } + return try sdkRegistry.synthesizedSDK(platform: platform, sdkManifestPath: sdkManifestPath, triple: triple) + default: + return try sdkRegistry.lookup(nameOrPath: sdkroot, basePath: $0.sourceRoot, activeRunDestination: parameters.activeRunDestination) + } + } ?? nil } catch { sdk = nil sdkLookupErrors.append(error) } + if let s = sdk { // Evaluate the SDK variant, if there is one. let sdkVariantName: String @@ -3512,28 +3525,46 @@ private class SettingsBuilder: ProjectMatchLookup { // Destination info: since runDestination.{platform,sdk} were set by the IDE, we expect them to resolve in Swift Build correctly guard let runDestination = self.parameters.activeRunDestination else { return } - guard let destinationPlatform: Platform = self.core.platformRegistry.lookup(name: runDestination.platform) else { - self.errors.append("unable to resolve run destination platform: '\(runDestination.platform)'") - return - } + + let destinationPlatform: Platform let destinationSDK: SDK - do { - if let sdk = try sdkRegistry.lookup(runDestination.sdk, activeRunDestination: runDestination) { - destinationSDK = sdk - } else if let sdkManifestPath = runDestination.sdkManifestPath, - let triple = runDestination.triple, - let sdk = try sdkRegistry.synthesizedSDK(sdkManifestPath: sdkManifestPath, triple: triple) { - destinationSDK = sdk - } else { - self.errors.append("unable to resolve run destination SDK: '\(runDestination.sdk)'") + switch runDestination.buildTarget { + case let .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple): + // FIXME: the platform should be determined using the triple + guard let platform = self.core.platformRegistry.lookup(name: "webassembly") else { + self.errors.append("unable to resolve run destination platform: 'webassembly'") + return + } + + destinationPlatform = platform + + guard let sdk = try? sdkRegistry.synthesizedSDK(platform: platform, sdkManifestPath: sdkManifestPath, triple: triple) else { + self.errors.append("unable to synthesize SDK for Swift SDK build target: '\(runDestination.buildTarget)'") + return + } + destinationSDK = sdk + default: + guard let platform = self.core.platformRegistry.lookup(name: runDestination.platform) else { + self.errors.append("unable to resolve run destination platform: '\(runDestination.platform)'") + return + } + + destinationPlatform = platform + + do { + if let sdk = try sdkRegistry.lookup(runDestination.sdk, activeRunDestination: runDestination) { + destinationSDK = sdk + } else { + self.errors.append("unable to resolve run destination SDK: '\(runDestination.sdk)'") + return + } + } catch let error as AmbiguousSDKLookupError { + self.diagnostics.append(error.diagnostic) + return + } catch { + self.errors.append("\(error)") return } - } catch let error as AmbiguousSDKLookupError { - self.diagnostics.append(error.diagnostic) - return - } catch { - self.errors.append("\(error)") - return } let destinationPlatformIsMacOS = destinationPlatform.name == "macosx" @@ -3644,9 +3675,23 @@ private class SettingsBuilder: ProjectMatchLookup { // Destination info: since runDestination.{platform,sdk} were set by the IDE, we expect them to resolve in Swift Build correctly guard let runDestination = self.parameters.activeRunDestination else { return } - guard let destinationPlatform: Platform = self.core.platformRegistry.lookup(name: runDestination.platform) else { - self.errors.append("unable to resolve run destination platform: '\(runDestination.platform)'") - return + + let destinationPlatform: Platform + + switch runDestination.buildTarget { + case .swiftSDK: + // TODO use the triple to decide the platform, or use a fallback + guard let platform: Platform = self.core.platformRegistry.lookup(name: "webassembly") else { + self.errors.append("unable to resolve run destination platform: '\(runDestination.platform)'") + return + } + destinationPlatform = platform + default: + guard let platform: Platform = self.core.platformRegistry.lookup(name: runDestination.platform) else { + self.errors.append("unable to resolve run destination platform: '\(runDestination.platform)'") + return + } + destinationPlatform = platform } // Target info diff --git a/Sources/SWBCore/WorkspaceContext.swift b/Sources/SWBCore/WorkspaceContext.swift index 46dd3fe8..1b8a3cc5 100644 --- a/Sources/SWBCore/WorkspaceContext.swift +++ b/Sources/SWBCore/WorkspaceContext.swift @@ -214,8 +214,8 @@ public struct WorkspaceContextSDKRegistry: SDKRegistryLookup, Sendable { return try lookupInEach { try $0.lookup(nameOrPath: nameOrPath, basePath: basePath, activeRunDestination: activeRunDestination) } } - func synthesizedSDK(sdkManifestPath: String, triple: String) throws -> SDK? { - return try lookupInEach { try $0.synthesizedSDK(sdkManifestPath: sdkManifestPath, triple: triple) } + func synthesizedSDK(platform: Platform, sdkManifestPath: String, triple: String) throws -> SDK? { + return try lookupInEach { try $0.synthesizedSDK(platform: platform, sdkManifestPath: sdkManifestPath, triple: triple) } } } @@ -251,8 +251,8 @@ public struct WorkspaceContextSDKRegistry: SDKRegistryLookup, Sendable { return try underlyingLookup.lookup(nameOrPath: nameOrPath, basePath: basePath, activeRunDestination: activeRunDestination) } - public func synthesizedSDK(sdkManifestPath: String, triple: String) throws -> SDK? { - return try underlyingLookup.synthesizedSDK(sdkManifestPath: sdkManifestPath, triple: triple) + public func synthesizedSDK(platform: Platform, sdkManifestPath: String, triple: String) throws -> SDK? { + return try underlyingLookup.synthesizedSDK(platform: platform, sdkManifestPath: sdkManifestPath, triple: triple) } } diff --git a/Sources/SWBProtocol/MessageSupport.swift b/Sources/SWBProtocol/MessageSupport.swift index 3e75a80f..5124c9e2 100644 --- a/Sources/SWBProtocol/MessageSupport.swift +++ b/Sources/SWBProtocol/MessageSupport.swift @@ -318,27 +318,42 @@ public struct BuildParametersMessagePayload: SerializableCodable, Equatable, Sen } public struct RunDestinationInfo: SerializableCodable, Hashable, Sendable { + public var disableOnlyActiveArch: Bool + public var hostTargetedPlatform: String? + + public var buildTarget: BuildTarget? + public var platform: String public var sdk: String public var sdkVariant: String? public var targetArchitecture: String public var supportedArchitectures: OrderedSet - public var disableOnlyActiveArch: Bool - public var hostTargetedPlatform: String? - public var sdkManifestPath: String? - public var triple: String? - public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: OrderedSet, sdkManifestPath: String? = nil, triple: String? = nil, disableOnlyActiveArch: Bool, hostTargetedPlatform: String?) { + public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: OrderedSet, disableOnlyActiveArch: Bool, hostTargetedPlatform: String?) { self.platform = platform self.sdk = sdk self.sdkVariant = sdkVariant self.targetArchitecture = targetArchitecture self.supportedArchitectures = supportedArchitectures self.disableOnlyActiveArch = disableOnlyActiveArch - self.sdkManifestPath = sdkManifestPath - self.triple = triple self.hostTargetedPlatform = hostTargetedPlatform + self.buildTarget = nil } + + public init(buildTarget: BuildTarget, disableOnlyActiveArch: Bool, hostTargetedPlatform: String? = nil) { + self.platform = "" + self.sdk = "" + self.sdkVariant = nil + self.targetArchitecture = "" + self.supportedArchitectures = [] + self.buildTarget = buildTarget + self.disableOnlyActiveArch = disableOnlyActiveArch + self.hostTargetedPlatform = hostTargetedPlatform + } +} + +public enum BuildTarget: SerializableCodable, Hashable, Sendable { + case swiftSDK(sdkManifestPath: String, triple: String) } /// The arena info being sent in a Message. diff --git a/Sources/SwiftBuild/SWBBuildParameters.swift b/Sources/SwiftBuild/SWBBuildParameters.swift index 17af2cac..c3a8ca81 100644 --- a/Sources/SwiftBuild/SWBBuildParameters.swift +++ b/Sources/SwiftBuild/SWBBuildParameters.swift @@ -36,15 +36,47 @@ public struct SWBBuildParameters: Codable, Sendable { /// Refer to `SWBProtocol.RunDestinationInfo` public struct SWBRunDestinationInfo: Codable, Sendable { + public enum SWBBuildTarget: Codable, Sendable { + case appleSDK(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String]) + case swiftSDK(sdkManifestPath: String, triple: String) + } + public var disableOnlyActiveArch: Bool + public var hostTargetedPlatform: String? + + public var _internalBuildTarget: SWBBuildTarget? + + public var buildTarget: SWBBuildTarget { + get { + if let bt = _internalBuildTarget { + return bt + } + + return .appleSDK(platform: self.platform, sdk: self.sdk, sdkVariant: self.sdkVariant, targetArchitecture: self.targetArchitecture, supportedArchitectures: self.supportedArchitectures) + } + set { + switch newValue { + case let .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant, targetArchitecture: targetArchitecture, supportedArchitectures: supportedArchitectures): + self.platform = platform + self.sdk = sdk + self.sdkVariant = sdkVariant + self.targetArchitecture = targetArchitecture + self.supportedArchitectures = supportedArchitectures + case .swiftSDK: + self._internalBuildTarget = newValue + self.platform = "" + self.sdk = "" + self.sdkVariant = nil + self.targetArchitecture = "" + self.supportedArchitectures = [] + } + } + } + public var platform: String public var sdk: String public var sdkVariant: String? public var targetArchitecture: String public var supportedArchitectures: [String] - public var disableOnlyActiveArch: Bool - public var hostTargetedPlatform: String? - public var sdkManifestPath: String? - public var triple: String? public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], disableOnlyActiveArch: Bool) { self.platform = platform @@ -55,11 +87,30 @@ public struct SWBRunDestinationInfo: Codable, Sendable { self.disableOnlyActiveArch = disableOnlyActiveArch } - public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], sdkManifestPath: String? = nil, triple: String? = nil, disableOnlyActiveArch: Bool, hostTargetedPlatform: String?) { + public init(buildTarget: SWBBuildTarget, disableOnlyActiveArch: Bool, hostTargetedPlatform: String? = nil) { + switch buildTarget { + case let .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant, targetArchitecture: targetArchitecture, supportedArchitectures: supportedArchitectures): + self.platform = platform + self.sdk = sdk + self.sdkVariant = sdkVariant + self.targetArchitecture = targetArchitecture + self.supportedArchitectures = supportedArchitectures + break + case .swiftSDK: + self._internalBuildTarget = buildTarget + self.platform = "" + self.sdk = "" + self.sdkVariant = nil + self.targetArchitecture = "" + self.supportedArchitectures = [] + } + self.disableOnlyActiveArch = disableOnlyActiveArch + self.hostTargetedPlatform = hostTargetedPlatform + } + + public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], disableOnlyActiveArch: Bool, hostTargetedPlatform: String?) { self.init(platform: platform, sdk: sdk, sdkVariant: sdkVariant, targetArchitecture: targetArchitecture, supportedArchitectures: supportedArchitectures, disableOnlyActiveArch: disableOnlyActiveArch) self.hostTargetedPlatform = hostTargetedPlatform - self.sdkManifestPath = sdkManifestPath - self.triple = triple } } diff --git a/Sources/SwiftBuild/SWBBuildServiceSession.swift b/Sources/SwiftBuild/SWBBuildServiceSession.swift index c080a2c2..dcd31b87 100644 --- a/Sources/SwiftBuild/SWBBuildServiceSession.swift +++ b/Sources/SwiftBuild/SWBBuildServiceSession.swift @@ -838,7 +838,12 @@ extension SWBBuildParameters { fileprivate extension RunDestinationInfo { init(_ x: SWBRunDestinationInfo) { - self.init(platform: x.platform, sdk: x.sdk, sdkVariant: x.sdkVariant, targetArchitecture: x.targetArchitecture, supportedArchitectures: OrderedSet(x.supportedArchitectures), sdkManifestPath: x.sdkManifestPath, triple: x.triple, disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) + switch x.buildTarget { + case .appleSDK: + self.init(platform: x.platform, sdk: x.sdk, sdkVariant: x.sdkVariant, targetArchitecture: x.targetArchitecture, supportedArchitectures: OrderedSet(x.supportedArchitectures), disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) + case let .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple): + self.init(buildTarget: .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple), disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) + } } } From ba56abd78acb017c3b6e917ad9eccc5deb08f4ef Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Fri, 12 Dec 2025 13:07:03 -0500 Subject: [PATCH 13/18] Move the workaround for the UnixLd removal of the -sdk link argument into WasmLd --- Sources/SWBGenericUnixPlatform/Specs/UnixLd.xcspec | 2 +- Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Sources/SWBGenericUnixPlatform/Specs/UnixLd.xcspec b/Sources/SWBGenericUnixPlatform/Specs/UnixLd.xcspec index 17cb0952..b408bd89 100644 --- a/Sources/SWBGenericUnixPlatform/Specs/UnixLd.xcspec +++ b/Sources/SWBGenericUnixPlatform/Specs/UnixLd.xcspec @@ -63,7 +63,7 @@ Type = Path; DefaultValue = "$(SYSROOT:default=$(SDKROOT))"; Condition = "$(LINKER_DRIVER) == swiftc"; - CommandLineArgs = ("-sysroot", "$(SWIFTC_SDKROOT_LINKER_INPUT)", "-sdk", "$(SWIFTC_SDKROOT_LINKER_INPUT)"); + CommandLineFlag = "-sysroot"; IsInputDependency = Yes; }, { diff --git a/Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec b/Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec index 985dfc97..dc6ba13a 100644 --- a/Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec +++ b/Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec @@ -137,6 +137,14 @@ Type = Path; DefaultValue = ""; }, + { + Name = SWIFTC_SDKROOT_LINKER_INPUT; + Type = Path; + DefaultValue = "$(SYSROOT:default=$(SDKROOT))"; + Condition = "$(LINKER_DRIVER) == swiftc"; + CommandLineFlag = "-sdk"; + IsInputDependency = Yes; + }, { Name = "__INPUT_FILE_LIST_PATH__"; Type = Path; From 2d0236470fb87c5f17ca50044671b02842ee676b Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 16 Dec 2025 10:37:39 -0500 Subject: [PATCH 14/18] Rework the SWBBuildTarget API into a struct instead of an enum Fix the SDKROOT default value --- Sources/SWBCore/BuildRequestContext.swift | 16 +- Sources/SWBCore/ConfiguredTarget.swift | 19 ++- Sources/SWBCore/DependencyResolution.swift | 31 ++-- Sources/SWBCore/SDKRegistry.swift | 13 +- Sources/SWBCore/Settings/Settings.swift | 37 ++-- Sources/SWBProtocol/MessageSupport.swift | 29 +--- .../StaleFileRemovalContext.swift | 6 +- Sources/SWBTaskExecution/ProjectPlanner.swift | 2 +- .../ValidateProductTaskAction.swift | 2 +- .../RunDestinationTestSupport.swift | 60 +++++-- .../Specs/WasmLd.xcspec | 2 +- Sources/SwiftBuild/SWBBuildParameters.swift | 161 ++++++++++++------ .../SwiftBuild/SWBBuildServiceSession.swift | 11 +- .../MessageSerializationTests.swift | 8 +- 14 files changed, 260 insertions(+), 137 deletions(-) diff --git a/Sources/SWBCore/BuildRequestContext.swift b/Sources/SWBCore/BuildRequestContext.swift index d971d45c..f8939fe5 100644 --- a/Sources/SWBCore/BuildRequestContext.swift +++ b/Sources/SWBCore/BuildRequestContext.swift @@ -197,10 +197,11 @@ extension BuildRequestContext { func platformAndSDKVariant(for target: ConfiguredTarget) -> PlatformAndSDKVariant { if hasEnabledIndexBuildArena, let activeRunDestination = target.parameters.activeRunDestination, - let platform = workspaceContext.core.platformRegistry.lookup(name: activeRunDestination.platform) { + case let .appleSDK(platform: platform, _, sdkVariant: sdkVariant) = activeRunDestination.buildTarget, + let platform = workspaceContext.core.platformRegistry.lookup(name: platform) { // Configured targets include their platform in parameters, we can use it directly and avoid the expense of `getCachedSettings()` calls. // If in future `ConfiguredTarget` carries along an instance of its Settings, we can avoid this check and go back to using `Settings` without the cost of `getCachedSettings`. - return PlatformAndSDKVariant(platform: platform, sdkVariant: activeRunDestination.sdkVariant) + return PlatformAndSDKVariant(platform: platform, sdkVariant: sdkVariant) } else { let settings = getCachedSettings(target.parameters, target: target.target) return PlatformAndSDKVariant(platform: settings.platform, sdkVariant: settings.sdkVariant?.name) @@ -249,9 +250,14 @@ extension BuildRequestContext { guard let destination = runDestination else { return selectWithoutRunDestination() } - if matchesPlatform(lhsPlatform, platformName: destination.platform, sdkVariant: destination.sdkVariant) { return lhs } - if matchesPlatform(rhsPlatform, platformName: destination.platform, sdkVariant: destination.sdkVariant) { return rhs } - guard let destinationPlatform = workspaceContext.core.platformRegistry.lookup(name: destination.platform) else { + + guard case let .appleSDK(platform: platform, _, sdkVariant: sdkVariant) = destination.buildTarget else { + return selectWithoutRunDestination() + } + + if matchesPlatform(lhsPlatform, platformName: platform, sdkVariant: sdkVariant) { return lhs } + if matchesPlatform(rhsPlatform, platformName: platform, sdkVariant: sdkVariant) { return rhs } + guard let destinationPlatform = workspaceContext.core.platformRegistry.lookup(name: platform) else { return selectWithoutRunDestination() } if lhsPlatform.platform?.familyName != rhsPlatform.platform?.familyName { diff --git a/Sources/SWBCore/ConfiguredTarget.swift b/Sources/SWBCore/ConfiguredTarget.swift index 5ab5c0c5..685c22f0 100644 --- a/Sources/SWBCore/ConfiguredTarget.swift +++ b/Sources/SWBCore/ConfiguredTarget.swift @@ -65,9 +65,11 @@ public final class ConfiguredTarget: Hashable, CustomStringConvertible, Serializ if !parameters.isEmpty { components.append(("parameters", parameters.joined(separator: "-"))) } - if specializeGuidForActiveRunDestination, let runDestination = self.parameters.activeRunDestination { - var runDestString = runDestination.platform - if let sdkVariant = runDestination.sdkVariant { + if specializeGuidForActiveRunDestination, + let runDestination = self.parameters.activeRunDestination, + case let .appleSDK(platform: platform, _, sdkVariant: sdkVariant) = runDestination.buildTarget { + var runDestString = platform + if let sdkVariant = sdkVariant { runDestString += "+\(sdkVariant)" } components.append(("runDestination", runDestString)) @@ -106,8 +108,17 @@ public final class ConfiguredTarget: Hashable, CustomStringConvertible, Serializ return nil } } + if specializeGuidForActiveRunDestination { - let discriminator = self.parameters.activeRunDestination.map{ "\($0.platform)-\($0.sdkVariant ?? "")" } ?? "" + let discriminator: String + switch self.parameters.activeRunDestination?.buildTarget { + case let .appleSDK(platform: platform, _, sdkVariant: sdkVariant): + discriminator = "\(platform)-\(sdkVariant ?? "")" + case let .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple): + discriminator = "\(sdkManifestPath)-\(triple)" + default: + discriminator = "" + } parameters.append(discriminator) } return .init(id: ["target", target.name, target.guid, parameters.joined(separator: ":")].joined(separator: "-")) diff --git a/Sources/SWBCore/DependencyResolution.swift b/Sources/SWBCore/DependencyResolution.swift index 80343091..dd1f7c16 100644 --- a/Sources/SWBCore/DependencyResolution.swift +++ b/Sources/SWBCore/DependencyResolution.swift @@ -213,7 +213,7 @@ struct SpecializationParameters: Hashable, CustomStringConvertible { overrides["SUPPORTS_MACCATALYST"] = sdkVariant.name == MacCatalystInfo.sdkVariantName ? "YES" : "NO" } if let supportedPlatforms { - if let platform = parameters.activeRunDestination?.platform { + if case let .appleSDK(platform: platform, _, _) = parameters.activeRunDestination?.buildTarget { // If the specialization matches the platform of the active run destination, we do not need to impose it. if !supportedPlatforms.contains(platform) { overrides["SUPPORTED_PLATFORMS"] = supportedPlatforms.joined(separator: " ") @@ -258,9 +258,12 @@ struct SpecializationParameters: Hashable, CustomStringConvertible { // This seems like an unfortunate way to get from the SDK to its platform. But SettingsBuilder.computeBoundProperties() creates a scope to evaluate the PLATFORM_NAME defined in the SDK's default properties, so maybe there isn't a clearly better way. if let overridingSdk, let overridingPlatform = workspaceContext.core.platformRegistry.platforms.filter({ $0.sdks.contains(where: { $0.canonicalName == overridingSdk.canonicalName }) }).first { platformName = overridingPlatform.name + } else if case let .appleSDK(platform: platform, _, _) = parameters.activeRunDestination?.buildTarget { + platformName = platform } else { - platformName = parameters.activeRunDestination?.platform + platformName = nil } + if platformName == nil { if let overridingSdk = overridingSdk { let platformNames = workspaceContext.core.platformRegistry.platforms.map { $0.name } @@ -272,7 +275,7 @@ struct SpecializationParameters: Hashable, CustomStringConvertible { // Otherwise there was no overriding SDK provided, and there is no active run destination (or somehow there's a destination without a platform). This is valid, but it's not clear to me what this means for specialization parameters. } let sdkSuffix: String? - if let sdk = parameters.activeRunDestination?.sdk { + if case let .appleSDK(_, sdk: sdk, _) = parameters.activeRunDestination?.buildTarget { if let suffix = try? workspaceContext.sdkRegistry.lookup(sdk, activeRunDestination: parameters.activeRunDestination)?.canonicalNameSuffix, !suffix.isEmpty { sdkSuffix = suffix } else { @@ -282,7 +285,13 @@ struct SpecializationParameters: Hashable, CustomStringConvertible { } else { sdkSuffix = nil } - self.init(workspaceContext: workspaceContext, platformName: platformName, sdkVariantName: parameters.activeRunDestination?.sdkVariant, canonicalNameSuffix: sdkSuffix, diagnostics: diagnostics) + let sdkVariantName: String? + if case let .appleSDK(_, _, sdkVariant: sdkVariant) = parameters.activeRunDestination?.buildTarget { + sdkVariantName = sdkVariant + } else { + sdkVariantName = nil + } + self.init(workspaceContext: workspaceContext, platformName: platformName, sdkVariantName: sdkVariantName, canonicalNameSuffix: sdkSuffix, diagnostics: diagnostics) } fileprivate init(workspaceContext: WorkspaceContext, platformName: String?, sdkVariantName: String?, canonicalNameSuffix: String?, diagnostics: [Diagnostic] = []) { @@ -532,12 +541,12 @@ extension SpecializationParameters { let archName: String = platform.determineDefaultArchForIndexArena(preferredArch: workspaceContext.systemInfo?.nativeArchitecture, using: workspaceContext.core) ?? "unknown_arch" for sdkVariant in matchingSDK.variants.keys.sorted() { - let runDestination = RunDestinationInfo(platform: platform.name, sdk: matchingSDK.canonicalName, sdkVariant: sdkVariant, targetArchitecture: archName, supportedArchitectures: [archName], disableOnlyActiveArch: false, hostTargetedPlatform: nil) + let runDestination = RunDestinationInfo(buildTarget: .appleSDK(platform: platform.name, sdk: matchingSDK.canonicalName, sdkVariant: sdkVariant), targetArchitecture: archName, supportedArchitectures: [archName], disableOnlyActiveArch: false, hostTargetedPlatform: nil) let buildParams = buildRequest.parameters.replacing(activeRunDestination: runDestination, activeArchitecture: archName) let specializationParams = SpecializationParameters.default(workspaceContext: workspaceContext, buildRequestContext: buildRequestContext, parameters: buildParams) platformBuildParameters.append(PlatformBuildParameters(buildParams: buildParams, specializationParams: specializationParams)) - if runDestination.platform == hostOS && runDestination.sdkVariant == matchingSDK.defaultVariant?.name { + if platform.name == hostOS && sdkVariant == matchingSDK.defaultVariant?.name { hostBuildParameters = platformBuildParameters.last } } @@ -594,14 +603,14 @@ extension SpecializationParameters { for platformParams in platformBuildParametersForIndex { // Before forming all new settings for this platform, do a fast check using `SUPPORTED_PLATFORMS` of `unconfiguredSettings`. // This significantly cuts down the work that this function is doing. - if platformParams.buildParams.activeRunDestination?.sdkVariant == MacCatalystInfo.sdkVariantName { + if case let .appleSDK(_, _, sdkVariant: sdkVariant) = platformParams.buildParams.activeRunDestination?.buildTarget, sdkVariant == MacCatalystInfo.sdkVariantName { // macCatalyst has various special rules, check it by forming new settings normally, below. // Carve out once small exception for host tools, which should never build for Catalyst. if let standardTarget = target as? StandardTarget, ProductTypeIdentifier(standardTarget.productTypeIdentifier).isHostBuildTool { continue } } else { - if let platformName = platformParams.buildParams.activeRunDestination?.platform, unconfiguredSupportedPlatforms.count > 0 { + if case let .appleSDK(platform: platformName, _, _) = platformParams.buildParams.activeRunDestination?.buildTarget, unconfiguredSupportedPlatforms.count > 0 { guard unconfiguredSupportedPlatforms.contains(platformName) else { continue } } } @@ -649,10 +658,10 @@ extension SpecializationParameters { guard let targetPlatform = settings.platform else { return false } - if targetPlatform.name != runDestination.platform { + if case let .appleSDK(platform: platform, _, _) = runDestination.buildTarget, targetPlatform.name != platform { return false } - if settings.sdkVariant?.name != runDestination.sdkVariant { + if case let .appleSDK(_, _, sdkVariant: sdkVariant) = runDestination.buildTarget, settings.sdkVariant?.name != sdkVariant { return false } @@ -824,7 +833,7 @@ extension SpecializationParameters { imposedSupportedPlatforms = supportedPlatforms let hostPlatform = settings.globalScope.evaluate(BuiltinMacros.HOST_PLATFORM) - let runDestinationPlatform = buildRequest.parameters.activeRunDestination?.platform + let runDestinationPlatform = if case let .appleSDK(platform: platform, _, _) = buildRequest.parameters.activeRunDestination?.buildTarget { platform } else { Optional.none } let supportedPlatformsWithoutSimulators = Set(supportedPlatforms.compactMap { self.workspaceContext.core.platformRegistry.lookup(name: $0) }.filter { !$0.isSimulator }.map { $0.name }) // If the given specialization is unsupported, we still need to impose a platform. diff --git a/Sources/SWBCore/SDKRegistry.swift b/Sources/SWBCore/SDKRegistry.swift index 0777dc4d..b3097a9b 100644 --- a/Sources/SWBCore/SDKRegistry.swift +++ b/Sources/SWBCore/SDKRegistry.swift @@ -1174,7 +1174,6 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send "GENERATE_TEXT_BASED_STUBS": "NO", "GENERATE_INTERMEDIATE_TEXT_BASED_STUBS": "NO", - // TODO check how this impacts operation on Windows "CHOWN": "/usr/bin/chown", // TODO are these going to be appropriate for all kinds of SDK's? @@ -1295,7 +1294,14 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send // If we got here, we have DriverKit SDKs (the only ones which use cohort platforms) for multiple cohort platforms. Narrow down the list by disambiguating using the run destination. func selectSDKList() -> [SDK]? { - if let list = sdksByCohortPlatform[activeRunDestination?.platform] { + let platform: String? + if case let .appleSDK(platform: p, _, _) = activeRunDestination?.buildTarget { + platform = p + } else { + platform = nil + } + + if let list = sdksByCohortPlatform[platform] { return list } @@ -1303,7 +1309,8 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send // by the cohort platforms of the run destination's SDK's platform. This is necessary to resolve // driverkit when we have a DriverKit run destination but with a platform-specific SDK. if let runDestination = activeRunDestination, - let cohortPlatforms = try? lookup(runDestination.sdk, activeRunDestination: nil)?.cohortPlatforms { + case let .appleSDK(_, sdk: sdk, _) = runDestination.buildTarget, + let cohortPlatforms = try? lookup(sdk, activeRunDestination: nil)?.cohortPlatforms { for cohortPlatform in cohortPlatforms { if let list = sdksByCohortPlatform[cohortPlatform] { return list diff --git a/Sources/SWBCore/Settings/Settings.swift b/Sources/SWBCore/Settings/Settings.swift index 24c20d7b..08924ca0 100644 --- a/Sources/SWBCore/Settings/Settings.swift +++ b/Sources/SWBCore/Settings/Settings.swift @@ -1521,9 +1521,10 @@ private class SettingsBuilder: ProjectMatchLookup { // Add the SDK overrides. if let sdk = boundProperties.sdk { let scope = createScope(sdkToUse: sdk) - let destinationIsMacCatalyst = parameters.activeRunDestination?.sdkVariant == MacCatalystInfo.sdkVariantName let supportsMacCatalyst = Settings.supportsMacCatalyst(scope: scope, core: core) - if destinationIsMacCatalyst && supportsMacCatalyst { + if case let .appleSDK(platform: _, sdk: _, sdkVariant: sdkVariant) = parameters.activeRunDestination?.buildTarget, + sdkVariant == MacCatalystInfo.sdkVariantName, + supportsMacCatalyst { pushTable(.exported) { $0.push(BuiltinMacros.SUPPORTED_PLATFORMS, BuiltinMacros.namespace.parseStringList(["$(inherited)", "macosx"])) } @@ -1782,8 +1783,9 @@ private class SettingsBuilder: ProjectMatchLookup { // We will replace SDKROOT values of "auto" here if the run destination is compatible. let usesReplaceableAutomaticSDKRoot: Bool - if sdkroot == "auto", let activePlatform = parameters.activeRunDestination?.platform { - let destinationIsMacCatalyst = parameters.activeRunDestination?.sdkVariant == MacCatalystInfo.sdkVariantName + if sdkroot == "auto", + case let .appleSDK(platform: activePlatform, sdk: _, sdkVariant: sdkVariant) = parameters.activeRunDestination?.buildTarget { + let destinationIsMacCatalyst = sdkVariant == MacCatalystInfo.sdkVariantName let scope = createScope(effectiveTargetConfig, sdkToUse: sdk) let supportedPlatforms = scope.evaluate(BuiltinMacros.SUPPORTED_PLATFORMS) @@ -1798,7 +1800,8 @@ private class SettingsBuilder: ProjectMatchLookup { } else { usesReplaceableAutomaticSDKRoot = false } - if usesReplaceableAutomaticSDKRoot, let activeSDK = parameters.activeRunDestination?.sdk { + if usesReplaceableAutomaticSDKRoot, + case let .appleSDK(platform: _, sdk: activeSDK, sdkVariant: _) = parameters.activeRunDestination?.buildTarget { sdkroot = activeSDK } @@ -1824,7 +1827,7 @@ private class SettingsBuilder: ProjectMatchLookup { if let s = sdk { // Evaluate the SDK variant, if there is one. let sdkVariantName: String - if usesReplaceableAutomaticSDKRoot, let activeSDKVariant = parameters.activeRunDestination?.sdkVariant { + if usesReplaceableAutomaticSDKRoot, case let .appleSDK(platform: _, sdk: _, sdkVariant: activeSDKVariant) = parameters.activeRunDestination?.buildTarget, let activeSDKVariant { sdkVariantName = activeSDKVariant } else { sdkVariantName = createScope(effectiveTargetConfig, sdkToUse: s).evaluate(BuiltinMacros.SDK_VARIANT) @@ -3543,19 +3546,19 @@ private class SettingsBuilder: ProjectMatchLookup { return } destinationSDK = sdk - default: - guard let platform = self.core.platformRegistry.lookup(name: runDestination.platform) else { - self.errors.append("unable to resolve run destination platform: '\(runDestination.platform)'") + case let .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant): + guard let platform = self.core.platformRegistry.lookup(name: platform) else { + self.errors.append("unable to resolve run destination platform: '\(platform)'") return } destinationPlatform = platform do { - if let sdk = try sdkRegistry.lookup(runDestination.sdk, activeRunDestination: runDestination) { + if let sdk = try sdkRegistry.lookup(sdk, activeRunDestination: runDestination) { destinationSDK = sdk } else { - self.errors.append("unable to resolve run destination SDK: '\(runDestination.sdk)'") + self.errors.append("unable to resolve run destination SDK: '\(sdk)'") return } } catch let error as AmbiguousSDKLookupError { @@ -3577,7 +3580,9 @@ private class SettingsBuilder: ProjectMatchLookup { do { let scope = createScope(sdkToUse: nil) - let destinationIsMacCatalyst = runDestination.sdkVariant == MacCatalystInfo.sdkVariantName + let destinationIsMacCatalyst = if case let .appleSDK(platform: _, sdk: _, sdkVariant: sdkVariant) = runDestination.buildTarget { + sdkVariant == MacCatalystInfo.sdkVariantName + } else { false } let supportsMacCatalyst = Settings.supportsMacCatalyst(scope: scope, core: core) if destinationIsMacCatalyst && supportsMacCatalyst { pushTable(.exported) { @@ -3682,13 +3687,13 @@ private class SettingsBuilder: ProjectMatchLookup { case .swiftSDK: // TODO use the triple to decide the platform, or use a fallback guard let platform: Platform = self.core.platformRegistry.lookup(name: "webassembly") else { - self.errors.append("unable to resolve run destination platform: '\(runDestination.platform)'") + self.errors.append("unable to resolve run destination platform: 'webassembly'") return } destinationPlatform = platform - default: - guard let platform: Platform = self.core.platformRegistry.lookup(name: runDestination.platform) else { - self.errors.append("unable to resolve run destination platform: '\(runDestination.platform)'") + case let .appleSDK(platform: platformName, sdk: _, sdkVariant: _): + guard let platform: Platform = self.core.platformRegistry.lookup(name: platformName) else { + self.errors.append("unable to resolve run destination platform: '\(platformName)'") return } destinationPlatform = platform diff --git a/Sources/SWBProtocol/MessageSupport.swift b/Sources/SWBProtocol/MessageSupport.swift index 5124c9e2..04578422 100644 --- a/Sources/SWBProtocol/MessageSupport.swift +++ b/Sources/SWBProtocol/MessageSupport.swift @@ -318,41 +318,24 @@ public struct BuildParametersMessagePayload: SerializableCodable, Equatable, Sen } public struct RunDestinationInfo: SerializableCodable, Hashable, Sendable { - public var disableOnlyActiveArch: Bool - public var hostTargetedPlatform: String? - - public var buildTarget: BuildTarget? + public var buildTarget: BuildTarget - public var platform: String - public var sdk: String - public var sdkVariant: String? public var targetArchitecture: String public var supportedArchitectures: OrderedSet + public var disableOnlyActiveArch: Bool + public var hostTargetedPlatform: String? - public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: OrderedSet, disableOnlyActiveArch: Bool, hostTargetedPlatform: String?) { - self.platform = platform - self.sdk = sdk - self.sdkVariant = sdkVariant + public init(buildTarget: BuildTarget, targetArchitecture: String, supportedArchitectures: OrderedSet, disableOnlyActiveArch: Bool, hostTargetedPlatform: String? = nil) { + self.buildTarget = buildTarget self.targetArchitecture = targetArchitecture self.supportedArchitectures = supportedArchitectures self.disableOnlyActiveArch = disableOnlyActiveArch self.hostTargetedPlatform = hostTargetedPlatform - self.buildTarget = nil - } - - public init(buildTarget: BuildTarget, disableOnlyActiveArch: Bool, hostTargetedPlatform: String? = nil) { - self.platform = "" - self.sdk = "" - self.sdkVariant = nil - self.targetArchitecture = "" - self.supportedArchitectures = [] - self.buildTarget = buildTarget - self.disableOnlyActiveArch = disableOnlyActiveArch - self.hostTargetedPlatform = hostTargetedPlatform } } public enum BuildTarget: SerializableCodable, Hashable, Sendable { + case appleSDK(platform: String, sdk: String, sdkVariant: String?) case swiftSDK(sdkManifestPath: String, triple: String) } diff --git a/Sources/SWBTaskConstruction/StaleFileRemovalContext.swift b/Sources/SWBTaskConstruction/StaleFileRemovalContext.swift index 3c742681..841a3e76 100644 --- a/Sources/SWBTaskConstruction/StaleFileRemovalContext.swift +++ b/Sources/SWBTaskConstruction/StaleFileRemovalContext.swift @@ -60,9 +60,9 @@ extension StaleFileRemovalContext { } else { staleFileRemovalIdentifier += "workspace" staleFileRemovalIdentifier += "-\(globalProductPlan.planRequest.buildRequest.parameters.configuration ?? "none")" - if let destination = globalProductPlan.planRequest.buildRequest.parameters.activeRunDestination { - staleFileRemovalIdentifier += "-\(destination.sdk)" - if let variant = destination.sdkVariant { + if case let .appleSDK(_, sdk: sdk, sdkVariant: variant) = globalProductPlan.planRequest.buildRequest.parameters.activeRunDestination?.buildTarget { + staleFileRemovalIdentifier += "-\(sdk)" + if let variant { staleFileRemovalIdentifier += "-\(variant)" } } diff --git a/Sources/SWBTaskExecution/ProjectPlanner.swift b/Sources/SWBTaskExecution/ProjectPlanner.swift index 287c35b7..f48f5fa2 100644 --- a/Sources/SWBTaskExecution/ProjectPlanner.swift +++ b/Sources/SWBTaskExecution/ProjectPlanner.swift @@ -136,6 +136,6 @@ private extension BuildParameters { // All relevant platforms define a preferredArch, so the undefined_arch fallback case should never happen // in practice, and indicates a serious issue occurred during plugin loading. let targetArchitecture = platform.preferredArch ?? "undefined_arch" - return RunDestinationInfo(platform: platform.name, sdk: platform.name, sdkVariant: nil, targetArchitecture: targetArchitecture, supportedArchitectures: [targetArchitecture], disableOnlyActiveArch: false, hostTargetedPlatform: nil) + return RunDestinationInfo(buildTarget: .appleSDK(platform: platform.name, sdk: platform.name, sdkVariant: nil), targetArchitecture: targetArchitecture, supportedArchitectures: [targetArchitecture], disableOnlyActiveArch: false, hostTargetedPlatform: nil) } } diff --git a/Sources/SWBTaskExecution/TaskActions/ValidateProductTaskAction.swift b/Sources/SWBTaskExecution/TaskActions/ValidateProductTaskAction.swift index 398f01ee..a910712d 100644 --- a/Sources/SWBTaskExecution/TaskActions/ValidateProductTaskAction.swift +++ b/Sources/SWBTaskExecution/TaskActions/ValidateProductTaskAction.swift @@ -188,7 +188,7 @@ public final class ValidateProductTaskAction: TaskAction { // Validate the iPad multitasking/splitview support in the Info.plist. This never causes the tool to fail, but it may emit warnings. validateiPadMultiTaskingSplitViewSupport(infoPlist, outputDelegate: outputDelegate) - if let configuredTarget = task.forTarget, let platform = configuredTarget.parameters.activeRunDestination?.platform { + if let configuredTarget = task.forTarget, case let .appleSDK(platform: platform, _, _) = configuredTarget.parameters.activeRunDestination?.buildTarget { // Validate that this is actually an App Store category. validateAppStoreCategory(infoPlist, platform: platform, targetName: configuredTarget.target.name, schemeCommand: executionDelegate.schemeCommand, options: options, outputDelegate: outputDelegate) diff --git a/Sources/SWBTestSupport/RunDestinationTestSupport.swift b/Sources/SWBTestSupport/RunDestinationTestSupport.swift index fa29f90c..1e89c82c 100644 --- a/Sources/SWBTestSupport/RunDestinationTestSupport.swift +++ b/Sources/SWBTestSupport/RunDestinationTestSupport.swift @@ -19,6 +19,7 @@ import Foundation package protocol _RunDestinationInfo { init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], disableOnlyActiveArch: Bool) + // These assume that this is an Apple SDK build target, otherwise you get default values var platform: String { get } var sdk: String { get } var sdkVariant: String? { get } @@ -299,20 +300,28 @@ extension RunDestinationInfo { /// /// - note: Returns `nil` for non-Mach-O platforms such as Linux. package func buildVersionPlatform(_ core: Core) -> BuildVersion.Platform? { - guard let sdk = try? core.sdkRegistry.lookup(sdk, activeRunDestination: self) else { return nil } + guard case let .appleSDK(_, sdk: sdk, sdkVariant: sdkVariant) = buildTarget, + let sdk = try? core.sdkRegistry.lookup(sdk, activeRunDestination: self) else { + return nil + } return sdk.targetBuildVersionPlatform(sdkVariant: sdkVariant.map { sdkVariant in sdk.variant(for: sdkVariant) } ?? sdk.defaultVariant) } package func imageFormat(_ core: Core) -> ImageFormat { - switch platform { - case "webassembly": + switch buildTarget { + case let .appleSDK(platform: platform, _, _): + switch platform { + case "webassembly": + fatalError("not implemented") + case "windows": + return .pe + case _ where buildVersionPlatform(core) != nil: + return .macho + default: + return .elf + } + case .swiftSDK: fatalError("not implemented") - case "windows": - return .pe - case _ where buildVersionPlatform(core) != nil: - return .macho - default: - return .elf } } @@ -326,7 +335,12 @@ extension RunDestinationInfo { } switch imageFormat(core) { case .elf: - environment.prependPath(key: "LD_LIBRARY_PATH", value: toolchain.path.join("usr/lib/swift/\(platform)").str) + if case let .appleSDK(platform: platform, _, _) = buildTarget { + environment.prependPath(key: "LD_LIBRARY_PATH", value: toolchain.path.join("usr/lib/swift/\(platform)").str) + } else { + // Fall back to the OS provided Swift runtime + break + } case .pe: environment.prependPath(key: .path, value: core.developerPath.path.join("Runtimes").join(toolchain.version.description).join("usr/bin").str) case .macho: @@ -385,6 +399,30 @@ extension _RunDestinationInfo { extension RunDestinationInfo: _RunDestinationInfo { package init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], disableOnlyActiveArch: Bool) { - self.init(platform: platform, sdk: sdk, sdkVariant: sdkVariant, targetArchitecture: targetArchitecture, supportedArchitectures: OrderedSet(supportedArchitectures), disableOnlyActiveArch: disableOnlyActiveArch, hostTargetedPlatform: nil) + self.init(buildTarget: .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant), targetArchitecture: targetArchitecture, supportedArchitectures: OrderedSet(supportedArchitectures), disableOnlyActiveArch: disableOnlyActiveArch, hostTargetedPlatform: nil) + } + + package var platform: String { + guard case let .appleSDK(platform: platform, _, _) = buildTarget else { + return "" + } + + return platform + } + + package var sdk: String { + guard case let .appleSDK(_, sdk: sdk, _) = buildTarget else { + return "" + } + + return sdk + } + + package var sdkVariant: String? { + guard case let .appleSDK(_, _, sdkVariant: sdkVariant) = buildTarget else { + return nil + } + + return sdkVariant } } diff --git a/Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec b/Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec index dc6ba13a..297675ea 100644 --- a/Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec +++ b/Sources/SWBWebAssemblyPlatform/Specs/WasmLd.xcspec @@ -140,7 +140,7 @@ { Name = SWIFTC_SDKROOT_LINKER_INPUT; Type = Path; - DefaultValue = "$(SYSROOT:default=$(SDKROOT))"; + DefaultValue = "$(SDKROOT)"; Condition = "$(LINKER_DRIVER) == swiftc"; CommandLineFlag = "-sdk"; IsInputDependency = Yes; diff --git a/Sources/SwiftBuild/SWBBuildParameters.swift b/Sources/SwiftBuild/SWBBuildParameters.swift index c3a8ca81..fbc8f467 100644 --- a/Sources/SwiftBuild/SWBBuildParameters.swift +++ b/Sources/SwiftBuild/SWBBuildParameters.swift @@ -36,74 +36,78 @@ public struct SWBBuildParameters: Codable, Sendable { /// Refer to `SWBProtocol.RunDestinationInfo` public struct SWBRunDestinationInfo: Codable, Sendable { - public enum SWBBuildTarget: Codable, Sendable { - case appleSDK(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String]) - case swiftSDK(sdkManifestPath: String, triple: String) - } - public var disableOnlyActiveArch: Bool - public var hostTargetedPlatform: String? + public struct SWBBuildTarget: Codable, Sendable { + fileprivate var _internalBuildTarget: InternalBuildTarget - public var _internalBuildTarget: SWBBuildTarget? + public static func appleSDK(platform: String, sdk: String, sdkVariant: String?) -> SWBBuildTarget { + SWBBuildTarget(_internalBuildTarget: .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant)) + } + + public static func swiftSDK(sdkManifestPath: String, triple: String) -> SWBBuildTarget { + SWBBuildTarget(_internalBuildTarget: .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple)) + } - public var buildTarget: SWBBuildTarget { - get { - if let bt = _internalBuildTarget { - return bt + public func asAppleSDK() -> (platform: String, sdk: String, sdkVariant: String?)? { + guard case let .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant) = _internalBuildTarget else { + return nil } - return .appleSDK(platform: self.platform, sdk: self.sdk, sdkVariant: self.sdkVariant, targetArchitecture: self.targetArchitecture, supportedArchitectures: self.supportedArchitectures) + return (platform: platform, sdk: sdk, sdkVariant: sdkVariant) } - set { - switch newValue { - case let .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant, targetArchitecture: targetArchitecture, supportedArchitectures: supportedArchitectures): - self.platform = platform - self.sdk = sdk - self.sdkVariant = sdkVariant - self.targetArchitecture = targetArchitecture - self.supportedArchitectures = supportedArchitectures - case .swiftSDK: - self._internalBuildTarget = newValue - self.platform = "" - self.sdk = "" - self.sdkVariant = nil - self.targetArchitecture = "" - self.supportedArchitectures = [] + + public func asSwiftSDK() -> (sdkManifestPath: String, triple: String)? { + guard case let .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple) = _internalBuildTarget else { + return nil } + + return (sdkManifestPath: sdkManifestPath, triple: triple) } } - public var platform: String - public var sdk: String - public var sdkVariant: String? + public var buildTarget: SWBBuildTarget public var targetArchitecture: String public var supportedArchitectures: [String] + public var disableOnlyActiveArch: Bool + public var hostTargetedPlatform: String? + + @available(*, deprecated, message: "Use buildTarget and match on the appleSDK case instead") + public var platform: String { + guard case let .appleSDK(platform: platform, _, _) = buildTarget._internalBuildTarget else { + return "" + } + + return platform + } + + @available(*, deprecated, message: "Use buildTarget and match on the appleSDK case instead") + public var sdk: String { + guard case let .appleSDK(_, sdk: sdk, _) = buildTarget._internalBuildTarget else { + return "" + } + + return sdk + } + + @available(*, deprecated, message: "Use buildTarget and match on the appleSDK case instead") + public var sdkVariant: String? { + guard case let .appleSDK(_, _, sdkVariant: sdkVariant) = buildTarget._internalBuildTarget else { + return nil + } + + return sdkVariant + } public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], disableOnlyActiveArch: Bool) { - self.platform = platform - self.sdk = sdk - self.sdkVariant = sdkVariant + self.buildTarget = .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant) self.targetArchitecture = targetArchitecture self.supportedArchitectures = supportedArchitectures self.disableOnlyActiveArch = disableOnlyActiveArch } - public init(buildTarget: SWBBuildTarget, disableOnlyActiveArch: Bool, hostTargetedPlatform: String? = nil) { - switch buildTarget { - case let .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant, targetArchitecture: targetArchitecture, supportedArchitectures: supportedArchitectures): - self.platform = platform - self.sdk = sdk - self.sdkVariant = sdkVariant - self.targetArchitecture = targetArchitecture - self.supportedArchitectures = supportedArchitectures - break - case .swiftSDK: - self._internalBuildTarget = buildTarget - self.platform = "" - self.sdk = "" - self.sdkVariant = nil - self.targetArchitecture = "" - self.supportedArchitectures = [] - } + public init(buildTarget: SWBBuildTarget, targetArchitecture: String, supportedArchitectures: [String], disableOnlyActiveArch: Bool, hostTargetedPlatform: String? = nil) { + self.buildTarget = buildTarget + self.targetArchitecture = targetArchitecture + self.supportedArchitectures = supportedArchitectures self.disableOnlyActiveArch = disableOnlyActiveArch self.hostTargetedPlatform = hostTargetedPlatform } @@ -114,6 +118,63 @@ public struct SWBRunDestinationInfo: Codable, Sendable { } } +fileprivate enum InternalBuildTarget: Codable, Sendable { + case appleSDK(platform: String, sdk: String, sdkVariant: String?) + case swiftSDK(sdkManifestPath: String, triple: String) + + private enum CodingKeys: String, CodingKey { + // Selector + case buildTarget + + // Apple SDK + case platform + case sdk + case sdkVariant + + // Swift SDK + case sdkManifestPath + case triple + } + + private enum BuildTarget: String, Codable { + case appleSDK + case swiftSDK + + init(_ buildTarget: InternalBuildTarget) { + switch buildTarget { + case .appleSDK: + self = .appleSDK + case .swiftSDK: + self = .swiftSDK + } + } + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + switch try container.decode(BuildTarget.self, forKey: .buildTarget) { + case .appleSDK: + self = try .appleSDK(platform: container.decode(String.self, forKey: .platform), sdk: container.decode(String.self, forKey: .sdk), sdkVariant: container.decode(String?.self, forKey: .sdkVariant)) + case .swiftSDK: + self = try .swiftSDK(sdkManifestPath: container.decode(String.self, forKey: .sdkManifestPath), triple: container.decode(String.self, forKey: .triple)) + } + } + + public func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(BuildTarget(self), forKey: .buildTarget) + switch self { + case let .appleSDK(platform, sdk, sdkVariant): + try container.encode(platform, forKey: .platform) + try container.encode(sdk, forKey: .sdk) + try container.encode(sdkVariant, forKey: .sdkVariant) + case let .swiftSDK(sdkManifestPath, triple): + try container.encode(sdkManifestPath, forKey: .sdkManifestPath) + try container.encode(triple, forKey: .triple) + } + } +} + /// Refer to `SWBProtocol.ArenaInfo` public struct SWBArenaInfo: Codable, Sendable { public var derivedDataPath: String diff --git a/Sources/SwiftBuild/SWBBuildServiceSession.swift b/Sources/SwiftBuild/SWBBuildServiceSession.swift index dcd31b87..5a56cdb9 100644 --- a/Sources/SwiftBuild/SWBBuildServiceSession.swift +++ b/Sources/SwiftBuild/SWBBuildServiceSession.swift @@ -838,11 +838,12 @@ extension SWBBuildParameters { fileprivate extension RunDestinationInfo { init(_ x: SWBRunDestinationInfo) { - switch x.buildTarget { - case .appleSDK: - self.init(platform: x.platform, sdk: x.sdk, sdkVariant: x.sdkVariant, targetArchitecture: x.targetArchitecture, supportedArchitectures: OrderedSet(x.supportedArchitectures), disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) - case let .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple): - self.init(buildTarget: .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple), disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) + if let appleSDK = x.buildTarget.asAppleSDK() { + self.init(buildTarget: .appleSDK(platform: appleSDK.platform, sdk: appleSDK.sdk, sdkVariant: appleSDK.sdkVariant), targetArchitecture: x.targetArchitecture, supportedArchitectures: OrderedSet(x.supportedArchitectures), disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) + } else if let swiftSDK = x.buildTarget.asSwiftSDK() { + self.init(buildTarget: .swiftSDK(sdkManifestPath: swiftSDK.sdkManifestPath, triple: swiftSDK.triple), targetArchitecture: x.targetArchitecture, supportedArchitectures: OrderedSet(x.supportedArchitectures), disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) + } else { + fatalError("not implemented") } } } diff --git a/Tests/SWBProtocolTests/MessageSerializationTests.swift b/Tests/SWBProtocolTests/MessageSerializationTests.swift index 17445420..b7dfd58f 100644 --- a/Tests/SWBProtocolTests/MessageSerializationTests.swift +++ b/Tests/SWBProtocolTests/MessageSerializationTests.swift @@ -24,9 +24,11 @@ import Testing action: "build", configuration: "Debug", activeRunDestination: RunDestinationInfo( - platform: "osOS", - sdk: "osos", - sdkVariant: "x", + buildTarget: .appleSDK( + platform: "osOS", + sdk: "osos", + sdkVariant: "x", + ), targetArchitecture: "arm128", supportedArchitectures: ["arm128"], disableOnlyActiveArch: true, From afa0d524628f50c94fb0e1b85ef029b155be6bec Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 16 Dec 2025 14:39:55 -0500 Subject: [PATCH 15/18] Add a new platformName capability to PlatformInfoExtension, using that to determine platform from triple --- .../Extensions/PlatformInfoExtension.swift | 6 ++ Sources/SWBCore/Settings/Settings.swift | 63 ++++++++++++++++--- Sources/SWBWebAssemblyPlatform/Plugin.swift | 9 +++ 3 files changed, 68 insertions(+), 10 deletions(-) diff --git a/Sources/SWBCore/Extensions/PlatformInfoExtension.swift b/Sources/SWBCore/Extensions/PlatformInfoExtension.swift index e1321c31..0e868261 100644 --- a/Sources/SWBCore/Extensions/PlatformInfoExtension.swift +++ b/Sources/SWBCore/Extensions/PlatformInfoExtension.swift @@ -35,6 +35,8 @@ public protocol PlatformInfoExtension: Sendable { func additionalPlatforms(context: any PlatformInfoExtensionAdditionalPlatformsContext) throws -> [(path: Path, data: [String: PropertyListItem])] func adjustPlatformSDKSearchPaths(platformName: String, platformPath: Path, sdkSearchPaths: inout [Path]) + + func platformName(triple: LLVMTriple) -> String? } extension PlatformInfoExtension { @@ -64,6 +66,10 @@ extension PlatformInfoExtension { public func adjustPlatformSDKSearchPaths(platformName: String, platformPath: Path, sdkSearchPaths: inout [Path]) { } + + public func platformName(triple: LLVMTriple) -> String? { + return nil + } } public protocol PlatformInfoExtensionAdditionalPlatformsContext: Sendable { diff --git a/Sources/SWBCore/Settings/Settings.swift b/Sources/SWBCore/Settings/Settings.swift index 08924ca0..b6bccd4b 100644 --- a/Sources/SWBCore/Settings/Settings.swift +++ b/Sources/SWBCore/Settings/Settings.swift @@ -1809,11 +1809,23 @@ private class SettingsBuilder: ProjectMatchLookup { sdk = try project.map { switch parameters.activeRunDestination?.buildTarget { case let .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple): - // FIXME platform should be decided by the triple - guard let platform = core.platformRegistry.lookup(name: "webassembly") else { - errors.append("unable to find platform 'webassembly'") + let llvmTriple = try LLVMTriple(triple) + + var platformName: String? = nil + for platformExtension in core.pluginManager.extensions(of: PlatformInfoExtensionPoint.self) { + platformName = platformExtension.platformName(triple: llvmTriple) + if platformName != nil { + break + } + } + + // FIXME fall back on a platform if none can be found to match the triple + + guard let platformName, let platform = core.platformRegistry.lookup(name: platformName) else { + errors.append("unable to find platform for \(triple)") return nil } + return try sdkRegistry.synthesizedSDK(platform: platform, sdkManifestPath: sdkManifestPath, triple: triple) default: return try sdkRegistry.lookup(nameOrPath: sdkroot, basePath: $0.sourceRoot, activeRunDestination: parameters.activeRunDestination) @@ -3533,9 +3545,25 @@ private class SettingsBuilder: ProjectMatchLookup { let destinationSDK: SDK switch runDestination.buildTarget { case let .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple): - // FIXME: the platform should be determined using the triple - guard let platform = self.core.platformRegistry.lookup(name: "webassembly") else { - self.errors.append("unable to resolve run destination platform: 'webassembly'") + let llvmTriple = try? LLVMTriple(triple) + + guard let llvmTriple else { + self.errors.append("invalid triple \(triple)") + return + } + + var platformName: String? = nil + for platformExtension in core.pluginManager.extensions(of: PlatformInfoExtensionPoint.self) { + platformName = platformExtension.platformName(triple: llvmTriple) + if platformName != nil { + break + } + } + + // FIXME fall back on a platform if none can be found to match the triple + + guard let platformName, let platform = core.platformRegistry.lookup(name: platformName) else { + self.errors.append("unable to find platform for \(triple)") return } @@ -3684,10 +3712,25 @@ private class SettingsBuilder: ProjectMatchLookup { let destinationPlatform: Platform switch runDestination.buildTarget { - case .swiftSDK: - // TODO use the triple to decide the platform, or use a fallback - guard let platform: Platform = self.core.platformRegistry.lookup(name: "webassembly") else { - self.errors.append("unable to resolve run destination platform: 'webassembly'") + case let .swiftSDK(_, triple: triple): + let llvmTriple = try? LLVMTriple(triple) + guard let llvmTriple else { + errors.append("Invalid triple: \(triple)") + return + } + + var platformName: String? = nil + for platformExtension in core.pluginManager.extensions(of: PlatformInfoExtensionPoint.self) { + platformName = platformExtension.platformName(triple: llvmTriple) + if platformName != nil { + break + } + } + + // FIXME fall back on a platform if none can be found to match the triple + + guard let platformName, let platform = core.platformRegistry.lookup(name: platformName) else { + errors.append("unable to find platform for \(triple)") return } destinationPlatform = platform diff --git a/Sources/SWBWebAssemblyPlatform/Plugin.swift b/Sources/SWBWebAssemblyPlatform/Plugin.swift index dbc99e82..e9aaac4d 100644 --- a/Sources/SWBWebAssemblyPlatform/Plugin.swift +++ b/Sources/SWBWebAssemblyPlatform/Plugin.swift @@ -45,6 +45,15 @@ struct WebAssemblyPlatformExtension: PlatformInfoExtension { ]) ] } + + func platformName(triple: LLVMTriple) -> String? { + // FIXME this shouldn't be recommending webassembly for linux triples + if triple.arch == "wasm32" || triple.system == "linux" { + return "webassembly" + } + + return nil + } } // TODO: We currently hardcode WebAssembly-specific information here but From 95e4f3885b2b1a763c3f5e21e2cdd0887eb93791 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Wed, 17 Dec 2025 13:19:57 -0500 Subject: [PATCH 16/18] Refactor name of appleSDK to toolchainSDK Code review feedback --- Sources/SWBCore/BuildRequestContext.swift | 4 +- Sources/SWBCore/ConfiguredTarget.swift | 4 +- Sources/SWBCore/DependencyResolution.swift | 20 +-- Sources/SWBCore/SDKRegistry.swift | 4 +- Sources/SWBCore/Settings/Settings.swift | 115 +++++++++--------- Sources/SWBGenericUnixPlatform/Plugin.swift | 9 ++ Sources/SWBProtocol/MessageSupport.swift | 2 +- .../StaleFileRemovalContext.swift | 2 +- Sources/SWBTaskExecution/ProjectPlanner.swift | 2 +- .../ValidateProductTaskAction.swift | 2 +- .../RunDestinationTestSupport.swift | 25 ++-- Sources/SWBWebAssemblyPlatform/Plugin.swift | 3 +- Sources/SwiftBuild/SWBBuildParameters.swift | 40 +++--- .../SwiftBuild/SWBBuildServiceSession.swift | 11 +- .../MessageSerializationTests.swift | 2 +- 15 files changed, 127 insertions(+), 118 deletions(-) diff --git a/Sources/SWBCore/BuildRequestContext.swift b/Sources/SWBCore/BuildRequestContext.swift index f8939fe5..3c9c7a78 100644 --- a/Sources/SWBCore/BuildRequestContext.swift +++ b/Sources/SWBCore/BuildRequestContext.swift @@ -197,7 +197,7 @@ extension BuildRequestContext { func platformAndSDKVariant(for target: ConfiguredTarget) -> PlatformAndSDKVariant { if hasEnabledIndexBuildArena, let activeRunDestination = target.parameters.activeRunDestination, - case let .appleSDK(platform: platform, _, sdkVariant: sdkVariant) = activeRunDestination.buildTarget, + case let .toolchainSDK(platform: platform, _, sdkVariant: sdkVariant) = activeRunDestination.buildTarget, let platform = workspaceContext.core.platformRegistry.lookup(name: platform) { // Configured targets include their platform in parameters, we can use it directly and avoid the expense of `getCachedSettings()` calls. // If in future `ConfiguredTarget` carries along an instance of its Settings, we can avoid this check and go back to using `Settings` without the cost of `getCachedSettings`. @@ -251,7 +251,7 @@ extension BuildRequestContext { return selectWithoutRunDestination() } - guard case let .appleSDK(platform: platform, _, sdkVariant: sdkVariant) = destination.buildTarget else { + guard case let .toolchainSDK(platform: platform, _, sdkVariant: sdkVariant) = destination.buildTarget else { return selectWithoutRunDestination() } diff --git a/Sources/SWBCore/ConfiguredTarget.swift b/Sources/SWBCore/ConfiguredTarget.swift index 685c22f0..7424a40b 100644 --- a/Sources/SWBCore/ConfiguredTarget.swift +++ b/Sources/SWBCore/ConfiguredTarget.swift @@ -67,7 +67,7 @@ public final class ConfiguredTarget: Hashable, CustomStringConvertible, Serializ } if specializeGuidForActiveRunDestination, let runDestination = self.parameters.activeRunDestination, - case let .appleSDK(platform: platform, _, sdkVariant: sdkVariant) = runDestination.buildTarget { + case let .toolchainSDK(platform: platform, _, sdkVariant: sdkVariant) = runDestination.buildTarget { var runDestString = platform if let sdkVariant = sdkVariant { runDestString += "+\(sdkVariant)" @@ -112,7 +112,7 @@ public final class ConfiguredTarget: Hashable, CustomStringConvertible, Serializ if specializeGuidForActiveRunDestination { let discriminator: String switch self.parameters.activeRunDestination?.buildTarget { - case let .appleSDK(platform: platform, _, sdkVariant: sdkVariant): + case let .toolchainSDK(platform: platform, _, sdkVariant: sdkVariant): discriminator = "\(platform)-\(sdkVariant ?? "")" case let .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple): discriminator = "\(sdkManifestPath)-\(triple)" diff --git a/Sources/SWBCore/DependencyResolution.swift b/Sources/SWBCore/DependencyResolution.swift index dd1f7c16..4217e186 100644 --- a/Sources/SWBCore/DependencyResolution.swift +++ b/Sources/SWBCore/DependencyResolution.swift @@ -213,7 +213,7 @@ struct SpecializationParameters: Hashable, CustomStringConvertible { overrides["SUPPORTS_MACCATALYST"] = sdkVariant.name == MacCatalystInfo.sdkVariantName ? "YES" : "NO" } if let supportedPlatforms { - if case let .appleSDK(platform: platform, _, _) = parameters.activeRunDestination?.buildTarget { + if case let .toolchainSDK(platform: platform, _, _) = parameters.activeRunDestination?.buildTarget { // If the specialization matches the platform of the active run destination, we do not need to impose it. if !supportedPlatforms.contains(platform) { overrides["SUPPORTED_PLATFORMS"] = supportedPlatforms.joined(separator: " ") @@ -258,7 +258,7 @@ struct SpecializationParameters: Hashable, CustomStringConvertible { // This seems like an unfortunate way to get from the SDK to its platform. But SettingsBuilder.computeBoundProperties() creates a scope to evaluate the PLATFORM_NAME defined in the SDK's default properties, so maybe there isn't a clearly better way. if let overridingSdk, let overridingPlatform = workspaceContext.core.platformRegistry.platforms.filter({ $0.sdks.contains(where: { $0.canonicalName == overridingSdk.canonicalName }) }).first { platformName = overridingPlatform.name - } else if case let .appleSDK(platform: platform, _, _) = parameters.activeRunDestination?.buildTarget { + } else if case let .toolchainSDK(platform: platform, _, _) = parameters.activeRunDestination?.buildTarget { platformName = platform } else { platformName = nil @@ -275,7 +275,7 @@ struct SpecializationParameters: Hashable, CustomStringConvertible { // Otherwise there was no overriding SDK provided, and there is no active run destination (or somehow there's a destination without a platform). This is valid, but it's not clear to me what this means for specialization parameters. } let sdkSuffix: String? - if case let .appleSDK(_, sdk: sdk, _) = parameters.activeRunDestination?.buildTarget { + if case let .toolchainSDK(_, sdk: sdk, _) = parameters.activeRunDestination?.buildTarget { if let suffix = try? workspaceContext.sdkRegistry.lookup(sdk, activeRunDestination: parameters.activeRunDestination)?.canonicalNameSuffix, !suffix.isEmpty { sdkSuffix = suffix } else { @@ -286,7 +286,7 @@ struct SpecializationParameters: Hashable, CustomStringConvertible { sdkSuffix = nil } let sdkVariantName: String? - if case let .appleSDK(_, _, sdkVariant: sdkVariant) = parameters.activeRunDestination?.buildTarget { + if case let .toolchainSDK(_, _, sdkVariant: sdkVariant) = parameters.activeRunDestination?.buildTarget { sdkVariantName = sdkVariant } else { sdkVariantName = nil @@ -541,7 +541,7 @@ extension SpecializationParameters { let archName: String = platform.determineDefaultArchForIndexArena(preferredArch: workspaceContext.systemInfo?.nativeArchitecture, using: workspaceContext.core) ?? "unknown_arch" for sdkVariant in matchingSDK.variants.keys.sorted() { - let runDestination = RunDestinationInfo(buildTarget: .appleSDK(platform: platform.name, sdk: matchingSDK.canonicalName, sdkVariant: sdkVariant), targetArchitecture: archName, supportedArchitectures: [archName], disableOnlyActiveArch: false, hostTargetedPlatform: nil) + let runDestination = RunDestinationInfo(buildTarget: .toolchainSDK(platform: platform.name, sdk: matchingSDK.canonicalName, sdkVariant: sdkVariant), targetArchitecture: archName, supportedArchitectures: [archName], disableOnlyActiveArch: false, hostTargetedPlatform: nil) let buildParams = buildRequest.parameters.replacing(activeRunDestination: runDestination, activeArchitecture: archName) let specializationParams = SpecializationParameters.default(workspaceContext: workspaceContext, buildRequestContext: buildRequestContext, parameters: buildParams) platformBuildParameters.append(PlatformBuildParameters(buildParams: buildParams, specializationParams: specializationParams)) @@ -603,14 +603,14 @@ extension SpecializationParameters { for platformParams in platformBuildParametersForIndex { // Before forming all new settings for this platform, do a fast check using `SUPPORTED_PLATFORMS` of `unconfiguredSettings`. // This significantly cuts down the work that this function is doing. - if case let .appleSDK(_, _, sdkVariant: sdkVariant) = platformParams.buildParams.activeRunDestination?.buildTarget, sdkVariant == MacCatalystInfo.sdkVariantName { + if case let .toolchainSDK(_, _, sdkVariant: sdkVariant) = platformParams.buildParams.activeRunDestination?.buildTarget, sdkVariant == MacCatalystInfo.sdkVariantName { // macCatalyst has various special rules, check it by forming new settings normally, below. // Carve out once small exception for host tools, which should never build for Catalyst. if let standardTarget = target as? StandardTarget, ProductTypeIdentifier(standardTarget.productTypeIdentifier).isHostBuildTool { continue } } else { - if case let .appleSDK(platform: platformName, _, _) = platformParams.buildParams.activeRunDestination?.buildTarget, unconfiguredSupportedPlatforms.count > 0 { + if case let .toolchainSDK(platform: platformName, _, _) = platformParams.buildParams.activeRunDestination?.buildTarget, unconfiguredSupportedPlatforms.count > 0 { guard unconfiguredSupportedPlatforms.contains(platformName) else { continue } } } @@ -658,10 +658,10 @@ extension SpecializationParameters { guard let targetPlatform = settings.platform else { return false } - if case let .appleSDK(platform: platform, _, _) = runDestination.buildTarget, targetPlatform.name != platform { + if case let .toolchainSDK(platform: platform, _, _) = runDestination.buildTarget, targetPlatform.name != platform { return false } - if case let .appleSDK(_, _, sdkVariant: sdkVariant) = runDestination.buildTarget, settings.sdkVariant?.name != sdkVariant { + if case let .toolchainSDK(_, _, sdkVariant: sdkVariant) = runDestination.buildTarget, settings.sdkVariant?.name != sdkVariant { return false } @@ -833,7 +833,7 @@ extension SpecializationParameters { imposedSupportedPlatforms = supportedPlatforms let hostPlatform = settings.globalScope.evaluate(BuiltinMacros.HOST_PLATFORM) - let runDestinationPlatform = if case let .appleSDK(platform: platform, _, _) = buildRequest.parameters.activeRunDestination?.buildTarget { platform } else { Optional.none } + let runDestinationPlatform = if case let .toolchainSDK(platform: platform, _, _) = buildRequest.parameters.activeRunDestination?.buildTarget { platform } else { Optional.none } let supportedPlatformsWithoutSimulators = Set(supportedPlatforms.compactMap { self.workspaceContext.core.platformRegistry.lookup(name: $0) }.filter { !$0.isSimulator }.map { $0.name }) // If the given specialization is unsupported, we still need to impose a platform. diff --git a/Sources/SWBCore/SDKRegistry.swift b/Sources/SWBCore/SDKRegistry.swift index b3097a9b..2642e609 100644 --- a/Sources/SWBCore/SDKRegistry.swift +++ b/Sources/SWBCore/SDKRegistry.swift @@ -1295,7 +1295,7 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send func selectSDKList() -> [SDK]? { let platform: String? - if case let .appleSDK(platform: p, _, _) = activeRunDestination?.buildTarget { + if case let .toolchainSDK(platform: p, _, _) = activeRunDestination?.buildTarget { platform = p } else { platform = nil @@ -1309,7 +1309,7 @@ public final class SDKRegistry: SDKRegistryLookup, CustomStringConvertible, Send // by the cohort platforms of the run destination's SDK's platform. This is necessary to resolve // driverkit when we have a DriverKit run destination but with a platform-specific SDK. if let runDestination = activeRunDestination, - case let .appleSDK(_, sdk: sdk, _) = runDestination.buildTarget, + case let .toolchainSDK(_, sdk: sdk, _) = runDestination.buildTarget, let cohortPlatforms = try? lookup(sdk, activeRunDestination: nil)?.cohortPlatforms { for cohortPlatform in cohortPlatforms { if let list = sdksByCohortPlatform[cohortPlatform] { diff --git a/Sources/SWBCore/Settings/Settings.swift b/Sources/SWBCore/Settings/Settings.swift index b6bccd4b..cad5ca4e 100644 --- a/Sources/SWBCore/Settings/Settings.swift +++ b/Sources/SWBCore/Settings/Settings.swift @@ -1265,6 +1265,35 @@ private class SettingsBuilder: ProjectMatchLookup { } } + enum FindPlatformError: Error { case message(String) } + + func findPlatform(for triple: String, core: Core) -> Result { + let llvmTriple = try? LLVMTriple(triple) + + guard let llvmTriple else { + return .failure(.message("invalid triple \(triple)")) + } + + var platformNames = OrderedSet() + for platformExtension in core.pluginManager.extensions(of: PlatformInfoExtensionPoint.self) { + if let platformName = platformExtension.platformName(triple: llvmTriple) { + platformNames.append(platformName) + } + } + + guard let platformName = platformNames.first, platformNames.count == 1 else { + return .failure(.message("unable to find a single platform name for triple '\(triple)'. results: \(platformNames)")) + } + + // FIXME fall back on a platform if none can be found to match the triple + + guard let platform = core.platformRegistry.lookup(name: platformName) else { + return .failure(.message("unable to find platform for '\(platformName)'")) + } + + return .success(platform) + } + // Properties the builder was initialized with. let workspaceContext: WorkspaceContext @@ -1522,7 +1551,7 @@ private class SettingsBuilder: ProjectMatchLookup { if let sdk = boundProperties.sdk { let scope = createScope(sdkToUse: sdk) let supportsMacCatalyst = Settings.supportsMacCatalyst(scope: scope, core: core) - if case let .appleSDK(platform: _, sdk: _, sdkVariant: sdkVariant) = parameters.activeRunDestination?.buildTarget, + if case let .toolchainSDK(platform: _, sdk: _, sdkVariant: sdkVariant) = parameters.activeRunDestination?.buildTarget, sdkVariant == MacCatalystInfo.sdkVariantName, supportsMacCatalyst { pushTable(.exported) { @@ -1784,7 +1813,7 @@ private class SettingsBuilder: ProjectMatchLookup { // We will replace SDKROOT values of "auto" here if the run destination is compatible. let usesReplaceableAutomaticSDKRoot: Bool if sdkroot == "auto", - case let .appleSDK(platform: activePlatform, sdk: _, sdkVariant: sdkVariant) = parameters.activeRunDestination?.buildTarget { + case let .toolchainSDK(platform: activePlatform, sdk: _, sdkVariant: sdkVariant) = parameters.activeRunDestination?.buildTarget { let destinationIsMacCatalyst = sdkVariant == MacCatalystInfo.sdkVariantName let scope = createScope(effectiveTargetConfig, sdkToUse: sdk) @@ -1801,7 +1830,7 @@ private class SettingsBuilder: ProjectMatchLookup { usesReplaceableAutomaticSDKRoot = false } if usesReplaceableAutomaticSDKRoot, - case let .appleSDK(platform: _, sdk: activeSDK, sdkVariant: _) = parameters.activeRunDestination?.buildTarget { + case let .toolchainSDK(platform: _, sdk: activeSDK, sdkVariant: _) = parameters.activeRunDestination?.buildTarget { sdkroot = activeSDK } @@ -1809,21 +1838,15 @@ private class SettingsBuilder: ProjectMatchLookup { sdk = try project.map { switch parameters.activeRunDestination?.buildTarget { case let .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple): - let llvmTriple = try LLVMTriple(triple) - - var platformName: String? = nil - for platformExtension in core.pluginManager.extensions(of: PlatformInfoExtensionPoint.self) { - platformName = platformExtension.platformName(triple: llvmTriple) - if platformName != nil { - break - } - } - - // FIXME fall back on a platform if none can be found to match the triple + let findPlatformResult = findPlatform(for: triple, core: core) + let platform: Platform - guard let platformName, let platform = core.platformRegistry.lookup(name: platformName) else { - errors.append("unable to find platform for \(triple)") + switch findPlatformResult { + case let .failure(.message(msg)): + errors.append(msg) return nil + case let .success(platform: p): + platform = p } return try sdkRegistry.synthesizedSDK(platform: platform, sdkManifestPath: sdkManifestPath, triple: triple) @@ -1839,7 +1862,7 @@ private class SettingsBuilder: ProjectMatchLookup { if let s = sdk { // Evaluate the SDK variant, if there is one. let sdkVariantName: String - if usesReplaceableAutomaticSDKRoot, case let .appleSDK(platform: _, sdk: _, sdkVariant: activeSDKVariant) = parameters.activeRunDestination?.buildTarget, let activeSDKVariant { + if usesReplaceableAutomaticSDKRoot, case let .toolchainSDK(platform: _, sdk: _, sdkVariant: activeSDKVariant) = parameters.activeRunDestination?.buildTarget, let activeSDKVariant { sdkVariantName = activeSDKVariant } else { sdkVariantName = createScope(effectiveTargetConfig, sdkToUse: s).evaluate(BuiltinMacros.SDK_VARIANT) @@ -3545,36 +3568,22 @@ private class SettingsBuilder: ProjectMatchLookup { let destinationSDK: SDK switch runDestination.buildTarget { case let .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple): - let llvmTriple = try? LLVMTriple(triple) + let findPlatformResult = findPlatform(for: triple, core: core) - guard let llvmTriple else { - self.errors.append("invalid triple \(triple)") + switch findPlatformResult { + case let .failure(.message(msg)): + self.errors.append(msg) return + case let .success(platform): + destinationPlatform = platform } - var platformName: String? = nil - for platformExtension in core.pluginManager.extensions(of: PlatformInfoExtensionPoint.self) { - platformName = platformExtension.platformName(triple: llvmTriple) - if platformName != nil { - break - } - } - - // FIXME fall back on a platform if none can be found to match the triple - - guard let platformName, let platform = core.platformRegistry.lookup(name: platformName) else { - self.errors.append("unable to find platform for \(triple)") - return - } - - destinationPlatform = platform - - guard let sdk = try? sdkRegistry.synthesizedSDK(platform: platform, sdkManifestPath: sdkManifestPath, triple: triple) else { + guard let sdk = try? sdkRegistry.synthesizedSDK(platform: destinationPlatform, sdkManifestPath: sdkManifestPath, triple: triple) else { self.errors.append("unable to synthesize SDK for Swift SDK build target: '\(runDestination.buildTarget)'") return } destinationSDK = sdk - case let .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant): + case let .toolchainSDK(platform: platform, sdk: sdk, _): guard let platform = self.core.platformRegistry.lookup(name: platform) else { self.errors.append("unable to resolve run destination platform: '\(platform)'") return @@ -3608,7 +3617,7 @@ private class SettingsBuilder: ProjectMatchLookup { do { let scope = createScope(sdkToUse: nil) - let destinationIsMacCatalyst = if case let .appleSDK(platform: _, sdk: _, sdkVariant: sdkVariant) = runDestination.buildTarget { + let destinationIsMacCatalyst = if case let .toolchainSDK(platform: _, sdk: _, sdkVariant: sdkVariant) = runDestination.buildTarget { sdkVariant == MacCatalystInfo.sdkVariantName } else { false } let supportsMacCatalyst = Settings.supportsMacCatalyst(scope: scope, core: core) @@ -3713,28 +3722,16 @@ private class SettingsBuilder: ProjectMatchLookup { switch runDestination.buildTarget { case let .swiftSDK(_, triple: triple): - let llvmTriple = try? LLVMTriple(triple) - guard let llvmTriple else { - errors.append("Invalid triple: \(triple)") - return - } + let findPlatformResult = findPlatform(for: triple, core: core) - var platformName: String? = nil - for platformExtension in core.pluginManager.extensions(of: PlatformInfoExtensionPoint.self) { - platformName = platformExtension.platformName(triple: llvmTriple) - if platformName != nil { - break - } - } - - // FIXME fall back on a platform if none can be found to match the triple - - guard let platformName, let platform = core.platformRegistry.lookup(name: platformName) else { - errors.append("unable to find platform for \(triple)") + switch findPlatformResult { + case let .failure(.message(msg)): + self.errors.append(msg) return + case let .success(p): + destinationPlatform = p } - destinationPlatform = platform - case let .appleSDK(platform: platformName, sdk: _, sdkVariant: _): + case let .toolchainSDK(platform: platformName, sdk: _, sdkVariant: _): guard let platform: Platform = self.core.platformRegistry.lookup(name: platformName) else { self.errors.append("unable to resolve run destination platform: '\(platformName)'") return diff --git a/Sources/SWBGenericUnixPlatform/Plugin.swift b/Sources/SWBGenericUnixPlatform/Plugin.swift index 5e103d24..1baad32c 100644 --- a/Sources/SWBGenericUnixPlatform/Plugin.swift +++ b/Sources/SWBGenericUnixPlatform/Plugin.swift @@ -92,6 +92,15 @@ struct GenericUnixPlatformInfoExtension: PlatformInfoExtension { ]) } } + + func platformName(triple: LLVMTriple) -> String? { + // FIXME this shouldn't be the webassembly platform here + if triple.system == "linux" { + return "webassembly" + } + + return nil + } } struct GenericUnixSDKRegistryExtension: SDKRegistryExtension { diff --git a/Sources/SWBProtocol/MessageSupport.swift b/Sources/SWBProtocol/MessageSupport.swift index 04578422..10468a80 100644 --- a/Sources/SWBProtocol/MessageSupport.swift +++ b/Sources/SWBProtocol/MessageSupport.swift @@ -335,7 +335,7 @@ public struct RunDestinationInfo: SerializableCodable, Hashable, Sendable { } public enum BuildTarget: SerializableCodable, Hashable, Sendable { - case appleSDK(platform: String, sdk: String, sdkVariant: String?) + case toolchainSDK(platform: String, sdk: String, sdkVariant: String?) case swiftSDK(sdkManifestPath: String, triple: String) } diff --git a/Sources/SWBTaskConstruction/StaleFileRemovalContext.swift b/Sources/SWBTaskConstruction/StaleFileRemovalContext.swift index 841a3e76..7c80a43c 100644 --- a/Sources/SWBTaskConstruction/StaleFileRemovalContext.swift +++ b/Sources/SWBTaskConstruction/StaleFileRemovalContext.swift @@ -60,7 +60,7 @@ extension StaleFileRemovalContext { } else { staleFileRemovalIdentifier += "workspace" staleFileRemovalIdentifier += "-\(globalProductPlan.planRequest.buildRequest.parameters.configuration ?? "none")" - if case let .appleSDK(_, sdk: sdk, sdkVariant: variant) = globalProductPlan.planRequest.buildRequest.parameters.activeRunDestination?.buildTarget { + if case let .toolchainSDK(_, sdk: sdk, sdkVariant: variant) = globalProductPlan.planRequest.buildRequest.parameters.activeRunDestination?.buildTarget { staleFileRemovalIdentifier += "-\(sdk)" if let variant { staleFileRemovalIdentifier += "-\(variant)" diff --git a/Sources/SWBTaskExecution/ProjectPlanner.swift b/Sources/SWBTaskExecution/ProjectPlanner.swift index f48f5fa2..7fe87669 100644 --- a/Sources/SWBTaskExecution/ProjectPlanner.swift +++ b/Sources/SWBTaskExecution/ProjectPlanner.swift @@ -136,6 +136,6 @@ private extension BuildParameters { // All relevant platforms define a preferredArch, so the undefined_arch fallback case should never happen // in practice, and indicates a serious issue occurred during plugin loading. let targetArchitecture = platform.preferredArch ?? "undefined_arch" - return RunDestinationInfo(buildTarget: .appleSDK(platform: platform.name, sdk: platform.name, sdkVariant: nil), targetArchitecture: targetArchitecture, supportedArchitectures: [targetArchitecture], disableOnlyActiveArch: false, hostTargetedPlatform: nil) + return RunDestinationInfo(buildTarget: .toolchainSDK(platform: platform.name, sdk: platform.name, sdkVariant: nil), targetArchitecture: targetArchitecture, supportedArchitectures: [targetArchitecture], disableOnlyActiveArch: false, hostTargetedPlatform: nil) } } diff --git a/Sources/SWBTaskExecution/TaskActions/ValidateProductTaskAction.swift b/Sources/SWBTaskExecution/TaskActions/ValidateProductTaskAction.swift index a910712d..6a3de8ef 100644 --- a/Sources/SWBTaskExecution/TaskActions/ValidateProductTaskAction.swift +++ b/Sources/SWBTaskExecution/TaskActions/ValidateProductTaskAction.swift @@ -188,7 +188,7 @@ public final class ValidateProductTaskAction: TaskAction { // Validate the iPad multitasking/splitview support in the Info.plist. This never causes the tool to fail, but it may emit warnings. validateiPadMultiTaskingSplitViewSupport(infoPlist, outputDelegate: outputDelegate) - if let configuredTarget = task.forTarget, case let .appleSDK(platform: platform, _, _) = configuredTarget.parameters.activeRunDestination?.buildTarget { + if let configuredTarget = task.forTarget, case let .toolchainSDK(platform: platform, _, _) = configuredTarget.parameters.activeRunDestination?.buildTarget { // Validate that this is actually an App Store category. validateAppStoreCategory(infoPlist, platform: platform, targetName: configuredTarget.target.name, schemeCommand: executionDelegate.schemeCommand, options: options, outputDelegate: outputDelegate) diff --git a/Sources/SWBTestSupport/RunDestinationTestSupport.swift b/Sources/SWBTestSupport/RunDestinationTestSupport.swift index 1e89c82c..e00cf066 100644 --- a/Sources/SWBTestSupport/RunDestinationTestSupport.swift +++ b/Sources/SWBTestSupport/RunDestinationTestSupport.swift @@ -300,7 +300,7 @@ extension RunDestinationInfo { /// /// - note: Returns `nil` for non-Mach-O platforms such as Linux. package func buildVersionPlatform(_ core: Core) -> BuildVersion.Platform? { - guard case let .appleSDK(_, sdk: sdk, sdkVariant: sdkVariant) = buildTarget, + guard case let .toolchainSDK(_, sdk: sdk, sdkVariant: sdkVariant) = buildTarget, let sdk = try? core.sdkRegistry.lookup(sdk, activeRunDestination: self) else { return nil } @@ -309,7 +309,7 @@ extension RunDestinationInfo { package func imageFormat(_ core: Core) -> ImageFormat { switch buildTarget { - case let .appleSDK(platform: platform, _, _): + case let .toolchainSDK(platform: platform, _, _): switch platform { case "webassembly": fatalError("not implemented") @@ -335,11 +335,16 @@ extension RunDestinationInfo { } switch imageFormat(core) { case .elf: - if case let .appleSDK(platform: platform, _, _) = buildTarget { + switch buildTarget { + case let .toolchainSDK(platform, _, _): environment.prependPath(key: "LD_LIBRARY_PATH", value: toolchain.path.join("usr/lib/swift/\(platform)").str) - } else { - // Fall back to the OS provided Swift runtime - break + case let .swiftSDK(_, triple): + guard let llvmTriple = try? LLVMTriple(triple) else { + // Fall back to the OS provided Swift runtime + break + } + + environment.prependPath(key: "LD_LIBRARY_PATH", value: toolchain.path.join("usr/lib/swift/\(llvmTriple.system)").str) } case .pe: environment.prependPath(key: .path, value: core.developerPath.path.join("Runtimes").join(toolchain.version.description).join("usr/bin").str) @@ -399,11 +404,11 @@ extension _RunDestinationInfo { extension RunDestinationInfo: _RunDestinationInfo { package init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], disableOnlyActiveArch: Bool) { - self.init(buildTarget: .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant), targetArchitecture: targetArchitecture, supportedArchitectures: OrderedSet(supportedArchitectures), disableOnlyActiveArch: disableOnlyActiveArch, hostTargetedPlatform: nil) + self.init(buildTarget: .toolchainSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant), targetArchitecture: targetArchitecture, supportedArchitectures: OrderedSet(supportedArchitectures), disableOnlyActiveArch: disableOnlyActiveArch, hostTargetedPlatform: nil) } package var platform: String { - guard case let .appleSDK(platform: platform, _, _) = buildTarget else { + guard case let .toolchainSDK(platform: platform, _, _) = buildTarget else { return "" } @@ -411,7 +416,7 @@ extension RunDestinationInfo: _RunDestinationInfo { } package var sdk: String { - guard case let .appleSDK(_, sdk: sdk, _) = buildTarget else { + guard case let .toolchainSDK(_, sdk: sdk, _) = buildTarget else { return "" } @@ -419,7 +424,7 @@ extension RunDestinationInfo: _RunDestinationInfo { } package var sdkVariant: String? { - guard case let .appleSDK(_, _, sdkVariant: sdkVariant) = buildTarget else { + guard case let .toolchainSDK(_, _, sdkVariant: sdkVariant) = buildTarget else { return nil } diff --git a/Sources/SWBWebAssemblyPlatform/Plugin.swift b/Sources/SWBWebAssemblyPlatform/Plugin.swift index e9aaac4d..e96c8e2c 100644 --- a/Sources/SWBWebAssemblyPlatform/Plugin.swift +++ b/Sources/SWBWebAssemblyPlatform/Plugin.swift @@ -47,8 +47,7 @@ struct WebAssemblyPlatformExtension: PlatformInfoExtension { } func platformName(triple: LLVMTriple) -> String? { - // FIXME this shouldn't be recommending webassembly for linux triples - if triple.arch == "wasm32" || triple.system == "linux" { + if triple.system.hasPrefix("wasi") { return "webassembly" } diff --git a/Sources/SwiftBuild/SWBBuildParameters.swift b/Sources/SwiftBuild/SWBBuildParameters.swift index fbc8f467..68ede26a 100644 --- a/Sources/SwiftBuild/SWBBuildParameters.swift +++ b/Sources/SwiftBuild/SWBBuildParameters.swift @@ -37,18 +37,18 @@ public struct SWBBuildParameters: Codable, Sendable { /// Refer to `SWBProtocol.RunDestinationInfo` public struct SWBRunDestinationInfo: Codable, Sendable { public struct SWBBuildTarget: Codable, Sendable { - fileprivate var _internalBuildTarget: InternalBuildTarget + var _internalBuildTarget: InternalBuildTarget - public static func appleSDK(platform: String, sdk: String, sdkVariant: String?) -> SWBBuildTarget { - SWBBuildTarget(_internalBuildTarget: .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant)) + public static func toolchainSDK(platform: String, sdk: String, sdkVariant: String?) -> SWBBuildTarget { + SWBBuildTarget(_internalBuildTarget: .toolchainSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant)) } public static func swiftSDK(sdkManifestPath: String, triple: String) -> SWBBuildTarget { SWBBuildTarget(_internalBuildTarget: .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple)) } - public func asAppleSDK() -> (platform: String, sdk: String, sdkVariant: String?)? { - guard case let .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant) = _internalBuildTarget else { + public func asToolchainSDK() -> (platform: String, sdk: String, sdkVariant: String?)? { + guard case let .toolchainSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant) = _internalBuildTarget else { return nil } @@ -70,27 +70,27 @@ public struct SWBRunDestinationInfo: Codable, Sendable { public var disableOnlyActiveArch: Bool public var hostTargetedPlatform: String? - @available(*, deprecated, message: "Use buildTarget and match on the appleSDK case instead") + @available(*, deprecated, message: "Use buildTarget and match on the toolchainSDK case instead") public var platform: String { - guard case let .appleSDK(platform: platform, _, _) = buildTarget._internalBuildTarget else { + guard case let .toolchainSDK(platform: platform, _, _) = buildTarget._internalBuildTarget else { return "" } return platform } - @available(*, deprecated, message: "Use buildTarget and match on the appleSDK case instead") + @available(*, deprecated, message: "Use buildTarget and match on the toolchainSDK case instead") public var sdk: String { - guard case let .appleSDK(_, sdk: sdk, _) = buildTarget._internalBuildTarget else { + guard case let .toolchainSDK(_, sdk: sdk, _) = buildTarget._internalBuildTarget else { return "" } return sdk } - @available(*, deprecated, message: "Use buildTarget and match on the appleSDK case instead") + @available(*, deprecated, message: "Use buildTarget and match on the toolchainSDK case instead") public var sdkVariant: String? { - guard case let .appleSDK(_, _, sdkVariant: sdkVariant) = buildTarget._internalBuildTarget else { + guard case let .toolchainSDK(_, _, sdkVariant: sdkVariant) = buildTarget._internalBuildTarget else { return nil } @@ -98,7 +98,7 @@ public struct SWBRunDestinationInfo: Codable, Sendable { } public init(platform: String, sdk: String, sdkVariant: String?, targetArchitecture: String, supportedArchitectures: [String], disableOnlyActiveArch: Bool) { - self.buildTarget = .appleSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant) + self.buildTarget = .toolchainSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant) self.targetArchitecture = targetArchitecture self.supportedArchitectures = supportedArchitectures self.disableOnlyActiveArch = disableOnlyActiveArch @@ -118,8 +118,8 @@ public struct SWBRunDestinationInfo: Codable, Sendable { } } -fileprivate enum InternalBuildTarget: Codable, Sendable { - case appleSDK(platform: String, sdk: String, sdkVariant: String?) +enum InternalBuildTarget: Codable, Sendable { + case toolchainSDK(platform: String, sdk: String, sdkVariant: String?) case swiftSDK(sdkManifestPath: String, triple: String) private enum CodingKeys: String, CodingKey { @@ -137,13 +137,13 @@ fileprivate enum InternalBuildTarget: Codable, Sendable { } private enum BuildTarget: String, Codable { - case appleSDK + case toolchainSDK case swiftSDK init(_ buildTarget: InternalBuildTarget) { switch buildTarget { - case .appleSDK: - self = .appleSDK + case .toolchainSDK: + self = .toolchainSDK case .swiftSDK: self = .swiftSDK } @@ -153,8 +153,8 @@ fileprivate enum InternalBuildTarget: Codable, Sendable { public init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) switch try container.decode(BuildTarget.self, forKey: .buildTarget) { - case .appleSDK: - self = try .appleSDK(platform: container.decode(String.self, forKey: .platform), sdk: container.decode(String.self, forKey: .sdk), sdkVariant: container.decode(String?.self, forKey: .sdkVariant)) + case .toolchainSDK: + self = try .toolchainSDK(platform: container.decode(String.self, forKey: .platform), sdk: container.decode(String.self, forKey: .sdk), sdkVariant: container.decode(String?.self, forKey: .sdkVariant)) case .swiftSDK: self = try .swiftSDK(sdkManifestPath: container.decode(String.self, forKey: .sdkManifestPath), triple: container.decode(String.self, forKey: .triple)) } @@ -164,7 +164,7 @@ fileprivate enum InternalBuildTarget: Codable, Sendable { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(BuildTarget(self), forKey: .buildTarget) switch self { - case let .appleSDK(platform, sdk, sdkVariant): + case let .toolchainSDK(platform, sdk, sdkVariant): try container.encode(platform, forKey: .platform) try container.encode(sdk, forKey: .sdk) try container.encode(sdkVariant, forKey: .sdkVariant) diff --git a/Sources/SwiftBuild/SWBBuildServiceSession.swift b/Sources/SwiftBuild/SWBBuildServiceSession.swift index 5a56cdb9..972fcfe8 100644 --- a/Sources/SwiftBuild/SWBBuildServiceSession.swift +++ b/Sources/SwiftBuild/SWBBuildServiceSession.swift @@ -838,12 +838,11 @@ extension SWBBuildParameters { fileprivate extension RunDestinationInfo { init(_ x: SWBRunDestinationInfo) { - if let appleSDK = x.buildTarget.asAppleSDK() { - self.init(buildTarget: .appleSDK(platform: appleSDK.platform, sdk: appleSDK.sdk, sdkVariant: appleSDK.sdkVariant), targetArchitecture: x.targetArchitecture, supportedArchitectures: OrderedSet(x.supportedArchitectures), disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) - } else if let swiftSDK = x.buildTarget.asSwiftSDK() { - self.init(buildTarget: .swiftSDK(sdkManifestPath: swiftSDK.sdkManifestPath, triple: swiftSDK.triple), targetArchitecture: x.targetArchitecture, supportedArchitectures: OrderedSet(x.supportedArchitectures), disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) - } else { - fatalError("not implemented") + switch x.buildTarget._internalBuildTarget { + case let .toolchainSDK(platform, sdk, sdkVariant): + self.init(buildTarget: .toolchainSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant), targetArchitecture: x.targetArchitecture, supportedArchitectures: OrderedSet(x.supportedArchitectures), disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) + case let .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple): + self.init(buildTarget: .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple), targetArchitecture: x.targetArchitecture, supportedArchitectures: OrderedSet(x.supportedArchitectures), disableOnlyActiveArch: x.disableOnlyActiveArch, hostTargetedPlatform: x.hostTargetedPlatform) } } } diff --git a/Tests/SWBProtocolTests/MessageSerializationTests.swift b/Tests/SWBProtocolTests/MessageSerializationTests.swift index b7dfd58f..895b461b 100644 --- a/Tests/SWBProtocolTests/MessageSerializationTests.swift +++ b/Tests/SWBProtocolTests/MessageSerializationTests.swift @@ -24,7 +24,7 @@ import Testing action: "build", configuration: "Debug", activeRunDestination: RunDestinationInfo( - buildTarget: .appleSDK( + buildTarget: .toolchainSDK( platform: "osOS", sdk: "osos", sdkVariant: "x", From e7cc4ae6a6f7b3e13867d96e3b45bd25952ce788 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Wed, 17 Dec 2025 15:42:12 -0500 Subject: [PATCH 17/18] Introduce compatibility with encoding/decoding of the build targets --- Sources/SWBProtocol/MessageSupport.swift | 57 +++++++++++++++++++++ Sources/SwiftBuild/SWBBuildParameters.swift | 51 ++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/Sources/SWBProtocol/MessageSupport.swift b/Sources/SWBProtocol/MessageSupport.swift index 10468a80..786f0fb8 100644 --- a/Sources/SWBProtocol/MessageSupport.swift +++ b/Sources/SWBProtocol/MessageSupport.swift @@ -332,6 +332,63 @@ public struct RunDestinationInfo: SerializableCodable, Hashable, Sendable { self.disableOnlyActiveArch = disableOnlyActiveArch self.hostTargetedPlatform = hostTargetedPlatform } + + public enum CodingKeys: CodingKey { + case buildTarget + case targetArchitecture + case supportedArchitectures + case disableOnlyActiveArch + case hostTargetedPlatform + + // These are the old coding keys that were previously associated with toolchain SDK's + case platform + case sdk + case sdkVariant + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + do { + // Handle the message payload from earlier versions that didn't have the buildTarget enumeration + let platform = try container.decode(String.self, forKey: .platform) + let sdk: String = try container.decode(String.self, forKey: .sdk) + let sdkVariant: String? = try container.decode(String?.self, forKey: .sdkVariant) + self.buildTarget = .toolchainSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant) + } catch DecodingError.keyNotFound { + // This message is current and has the build target + self.buildTarget = try container.decode(BuildTarget.self, forKey: .buildTarget) + } + + self.targetArchitecture = try container.decode(String.self, forKey: .targetArchitecture) + self.supportedArchitectures = try container.decode(OrderedSet.self, forKey: .supportedArchitectures) + self.disableOnlyActiveArch = try container.decode(Bool.self, forKey: .disableOnlyActiveArch) + + // Some versions of the message don't have this field + do { + self.hostTargetedPlatform = try container.decode(String?.self, forKey: .hostTargetedPlatform) + } catch DecodingError.keyNotFound { + self.hostTargetedPlatform = nil + } + } + + public func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + switch self.buildTarget { + case let .toolchainSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant): + try container.encode(platform, forKey: .platform) + try container.encode(sdk, forKey: .sdk) + try container.encode(sdkVariant, forKey: .sdkVariant) + case .swiftSDK: + try container.encode(buildTarget, forKey: .buildTarget) + } + + try container.encode(self.targetArchitecture, forKey: .targetArchitecture) + try container.encode(self.supportedArchitectures, forKey: .supportedArchitectures) + try container.encode(self.disableOnlyActiveArch, forKey: .disableOnlyActiveArch) + try container.encode(self.hostTargetedPlatform, forKey: .hostTargetedPlatform) + } } public enum BuildTarget: SerializableCodable, Hashable, Sendable { diff --git a/Sources/SwiftBuild/SWBBuildParameters.swift b/Sources/SwiftBuild/SWBBuildParameters.swift index 68ede26a..624481dd 100644 --- a/Sources/SwiftBuild/SWBBuildParameters.swift +++ b/Sources/SwiftBuild/SWBBuildParameters.swift @@ -70,6 +70,57 @@ public struct SWBRunDestinationInfo: Codable, Sendable { public var disableOnlyActiveArch: Bool public var hostTargetedPlatform: String? + public enum CodingKeys: CodingKey { + case buildTarget + case targetArchitecture + case supportedArchitectures + case disableOnlyActiveArch + case hostTargetedPlatform + + // These are the old coding keys that were previously associated with toolchain SDK's + case platform + case sdk + case sdkVariant + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + do { + // Handle the message payload from earlier versions that didn't have the buildTarget enumeration + let platform = try container.decode(String.self, forKey: .platform) + let sdk: String = try container.decode(String.self, forKey: .sdk) + let sdkVariant: String? = try container.decode(String?.self, forKey: .sdkVariant) + self.buildTarget = .toolchainSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant) + } catch DecodingError.keyNotFound { + // This message is current and has the build target + self.buildTarget = try container.decode(SWBBuildTarget.self, forKey: .buildTarget) + } + + self.targetArchitecture = try container.decode(String.self, forKey: .targetArchitecture) + self.supportedArchitectures = try container.decode([String].self, forKey: .supportedArchitectures) + self.disableOnlyActiveArch = try container.decode(Bool.self, forKey: .disableOnlyActiveArch) + self.hostTargetedPlatform = try container.decode(String?.self, forKey: .hostTargetedPlatform) + } + + public func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + switch self.buildTarget._internalBuildTarget { + case let .toolchainSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant): + try container.encode(platform, forKey: .platform) + try container.encode(sdk, forKey: .sdk) + try container.encode(sdkVariant, forKey: .sdkVariant) + case .swiftSDK: + try container.encode(buildTarget, forKey: .buildTarget) + } + + try container.encode(self.targetArchitecture, forKey: .targetArchitecture) + try container.encode(self.supportedArchitectures, forKey: .supportedArchitectures) + try container.encode(self.disableOnlyActiveArch, forKey: .disableOnlyActiveArch) + try container.encode(self.hostTargetedPlatform, forKey: .hostTargetedPlatform) + } + @available(*, deprecated, message: "Use buildTarget and match on the toolchainSDK case instead") public var platform: String { guard case let .toolchainSDK(platform: platform, _, _) = buildTarget._internalBuildTarget else { From f26b36be456d1e9a6f08001f21d4f893ff09a0af Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Thu, 18 Dec 2025 14:09:58 -0500 Subject: [PATCH 18/18] Code review feedback --- Sources/SWBCore/Settings/Settings.swift | 17 ++++++-------- Sources/SWBGenericUnixPlatform/Plugin.swift | 9 -------- Sources/SWBProtocol/MessageSupport.swift | 15 ++++--------- Sources/SwiftBuild/SWBBuildParameters.swift | 25 ++++----------------- 4 files changed, 15 insertions(+), 51 deletions(-) diff --git a/Sources/SWBCore/Settings/Settings.swift b/Sources/SWBCore/Settings/Settings.swift index cad5ca4e..d9178b76 100644 --- a/Sources/SWBCore/Settings/Settings.swift +++ b/Sources/SWBCore/Settings/Settings.swift @@ -1268,20 +1268,17 @@ private class SettingsBuilder: ProjectMatchLookup { enum FindPlatformError: Error { case message(String) } func findPlatform(for triple: String, core: Core) -> Result { - let llvmTriple = try? LLVMTriple(triple) + let llvmTriple: LLVMTriple - guard let llvmTriple else { - return .failure(.message("invalid triple \(triple)")) + do { + llvmTriple = try LLVMTriple(triple) + } catch { + return .failure(.message("\(error)")) } - var platformNames = OrderedSet() - for platformExtension in core.pluginManager.extensions(of: PlatformInfoExtensionPoint.self) { - if let platformName = platformExtension.platformName(triple: llvmTriple) { - platformNames.append(platformName) - } - } + let platformNames = core.pluginManager.extensions(of: PlatformInfoExtensionPoint.self).compactMap({ $0.platformName(triple: llvmTriple) }).sorted() - guard let platformName = platformNames.first, platformNames.count == 1 else { + guard let platformName = platformNames.only else { return .failure(.message("unable to find a single platform name for triple '\(triple)'. results: \(platformNames)")) } diff --git a/Sources/SWBGenericUnixPlatform/Plugin.swift b/Sources/SWBGenericUnixPlatform/Plugin.swift index 1baad32c..5e103d24 100644 --- a/Sources/SWBGenericUnixPlatform/Plugin.swift +++ b/Sources/SWBGenericUnixPlatform/Plugin.swift @@ -92,15 +92,6 @@ struct GenericUnixPlatformInfoExtension: PlatformInfoExtension { ]) } } - - func platformName(triple: LLVMTriple) -> String? { - // FIXME this shouldn't be the webassembly platform here - if triple.system == "linux" { - return "webassembly" - } - - return nil - } } struct GenericUnixSDKRegistryExtension: SDKRegistryExtension { diff --git a/Sources/SWBProtocol/MessageSupport.swift b/Sources/SWBProtocol/MessageSupport.swift index 786f0fb8..16ab4383 100644 --- a/Sources/SWBProtocol/MessageSupport.swift +++ b/Sources/SWBProtocol/MessageSupport.swift @@ -349,27 +349,20 @@ public struct RunDestinationInfo: SerializableCodable, Hashable, Sendable { public init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - do { + if let buildTarget = try container.decodeIfPresent(BuildTarget.self, forKey: .buildTarget) { + self.buildTarget = buildTarget + } else { // Handle the message payload from earlier versions that didn't have the buildTarget enumeration let platform = try container.decode(String.self, forKey: .platform) let sdk: String = try container.decode(String.self, forKey: .sdk) let sdkVariant: String? = try container.decode(String?.self, forKey: .sdkVariant) self.buildTarget = .toolchainSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant) - } catch DecodingError.keyNotFound { - // This message is current and has the build target - self.buildTarget = try container.decode(BuildTarget.self, forKey: .buildTarget) } self.targetArchitecture = try container.decode(String.self, forKey: .targetArchitecture) self.supportedArchitectures = try container.decode(OrderedSet.self, forKey: .supportedArchitectures) self.disableOnlyActiveArch = try container.decode(Bool.self, forKey: .disableOnlyActiveArch) - - // Some versions of the message don't have this field - do { - self.hostTargetedPlatform = try container.decode(String?.self, forKey: .hostTargetedPlatform) - } catch DecodingError.keyNotFound { - self.hostTargetedPlatform = nil - } + self.hostTargetedPlatform = try container.decodeIfPresent(String.self, forKey: .hostTargetedPlatform) } public func encode(to encoder: any Encoder) throws { diff --git a/Sources/SwiftBuild/SWBBuildParameters.swift b/Sources/SwiftBuild/SWBBuildParameters.swift index 624481dd..e9354521 100644 --- a/Sources/SwiftBuild/SWBBuildParameters.swift +++ b/Sources/SwiftBuild/SWBBuildParameters.swift @@ -46,22 +46,6 @@ public struct SWBRunDestinationInfo: Codable, Sendable { public static func swiftSDK(sdkManifestPath: String, triple: String) -> SWBBuildTarget { SWBBuildTarget(_internalBuildTarget: .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple)) } - - public func asToolchainSDK() -> (platform: String, sdk: String, sdkVariant: String?)? { - guard case let .toolchainSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant) = _internalBuildTarget else { - return nil - } - - return (platform: platform, sdk: sdk, sdkVariant: sdkVariant) - } - - public func asSwiftSDK() -> (sdkManifestPath: String, triple: String)? { - guard case let .swiftSDK(sdkManifestPath: sdkManifestPath, triple: triple) = _internalBuildTarget else { - return nil - } - - return (sdkManifestPath: sdkManifestPath, triple: triple) - } } public var buildTarget: SWBBuildTarget @@ -86,21 +70,20 @@ public struct SWBRunDestinationInfo: Codable, Sendable { public init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - do { + if let buildTarget = try container.decodeIfPresent(SWBBuildTarget.self, forKey: .buildTarget) { + self.buildTarget = buildTarget + } else { // Handle the message payload from earlier versions that didn't have the buildTarget enumeration let platform = try container.decode(String.self, forKey: .platform) let sdk: String = try container.decode(String.self, forKey: .sdk) let sdkVariant: String? = try container.decode(String?.self, forKey: .sdkVariant) self.buildTarget = .toolchainSDK(platform: platform, sdk: sdk, sdkVariant: sdkVariant) - } catch DecodingError.keyNotFound { - // This message is current and has the build target - self.buildTarget = try container.decode(SWBBuildTarget.self, forKey: .buildTarget) } self.targetArchitecture = try container.decode(String.self, forKey: .targetArchitecture) self.supportedArchitectures = try container.decode([String].self, forKey: .supportedArchitectures) self.disableOnlyActiveArch = try container.decode(Bool.self, forKey: .disableOnlyActiveArch) - self.hostTargetedPlatform = try container.decode(String?.self, forKey: .hostTargetedPlatform) + self.hostTargetedPlatform = try container.decodeIfPresent(String.self, forKey: .hostTargetedPlatform) } public func encode(to encoder: any Encoder) throws {