Skip to content

Commit 100549b

Browse files
authored
Merge branch 'main' into revert-1077-revert-991-disfavor-cwd
2 parents 827f87d + 7c14673 commit 100549b

24 files changed

+818
-105
lines changed

Sources/CSwiftScan/include/swiftscan_header.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ typedef struct swiftscan_module_details_s *swiftscan_module_details_t;
4343
typedef struct swiftscan_dependency_info_s *swiftscan_dependency_info_t;
4444
typedef struct swiftscan_dependency_graph_s *swiftscan_dependency_graph_t;
4545
typedef struct swiftscan_import_set_s *swiftscan_import_set_t;
46+
typedef struct swiftscan_diagnostic_info_s *swiftscan_diagnostic_info_t;
47+
48+
typedef enum {
49+
SWIFTSCAN_DIAGNOSTIC_SEVERITY_ERROR = 0,
50+
SWIFTSCAN_DIAGNOSTIC_SEVERITY_WARNING = 1,
51+
SWIFTSCAN_DIAGNOSTIC_SEVERITY_NOTE = 2,
52+
SWIFTSCAN_DIAGNOSTIC_SEVERITY_REMARK = 3
53+
} swiftscan_diagnostic_severity_t;
54+
typedef struct {
55+
swiftscan_diagnostic_info_t *diagnostics;
56+
size_t count;
57+
} swiftscan_diagnostic_set_t;
4658
typedef struct {
4759
swiftscan_dependency_info_t *modules;
4860
size_t count;
@@ -210,6 +222,18 @@ typedef struct {
210222
swiftscan_scan_invocation_t);
211223
swiftscan_import_set_t
212224
(*swiftscan_import_set_create)(swiftscan_scanner_t, swiftscan_scan_invocation_t);
225+
226+
//=== Scanner Diagnostics -------------------------------------------------===//
227+
swiftscan_diagnostic_set_t*
228+
(*swiftscan_scanner_diagnostics_query)(swiftscan_scanner_t);
229+
void
230+
(*swiftscan_scanner_diagnostics_reset)(swiftscan_scanner_t);
231+
swiftscan_string_ref_t
232+
(*swiftscan_diagnostic_get_message)(swiftscan_diagnostic_info_t);
233+
swiftscan_diagnostic_severity_t
234+
(*swiftscan_diagnostic_get_severity)(swiftscan_diagnostic_info_t);
235+
void
236+
(*swiftscan_diagnostics_set_dispose)(swiftscan_diagnostic_set_t*);
213237

214238
//=== Scanner Cache Functions ---------------------------------------------===//
215239
void (*swiftscan_scanner_cache_serialize)(swiftscan_scanner_t scanner, const char * path);

Sources/SwiftDriver/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ add_library(SwiftDriver
9797
Toolchains/WebAssemblyToolchain.swift
9898
Toolchains/WindowsToolchain.swift
9999

100+
ToolingInterface/SimpleExecutor.swift
101+
ToolingInterface/ToolingUtil.swift
102+
100103
Utilities/DOTJobGraphSerializer.swift
101104
Utilities/DOTModuleDependencyGraphSerializer.swift
102105
Utilities/DateAdditions.swift

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ public struct Driver {
562562
swiftCompilerPrefixArgs: self.swiftCompilerPrefixArgs)
563563

564564
// Classify and collect all of the input files.
565-
let inputFiles = try Self.collectInputFiles(&self.parsedOptions, diagnosticsEngine: diagnosticsEngine)
565+
let inputFiles = try Self.collectInputFiles(&self.parsedOptions, diagnosticsEngine: diagnosticsEngine, fileSystem: self.fileSystem)
566566
self.inputFiles = inputFiles
567567
self.recordedInputModificationDates = .init(uniqueKeysWithValues:
568568
Set(inputFiles).compactMap {
@@ -634,6 +634,7 @@ public struct Driver {
634634
fileSystem: fileSystem,
635635
workingDirectory: workingDirectory,
636636
diagnosticEngine: diagnosticEngine)
637+
Self.validateEmitDependencyGraphArgs(&parsedOptions, diagnosticEngine: diagnosticEngine)
637638
Self.validateParseableOutputArgs(&parsedOptions, diagnosticEngine: diagnosticEngine)
638639
Self.validateCompilationConditionArgs(&parsedOptions, diagnosticEngine: diagnosticEngine)
639640
Self.validateFrameworkSearchPathArgs(&parsedOptions, diagnosticEngine: diagnosticEngine)
@@ -1247,7 +1248,7 @@ extension Driver {
12471248
}
12481249

12491250
/// Expand response files in the input arguments and return a new argument list.
1250-
@_spi(Testing) public static func expandResponseFiles(
1251+
public static func expandResponseFiles(
12511252
_ args: [String],
12521253
fileSystem: FileSystem,
12531254
diagnosticsEngine: DiagnosticsEngine
@@ -1790,10 +1791,11 @@ extension Driver {
17901791
/// Collect all of the input files from the parsed options, translating them into input files.
17911792
private static func collectInputFiles(
17921793
_ parsedOptions: inout ParsedOptions,
1793-
diagnosticsEngine: DiagnosticsEngine
1794+
diagnosticsEngine: DiagnosticsEngine,
1795+
fileSystem: FileSystem
17941796
) throws -> [TypedVirtualPath] {
17951797
var swiftFiles = [String: String]() // [Basename: Path]
1796-
return try parsedOptions.allInputs.map { input in
1798+
var paths: [TypedVirtualPath] = try parsedOptions.allInputs.map { input in
17971799
// Standard input is assumed to be Swift code.
17981800
if input == "-" {
17991801
return TypedVirtualPath(file: .standardInput, type: .swift)
@@ -1823,6 +1825,29 @@ extension Driver {
18231825

18241826
return TypedVirtualPath(file: inputHandle, type: fileType)
18251827
}
1828+
1829+
if parsedOptions.hasArgument(.e) {
1830+
if let mainPath = swiftFiles["main.swift"] {
1831+
diagnosticsEngine.emit(.error_two_files_same_name(basename: "main.swift", firstPath: mainPath, secondPath: "-e"))
1832+
diagnosticsEngine.emit(.note_explain_two_files_same_name)
1833+
throw Diagnostics.fatalError
1834+
}
1835+
1836+
try withTemporaryDirectory(dir: fileSystem.tempDirectory, removeTreeOnDeinit: false) { absPath in
1837+
let filePath = VirtualPath.absolute(absPath.appending(component: "main.swift"))
1838+
1839+
try fileSystem.writeFileContents(filePath) { file in
1840+
file <<< ###"#sourceLocation(file: "-e", line: 1)\###n"###
1841+
for option in parsedOptions.arguments(for: .e) {
1842+
file <<< option.argument.asSingle <<< "\n"
1843+
}
1844+
}
1845+
1846+
paths.append(TypedVirtualPath(file: filePath.intern(), type: .swift))
1847+
}
1848+
}
1849+
1850+
return paths
18261851
}
18271852

18281853
/// Determine the primary compiler and linker output kinds.
@@ -2646,6 +2671,28 @@ extension Driver {
26462671
}
26472672
}
26482673

2674+
static func validateEmitDependencyGraphArgs(_ parsedOptions: inout ParsedOptions,
2675+
diagnosticEngine: DiagnosticsEngine) {
2676+
// '-print-explicit-dependency-graph' requires '-explicit-module-build'
2677+
if parsedOptions.hasArgument(.printExplicitDependencyGraph) &&
2678+
!parsedOptions.hasArgument(.driverExplicitModuleBuild) {
2679+
diagnosticEngine.emit(Error.optionRequiresAnother(Option.printExplicitDependencyGraph.spelling,
2680+
Option.driverExplicitModuleBuild.spelling))
2681+
}
2682+
// '-explicit-dependency-graph-format=' requires '-print-explicit-dependency-graph'
2683+
if parsedOptions.hasArgument(.explicitDependencyGraphFormat) &&
2684+
!parsedOptions.hasArgument(.printExplicitDependencyGraph) {
2685+
diagnosticEngine.emit(Error.optionRequiresAnother(Option.explicitDependencyGraphFormat.spelling,
2686+
Option.printExplicitDependencyGraph.spelling))
2687+
}
2688+
// '-explicit-dependency-graph-format=' only supports values 'json' and 'dot'
2689+
if let formatArg = parsedOptions.getLastArgument(.explicitDependencyGraphFormat)?.asSingle {
2690+
if formatArg != "json" && formatArg != "dot" {
2691+
diagnosticEngine.emit(.error_unsupported_argument(argument: formatArg,
2692+
option: .explicitDependencyGraphFormat))
2693+
}
2694+
}
2695+
}
26492696

26502697
static func validateProfilingArgs(_ parsedOptions: inout ParsedOptions,
26512698
fileSystem: FileSystem,

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,25 @@ public class InterModuleDependencyOracle {
118118
swiftScan.resetScannerCache()
119119
}
120120
}
121+
122+
@_spi(Testing) public func supportsScannerDiagnostics() throws -> Bool {
123+
guard let swiftScan = swiftScanLibInstance else {
124+
fatalError("Attempting to reset scanner cache with no scanner instance.")
125+
}
126+
return swiftScan.supportsScannerDiagnostics()
127+
}
128+
129+
@_spi(Testing) public func getScannerDiagnostics() throws -> [ScannerDiagnosticPayload]? {
130+
guard let swiftScan = swiftScanLibInstance else {
131+
fatalError("Attempting to reset scanner cache with no scanner instance.")
132+
}
133+
guard swiftScan.supportsScannerDiagnostics() else {
134+
return nil
135+
}
136+
let diags = try swiftScan.queryScannerDiagnostics()
137+
try swiftScan.resetScannerDiagnostics()
138+
return diags.isEmpty ? nil : diags
139+
}
121140

122141
private var hasScannerInstance: Bool { self.swiftScanLibInstance != nil }
123142

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ extension Diagnostic.Message {
2727
static func warn_scanner_frontend_fallback() -> Diagnostic.Message {
2828
.warning("Fallback to `swift-frontend` dependency scanner invocation")
2929
}
30+
static func scanner_diagnostic_error(_ message: String) -> Diagnostic.Message {
31+
.error("Dependency scanning failure: \(message)")
32+
}
33+
static func scanner_diagnostic_warn(_ message: String) -> Diagnostic.Message {
34+
.warning(message)
35+
}
36+
static func scanner_diagnostic_note(_ message: String) -> Diagnostic.Message {
37+
.note(message)
38+
}
39+
static func scanner_diagnostic_remark(_ message: String) -> Diagnostic.Message {
40+
.remark(message)
41+
}
3042
}
3143

3244
public extension Driver {
@@ -177,6 +189,23 @@ public extension Driver {
177189
try interModuleDependencyOracle.getDependencies(workingDirectory: cwd,
178190
moduleAliases: moduleOutputInfo.aliases,
179191
commandLine: command)
192+
let possibleDiags = try interModuleDependencyOracle.getScannerDiagnostics()
193+
if let diags = possibleDiags {
194+
for diagnostic in diags {
195+
switch diagnostic.severity {
196+
case .error:
197+
diagnosticEngine.emit(.scanner_diagnostic_error(diagnostic.message))
198+
case .warning:
199+
diagnosticEngine.emit(.scanner_diagnostic_warn(diagnostic.message))
200+
case .note:
201+
diagnosticEngine.emit(.scanner_diagnostic_note(diagnostic.message))
202+
case .remark:
203+
diagnosticEngine.emit(.scanner_diagnostic_remark(diagnostic.message))
204+
case .ignored:
205+
diagnosticEngine.emit(.scanner_diagnostic_error(diagnostic.message))
206+
}
207+
}
208+
}
180209
} else {
181210
// Fallback to legacy invocation of the dependency scanner with
182211
// `swift-frontend -scan-dependencies`

Sources/SwiftDriver/Jobs/Planning.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,12 @@ extension Driver {
660660
try resolveDependencyModulePaths(dependencyGraph: &dependencyGraph)
661661

662662
if parsedOptions.hasArgument(.printExplicitDependencyGraph) {
663-
try stdoutStream <<< dependencyGraph.toJSONString()
663+
let outputFormat = parsedOptions.getLastArgument(.explicitDependencyGraphFormat)?.asSingle
664+
if outputFormat == nil || outputFormat == "json" {
665+
try stdoutStream <<< dependencyGraph.toJSONString()
666+
} else if outputFormat == "dot" {
667+
DOTModuleDependencyGraphSerializer(dependencyGraph).writeDOT(to: &stdoutStream)
668+
}
664669
stdoutStream.flush()
665670
}
666671

Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ extension WindowsToolchain {
4444
let librarian: String
4545
switch parsedOptions.getLastArgument(.useLd)?.asSingle {
4646
case .none:
47-
librarian = lto == nil ? "link.exe" : "lld-link.exe"
47+
librarian = lto == nil ? "link" : "lld-link"
4848
case .some("lld"), .some("lld.exe"), .some("lld-link"), .some("lld-link.exe"):
49-
librarian = "lld-link.exe"
49+
librarian = "lld-link"
5050
case let .some(linker):
5151
librarian = linker
5252
}

Sources/SwiftDriver/SwiftScan/SwiftScan.swift

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import func Foundation.free
1818
import protocol TSCBasic.DiagnosticData
1919
import struct TSCBasic.AbsolutePath
2020
import struct TSCUtility.Version
21+
import struct TSCBasic.Diagnostic
2122

2223
public enum DependencyScanningError: Error, DiagnosticData {
2324
case missingRequiredSymbol(String)
@@ -57,6 +58,28 @@ public enum DependencyScanningError: Error, DiagnosticData {
5758
}
5859
}
5960

61+
@_spi(Testing) public struct ScannerDiagnosticPayload {
62+
@_spi(Testing) public let severity: Diagnostic.Behavior
63+
@_spi(Testing) public let message: String
64+
}
65+
66+
internal extension swiftscan_diagnostic_severity_t {
67+
func toDiagnosticBehavior() -> Diagnostic.Behavior {
68+
switch self {
69+
case SWIFTSCAN_DIAGNOSTIC_SEVERITY_ERROR:
70+
return Diagnostic.Behavior.error
71+
case SWIFTSCAN_DIAGNOSTIC_SEVERITY_WARNING:
72+
return Diagnostic.Behavior.warning
73+
case SWIFTSCAN_DIAGNOSTIC_SEVERITY_NOTE:
74+
return Diagnostic.Behavior.note
75+
case SWIFTSCAN_DIAGNOSTIC_SEVERITY_REMARK:
76+
return Diagnostic.Behavior.remark
77+
default:
78+
return Diagnostic.Behavior.error
79+
}
80+
}
81+
}
82+
6083
/// Wrapper for libSwiftScan, taking care of initialization, shutdown, and dispatching dependency scanning queries.
6184
internal final class SwiftScan {
6285
/// The path to the libSwiftScan dylib.
@@ -235,6 +258,41 @@ internal final class SwiftScan {
235258
func resetScannerCache() {
236259
api.swiftscan_scanner_cache_reset(scanner)
237260
}
261+
262+
@_spi(Testing) public func supportsScannerDiagnostics() -> Bool {
263+
return api.swiftscan_scanner_diagnostics_query != nil &&
264+
api.swiftscan_scanner_diagnostics_reset != nil &&
265+
api.swiftscan_diagnostic_get_message != nil &&
266+
api.swiftscan_diagnostic_get_severity != nil &&
267+
api.swiftscan_diagnostics_set_dispose != nil
268+
}
269+
270+
@_spi(Testing) public func queryScannerDiagnostics() throws -> [ScannerDiagnosticPayload] {
271+
var result: [ScannerDiagnosticPayload] = []
272+
let diagnosticSetRefOrNull = api.swiftscan_scanner_diagnostics_query(scanner)
273+
guard let diagnosticSetRef = diagnosticSetRefOrNull else {
274+
// Seems heavy-handed to fail here
275+
// throw DependencyScanningError.dependencyScanFailed
276+
return []
277+
}
278+
defer { api.swiftscan_diagnostics_set_dispose(diagnosticSetRef) }
279+
let diagnosticRefArray = Array(UnsafeBufferPointer(start: diagnosticSetRef.pointee.diagnostics,
280+
count: Int(diagnosticSetRef.pointee.count)))
281+
282+
for diagnosticRefOrNull in diagnosticRefArray {
283+
guard let diagnosticRef = diagnosticRefOrNull else {
284+
throw DependencyScanningError.dependencyScanFailed
285+
}
286+
let message = try toSwiftString(api.swiftscan_diagnostic_get_message(diagnosticRef))
287+
let severity = api.swiftscan_diagnostic_get_severity(diagnosticRef)
288+
result.append(ScannerDiagnosticPayload(severity: severity.toDiagnosticBehavior(), message: message))
289+
}
290+
return result
291+
}
292+
293+
@_spi(Testing) public func resetScannerDiagnostics() throws {
294+
api.swiftscan_scanner_diagnostics_reset(scanner)
295+
}
238296

239297
@_spi(Testing) public func canQuerySupportedArguments() -> Bool {
240298
return api.swiftscan_compiler_supported_arguments_query != nil &&
@@ -300,6 +358,18 @@ private extension swiftscan_functions_t {
300358
// Clang dependency captured PCM args
301359
self.swiftscan_clang_detail_get_captured_pcm_args =
302360
try loadOptional("swiftscan_clang_detail_get_captured_pcm_args")
361+
362+
// Scanner diagnostic emission query
363+
self.swiftscan_scanner_diagnostics_query =
364+
try loadOptional("swiftscan_scanner_diagnostics_query")
365+
self.swiftscan_scanner_diagnostics_reset =
366+
try loadOptional("swiftscan_scanner_diagnostics_reset")
367+
self.swiftscan_diagnostic_get_message =
368+
try loadOptional("swiftscan_diagnostic_get_message")
369+
self.swiftscan_diagnostic_get_severity =
370+
try loadOptional("swiftscan_diagnostic_get_severity")
371+
self.swiftscan_diagnostics_set_dispose =
372+
try loadOptional("swiftscan_diagnostics_set_dispose")
303373

304374
// MARK: Required Methods
305375
func loadRequired<T>(_ symbol: String) throws -> T {

Sources/SwiftDriver/Toolchains/Toolchain.swift

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,7 @@ extension Toolchain {
191191

192192
/// - Returns: String in the form of: `SWIFT_DRIVER_TOOLNAME_EXEC`
193193
private func envVarName(for toolName: String) -> String {
194-
var lookupName = toolName
195-
#if os(Windows)
196-
lookupName = lookupName.replacingOccurrences(of: ".exe", with: "")
197-
#endif
198-
lookupName = lookupName.replacingOccurrences(of: "-", with: "_").uppercased()
194+
let lookupName = toolName.replacingOccurrences(of: "-", with: "_").uppercased()
199195
return "SWIFT_DRIVER_\(lookupName)_EXEC"
200196
}
201197

@@ -209,9 +205,9 @@ extension Toolchain {
209205

210206
/// Looks for the executable in the `SWIFT_DRIVER_TOOLNAME_EXEC` environment variable, if found nothing,
211207
/// looks in the `executableDir`, `xcrunFind` or in the `searchPaths`.
212-
/// - Parameter executable: executable to look for [i.e. `swift`].
208+
/// - Parameter executable: executable to look for [i.e. `swift`]. Executable suffix (eg. `.exe`) should be omitted.
213209
func lookup(executable: String) throws -> AbsolutePath {
214-
if let overrideString = envVar(forExecutable: executableName(executable)),
210+
if let overrideString = envVar(forExecutable: executable),
215211
let path = try? AbsolutePath(validating: overrideString) {
216212
return path
217213
} else if let toolDir = toolDirectory,
@@ -222,7 +218,7 @@ extension Toolchain {
222218
return path
223219
} else if let path = try? xcrunFind(executable: executableName(executable)) {
224220
return path
225-
} else if !["swift-frontend", "swift", "swift-frontend.exe", "swift.exe"].contains(executable),
221+
} else if !["swift-frontend", "swift"].contains(executable),
226222
let parentDirectory = try? getToolPath(.swiftCompiler).parentDirectory,
227223
parentDirectory != executableDir,
228224
let path = lookupExecutablePath(filename: executableName(executable), searchPaths: [parentDirectory]) {
@@ -231,14 +227,14 @@ extension Toolchain {
231227
return path
232228
} else if let path = lookupExecutablePath(filename: executableName(executable), searchPaths: searchPaths) {
233229
return path
234-
} else if executable == executableName("swift-frontend") {
230+
} else if executable == "swift-frontend" {
235231
// Temporary shim: fall back to looking for "swift" before failing.
236-
return try lookup(executable: executableName("swift"))
232+
return try lookup(executable: "swift")
237233
} else if fallbackToExecutableDefaultPath {
238234
if self is WindowsToolchain {
239235
return try getToolPath(.swiftCompiler)
240236
.parentDirectory
241-
.appending(component: executable)
237+
.appending(component: executableName(executable))
242238
} else {
243239
return AbsolutePath("/usr/bin/" + executable)
244240
}

0 commit comments

Comments
 (0)