Skip to content

Commit 4497e77

Browse files
committed
Fix two small issues with handling of plugin triples
- We were not stringently using version-less triples in all comparisons - We were not merging the supported triples of all executable info entries into the final `toolNamesToTriples` which could lead to incorrect errors about unsupported platforms rdar://101096803
1 parent a89e99b commit 4497e77

File tree

3 files changed

+62
-14
lines changed

3 files changed

+62
-14
lines changed

Sources/SPMBuildCore/BinaryTarget+Extensions.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,14 @@ extension BinaryTarget {
7474
// Filter supported triples with versionLessTriple and pass into
7575
// ExecutableInfo; empty if non matching triples found.
7676
try entry.value.variants.map{
77-
ExecutableInfo(name: entry.key, executablePath: try AbsolutePath(validating: $0.path, relativeTo: self.artifactPath), supportedTriples: $0.supportedTriples.filter({$0 == versionLessTriple}))
77+
let filteredSupportedTriples = try $0.supportedTriples.filter({try $0.withoutVersion() == versionLessTriple})
78+
return ExecutableInfo(name: entry.key, executablePath: try AbsolutePath(validating: $0.path, relativeTo: self.artifactPath), supportedTriples: filteredSupportedTriples)
7879
}
7980
}
8081
}
8182
}
8283

