Skip to content

Commit a54dd3b

Browse files
authored
Use a different path extension for swift-testing builds (#7163)
Currently, SwiftPM is using the same path to build swift-testing and XCTest content. This works about 90% of the time because we only need one or the other at any given moment, but it causes some workflows to fail on Linux because the build system sees the existing build product and assumes the build has already completed, which is incorrect. Darwin doesn't seem to be affected (because the XCTest build product is a bundle rather than an executable.) This PR selects a different path extension, ".swift-testing", for swift-testing's build product.
1 parent 3e4ec32 commit a54dd3b

File tree

10 files changed

+53
-25
lines changed

10 files changed

+53
-25
lines changed

Sources/Build/BuildManifest/LLBuildManifestBuilder.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,9 @@ extension LLBuildManifestBuilder {
268268

269269
let outputs = testEntryPointTarget.target.sources.paths
270270

271-
guard let mainOutput = (outputs.first { $0.basename == TestEntryPointTool.mainFileName }) else {
272-
throw InternalError("main output (\(TestEntryPointTool.mainFileName)) not found")
271+
let mainFileName = TestEntryPointTool.mainFileName(for: buildParameters.testingParameters.library)
272+
guard let mainOutput = (outputs.first { $0.basename == mainFileName }) else {
273+
throw InternalError("main output (\(mainFileName)) not found")
273274
}
274275
let cmdName = mainOutput.pathString
275276
self.manifest.addTestEntryPointCmd(

Sources/Build/BuildOperationBuildSystemDelegateHandler.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,15 +200,22 @@ final class TestDiscoveryCommand: CustomLLBuildCommand, TestBuildCommand {
200200
}
201201
}
202202

203+
extension TestEntryPointTool {
204+
public static func mainFileName(for library: BuildParameters.Testing.Library) -> String {
205+
"runner-\(library).swift"
206+
}
207+
}
208+
203209
final class TestEntryPointCommand: CustomLLBuildCommand, TestBuildCommand {
204210
private func execute(fileSystem: Basics.FileSystem, tool: TestEntryPointTool) throws {
205211
let outputs = tool.outputs.compactMap { try? AbsolutePath(validating: $0.name) }
206212

207213
// Find the main output file
214+
let mainFileName = TestEntryPointTool.mainFileName(for: self.context.buildParameters.testingParameters.library)
208215
guard let mainFile = outputs.first(where: { path in
209-
path.basename == TestEntryPointTool.mainFileName
216+
path.basename == mainFileName
210217
}) else {
211-
throw InternalError("main file output (\(TestEntryPointTool.mainFileName)) not found")
218+
throw InternalError("main file output (\(mainFileName)) not found")
212219
}
213220

214221
// Write the main file.
@@ -393,7 +400,8 @@ public struct BuildDescription: Codable {
393400
return try BuiltTestProduct(
394401
productName: desc.product.name,
395402
binaryPath: desc.binaryPath,
396-
packagePath: desc.package.path
403+
packagePath: desc.package.path,
404+
library: desc.buildParameters.testingParameters.library
397405
)
398406
}
399407
self.pluginDescriptions = pluginDescriptions

Sources/Build/BuildPlan/BuildPlan+Test.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ extension BuildPlan {
109109
resolvedTargetDependencies: [ResolvedTarget.Dependency]
110110
) throws -> SwiftTargetBuildDescription {
111111
let entryPointDerivedDir = buildParameters.buildPath.appending(components: "\(testProduct.name).derived")
112-
let entryPointMainFile = entryPointDerivedDir.appending(component: TestEntryPointTool.mainFileName)
112+
let entryPointMainFileName = TestEntryPointTool.mainFileName(for: buildParameters.testingParameters.library)
113+
let entryPointMainFile = entryPointDerivedDir.appending(component: entryPointMainFileName)
113114
let entryPointSources = Sources(paths: [entryPointMainFile], root: entryPointDerivedDir)
114115

115116
let entryPointTarget = SwiftTarget(

Sources/LLBuildManifest/Tools.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ public struct TestDiscoveryTool: ToolProtocol {
6363

6464
public struct TestEntryPointTool: ToolProtocol {
6565
public static let name: String = "test-entry-point-tool"
66-
public static let mainFileName: String = "runner.swift"
6766

6867
public var inputs: [Node]
6968
public var outputs: [Node]

Sources/SPMBuildCore/BuildParameters/BuildParameters.swift

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -286,12 +286,16 @@ public struct BuildParameters: Encodable {
286286
guard !targetTriple.isWASI() else {
287287
return try RelativePath(validating: "\(product.name).wasm")
288288
}
289-
290-
let base = "\(product.name).xctest"
291-
if targetTriple.isDarwin() {
292-
return try RelativePath(validating: "\(base)/Contents/MacOS/\(product.name)")
293-
} else {
294-
return try RelativePath(validating: base)
289+
switch testingParameters.library {
290+
case .xctest:
291+
let base = "\(product.name).xctest"
292+
if targetTriple.isDarwin() {
293+
return try RelativePath(validating: "\(base)/Contents/MacOS/\(product.name)")
294+
} else {
295+
return try RelativePath(validating: base)
296+
}
297+
case .swiftTesting:
298+
return try RelativePath(validating: "\(product.name).swift-testing")
295299
}
296300
case .macro:
297301
#if BUILD_MACROS_AS_DYLIBS

Sources/SPMBuildCore/BuiltTestProduct.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,39 @@ public struct BuiltTestProduct: Codable {
2424
public let packagePath: AbsolutePath
2525

2626
/// The path of the test bundle.
27+
///
28+
/// When the test product is not bundled (for instance, when using XCTest on
29+
/// non-Darwin targets), this path is equal to ``binaryPath``.
2730
public var bundlePath: AbsolutePath {
28-
// Go up the folder hierarchy until we find the .xctest bundle.
31+
// Go up the folder hierarchy until we find the .xctest or
32+
// .swift-testing bundle.
33+
let pathExtension: String
34+
switch library {
35+
case .xctest:
36+
pathExtension = ".xctest"
37+
case .swiftTesting:
38+
pathExtension = ".swift-testing"
39+
}
2940
let hierarchySequence = sequence(first: binaryPath, next: { $0.isRoot ? nil : $0.parentDirectory })
30-
guard let bundlePath = hierarchySequence.first(where: { $0.basename.hasSuffix(".xctest") }) else {
41+
guard let bundlePath = hierarchySequence.first(where: { $0.basename.hasSuffix(pathExtension) }) else {
3142
fatalError("could not find test bundle path from '\(binaryPath)'")
3243
}
3344

3445
return bundlePath
3546
}
3647

48+
/// The library used to build this test product.
49+
public var library: BuildParameters.Testing.Library
50+
3751
/// Creates a new instance.
3852
/// - Parameters:
3953
/// - productName: The test product name.
4054
/// - binaryPath: The path of the test binary.
4155
/// - packagePath: The path to the package this product was declared in.
42-
public init(productName: String, binaryPath: AbsolutePath, packagePath: AbsolutePath) {
56+
public init(productName: String, binaryPath: AbsolutePath, packagePath: AbsolutePath, library: BuildParameters.Testing.Library) {
4357
self.productName = productName
4458
self.binaryPath = binaryPath
4559
self.packagePath = packagePath
60+
self.library = library
4661
}
4762
}

Sources/SPMTestSupport/SwiftPMProduct.swift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,11 @@ extension SwiftPM {
4444
}
4545
}
4646

47-
/// Path to currently built binary.
48-
public var path: AbsolutePath {
49-
return Self.testBinaryPath(for: self.executableName)
47+
public var xctestBinaryPath: AbsolutePath {
48+
Self.xctestBinaryPath(for: executableName)
5049
}
5150

52-
public static func testBinaryPath(for executableName: RelativePath) -> AbsolutePath {
51+
public static func xctestBinaryPath(for executableName: RelativePath) -> AbsolutePath {
5352
#if canImport(Darwin)
5453
for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") {
5554
return try! AbsolutePath(AbsolutePath(validating: bundle.bundlePath).parentDirectory, executableName)
@@ -114,15 +113,15 @@ extension SwiftPM {
114113
#endif
115114
// FIXME: We use this private environment variable hack to be able to
116115
// create special conditions in swift-build for swiftpm tests.
117-
environment["SWIFTPM_TESTS_MODULECACHE"] = self.path.parentDirectory.pathString
116+
environment["SWIFTPM_TESTS_MODULECACHE"] = xctestBinaryPath.parentDirectory.pathString
118117
#if !os(Windows)
119118
environment["SDKROOT"] = nil
120119
#endif
121120

122121
// Unset the internal env variable that allows skipping certain tests.
123122
environment["_SWIFTPM_SKIP_TESTS_LIST"] = nil
124123

125-
var completeArgs = [self.path.pathString]
124+
var completeArgs = [xctestBinaryPath.pathString]
126125
if let packagePath = packagePath {
127126
completeArgs += ["--package-path", packagePath.pathString]
128127
}

Sources/XCBuildSupport/XcodeBuildSystem.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ public final class XcodeBuildSystem: SPMBuildCore.BuildSystem {
5656
BuiltTestProduct(
5757
productName: product.name,
5858
binaryPath: binaryPath,
59-
packagePath: package.path
59+
packagePath: package.path,
60+
library: buildParameters.testingParameters.library
6061
)
6162
)
6263
}

Tests/CommandsTests/BuildToolTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ final class BuildToolTests: CommandsTestCase {
506506
return buildArenaPath.appending(component: filename)
507507
}
508508

509-
let dummySwiftcPath = SwiftPM.testBinaryPath(for: "dummy-swiftc")
509+
let dummySwiftcPath = SwiftPM.xctestBinaryPath(for: "dummy-swiftc")
510510
let swiftCompilerPath = try UserToolchain.default.swiftCompilerPath
511511

512512
var environment = [

Tests/CommandsTests/RunToolTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ final class RunToolTests: CommandsTestCase {
123123
let sync = DispatchGroup()
124124
let outputHandler = OutputHandler(sync: sync)
125125
let process = Process(
126-
arguments: [SwiftPM.Run.path.pathString, "--package-path", fixturePath.pathString],
126+
arguments: [SwiftPM.Run.xctestBinaryPath.pathString, "--package-path", fixturePath.pathString],
127127
outputRedirection: .stream(stdout: outputHandler.handle(bytes:), stderr: outputHandler.handle(bytes:))
128128
)
129129

0 commit comments

Comments
 (0)