Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions Sources/SWBBuildSystem/BuildOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2304,9 +2304,9 @@ internal final class OperationSystemAdaptor: SWBLLBuild.BuildSystemDelegate, Act
private func inputNounPhraseForBuildKey(_ inputKey: BuildKey) -> String {
switch inputKey {
case is BuildKey.Command, is BuildKey.CustomTask:
return "the producer"
return "the task producing"
case is BuildKey.DirectoryContents, is BuildKey.FilteredDirectoryContents, is BuildKey.DirectoryTreeSignature, is BuildKey.Node:
return "an input"
return "an input of"
case is BuildKey.Target, is BuildKey.Stat:
return "<unexpected build key>"
default:
Expand Down Expand Up @@ -2343,15 +2343,15 @@ internal final class OperationSystemAdaptor: SWBLLBuild.BuildSystemDelegate, Act
previousFrameID = nil
case .signatureChanged:
category = .ruleSignatureChanged
description = "signature of \(descriptionForBuildKey(rule)) changed"
description = "arguments, environment, or working directory of \(descriptionForBuildKey(rule)) changed"
previousFrameID = nil
case .invalidValue:
category = .ruleHadInvalidValue
previousFrameID = nil
if let command = rule as? BuildKey.Command, let task = lookupTask(TaskIdentifier(rawValue: command.name)), task.alwaysExecuteTask {
description = "\(descriptionForBuildKey(rule)) is configured to run in every incremental build"
description = "\(descriptionForBuildKey(rule)) was configured to run in every incremental build"
} else if rule is BuildKey.Command || rule is BuildKey.CustomTask {
description = "\(descriptionForBuildKey(rule)) did not have up-to-date outputs"
description = "outputs of \(descriptionForBuildKey(rule)) were missing or modified"
} else {
description = "\(descriptionForBuildKey(rule)) changed"
}
Expand All @@ -2361,7 +2361,7 @@ internal final class OperationSystemAdaptor: SWBLLBuild.BuildSystemDelegate, Act
if isTriggerNode(rule), let mutatedNodeDescription = descriptionOfInputMutatedByBuildKey(inputRule) {
description = "\(descriptionForBuildKey(inputRule)) mutated \(mutatedNodeDescription)"
} else {
description = "\(inputNounPhraseForBuildKey(inputRule)) of \(descriptionForBuildKey(rule)) \(rebuiltVerbPhraseForBuildKey(inputRule))"
description = "\(inputNounPhraseForBuildKey(inputRule)) \(descriptionForBuildKey(rule)) \(rebuiltVerbPhraseForBuildKey(inputRule))"
}
previousFrameID = previousFrameIdentifier
} else {
Expand All @@ -2370,7 +2370,7 @@ internal final class OperationSystemAdaptor: SWBLLBuild.BuildSystemDelegate, Act
}
case .forced:
category = .ruleForced
description = "\(descriptionForBuildKey(rule)) was forced to run"
description = "\(descriptionForBuildKey(rule)) was forced to run to break a cycle in the build graph"
previousFrameID = nil
@unknown default:
category = .none
Expand Down
11 changes: 11 additions & 0 deletions Sources/SwiftBuild/SWBBuildOperationBacktraceFrame.swift
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,15 @@ public struct SWBTaskBacktrace {
}
self.frames = frames
}

public func renderTextualRepresentation() -> String {
var textualBacktrace: String = ""
for (frameNumber, frame) in frames.enumerated() {
guard frame.category.isUserFacing else {
continue
}
textualBacktrace += "#\(frameNumber): \(frame.description)\n"
}
return textualBacktrace
}
}
8 changes: 8 additions & 0 deletions Sources/SwiftBuildTestSupport/TaskBacktraces.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ extension BuildOperationTester.BuildResults {
}
}
}

package func checkTextualBacktrace(_ task: Task, _ expected: String, sourceLocation: SourceLocation = #_sourceLocation) {
if let frameID = getBacktraceID(task, sourceLocation: sourceLocation), let backtrace = reconstructBacktrace(for: frameID) {
#expect(backtrace.renderTextualRepresentation() == expected, sourceLocation: sourceLocation)
} else {
// already recorded an issue
}
}
}

