Skip to content

Commit 5848895

Browse files
committed
[Dependency Scanning] Fallback to calling the swift-frontend for dependency scanning queries if no instance of libSwiftScan is found.
1 parent c931c60 commit 5848895

File tree

2 files changed

+49
-15
lines changed

2 files changed

+49
-15
lines changed

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,14 @@ public class InterModuleDependencyOracle {
5353
}
5454

5555
/// Given a specified toolchain path, locate and instantiate an instance of the SwiftScan library
56+
/// Returns True if a library instance exists (either verified or newly-created).
5657
@_spi(Testing) public func verifyOrCreateScannerInstance(fileSystem: FileSystem,
57-
swiftScanLibPath: AbsolutePath) throws {
58-
try queue.sync {
58+
swiftScanLibPath: AbsolutePath)
59+
throws -> Bool {
60+
return try queue.sync {
5961
if swiftScanLibInstance == nil {
6062
guard fileSystem.exists(swiftScanLibPath) else {
61-
throw DependencyScanningError.scanningLibraryNotFound(swiftScanLibPath)
63+
return false
6264
}
6365
swiftScanLibInstance = try SwiftScan(dylib: swiftScanLibPath)
6466
} else {
@@ -67,6 +69,7 @@ public class InterModuleDependencyOracle {
6769
.scanningLibraryInvocationMismatch(swiftScanLibInstance!.path, swiftScanLibPath)
6870
}
6971
}
72+
return true
7073
}
7174
}
7275

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ import Foundation
1313
import TSCBasic
1414
import SwiftOptions
1515

16+
extension Diagnostic.Message {
17+
static func warn_scanner_frontend_fallback() -> Diagnostic.Message {
18+
.warning("Fallback to `swift-frontend` dependency scanner invocation")
19+
}
20+
}
21+
1622
internal extension Driver {
1723
/// Precompute the dependencies for a given Swift compilation, producing a
1824
/// dependency graph including all Swift and C module files and
@@ -39,7 +45,7 @@ internal extension Driver {
3945
// Aggregate the fast dependency scanner arguments
4046
var inputs: [TypedVirtualPath] = []
4147
var commandLine: [Job.ArgTemplate] = swiftCompilerPrefixArgs.map { Job.ArgTemplate.flag($0) }
42-
48+
commandLine.appendFlag("-frontend")
4349
commandLine.appendFlag("-scan-dependencies")
4450
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs,
4551
bridgingHeaderHandling: .precompiled,
@@ -93,24 +99,36 @@ internal extension Driver {
9399
let forceResponseFiles = parsedOptions.hasArgument(.driverForceResponseFiles)
94100
let dependencyGraph: InterModuleDependencyGraph
95101

96-
if (!parsedOptions.hasArgument(.driverScanDependenciesNonLib)) {
97-
try interModuleDependencyOracle
102+
// If `-nonlib-dependency-scanner` was specified or the libSwiftScan library cannot be found,
103+
// attempt to fallback to using `swift-frontend -scan-dependencies` invocations for dependency
104+
// scanning.
105+
var fallbackToFrontend = parsedOptions.hasArgument(.driverScanDependenciesNonLib)
106+
if try interModuleDependencyOracle
98107
.verifyOrCreateScannerInstance(fileSystem: fileSystem,
99-
swiftScanLibPath: try getScanLibPath(of: toolchain))
108+
swiftScanLibPath: try getScanLibPath(of: toolchain)) == false {
109+
fallbackToFrontend = true
110+
diagnosticEngine.emit(.warn_scanner_frontend_fallback())
111+
}
112+
113+
if (!fallbackToFrontend) {
100114
let cwd = workingDirectory ?? fileSystem.currentWorkingDirectory!
101115
var command = try itemizedJobCommand(of: scannerJob,
102116
forceResponseFiles: forceResponseFiles,
103117
using: executor.resolver)
104118
// Remove the tool executable to only leave the arguments
105119
command.removeFirst()
120+
// We generate full swiftc -frontend -scan-dependencies invocations in order to also be
121+
// able to launch them as standalone jobs. Frontend's argument parser won't recognize
122+
// -frontend when passed directly.
123+
if command.first == "-frontend" {
124+
command.removeFirst()
125+
}
106126
dependencyGraph =
107127
try interModuleDependencyOracle.getDependencies(workingDirectory: cwd,
108128
commandLine: command)
109129
} else {
110130
// Fallback to legacy invocation of the dependency scanner with
111131
// `swift-frontend -scan-dependencies`
112-
print("Dependency Scanner invocation:")
113-
print(try executor.description(of: scannerJob, forceResponseFiles: false))
114132
dependencyGraph =
115133
try self.executor.execute(job: scannerJob,
116134
capturingJSONOutputAs: InterModuleDependencyGraph.self,
@@ -125,26 +143,38 @@ internal extension Driver {
125143
let batchScanningJob = try batchDependencyScanningJob(for: moduleInfos)
126144
let forceResponseFiles = parsedOptions.hasArgument(.driverForceResponseFiles)
127145

128-
let moduleVersionedGraphMap: [ModuleDependencyId: [InterModuleDependencyGraph]]
129-
if (!parsedOptions.hasArgument(.driverScanDependenciesNonLib)) {
130-
try interModuleDependencyOracle
146+
// If `-nonlib-dependency-scanner` was specified or the libSwiftScan library cannot be found,
147+
// attempt to fallback to using `swift-frontend -scan-dependencies` invocations for dependency
148+
// scanning.
149+
var fallbackToFrontend = parsedOptions.hasArgument(.driverScanDependenciesNonLib)
150+
if try interModuleDependencyOracle
131151
.verifyOrCreateScannerInstance(fileSystem: fileSystem,
132-
swiftScanLibPath: try getScanLibPath(of: toolchain))
152+
swiftScanLibPath: try getScanLibPath(of: toolchain)) == false {
153+
fallbackToFrontend = true
154+
diagnosticEngine.emit(.warn_scanner_frontend_fallback())
155+
}
156+
157+
let moduleVersionedGraphMap: [ModuleDependencyId: [InterModuleDependencyGraph]]
158+
if (!fallbackToFrontend) {
133159
let cwd = workingDirectory ?? fileSystem.currentWorkingDirectory!
134160
var command = try itemizedJobCommand(of: batchScanningJob,
135161
forceResponseFiles: forceResponseFiles,
136162
using: executor.resolver)
137163
// Remove the tool executable to only leave the arguments
138164
command.removeFirst()
165+
// We generate full swiftc -frontend -scan-dependencies invocations in order to also be
166+
// able to launch them as standalone jobs. Frontend's argument parser won't recognize
167+
// -frontend when passed directly.
168+
if command.first == "-frontend" {
169+
command.removeFirst()
170+
}
139171
moduleVersionedGraphMap =
140172
try interModuleDependencyOracle.getBatchDependencies(workingDirectory: cwd,
141173
commandLine: command,
142174
batchInfos: moduleInfos)
143175
} else {
144176
// Fallback to legacy invocation of the dependency scanner with
145177
// `swift-frontend -scan-dependencies`
146-
print("Dependency Scanner (batch) invocation:")
147-
print(try executor.description(of: batchScanningJob, forceResponseFiles: false))
148178
moduleVersionedGraphMap = try executeLegacyBatchScan(moduleInfos: moduleInfos,
149179
batchScanningJob: batchScanningJob,
150180
forceResponseFiles: forceResponseFiles)
@@ -203,6 +233,7 @@ internal extension Driver {
203233

204234
// The dependency scanner automatically operates in batch mode if -batch-scan-input-file
205235
// is present.
236+
commandLine.appendFlag("-frontend")
206237
commandLine.appendFlag("-scan-dependencies")
207238
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs,
208239
bridgingHeaderHandling: .precompiled,

0 commit comments

Comments
 (0)