From d8540b66e251d3031e74fc941e0458f7762fe07d Mon Sep 17 00:00:00 2001 From: Finagolfin Date: Thu, 16 Apr 2026 20:20:19 +0530 Subject: [PATCH 1/3] Fix searching for SDKs when a `--triple` is specified along with the SDK name Extend `selectBundle()` to use the existing `selectSwiftSDK(id:hostTriple:targetTriple)` overload, plus fix the latter to check the full triple string, which affects `swift sdk configure` also. Fixes #7973 and #9220 --- Sources/PackageModel/SwiftSDKs/SwiftSDK.swift | 2 +- .../SwiftSDKs/SwiftSDKBundle.swift | 2 +- .../SwiftSDKs/SwiftSDKBundleStore.swift | 23 ++++++++++++++++++- .../CommandsTests/SwiftSDKCommandTests.swift | 15 ++++++++++++ .../SwiftSDKBundleTests.swift | 8 +++++++ 5 files changed, 47 insertions(+), 3 deletions(-) diff --git a/Sources/PackageModel/SwiftSDKs/SwiftSDK.swift b/Sources/PackageModel/SwiftSDKs/SwiftSDK.swift index fced8a250fe..53bf546c3d1 100644 --- a/Sources/PackageModel/SwiftSDKs/SwiftSDK.swift +++ b/Sources/PackageModel/SwiftSDKs/SwiftSDK.swift @@ -786,7 +786,7 @@ public struct SwiftSDK: Equatable { swiftSDK = targetSwiftSDK } else if let swiftSDKSelector { do { - swiftSDK = try store.selectBundle(matching: swiftSDKSelector, hostTriple: hostTriple) + swiftSDK = try store.selectBundle(matching: swiftSDKSelector, hostTriple: hostTriple, targetTriple: customCompileTriple) } catch { // If a user-installed bundle for the selector doesn't exist, check if the // selector is recognized as a default SDK. diff --git a/Sources/PackageModel/SwiftSDKs/SwiftSDKBundle.swift b/Sources/PackageModel/SwiftSDKs/SwiftSDKBundle.swift index a353c08ba53..96cebda19f7 100644 --- a/Sources/PackageModel/SwiftSDKs/SwiftSDKBundle.swift +++ b/Sources/PackageModel/SwiftSDKs/SwiftSDKBundle.swift @@ -67,7 +67,7 @@ extension [SwiftSDKBundle] { } } - return variant.swiftSDKs.first { $0.targetTriple == targetTriple } + return variant.swiftSDKs.first { $0.targetTriple?.tripleString == targetTriple.tripleString } } } } diff --git a/Sources/PackageModel/SwiftSDKs/SwiftSDKBundleStore.swift b/Sources/PackageModel/SwiftSDKs/SwiftSDKBundleStore.swift index 5b506feba78..226112c1210 100644 --- a/Sources/PackageModel/SwiftSDKs/SwiftSDKBundleStore.swift +++ b/Sources/PackageModel/SwiftSDKs/SwiftSDKBundleStore.swift @@ -47,6 +47,7 @@ public final class SwiftSDKBundleStore { enum Error: Swift.Error, CustomStringConvertible { case noMatchingSwiftSDK(selector: String, hostTriple: Triple) + case noMatchingSwiftSDKWithTriple(selector: String, hostTriple: Triple, targetTriple: Triple) var description: String { switch self { @@ -56,6 +57,12 @@ public final class SwiftSDKBundleStore { `\(hostTriple.tripleString)`. Use `swift sdk list` command to see \ available Swift SDKs. """ + case let .noMatchingSwiftSDKWithTriple(selector, hostTriple, targetTriple): + return """ + No Swift SDK found matching query `\(selector)`, target triple \ + `\(targetTriple.tripleString)`, and host triple `\(hostTriple.tripleString)`. \ + Use `swift sdk list` command to see available Swift SDKs. + """ } } } @@ -123,10 +130,12 @@ public final class SwiftSDKBundleStore { /// - Parameters: /// - query: either an artifact ID or target triple to filter with. /// - hostTriple: triple of the host building with these Swift SDKs. + /// - targetTriple: optional separate target triple to look for /// - Returns: ``SwiftSDK`` value matching `query` either by artifact ID or target triple, `nil` if none found. public func selectBundle( matching selector: String, - hostTriple: Triple + hostTriple: Triple, + targetTriple: Triple? = nil ) throws -> SwiftSDK { let validBundles = try self.allValidBundles @@ -136,6 +145,18 @@ public final class SwiftSDKBundleStore { ) } + if let triple = targetTriple { + guard var selectedSwiftSDK = validBundles.selectSwiftSDK( + id: selector, + hostTriple: hostTriple, + targetTriple: triple + ) else { + throw Error.noMatchingSwiftSDKWithTriple(selector: selector, hostTriple: hostTriple, targetTriple: triple) + } + selectedSwiftSDK.applyPathCLIOptions() + return selectedSwiftSDK + } + guard var selectedSwiftSDKs = validBundles.selectSwiftSDK( matching: selector, hostTriple: hostTriple, diff --git a/Tests/CommandsTests/SwiftSDKCommandTests.swift b/Tests/CommandsTests/SwiftSDKCommandTests.swift index c3f62369fdc..157e4b0ca9f 100644 --- a/Tests/CommandsTests/SwiftSDKCommandTests.swift +++ b/Tests/CommandsTests/SwiftSDKCommandTests.swift @@ -295,6 +295,21 @@ struct SwiftSDKCommandTests { } } + await expectThrowsCommandExecutionError( + try await command.execute( + [ + "configure", "--show-configuration", + "--swift-sdks-path", fixturePath.pathString, + "test-artifact", + "aarch64-unknown-linux-gnu11.0", + ] + ) + ) { error in + let stderr = error.stderr + #expect(stderr.contains("Error: Swift SDK with ID `test-artifact`, host triple ")) + #expect(stderr.contains(", and target triple aarch64-unknown-linux-gnu11.0 is not currently installed.")) + } + (stdout, stderr) = try await command.execute( ["remove", "--swift-sdks-path", fixturePath.pathString, "test-artifact"]) diff --git a/Tests/PackageModelTests/SwiftSDKBundleTests.swift b/Tests/PackageModelTests/SwiftSDKBundleTests.swift index 8262336c8c3..5856b0e1e71 100644 --- a/Tests/PackageModelTests/SwiftSDKBundleTests.swift +++ b/Tests/PackageModelTests/SwiftSDKBundleTests.swift @@ -391,6 +391,14 @@ final class SwiftSDKBundleTests: XCTestCase { bundleName: AbsolutePath(bundles[1].path).components.last! ), ]) + + let tripleSDK = try store.selectBundle( + matching: "\(testArtifactID)1", + hostTriple: Triple("arm64-apple-macosx14.0"), + targetTriple: targetTriple + ) + + XCTAssertEqual(tripleSDK.targetTriple, targetTriple) } func testTargetSDKDerivation() async throws { From 019b447c5b43b4058e534e4cfaf21aaed3e6afa8 Mon Sep 17 00:00:00 2001 From: Finagolfin Date: Mon, 20 Apr 2026 22:09:51 +0530 Subject: [PATCH 2/3] Error if multiple Swift SDKs match `--swift-sdk ` ### Motivation: SDK search assumed you knew what you're doing and would pick any SDK that matched, time to make that more strict. ### Modifications: Collect all matches instead, then spit out different errors if there were multiple matches. ### Result: Emphasize to SDK users that they need to have their installed SDKs not contain the same target triples, when selecting with a triple alone. --- Sources/PackageModel/SwiftSDKs/SwiftSDK.swift | 2 +- .../SwiftSDKs/SwiftSDKBundle.swift | 63 ++------- .../SwiftSDKs/SwiftSDKBundleStore.swift | 60 ++++++-- .../SwiftSDKBundleTests.swift | 102 +++++++++++++- Tests/PackageModelTests/SwiftSDKTests.swift | 130 +++++++++++++++--- 5 files changed, 274 insertions(+), 83 deletions(-) diff --git a/Sources/PackageModel/SwiftSDKs/SwiftSDK.swift b/Sources/PackageModel/SwiftSDKs/SwiftSDK.swift index 53bf546c3d1..0ec7074cf82 100644 --- a/Sources/PackageModel/SwiftSDKs/SwiftSDK.swift +++ b/Sources/PackageModel/SwiftSDKs/SwiftSDK.swift @@ -786,7 +786,7 @@ public struct SwiftSDK: Equatable { swiftSDK = targetSwiftSDK } else if let swiftSDKSelector { do { - swiftSDK = try store.selectBundle(matching: swiftSDKSelector, hostTriple: hostTriple, targetTriple: customCompileTriple) + (_, swiftSDK) = try store.selectBundle(matching: swiftSDKSelector, hostTriple: hostTriple, targetTriple: customCompileTriple) } catch { // If a user-installed bundle for the selector doesn't exist, check if the // selector is recognized as a default SDK. diff --git a/Sources/PackageModel/SwiftSDKs/SwiftSDKBundle.swift b/Sources/PackageModel/SwiftSDKs/SwiftSDKBundle.swift index 96cebda19f7..020267d7a17 100644 --- a/Sources/PackageModel/SwiftSDKs/SwiftSDKBundle.swift +++ b/Sources/PackageModel/SwiftSDKs/SwiftSDKBundle.swift @@ -79,15 +79,14 @@ extension [SwiftSDKBundle] { /// - Parameters: /// - selector: either an artifact ID or target triple to filter with. /// - hostTriple: triple of the host building with these Swift SDKs. - /// - observabilityScope: observability scope to log warnings about multiple matches. - /// - Returns: ``SwiftSDK`` value matching `query` either by artifact ID or target triple, `nil` if none found. + /// - Returns: a tuple containing all `selector` matches to the artifact ID or target triple, + /// including the corresponding artifact ID for each target triple matched func selectSwiftSDK( matching selector: String, - hostTriple: Triple, - observabilityScope: ObservabilityScope - ) -> SwiftSDK? { - var matchedByID: (path: AbsolutePath, variant: SwiftSDKBundle.Variant, swiftSDK: SwiftSDK)? - var matchedByTriple: (path: AbsolutePath, variant: SwiftSDKBundle.Variant, swiftSDK: SwiftSDK)? + hostTriple: Triple + ) -> (idMatches: [SwiftSDK], tripleMatches: [String: SwiftSDK]) { + var idHits: [SwiftSDK] = [] + var tripleHits: [String: SwiftSDK] = [:] for bundle in self { for (artifactID, variants) in bundle.artifacts { @@ -95,56 +94,22 @@ extension [SwiftSDKBundle] { guard variant.isSupporting(hostTriple: hostTriple) else { continue } for swiftSDK in variant.swiftSDKs { + // All artifact IDs are checked by installIfValid() to be + // unique, but the selected ID must only have one target triple, + // in this method where no target triple is specified with the ID. if artifactID == selector { - if let matchedByID { - observabilityScope.emit( - warning: - """ - multiple Swift SDKs match ID `\(artifactID)` and host triple \( - hostTriple.tripleString - ), selected one at \( - matchedByID.path.appending(matchedByID.variant.metadata.path) - ) - """ - ) - } else { - matchedByID = (bundle.path, variant, swiftSDK) - } + idHits.append(swiftSDK) } - + // Multiple SDKs can vend the same triple, so list them all and + // return the corresponding artifact ID also. if swiftSDK.targetTriple?.tripleString == selector { - if let matchedByTriple { - observabilityScope.emit( - warning: - """ - multiple Swift SDKs match target triple `\(selector)` and host triple \( - hostTriple.tripleString - ), selected one at \( - matchedByTriple.path.appending(matchedByTriple.variant.metadata.path) - ) - """ - ) - } else { - matchedByTriple = (bundle.path, variant, swiftSDK) - } + tripleHits[artifactID] = swiftSDK } } } } } - - if let matchedByID, let matchedByTriple, matchedByID != matchedByTriple { - observabilityScope.emit( - warning: - """ - multiple Swift SDKs match the query `\(selector)` and host triple \( - hostTriple.tripleString - ), selected one at \(matchedByID.path.appending(matchedByID.variant.metadata.path)) - """ - ) - } - - return matchedByID?.swiftSDK ?? matchedByTriple?.swiftSDK + return (idMatches: idHits, tripleMatches: tripleHits) } public var sortedArtifactIDs: [String] { diff --git a/Sources/PackageModel/SwiftSDKs/SwiftSDKBundleStore.swift b/Sources/PackageModel/SwiftSDKs/SwiftSDKBundleStore.swift index 226112c1210..3166b262423 100644 --- a/Sources/PackageModel/SwiftSDKs/SwiftSDKBundleStore.swift +++ b/Sources/PackageModel/SwiftSDKs/SwiftSDKBundleStore.swift @@ -46,22 +46,43 @@ public final class SwiftSDKBundleStore { } enum Error: Swift.Error, CustomStringConvertible { + case matchingBothToSwiftSDK(selector: String, hostTriple: Triple) + case multipleSDKMatchesForID(selector: String, hostTriple: Triple) + case multipleSDKMatchesForTriple(selector: String, hostTriple: Triple, matches: [String]) case noMatchingSwiftSDK(selector: String, hostTriple: Triple) case noMatchingSwiftSDKWithTriple(selector: String, hostTriple: Triple, targetTriple: Triple) var description: String { switch self { + case let .matchingBothToSwiftSDK(selector, hostTriple): + return """ + The query for `\(selector)` and host triple `\(hostTriple.tripleString)` \ + matched both an SDK and a target triple. Use the `swift sdk list` command \ + to see available Swift SDKs and remove one of them. + """ + case let .multipleSDKMatchesForID(selector, hostTriple): + return """ + The query for `\(selector)` and host triple `\(hostTriple.tripleString)` \ + has multiple target triples. Use the `--triple` flag to specify a triple. + """ + case let .multipleSDKMatchesForTriple(selector, hostTriple, matches): + return """ + The query for `\(selector)` and host triple `\(hostTriple.tripleString)` \ + matched multiple SDKs: \(matches.joined(separator: ", ")). Use the \ + `swift sdk list` command to see available Swift SDKs and try a different \ + query like `--swift-sdk \(matches[0]) --triple \(selector)` or remove an SDK. + """ case let .noMatchingSwiftSDK(selector, hostTriple): return """ No Swift SDK found matching query `\(selector)` and host triple \ - `\(hostTriple.tripleString)`. Use `swift sdk list` command to see \ + `\(hostTriple.tripleString)`. Use the `swift sdk list` command to see \ available Swift SDKs. """ case let .noMatchingSwiftSDKWithTriple(selector, hostTriple, targetTriple): return """ No Swift SDK found matching query `\(selector)`, target triple \ `\(targetTriple.tripleString)`, and host triple `\(hostTriple.tripleString)`. \ - Use `swift sdk list` command to see available Swift SDKs. + Use the `swift sdk list` command to see available Swift SDKs. """ } } @@ -128,15 +149,16 @@ public final class SwiftSDKBundleStore { /// Select a Swift SDK matching a given query and host triple from all Swift SDKs available in /// ``SwiftSDKBundleStore//swiftSDKsDirectory``. /// - Parameters: - /// - query: either an artifact ID or target triple to filter with. + /// - selector: either an artifact ID or target triple to filter with. /// - hostTriple: triple of the host building with these Swift SDKs. /// - targetTriple: optional separate target triple to look for - /// - Returns: ``SwiftSDK`` value matching `query` either by artifact ID or target triple, `nil` if none found. + /// - Returns: tuple with the Artifact ID and ``SwiftSDK`` value that matched `selector` either by + /// artifact ID or target triple, throws if multiple or none found. public func selectBundle( matching selector: String, hostTriple: Triple, targetTriple: Triple? = nil - ) throws -> SwiftSDK { + ) throws -> (String, SwiftSDK) { let validBundles = try self.allValidBundles guard !validBundles.isEmpty else { @@ -154,20 +176,32 @@ public final class SwiftSDKBundleStore { throw Error.noMatchingSwiftSDKWithTriple(selector: selector, hostTriple: hostTriple, targetTriple: triple) } selectedSwiftSDK.applyPathCLIOptions() - return selectedSwiftSDK + return (selector, selectedSwiftSDK) } - guard var selectedSwiftSDKs = validBundles.selectSwiftSDK( - matching: selector, - hostTriple: hostTriple, - observabilityScope: self.observabilityScope - ) else { + var selectedSwiftSDK: SwiftSDK + var id: String + let SDKs = validBundles.selectSwiftSDK(matching: selector, hostTriple: hostTriple) + if SDKs.tripleMatches.count > 1 { + throw Error.multipleSDKMatchesForTriple(selector: selector, hostTriple: hostTriple, matches: Array(SDKs.tripleMatches.keys).sorted()) + } else if SDKs.idMatches.count > 1 { + throw Error.multipleSDKMatchesForID(selector: selector, hostTriple: hostTriple) + } else if SDKs.idMatches.count == 1 { + guard SDKs.tripleMatches.count == 0 else { + throw Error.matchingBothToSwiftSDK(selector: selector, hostTriple: hostTriple) + } + id = selector + selectedSwiftSDK = SDKs.idMatches[0] + } else if let match = SDKs.tripleMatches.first { + id = match.key + selectedSwiftSDK = match.value + } else { throw Error.noMatchingSwiftSDK(selector: selector, hostTriple: hostTriple) } - selectedSwiftSDKs.applyPathCLIOptions() + selectedSwiftSDK.applyPathCLIOptions() - return selectedSwiftSDKs + return (id, selectedSwiftSDK) } /// Installs a Swift SDK bundle from a given path or URL to ``SwiftSDKBundleStore//swiftSDKsDirectory``. diff --git a/Tests/PackageModelTests/SwiftSDKBundleTests.swift b/Tests/PackageModelTests/SwiftSDKBundleTests.swift index 5856b0e1e71..39c04a611d5 100644 --- a/Tests/PackageModelTests/SwiftSDKBundleTests.swift +++ b/Tests/PackageModelTests/SwiftSDKBundleTests.swift @@ -375,12 +375,13 @@ final class SwiftSDKBundleTests: XCTestCase { try await store.install(bundlePathOrURL: bundle.path, archiver) } - let sdk = try store.selectBundle( + let (id, sdk) = try store.selectBundle( matching: "\(testArtifactID)1", hostTriple: Triple("arm64-apple-macosx14.0") ) XCTAssertEqual(sdk.targetTriple, targetTriple) + XCTAssertEqual(id, "\(testArtifactID)1") XCTAssertEqual(output, [ .installationSuccessful( bundlePathOrURL: bundles[0].path, @@ -392,13 +393,107 @@ final class SwiftSDKBundleTests: XCTestCase { ), ]) - let tripleSDK = try store.selectBundle( + let (name, tripleSDK) = try store.selectBundle( matching: "\(testArtifactID)1", hostTriple: Triple("arm64-apple-macosx14.0"), targetTriple: targetTriple ) XCTAssertEqual(tripleSDK.targetTriple, targetTriple) + XCTAssertEqual(name, "\(testArtifactID)1") + + let (match, matchSDK) = try store.selectBundle( + matching: "\(targetTriple.tripleString)", + hostTriple: Triple("i686-apple-macosx14.0") + ) + + XCTAssertEqual(matchSDK.targetTriple, targetTriple) + XCTAssertEqual(match, "\(testArtifactID)2") + } + + func testBundleSelectionByTripleAndErrors() async throws { + let (fileSystem, bundles, swiftSDKsDirectory) = try generateTestFileSystem( + bundleArtifacts: [ + .init(id: "\(testArtifactID)1", supportedTriples: [arm64Triple]), + .init(id: "\(testArtifactID)2", supportedTriples: [arm64Triple]), + .init(id: "\(targetTriple.tripleString)", supportedTriples: [i686Triple]) + ] + ) + let system = ObservabilitySystem.makeForTesting() + + var output = [SwiftSDKBundleStore.Output]() + let store = SwiftSDKBundleStore( + swiftSDKsDirectory: swiftSDKsDirectory, + hostToolchainBinDir: "/tmp", + fileSystem: fileSystem, + observabilityScope: system.topScope, + outputHandler: { + output.append($0) + } + ) + + let archiver = MockArchiver() + for bundle in bundles { + try await store.install(bundlePathOrURL: bundle.path, archiver) + } + + XCTAssertThrowsError(try store.selectBundle( + matching: "\(testArtifactID)3", + hostTriple: Triple("arm64-apple-macosx14.0"), + targetTriple: targetTriple + )) { error in + XCTAssertEqual( + "\(error)", + """ + No Swift SDK found matching query `\(testArtifactID)3`, target triple \ + `\(targetTriple.tripleString)`, and host triple `arm64-apple-macosx14.0`. \ + Use the `swift sdk list` command to see available Swift SDKs. + """ + ) + } + + XCTAssertThrowsError(try store.selectBundle( + matching: targetTriple.tripleString, + hostTriple: Triple("arm64-apple-macosx14.0") + )) { error in + XCTAssertEqual( + "\(error)", + """ + The query for `\(targetTriple.tripleString)` and host triple `arm64-apple-macosx14.0` \ + matched multiple SDKs: \(testArtifactID)1, \(testArtifactID)2. Use the \ + `swift sdk list` command to see available Swift SDKs and try a different \ + query like `--swift-sdk \(testArtifactID)1 --triple \(targetTriple.tripleString)` or remove an SDK. + """ + ) + } + + XCTAssertThrowsError(try store.selectBundle( + matching: "\(targetTriple.tripleString)", + hostTriple: Triple("i686-apple-macosx14.0") + )) { error in + XCTAssertEqual( + "\(error)", + """ + The query for `\(targetTriple.tripleString)` and host triple `i686-apple-macosx14.0` \ + matched both an SDK and a target triple. Use the `swift sdk list` command \ + to see available Swift SDKs and remove one of them. + """ + ) + } + + XCTAssertThrowsError(try store.selectBundle( + matching: "armv7-unknown-linux", + hostTriple: Triple("arm64-apple-macosx14.0") + )) { error in + XCTAssertEqual( + "\(error)", + """ + No Swift SDK found matching query `armv7-unknown-linux` and host triple \ + `arm64-apple-macosx14.0`. Use the `swift sdk list` command to see \ + available Swift SDKs. + """ + ) + } } func testTargetSDKDerivation() async throws { @@ -586,12 +681,13 @@ final class SwiftSDKBundleTests: XCTestCase { } let hostTriple = try Triple("arm64-apple-macosx14.0") - let sdk = try store.selectBundle( + let (id, sdk) = try store.selectBundle( matching: testArtifactID, hostTriple: hostTriple ) XCTAssertEqual(sdk.targetTriple, targetTriple) + XCTAssertEqual(id, testArtifactID) XCTAssertEqual(output, [ .installationSuccessful( bundlePathOrURL: bundles[0].path, diff --git a/Tests/PackageModelTests/SwiftSDKTests.swift b/Tests/PackageModelTests/SwiftSDKTests.swift index 37877f3840c..d2db91a71f9 100644 --- a/Tests/PackageModelTests/SwiftSDKTests.swift +++ b/Tests/PackageModelTests/SwiftSDKTests.swift @@ -26,6 +26,7 @@ private let olderHostTriple = try! Triple("arm64-apple-darwin20.1.0") private let linuxGNUTargetTriple = try! Triple("x86_64-unknown-linux-gnu") private let linuxMuslTargetTriple = try! Triple("x86_64-unknown-linux-musl") private let androidTargetTriple = try! Triple("aarch64-unknown-linux-android28") +private let androidx64TargetTriple = try! Triple("x86_64-unknown-linux-android35") private let wasiTargetTriple = try! Triple("wasm32-unknown-wasi") private let extraFlags = BuildFlags( cCompilerFlags: ["-fintegrated-as"], @@ -201,6 +202,20 @@ private let androidWithoutSDKRootPathSwiftSDKv4 = ( """# as SerializedJSON ) +private let androidx64WithoutSDKRootPathSwiftSDKv4 = ( + path: bundleRootPath.appending(component: "androidWithoutSDKRootPathSwiftSDKv4.json"), + json: #""" + { + "targetTriples": { + "\#(androidx64TargetTriple.tripleString)": { + "toolsetPaths": ["/tools/otherToolsNoRoot.json"] + } + }, + "schemaVersion": "4.0" + } + """# as SerializedJSON +) + private let missingToolsetSwiftSDKv4 = ( path: bundleRootPath.appending(component: "missingToolsetSwiftSDKv4.json"), json: #""" @@ -386,6 +401,24 @@ private let parsedToolsetNoSDKRootPathDestination = SwiftSDK( ) ) +private let parsedAndroidToolsetNoSDKRootPathDestination = SwiftSDK( + targetTriple: androidx64TargetTriple, + toolset: .init( + knownTools: [ + .librarian: .init(path: try! AbsolutePath(validating: "\(usrBinTools[.librarian]!)")), + .linker: .init(path: try! AbsolutePath(validating: "\(usrBinTools[.linker]!)")), + .debugger: .init(path: try! AbsolutePath(validating: "\(usrBinTools[.debugger]!)")), + ], + rootPaths: [] + ), + swiftSDKManifest: androidx64WithoutSDKRootPathSwiftSDKv4.path, + pathsConfiguration: .init( + sdkRootPath: nil, + toolsetPaths: ["/tools/otherToolsNoRoot.json"] + .map { try! AbsolutePath(validating: $0) } + ) +) + private let testFiles: [(path: AbsolutePath, json: SerializedJSON)] = [ destinationV1, destinationV2, @@ -678,14 +711,11 @@ final class SwiftSDKTests: XCTestCase { ), ] - let system = ObservabilitySystem.makeForTesting() - XCTAssertEqual( bundles.selectSwiftSDK( matching: "id1", - hostTriple: hostTriple, - observabilityScope: system.topScope - ), + hostTriple: hostTriple + ).idMatches.first, parsedDestinationV2GNU ) @@ -694,17 +724,15 @@ final class SwiftSDKTests: XCTestCase { XCTAssertNil( bundles.selectSwiftSDK( matching: "id2", - hostTriple: hostTriple, - observabilityScope: system.topScope - ) + hostTriple: hostTriple + ).idMatches.first ) XCTAssertEqual( bundles.selectSwiftSDK( matching: "id3", - hostTriple: hostTriple, - observabilityScope: system.topScope - ), + hostTriple: hostTriple + ).idMatches.first, parsedDestinationV2Musl ) @@ -720,9 +748,8 @@ final class SwiftSDKTests: XCTestCase { XCTAssertEqual( bundles.selectSwiftSDK( matching: "id4", - hostTriple: hostTriple, - observabilityScope: system.topScope - ), + hostTriple: hostTriple + ).idMatches.first, parsedDestinationForOlderHost ) @@ -738,9 +765,8 @@ final class SwiftSDKTests: XCTestCase { XCTAssertEqual( bundles.selectSwiftSDK( matching: "id5", - hostTriple: hostTriple, - observabilityScope: system.topScope - ), + hostTriple: hostTriple + ).idMatches.first, parsedDestinationV2GNU ) } @@ -769,4 +795,74 @@ final class SwiftSDKTests: XCTestCase { XCTAssertFalse(cFlags.contains { $0.lowercased().contains("macos") }, "Found macOS path in \(cFlags)") #endif } + + func testSelectSDKWithMultipleMatches() throws { + let bundles = [ + SwiftSDKBundle( + path: try AbsolutePath(validating: "/droidSDKs.artifactsbundle"), + artifacts: [ + "droid-multiarch": [ + .init( + metadata: .init( + path: "droid", + supportedTriples: [hostTriple] + ), + swiftSDKs: [parsedToolsetNoSDKRootPathDestination, parsedAndroidToolsetNoSDKRootPathDestination] + ), + ], + "droid-single": [ + .init( + metadata: .init( + path: "droid-single", + supportedTriples: [hostTriple] + ), + swiftSDKs: [parsedToolsetNoSDKRootPathDestination] + ), + ], + ] + ), + ] + + XCTAssertEqual( + bundles.selectSwiftSDK( + id: "droid-multiarch", + hostTriple: hostTriple, + targetTriple: androidTargetTriple + ), + parsedToolsetNoSDKRootPathDestination + ) + + XCTAssertNil( + bundles.selectSwiftSDK( + id: "droid-single", + hostTriple: hostTriple, + targetTriple: androidx64TargetTriple + ) + ) + + XCTAssertEqual( + bundles.selectSwiftSDK( + matching: androidTargetTriple.tripleString, + hostTriple: hostTriple + ).tripleMatches, + ["droid-multiarch" : parsedToolsetNoSDKRootPathDestination, + "droid-single" : parsedToolsetNoSDKRootPathDestination] + ) + + XCTAssertEqual( + bundles.selectSwiftSDK( + matching: androidx64TargetTriple.tripleString, + hostTriple: hostTriple + ).tripleMatches, + ["droid-multiarch" : parsedAndroidToolsetNoSDKRootPathDestination] + ) + + XCTAssertEqual( + bundles.selectSwiftSDK( + matching: "droid-multiarch", + hostTriple: hostTriple + ).idMatches, + [parsedToolsetNoSDKRootPathDestination, parsedAndroidToolsetNoSDKRootPathDestination] + ) + } } From e1e00f7c4963587bc36625ad5b56b7ee0e62aedc Mon Sep 17 00:00:00 2001 From: Finagolfin Date: Wed, 29 Apr 2026 21:59:11 +0530 Subject: [PATCH 3/3] Fix initializing `librarySearchPaths` in UserToolchain --- Sources/PackageModel/UserToolchain.swift | 2 +- Tests/BuildTests/BuildPlanTests.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/PackageModel/UserToolchain.swift b/Sources/PackageModel/UserToolchain.swift index 4bb37aa6965..d76821f588c 100644 --- a/Sources/PackageModel/UserToolchain.swift +++ b/Sources/PackageModel/UserToolchain.swift @@ -857,7 +857,7 @@ public final class UserToolchain: Toolchain { xcbuildFlags: swiftSDK.toolset.knownTools[.xcbuild]?.extraCLIOptions ?? []) self.includeSearchPaths = swiftSDK.pathsConfiguration.includeSearchPaths ?? [] - self.librarySearchPaths = swiftSDK.pathsConfiguration.includeSearchPaths ?? [] + self.librarySearchPaths = swiftSDK.pathsConfiguration.librarySearchPaths ?? [] self.librarianPath = try swiftSDK.toolset.knownTools[.librarian]?.path ?? UserToolchain.determineLibrarian( triple: triple, diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index ae60bd3eec4..6f0cae70ebf 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -5598,7 +5598,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { // Link Product let exeLinkArguments = try result.buildProduct(for: "exe").linkArguments() - let exeLinkArgumentsPattern: [StringPattern] = ["-L", "\(sdkIncludeSearchPath)"] + let exeLinkArgumentsPattern: [StringPattern] = ["-L", "\(sdkLibrarySearchPath)"] XCTAssertMatch(exeLinkArguments, exeLinkArgumentsPattern) }