From f5dd6726aee3568566211ac112cb0579d94895bf Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Mon, 23 Sep 2024 08:36:11 -0700 Subject: [PATCH] =?UTF-8?q?Revert=20"Allow=20for=20non-external=20lookup?= =?UTF-8?q?=20of=20libSwiftScan=20symbols=20and=20centralize=20=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit d616136c091a9d57c2cd959a39f022b34d0ba5de. --- Sources/SwiftDriver/Driver/Driver.swift | 209 ++++-------------- .../Execution/DriverExecutor.swift | 2 +- .../InterModuleDependencyOracle.swift | 29 +-- .../ModuleDependencyScanning.swift | 48 +++- .../Jobs/EmitSupportedFeaturesJob.swift | 27 ++- .../SwiftDriver/Jobs/FrontendJobHelpers.swift | 6 +- .../SwiftDriver/Jobs/PrintTargetInfoJob.swift | 91 ++++---- Sources/SwiftDriver/SwiftScan/Loader.swift | 13 -- Sources/SwiftDriver/SwiftScan/SwiftScan.swift | 184 ++++++++------- .../ToolingInterface/ToolingUtil.swift | 21 +- .../SwiftDriverTests/CachingBuildTests.swift | 24 +- .../ExplicitModuleBuildTests.swift | 30 ++- Tests/SwiftDriverTests/SwiftDriverTests.swift | 32 +-- Tests/TestUtilities/DriverExtensions.swift | 21 ++ Tests/ToolingTestShim/CToolingTestShimImpl.c | 8 +- 15 files changed, 333 insertions(+), 412 deletions(-) diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index 44553388c..55f3ce3c5 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -158,10 +158,6 @@ public struct Driver { /// Whether we are using the driver as the integrated driver via libSwiftDriver public let integratedDriver: Bool - /// If true, the driver instance is executed in the context of a - /// Swift compiler image which contains symbols normally queried from a libSwiftScan instance. - internal let compilerIntegratedTooling: Bool - /// The file system which we should interact with. @_spi(Testing) public let fileSystem: FileSystem @@ -413,10 +409,6 @@ public struct Driver { /// as explicit inputs by the various compilation jobs. @_spi(Testing) public var explicitDependencyBuildPlanner: ExplicitDependencyBuildPlanner? = nil - /// A reference to the instance of libSwiftScan which is shared with the driver's - /// `InterModuleDependencyOracle`, but also used for non-scanning tasks, such as target info - /// and supported compiler feature queries - @_spi(Testing) public var swiftScanLibInstance: SwiftScan? = nil /// An oracle for querying inter-module dependencies /// Can either be an argument to the driver in many-module contexts where dependency information /// is shared across many targets; otherwise, a new instance is created by the driver itself. @@ -580,33 +572,6 @@ public struct Driver { fileSystem: fileSystem, executor: executor, integratedDriver: integratedDriver, - compilerIntegratedTooling: false, - compilerExecutableDir: compilerExecutableDir, - externalTargetModuleDetailsMap: externalTargetModuleDetailsMap, - interModuleDependencyOracle: interModuleDependencyOracle - ) - } - - @available(*, deprecated, renamed: "init(args:env:diagnosticsOutput:fileSystem:executor:integratedDriver:compilerIntegratedTooling:compilerExecutableDir:externalTargetModuleDetailsMap:interModuleDependencyOracle:)") - public init( - args: [String], - env: [String: String] = ProcessEnv.vars, - diagnosticsOutput: DiagnosticsOutput = .engine(DiagnosticsEngine(handlers: [Driver.stderrDiagnosticsHandler])), - fileSystem: FileSystem = localFileSystem, - executor: DriverExecutor, - integratedDriver: Bool = true, - compilerExecutableDir: AbsolutePath? = nil, - externalTargetModuleDetailsMap: ExternalTargetModuleDetailsMap? = nil, - interModuleDependencyOracle: InterModuleDependencyOracle? = nil - ) throws { - try self.init( - args: args, - env: env, - diagnosticsOutput: diagnosticsOutput, - fileSystem: fileSystem, - executor: executor, - integratedDriver: integratedDriver, - compilerIntegratedTooling: false, compilerExecutableDir: compilerExecutableDir, externalTargetModuleDetailsMap: externalTargetModuleDetailsMap, interModuleDependencyOracle: interModuleDependencyOracle @@ -627,8 +592,6 @@ public struct Driver { /// is present to streamline testing, it shouldn't be used in production. /// - Parameter integratedDriver: Used to distinguish whether the driver is being used as /// an executable or as a library. - /// - Parameter compilerIntegratedTooling: If true, this code is executed in the context of a - /// Swift compiler image which contains symbols normally queried from a libSwiftScan instance. /// - Parameter compilerExecutableDir: Directory that contains the compiler executable to be used. /// Used when in `integratedDriver` mode as a substitute for the driver knowing its executable path. /// - Parameter externalTargetModuleDetailsMap: A dictionary of external targets that are a part of @@ -643,7 +606,6 @@ public struct Driver { fileSystem: FileSystem = localFileSystem, executor: DriverExecutor, integratedDriver: Bool = true, - compilerIntegratedTooling: Bool = false, compilerExecutableDir: AbsolutePath? = nil, externalTargetModuleDetailsMap: ExternalTargetModuleDetailsMap? = nil, interModuleDependencyOracle: InterModuleDependencyOracle? = nil @@ -651,7 +613,6 @@ public struct Driver { self.env = env self.fileSystem = fileSystem self.integratedDriver = integratedDriver - self.compilerIntegratedTooling = compilerIntegratedTooling let diagnosticsEngine: DiagnosticsEngine switch diagnosticsOutput { @@ -707,7 +668,7 @@ public struct Driver { self.useStaticResourceDir = staticExecutable || staticStdlib // Build the toolchain and determine target information. - (self.toolchain, self.swiftCompilerPrefixArgs) = + (self.toolchain, self.frontendTargetInfo, self.swiftCompilerPrefixArgs) = try Self.computeToolchain( &self.parsedOptions, diagnosticsEngine: diagnosticEngine, compilerMode: self.compilerMode, env: env, @@ -716,40 +677,13 @@ public struct Driver { workingDirectory: self.workingDirectory, compilerExecutableDir: compilerExecutableDir) - // Create an instance of an inter-module dependency oracle, if the driver's - // client did not provide one. The clients are expected to provide an oracle - // when they wish to share module dependency information across targets. - if let dependencyOracle = interModuleDependencyOracle { - self.interModuleDependencyOracle = dependencyOracle - } else { - self.interModuleDependencyOracle = InterModuleDependencyOracle() - } - - self.swiftScanLibInstance = try Self.initializeSwiftScanInstance(&parsedOptions, - diagnosticsEngine: diagnosticEngine, - toolchain: self.toolchain, - interModuleDependencyOracle: self.interModuleDependencyOracle, - fileSystem: self.fileSystem, - compilerIntegratedTooling: self.compilerIntegratedTooling) - // Compute the host machine's triple self.hostTriple = try Self.computeHostTriple(&self.parsedOptions, diagnosticsEngine: diagnosticEngine, - libSwiftScan: self.swiftScanLibInstance, toolchain: self.toolchain, executor: self.executor, fileSystem: fileSystem, - workingDirectory: self.workingDirectory) - - // Compute the entire target info, including runtime resource paths - self.frontendTargetInfo = try Self.computeTargetInfo(&self.parsedOptions, diagnosticsEngine: diagnosticEngine, - compilerMode: self.compilerMode, env: env, - executor: self.executor, - libSwiftScan: self.swiftScanLibInstance, - toolchain: self.toolchain, - fileSystem: fileSystem, - useStaticResourceDir: self.useStaticResourceDir, - workingDirectory: self.workingDirectory, - compilerExecutableDir: compilerExecutableDir) + workingDirectory: self.workingDirectory, + swiftCompilerPrefixArgs: self.swiftCompilerPrefixArgs) // Classify and collect all of the input files. let inputFiles = try Self.collectInputFiles(&self.parsedOptions, diagnosticsEngine: diagnosticsEngine, fileSystem: self.fileSystem) @@ -782,6 +716,15 @@ public struct Driver { } } + // Create an instance of an inter-module dependency oracle, if the driver's + // client did not provide one. The clients are expected to provide an oracle + // when they wish to share module dependency information across targets. + if let dependencyOracle = interModuleDependencyOracle { + self.interModuleDependencyOracle = dependencyOracle + } else { + self.interModuleDependencyOracle = InterModuleDependencyOracle() + } + self.fileListThreshold = try Self.computeFileListThreshold(&self.parsedOptions, diagnosticsEngine: diagnosticsEngine) self.shouldUseInputFileList = inputFiles.count > fileListThreshold @@ -867,7 +810,6 @@ public struct Driver { self.supportedFrontendFlags = try Self.computeSupportedCompilerArgs(of: self.toolchain, - libSwiftScan: self.swiftScanLibInstance, parsedOptions: &self.parsedOptions, diagnosticsEngine: diagnosticEngine, fileSystem: fileSystem, @@ -912,18 +854,6 @@ public struct Driver { self.scannerPrefixMapToolchain = nil } - // Initialize the CAS instance - if self.swiftScanLibInstance != nil && - self.enableCaching && - self.supportedFrontendFeatures.contains(KnownCompilerFeature.compilation_caching.rawValue) { - self.cas = - try self.interModuleDependencyOracle.getOrCreateCAS(pluginPath: try Self.getCASPluginPath(parsedOptions: &self.parsedOptions, - toolchain: self.toolchain), - onDiskPath: try Self.getOnDiskCASPath(parsedOptions: &self.parsedOptions, - toolchain: self.toolchain), - pluginOptions: try Self.getCASPluginOptions(parsedOptions: &self.parsedOptions)) - } - self.enabledSanitizers = try Self.parseSanitizerArgValues( &parsedOptions, diagnosticEngine: diagnosticEngine, @@ -3296,53 +3226,23 @@ extension Driver { static func computeHostTriple( _ parsedOptions: inout ParsedOptions, diagnosticsEngine: DiagnosticsEngine, - libSwiftScan: SwiftScan?, toolchain: Toolchain, executor: DriverExecutor, fileSystem: FileSystem, - workingDirectory: AbsolutePath?) throws -> Triple { + workingDirectory: AbsolutePath?, + swiftCompilerPrefixArgs: [String]) throws -> Triple { let frontendOverride = try FrontendOverride(&parsedOptions, diagnosticsEngine) frontendOverride.setUpForTargetInfo(toolchain) defer { frontendOverride.setUpForCompilation(toolchain) } return try Self.computeTargetInfo(target: nil, targetVariant: nil, swiftCompilerPrefixArgs: frontendOverride.prefixArgsForTargetInfo, - libSwiftScan: libSwiftScan, toolchain: toolchain, fileSystem: fileSystem, workingDirectory: workingDirectory, diagnosticsEngine: diagnosticsEngine, executor: executor).target.triple } - static func initializeSwiftScanInstance( - _ parsedOptions: inout ParsedOptions, - diagnosticsEngine: DiagnosticsEngine, - toolchain: Toolchain, - interModuleDependencyOracle: InterModuleDependencyOracle, - fileSystem: FileSystem, - compilerIntegratedTooling: Bool) throws -> SwiftScan? { - guard !parsedOptions.hasArgument(.driverScanDependenciesNonLib) else { - return nil - } - - let swiftScanLibPath: AbsolutePath? = compilerIntegratedTooling ? nil : try toolchain.lookupSwiftScanLib() - do { - guard compilerIntegratedTooling || - (swiftScanLibPath != nil && fileSystem.exists(swiftScanLibPath!)) else { - diagnosticsEngine.emit(.warn_scan_dylib_not_found()) - return nil - } - - // Ensure the oracle initializes or verifies the existing scanner instance - try interModuleDependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: swiftScanLibPath) - // The driver needs a reference to this for non-scanning tasks - return interModuleDependencyOracle.getScannerInstance() - } catch { - diagnosticsEngine.emit(.warn_scan_dylib_load_failed(swiftScanLibPath?.description ?? "built-in")) - } - return nil - } - static func computeToolchain( _ parsedOptions: inout ParsedOptions, diagnosticsEngine: DiagnosticsEngine, @@ -3353,11 +3253,23 @@ extension Driver { useStaticResourceDir: Bool, workingDirectory: AbsolutePath?, compilerExecutableDir: AbsolutePath? - ) throws -> (Toolchain, [String]) { + ) throws -> (Toolchain, FrontendTargetInfo, [String]) { let explicitTarget = (parsedOptions.getLastArgument(.target)?.asSingle) .map { Triple($0, normalizing: true) } + let explicitTargetVariant = (parsedOptions.getLastArgument(.targetVariant)?.asSingle) + .map { + Triple($0, normalizing: true) + } + + // Determine the resource directory. + let resourceDirPath: VirtualPath? + if let resourceDirArg = parsedOptions.getLastArgument(.resourceDir) { + resourceDirPath = try VirtualPath(path: resourceDirArg.asSingle) + } else { + resourceDirPath = nil + } let toolchainType = try explicitTarget?.toolchainType(diagnosticsEngine) ?? defaultToolchainType @@ -3371,61 +3283,30 @@ extension Driver { compilerExecutableDir: compilerExecutableDir, toolDirectory: toolDir) - let frontendOverride = try FrontendOverride(&parsedOptions, diagnosticsEngine) - return (toolchain, frontendOverride.prefixArgs) - } - - static func computeTargetInfo(_ parsedOptions: inout ParsedOptions, - diagnosticsEngine: DiagnosticsEngine, - compilerMode: CompilerMode, - env: [String: String], - executor: DriverExecutor, - libSwiftScan: SwiftScan?, - toolchain: Toolchain, - fileSystem: FileSystem, - useStaticResourceDir: Bool, - workingDirectory: AbsolutePath?, - compilerExecutableDir: AbsolutePath?) throws -> FrontendTargetInfo { - let explicitTarget = (parsedOptions.getLastArgument(.target)?.asSingle) - .map { - Triple($0, normalizing: true) - } - let explicitTargetVariant = (parsedOptions.getLastArgument(.targetVariant)?.asSingle) - .map { - Triple($0, normalizing: true) - } - let frontendOverride = try FrontendOverride(&parsedOptions, diagnosticsEngine) frontendOverride.setUpForTargetInfo(toolchain) defer { frontendOverride.setUpForCompilation(toolchain) } - // Find the SDK, if any. let sdkPath: VirtualPath? = Self.computeSDKPath( &parsedOptions, compilerMode: compilerMode, toolchain: toolchain, targetTriple: explicitTarget, fileSystem: fileSystem, diagnosticsEngine: diagnosticsEngine, env: env) + // Query the frontend for target information. do { - // Determine the resource directory. - let resourceDirPath: VirtualPath? - if let resourceDirArg = parsedOptions.getLastArgument(.resourceDir) { - resourceDirPath = try VirtualPath(path: resourceDirArg.asSingle) - } else { - resourceDirPath = nil - } var info: FrontendTargetInfo = try Self.computeTargetInfo(target: explicitTarget, targetVariant: explicitTargetVariant, sdkPath: sdkPath, resourceDirPath: resourceDirPath, runtimeCompatibilityVersion: - parsedOptions.getLastArgument(.runtimeCompatibilityVersion)?.asSingle, + parsedOptions.getLastArgument(.runtimeCompatibilityVersion)?.asSingle, useStaticResourceDir: useStaticResourceDir, swiftCompilerPrefixArgs: frontendOverride.prefixArgsForTargetInfo, - libSwiftScan: libSwiftScan, toolchain: toolchain, fileSystem: fileSystem, workingDirectory: workingDirectory, diagnosticsEngine: diagnosticsEngine, executor: executor) + // Parse the runtime compatibility version. If present, it will override // what is reported by the frontend. if let versionString = @@ -3447,23 +3328,23 @@ extension Driver { diagnosticsEngine.emit(.warning_inferring_simulator_target(originalTriple: explicitTarget, inferredTriple: info.target.triple)) } - return info + return (toolchain, info, frontendOverride.prefixArgs) } catch let JobExecutionError.decodingError(decodingError, dataToDecode, processResult) { let stringToDecode = String(data: dataToDecode, encoding: .utf8) let errorDesc: String switch decodingError { - case let .typeMismatch(type, context): - errorDesc = "type mismatch: \(type), path: \(context.codingPath)" - case let .valueNotFound(type, context): - errorDesc = "value missing: \(type), path: \(context.codingPath)" - case let .keyNotFound(key, context): - errorDesc = "key missing: \(key), path: \(context.codingPath)" - case let .dataCorrupted(context): - errorDesc = "data corrupted at path: \(context.codingPath)" - @unknown default: - errorDesc = "unknown decoding error" + case let .typeMismatch(type, context): + errorDesc = "type mismatch: \(type), path: \(context.codingPath)" + case let .valueNotFound(type, context): + errorDesc = "value missing: \(type), path: \(context.codingPath)" + case let .keyNotFound(key, context): + errorDesc = "key missing: \(key), path: \(context.codingPath)" + case let .dataCorrupted(context): + errorDesc = "data corrupted at path: \(context.codingPath)" + @unknown default: + errorDesc = "unknown decoding error" } throw Error.unableToDecodeFrontendTargetInfo( stringToDecode, @@ -3757,23 +3638,21 @@ extension Driver { // CAS and Caching. extension Driver { - static func getCASPluginPath(parsedOptions: inout ParsedOptions, - toolchain: Toolchain) throws -> AbsolutePath? { + mutating func getCASPluginPath() throws -> AbsolutePath? { if let pluginPath = parsedOptions.getLastArgument(.casPluginPath)?.asSingle { return try AbsolutePath(validating: pluginPath.description) } return try toolchain.lookupToolchainCASPluginLib() } - static func getOnDiskCASPath(parsedOptions: inout ParsedOptions, - toolchain: Toolchain) throws -> AbsolutePath? { + mutating func getOnDiskCASPath() throws -> AbsolutePath? { if let casPathOpt = parsedOptions.getLastArgument(.casPath)?.asSingle { return try AbsolutePath(validating: casPathOpt.description) } return nil; } - static func getCASPluginOptions(parsedOptions: inout ParsedOptions) throws -> [(String, String)] { + mutating func getCASPluginOptions() throws -> [(String, String)] { var options : [(String, String)] = [] for opt in parsedOptions.arguments(for: .casPluginOption) { let pluginArg = opt.argument.asSingle.split(separator: "=", maxSplits: 1) diff --git a/Sources/SwiftDriver/Execution/DriverExecutor.swift b/Sources/SwiftDriver/Execution/DriverExecutor.swift index 2628c2d5a..b93c45ad6 100644 --- a/Sources/SwiftDriver/Execution/DriverExecutor.swift +++ b/Sources/SwiftDriver/Execution/DriverExecutor.swift @@ -80,7 +80,7 @@ public struct DriverExecutorWorkload { } } -@_spi(Testing) public enum JobExecutionError: Error { +enum JobExecutionError: Error { case jobFailedWithNonzeroExitCode(Int, String) case failedToReadJobOutput // A way to pass more information to the catch point diff --git a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift index 63162810c..d389071c5 100644 --- a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift +++ b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift @@ -83,17 +83,16 @@ public class InterModuleDependencyOracle { } /// Given a specified toolchain path, locate and instantiate an instance of the SwiftScan library - public func verifyOrCreateScannerInstance(swiftScanLibPath: AbsolutePath?) throws { + public func verifyOrCreateScannerInstance(fileSystem: FileSystem, + swiftScanLibPath: AbsolutePath) throws { return try queue.sync { - guard let scanInstance = swiftScanLibInstance else { + if swiftScanLibInstance == nil { swiftScanLibInstance = try SwiftScan(dylib: swiftScanLibPath) - return - } - - guard scanInstance.path?.description == swiftScanLibPath?.description else { - throw DependencyScanningError - .scanningLibraryInvocationMismatch(scanInstance.path?.description ?? "built-in", - swiftScanLibPath?.description ?? "built-in") + } else { + guard swiftScanLibInstance!.path == swiftScanLibPath else { + throw DependencyScanningError + .scanningLibraryInvocationMismatch(swiftScanLibInstance!.path, swiftScanLibPath) + } } } } @@ -210,20 +209,10 @@ public class InterModuleDependencyOracle { } } - // Note: this is `true` even in the `compilerIntegratedTooling` mode - // where the `SwiftScan` instance refers to the own image the driver is - // running in, since there is still technically a `SwiftScan` handle - // capable of handling API requests expected of it. private var hasScannerInstance: Bool { self.swiftScanLibInstance != nil } - func getScannerInstance() -> SwiftScan? { - self.swiftScanLibInstance - } - func setScannerInstance(_ instance: SwiftScan?) { - self.swiftScanLibInstance = instance - } /// Queue to sunchronize accesses to the scanner - let queue = DispatchQueue(label: "org.swift.swift-driver.swift-scan") + internal let queue = DispatchQueue(label: "org.swift.swift-driver.swift-scan") /// A reference to an instance of the compiler's libSwiftScan shared library private var swiftScanLibInstance: SwiftScan? = nil diff --git a/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift b/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift index 70a4e5f9f..23be50297 100644 --- a/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift +++ b/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift @@ -164,6 +164,41 @@ public extension Driver { contents) } + /// Returns false if the lib is available and ready to use + private mutating func initSwiftScanLib() throws -> Bool { + // `-nonlib-dependency-scanner` was specified + guard !parsedOptions.hasArgument(.driverScanDependenciesNonLib) else { + return true + } + + // If the libSwiftScan library cannot be found, + // attempt to fallback to using `swift-frontend -scan-dependencies` invocations for dependency + // scanning. + guard let scanLibPath = try toolchain.lookupSwiftScanLib(), + fileSystem.exists(scanLibPath) else { + diagnosticEngine.emit(.warn_scan_dylib_not_found()) + return true + } + + do { + try interModuleDependencyOracle.verifyOrCreateScannerInstance(fileSystem: fileSystem, + swiftScanLibPath: scanLibPath) + if isCachingEnabled { + self.cas = try interModuleDependencyOracle.getOrCreateCAS(pluginPath: try getCASPluginPath(), + onDiskPath: try getOnDiskCASPath(), + pluginOptions: try getCASPluginOptions()) + } + } catch { + if isCachingEnabled { + diagnosticEngine.emit(.error_caching_enabled_libswiftscan_load_failure(scanLibPath.description)) + } else { + diagnosticEngine.emit(.warn_scan_dylib_load_failed(scanLibPath.description)) + } + return true + } + return false + } + static func sanitizeCommandForLibScanInvocation(_ command: inout [String]) { // Remove the tool executable to only leave the arguments. When passing the // command line into libSwiftScan, the library is itself the tool and only @@ -182,7 +217,8 @@ public extension Driver { let forceResponseFiles = parsedOptions.hasArgument(.driverForceResponseFiles) let imports: InterModuleDependencyImports - if supportInProcessSwiftScanQueries { + let isSwiftScanLibAvailable = !(try initSwiftScanLib()) + if isSwiftScanLibAvailable { var scanDiagnostics: [ScannerDiagnosticPayload] = [] guard let cwd = workingDirectory else { throw DependencyScanningError.dependencyScanFailed("cannot determine working directory") @@ -258,7 +294,8 @@ public extension Driver { stdoutStream.flush() } - if supportInProcessSwiftScanQueries { + let isSwiftScanLibAvailable = !(try initSwiftScanLib()) + if isSwiftScanLibAvailable { var scanDiagnostics: [ScannerDiagnosticPayload] = [] guard let cwd = workingDirectory else { throw DependencyScanningError.dependencyScanFailed("cannot determine working directory") @@ -296,7 +333,8 @@ public extension Driver { let forceResponseFiles = parsedOptions.hasArgument(.driverForceResponseFiles) let moduleVersionedGraphMap: [ModuleDependencyId: [InterModuleDependencyGraph]] - if supportInProcessSwiftScanQueries { + let isSwiftScanLibAvailable = !(try initSwiftScanLib()) + if isSwiftScanLibAvailable { var scanDiagnostics: [ScannerDiagnosticPayload] = [] guard let cwd = workingDirectory else { throw DependencyScanningError.dependencyScanFailed("cannot determine working directory") @@ -464,7 +502,3 @@ public extension Driver { .parentDirectory // toolchain root } } - -extension Driver { - var supportInProcessSwiftScanQueries: Bool { return self.swiftScanLibInstance != nil } -} diff --git a/Sources/SwiftDriver/Jobs/EmitSupportedFeaturesJob.swift b/Sources/SwiftDriver/Jobs/EmitSupportedFeaturesJob.swift index 06fce203d..1adfbd827 100644 --- a/Sources/SwiftDriver/Jobs/EmitSupportedFeaturesJob.swift +++ b/Sources/SwiftDriver/Jobs/EmitSupportedFeaturesJob.swift @@ -59,19 +59,18 @@ extension Toolchain { extension Driver { static func computeSupportedCompilerArgs(of toolchain: Toolchain, - libSwiftScan: SwiftScan?, parsedOptions: inout ParsedOptions, diagnosticsEngine: DiagnosticsEngine, fileSystem: FileSystem, executor: DriverExecutor) throws -> Set { - if let libSwiftScanInstance = libSwiftScan, - libSwiftScanInstance.canQuerySupportedArguments() { - do { - return try libSwiftScanInstance.querySupportedArguments() - } catch { - diagnosticsEngine.emit(.remark_inprocess_supported_features_query_failed(error.localizedDescription)) + do { + if let supportedArgs = + try querySupportedCompilerArgsInProcess(of: toolchain, fileSystem: fileSystem) { + return supportedArgs } + } catch { + diagnosticsEngine.emit(.remark_inprocess_supported_features_query_failed(error.localizedDescription)) } // Fallback: Invoke `swift-frontend -emit-supported-features` and decode the output @@ -89,6 +88,20 @@ extension Driver { return Set(decodedSupportedFlagList) } + static func querySupportedCompilerArgsInProcess(of toolchain: Toolchain, + fileSystem: FileSystem) + throws -> Set? { + let optionalSwiftScanLibPath = try toolchain.lookupSwiftScanLib() + if let swiftScanLibPath = optionalSwiftScanLibPath, + fileSystem.exists(swiftScanLibPath) { + let libSwiftScanInstance = try SwiftScan(dylib: swiftScanLibPath) + if libSwiftScanInstance.canQuerySupportedArguments() { + return try libSwiftScanInstance.querySupportedArguments() + } + } + return nil + } + static func computeSupportedCompilerFeatures(of toolchain: Toolchain, env: [String: String]) throws -> Set { struct FeatureInfo: Codable { diff --git a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift index 386412b5e..0061a4b04 100644 --- a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift +++ b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift @@ -406,13 +406,11 @@ extension Driver { // CAS related options. if isCachingEnabled { commandLine.appendFlag(.cacheCompileJob) - if let casPath = try Self.getOnDiskCASPath(parsedOptions: &parsedOptions, - toolchain: toolchain) { + if let casPath = try getOnDiskCASPath() { commandLine.appendFlag(.casPath) commandLine.appendFlag(casPath.pathString) } - if let pluginPath = try Self.getCASPluginPath(parsedOptions: &parsedOptions, - toolchain: toolchain) { + if let pluginPath = try getCASPluginPath() { commandLine.appendFlag(.casPluginPath) commandLine.appendFlag(pluginPath.pathString) } diff --git a/Sources/SwiftDriver/Jobs/PrintTargetInfoJob.swift b/Sources/SwiftDriver/Jobs/PrintTargetInfoJob.swift index 5839b8bd7..679e63533 100644 --- a/Sources/SwiftDriver/Jobs/PrintTargetInfoJob.swift +++ b/Sources/SwiftDriver/Jobs/PrintTargetInfoJob.swift @@ -181,39 +181,46 @@ extension Toolchain { } extension Driver { - @_spi(Testing) public static func queryTargetInfoInProcess(libSwiftScanInstance: SwiftScan, - toolchain: Toolchain, + @_spi(Testing) public static func queryTargetInfoInProcess(of toolchain: Toolchain, fileSystem: FileSystem, workingDirectory: AbsolutePath?, - invocationCommand: [String]) throws -> FrontendTargetInfo { - let cwd = try workingDirectory ?? fileSystem.tempDirectory - let compilerExecutablePath = try toolchain.resolvedTool(.swiftCompiler).path - let targetInfoData = - try libSwiftScanInstance.queryTargetInfoJSON(workingDirectory: cwd, - compilerExecutablePath: compilerExecutablePath, - invocationCommand: invocationCommand) - do { - return try JSONDecoder().decode(FrontendTargetInfo.self, from: targetInfoData) - } catch let decodingError as DecodingError { - let stringToDecode = String(data: targetInfoData, encoding: .utf8) - let errorDesc: String - switch decodingError { - case let .typeMismatch(type, context): - errorDesc = "type mismatch: \(type), path: \(context.codingPath)" - case let .valueNotFound(type, context): - errorDesc = "value missing: \(type), path: \(context.codingPath)" - case let .keyNotFound(key, context): - errorDesc = "key missing: \(key), path: \(context.codingPath)" - case let .dataCorrupted(context): - errorDesc = "data corrupted at path: \(context.codingPath)" - @unknown default: - errorDesc = "unknown decoding error" + invocationCommand: [String]) throws -> FrontendTargetInfo? { + let optionalSwiftScanLibPath = try toolchain.lookupSwiftScanLib() + if let swiftScanLibPath = optionalSwiftScanLibPath, + fileSystem.exists(swiftScanLibPath) { + let libSwiftScanInstance = try SwiftScan(dylib: swiftScanLibPath) + if libSwiftScanInstance.canQueryTargetInfo() { + let cwd = try workingDirectory ?? fileSystem.tempDirectory + let compilerExecutablePath = try toolchain.resolvedTool(.swiftCompiler).path + let targetInfoData = + try libSwiftScanInstance.queryTargetInfoJSON(workingDirectory: cwd, + compilerExecutablePath: compilerExecutablePath, + invocationCommand: invocationCommand) + do { + return try JSONDecoder().decode(FrontendTargetInfo.self, from: targetInfoData) + } catch let decodingError as DecodingError { + let stringToDecode = String(data: targetInfoData, encoding: .utf8) + let errorDesc: String + switch decodingError { + case let .typeMismatch(type, context): + errorDesc = "type mismatch: \(type), path: \(context.codingPath)" + case let .valueNotFound(type, context): + errorDesc = "value missing: \(type), path: \(context.codingPath)" + case let .keyNotFound(key, context): + errorDesc = "key missing: \(key), path: \(context.codingPath)" + case let .dataCorrupted(context): + errorDesc = "data corrupted at path: \(context.codingPath)" + @unknown default: + errorDesc = "unknown decoding error" + } + throw Error.unableToDecodeFrontendTargetInfo( + stringToDecode, + invocationCommand, + errorDesc) + } } - throw Error.unableToDecodeFrontendTargetInfo( - stringToDecode, - invocationCommand, - errorDesc) } + return nil } static func computeTargetInfo(target: Triple?, @@ -224,7 +231,6 @@ extension Driver { requiresInPlaceExecution: Bool = false, useStaticResourceDir: Bool = false, swiftCompilerPrefixArgs: [String], - libSwiftScan: SwiftScan?, toolchain: Toolchain, fileSystem: FileSystem, workingDirectory: AbsolutePath?, @@ -237,19 +243,20 @@ extension Driver { requiresInPlaceExecution: requiresInPlaceExecution, useStaticResourceDir: useStaticResourceDir, swiftCompilerPrefixArgs: swiftCompilerPrefixArgs) - if let libSwiftScanInstance = libSwiftScan, - libSwiftScanInstance.canQueryTargetInfo() { - do { - var command = try Self.itemizedJobCommand(of: frontendTargetInfoJob, - useResponseFiles: .disabled, - using: executor.resolver) - Self.sanitizeCommandForLibScanInvocation(&command) - return try Self.queryTargetInfoInProcess(libSwiftScanInstance: libSwiftScanInstance, toolchain: toolchain, - fileSystem: fileSystem, workingDirectory: workingDirectory, - invocationCommand: command) - } catch { - diagnosticsEngine.emit(.remark_inprocess_target_info_query_failed(error.localizedDescription)) + var command = try Self.itemizedJobCommand(of: frontendTargetInfoJob, + useResponseFiles: .disabled, + using: executor.resolver) + Self.sanitizeCommandForLibScanInvocation(&command) + + do { + if let targetInfo = + try Self.queryTargetInfoInProcess(of: toolchain, fileSystem: fileSystem, + workingDirectory: workingDirectory, + invocationCommand: command) { + return targetInfo } + } catch { + diagnosticsEngine.emit(.remark_inprocess_target_info_query_failed(error.localizedDescription)) } // Fallback: Invoke `swift-frontend -print-target-info` and decode the output diff --git a/Sources/SwiftDriver/SwiftScan/Loader.swift b/Sources/SwiftDriver/SwiftScan/Loader.swift index 0c4f0928c..2ab4e6fd4 100644 --- a/Sources/SwiftDriver/SwiftScan/Loader.swift +++ b/Sources/SwiftDriver/SwiftScan/Loader.swift @@ -161,19 +161,6 @@ extension Loader { return Handle(value: handle) } - public static func getSelfHandle(mode: Flags) throws -> Handle { -#if os(Windows) - guard let handle = GetModuleHandleW(nil) else { - throw Loader.Error.open("GetModuleHandleW(nil) failure: \(GetLastError())") - } -#else - guard let handle = dlopen(nil, mode.rawValue) else { - throw Loader.Error.open(Loader.error() ?? "unknown error") - } -#endif - return Handle(value: handle) - } - public static func lookup(symbol: String, in module: Handle) -> T? { #if os(Windows) guard let pointer = GetProcAddress(module.value!, symbol) else { diff --git a/Sources/SwiftDriver/SwiftScan/SwiftScan.swift b/Sources/SwiftDriver/SwiftScan/SwiftScan.swift index b5f80e918..87b8fc538 100644 --- a/Sources/SwiftDriver/SwiftScan/SwiftScan.swift +++ b/Sources/SwiftDriver/SwiftScan/SwiftScan.swift @@ -32,7 +32,7 @@ public enum DependencyScanningError: LocalizedError, DiagnosticData, Equatable { case moduleNameDecodeFailure(String) case unsupportedDependencyDetailsKind(Int) case invalidStringPtr - case scanningLibraryInvocationMismatch(String, String) + case scanningLibraryInvocationMismatch(AbsolutePath, AbsolutePath) case scanningLibraryNotFound(AbsolutePath) case argumentQueryFailed case unsupportedConfigurationForCaching(String) @@ -56,7 +56,7 @@ public enum DependencyScanningError: LocalizedError, DiagnosticData, Equatable { case .invalidStringPtr: return "Dependency module details contains a corrupted string reference" case .scanningLibraryInvocationMismatch(let path1, let path2): - return "Dependency Scanning library differs across driver invocations: \(path1) and \(path2)" + return "Dependency Scanning library differs across driver invocations: \(path1.description) and \(path2.description)" case .scanningLibraryNotFound(let path): return "Dependency Scanning library not found at path: \(path)" case .argumentQueryFailed: @@ -112,7 +112,7 @@ private extension String { /// Wrapper for libSwiftScan, taking care of initialization, shutdown, and dispatching dependency scanning queries. @_spi(Testing) public final class SwiftScan { /// The path to the libSwiftScan dylib. - let path: AbsolutePath? + let path: AbsolutePath /// The handle to the dylib. let dylib: Loader.Handle @@ -123,21 +123,13 @@ private extension String { /// Instance of a scanner, which maintains shared state across scan queries. let scanner: swiftscan_scanner_t; - @_spi(Testing) public init(dylib path: AbsolutePath? = nil) throws { + @_spi(Testing) public init(dylib path: AbsolutePath) throws { self.path = path - if let externalPath = path { -#if os(Windows) - self.dylib = try Loader.load(externalPath.pathString, mode: []) -#else - self.dylib = try Loader.load(externalPath.pathString, mode: [.lazy, .local, .first]) -#endif - } else { -#if os(Windows) - self.dylib = try Loader.getSelfHandle(mode: []) -#else - self.dylib = try Loader.getSelfHandle(mode: [.lazy, .local, .first]) -#endif - } + #if os(Windows) + self.dylib = try Loader.load(path.pathString, mode: []) + #else + self.dylib = try Loader.load(path.pathString, mode: [.lazy, .local, .first]) + #endif self.api = try swiftscan_functions_t(self.dylib) guard let scanner = api.swiftscan_scanner_create() else { throw DependencyScanningError.failedToInstantiateScanner @@ -543,7 +535,7 @@ private extension swiftscan_functions_t { // MARK: Optional Methods // Future optional methods can be queried here - func loadOptional(_ symbol: String) -> T? { + func loadOptional(_ symbol: String) throws -> T? { guard let sym: T = Loader.lookup(symbol: symbol, in: swiftscan) else { return nil } @@ -551,130 +543,130 @@ private extension swiftscan_functions_t { } // Supported features/flags query self.swiftscan_string_set_dispose = - loadOptional("swiftscan_string_set_dispose") + try loadOptional("swiftscan_string_set_dispose") self.swiftscan_compiler_supported_arguments_query = - loadOptional("swiftscan_compiler_supported_arguments_query") + try loadOptional("swiftscan_compiler_supported_arguments_query") self.swiftscan_compiler_supported_features_query = - loadOptional("swiftscan_compiler_supported_features_query") + try loadOptional("swiftscan_compiler_supported_features_query") // Target Info query self.swiftscan_compiler_target_info_query_v2 = - loadOptional("swiftscan_compiler_target_info_query_v2") + try loadOptional("swiftscan_compiler_target_info_query_v2") // Dependency scanner serialization/deserialization features self.swiftscan_scanner_cache_serialize = - loadOptional("swiftscan_scanner_cache_serialize") + try loadOptional("swiftscan_scanner_cache_serialize") self.swiftscan_scanner_cache_load = - loadOptional("swiftscan_scanner_cache_load") + try loadOptional("swiftscan_scanner_cache_load") self.swiftscan_scanner_cache_reset = - loadOptional("swiftscan_scanner_cache_reset") + try loadOptional("swiftscan_scanner_cache_reset") // Clang dependency captured PCM args self.swiftscan_clang_detail_get_captured_pcm_args = - loadOptional("swiftscan_clang_detail_get_captured_pcm_args") + try loadOptional("swiftscan_clang_detail_get_captured_pcm_args") // Scanner diagnostic emission query self.swiftscan_scanner_diagnostics_query = - loadOptional("swiftscan_scanner_diagnostics_query") + try loadOptional("swiftscan_scanner_diagnostics_query") self.swiftscan_scanner_diagnostics_reset = - loadOptional("swiftscan_scanner_diagnostics_reset") + try loadOptional("swiftscan_scanner_diagnostics_reset") self.swiftscan_diagnostic_get_message = - loadOptional("swiftscan_diagnostic_get_message") + try loadOptional("swiftscan_diagnostic_get_message") self.swiftscan_diagnostic_get_severity = - loadOptional("swiftscan_diagnostic_get_severity") + try loadOptional("swiftscan_diagnostic_get_severity") self.swiftscan_diagnostics_set_dispose = - loadOptional("swiftscan_diagnostics_set_dispose") + try loadOptional("swiftscan_diagnostics_set_dispose") self.swiftscan_string_dispose = - loadOptional("swiftscan_string_dispose") + try loadOptional("swiftscan_string_dispose") // isFramework on binary module dependencies self.swiftscan_swift_binary_detail_get_is_framework = - loadOptional("swiftscan_swift_binary_detail_get_is_framework") + try loadOptional("swiftscan_swift_binary_detail_get_is_framework") // Clang module dependencies of header input of binary module dependencies self.swiftscan_swift_binary_detail_get_header_dependency_module_dependencies = - loadOptional("swiftscan_swift_binary_detail_get_header_dependency_module_dependencies") + try loadOptional("swiftscan_swift_binary_detail_get_header_dependency_module_dependencies") // Bridging PCH build command-line self.swiftscan_swift_textual_detail_get_bridging_pch_command_line = - loadOptional("swiftscan_swift_textual_detail_get_bridging_pch_command_line") + try loadOptional("swiftscan_swift_textual_detail_get_bridging_pch_command_line") // Caching related APIs. self.swiftscan_swift_textual_detail_get_module_cache_key = - loadOptional("swiftscan_swift_textual_detail_get_module_cache_key") + try loadOptional("swiftscan_swift_textual_detail_get_module_cache_key") self.swiftscan_swift_binary_detail_get_module_cache_key = - loadOptional("swiftscan_swift_binary_detail_get_module_cache_key") + try loadOptional("swiftscan_swift_binary_detail_get_module_cache_key") self.swiftscan_clang_detail_get_module_cache_key = - loadOptional("swiftscan_clang_detail_get_module_cache_key") - - self.swiftscan_cas_options_create = loadOptional("swiftscan_cas_options_create") - self.swiftscan_cas_options_set_plugin_path = loadOptional("swiftscan_cas_options_set_plugin_path") - self.swiftscan_cas_options_set_ondisk_path = loadOptional("swiftscan_cas_options_set_ondisk_path") - self.swiftscan_cas_options_set_plugin_option = loadOptional("swiftscan_cas_options_set_plugin_option") - self.swiftscan_cas_options_dispose = loadOptional("swiftscan_cas_options_dispose") - self.swiftscan_cas_create_from_options = loadOptional("swiftscan_cas_create_from_options") - self.swiftscan_cas_get_ondisk_size = loadOptional("swiftscan_cas_get_ondisk_size") - self.swiftscan_cas_set_ondisk_size_limit = loadOptional("swiftscan_cas_set_ondisk_size_limit") - self.swiftscan_cas_prune_ondisk_data = loadOptional("swiftscan_cas_prune_ondisk_data") - self.swiftscan_cas_dispose = loadOptional("swiftscan_cas_dispose") - self.swiftscan_cache_compute_key = loadOptional("swiftscan_cache_compute_key") - self.swiftscan_cache_compute_key_from_input_index = loadOptional("swiftscan_cache_compute_key_from_input_index") - self.swiftscan_cas_store = loadOptional("swiftscan_cas_store") - - self.swiftscan_cache_query = loadOptional("swiftscan_cache_query") - self.swiftscan_cache_query_async = loadOptional("swiftscan_cache_query_async") - - self.swiftscan_cached_compilation_get_num_outputs = loadOptional("swiftscan_cached_compilation_get_num_outputs") - self.swiftscan_cached_compilation_get_output = loadOptional("swiftscan_cached_compilation_get_output") - self.swiftscan_cached_compilation_make_global_async = loadOptional("swiftscan_cached_compilation_make_global_async") - self.swiftscan_cached_compilation_is_uncacheable = loadOptional("swiftscan_cached_compilation_is_uncacheable") - self.swiftscan_cached_compilation_dispose = loadOptional("swiftscan_cached_compilation_dispose") - - self.swiftscan_cached_output_load = loadOptional("swiftscan_cached_output_load") - self.swiftscan_cached_output_load_async = loadOptional("swiftscan_cached_output_load_async") - self.swiftscan_cached_output_is_materialized = loadOptional("swiftscan_cached_output_is_materialized") - self.swiftscan_cached_output_get_casid = loadOptional("swiftscan_cached_output_get_casid") - self.swiftscan_cached_output_get_name = loadOptional("swiftscan_cached_output_get_name") - self.swiftscan_cached_output_dispose = loadOptional("swiftscan_cached_output_dispose") - - self.swiftscan_cache_action_cancel = loadOptional("swiftscan_cache_action_cancel") - self.swiftscan_cache_cancellation_token_dispose = loadOptional("swiftscan_cache_cancellation_token_dispose") - - self.swiftscan_cache_download_cas_object_async = loadOptional("swiftscan_cache_download_cas_object_async") - - self.swiftscan_cache_replay_instance_create = loadOptional("swiftscan_cache_replay_instance_create") - self.swiftscan_cache_replay_instance_dispose = loadOptional("swiftscan_cache_replay_instance_dispose") - self.swiftscan_cache_replay_compilation = loadOptional("swiftscan_cache_replay_compilation") - - self.swiftscan_cache_replay_result_get_stdout = loadOptional("swiftscan_cache_replay_result_get_stdout") - self.swiftscan_cache_replay_result_get_stderr = loadOptional("swiftscan_cache_replay_result_get_stderr") - self.swiftscan_cache_replay_result_dispose = loadOptional("swiftscan_cache_replay_result_dispose") - - self.swiftscan_diagnostic_get_source_location = loadOptional("swiftscan_diagnostic_get_source_location") - self.swiftscan_source_location_get_buffer_identifier = loadOptional("swiftscan_source_location_get_buffer_identifier") - self.swiftscan_source_location_get_line_number = loadOptional("swiftscan_source_location_get_line_number") - self.swiftscan_source_location_get_column_number = loadOptional("swiftscan_source_location_get_column_number") - - self.swiftscan_module_info_get_link_libraries = loadOptional("swiftscan_module_info_get_link_libraries") - self.swiftscan_link_library_info_get_link_name = loadOptional("swiftscan_link_library_info_get_link_name") - self.swiftscan_link_library_info_get_is_framework = loadOptional("swiftscan_link_library_info_get_is_framework") - self.swiftscan_link_library_info_get_should_force_load = loadOptional("swiftscan_link_library_info_get_should_force_load") + try loadOptional("swiftscan_clang_detail_get_module_cache_key") + + self.swiftscan_cas_options_create = try loadOptional("swiftscan_cas_options_create") + self.swiftscan_cas_options_set_plugin_path = try loadOptional("swiftscan_cas_options_set_plugin_path") + self.swiftscan_cas_options_set_ondisk_path = try loadOptional("swiftscan_cas_options_set_ondisk_path") + self.swiftscan_cas_options_set_plugin_option = try loadOptional("swiftscan_cas_options_set_plugin_option") + self.swiftscan_cas_options_dispose = try loadOptional("swiftscan_cas_options_dispose") + self.swiftscan_cas_create_from_options = try loadOptional("swiftscan_cas_create_from_options") + self.swiftscan_cas_get_ondisk_size = try loadOptional("swiftscan_cas_get_ondisk_size") + self.swiftscan_cas_set_ondisk_size_limit = try loadOptional("swiftscan_cas_set_ondisk_size_limit") + self.swiftscan_cas_prune_ondisk_data = try loadOptional("swiftscan_cas_prune_ondisk_data") + self.swiftscan_cas_dispose = try loadOptional("swiftscan_cas_dispose") + self.swiftscan_cache_compute_key = try loadOptional("swiftscan_cache_compute_key") + self.swiftscan_cache_compute_key_from_input_index = try loadOptional("swiftscan_cache_compute_key_from_input_index") + self.swiftscan_cas_store = try loadOptional("swiftscan_cas_store") + + self.swiftscan_cache_query = try loadOptional("swiftscan_cache_query") + self.swiftscan_cache_query_async = try loadOptional("swiftscan_cache_query_async") + + self.swiftscan_cached_compilation_get_num_outputs = try loadOptional("swiftscan_cached_compilation_get_num_outputs") + self.swiftscan_cached_compilation_get_output = try loadOptional("swiftscan_cached_compilation_get_output") + self.swiftscan_cached_compilation_make_global_async = try loadOptional("swiftscan_cached_compilation_make_global_async") + self.swiftscan_cached_compilation_is_uncacheable = try loadOptional("swiftscan_cached_compilation_is_uncacheable") + self.swiftscan_cached_compilation_dispose = try loadOptional("swiftscan_cached_compilation_dispose") + + self.swiftscan_cached_output_load = try loadOptional("swiftscan_cached_output_load") + self.swiftscan_cached_output_load_async = try loadOptional("swiftscan_cached_output_load_async") + self.swiftscan_cached_output_is_materialized = try loadOptional("swiftscan_cached_output_is_materialized") + self.swiftscan_cached_output_get_casid = try loadOptional("swiftscan_cached_output_get_casid") + self.swiftscan_cached_output_get_name = try loadOptional("swiftscan_cached_output_get_name") + self.swiftscan_cached_output_dispose = try loadOptional("swiftscan_cached_output_dispose") + + self.swiftscan_cache_action_cancel = try loadOptional("swiftscan_cache_action_cancel") + self.swiftscan_cache_cancellation_token_dispose = try loadOptional("swiftscan_cache_cancellation_token_dispose") + + self.swiftscan_cache_download_cas_object_async = try loadOptional("swiftscan_cache_download_cas_object_async") + + self.swiftscan_cache_replay_instance_create = try loadOptional("swiftscan_cache_replay_instance_create") + self.swiftscan_cache_replay_instance_dispose = try loadOptional("swiftscan_cache_replay_instance_dispose") + self.swiftscan_cache_replay_compilation = try loadOptional("swiftscan_cache_replay_compilation") + + self.swiftscan_cache_replay_result_get_stdout = try loadOptional("swiftscan_cache_replay_result_get_stdout") + self.swiftscan_cache_replay_result_get_stderr = try loadOptional("swiftscan_cache_replay_result_get_stderr") + self.swiftscan_cache_replay_result_dispose = try loadOptional("swiftscan_cache_replay_result_dispose") + + self.swiftscan_diagnostic_get_source_location = try loadOptional("swiftscan_diagnostic_get_source_location") + self.swiftscan_source_location_get_buffer_identifier = try loadOptional("swiftscan_source_location_get_buffer_identifier") + self.swiftscan_source_location_get_line_number = try loadOptional("swiftscan_source_location_get_line_number") + self.swiftscan_source_location_get_column_number = try loadOptional("swiftscan_source_location_get_column_number") + + self.swiftscan_module_info_get_link_libraries = try loadOptional("swiftscan_module_info_get_link_libraries") + self.swiftscan_link_library_info_get_link_name = try loadOptional("swiftscan_link_library_info_get_link_name") + self.swiftscan_link_library_info_get_is_framework = try loadOptional("swiftscan_link_library_info_get_is_framework") + self.swiftscan_link_library_info_get_should_force_load = try loadOptional("swiftscan_link_library_info_get_should_force_load") // Swift Overlay Dependencies self.swiftscan_swift_textual_detail_get_swift_overlay_dependencies = - loadOptional("swiftscan_swift_textual_detail_get_swift_overlay_dependencies") + try loadOptional("swiftscan_swift_textual_detail_get_swift_overlay_dependencies") // Header dependencies of binary modules self.swiftscan_swift_binary_detail_get_header_dependencies = - loadOptional("swiftscan_swift_binary_detail_get_header_dependencies") + try loadOptional("swiftscan_swift_binary_detail_get_header_dependencies") self.swiftscan_swift_binary_detail_get_header_dependency = - loadOptional("swiftscan_swift_binary_detail_get_header_dependency") + try loadOptional("swiftscan_swift_binary_detail_get_header_dependency") // Per-scan-query diagnostic output self.swiftscan_dependency_graph_get_diagnostics = - loadOptional("swiftscan_dependency_graph_get_diagnostics") + try loadOptional("swiftscan_dependency_graph_get_diagnostics") self.swiftscan_import_set_get_diagnostics = - loadOptional("swiftscan_import_set_get_diagnostics") + try loadOptional("swiftscan_import_set_get_diagnostics") // MARK: Required Methods func loadRequired(_ symbol: String) throws -> T { diff --git a/Sources/SwiftDriver/ToolingInterface/ToolingUtil.swift b/Sources/SwiftDriver/ToolingInterface/ToolingUtil.swift index 680c14cc7..3459ddbba 100644 --- a/Sources/SwiftDriver/ToolingInterface/ToolingUtil.swift +++ b/Sources/SwiftDriver/ToolingInterface/ToolingUtil.swift @@ -35,20 +35,6 @@ public func getSingleFrontendInvocationFromDriverArgumentsV2(driverPath: UnsafeP action: @convention(c) (CInt, UnsafePointer?>) -> Bool, diagnosticCallback: @convention(c) (CInt, UnsafePointer) -> Void, forceNoOutputs: Bool = false) -> Bool { - return getSingleFrontendInvocationFromDriverArgumentsV3(driverPath: driverPath, argListCount: argListCount, - argList: argList, action: action, - diagnosticCallback: diagnosticCallback, - compilerIntegratedTooling: true) -} - -@_cdecl("swift_getSingleFrontendInvocationFromDriverArgumentsV3") -public func getSingleFrontendInvocationFromDriverArgumentsV3(driverPath: UnsafePointer, - argListCount: CInt, - argList: UnsafePointer?>, - action: @convention(c) (CInt, UnsafePointer?>) -> Bool, - diagnosticCallback: @convention(c) (CInt, UnsafePointer) -> Void, - compilerIntegratedTooling: Bool = false, - forceNoOutputs: Bool = false) -> Bool { // Bridge the driver path argument let bridgedDriverPath = String(cString: driverPath) @@ -74,7 +60,6 @@ public func getSingleFrontendInvocationFromDriverArgumentsV3(driverPath: UnsafeP action: bridgedAction, diagnostics: &diagnostics, diagnosticCallback: bridgedDiagnosticCallback, - compilerIntegratedTooling: compilerIntegratedTooling, forceNoOutputs: forceNoOutputs) return result } @@ -87,8 +72,6 @@ public func getSingleFrontendInvocationFromDriverArgumentsV3(driverPath: UnsafeP /// \param argList The driver arguments (i.e. normal arguments for \c swiftc). /// \param diagnostics Contains the diagnostics emitted by the driver /// \param action invokes a user-provided action on the resulting frontend invocation command -/// \param compilerIntegratedTooling If true, this code is executed in the context of a -/// Swift compiler image which contains symbols normally queried from a libSwiftScan instance. /// \param forceNoOutputs If true, override the output mode to "-typecheck" and /// produce no outputs. For example, this disables "-emit-module" and "-c" and /// prevents the creation of temporary files. @@ -102,7 +85,6 @@ public func getSingleFrontendInvocationFromDriverArgumentsV2(driverPath: String, action: ([String]) -> Bool, diagnostics: inout [Diagnostic], diagnosticCallback: @escaping (CInt, String) -> Void, - compilerIntegratedTooling: Bool = false, forceNoOutputs: Bool = false) -> Bool { /// Handler for emitting diagnostics to tooling clients. let toolingDiagnosticsHandler: DiagnosticsEngine.DiagnosticsHandler = { diagnostic in @@ -166,8 +148,7 @@ public func getSingleFrontendInvocationFromDriverArgumentsV2(driverPath: String, env: ProcessEnv.vars) var driver = try Driver(args: parsedOptions.commandLine, diagnosticsOutput: .engine(diagnosticsEngine), - executor: executor, - compilerIntegratedTooling: compilerIntegratedTooling) + executor: executor) if diagnosticsEngine.hasErrors { return true } diff --git a/Tests/SwiftDriverTests/CachingBuildTests.swift b/Tests/SwiftDriverTests/CachingBuildTests.swift index 936b563d1..67ec92755 100644 --- a/Tests/SwiftDriverTests/CachingBuildTests.swift +++ b/Tests/SwiftDriverTests/CachingBuildTests.swift @@ -389,7 +389,8 @@ final class CachingBuildTests: XCTestCase { XCTAssertFalse(driver.diagnosticEngine.hasErrors) let scanLibPath = try XCTUnwrap(driver.getSwiftScanLibPath()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) let cas = try dependencyOracle.getOrCreateCAS(pluginPath: nil, onDiskPath: casPath, pluginOptions: []) if let driverCAS = driver.cas { @@ -444,7 +445,8 @@ final class CachingBuildTests: XCTestCase { XCTAssertFalse(driver.diagnosticEngine.hasErrors) let scanLibPath = try XCTUnwrap(driver.getSwiftScanLibPath()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) let cas = try dependencyOracle.getOrCreateCAS(pluginPath: nil, onDiskPath: casPath, pluginOptions: []) if let driverCAS = driver.cas { @@ -628,7 +630,8 @@ final class CachingBuildTests: XCTestCase { XCTAssertFalse(driver.diagnosticEngine.hasErrors) let scanLibPath = try XCTUnwrap(driver.getSwiftScanLibPath()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) let cas = try dependencyOracle.getOrCreateCAS(pluginPath: nil, onDiskPath: casPath, pluginOptions: []) if let driverCAS = driver.cas { @@ -682,7 +685,8 @@ final class CachingBuildTests: XCTestCase { interModuleDependencyOracle: dependencyOracle) let scanLibPath = try XCTUnwrap(fooBuildDriver.getSwiftScanLibPath()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) guard try dependencyOracle.supportsBinaryModuleHeaderDependencies() else { throw XCTSkip("libSwiftScan does not support binary module header dependencies.") } @@ -749,7 +753,8 @@ final class CachingBuildTests: XCTestCase { env: ProcessEnv.vars, interModuleDependencyOracle: dependencyOracle) let scanLibPath = try XCTUnwrap(driver.getSwiftScanLibPath()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + 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 @@ -900,7 +905,8 @@ final class CachingBuildTests: XCTestCase { throw XCTSkip("frontend doesn't support prefix map") } let scanLibPath = try XCTUnwrap(driver.getSwiftScanLibPath()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) let resolver = try ArgsResolver(fileSystem: localFileSystem) let scannerCommand = try driver.dependencyScannerInvocationCommand().1.map { try resolver.resolve($0) } @@ -966,7 +972,8 @@ final class CachingBuildTests: XCTestCase { XCTAssertFalse(driver.diagnosticEngine.hasErrors) let scanLibPath = try XCTUnwrap(driver.getSwiftScanLibPath()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) let cas = try dependencyOracle.getOrCreateCAS(pluginPath: nil, onDiskPath: casPath, pluginOptions: []) if let driverCAS = driver.cas { @@ -994,7 +1001,8 @@ final class CachingBuildTests: XCTestCase { let casPath = path.appending(component: "cas") let driver = try Driver(args: ["swiftc", "-v"]) let scanLibPath = try XCTUnwrap(driver.getSwiftScanLibPath()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) let cas = try dependencyOracle.getOrCreateCAS(pluginPath: nil, onDiskPath: casPath, pluginOptions: []) guard cas.supportsSizeManagement else { throw XCTSkip("CAS size management is not supported") diff --git a/Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift b/Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift index 9b2cc3250..73666ffa1 100644 --- a/Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift +++ b/Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift @@ -426,7 +426,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()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) guard try dependencyOracle.supportsLinkLibraries() else { throw XCTSkip("libSwiftScan does not support link library reporting.") } @@ -1194,7 +1195,8 @@ final class ExplicitModuleBuildTests: XCTestCase { // queries. let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) try withTemporaryDirectory { path in let main = path.appending(component: "foo.swift") @@ -1370,7 +1372,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()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) guard try dependencyOracle.supportsBinaryFrameworkDependencies() else { throw XCTSkip("libSwiftScan does not support framework binary dependency reporting.") } @@ -1414,7 +1417,8 @@ final class ExplicitModuleBuildTests: XCTestCase { // queries. let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) // Create a simple test case. try withTemporaryDirectory { path in @@ -1519,7 +1523,8 @@ final class ExplicitModuleBuildTests: XCTestCase { // queries. let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) guard try dependencyOracle.supportsScannerDiagnostics() else { throw XCTSkip("libSwiftScan does not support diagnostics query.") } @@ -1680,7 +1685,8 @@ final class ExplicitModuleBuildTests: XCTestCase { // queries. let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) // Create a simple test case. try withTemporaryDirectory { path in @@ -1858,7 +1864,8 @@ final class ExplicitModuleBuildTests: XCTestCase { // queries. let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) if !(try dependencyOracle.supportsPerScanDiagnostics()) { throw XCTSkip("Scanner does not support per-scan diagnostics") } @@ -2048,7 +2055,8 @@ final class ExplicitModuleBuildTests: XCTestCase { let (stdlibPath, shimsPath, toolchain, _) = try getDriverArtifactsForScanning() let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) - try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) // Create a simple test case. try withTemporaryDirectory { path in let main = path.appending(component: "testDependencyScanning.swift") @@ -2149,7 +2157,8 @@ final class ExplicitModuleBuildTests: XCTestCase { let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) // Run the first scan and serialize the cache contents. let firstDependencyOracle = InterModuleDependencyOracle() - try firstDependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try firstDependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) var firstScanDiagnostics: [ScannerDiagnosticPayload] = [] let firstScanGraph = try firstDependencyOracle.getDependencies(workingDirectory: path, @@ -2159,7 +2168,8 @@ final class ExplicitModuleBuildTests: XCTestCase { // Run the second scan, re-using the serialized cache contents. let secondDependencyOracle = InterModuleDependencyOracle() - try secondDependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath) + try secondDependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) XCTAssertFalse(secondDependencyOracle.loadScannerCache(from: cacheSavePath)) var secondScanDiagnostics: [ScannerDiagnosticPayload] = [] let secondScanGraph = diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index 86fa58739..cea18772e 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -5419,11 +5419,9 @@ final class SwiftDriverTests: XCTestCase { if localFileSystem.exists(swiftScanLibPath) { let libSwiftScanInstance = try SwiftScan(dylib: swiftScanLibPath) if libSwiftScanInstance.canQueryTargetInfo() { - let _ = try Driver.queryTargetInfoInProcess(libSwiftScanInstance: libSwiftScanInstance, - toolchain: driver.toolchain, - fileSystem: localFileSystem, - workingDirectory: localFileSystem.currentWorkingDirectory, - invocationCommand: printTargetInfoCommand) + XCTAssertTrue(try driver.verifyBeingAbleToQueryTargetInfoInProcess(workingDirectory: localFileSystem.currentWorkingDirectory, + invocationCommand: printTargetInfoCommand, + expectedSDKPath: "/bar")) } } } @@ -5441,11 +5439,9 @@ final class SwiftDriverTests: XCTestCase { if localFileSystem.exists(swiftScanLibPath) { let libSwiftScanInstance = try SwiftScan(dylib: swiftScanLibPath) if libSwiftScanInstance.canQueryTargetInfo() { - let _ = try Driver.queryTargetInfoInProcess(libSwiftScanInstance: libSwiftScanInstance, - toolchain: driver.toolchain, - fileSystem: localFileSystem, - workingDirectory: localFileSystem.currentWorkingDirectory, - invocationCommand: printTargetInfoCommand) + XCTAssertTrue(try driver.verifyBeingAbleToQueryTargetInfoInProcess(workingDirectory: localFileSystem.currentWorkingDirectory, + invocationCommand: printTargetInfoCommand, + expectedSDKPath: "/tmp/foo bar")) } } } @@ -5479,9 +5475,9 @@ final class SwiftDriverTests: XCTestCase { env: hideSwiftScanEnv, executor: MockExecutor(resolver: ArgsResolver(fileSystem: InMemoryFileSystem())))) { error in - if case .decodingError = error as? JobExecutionError {} + if case .unableToDecodeFrontendTargetInfo = error as? Driver.Error {} else { - XCTFail("not a decoding error: \(error)") + XCTFail("not a decoding error") } } } @@ -5490,9 +5486,15 @@ final class SwiftDriverTests: XCTestCase { XCTAssertThrowsError(try Driver(args: ["swift", "-print-target-info"], env: ["SWIFT_DRIVER_SWIFT_FRONTEND_EXEC": "/bad/path/to/swift-frontend"])) { error in - if case .posix_spawn = error as? TSCBasic.SystemError {} - else { - XCTFail("unexpected error: \(error)") + XCTAssertTrue(error is Driver.Error) + + switch error { + case Driver.Error.failedToRetrieveFrontendTargetInfo, + Driver.Error.failedToRunFrontendToRetrieveTargetInfo: + break; + + default: + XCTFail("unexpected error \(error)") } } } diff --git a/Tests/TestUtilities/DriverExtensions.swift b/Tests/TestUtilities/DriverExtensions.swift index 756353420..81de3fbb2 100644 --- a/Tests/TestUtilities/DriverExtensions.swift +++ b/Tests/TestUtilities/DriverExtensions.swift @@ -44,6 +44,27 @@ extension Driver { public static func sdkArgumentsForTesting() throws -> [String]? { try cachedSDKPath.map {["-sdk", try $0.get()]} } + + + public func verifyBeingAbleToQueryTargetInfoInProcess(workingDirectory: AbsolutePath?, + invocationCommand: [String], + expectedSDKPath: String) throws -> Bool { + guard let targetInfo = try Self.queryTargetInfoInProcess(of: toolchain, + fileSystem: fileSystem, + workingDirectory: workingDirectory, + invocationCommand: invocationCommand) else { + return false + } + + guard let sdkPath = targetInfo.sdkPath else { + return false + } + + if sdkPath.path.description != expectedSDKPath { + return false + } + return true + } } /// Set to nil if cannot perform on this host diff --git a/Tests/ToolingTestShim/CToolingTestShimImpl.c b/Tests/ToolingTestShim/CToolingTestShimImpl.c index 9dd8c2f60..0ca224604 100644 --- a/Tests/ToolingTestShim/CToolingTestShimImpl.c +++ b/Tests/ToolingTestShim/CToolingTestShimImpl.c @@ -1,7 +1,7 @@ #include "include/tooling_shim.h" -bool swift_getSingleFrontendInvocationFromDriverArgumentsV3(const char *, int, const char**, bool(int, const char**), - void(swiftdriver_tooling_diagnostic_kind, const char*), bool, bool); +bool swift_getSingleFrontendInvocationFromDriverArgumentsV2(const char *, int, const char**, bool(int, const char**), + void(swiftdriver_tooling_diagnostic_kind, const char*), bool); bool getSingleFrontendInvocationFromDriverArgumentsTest(const char *driverPath, int argListCount, const char** argList, @@ -9,6 +9,6 @@ bool getSingleFrontendInvocationFromDriverArgumentsTest(const char *driverPath, void diagnosticCallback(swiftdriver_tooling_diagnostic_kind diagnosticKind, const char* message), bool forceNoOutputs) { - return swift_getSingleFrontendInvocationFromDriverArgumentsV3(driverPath, argListCount, argList, - action, diagnosticCallback, false, forceNoOutputs); + return swift_getSingleFrontendInvocationFromDriverArgumentsV2(driverPath, argListCount, argList, + action, diagnosticCallback, forceNoOutputs); }