Skip to content

Commit 3e48888

Browse files
committed
Fallback on 'swift-frontend -scan-dependencies ...' fallback path in case libSwiftScan shared library cannot be loaded.
Resolves rdar://127768140
1 parent 5833856 commit 3e48888

File tree

2 files changed

+91
-18
lines changed

2 files changed

+91
-18
lines changed

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

+32-18
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,14 @@ import class Foundation.JSONDecoder
2323
import var Foundation.EXIT_SUCCESS
2424

2525
extension Diagnostic.Message {
26-
static func warn_scanner_frontend_fallback() -> Diagnostic.Message {
27-
.warning("Fallback to `swift-frontend` dependency scanner invocation")
26+
static func warn_scan_dylib_not_found() -> Diagnostic.Message {
27+
.warning("Unable to locate libSwiftScan. Fallback to `swift-frontend` dependency scanner invocation.")
28+
}
29+
static func warn_scan_dylib_load_failed(_ libPath: String) -> Diagnostic.Message {
30+
.warning("In-process dependency scan query failed due to incompatible libSwiftScan (\(libPath)). Fallback to `swift-frontend` dependency scanner invocation. Specify '-nonlib-dependency-scanner' to silence this warning.")
31+
}
32+
static func error_caching_enabled_libswiftscan_load_failure(_ libPath: String) -> Diagnostic.Message {
33+
.error("Swift Caching enabled - libSwiftScan load failed (\(libPath)).")
2834
}
2935
static func scanner_diagnostic_error(_ message: String) -> Diagnostic.Message {
3036
.error(message)
@@ -156,27 +162,35 @@ public extension Driver {
156162

157163
/// Returns false if the lib is available and ready to use
158164
private mutating func initSwiftScanLib() throws -> Bool {
159-
// If `-nonlib-dependency-scanner` was specified or the libSwiftScan library cannot be found,
165+
// `-nonlib-dependency-scanner` was specified
166+
guard !parsedOptions.hasArgument(.driverScanDependenciesNonLib) else {
167+
return true
168+
}
169+
170+
// If the libSwiftScan library cannot be found,
160171
// attempt to fallback to using `swift-frontend -scan-dependencies` invocations for dependency
161172
// scanning.
162-
guard !parsedOptions.hasArgument(.driverScanDependenciesNonLib),
163-
let scanLibPath = try toolchain.lookupSwiftScanLib(),
173+
guard let scanLibPath = try toolchain.lookupSwiftScanLib(),
164174
fileSystem.exists(scanLibPath) else {
165-
// This warning is mostly useful for debugging the driver, so let's hide it
166-
// when libSwiftDriver is used, instead of a swift-driver executable.
167-
if !integratedDriver {
168-
diagnosticEngine.emit(.warn_scanner_frontend_fallback())
169-
}
170-
175+
diagnosticEngine.emit(.warn_scan_dylib_not_found())
171176
return true
172177
}
173178

174-
try interModuleDependencyOracle.verifyOrCreateScannerInstance(fileSystem: fileSystem,
175-
swiftScanLibPath: scanLibPath)
176-
if isCachingEnabled {
177-
self.cas = try interModuleDependencyOracle.getOrCreateCAS(pluginPath: try getCASPluginPath(),
178-
onDiskPath: try getOnDiskCASPath(),
179-
pluginOptions: try getCASPluginOptions())
179+
do {
180+
try interModuleDependencyOracle.verifyOrCreateScannerInstance(fileSystem: fileSystem,
181+
swiftScanLibPath: scanLibPath)
182+
if isCachingEnabled {
183+
self.cas = try interModuleDependencyOracle.getOrCreateCAS(pluginPath: try getCASPluginPath(),
184+
onDiskPath: try getOnDiskCASPath(),
185+
pluginOptions: try getCASPluginOptions())
186+
}
187+
} catch {
188+
if isCachingEnabled {
189+
diagnosticEngine.emit(.error_caching_enabled_libswiftscan_load_failure(scanLibPath.description))
190+
} else {
191+
diagnosticEngine.emit(.warn_scan_dylib_load_failed(scanLibPath.description))
192+
}
193+
return true
180194
}
181195
return false
182196
}
@@ -259,7 +273,7 @@ public extension Driver {
259273
}
260274
}
261275

262-
mutating internal func performDependencyScan() throws -> InterModuleDependencyGraph {
276+
mutating func performDependencyScan() throws -> InterModuleDependencyGraph {
263277
let scannerJob = try dependencyScanningJob()
264278
let forceResponseFiles = parsedOptions.hasArgument(.driverForceResponseFiles)
265279
let dependencyGraph: InterModuleDependencyGraph

Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift

+59
Original file line numberDiff line numberDiff line change
@@ -1597,6 +1597,65 @@ final class ExplicitModuleBuildTests: XCTestCase {
15971597
}
15981598
}
15991599

1600+
// Ensure dependency scanning succeeds via fallback `swift-frontend -scan-dependenceis`
1601+
// mechanism if libSwiftScan.dylib fails to load.
1602+
func testDependencyScanningFallback() throws {
1603+
let (stdlibPath, shimsPath, _, _) = try getDriverArtifactsForScanning()
1604+
1605+
// Create a simple test case.
1606+
try withTemporaryDirectory { path in
1607+
let main = path.appending(component: "testDependencyScanningFallback.swift")
1608+
try localFileSystem.writeFileContents(main, bytes: "import C;")
1609+
1610+
let dummyBrokenDylib = path.appending(component: "lib_InternalSwiftScan.dylib")
1611+
try localFileSystem.writeFileContents(dummyBrokenDylib, bytes: "n/a")
1612+
1613+
var environment = ProcessEnv.vars
1614+
environment["SWIFT_DRIVER_SWIFTSCAN_LIB"] = dummyBrokenDylib.nativePathString(escaped: true)
1615+
1616+
let cHeadersPath: AbsolutePath =
1617+
try testInputsPath.appending(component: "ExplicitModuleBuilds")
1618+
.appending(component: "CHeaders")
1619+
let swiftModuleInterfacesPath: AbsolutePath =
1620+
try testInputsPath.appending(component: "ExplicitModuleBuilds")
1621+
.appending(component: "Swift")
1622+
let sdkArgumentsForTesting: [String] = (try? Driver.sdkArgumentsForTesting()) ?? []
1623+
let driverArgs: [String] = ["swiftc",
1624+
"-I", cHeadersPath.nativePathString(escaped: true),
1625+
"-I", swiftModuleInterfacesPath.nativePathString(escaped: true),
1626+
"-I", stdlibPath.nativePathString(escaped: true),
1627+
"-I", shimsPath.nativePathString(escaped: true),
1628+
"/tmp/Foo.o",
1629+
"-explicit-module-build",
1630+
"-working-directory", path.nativePathString(escaped: true),
1631+
"-disable-clang-target",
1632+
main.nativePathString(escaped: true)] + sdkArgumentsForTesting
1633+
do {
1634+
var driver = try Driver(args: driverArgs, env: environment)
1635+
let interModuleDependencyGraph = try driver.performDependencyScan()
1636+
XCTAssertTrue(driver.diagnosticEngine.diagnostics.contains { $0.behavior == .warning &&
1637+
$0.message.text == "In-process dependency scan query failed due to incompatible libSwiftScan (\(dummyBrokenDylib.nativePathString(escaped: true))). Fallback to `swift-frontend` dependency scanner invocation. Specify '-nonlib-dependency-scanner' to silence this warning."})
1638+
XCTAssertTrue(interModuleDependencyGraph.mainModule.directDependencies?.contains(where: { $0.moduleName == "C" }))
1639+
}
1640+
1641+
// Ensure no warning is emitted with '-nonlib-dependency-scanner'
1642+
do {
1643+
var driver = try Driver(args: driverArgs + ["-nonlib-dependency-scanner"], env: environment)
1644+
let _ = try driver.performDependencyScan()
1645+
XCTAssertFalse(driver.diagnosticEngine.diagnostics.contains { $0.behavior == .warning &&
1646+
$0.message.text == "In-process dependency scan query failed due to incompatible libSwiftScan (\(dummyBrokenDylib.nativePathString(escaped: true))). Fallback to `swift-frontend` dependency scanner invocation. Specify '-nonlib-dependency-scanner' to silence this warning."})
1647+
}
1648+
1649+
// Ensure error is emitted when caching is enabled
1650+
do {
1651+
var driver = try Driver(args: driverArgs + ["-cache-compile-job"], env: environment)
1652+
let _ = try driver.performDependencyScan()
1653+
XCTAssertFalse(driver.diagnosticEngine.diagnostics.contains { $0.behavior == .error &&
1654+
$0.message.text == "Swift Caching enabled - libSwiftScan load failed (\(dummyBrokenDylib.nativePathString(escaped: true))."})
1655+
}
1656+
}
1657+
}
1658+
16001659
func testParallelDependencyScanningDiagnostics() throws {
16011660
let (stdlibPath, shimsPath, toolchain, _) = try getDriverArtifactsForScanning()
16021661
// The dependency oracle wraps an instance of libSwiftScan and ensures thread safety across

0 commit comments

Comments
 (0)