Skip to content

Commit 7e6a0b8

Browse files
authored
Merge pull request swiftlang#548 from swiftlang/owenv/backtrace-descriptions
Improve printed descriptions of task backtraces
2 parents 4f0c40a + 60b27cb commit 7e6a0b8

File tree

4 files changed

+139
-17
lines changed

4 files changed

+139
-17
lines changed

Sources/SWBBuildSystem/BuildOperation.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2304,9 +2304,9 @@ internal final class OperationSystemAdaptor: SWBLLBuild.BuildSystemDelegate, Act
23042304
private func inputNounPhraseForBuildKey(_ inputKey: BuildKey) -> String {
23052305
switch inputKey {
23062306
case is BuildKey.Command, is BuildKey.CustomTask:
2307-
return "the producer"
2307+
return "the task producing"
23082308
case is BuildKey.DirectoryContents, is BuildKey.FilteredDirectoryContents, is BuildKey.DirectoryTreeSignature, is BuildKey.Node:
2309-
return "an input"
2309+
return "an input of"
23102310
case is BuildKey.Target, is BuildKey.Stat:
23112311
return "<unexpected build key>"
23122312
default:
@@ -2343,15 +2343,15 @@ internal final class OperationSystemAdaptor: SWBLLBuild.BuildSystemDelegate, Act
23432343
previousFrameID = nil
23442344
case .signatureChanged:
23452345
category = .ruleSignatureChanged
2346-
description = "signature of \(descriptionForBuildKey(rule)) changed"
2346+
description = "arguments, environment, or working directory of \(descriptionForBuildKey(rule)) changed"
23472347
previousFrameID = nil
23482348
case .invalidValue:
23492349
category = .ruleHadInvalidValue
23502350
previousFrameID = nil
23512351
if let command = rule as? BuildKey.Command, let task = lookupTask(TaskIdentifier(rawValue: command.name)), task.alwaysExecuteTask {
2352-
description = "\(descriptionForBuildKey(rule)) is configured to run in every incremental build"
2352+
description = "\(descriptionForBuildKey(rule)) was configured to run in every incremental build"
23532353
} else if rule is BuildKey.Command || rule is BuildKey.CustomTask {
2354-
description = "\(descriptionForBuildKey(rule)) did not have up-to-date outputs"
2354+
description = "outputs of \(descriptionForBuildKey(rule)) were missing or modified"
23552355
} else {
23562356
description = "\(descriptionForBuildKey(rule)) changed"
23572357
}
@@ -2361,7 +2361,7 @@ internal final class OperationSystemAdaptor: SWBLLBuild.BuildSystemDelegate, Act
23612361
if isTriggerNode(rule), let mutatedNodeDescription = descriptionOfInputMutatedByBuildKey(inputRule) {
23622362
description = "\(descriptionForBuildKey(inputRule)) mutated \(mutatedNodeDescription)"
23632363
} else {
2364-
description = "\(inputNounPhraseForBuildKey(inputRule)) of \(descriptionForBuildKey(rule)) \(rebuiltVerbPhraseForBuildKey(inputRule))"
2364+
description = "\(inputNounPhraseForBuildKey(inputRule)) \(descriptionForBuildKey(rule)) \(rebuiltVerbPhraseForBuildKey(inputRule))"
23652365
}
23662366
previousFrameID = previousFrameIdentifier
23672367
} else {
@@ -2370,7 +2370,7 @@ internal final class OperationSystemAdaptor: SWBLLBuild.BuildSystemDelegate, Act
23702370
}
23712371
case .forced:
23722372
category = .ruleForced
2373-
description = "\(descriptionForBuildKey(rule)) was forced to run"
2373+
description = "\(descriptionForBuildKey(rule)) was forced to run to break a cycle in the build graph"
23742374
previousFrameID = nil
23752375
@unknown default:
23762376
category = .none

Sources/SwiftBuild/SWBBuildOperationBacktraceFrame.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,15 @@ public struct SWBTaskBacktrace {
193193
}
194194
self.frames = frames
195195
}
196+
197+
public func renderTextualRepresentation() -> String {
198+
var textualBacktrace: String = ""
199+
for (frameNumber, frame) in frames.enumerated() {
200+
guard frame.category.isUserFacing else {
201+
continue
202+
}
203+
textualBacktrace += "#\(frameNumber): \(frame.description)\n"
204+
}
205+
return textualBacktrace
206+
}
196207
}