extension BuildOperationTester {
Expand Down
123 changes: 113 additions & 10 deletions Tests/SWBBuildSystemTests/BuildBacktraceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,11 @@ fileprivate struct BuildBacktraceTests: CoreBasedTests {
results.checkTask(.matchTargetName("TargetBar"), .matchRuleType("Ld")) { task in
results.checkBacktrace(task, [
"<category='ruleInputRebuilt' description='an input of 'Link TargetBar (x86_64)' changed'>",
"<category='ruleInputRebuilt' description='the producer of file '\(SRCROOT.str)/build/EagerLinkingTBDs/Debug/TargetFoo.framework/Versions/A/TargetFoo.tbd' ran'>",
"<category='ruleInputRebuilt' description='the task producing file '\(SRCROOT.str)/build/EagerLinkingTBDs/Debug/TargetFoo.framework/Versions/A/TargetFoo.tbd' ran'>",
"<category='ruleInputRebuilt' description='an input of 'Generate TBD TargetFoo' changed'>",
"<category='ruleInputRebuilt' description='the producer of file '\(SRCROOT.str)/build/Debug/TargetFoo.framework/Versions/A/TargetFoo' ran'>",
"<category='ruleInputRebuilt' description='the task producing file '\(SRCROOT.str)/build/Debug/TargetFoo.framework/Versions/A/TargetFoo' ran'>",
"<category='ruleInputRebuilt' description='an input of 'Link TargetFoo (x86_64)' changed'>",
"<category='ruleInputRebuilt' description='the producer of file '\(SRCROOT.str)/build/aProject.build/Debug/TargetFoo.build/Objects-normal/x86_64/foo.o' ran'>",
"<category='ruleInputRebuilt' description='the task producing file '\(SRCROOT.str)/build/aProject.build/Debug/TargetFoo.build/Objects-normal/x86_64/foo.o' ran'>",
"<category='ruleInputRebuilt' description='an input of 'Compile foo.c (x86_64)' changed'>",
"<category='ruleHadInvalidValue' description='file '\(SRCROOT.str)/Sources/foo.c' changed'>"
])
Expand All @@ -139,8 +139,8 @@ fileprivate struct BuildBacktraceTests: CoreBasedTests {
results.checkTask(.matchTargetName("TargetFoo"), .matchRuleType("CompileC")) { task in
results.checkBacktrace(task, [
"<category='ruleInputRebuilt' description='an input of 'Compile foo.c (x86_64)' changed'>",
"<category='ruleInputRebuilt' description='the producer of file '\(SRCROOT.str)/build/aProject.build/Debug/TargetFoo.build/Objects-normal/x86_64/7187679823f38a2a940e0043cdf9d637-common-args.resp' ran'>",
"<category='ruleSignatureChanged' description='signature of 'Write 7187679823f38a2a940e0043cdf9d637-common-args.resp (x86_64)' changed'>"
"<category='ruleInputRebuilt' description='the task producing file '\(SRCROOT.str)/build/aProject.build/Debug/TargetFoo.build/Objects-normal/x86_64/7187679823f38a2a940e0043cdf9d637-common-args.resp' ran'>",
"<category='ruleSignatureChanged' description='arguments, environment, or working directory of 'Write 7187679823f38a2a940e0043cdf9d637-common-args.resp (x86_64)' changed'>"
])
}
if tester.fs.fileSystemMode == .checksumOnly {
Expand All @@ -155,10 +155,10 @@ fileprivate struct BuildBacktraceTests: CoreBasedTests {
results.checkTask(.matchTargetName("TargetBar"), .matchRuleType("Ld")) { task in
results.checkBacktrace(task, [
"<category='ruleInputRebuilt' description='an input of 'Link TargetBar (x86_64)' changed'>",
"<category='ruleInputRebuilt' description='the producer of file '\(SRCROOT.str)/build/aProject.build/Debug/TargetBar.build/Objects-normal/x86_64/bar.o' ran'>",
"<category='ruleInputRebuilt' description='the task producing file '\(SRCROOT.str)/build/aProject.build/Debug/TargetBar.build/Objects-normal/x86_64/bar.o' ran'>",
"<category='ruleInputRebuilt' description='an input of 'Compile bar.c (x86_64)' changed'>",
"<category='ruleInputRebuilt' description='the producer of file '\(SRCROOT.str)/build/aProject.build/Debug/TargetBar.build/Objects-normal/x86_64/7187679823f38a2a940e0043cdf9d637-common-args.resp' ran'>",
"<category='ruleSignatureChanged' description='signature of 'Write 7187679823f38a2a940e0043cdf9d637-common-args.resp (x86_64)' changed'>"
"<category='ruleInputRebuilt' description='the task producing file '\(SRCROOT.str)/build/aProject.build/Debug/TargetBar.build/Objects-normal/x86_64/7187679823f38a2a940e0043cdf9d637-common-args.resp' ran'>",
"<category='ruleSignatureChanged' description='arguments, environment, or working directory of 'Write 7187679823f38a2a940e0043cdf9d637-common-args.resp (x86_64)' changed'>"
])
}
}
Expand Down Expand Up @@ -320,7 +320,7 @@ fileprivate struct BuildBacktraceTests: CoreBasedTests {
results.checkNoDiagnostics()
results.checkTask(.matchTargetName("TargetFoo"), .matchRuleType("CompileC")) { task in
results.checkBacktrace(task, [
"<category='ruleHadInvalidValue' description=''Compile foo.c (x86_64)' did not have up-to-date outputs'>",
"<category='ruleHadInvalidValue' description='outputs of 'Compile foo.c (x86_64)' were missing or modified'>",
])
}
}
Expand Down Expand Up @@ -374,7 +374,7 @@ fileprivate struct BuildBacktraceTests: CoreBasedTests {
results.checkNoDiagnostics()
results.checkTask(.matchTargetName("TargetFoo"), .matchRuleType("PhaseScriptExecution")) { task in
results.checkBacktrace(task, [
"<category='ruleHadInvalidValue' description=''Run custom shell script 'Script'' is configured to run in every incremental build'>"
"<category='ruleHadInvalidValue' description=''Run custom shell script 'Script'' was configured to run in every incremental build'>"
])
}
}
Expand Down Expand Up @@ -471,4 +471,107 @@ fileprivate struct BuildBacktraceTests: CoreBasedTests {
}
}
}

@Test(.requireSDKs(.macOS))
func backtraceTextRendering() async throws {
try await withTemporaryDirectory { tmpDirPath async throws -> Void in
let testWorkspace = TestWorkspace(
"Test",
sourceRoot: tmpDirPath.join("Test"),
projects: [
TestProject(
"aProject",
groupTree: TestGroup(
"Sources",
path: "Sources",
children: [
TestFile("foo.c"),
TestFile("bar.c"),
]),
buildConfigurations: [
TestBuildConfiguration(
"Debug",
buildSettings: [
"PRODUCT_NAME": "$(TARGET_NAME)",
])
],
targets: [
TestStandardTarget(
"TargetFoo",
type: .framework,
buildPhases: [
TestSourcesBuildPhase([
"foo.c",
]),
]),
TestStandardTarget(
"TargetBar",
type: .framework,
buildPhases: [
TestSourcesBuildPhase([
"bar.c",
]),
TestFrameworksBuildPhase([
"TargetFoo.framework"
])
], dependencies: ["TargetFoo"]),
])
])

let tester = try await BuildOperationTester(getCore(), testWorkspace, simulated: false, fileSystem: localFS)
let parameters = BuildParameters(configuration: "Debug")
let buildRequest = BuildRequest(parameters: parameters, buildTargets: tester.workspace.projects[0].targets.map({ BuildRequest.BuildTargetInfo(parameters: parameters, target: $0) }), dependencyScope: .workspace, continueBuildingAfterErrors: true, useParallelTargets: true, useImplicitDependencies: false, useDryRun: false)
let SRCROOT = testWorkspace.sourceRoot.join("aProject")

// Create the source files.
try await tester.fs.writeFileContents(SRCROOT.join("Sources/foo.c")) { file in
file <<<
"""
int foo(void) {
return 1;
}
"""
}
try await tester.fs.writeFileContents(SRCROOT.join("Sources/bar.c")) { file in
file <<<
"""
int bar(void) {
return 2;
}
"""
}

try await tester.checkBuild(runDestination: .macOS, buildRequest: buildRequest, persistent: true) { results in
results.checkNoDiagnostics()
}

try await tester.checkNullBuild(runDestination: .macOS, buildRequest: buildRequest, persistent: true)

try await tester.fs.writeFileContents(SRCROOT.join("Sources/foo.c")) { file in
file <<<
"""
int foo2(void) {
return 42;
}
"""
}

try await tester.checkBuild(runDestination: .macOS, buildRequest: buildRequest, persistent: true) { results in
results.checkNoDiagnostics()
results.checkTask(.matchTargetName("TargetBar"), .matchRuleType("Ld")) { task in
results.checkTextualBacktrace(task, """
#0: an input of 'Link TargetBar (x86_64)' changed
#1: the task producing file '\(SRCROOT.str)/build/EagerLinkingTBDs/Debug/TargetFoo.framework/Versions/A/TargetFoo.tbd' ran
#2: an input of 'Generate TBD TargetFoo' changed
#3: the task producing file '\(SRCROOT.str)/build/Debug/TargetFoo.framework/Versions/A/TargetFoo' ran
#4: an input of 'Link TargetFoo (x86_64)' changed
#5: the task producing file '\(SRCROOT.str)/build/aProject.build/Debug/TargetFoo.build/Objects-normal/x86_64/foo.o' ran
#6: an input of 'Compile foo.c (x86_64)' changed
#7: file '\(SRCROOT.str)/Sources/foo.c' changed

""")
}
}
}
}
}
Loading