Skip to content

Commit dec1ded

Browse files
authored
Improve Swift Build error formatting (#8493)
### Motivation: This improves a bit the error/warning output when building with the new `--build-system swiftbuild`. This was the current output: ```shell warning: unknown Enabling the Swift language feature 'MemberImportVisibility' is recommended; set 'SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES' [] error: path("/Users/pmattos/Development/SampleProjects/SamplePackages/PackageAccessCLI/Sources/ExampleApp/main.swift", fileLocation: Optional(SwiftBuild.SwiftBuildMessage.DiagnosticInfo.Location.FileLocation.textual(line: 6, column: Optional(5)))) cannot find 'bar' in scope [] ``` ...and this is the improved one: ```shell warning: Enabling the Swift language feature 'MemberImportVisibility' is recommended; set 'SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES' error: /Users/pmattos/Development/SampleProjects/SamplePackages/PackageAccessCLI/Sources/ExampleApp/main.swift:5:5 cannot find 'foo2' in scope ``` Eventually, we should consider adopting the error output style from the `--build-system native` instead, i.e.: ```shell /Users/pmattos/Development/SampleProjects/SamplePackages/PackageAccessCLI/Sources/ExampleApp/main.swift:5:5: error: cannot find 'foo2' in scope 3 | print("Hello, world!") 4 | 5 | _ = foo2() | `- error: cannot find 'foo2' in scope 6 | _ = bar() 7 | ``` ### Modifications: These formatting changes are strictly local to the new `SwiftBuildSupport` target. ### Result: Slightly better error formatting :-)
1 parent b69b792 commit dec1ded

File tree

4 files changed

+74
-32
lines changed

4 files changed

+74
-32
lines changed

IntegrationTests/Tests/IntegrationTests/SwiftPMTests.swift

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -110,29 +110,30 @@ private struct SwiftPMTests {
110110
.requireThreadSafeWorkingDirectory,
111111
.bug(id: 0, "SWBINTTODO: Linux: /lib/x86_64-linux-gnu/Scrt1.o:function _start: error:"),
112112
.bug("https://github.com/swiftlang/swift-package-manager/issues/8380", "lld-link: error: subsystem must be defined"),
113-
.bug(id:0, "SWBINTTODO: MacOS: Could not find or use auto-linked library 'Testing': library 'Testing' not found"),
113+
.bug(id: 0, "SWBINTTODO: MacOS: Could not find or use auto-linked library 'Testing': library 'Testing' not found"),
114114
arguments: BuildSystemProvider.allCases
115115
)
116116
func packageInitLibrary(_ buildSystemProvider: BuildSystemProvider) throws {
117-
do {
118-
try withTemporaryDirectory { tmpDir in
119-
let packagePath = tmpDir.appending(component: "foo")
120-
try localFileSystem.createDirectory(packagePath)
121-
try sh(swiftPackage, "--package-path", packagePath, "init", "--type", "library")
122-
try withKnownIssue("""
123-
Linux: /lib/x86_64-linux-gnu/Scrt1.o:function _start: error: undefined reference to 'main'
124-
Windows: lld-link: error: subsystem must be defined
125-
MacOS: Could not find or use auto-linked library 'Testing': library 'Testing' not found
126-
""") {
127-
try sh(swiftBuild, "--package-path", packagePath, "--build-system", buildSystemProvider.rawValue, "--vv")
128-
let (stdout, stderr) = try sh(
129-
swiftTest, "--package-path", packagePath, "--build-system", buildSystemProvider.rawValue, "--vv"
130-
)
131-
#expect(!stderr.contains("error:"))
132-
#expect(stdout.contains("Test Suite 'All tests' passed"))
133-
} when: {
134-
buildSystemProvider == .swiftbuild
135-
}
117+
try withTemporaryDirectory { tmpDir in
118+
let packagePath = tmpDir.appending(component: "foo")
119+
try localFileSystem.createDirectory(packagePath)
120+
try sh(swiftPackage, "--package-path", packagePath, "init", "--type", "library")
121+
try withKnownIssue(
122+
"""
123+
Linux: /lib/x86_64-linux-gnu/Scrt1.o:function _start: error: undefined reference to 'main'
124+
Windows: lld-link: error: subsystem must be defined
125+
MacOS: Could not find or use auto-linked library 'Testing': library 'Testing' not found
126+
""",
127+
isIntermittent: true
128+
) {
129+
try sh(swiftBuild, "--package-path", packagePath, "--build-system", buildSystemProvider.rawValue, "--vv")
130+
let (stdout, stderr) = try sh(
131+
swiftTest, "--package-path", packagePath, "--build-system", buildSystemProvider.rawValue, "--vv"
132+
)
133+
#expect(!stderr.contains("error:"))
134+
#expect(stdout.contains("Test Suite 'All tests' passed"))
135+
} when: {
136+
buildSystemProvider == .swiftbuild
136137
}
137138
}
138139
}

Sources/SwiftBuildSupport/SwiftBuildSystem.swift

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -353,15 +353,23 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem {
353353
}
354354
progressAnimation.update(step: step, total: 100, text: message)
355355
case .diagnostic(let info):
356-
if info.kind == .error {
357-
self.observabilityScope.emit(error: "\(info.location) \(info.message) \(info.fixIts)")
358-
} else if info.kind == .warning {
359-
self.observabilityScope.emit(warning: "\(info.location) \(info.message) \(info.fixIts)")
360-
} else if info.kind == .note {
361-
self.observabilityScope.emit(info: "\(info.location) \(info.message) \(info.fixIts)")
362-
} else if info.kind == .remark {
363-
self.observabilityScope.emit(debug: "\(info.location) \(info.message) \(info.fixIts)")
356+
let fixItsDescription = if info.fixIts.hasContent {
357+
": " + info.fixIts.map { String(describing: $0) }.joined(separator: ", ")
358+
} else {
359+
""
360+
}
361+
let message = if let locationDescription = info.location.userDescription {
362+
"\(locationDescription) \(info.message)\(fixItsDescription)"
363+
} else {
364+
"\(info.message)\(fixItsDescription)"
365+
}
366+
let severity: Diagnostic.Severity = switch info.kind {
367+
case .error: .error
368+
case .warning: .warning
369+
case .note: .info
370+
case .remark: .debug
364371
}
372+
self.observabilityScope.emit(severity: severity, message: message)
365373
case .taskOutput(let info):
366374
self.observabilityScope.emit(info: "\(info.data)")
367375
case .taskStarted(let info):
@@ -509,6 +517,8 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem {
509517
}
510518
}
511519

520+
// MARK: - Helpers
521+
512522
extension String {
513523
/// Escape the usual shell related things, such as quoting, but also handle Windows
514524
/// back-slashes.
@@ -541,3 +551,34 @@ extension Basics.Diagnostic.Severity {
541551
self <= .info
542552
}
543553
}
554+
555+
#if canImport(SwiftBuild)
556+
557+
fileprivate extension SwiftBuild.SwiftBuildMessage.DiagnosticInfo.Location {
558+
var userDescription: String? {
559+
switch self {
560+
case .path(let path, let fileLocation):
561+
switch fileLocation {
562+
case .textual(let line, let column):
563+
var description = "\(path):\(line)"
564+
if let column { description += ":\(column)" }
565+
return description
566+
case .object(let identifier):
567+
return "\(path):\(identifier)"
568+
case .none:
569+
return path
570+
}
571+
572+
case .buildSettings(let names):
573+
return names.joined(separator: ", ")
574+
575+
case .buildFiles(let buildFiles, let targetGUID):
576+
return "\(targetGUID): " + buildFiles.map { String(describing: $0) }.joined(separator: ", ")
577+
578+
case .unknown:
579+
return nil
580+
}
581+
}
582+
}
583+
584+
#endif

Sources/_InternalTestSupport/Observability.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,14 @@ public struct TestingObservability {
5656
self.collector.hasWarnings
5757
}
5858

59-
final class Collector: ObservabilityHandlerProvider, DiagnosticsHandler, CustomStringConvertible {
59+
fileprivate final class Collector: ObservabilityHandlerProvider, DiagnosticsHandler, CustomStringConvertible {
6060
var diagnosticsHandler: DiagnosticsHandler { self }
6161

62-
let diagnostics: ThreadSafeArrayStore<Basics.Diagnostic>
6362
private let verbose: Bool
63+
let diagnostics = ThreadSafeArrayStore<Basics.Diagnostic>()
6464

6565
init(verbose: Bool) {
6666
self.verbose = verbose
67-
self.diagnostics = .init()
6867
}
6968

7069
// TODO: do something useful with scope
@@ -98,6 +97,7 @@ public func XCTAssertNoDiagnostics(
9897
) {
9998
let diagnostics = problemsOnly ? diagnostics.filter { $0.severity >= .warning } : diagnostics
10099
if diagnostics.isEmpty { return }
100+
101101
let description = diagnostics.map { "- " + $0.description }.joined(separator: "\n")
102102
XCTFail("Found unexpected diagnostics: \n\(description)", file: file, line: line)
103103
}

Tests/XCBuildSupportTests/PIFBuilderTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2952,7 +2952,7 @@ final class PIFBuilderTests: XCTestCase {
29522952
"/Foo/Sources/qux/main.swift"
29532953
)
29542954

2955-
let observability = ObservabilitySystem.makeForTesting()
2955+
let observability = ObservabilitySystem.makeForTesting(verbose: false) // Don't print expected [error]s.
29562956
let graph = try loadModulesGraph(
29572957
fileSystem: fs,
29582958
manifests: [

0 commit comments

Comments
 (0)