83-
fileprivate extension Triple {
84+
extension Triple {
8485
func withoutVersion() throws -> Triple {
8586
if isDarwin() {
8687
let stringWithoutVersion = tripleString(forPlatformVersion: "")

Sources/SPMBuildCore/PluginInvocation.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,8 @@ extension PackageGraph {
372372

373373
let toolNamesToTriples = accessibleTools.reduce(into: [String: [String]](), { dict, tool in
374374
switch tool {
375-
case .vendedTool(let name, _, let triple):
376-
dict[name] = triple
375+
case .vendedTool(let name, _, let triples):
376+
dict[name, default: []].append(contentsOf: triples)
377377
default: break
378378
}
379379
})
@@ -533,7 +533,7 @@ public extension PluginTarget {
533533
if let target = executableOrBinaryTarget as? BinaryTarget {
534534
// TODO: Memoize this result for the host triple
535535
let execInfos = try target.parseArtifactArchives(for: hostTriple, fileSystem: fileSystem)
536-
return execInfos.map{ .vendedTool(name: $0.name, path: $0.executablePath, supportedTriples: $0.supportedTriples.map{$0.tripleString}) }
536+
return try execInfos.map{ .vendedTool(name: $0.name, path: $0.executablePath, supportedTriples: try $0.supportedTriples.map{ try $0.withoutVersion().tripleString }) }
537537
}
538538
// For an executable target we create a `builtTool`.
539539
else if executableOrBinaryTarget.type == .executable {

Tests/SPMBuildCoreTests/PluginInvocationTests.swift

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,8 +1056,7 @@ class PluginInvocationTests: XCTestCase {
10561056
}
10571057
}
10581058

1059-
1060-
func testParseArtifactNotSupportedOnTargetPlatform() throws {
1059+
func checkParseArtifactsPlatformCompatibility(artifactSupportedTriples: [Triple], hostTriple: Triple, pluginResultChecker: ([ResolvedTarget: [BuildToolPluginInvocationResult]]) throws -> ()) throws {
10611060
// Only run the test if the environment in which we're running actually supports Swift concurrency (which the plugin APIs require).
10621061
try XCTSkipIf(!UserToolchain.default.supportsSwiftConcurrency(), "skipping because test environment doesn't support concurrency")
10631062

@@ -1119,7 +1118,12 @@ class PluginInvocationTests: XCTestCase {
11191118
}
11201119
"""
11211120
try localFileSystem.writeFileContents(myPluginTargetDir.appending(component: "plugin.swift"), string: content)
1122-
let tripleString = "x86_64-apple-macos15"
1121+
let artifactVariants = artifactSupportedTriples.map {
1122+
"""
1123+
{ "path": "LocalBinaryTool.sh", "supportedTriples": ["\($0.tripleString)"] }
1124+
"""
1125+
}
1126+
11231127
try localFileSystem.writeFileContents(packageDir.appending(components: "Binaries", "LocalBinaryTool.artifactbundle", "info.json")) {
11241128
$0 <<< """
11251129
{ "schemaVersion": "1.0",
@@ -1128,9 +1132,7 @@ class PluginInvocationTests: XCTestCase {
11281132
"type": "executable",
11291133
"version": "1.2.3",
11301134
"variants": [
1131-
{ "path": "LocalBinaryTool.sh",
1132-
"supportedTriples": ["\(tripleString)"]
1133-
},
1135+
\(artifactVariants.joined(separator: ","))
11341136
]
11351137
}
11361138
}
@@ -1166,12 +1168,16 @@ class PluginInvocationTests: XCTestCase {
11661168
XCTAssertEqual(buildToolPlugin.name, "Foo")
11671169
XCTAssertEqual(buildToolPlugin.capability, .buildTool)
11681170

1171+
// Construct a toolchain with a made-up host/target triple
1172+
let destination = try Destination.default
1173+
let toolchain = try UserToolchain(destination: Destination(hostTriple: hostTriple, targetTriple: hostTriple, sdkRootDir: destination.sdkRootDir, toolchainBinDir: destination.toolchainBinDir))
1174+
11691175
// Create a plugin script runner for the duration of the test.
11701176
let pluginCacheDir = tmpPath.appending(component: "plugin-cache")
11711177
let pluginScriptRunner = DefaultPluginScriptRunner(
11721178
fileSystem: localFileSystem,
11731179
cacheDir: pluginCacheDir,
1174-
toolchain: try UserToolchain.default
1180+
toolchain: toolchain
11751181
)
11761182

11771183
// Invoke build tool plugin
@@ -1186,13 +1192,54 @@ class PluginInvocationTests: XCTestCase {
11861192
observabilityScope: observability.topScope,
11871193
fileSystem: localFileSystem
11881194
)
1189-
var checked = false
1195+
try pluginResultChecker(result)
1196+
}
1197+
}
1198+
1199+
func testParseArtifactNotSupportedOnTargetPlatform() throws {
1200+
let hostTriple = try UserToolchain.default.triple
1201+
let artifactSupportedTriples = try [Triple("riscv64-apple-windows-android")]
1202+
1203+
var checked = false
1204+
try checkParseArtifactsPlatformCompatibility(artifactSupportedTriples: artifactSupportedTriples, hostTriple: hostTriple) { result in
11901205
if let pluginResult = result.first,
11911206
let diag = pluginResult.value.first?.diagnostics,
11921207
diag.description == "[[error]: Tool ‘LocalBinaryTool’ is not supported on the target platform]" {
11931208
checked = true
11941209
}
1195-
XCTAssertTrue(checked)
1210+
}
1211+
XCTAssertTrue(checked)
1212+
}
1213+
1214+
func testParseArtifactsDoesNotCheckPlatformVersion() throws {
1215+
#if !os(macOS)
1216+
throw XCTSkip("platform versions are only available if the host is macOS")
1217+
#else
1218+
let hostTriple = try UserToolchain.default.triple
1219+
let artifactSupportedTriples = try [Triple("\(hostTriple.withoutVersion().tripleString)20.0")]
1220+
1221+
try checkParseArtifactsPlatformCompatibility(artifactSupportedTriples: artifactSupportedTriples, hostTriple: hostTriple) { result in
1222+
result.forEach {
1223+
$0.value.forEach {
1224+
XCTAssertTrue($0.succeeded, "plugin unexpectedly failed")
1225+
XCTAssertEqual($0.diagnostics.map { $0.message }, [], "plugin produced unexpected diagnostics")
1226+
}
1227+
}
1228+
}
1229+
#endif
1230+
}
1231+
1232+
func testParseArtifactsConsidersAllSupportedTriples() throws {
1233+
let hostTriple = try UserToolchain.default.triple
1234+
let artifactSupportedTriples = [hostTriple, try Triple("riscv64-apple-windows-android")]
1235+
1236+
try checkParseArtifactsPlatformCompatibility(artifactSupportedTriples: artifactSupportedTriples, hostTriple: hostTriple) { result in
1237+
result.forEach {
1238+
$0.value.forEach {
1239+
XCTAssertTrue($0.succeeded, "plugin unexpectedly failed")
1240+
XCTAssertEqual($0.diagnostics.map { $0.message }, [], "plugin produced unexpected diagnostics")
1241+
}
1242+
}
11961243
}
11971244
}
11981245
}

0 commit comments

Comments
 (0)