From d5d64d1ea3a5a0a928d3383923ae0585565a966c Mon Sep 17 00:00:00 2001 From: Steven Wu Date: Mon, 22 Jan 2024 14:07:10 -0800 Subject: [PATCH] [SwiftScan] Add APIs to load/check libSwiftScan directly Add APIs for SwiftDriver library users to directly load/check the libSwiftScan directly before calling into its function. * Add APIs to query Driver for libSwiftScan location * Make `verifyOrCreateScannerInstance` to be public APIs to load or check the libSwiftScan. * Update `verifyOrCreateScannerInstance` to be more ergonomic to use. The function only returns true if the given path to libSwiftScan does not exist while most of the time caller actually errors out in those cases. Make throwing error the default behavior and caller can check for file existance before calling the function to perserve old behavior. --- Sources/SwiftDriver/Driver/Driver.swift | 4 ++ .../InterModuleDependencyOracle.swift | 10 +-- .../ModuleDependencyScanning.swift | 21 +++--- .../SwiftDriverTests/CachingBuildTests.swift | 50 +++++---------- .../ExplicitModuleBuildTests.swift | 64 +++++-------------- Tests/SwiftDriverTests/SwiftDriverTests.swift | 4 +- 6 files changed, 50 insertions(+), 103 deletions(-) diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index 91961e7b4..cd5a2dcc6 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -487,6 +487,10 @@ public struct Driver { return supportedFrontendFeatures.contains(feature.rawValue) } + public func getSwiftScanLibPath() throws -> AbsolutePath? { + return try toolchain.lookupSwiftScanLib() + } + @_spi(Testing) public static func findBlocklists(RelativeTo execDir: AbsolutePath) throws -> [AbsolutePath] { // Expect to find all blocklists in such dir: diff --git a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift index 4c21f1c4c..e70de949b 100644 --- a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift +++ b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift @@ -77,15 +77,10 @@ public class InterModuleDependencyOracle { } /// Given a specified toolchain path, locate and instantiate an instance of the SwiftScan library - /// Returns True if a library instance exists (either verified or newly-created). - @_spi(Testing) public func verifyOrCreateScannerInstance(fileSystem: FileSystem, - swiftScanLibPath: AbsolutePath) - throws -> Bool { + public func verifyOrCreateScannerInstance(fileSystem: FileSystem, + swiftScanLibPath: AbsolutePath) throws { return try queue.sync { if swiftScanLibInstance == nil { - guard fileSystem.exists(swiftScanLibPath) else { - return false - } swiftScanLibInstance = try SwiftScan(dylib: swiftScanLibPath) } else { guard swiftScanLibInstance!.path == swiftScanLibPath else { @@ -93,7 +88,6 @@ public class InterModuleDependencyOracle { .scanningLibraryInvocationMismatch(swiftScanLibInstance!.path, swiftScanLibPath) } } - return true } } diff --git a/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift b/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift index faa87c197..74be48b69 100644 --- a/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift +++ b/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift @@ -159,25 +159,26 @@ public extension Driver { // If `-nonlib-dependency-scanner` was specified or the libSwiftScan library cannot be found, // attempt to fallback to using `swift-frontend -scan-dependencies` invocations for dependency // scanning. - var fallbackToFrontend = parsedOptions.hasArgument(.driverScanDependenciesNonLib) - let optionalScanLibPath = try toolchain.lookupSwiftScanLib() - if let scanLibPath = optionalScanLibPath, - try interModuleDependencyOracle - .verifyOrCreateScannerInstance(fileSystem: fileSystem, - swiftScanLibPath: scanLibPath) == false { - fallbackToFrontend = true + guard !parsedOptions.hasArgument(.driverScanDependenciesNonLib), + let scanLibPath = try toolchain.lookupSwiftScanLib(), + fileSystem.exists(scanLibPath) else { // This warning is mostly useful for debugging the driver, so let's hide it - // when libSwiftDriver is used, instead of a swift-driver executable. + // when libSwiftDriver is used, instead of a swift-driver executable. if !integratedDriver { diagnosticEngine.emit(.warn_scanner_frontend_fallback()) } + + return true } - if !fallbackToFrontend && isCachingEnabled { + + try interModuleDependencyOracle.verifyOrCreateScannerInstance(fileSystem: fileSystem, + swiftScanLibPath: scanLibPath) + if isCachingEnabled { self.cas = try interModuleDependencyOracle.getOrCreateCAS(pluginPath: try getCASPluginPath(), onDiskPath: try getOnDiskCASPath(), pluginOptions: try getCASPluginOptions()) } - return fallbackToFrontend + return false } static func sanitizeCommandForLibScanInvocation(_ command: inout [String]) { diff --git a/Tests/SwiftDriverTests/CachingBuildTests.swift b/Tests/SwiftDriverTests/CachingBuildTests.swift index 8202fa9dc..fea29a1eb 100644 --- a/Tests/SwiftDriverTests/CachingBuildTests.swift +++ b/Tests/SwiftDriverTests/CachingBuildTests.swift @@ -499,13 +499,9 @@ final class CachingBuildTests: XCTestCase { try driver.run(jobs: jobs) XCTAssertFalse(driver.diagnosticEngine.hasErrors) - let scanLibPath = try XCTUnwrap(driver.toolchain.lookupSwiftScanLib()) - guard try dependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } + let scanLibPath = try XCTUnwrap(driver.getSwiftScanLibPath()) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) let cas = try dependencyOracle.getOrCreateCAS(pluginPath: nil, onDiskPath: casPath, pluginOptions: []) if let driverCAS = driver.cas { @@ -558,13 +554,9 @@ final class CachingBuildTests: XCTestCase { env: ProcessEnv.vars, interModuleDependencyOracle: dependencyOracle) - let scanLibPath = try XCTUnwrap(fooBuildDriver.toolchain.lookupSwiftScanLib()) - guard try dependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } + let scanLibPath = try XCTUnwrap(fooBuildDriver.getSwiftScanLibPath()) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) guard try dependencyOracle.supportsBinaryModuleHeaderDependencies() else { throw XCTSkip("libSwiftScan does not support binary module header dependencies.") } @@ -630,13 +622,9 @@ final class CachingBuildTests: XCTestCase { main.nativePathString(escaped: true)] + sdkArgumentsForTesting, env: ProcessEnv.vars, interModuleDependencyOracle: dependencyOracle) - let scanLibPath = try XCTUnwrap(driver.toolchain.lookupSwiftScanLib()) - guard try dependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } + let scanLibPath = try XCTUnwrap(driver.getSwiftScanLibPath()) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) let resolver = try ArgsResolver(fileSystem: localFileSystem) var scannerCommand = try driver.dependencyScannerInvocationCommand().1.map { try resolver.resolve($0) } // We generate full swiftc -frontend -scan-dependencies invocations in order to also be @@ -770,13 +758,9 @@ final class CachingBuildTests: XCTestCase { guard driver.isFrontendArgSupported(.scannerPrefixMap) else { throw XCTSkip("frontend doesn't support prefix map") } - let scanLibPath = try XCTUnwrap(driver.toolchain.lookupSwiftScanLib()) - guard try dependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } + let scanLibPath = try XCTUnwrap(driver.getSwiftScanLibPath()) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) let resolver = try ArgsResolver(fileSystem: localFileSystem) let scannerCommand = try driver.dependencyScannerInvocationCommand().1.map { try resolver.resolve($0) } @@ -841,13 +825,9 @@ final class CachingBuildTests: XCTestCase { try driver.run(jobs: jobs) XCTAssertFalse(driver.diagnosticEngine.hasErrors) - let scanLibPath = try XCTUnwrap(driver.toolchain.lookupSwiftScanLib()) - guard try dependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } + let scanLibPath = try XCTUnwrap(driver.getSwiftScanLibPath()) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) let cas = try dependencyOracle.getOrCreateCAS(pluginPath: nil, onDiskPath: casPath, pluginOptions: []) if let driverCAS = driver.cas { diff --git a/Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift b/Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift index 2d365d088..3be9ad003 100644 --- a/Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift +++ b/Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift @@ -903,12 +903,8 @@ final class ExplicitModuleBuildTests: XCTestCase { // queries. let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) - guard try dependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) try withTemporaryDirectory { path in let main = path.appending(component: "foo.swift") @@ -1083,12 +1079,8 @@ final class ExplicitModuleBuildTests: XCTestCase { // 2. Run a dependency scan to find the just-built module let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) - guard try dependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) guard try dependencyOracle.supportsBinaryFrameworkDependencies() else { throw XCTSkip("libSwiftScan does not support framework binary dependency reporting.") } @@ -1184,12 +1176,8 @@ final class ExplicitModuleBuildTests: XCTestCase { // queries. let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) - guard try dependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) // Create a simple test case. try withTemporaryDirectory { path in @@ -1293,12 +1281,8 @@ final class ExplicitModuleBuildTests: XCTestCase { // queries. let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) - guard try dependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) guard try dependencyOracle.supportsScannerDiagnostics() else { throw XCTSkip("libSwiftScan does not support diagnostics query.") } @@ -1361,12 +1345,8 @@ final class ExplicitModuleBuildTests: XCTestCase { // queries. let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) - guard try dependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) // Create a simple test case. try withTemporaryDirectory { path in @@ -1566,12 +1546,8 @@ final class ExplicitModuleBuildTests: XCTestCase { let (stdlibPath, shimsPath, toolchain, _) = try getDriverArtifactsForScanning() let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) - guard try dependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) // Create a simple test case. try withTemporaryDirectory { path in let main = path.appending(component: "testDependencyScanning.swift") @@ -1668,12 +1644,8 @@ final class ExplicitModuleBuildTests: XCTestCase { let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) // Run the first scan and serialize the cache contents. let firstDependencyOracle = InterModuleDependencyOracle() - guard try firstDependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } + try firstDependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) let firstScanGraph = try firstDependencyOracle.getDependencies(workingDirectory: path, @@ -1682,12 +1654,8 @@ final class ExplicitModuleBuildTests: XCTestCase { // Run the second scan, re-using the serialized cache contents. let secondDependencyOracle = InterModuleDependencyOracle() - guard try secondDependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } + try secondDependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) XCTAssertFalse(secondDependencyOracle.loadScannerCache(from: cacheSavePath)) let secondScanGraph = try secondDependencyOracle.getDependencies(workingDirectory: path, diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index 39cc6a157..9afef83c7 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -5130,7 +5130,7 @@ final class SwiftDriverTests: XCTestCase { swiftCompilerPrefixArgs: []) var printTargetInfoCommand = try Driver.itemizedJobCommand(of: printTargetInfoJob, useResponseFiles: .disabled, using: ArgsResolver(fileSystem: InMemoryFileSystem())) Driver.sanitizeCommandForLibScanInvocation(&printTargetInfoCommand) - let swiftScanLibPath = try XCTUnwrap(driver.toolchain.lookupSwiftScanLib()) + let swiftScanLibPath = try XCTUnwrap(driver.getSwiftScanLibPath()) if localFileSystem.exists(swiftScanLibPath) { let libSwiftScanInstance = try SwiftScan(dylib: swiftScanLibPath) if libSwiftScanInstance.canQueryTargetInfo() { @@ -5150,7 +5150,7 @@ final class SwiftDriverTests: XCTestCase { swiftCompilerPrefixArgs: []) var printTargetInfoCommand = try Driver.itemizedJobCommand(of: printTargetInfoJob, useResponseFiles: .disabled, using: ArgsResolver(fileSystem: InMemoryFileSystem())) Driver.sanitizeCommandForLibScanInvocation(&printTargetInfoCommand) - let swiftScanLibPath = try XCTUnwrap(driver.toolchain.lookupSwiftScanLib()) + let swiftScanLibPath = try XCTUnwrap(driver.getSwiftScanLibPath()) if localFileSystem.exists(swiftScanLibPath) { let libSwiftScanInstance = try SwiftScan(dylib: swiftScanLibPath) if libSwiftScanInstance.canQueryTargetInfo() {