Skip to content

Improve Swift Build error formatting #8493

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 15, 2025
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
41 changes: 21 additions & 20 deletions IntegrationTests/Tests/IntegrationTests/SwiftPMTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,29 +110,30 @@ private struct SwiftPMTests {
.requireThreadSafeWorkingDirectory,
.bug(id: 0, "SWBINTTODO: Linux: /lib/x86_64-linux-gnu/Scrt1.o:function _start: error:"),
.bug("https://github.com/swiftlang/swift-package-manager/issues/8380", "lld-link: error: subsystem must be defined"),
.bug(id:0, "SWBINTTODO: MacOS: Could not find or use auto-linked library 'Testing': library 'Testing' not found"),
.bug(id: 0, "SWBINTTODO: MacOS: Could not find or use auto-linked library 'Testing': library 'Testing' not found"),
arguments: BuildSystemProvider.allCases
)
func packageInitLibrary(_ buildSystemProvider: BuildSystemProvider) throws {
do {
try withTemporaryDirectory { tmpDir in
let packagePath = tmpDir.appending(component: "foo")
try localFileSystem.createDirectory(packagePath)
try sh(swiftPackage, "--package-path", packagePath, "init", "--type", "library")
try withKnownIssue("""
Linux: /lib/x86_64-linux-gnu/Scrt1.o:function _start: error: undefined reference to 'main'
Windows: lld-link: error: subsystem must be defined
MacOS: Could not find or use auto-linked library 'Testing': library 'Testing' not found
""") {
try sh(swiftBuild, "--package-path", packagePath, "--build-system", buildSystemProvider.rawValue, "--vv")
let (stdout, stderr) = try sh(
swiftTest, "--package-path", packagePath, "--build-system", buildSystemProvider.rawValue, "--vv"
)
#expect(!stderr.contains("error:"))
#expect(stdout.contains("Test Suite 'All tests' passed"))
} when: {
buildSystemProvider == .swiftbuild
}
try withTemporaryDirectory { tmpDir in
let packagePath = tmpDir.appending(component: "foo")
try localFileSystem.createDirectory(packagePath)
try sh(swiftPackage, "--package-path", packagePath, "init", "--type", "library")
try withKnownIssue(
"""
Linux: /lib/x86_64-linux-gnu/Scrt1.o:function _start: error: undefined reference to 'main'
Windows: lld-link: error: subsystem must be defined
MacOS: Could not find or use auto-linked library 'Testing': library 'Testing' not found
""",
isIntermittent: true
) {
try sh(swiftBuild, "--package-path", packagePath, "--build-system", buildSystemProvider.rawValue, "--vv")
let (stdout, stderr) = try sh(
swiftTest, "--package-path", packagePath, "--build-system", buildSystemProvider.rawValue, "--vv"
)
#expect(!stderr.contains("error:"))
#expect(stdout.contains("Test Suite 'All tests' passed"))
} when: {
buildSystemProvider == .swiftbuild
}
}
}
Expand Down
57 changes: 49 additions & 8 deletions Sources/SwiftBuildSupport/SwiftBuildSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -353,15 +353,23 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem {
}
progressAnimation.update(step: step, total: 100, text: message)
case .diagnostic(let info):
if info.kind == .error {
self.observabilityScope.emit(error: "\(info.location) \(info.message) \(info.fixIts)")
} else if info.kind == .warning {
self.observabilityScope.emit(warning: "\(info.location) \(info.message) \(info.fixIts)")
} else if info.kind == .note {
self.observabilityScope.emit(info: "\(info.location) \(info.message) \(info.fixIts)")
} else if info.kind == .remark {
self.observabilityScope.emit(debug: "\(info.location) \(info.message) \(info.fixIts)")
let fixItsDescription = if info.fixIts.hasContent {
": " + info.fixIts.map { String(describing: $0) }.joined(separator: ", ")
} else {
""
}
let message = if let locationDescription = info.location.userDescription {
"\(locationDescription) \(info.message)\(fixItsDescription)"
} else {
"\(info.message)\(fixItsDescription)"
}
let severity: Diagnostic.Severity = switch info.kind {
case .error: .error
case .warning: .warning
case .note: .info
case .remark: .debug
}
self.observabilityScope.emit(severity: severity, message: message)
case .taskOutput(let info):
self.observabilityScope.emit(info: "\(info.data)")
case .taskStarted(let info):
Expand Down Expand Up @@ -509,6 +517,8 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem {
}
}

// MARK: - Helpers

extension String {
/// Escape the usual shell related things, such as quoting, but also handle Windows
/// back-slashes.
Expand Down Expand Up @@ -541,3 +551,34 @@ extension Basics.Diagnostic.Severity {
self <= .info
}
}

#if canImport(SwiftBuild)

fileprivate extension SwiftBuild.SwiftBuildMessage.DiagnosticInfo.Location {
var userDescription: String? {
switch self {
case .path(let path, let fileLocation):
switch fileLocation {
case .textual(let line, let column):
var description = "\(path):\(line)"
if let column { description += ":\(column)" }
return description
case .object(let identifier):
return "\(path):\(identifier)"
case .none:
return path
}

case .buildSettings(let names):
return names.joined(separator: ", ")

case .buildFiles(let buildFiles, let targetGUID):
return "\(targetGUID): " + buildFiles.map { String(describing: $0) }.joined(separator: ", ")

case .unknown:
return nil
}
}
}

#endif
6 changes: 3 additions & 3 deletions Sources/_InternalTestSupport/Observability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,14 @@ public struct TestingObservability {
self.collector.hasWarnings
}

final class Collector: ObservabilityHandlerProvider, DiagnosticsHandler, CustomStringConvertible {
fileprivate final class Collector: ObservabilityHandlerProvider, DiagnosticsHandler, CustomStringConvertible {
var diagnosticsHandler: DiagnosticsHandler { self }

let diagnostics: ThreadSafeArrayStore<Basics.Diagnostic>
private let verbose: Bool
let diagnostics = ThreadSafeArrayStore<Basics.Diagnostic>()

init(verbose: Bool) {
self.verbose = verbose
self.diagnostics = .init()
}

// TODO: do something useful with scope
Expand Down Expand Up @@ -98,6 +97,7 @@ public func XCTAssertNoDiagnostics(
) {
let diagnostics = problemsOnly ? diagnostics.filter { $0.severity >= .warning } : diagnostics
if diagnostics.isEmpty { return }

let description = diagnostics.map { "- " + $0.description }.joined(separator: "\n")
XCTFail("Found unexpected diagnostics: \n\(description)", file: file, line: line)
}
Expand Down
2 changes: 1 addition & 1 deletion Tests/XCBuildSupportTests/PIFBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2952,7 +2952,7 @@ final class PIFBuilderTests: XCTestCase {
"/Foo/Sources/qux/main.swift"
)

let observability = ObservabilitySystem.makeForTesting()
let observability = ObservabilitySystem.makeForTesting(verbose: false) // Don't print expected [error]s.
let graph = try loadModulesGraph(
fileSystem: fs,
manifests: [
Expand Down