Skip to content

Build plugin executables with debug symbols #5659

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 1 commit into from
Oct 20, 2022
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
26 changes: 25 additions & 1 deletion Sources/SPMTestSupport/Toolchain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Foundation
import PackageModel
import Workspace
import TSCBasic
import struct TSCUtility.SerializedDiagnostics

#if os(macOS)
private func macOSBundleRoot() throws -> AbsolutePath {
Expand Down Expand Up @@ -93,5 +94,28 @@ extension UserToolchain {
return true
#endif
}


/// Helper function to determine whether serialized diagnostics work properly in the current environment.
public func supportsSerializedDiagnostics(otherSwiftFlags: [String] = []) -> Bool {
do {
try testWithTemporaryDirectory { tmpPath in
let inputPath = tmpPath.appending(component: "best.swift")
try localFileSystem.writeFileContents(inputPath, string: "func foo() -> Bool {\nvar unused: Int\nreturn true\n}\n")
let outputPath = tmpPath.appending(component: "foo")
let serializedDiagnosticsPath = tmpPath.appending(component: "out.dia")
let toolchainPath = self.swiftCompilerPath.parentDirectory.parentDirectory
try Process.checkNonZeroExit(arguments: ["/usr/bin/xcrun", "--toolchain", toolchainPath.pathString, "swiftc", inputPath.pathString, "-Xfrontend", "-serialize-diagnostics-path", "-Xfrontend", serializedDiagnosticsPath.pathString, "-g", "-o", outputPath.pathString] + otherSwiftFlags)
try Process.checkNonZeroExit(arguments: [outputPath.pathString])

let diaFileContents = try localFileSystem.readFileContents(serializedDiagnosticsPath)
let diagnosticsSet = try SerializedDiagnostics(bytes: diaFileContents)
if diagnosticsSet.diagnostics.isEmpty {
throw StringError("does not support diagnostics")
}
}
return true
} catch {
return false
}
}
}
5 changes: 5 additions & 0 deletions Sources/Workspace/DefaultPluginScriptRunner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import PackageModel
import SPMBuildCore
import TSCBasic

import struct TSCUtility.SerializedDiagnostics
import struct TSCUtility.Triple

/// A plugin script runner that compiles the plugin source files as an executable binary for the host platform, and invokes it as a subprocess.
Expand Down Expand Up @@ -121,6 +122,8 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable {

// We use the toolchain's Swift compiler for compiling the plugin.
var commandLine = [self.toolchain.swiftCompilerPathForManifests.pathString]

observabilityScope.emit(debug: "Using compiler \(self.toolchain.swiftCompilerPathForManifests.pathString)")

// Get access to the path containing the PackagePlugin module and library.
let pluginLibraryPath = self.toolchain.swiftPMLibrariesLocation.pluginLibraryPath
Expand Down Expand Up @@ -166,6 +169,8 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable {
// Add any extra flags required as indicated by the ManifestLoader.
commandLine += self.toolchain.swiftCompilerFlags

commandLine.append("-g")

// Add the Swift language version implied by the package tools version.
commandLine += ["-swift-version", toolsVersion.swiftLanguageVersion.rawValue]

Expand Down
28 changes: 16 additions & 12 deletions Tests/SPMBuildCoreTests/PluginInvocationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -412,12 +412,14 @@ class PluginInvocationTests: XCTestCase {
XCTAssertEqual(delegate.compiledResult, result)
XCTAssertNil(delegate.cachedResult)

// Check the serialized diagnostics. We should no longer have an error but now have a warning.
let diaFileContents = try localFileSystem.readFileContents(result.diagnosticsFile)
let diagnosticsSet = try SerializedDiagnostics(bytes: diaFileContents)
XCTAssertEqual(diagnosticsSet.diagnostics.count, 1)
let warningDiagnostic = try XCTUnwrap(diagnosticsSet.diagnostics.first)
XCTAssertTrue(warningDiagnostic.text.hasPrefix("variable \'unused\' was never used"), "\(warningDiagnostic)")
if try UserToolchain.default.supportsSerializedDiagnostics() {
// Check the serialized diagnostics. We should no longer have an error but now have a warning.
let diaFileContents = try localFileSystem.readFileContents(result.diagnosticsFile)
let diagnosticsSet = try SerializedDiagnostics(bytes: diaFileContents)
XCTAssertEqual(diagnosticsSet.diagnostics.count, 1, "unexpected diagnostics count in \(diagnosticsSet.diagnostics) from \(result.diagnosticsFile.pathString)")
let warningDiagnostic = try XCTUnwrap(diagnosticsSet.diagnostics.first)
XCTAssertTrue(warningDiagnostic.text.hasPrefix("variable \'unused\' was never used"), "\(warningDiagnostic)")
}

// Check that the executable file exists.
XCTAssertTrue(localFileSystem.exists(result.executableFile), "\(result.executableFile.pathString)")
Expand Down Expand Up @@ -455,12 +457,14 @@ class PluginInvocationTests: XCTestCase {
XCTAssertNil(delegate.compiledResult)
XCTAssertEqual(delegate.cachedResult, result)

// Check that the diagnostics still have the same warning as before.
let diaFileContents = try localFileSystem.readFileContents(result.diagnosticsFile)
let diagnosticsSet = try SerializedDiagnostics(bytes: diaFileContents)
XCTAssertEqual(diagnosticsSet.diagnostics.count, 1)
let warningDiagnostic = try XCTUnwrap(diagnosticsSet.diagnostics.first)
XCTAssertTrue(warningDiagnostic.text.hasPrefix("variable \'unused\' was never used"), "\(warningDiagnostic)")
if try UserToolchain.default.supportsSerializedDiagnostics() {
// Check that the diagnostics still have the same warning as before.
let diaFileContents = try localFileSystem.readFileContents(result.diagnosticsFile)
let diagnosticsSet = try SerializedDiagnostics(bytes: diaFileContents)
XCTAssertEqual(diagnosticsSet.diagnostics.count, 1)
let warningDiagnostic = try XCTUnwrap(diagnosticsSet.diagnostics.first)
XCTAssertTrue(warningDiagnostic.text.hasPrefix("variable \'unused\' was never used"), "\(warningDiagnostic)")
}

// Check that the executable file exists.
XCTAssertTrue(localFileSystem.exists(result.executableFile), "\(result.executableFile.pathString)")
Expand Down