From 79be31adc42e09ed8a9f976986a4e40787bb0ef3 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 16 Aug 2023 15:53:22 +0100 Subject: [PATCH 1/4] Fix backward compatibility in host triple checks It's useful to be able to set host triple in Swift SDKs to `arm64-apple-macosx13.0` to allow cross-compiling from an older version of macOS. This triple is not recognized as directly matching `arm64-apple-macosx14.0` on a newer version of macOS. We should support backward compatibility with Swift SDKs that were built for older version of macOS. (cherry picked from commit 82b1e83728092ff82a1941248410832086b6c88a) # Conflicts: # Sources/PackageModel/SwiftSDKBundle.swift # Tests/PackageModelTests/SwiftSDKBundleTests.swift --- Sources/Basics/Triple+Basics.swift | 8 ++ Sources/PackageModel/SwiftSDKBundle.swift | 16 +-- .../SwiftSDKBundleTests.swift | 119 +++++++++++++----- 3 files changed, 105 insertions(+), 38 deletions(-) diff --git a/Sources/Basics/Triple+Basics.swift b/Sources/Basics/Triple+Basics.swift index e49a25d8e0d..501dc18b319 100644 --- a/Sources/Basics/Triple+Basics.swift +++ b/Sources/Basics/Triple+Basics.swift @@ -117,6 +117,14 @@ extension Triple { ) } } + + public func matches(_ triple: Triple) -> Bool { + guard self.isMacOSX, let version = self._macOSVersion, let comparedVersion = triple._macOSVersion else { + return self.tripleString == triple.tripleString + } + + return version >= comparedVersion + } } extension Triple { diff --git a/Sources/PackageModel/SwiftSDKBundle.swift b/Sources/PackageModel/SwiftSDKBundle.swift index 1bcb435ffb4..6dead3707e2 100644 --- a/Sources/PackageModel/SwiftSDKBundle.swift +++ b/Sources/PackageModel/SwiftSDKBundle.swift @@ -79,30 +79,30 @@ public struct SwiftSDKBundle { /// - observabilityScope: observability scope to log warnings about multiple matches. /// - Returns: `Destination` value matching `query` either by artifact ID or target triple, `nil` if none found. public static func selectBundle( - fromBundlesAt destinationsDirectory: AbsolutePath?, + fromBundlesAt swiftSDKsDirectory: AbsolutePath?, fileSystem: FileSystem, matching selector: String, hostTriple: Triple, observabilityScope: ObservabilityScope ) throws -> Destination { - guard let destinationsDirectory = destinationsDirectory else { + guard let swiftSDKsDirectory else { throw StringError( """ - No directory found for installed Swift SDKs, specify one + No directory found for installed Swift SDKs, specify one \ with `--experimental-swift-sdks-path` option. """ ) } let validBundles = try SwiftSDKBundle.getAllValidBundles( - swiftSDKsDirectory: destinationsDirectory, + swiftSDKsDirectory: swiftSDKsDirectory, fileSystem: fileSystem, observabilityScope: observabilityScope ) guard !validBundles.isEmpty else { throw StringError( - "No valid Swift SDK bundles found at \(destinationsDirectory)." + "No valid Swift SDK bundles found at \(swiftSDKsDirectory)." ) } @@ -113,8 +113,8 @@ public struct SwiftSDKBundle { ) else { throw StringError( """ - No Swift SDK found matching query `\(selector)` and host triple - `\(hostTriple.tripleString)`. Use `swift experimental-sdk list` command to see + No Swift SDK found matching query `\(selector)` and host triple \ + `\(hostTriple.tripleString)`. Use `swift experimental-sdk list` command to see \ available destinations. """ ) @@ -434,7 +434,7 @@ extension [SwiftSDKBundle] { for bundle in self { for (artifactID, variants) in bundle.artifacts { for variant in variants { - guard variant.metadata.supportedTriples.contains(hostTriple) else { + guard variant.metadata.supportedTriples.contains(where: { hostTriple.matches($0) }) else { continue } diff --git a/Tests/PackageModelTests/SwiftSDKBundleTests.swift b/Tests/PackageModelTests/SwiftSDKBundleTests.swift index ab232006da3..8f89bac4e8a 100644 --- a/Tests/PackageModelTests/SwiftSDKBundleTests.swift +++ b/Tests/PackageModelTests/SwiftSDKBundleTests.swift @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// import Basics -import PackageModel +@testable import PackageModel import SPMTestSupport import XCTest @@ -22,27 +22,58 @@ import class TSCBasic.InMemoryFileSystem private let testArtifactID = "test-artifact" -private func generateInfoJSON(artifacts: [MockArtifact]) -> String { - """ - { - "artifacts" : { - \(artifacts.map { - """ - "\($0.id)" : { - "type" : "swiftSDK", - "version" : "0.0.1", - "variants" : [ - { - "path" : "\($0.id)/aarch64-unknown-linux", - "supportedTriples" : \($0.supportedTriples.map(\.tripleString)) +private let targetTriple = try! Triple("aarch64-unknown-linux") + +private let jsonEncoder = JSONEncoder() + +private func generateBundleFiles(bundle: MockBundle) throws -> [(String, ByteString)] { + try [ + ( + "\(bundle.path)/info.json", + ByteString(""" + { + "artifacts" : { + \(bundle.artifacts.map { + """ + "\($0.id)" : { + "type" : "swiftSDK", + "version" : "0.0.1", + "variants" : [ + { + "path" : "\($0.id)/\(targetTriple.triple)", + "supportedTriples" : \($0.supportedTriples.map(\.tripleString)) + } + ] } - ] - } - """ - }.joined(separator: ",\n") - ) - }, - "schemaVersion" : "1.0" + """ + }.joined(separator: ",\n") + ) + }, + "schemaVersion" : "1.0" + } + """.utf8) + ), + + ] + bundle.artifacts.map { + ( + "\(bundle.path)/\($0.id)/\(targetTriple.tripleString)/swift-sdk.json", + ByteString(try generateSwiftSDKMetadata(jsonEncoder).utf8) + ) + } +} + +private func generateSwiftSDKMetadata(_ encoder: JSONEncoder) throws -> String { + try """ + { + "schemaVersion": "4.0", + "targetTriples": \( + String( + bytes: encoder.encode([ + targetTriple.tripleString: SwiftSDKMetadataV4.TripleProperties(sdkRootPath: "sdk") + ]), + encoding: .utf8 + )! + ) } """ } @@ -64,15 +95,13 @@ private func generateTestFileSystem(bundleArtifacts: [MockArtifact]) throws -> ( return MockBundle(name: "test\(i).artifactbundle", path: "/\(bundleName)", artifacts: [artifacts]) } - let fileSystem = InMemoryFileSystem( - files: Dictionary(uniqueKeysWithValues: bundles.map { - ( - "\($0.path)/info.json", - ByteString( - encodingAsUTF8: generateInfoJSON(artifacts: $0.artifacts) - ) - ) - }) + + let fileSystem = try InMemoryFileSystem( + files: Dictionary( + uniqueKeysWithValues: bundles.flatMap { + try generateBundleFiles(bundle: $0) + } + ) ) let swiftSDKsDirectory = try AbsolutePath(validating: "/sdks") @@ -209,4 +238,34 @@ final class SwiftSDKBundleTests: XCTestCase { XCTAssertEqual(validBundles.count, bundles.count) } + + func testBundleSelection() async throws { + let (fileSystem, bundles, swiftSDKsDirectory) = try generateTestFileSystem( + bundleArtifacts: [ + .init(id: "\(testArtifactID)1", supportedTriples: [arm64Triple]), + .init(id: "\(testArtifactID)2", supportedTriples: [i686Triple]) + ] + ) + let system = ObservabilitySystem.makeForTesting() + + for bundle in bundles { + try SwiftSDKBundle.install( + bundlePathOrURL: bundle.path, + swiftSDKsDirectory: swiftSDKsDirectory, + fileSystem, + MockArchiver(), + system.topScope + ) + } + + let sdk = try SwiftSDKBundle.selectBundle( + fromBundlesAt: swiftSDKsDirectory, + fileSystem: fileSystem, + matching: "\(testArtifactID)1", + hostTriple: Triple("arm64-apple-macosx14.0"), + observabilityScope: system.topScope + ) + + XCTAssertEqual(sdk.targetTriple, targetTriple) + } } From ed8a7aeb368e8bd46cd96ec786fdc9e43d8ed1ea Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sun, 20 Aug 2023 11:54:13 +0100 Subject: [PATCH 2/4] Rename `matches` to `isRuntimeCompatible` (cherry picked from commit d63a94e5614500cdcf79b9eb03a7ba466572b5d1) --- Sources/Basics/Triple+Basics.swift | 2 +- Sources/PackageModel/SwiftSDKBundle.swift | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Sources/Basics/Triple+Basics.swift b/Sources/Basics/Triple+Basics.swift index 501dc18b319..67ea4e7845b 100644 --- a/Sources/Basics/Triple+Basics.swift +++ b/Sources/Basics/Triple+Basics.swift @@ -118,7 +118,7 @@ extension Triple { } } - public func matches(_ triple: Triple) -> Bool { + public func isRuntimeCompatible(with triple: Triple) -> Bool { guard self.isMacOSX, let version = self._macOSVersion, let comparedVersion = triple._macOSVersion else { return self.tripleString == triple.tripleString } diff --git a/Sources/PackageModel/SwiftSDKBundle.swift b/Sources/PackageModel/SwiftSDKBundle.swift index 6dead3707e2..4c6647eca13 100644 --- a/Sources/PackageModel/SwiftSDKBundle.swift +++ b/Sources/PackageModel/SwiftSDKBundle.swift @@ -434,7 +434,9 @@ extension [SwiftSDKBundle] { for bundle in self { for (artifactID, variants) in bundle.artifacts { for variant in variants { - guard variant.metadata.supportedTriples.contains(where: { hostTriple.matches($0) }) else { + guard variant.metadata.supportedTriples.contains(where: { + hostTriple.isRuntimeCompatible(with: $0) + }) else { continue } From 712a525f6bc1cef1e115bb405691b139006f2270 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 24 Aug 2023 17:21:06 +0100 Subject: [PATCH 3/4] Remove previous `isRuntimeCompatible` implementation (cherry picked from commit c67a76f0994d94d99d694b2028b0fafafd04579a) --- Sources/Basics/Triple+Basics.swift | 8 -------- Sources/PackageModel/SwiftSDKBundle.swift | 13 +++++++++++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Sources/Basics/Triple+Basics.swift b/Sources/Basics/Triple+Basics.swift index 67ea4e7845b..e49a25d8e0d 100644 --- a/Sources/Basics/Triple+Basics.swift +++ b/Sources/Basics/Triple+Basics.swift @@ -117,14 +117,6 @@ extension Triple { ) } } - - public func isRuntimeCompatible(with triple: Triple) -> Bool { - guard self.isMacOSX, let version = self._macOSVersion, let comparedVersion = triple._macOSVersion else { - return self.tripleString == triple.tripleString - } - - return version >= comparedVersion - } } extension Triple { diff --git a/Sources/PackageModel/SwiftSDKBundle.swift b/Sources/PackageModel/SwiftSDKBundle.swift index 4c6647eca13..2c9a6e35c9b 100644 --- a/Sources/PackageModel/SwiftSDKBundle.swift +++ b/Sources/PackageModel/SwiftSDKBundle.swift @@ -434,8 +434,17 @@ extension [SwiftSDKBundle] { for bundle in self { for (artifactID, variants) in bundle.artifacts { for variant in variants { - guard variant.metadata.supportedTriples.contains(where: { - hostTriple.isRuntimeCompatible(with: $0) + guard variant.metadata.supportedTriples.contains(where: { variantTriple in + if + hostTriple.arch == variantTriple.arch && + hostTriple.vendor == variantTriple.vendor && + hostTriple.os == variantTriple.os && + hostTriple.environment == variantTriple.environment + { + return hostTriple.osVersion >= variantTriple.osVersion + } else { + return false + } }) else { continue } From aca347e6630b28765564e36de6cc586585388750 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 24 Aug 2023 18:20:44 +0100 Subject: [PATCH 4/4] Fix build issues --- Sources/PackageModel/SwiftSDKBundle.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/PackageModel/SwiftSDKBundle.swift b/Sources/PackageModel/SwiftSDKBundle.swift index 2c9a6e35c9b..68f60a11033 100644 --- a/Sources/PackageModel/SwiftSDKBundle.swift +++ b/Sources/PackageModel/SwiftSDKBundle.swift @@ -441,7 +441,11 @@ extension [SwiftSDKBundle] { hostTriple.os == variantTriple.os && hostTriple.environment == variantTriple.environment { - return hostTriple.osVersion >= variantTriple.osVersion + if let hostOSVersion = hostTriple.osVersion, let variantOSVersion = variantTriple.osVersion { + return hostOSVersion >= variantOSVersion + } else { + return true + } } else { return false }