Sources/SwiftBuildTestSupport/TaskBacktraces.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,14 @@ extension BuildOperationTester.BuildResults {
8080
}
8181
}
8282
}
83+
84+
package func checkTextualBacktrace(_ task: Task, _ expected: String, sourceLocation: SourceLocation = #_sourceLocation) {
85+
if let frameID = getBacktraceID(task, sourceLocation: sourceLocation), let backtrace = reconstructBacktrace(for: frameID) {
86+
#expect(backtrace.renderTextualRepresentation() == expected, sourceLocation: sourceLocation)
87+
} else {
88+
// already recorded an issue
89+
}
90+
}
8391
}
8492

8593
extension BuildOperationTester {

Tests/SWBBuildSystemTests/BuildBacktraceTests.swift

Lines changed: 113 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,11 @@ fileprivate struct BuildBacktraceTests: CoreBasedTests {
121121
results.checkTask(.matchTargetName("TargetBar"), .matchRuleType("Ld")) { task in
122122
results.checkBacktrace(task, [
123123
"<category='ruleInputRebuilt' description='an input of 'Link TargetBar (x86_64)' changed'>",
124-
"<category='ruleInputRebuilt' description='the producer of file '\(SRCROOT.str)/build/EagerLinkingTBDs/Debug/TargetFoo.framework/Versions/A/TargetFoo.tbd' ran'>",
124+
"<category='ruleInputRebuilt' description='the task producing file '\(SRCROOT.str)/build/EagerLinkingTBDs/Debug/TargetFoo.framework/Versions/A/TargetFoo.tbd' ran'>",
125125
"<category='ruleInputRebuilt' description='an input of 'Generate TBD TargetFoo' changed'>",
126-
"<category='ruleInputRebuilt' description='the producer of file '\(SRCROOT.str)/build/Debug/TargetFoo.framework/Versions/A/TargetFoo' ran'>",
126+
"<category='ruleInputRebuilt' description='the task producing file '\(SRCROOT.str)/build/Debug/TargetFoo.framework/Versions/A/TargetFoo' ran'>",
127127
"<category='ruleInputRebuilt' description='an input of 'Link TargetFoo (x86_64)' changed'>",
128-
"<category='ruleInputRebuilt' description='the producer of file '\(SRCROOT.str)/build/aProject.build/Debug/TargetFoo.build/Objects-normal/x86_64/foo.o' ran'>",
128+
"<category='ruleInputRebuilt' description='the task producing file '\(SRCROOT.str)/build/aProject.build/Debug/TargetFoo.build/Objects-normal/x86_64/foo.o' ran'>",
129129
"<category='ruleInputRebuilt' description='an input of 'Compile foo.c (x86_64)' changed'>",
130130
"<category='ruleHadInvalidValue' description='file '\(SRCROOT.str)/Sources/foo.c' changed'>"
131131
])
@@ -139,8 +139,8 @@ fileprivate struct BuildBacktraceTests: CoreBasedTests {
139139
results.checkTask(.matchTargetName("TargetFoo"), .matchRuleType("CompileC")) { task in
140140
results.checkBacktrace(task, [
141141
"<category='ruleInputRebuilt' description='an input of 'Compile foo.c (x86_64)' changed'>",
142-
"<category='ruleInputRebuilt' description='the producer of file '\(SRCROOT.str)/build/aProject.build/Debug/TargetFoo.build/Objects-normal/x86_64/7187679823f38a2a940e0043cdf9d637-common-args.resp' ran'>",
143-
"<category='ruleSignatureChanged' description='signature of 'Write 7187679823f38a2a940e0043cdf9d637-common-args.resp (x86_64)' changed'>"
142+
"<category='ruleInputRebuilt' description='the task producing file '\(SRCROOT.str)/build/aProject.build/Debug/TargetFoo.build/Objects-normal/x86_64/7187679823f38a2a940e0043cdf9d637-common-args.resp' ran'>",
143+
"<category='ruleSignatureChanged' description='arguments, environment, or working directory of 'Write 7187679823f38a2a940e0043cdf9d637-common-args.resp (x86_64)' changed'>"
144144
])
145145
}
146146
if tester.fs.fileSystemMode == .checksumOnly {
@@ -155,10 +155,10 @@ fileprivate struct BuildBacktraceTests: CoreBasedTests {
155155
results.checkTask(.matchTargetName("TargetBar"), .matchRuleType("Ld")) { task in
156156
results.checkBacktrace(task, [
157157
"<category='ruleInputRebuilt' description='an input of 'Link TargetBar (x86_64)' changed'>",
158-
"<category='ruleInputRebuilt' description='the producer of file '\(SRCROOT.str)/build/aProject.build/Debug/TargetBar.build/Objects-normal/x86_64/bar.o' ran'>",
158+
"<category='ruleInputRebuilt' description='the task producing file '\(SRCROOT.str)/build/aProject.build/Debug/TargetBar.build/Objects-normal/x86_64/bar.o' ran'>",
159159
"<category='ruleInputRebuilt' description='an input of 'Compile bar.c (x86_64)' changed'>",
160-
"<category='ruleInputRebuilt' description='the producer of file '\(SRCROOT.str)/build/aProject.build/Debug/TargetBar.build/Objects-normal/x86_64/7187679823f38a2a940e0043cdf9d637-common-args.resp' ran'>",
161-
"<category='ruleSignatureChanged' description='signature of 'Write 7187679823f38a2a940e0043cdf9d637-common-args.resp (x86_64)' changed'>"
160+
"<category='ruleInputRebuilt' description='the task producing file '\(SRCROOT.str)/build/aProject.build/Debug/TargetBar.build/Objects-normal/x86_64/7187679823f38a2a940e0043cdf9d637-common-args.resp' ran'>",
161+
"<category='ruleSignatureChanged' description='arguments, environment, or working directory of 'Write 7187679823f38a2a940e0043cdf9d637-common-args.resp (x86_64)' changed'>"
162162
])
163163
}
164164
}
@@ -320,7 +320,7 @@ fileprivate struct BuildBacktraceTests: CoreBasedTests {
320320
results.checkNoDiagnostics()
321321
results.checkTask(.matchTargetName("TargetFoo"), .matchRuleType("CompileC")) { task in
322322
results.checkBacktrace(task, [
323-
"<category='ruleHadInvalidValue' description=''Compile foo.c (x86_64)' did not have up-to-date outputs'>",
323+
"<category='ruleHadInvalidValue' description='outputs of 'Compile foo.c (x86_64)' were missing or modified'>",
324324
])
325325
}
326326
}
@@ -374,7 +374,7 @@ fileprivate struct BuildBacktraceTests: CoreBasedTests {
374374
results.checkNoDiagnostics()
375375
results.checkTask(.matchTargetName("TargetFoo"), .matchRuleType("PhaseScriptExecution")) { task in
376376
results.checkBacktrace(task, [
377-
"<category='ruleHadInvalidValue' description=''Run custom shell script 'Script'' is configured to run in every incremental build'>"
377+
"<category='ruleHadInvalidValue' description=''Run custom shell script 'Script'' was configured to run in every incremental build'>"
378378
])
379379
}
380380
}
@@ -471,4 +471,107 @@ fileprivate struct BuildBacktraceTests: CoreBasedTests {
471471
}
472472
}
473473
}
474+
475+
@Test(.requireSDKs(.macOS))
476+
func backtraceTextRendering() async throws {
477+
try await withTemporaryDirectory { tmpDirPath async throws -> Void in
478+
let testWorkspace = TestWorkspace(
479+
"Test",
480+
sourceRoot: tmpDirPath.join("Test"),
481+
projects: [
482+
TestProject(
483+
"aProject",
484+
groupTree: TestGroup(
485+
"Sources",
486+
path: "Sources",
487+
children: [
488+
TestFile("foo.c"),
489+
TestFile("bar.c"),
490+
]),
491+
buildConfigurations: [
492+
TestBuildConfiguration(
493+
"Debug",
494+
buildSettings: [
495+
"PRODUCT_NAME": "$(TARGET_NAME)",
496+
])
497+
],
498+
targets: [
499+
TestStandardTarget(
500+
"TargetFoo",
501+
type: .framework,
502+
buildPhases: [
503+
TestSourcesBuildPhase([
504+
"foo.c",
505+
]),
506+
]),
507+
TestStandardTarget(
508+
"TargetBar",
509+
type: .framework,
510+
buildPhases: [
511+
TestSourcesBuildPhase([
512+
"bar.c",
513+
]),
514+
TestFrameworksBuildPhase([
515+
"TargetFoo.framework"
516+
])
517+
], dependencies: ["TargetFoo"]),
518+
])
519+
])
520+
521+
let tester = try await BuildOperationTester(getCore(), testWorkspace, simulated: false, fileSystem: localFS)
522+
let parameters = BuildParameters(configuration: "Debug")
523+
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)
524+
let SRCROOT = testWorkspace.sourceRoot.join("aProject")
525+
526+
// Create the source files.
527+
try await tester.fs.writeFileContents(SRCROOT.join("Sources/foo.c")) { file in
528+
file <<<
529+
"""
530+
int foo(void) {
531+
return 1;
532+
}
533+
"""
534+
}
535+
try await tester.fs.writeFileContents(SRCROOT.join("Sources/bar.c")) { file in
536+
file <<<
537+
"""
538+
int bar(void) {
539+
return 2;
540+
}
541+
"""
542+
}
543+
544+
try await tester.checkBuild(runDestination: .macOS, buildRequest: buildRequest, persistent: true) { results in
545+
results.checkNoDiagnostics()
546+
}
547+
548+
try await tester.checkNullBuild(runDestination: .macOS, buildRequest: buildRequest, persistent: true)
549+
550+
try await tester.fs.writeFileContents(SRCROOT.join("Sources/foo.c")) { file in
551+
file <<<
552+
"""
553+
int foo2(void) {
554+
return 42;
555+
}
556+
"""
557+
}
558+
559+
try await tester.checkBuild(runDestination: .macOS, buildRequest: buildRequest, persistent: true) { results in
560+
results.checkNoDiagnostics()
561+
results.checkTask(.matchTargetName("TargetBar"), .matchRuleType("Ld")) { task in
562+
results.checkTextualBacktrace(task, """
563+
#0: an input of 'Link TargetBar (x86_64)' changed
564+
#1: the task producing file '\(SRCROOT.str)/build/EagerLinkingTBDs/Debug/TargetFoo.framework/Versions/A/TargetFoo.tbd' ran
565+
#2: an input of 'Generate TBD TargetFoo' changed
566+
#3: the task producing file '\(SRCROOT.str)/build/Debug/TargetFoo.framework/Versions/A/TargetFoo' ran
567+
#4: an input of 'Link TargetFoo (x86_64)' changed
568+
#5: the task producing file '\(SRCROOT.str)/build/aProject.build/Debug/TargetFoo.build/Objects-normal/x86_64/foo.o' ran
569+
#6: an input of 'Compile foo.c (x86_64)' changed
570+
#7: file '\(SRCROOT.str)/Sources/foo.c' changed
571+
572+
""")
573+
}
574+
}
575+
}
576+
}
474577
}

0 commit comments

Comments
 (0)