From 34ff1f6d6f7969b9c232b4e158d8ed58e97981eb Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Tue, 14 Nov 2023 16:59:29 -0800 Subject: [PATCH] Revert "[SwiftDriver] PathRemapping and Cache Replay Support" --- README.md | 2 +- Sources/CSwiftScan/include/swiftscan_header.h | 88 +---- Sources/SwiftDriver/CMakeLists.txt | 1 - Sources/SwiftDriver/Driver/Driver.swift | 78 +---- .../SwiftDriver/Execution/ArgsResolver.swift | 6 +- .../ExplicitDependencyBuildPlanner.swift | 51 ++- .../InterModuleDependencyOracle.swift | 27 +- .../ModuleDependencyScanning.swift | 17 +- Sources/SwiftDriver/Jobs/CompileJob.swift | 34 +- .../SwiftDriver/Jobs/FrontendJobHelpers.swift | 188 ++-------- Sources/SwiftDriver/Jobs/GeneratePCHJob.swift | 8 +- Sources/SwiftDriver/Jobs/GeneratePCMJob.swift | 4 +- Sources/SwiftDriver/Jobs/Job.swift | 20 -- Sources/SwiftDriver/Jobs/Planning.swift | 4 +- .../Jobs/VerifyModuleInterfaceJob.swift | 20 +- Sources/SwiftDriver/SwiftScan/SwiftScan.swift | 116 ++++--- .../SwiftDriver/SwiftScan/SwiftScanCAS.swift | 322 ------------------ Sources/SwiftDriver/Utilities/FileType.swift | 53 +-- .../SwiftDriver/Utilities/VirtualPath.swift | 9 +- Sources/SwiftOptions/Options.swift | 12 +- .../SwiftDriverTests/CachingBuildTests.swift | 176 +++------- 21 files changed, 258 insertions(+), 978 deletions(-) delete mode 100644 Sources/SwiftDriver/SwiftScan/SwiftScanCAS.swift diff --git a/README.md b/README.md index bd35ddb05..5d0c6edc4 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ $ apt-get install libncurses-dev be found, e.g.: ``` -$ swift build -Xcc -I/path/to/build/Ninja-Release/swift-.../include -Xcc -I/path/to/build/Ninja-Release/llvm-.../include -Xcc -I/path/to/source/llvm-project/llvm/include --product makeOptions +$ swift build -Xcc -Xcc -I/path/to/build/Ninja-Release/swift-.../include -Xcc -I/path/to/build/Ninja-Release/llvm-.../include -Xcc -I/path/to/source/llvm-project/llvm/include --product makeOptions ``` Then, run `makeOptions` and redirect the output to overwrite `Options.swift`: diff --git a/Sources/CSwiftScan/include/swiftscan_header.h b/Sources/CSwiftScan/include/swiftscan_header.h index 63bf16913..79ea98bd4 100644 --- a/Sources/CSwiftScan/include/swiftscan_header.h +++ b/Sources/CSwiftScan/include/swiftscan_header.h @@ -18,7 +18,7 @@ #include #define SWIFTSCAN_VERSION_MAJOR 0 -#define SWIFTSCAN_VERSION_MINOR 6 +#define SWIFTSCAN_VERSION_MINOR 5 //=== Public Scanner Data Types -------------------------------------------===// @@ -78,15 +78,17 @@ typedef struct swiftscan_scan_invocation_s *swiftscan_scan_invocation_t; typedef void *swiftscan_scanner_t; //=== CAS/Caching Specification -------------------------------------------===// -typedef struct swiftscan_cas_options_s *swiftscan_cas_options_t; typedef struct swiftscan_cas_s *swiftscan_cas_t; -typedef struct swiftscan_cached_compilation_s *swiftscan_cached_compilation_t; -typedef struct swiftscan_cached_output_s *swiftscan_cached_output_t; -typedef struct swiftscan_cache_replay_instance_s - *swiftscan_cache_replay_instance_t; -typedef struct swiftscan_cache_replay_result_s *swiftscan_cache_replay_result_t; -typedef struct swiftscan_cache_cancellation_token_s - *swiftscan_cache_cancellation_token_t; +typedef struct swiftscan_cas_options_s *swiftscan_cas_options_t; + +typedef enum { + SWIFTSCAN_OUTPUT_TYPE_OBJECT = 0, + SWIFTSCAN_OUTPUT_TYPE_SWIFTMODULE = 1, + SWIFTSCAN_OUTPUT_TYPE_SWIFTINTERFACE = 2, + SWIFTSCAN_OUTPUT_TYPE_SWIFTPRIVATEINTERFACE = 3, + SWIFTSCAN_OUTPUT_TYPE_CLANG_MODULE = 4, + SWIFTSCAN_OUTPUT_TYPE_CLANG_PCH = 5 +} swiftscan_output_kind_t; //=== libSwiftScan Functions ------------------------------------------------===// @@ -279,74 +281,18 @@ typedef struct { const char *path); void (*swiftscan_cas_options_set_plugin_path)(swiftscan_cas_options_t options, const char *path); - bool (*swiftscan_cas_options_set_plugin_option)( - swiftscan_cas_options_t options, const char *name, const char *value, - swiftscan_string_ref_t *error); + bool (*swiftscan_cas_options_set_option)(swiftscan_cas_options_t options, + const char *name, const char *value, + swiftscan_string_ref_t *error); swiftscan_cas_t (*swiftscan_cas_create_from_options)( swiftscan_cas_options_t options, swiftscan_string_ref_t *error); void (*swiftscan_cas_dispose)(swiftscan_cas_t cas); swiftscan_string_ref_t (*swiftscan_cas_store)(swiftscan_cas_t cas, uint8_t *data, unsigned size, swiftscan_string_ref_t *error); - swiftscan_string_ref_t (*swiftscan_cache_compute_key)( - swiftscan_cas_t cas, int argc, const char **argv, const char *input, - swiftscan_string_ref_t *error); - - //=== Scanner Caching Query/Replay Operations -----------------------------===// - swiftscan_cached_compilation_t (*swiftscan_cache_query)( - swiftscan_cas_t cas, const char *key, bool globally, - swiftscan_string_ref_t *error); - void (*swiftscan_cache_query_async)( - swiftscan_cas_t cas, const char *key, bool globally, void *ctx, - void (*callback)(void *ctx, swiftscan_cached_compilation_t, - swiftscan_string_ref_t error), - swiftscan_cache_cancellation_token_t *); - - - unsigned (*swiftscan_cached_compilation_get_num_outputs)( - swiftscan_cached_compilation_t); - swiftscan_cached_output_t (*swiftscan_cached_compilation_get_output)( - swiftscan_cached_compilation_t, unsigned idx); - bool (*swiftscan_cached_compilation_is_uncacheable)( - swiftscan_cached_compilation_t); - void (*swiftscan_cached_compilation_make_global_async)( - swiftscan_cached_compilation_t, void *ctx, - void (*callback)(void *ctx, swiftscan_string_ref_t error), - swiftscan_cache_cancellation_token_t *); - void (*swiftscan_cached_compilation_dispose)(swiftscan_cached_compilation_t); - - bool (*swiftscan_cached_output_load)(swiftscan_cached_output_t, - swiftscan_string_ref_t *error); - void (*swiftscan_cached_output_load_async)( - swiftscan_cached_output_t, void *ctx, - void (*callback)(void *ctx, bool success, swiftscan_string_ref_t error), - swiftscan_cache_cancellation_token_t *); - bool (*swiftscan_cached_output_is_materialized)(swiftscan_cached_output_t); - swiftscan_string_ref_t (*swiftscan_cached_output_get_casid)( - swiftscan_cached_output_t); - swiftscan_string_ref_t (*swiftscan_cached_output_get_name)( - swiftscan_cached_output_t); - void (*swiftscan_cached_output_dispose)(swiftscan_cached_output_t); - - void (*swiftscan_cache_action_cancel)(swiftscan_cache_cancellation_token_t); - void (*swiftscan_cache_cancellation_token_dispose)( - swiftscan_cache_cancellation_token_t); - - swiftscan_cache_replay_instance_t (*swiftscan_cache_replay_instance_create)( - int argc, const char **argv, swiftscan_string_ref_t *error); - void (*swiftscan_cache_replay_instance_dispose)( - swiftscan_cache_replay_instance_t); - - swiftscan_cache_replay_result_t (*swiftscan_cache_replay_compilation)( - swiftscan_cache_replay_instance_t, swiftscan_cached_compilation_t, - swiftscan_string_ref_t *error); - - swiftscan_string_ref_t (*swiftscan_cache_replay_result_get_stdout)( - swiftscan_cache_replay_result_t); - swiftscan_string_ref_t (*swiftscan_cache_replay_result_get_stderr)( - swiftscan_cache_replay_result_t); - void (*swiftscan_cache_replay_result_dispose)( - swiftscan_cache_replay_result_t); + swiftscan_string_ref_t (*swiftscan_compute_cache_key)( + swiftscan_cas_t cas, int argc, const char *argv, const char *input, + swiftscan_output_kind_t, swiftscan_string_ref_t *error); } swiftscan_functions_t; diff --git a/Sources/SwiftDriver/CMakeLists.txt b/Sources/SwiftDriver/CMakeLists.txt index 2f9ad8344..d7785e768 100644 --- a/Sources/SwiftDriver/CMakeLists.txt +++ b/Sources/SwiftDriver/CMakeLists.txt @@ -18,7 +18,6 @@ add_library(SwiftDriver SwiftScan/DependencyGraphBuilder.swift SwiftScan/Loader.swift SwiftScan/SwiftScan.swift - SwiftScan/SwiftScanCAS.swift Driver/CompilerMode.swift Driver/DebugInfo.swift diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index e6a5eee6e..d0eee5354 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -224,10 +224,8 @@ public struct Driver { /// Should use file lists for inputs (number of inputs exceeds `fileListThreshold`). let shouldUseInputFileList: Bool - /// VirtualPath for shared all sources file list. `nil` if unused. This is used as a cache for - /// the file list computed during CompileJob creation and only holds valid to be query by tests - /// after planning to build. - @_spi(Testing) public var allSourcesFileList: VirtualPath? = nil + /// VirtualPath for shared all sources file list. `nil` if unused. + @_spi(Testing) public let allSourcesFileList: VirtualPath? /// The mode in which the compiler will execute. @_spi(Testing) public let compilerMode: CompilerMode @@ -274,43 +272,6 @@ public struct Driver { let enableCaching: Bool let useClangIncludeTree: Bool - /// CAS instance used for compilation. - public var cas: SwiftScanCAS? = nil - - /// Is swift caching enabled. - lazy var isCachingEnabled: Bool = { - return enableCaching && isFeatureSupported(.cache_compile_job) - }() - - /// Scanner prefix mapping. - let scannerPrefixMap: [AbsolutePath: AbsolutePath] - let scannerPrefixMapSDK: AbsolutePath? - let scannerPrefixMapToolchain: AbsolutePath? - lazy var prefixMapping: [(AbsolutePath, AbsolutePath)] = { - var mapping: [(AbsolutePath, AbsolutePath)] = scannerPrefixMap.map { - return ($0.key, $0.value) - } - do { - guard isFrontendArgSupported(.scannerPrefixMap) else { - return [] - } - if let sdkMapping = scannerPrefixMapSDK, - let sdkPath = absoluteSDKPath { - mapping.append((sdkPath, sdkMapping)) - } - if let toolchainMapping = scannerPrefixMapToolchain { - let toolchainPath = try toolchain.executableDir.parentDirectory // usr - .parentDirectory // toolchain - mapping.append((toolchainPath, toolchainMapping)) - } - // The mapping needs to be sorted so the mapping is determinisitic. - // The sorting order is reversed so /tmp/tmp is preferred over /tmp in remapping. - return mapping.sorted { $0.0 > $1.0 } - } catch { - return mapping.sorted { $0.0 > $1.0 } - } - }() - /// Code & data for incremental compilation. Nil if not running in incremental mode. /// Set during planning because needs the jobs to look at outputs. @_spi(Testing) public private(set) var incrementalCompilationState: IncrementalCompilationState? = nil @@ -424,7 +385,6 @@ public struct Driver { @_spi(Testing) public enum KnownCompilerFeature: String { case emit_abi_descriptor = "emit-abi-descriptor" - case cache_compile_job = "cache-compile-job" } lazy var sdkPath: VirtualPath? = { @@ -637,18 +597,7 @@ public struct Driver { let cachingEnableOverride = parsedOptions.hasArgument(.driverExplicitModuleBuild) && env.keys.contains("SWIFT_ENABLE_CACHING") self.enableCaching = parsedOptions.hasArgument(.cacheCompileJob) || cachingEnableOverride - self.useClangIncludeTree = !parsedOptions.hasArgument(.noClangIncludeTree) && !env.keys.contains("SWIFT_CACHING_USE_CLANG_CAS_FS") - self.scannerPrefixMap = try Self.computeScanningPrefixMapper(&parsedOptions) - if let sdkMapping = parsedOptions.getLastArgument(.scannerPrefixMapSdk)?.asSingle { - self.scannerPrefixMapSDK = try AbsolutePath(validating: sdkMapping) - } else { - self.scannerPrefixMapSDK = nil - } - if let toolchainMapping = parsedOptions.getLastArgument(.scannerPrefixMapToolchain)?.asSingle { - self.scannerPrefixMapToolchain = try AbsolutePath(validating: toolchainMapping) - } else { - self.scannerPrefixMapToolchain = nil - } + self.useClangIncludeTree = enableCaching && env.keys.contains("SWIFT_CACHING_USE_INCLUDE_TREE") // Compute the working directory. workingDirectory = try parsedOptions.getLastArgument(.workingDirectory).map { workingDirectoryArg in @@ -729,6 +678,13 @@ public struct Driver { self.fileListThreshold = try Self.computeFileListThreshold(&self.parsedOptions, diagnosticsEngine: diagnosticsEngine) self.shouldUseInputFileList = inputFiles.count > fileListThreshold + if shouldUseInputFileList { + let swiftInputs = inputFiles.filter(\.type.isPartOfSwiftCompilation) + self.allSourcesFileList = try VirtualPath.createUniqueFilelist(RelativePath(validating: "sources"), + .list(swiftInputs.map(\.file))) + } else { + self.allSourcesFileList = nil + } self.lto = Self.ltoKind(&parsedOptions, diagnosticsEngine: diagnosticsEngine) // Figure out the primary outputs from the driver. @@ -3568,18 +3524,4 @@ extension Driver { } return options } - - static func computeScanningPrefixMapper(_ parsedOptions: inout ParsedOptions) throws -> [AbsolutePath: AbsolutePath] { - var mapping: [AbsolutePath: AbsolutePath] = [:] - for opt in parsedOptions.arguments(for: .scannerPrefixMap) { - let pluginArg = opt.argument.asSingle.split(separator: "=", maxSplits: 1) - if pluginArg.count != 2 { - throw Error.invalidArgumentValue(Option.scannerPrefixMap.spelling, opt.argument.asSingle) - } - let key = try AbsolutePath(validating: String(pluginArg[0])) - let value = try AbsolutePath(validating: String(pluginArg[1])) - mapping[key] = value - } - return mapping - } } diff --git a/Sources/SwiftDriver/Execution/ArgsResolver.swift b/Sources/SwiftDriver/Execution/ArgsResolver.swift index 6c8e73fbb..79f9ff88d 100644 --- a/Sources/SwiftDriver/Execution/ArgsResolver.swift +++ b/Sources/SwiftDriver/Execution/ArgsResolver.swift @@ -65,16 +65,12 @@ public final class ArgsResolver { public func resolveArgumentList(for job: Job, useResponseFiles: ResponseFileHandling = .heuristic) throws -> ([String], usingResponseFile: Bool) { let tool = try resolve(.path(job.tool)) - var arguments = [tool] + (try resolveArgumentList(for: job.commandLine)) + var arguments = [tool] + (try job.commandLine.map { try resolve($0) }) let usingResponseFile = try createResponseFileIfNeeded(for: job, resolvedArguments: &arguments, useResponseFiles: useResponseFiles) return (arguments, usingResponseFile) } - public func resolveArgumentList(for commandLine: [Job.ArgTemplate]) throws -> [String] { - return try commandLine.map { try resolve($0) } - } - @available(*, deprecated, message: "use resolveArgumentList(for:,useResponseFiles:,quotePaths:)") public func resolveArgumentList(for job: Job, forceResponseFiles: Bool, quotePaths: Bool = false) throws -> [String] { diff --git a/Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift b/Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift index b54371946..1e1728289 100644 --- a/Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift +++ b/Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift @@ -45,7 +45,7 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT /// Whether we are using the integrated driver via libSwiftDriver shared lib private let integratedDriver: Bool private let mainModuleName: String? - private let cas: SwiftScanCAS? + private let enableCAS: Bool private let swiftScanOracle: InterModuleDependencyOracle /// Clang PCM names contain a hash of the command-line arguments that were used to build them. @@ -60,7 +60,7 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT dependencyOracle: InterModuleDependencyOracle, integratedDriver: Bool = true, supportsExplicitInterfaceBuild: Bool = false, - cas: SwiftScanCAS? = nil) throws { + enableCAS: Bool = false) throws { self.dependencyGraph = dependencyGraph self.toolchain = toolchain self.swiftScanOracle = dependencyOracle @@ -68,7 +68,7 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT self.mainModuleName = dependencyGraph.mainModuleName self.reachabilityMap = try dependencyGraph.computeTransitiveClosure() self.supportsExplicitInterfaceBuild = supportsExplicitInterfaceBuild - self.cas = cas + self.enableCAS = enableCAS } /// Supports resolving bridging header pch command from swiftScan. @@ -136,6 +136,9 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT for moduleId in swiftDependencies { let moduleInfo = try dependencyGraph.moduleInfo(of: moduleId) var inputs: [TypedVirtualPath] = [] + let outputs: [TypedVirtualPath] = [ + TypedVirtualPath(file: moduleInfo.modulePath.path, type: .swiftModule) + ] var commandLine: [Job.ArgTemplate] = [] // First, take the command line options provided in the dependency information let moduleDetails = try dependencyGraph.swiftModuleDetails(of: moduleId) @@ -152,18 +155,9 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT throw Driver.Error.malformedModuleDependency(moduleId.moduleName, "no `moduleInterfacePath` object") } + inputs.append(TypedVirtualPath(file: moduleInterfacePath.path, + type: .swiftInterface)) - let inputInterfacePath = TypedVirtualPath(file: moduleInterfacePath.path, type: .swiftInterface) - inputs.append(inputInterfacePath) - let outputModulePath = TypedVirtualPath(file: moduleInfo.modulePath.path, type: .swiftModule) - let outputs = [outputModulePath] - - let cacheKeys : [TypedVirtualPath : String] - if let key = moduleDetails.moduleCacheKey { - cacheKeys = [inputInterfacePath: key] - } else { - cacheKeys = [:] - } // Add precompiled module candidates, if present if let compiledCandidateList = moduleDetails.compiledModuleCandidates { for compiledCandidate in compiledCandidateList { @@ -179,8 +173,7 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT commandLine: commandLine, inputs: inputs, primaryInputs: [], - outputs: outputs, - outputCacheKeys: cacheKeys + outputs: outputs )) } return jobs @@ -212,20 +205,15 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT try resolveExplicitModuleDependencies(moduleId: moduleId, inputs: &inputs, commandLine: &commandLine) - let moduleMapPath = TypedVirtualPath(file: moduleDetails.moduleMapPath.path, type: .clangModuleMap) - let modulePCMPath = TypedVirtualPath(file: moduleInfo.modulePath.path, type: .pcm) - outputs.append(modulePCMPath) + let moduleMapPath = moduleDetails.moduleMapPath.path + let modulePCMPath = moduleInfo.modulePath + outputs.append(TypedVirtualPath(file: modulePCMPath.path, type: .pcm)) // The only required input is the .modulemap for this module. // Command line options in the dependency scanner output will include the // required modulemap, so here we must only add it to the list of inputs. - inputs.append(moduleMapPath) - let cacheKeys : [TypedVirtualPath : String] - if let key = moduleDetails.moduleCacheKey { - cacheKeys = [moduleMapPath: key] - } else { - cacheKeys = [:] - } + inputs.append(TypedVirtualPath(file: moduleMapPath, + type: .clangModuleMap)) jobs.append(Job( moduleName: moduleId.moduleName, @@ -234,8 +222,7 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT commandLine: commandLine, inputs: inputs, primaryInputs: [], - outputs: outputs, - outputCacheKeys: cacheKeys + outputs: outputs )) } return jobs @@ -260,7 +247,7 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT type: .swiftModule)) let prebuiltHeaderDependencyPaths = dependencyModule.prebuiltHeaderDependencyPaths ?? [] - if cas != nil && !prebuiltHeaderDependencyPaths.isEmpty { + if enableCAS && !prebuiltHeaderDependencyPaths.isEmpty { throw Driver.Error.unsupportedConfigurationForCaching("module \(dependencyModule.moduleName) has prebuilt header dependency") } @@ -290,9 +277,9 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT try serializeModuleDependencies(for: moduleId, swiftDependencyArtifacts: swiftDependencyArtifacts, clangDependencyArtifacts: clangDependencyArtifacts) - if let cas = self.cas { + if enableCAS { // When using a CAS, write JSON into CAS and pass the ID on command-line. - let casID = try cas.store(data: dependencyFileContent) + let casID = try swiftScanOracle.store(data: dependencyFileContent) commandLine.appendFlag("-explicit-swift-module-map-file") commandLine.appendFlag(casID) } else { @@ -458,7 +445,7 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT return } - assert(cas == nil, "Caching build should always return command-line from scanner") + assert(!enableCAS, "Caching build should always return command-line from scanner") // Prohibit the frontend from implicitly building textual modules into binary modules. commandLine.appendFlags("-disable-implicit-swift-modules", "-Xcc", "-fno-implicit-modules", diff --git a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift index 046426e5a..6065ab71f 100644 --- a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift +++ b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift @@ -13,7 +13,6 @@ import protocol TSCBasic.FileSystem import struct TSCBasic.AbsolutePath import struct Foundation.Data -import var TSCBasic.localFileSystem import Dispatch @@ -146,6 +145,13 @@ public class InterModuleDependencyOracle { return swiftScan.supportsBinaryModuleHeaderDependencies } + @_spi(Testing) public func supportsCaching() throws -> Bool { + guard let swiftScan = swiftScanLibInstance else { + fatalError("Attempting to query supported scanner API with no scanner instance.") + } + return swiftScan.supportsCaching + } + @_spi(Testing) public func supportsBridgingHeaderPCHCommand() throws -> Bool { guard let swiftScan = swiftScanLibInstance else { fatalError("Attempting to query supported scanner API with no scanner instance.") @@ -165,11 +171,26 @@ public class InterModuleDependencyOracle { return diags.isEmpty ? nil : diags } - @_spi(Testing) public func createCAS(pluginPath: AbsolutePath?, onDiskPath: AbsolutePath?, pluginOptions: [(String, String)]) throws -> SwiftScanCAS { + public func createCAS(pluginPath: AbsolutePath?, onDiskPath: AbsolutePath?, pluginOptions: [(String, String)]) throws { + guard let swiftScan = swiftScanLibInstance else { + fatalError("Attempting to reset scanner cache with no scanner instance.") + } + try swiftScan.createCAS(pluginPath: pluginPath?.pathString, onDiskPath: onDiskPath?.pathString, pluginOptions: pluginOptions) + } + + public func store(data: Data) throws -> String { + guard let swiftScan = swiftScanLibInstance else { + fatalError("Attempting to reset scanner cache with no scanner instance.") + } + return try swiftScan.store(data:data) + } + + public func computeCacheKeyForOutput(kind: FileType, commandLine: [Job.ArgTemplate], input: VirtualPath.Handle?) throws -> String { guard let swiftScan = swiftScanLibInstance else { fatalError("Attempting to reset scanner cache with no scanner instance.") } - return try swiftScan.createCAS(pluginPath: pluginPath?.pathString, onDiskPath: onDiskPath?.pathString, pluginOptions: pluginOptions) + let inputPath = input?.description ?? "" + return try swiftScan.computeCacheKeyForOutput(kind: kind, commandLine: commandLine.stringArray, input: inputPath) } private var hasScannerInstance: Bool { self.swiftScanLibInstance != nil } diff --git a/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift b/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift index e23b1d878..c0af39cb5 100644 --- a/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift +++ b/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift @@ -119,18 +119,11 @@ public extension Driver { commandLine.appendPath(dependencyPlaceholderMapFile) } + try commandLine.appendLast(.clangIncludeTree, from: &parsedOptions) if isFrontendArgSupported(.clangScannerModuleCachePath) { try commandLine.appendLast(.clangScannerModuleCachePath, from: &parsedOptions) } - if isFrontendArgSupported(.scannerPrefixMap) { - // construct `-scanner-prefix-mapper` for scanner. - for (key, value) in prefixMapping { - commandLine.appendFlag(.scannerPrefixMap) - commandLine.appendFlag(key.pathString + "=" + value.pathString) - } - } - // Pass on the input files commandLine.append(contentsOf: inputFiles.filter { $0.type == .swift }.map { .path($0.file) }) return (inputs, commandLine) @@ -172,10 +165,10 @@ public extension Driver { diagnosticEngine.emit(.warn_scanner_frontend_fallback()) } } - if !fallbackToFrontend && isCachingEnabled { - self.cas = try interModuleDependencyOracle.createCAS(pluginPath: try getCASPluginPath(), - onDiskPath: try getOnDiskCASPath(), - pluginOptions: try getCASPluginOptions()) + if !fallbackToFrontend && enableCaching { + try interModuleDependencyOracle.createCAS(pluginPath: try getCASPluginPath(), + onDiskPath: try getOnDiskCASPath(), + pluginOptions: try getCASPluginOptions()) } return fallbackToFrontend } diff --git a/Sources/SwiftDriver/Jobs/CompileJob.swift b/Sources/SwiftDriver/Jobs/CompileJob.swift index c8e68efe5..48763386a 100644 --- a/Sources/SwiftDriver/Jobs/CompileJob.swift +++ b/Sources/SwiftDriver/Jobs/CompileJob.swift @@ -97,8 +97,7 @@ extension Driver { .moduleTrace, .yamlOptimizationRecord, .bitstreamOptimizationRecord, .pcm, .pch, .clangModuleMap, .jsonCompilerFeatures, .jsonTargetInfo, .jsonSwiftArtifacts, .indexUnitOutputPath, .modDepCache, .jsonAPIBaseline, .jsonABIBaseline, - .swiftConstValues, .jsonAPIDescriptor, .moduleSummary, .moduleSemanticInfo, - .cachedDiagnostics, nil: + .swiftConstValues, .jsonAPIDescriptor, nil: return false } } @@ -113,18 +112,13 @@ extension Driver { outputType: FileType?, commandLine: inout [Job.ArgTemplate]) throws -> ([TypedVirtualPath], [TypedVirtualPath]) { - let useInputFileList = shouldUseInputFileList - if let sourcesFileList = allSourcesFileList { + let useInputFileList: Bool + if let allSourcesFileList = allSourcesFileList { + useInputFileList = true commandLine.appendFlag(.filelist) - commandLine.appendPath(sourcesFileList) - } else if shouldUseInputFileList { - let swiftInputs = inputFiles.filter(\.type.isPartOfSwiftCompilation) - let remappedSourcesFileList = try VirtualPath.createUniqueFilelist(RelativePath(validating: "sources"), - .list(swiftInputs.map{ return remapPath($0.file) })) - // Remember the filelist created. - self.allSourcesFileList = remappedSourcesFileList - commandLine.appendFlag(.filelist) - commandLine.appendPath(remappedSourcesFileList) + commandLine.appendPath(allSourcesFileList) + } else { + useInputFileList = false } let usePrimaryInputFileList = primaryInputs.count > fileListThreshold @@ -132,7 +126,7 @@ extension Driver { // primary file list commandLine.appendFlag(.primaryFilelist) let fileList = try VirtualPath.createUniqueFilelist(RelativePath(validating: "primaryInputs"), - .list(primaryInputs.map{ return remapPath($0.file) })) + .list(primaryInputs.map(\.file))) commandLine.appendPath(fileList) } @@ -172,11 +166,12 @@ extension Driver { let isPrimary = usesPrimaryFileInputs && primaryInputFiles.contains(input) if isPrimary { if !usePrimaryInputFileList { - try addPathOption(option: .primaryFile, path: input.file, to:&commandLine) + commandLine.appendFlag(.primaryFile) + commandLine.appendPath(input.file) } } else { if !useInputFileList { - try addPathArgument(input.file, to: &commandLine) + commandLine.appendPath(input.file) } } @@ -397,9 +392,6 @@ extension Driver { } else { displayInputs = primaryInputs } - // Only swift input files are contributing to the cache keys. - let cacheContributingInputs = displayInputs.filter() { $0.type == .swift } - let cacheKeys = try computeOutputCacheKeyForJob(commandLine: commandLine, inputs: cacheContributingInputs) return Job( moduleName: moduleOutputInfo.name, @@ -410,7 +402,6 @@ extension Driver { inputs: inputs, primaryInputs: primaryInputs, outputs: outputs, - outputCacheKeys: cacheKeys, inputOutputMap: inputOutputMap ) } @@ -473,8 +464,7 @@ extension FileType { .bitstreamOptimizationRecord, .swiftInterface, .privateSwiftInterface, .swiftSourceInfoFile, .clangModuleMap, .jsonSwiftArtifacts, .indexUnitOutputPath, .modDepCache, .jsonAPIBaseline, .jsonABIBaseline, - .swiftConstValues, .jsonAPIDescriptor, .moduleSummary, .moduleSemanticInfo, - .cachedDiagnostics: + .swiftConstValues, .jsonAPIDescriptor: fatalError("Output type can never be a primary output") } } diff --git a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift index cbbb1b1fd..0c36a26bb 100644 --- a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift +++ b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift @@ -75,7 +75,6 @@ extension Driver { break } - let jobNeedPathRemap: Bool // If in ExplicitModuleBuild mode and the dependency graph has been computed, add module // dependencies. // May also be used for generation of the dependency graph itself in ExplicitModuleBuild mode. @@ -84,10 +83,8 @@ extension Driver { switch kind { case .generatePCH: try addExplicitPCHBuildArguments(inputs: &inputs, commandLine: &commandLine) - jobNeedPathRemap = true case .compile, .emitModule, .interpret, .verifyModuleInterface: try addExplicitModuleBuildArguments(inputs: &inputs, commandLine: &commandLine) - jobNeedPathRemap = true case .backend, .mergeModule, .compileModuleFromInterface, .generatePCM, .dumpPCM, .repl, .printTargetInfo, .versionRequest, .autolinkExtract, .generateDSYM, @@ -95,10 +92,8 @@ extension Driver { .emitSupportedFeatures, .moduleWrap, .generateAPIBaseline, .generateABIBaseline, .compareAPIBaseline, .compareABIBaseline: - jobNeedPathRemap = false + break // Do not support creating from dependency scanner output. } - } else { - jobNeedPathRemap = false } if let variant = parsedOptions.getLastArgument(.targetVariant)?.asSingle { @@ -150,22 +145,24 @@ extension Driver { try commandLine.appendLast(.targetCpu, from: &parsedOptions) if let sdkPath = frontendTargetInfo.sdkPath?.path { - try addPathOption(option: .sdk, path: VirtualPath.lookup(sdkPath), to: &commandLine, remap: jobNeedPathRemap) + commandLine.appendFlag(.sdk) + commandLine.append(.path(VirtualPath.lookup(sdkPath))) } for args: (Option, Option) in [ (.visualcToolsRoot, .visualcToolsVersion), (.windowsSdkRoot, .windowsSdkVersion) ] { - let (rootOpt, versionOpt) = args - if let rootArg = parsedOptions.last(for: rootOpt), - isFrontendArgSupported(rootOpt) { - try addPathOption(rootArg, to: &commandLine, remap: jobNeedPathRemap) + let (rootArg, versionArg) = args + if let value = parsedOptions.getLastArgument(rootArg)?.asSingle, + isFrontendArgSupported(rootArg) { + commandLine.appendFlag(rootArg.spelling) + commandLine.appendPath(try .init(validating: value)) } - if let value = parsedOptions.getLastArgument(versionOpt)?.asSingle, - isFrontendArgSupported(versionOpt) { - commandLine.appendFlags(versionOpt.spelling, value) + if let value = parsedOptions.getLastArgument(versionArg)?.asSingle, + isFrontendArgSupported(versionArg) { + commandLine.appendFlags(versionArg.spelling, value) } } @@ -318,21 +315,19 @@ extension Driver { try commandLine.appendLast(.enableBuiltinModule, from: &parsedOptions) } - if !(isCachingEnabled && useClangIncludeTree), let workingDirectory = workingDirectory { + if !useClangIncludeTree, let workingDirectory = workingDirectory { // Add -Xcc -working-directory before any other -Xcc options to ensure it is // overridden by an explicit -Xcc -working-directory, although having a // different working directory is probably incorrect. commandLine.appendFlag(.Xcc) commandLine.appendFlag(.workingDirectory) commandLine.appendFlag(.Xcc) - try addPathArgument(.absolute(workingDirectory), to: &commandLine, remap: jobNeedPathRemap) + commandLine.appendPath(.absolute(workingDirectory)) } // Resource directory. - try addPathOption(option: .resourceDir, - path: VirtualPath.lookup(frontendTargetInfo.runtimeResourcePath.path), - to: &commandLine, - remap: jobNeedPathRemap) + commandLine.appendFlag(.resourceDir) + commandLine.appendPath(VirtualPath.lookup(frontendTargetInfo.runtimeResourcePath.path)) if self.useStaticResourceDir { commandLine.appendFlag("-use-static-resource-dir") @@ -359,7 +354,7 @@ extension Driver { } // CAS related options. - if isCachingEnabled { + if enableCaching { commandLine.appendFlag(.cacheCompileJob) if let casPath = try getOnDiskCASPath() { commandLine.appendFlag(.casPath) @@ -371,16 +366,15 @@ extension Driver { } try commandLine.appendAll(.casPluginOption, from: &parsedOptions) try commandLine.appendLast(.cacheRemarks, from: &parsedOptions) - if !useClangIncludeTree { - commandLine.appendFlag(.noClangIncludeTree) - } } - addCacheReplayMapping(to: &commandLine) + if useClangIncludeTree { + commandLine.appendFlag(.clangIncludeTree) + } // Pass through any subsystem flags. try commandLine.appendAll(.Xllvm, from: &parsedOptions) - if !(isCachingEnabled && useClangIncludeTree) { + if !useClangIncludeTree { try commandLine.appendAll(.Xcc, from: &parsedOptions) } @@ -395,16 +389,16 @@ extension Driver { // of a lookup failure. if parsedOptions.contains(.pchOutputDir) && !parsedOptions.contains(.driverExplicitModuleBuild) { - try addPathArgument(VirtualPath.lookup(importedObjCHeader), to:&commandLine, remap: jobNeedPathRemap) + commandLine.appendPath(VirtualPath.lookup(importedObjCHeader)) try commandLine.appendLast(.pchOutputDir, from: &parsedOptions) if !compilerMode.isSingleCompilation { commandLine.appendFlag(.pchDisableValidation) } } else { - try addPathArgument(VirtualPath.lookup(pch), to:&commandLine, remap: jobNeedPathRemap) + commandLine.appendPath(VirtualPath.lookup(pch)) } } else { - try addPathArgument(VirtualPath.lookup(importedObjCHeader), to:&commandLine, remap: jobNeedPathRemap) + commandLine.appendPath(VirtualPath.lookup(importedObjCHeader)) } } @@ -444,18 +438,18 @@ extension Driver { } } - mutating func addBridgingHeaderPCHCacheKeyArguments(commandLine: inout [Job.ArgTemplate], - pchCompileJob: Job?) throws { - guard let pchJob = pchCompileJob, isCachingEnabled else { return } + func addBridgingHeaderPCHCacheKeyArguments(commandLine: inout [Job.ArgTemplate], + pchCompileJob: Job?) throws { + guard let pchJob = pchCompileJob, enableCaching else { return } // The pch input file (the bridging header) is added as last inputs to the job. guard let inputFile = pchJob.inputs.last else { assertionFailure("no input files from pch job"); return } assert(inputFile.type == .objcHeader, "Expect objc header input type") - let bridgingHeaderCacheKey = try computeOutputCacheKey(commandLine: pchJob.commandLine, - input: inputFile) - guard let key = bridgingHeaderCacheKey else { return } + let bridgingHeaderCacheKey = try interModuleDependencyOracle.computeCacheKeyForOutput(kind: .pch, + commandLine: pchJob.commandLine, + input: inputFile.fileHandle) commandLine.appendFlag("-bridging-header-pch-key") - commandLine.appendFlag(key) + commandLine.appendFlag(bridgingHeaderCacheKey) } mutating func addFrontendSupplementaryOutputArguments(commandLine: inout [Job.ArgTemplate], @@ -641,7 +635,7 @@ extension Driver { var entries = [VirtualPath.Handle: [FileType: VirtualPath.Handle]]() for input in primaryInputs { if let output = inputOutputMap[input]?.first { - try addEntry(&entries, input: input, output: output) + addEntry(&entries, input: input, output: output) } else { // Primary inputs are expected to appear in the output file map even // if they have no corresponding outputs. @@ -660,7 +654,7 @@ extension Driver { } for flaggedPair in flaggedInputOutputPairs { - try addEntry(&entries, input: flaggedPair.input, output: flaggedPair.output) + addEntry(&entries, input: flaggedPair.input, output: flaggedPair.output) } // To match the legacy driver behavior, make sure we add an entry for the // file under indexing and the primary output file path. @@ -694,15 +688,14 @@ extension Driver { try commandLine.appendLast(.symbolGraphMinimumAccessLevel, from: &parsedOptions) } - mutating func addEntry(_ entries: inout [VirtualPath.Handle: [FileType: VirtualPath.Handle]], input: TypedVirtualPath?, output: TypedVirtualPath) throws { + func addEntry(_ entries: inout [VirtualPath.Handle: [FileType: VirtualPath.Handle]], input: TypedVirtualPath?, output: TypedVirtualPath) { let entryInput: VirtualPath.Handle if let input = input?.fileHandle, input != OutputFileMap.singleInputKey { entryInput = input } else { entryInput = inputFiles[0].fileHandle } - let inputEntry = isCachingEnabled ? remapPath(VirtualPath.lookup(entryInput)).intern() : entryInput - entries[inputEntry, default: [:]][output.type] = output.fileHandle + entries[entryInput, default: [:]][output.type] = output.fileHandle } /// Adds all dependencies required for an explicit module build @@ -739,116 +732,3 @@ extension Driver { return job.moduleName == moduleOutputInfo.name } } - -extension Driver { - private func getAbsolutePathFromVirtualPath(_ path: VirtualPath) -> AbsolutePath? { - guard let cwd = workingDirectory ?? fileSystem.currentWorkingDirectory else { - return nil - } - return path.resolvedRelativePath(base: cwd).absolutePath - } - - private mutating func remapPath(absolute path: AbsolutePath) -> AbsolutePath { - guard !prefixMapping.isEmpty else { - return path - } - for (prefix, value) in prefixMapping { - if path.isDescendantOfOrEqual(to: prefix) { - return value.appending(path.relative(to: prefix)) - } - } - return path - } - - public mutating func remapPath(_ path: VirtualPath) -> VirtualPath { - guard !prefixMapping.isEmpty, - let absPath = getAbsolutePathFromVirtualPath(path) else { - return path - } - let mappedPath = remapPath(absolute: absPath) - return try! VirtualPath(path: mappedPath.pathString) - } - - /// Helper function to add path to commandLine. Function will validate the path, and remap the path if needed. - public mutating func addPathArgument(_ path: VirtualPath, to commandLine: inout [Job.ArgTemplate], remap: Bool = true) throws { - guard remap && isCachingEnabled else { - commandLine.appendPath(path) - return - } - let mappedPath = remapPath(path) - commandLine.appendPath(mappedPath) - } - - public mutating func addPathOption(_ option: ParsedOption, to commandLine: inout [Job.ArgTemplate], remap: Bool = true) throws { - let path = try VirtualPath(path: option.argument.asSingle) - try addPathOption(option: option.option, path: path, to: &commandLine, remap: remap) - } - - public mutating func addPathOption(option: Option, path: VirtualPath, to commandLine: inout [Job.ArgTemplate], remap: Bool = true) throws { - commandLine.appendFlag(option) - let needRemap = remap && option.attributes.contains(.argumentIsPath) && - !option.attributes.contains(.cacheInvariant) - try addPathArgument(path, to: &commandLine, remap: needRemap) - } - - /// Helper function to add last argument with path to command-line. - public mutating func addLastArgumentWithPath(_ options: Option..., - from parsedOptions: inout ParsedOptions, - to commandLine: inout [Job.ArgTemplate], - remap: Bool = true) throws { - guard let parsedOption = parsedOptions.last(for: options) else { - return - } - try addPathOption(parsedOption, to: &commandLine, remap: remap) - } - - /// Helper function to add all arguments with path to command-line. - public mutating func addAllArgumentsWithPath(_ options: Option..., - from parsedOptions: inout ParsedOptions, - to commandLine: inout [Job.ArgTemplate], - remap: Bool) throws { - for matching in parsedOptions.arguments(for: options) { - try addPathOption(matching, to: &commandLine, remap: remap) - } - } - - public mutating func addCacheReplayMapping(to commandLine: inout [Job.ArgTemplate]) { - if isCachingEnabled && isFrontendArgSupported(.scannerPrefixMap) { - for (key, value) in prefixMapping { - commandLine.appendFlag("-cache-replay-prefix-map") - commandLine.appendFlag(value.pathString + "=" + key.pathString) - } - } - } -} - -extension Driver { - public mutating func computeOutputCacheKeyForJob(commandLine: [Job.ArgTemplate], - inputs: [TypedVirtualPath]) throws -> [TypedVirtualPath: String] { - // No caching setup, return empty dictionary. - guard let cas = self.cas else { - return [:] - } - // Resolve command-line first. - let resolver = try ArgsResolver(fileSystem: fileSystem) - let arguments: [String] = try resolver.resolveArgumentList(for: commandLine) - - return try inputs.reduce(into: [:]) { keys, input in - let remappedPath = remapPath(input.file) - keys[input] = try cas.computeCacheKey(commandLine: arguments, input: remappedPath.name) - } - } - - public mutating func computeOutputCacheKey(commandLine: [Job.ArgTemplate], - input: TypedVirtualPath) throws -> String? { - // No caching setup, return empty dictionary. - guard let cas = self.cas else { - return nil - } - // Resolve command-line first. - let resolver = try ArgsResolver(fileSystem: fileSystem) - let arguments: [String] = try resolver.resolveArgumentList(for: commandLine) - let remappedPath = remapPath(input.file) - return try cas.computeCacheKey(commandLine: arguments, input: remappedPath.name) - } -} diff --git a/Sources/SwiftDriver/Jobs/GeneratePCHJob.swift b/Sources/SwiftDriver/Jobs/GeneratePCHJob.swift index 9628c1fa7..628b6d9ed 100644 --- a/Sources/SwiftDriver/Jobs/GeneratePCHJob.swift +++ b/Sources/SwiftDriver/Jobs/GeneratePCHJob.swift @@ -32,7 +32,6 @@ extension Driver { if try supportsBridgingHeaderPCHCommand() { try addExplicitPCHBuildArguments(inputs: &inputs, commandLine: &commandLine) - addCacheReplayMapping(to: &commandLine) } else { try addGeneratePCHFlags(commandLine: &commandLine, inputs: &inputs) } @@ -68,9 +67,7 @@ extension Driver { outputs.append(output) inputs.append(input) - try addPathArgument(input.file, to: &commandLine) - - let cacheKeys = try computeOutputCacheKeyForJob(commandLine: commandLine, inputs: [input]) + commandLine.appendPath(input.file) return Job( moduleName: moduleOutputInfo.name, @@ -80,8 +77,7 @@ extension Driver { displayInputs: [], inputs: inputs, primaryInputs: [], - outputs: outputs, - outputCacheKeys: cacheKeys + outputs: outputs ) } } diff --git a/Sources/SwiftDriver/Jobs/GeneratePCMJob.swift b/Sources/SwiftDriver/Jobs/GeneratePCMJob.swift index 225a4bffe..86f1a4543 100644 --- a/Sources/SwiftDriver/Jobs/GeneratePCMJob.swift +++ b/Sources/SwiftDriver/Jobs/GeneratePCMJob.swift @@ -51,7 +51,6 @@ extension Driver { commandLine: &commandLine, inputs: &inputs, kind: .generatePCM, bridgingHeaderHandling: .ignored) try commandLine.appendLast(.indexStorePath, from: &parsedOptions) - let cacheKeys = try computeOutputCacheKeyForJob(commandLine: commandLine, inputs: [input]) return Job( moduleName: moduleOutputInfo.name, @@ -61,8 +60,7 @@ extension Driver { displayInputs: [], inputs: inputs, primaryInputs: [], - outputs: outputs, - outputCacheKeys: cacheKeys + outputs: outputs ) } diff --git a/Sources/SwiftDriver/Jobs/Job.swift b/Sources/SwiftDriver/Jobs/Job.swift index 1313f8e2a..0c3571165 100644 --- a/Sources/SwiftDriver/Jobs/Job.swift +++ b/Sources/SwiftDriver/Jobs/Job.swift @@ -101,9 +101,6 @@ public struct Job: Codable, Equatable, Hashable { /// The kind of job. public var kind: Kind - /// The Cache Key for the compilation. It is a dictionary from input file to its output cache key. - public var outputCacheKeys: [TypedVirtualPath: String] - /// A map from a primary input to all of its corresponding outputs private var compileInputOutputMap: [TypedVirtualPath : [TypedVirtualPath]] @@ -116,7 +113,6 @@ public struct Job: Codable, Equatable, Hashable { inputs: [TypedVirtualPath], primaryInputs: [TypedVirtualPath], outputs: [TypedVirtualPath], - outputCacheKeys: [TypedVirtualPath: String] = [:], inputOutputMap: [TypedVirtualPath : [TypedVirtualPath]] = [:], extraEnvironment: [String: String] = [:], requiresInPlaceExecution: Bool = false @@ -129,7 +125,6 @@ public struct Job: Codable, Equatable, Hashable { self.inputs = inputs self.primaryInputs = primaryInputs self.outputs = outputs - self.outputCacheKeys = outputCacheKeys self.compileInputOutputMap = inputOutputMap self.extraEnvironment = extraEnvironment self.requiresInPlaceExecution = requiresInPlaceExecution @@ -294,21 +289,6 @@ extension Job.Kind { return false } } - - /// Whether this job supports caching. - public var supportCaching: Bool { - switch self { - case .compile, .emitModule, .generatePCH, .compileModuleFromInterface, - .generatePCM, .verifyModuleInterface: - return true - case .backend, .mergeModule, .dumpPCM, .interpret, .repl, .printTargetInfo, - .versionRequest, .autolinkExtract, .generateDSYM, .help, .link, - .verifyDebugInfo, .scanDependencies, .emitSupportedFeatures, .moduleWrap, - .generateAPIBaseline, .generateABIBaseline, .compareAPIBaseline, - .compareABIBaseline: - return false - } - } } // MARK: - Job.ArgTemplate + Codable diff --git a/Sources/SwiftDriver/Jobs/Planning.swift b/Sources/SwiftDriver/Jobs/Planning.swift index b630a7cd1..fd5e23e51 100644 --- a/Sources/SwiftDriver/Jobs/Planning.swift +++ b/Sources/SwiftDriver/Jobs/Planning.swift @@ -688,8 +688,8 @@ extension Driver { dependencyOracle: interModuleDependencyOracle, integratedDriver: integratedDriver, supportsExplicitInterfaceBuild: - isFrontendArgSupported(.explicitInterfaceModuleBuild), - cas: cas) + isFrontendArgSupported(.explicitInterfaceModuleBuild), + enableCAS: enableCaching) return try explicitDependencyBuildPlanner!.generateExplicitModuleDependenciesBuildJobs() } diff --git a/Sources/SwiftDriver/Jobs/VerifyModuleInterfaceJob.swift b/Sources/SwiftDriver/Jobs/VerifyModuleInterfaceJob.swift index 0f1c845d1..cacc385ca 100644 --- a/Sources/SwiftDriver/Jobs/VerifyModuleInterfaceJob.swift +++ b/Sources/SwiftDriver/Jobs/VerifyModuleInterfaceJob.swift @@ -11,17 +11,18 @@ //===----------------------------------------------------------------------===// extension Driver { - mutating func computeCacheKeyForInterface(emitModuleJob: Job, - interfaceKind: FileType) throws -> String? { + func computeCacheKeyForInterface(emitModuleJob: Job, + interfaceKind: FileType) throws -> String? { assert(interfaceKind == .swiftInterface || interfaceKind == .privateSwiftInterface, "only expect interface output kind") let isNeeded = emitModuleJob.outputs.contains { $0.type == interfaceKind } - guard isCachingEnabled && isNeeded else { return nil } + guard enableCaching && isNeeded else { return nil } // Assume swiftinterface file is always the supplementary output for first input file. - let key = try computeOutputCacheKey(commandLine: emitModuleJob.commandLine, - input: emitModuleJob.inputs[0]) - return key + let mainInput = emitModuleJob.inputs[0] + return try interModuleDependencyOracle.computeCacheKeyForOutput(kind: interfaceKind, + commandLine: emitModuleJob.commandLine, + input: mainInput.fileHandle) } @_spi(Testing) @@ -34,7 +35,7 @@ extension Driver { var commandLine: [Job.ArgTemplate] = swiftCompilerPrefixArgs.map { Job.ArgTemplate.flag($0) } var inputs: [TypedVirtualPath] = [interfaceInput] commandLine.appendFlags("-frontend", "-typecheck-module-from-interface") - try addPathArgument(interfaceInput.file, to: &commandLine) + commandLine.appendPath(interfaceInput.file) try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .verifyModuleInterface) // FIXME: MSVC runtime flags @@ -57,8 +58,6 @@ extension Driver { if !optIn && isFrontendArgSupported(.downgradeTypecheckInterfaceError) { commandLine.appendFlag(.downgradeTypecheckInterfaceError) } - - let cacheKeys = try computeOutputCacheKeyForJob(commandLine: commandLine, inputs: [interfaceInput]) return Job( moduleName: moduleOutputInfo.name, kind: .verifyModuleInterface, @@ -67,8 +66,7 @@ extension Driver { displayInputs: [interfaceInput], inputs: inputs, primaryInputs: [], - outputs: outputs, - outputCacheKeys: cacheKeys + outputs: outputs ) } } diff --git a/Sources/SwiftDriver/SwiftScan/SwiftScan.swift b/Sources/SwiftDriver/SwiftScan/SwiftScan.swift index d048d96a7..a77cb1227 100644 --- a/Sources/SwiftDriver/SwiftScan/SwiftScan.swift +++ b/Sources/SwiftDriver/SwiftScan/SwiftScan.swift @@ -98,6 +98,9 @@ internal extension swiftscan_diagnostic_severity_t { /// Instance of a scanner, which maintains shared state across scan queries. let scanner: swiftscan_scanner_t; + /// Optional CAS instance. + var cas: swiftscan_cas_t? = nil + @_spi(Testing) public init(dylib path: AbsolutePath) throws { self.path = path #if os(Windows) @@ -114,6 +117,9 @@ internal extension swiftscan_diagnostic_severity_t { deinit { api.swiftscan_scanner_dispose(self.scanner) + if let scan_cas = cas { + api.swiftscan_cas_dispose(scan_cas) + } // FIXME: is it safe to dlclose() swiftscan? If so, do that here. // For now, let the handle leak. dylib.leak() @@ -283,10 +289,10 @@ internal extension swiftscan_diagnostic_severity_t { api.swiftscan_cas_options_dispose != nil && api.swiftscan_cas_options_set_ondisk_path != nil && api.swiftscan_cas_options_set_plugin_path != nil && - api.swiftscan_cas_options_set_plugin_option != nil && + api.swiftscan_cas_options_set_option != nil && api.swiftscan_cas_create_from_options != nil && api.swiftscan_cas_dispose != nil && - api.swiftscan_cache_compute_key != nil && + api.swiftscan_compute_cache_key != nil && api.swiftscan_cas_store != nil && api.swiftscan_swift_textual_detail_get_module_cache_key != nil && api.swiftscan_swift_binary_detail_get_module_cache_key != nil && @@ -386,18 +392,16 @@ internal extension swiftscan_diagnostic_severity_t { } } - func handleCASError(_ closure: (inout swiftscan_string_ref_t) -> T) throws -> T{ + private func handleCASError(_ closure: (inout swiftscan_string_ref_t) -> Bool) throws { var err_msg : swiftscan_string_ref_t = swiftscan_string_ref_t() - let ret = closure(&err_msg) - if err_msg.length != 0 { + guard !closure(&err_msg) else { let err_str = try toSwiftString(err_msg) api.swiftscan_string_dispose(err_msg) throw DependencyScanningError.casError(err_str) } - return ret } - func createCAS(pluginPath: String?, onDiskPath: String?, pluginOptions: [(String, String)]) throws -> SwiftScanCAS { + func createCAS(pluginPath: String?, onDiskPath: String?, pluginOptions: [(String, String)]) throws { let casOpts = api.swiftscan_cas_options_create() defer { api.swiftscan_cas_options_dispose(casOpts) @@ -410,13 +414,65 @@ internal extension swiftscan_diagnostic_severity_t { } for (name, value) in pluginOptions { try handleCASError { err_msg in - _ = api.swiftscan_cas_options_set_plugin_option(casOpts, name, value, &err_msg) + return api.swiftscan_cas_options_set_option(casOpts, name, value, &err_msg) } } - let cas = try handleCASError { err_msg in - api.swiftscan_cas_create_from_options(casOpts, &err_msg) + try handleCASError { err_msg in + self.cas = api.swiftscan_cas_create_from_options(casOpts, &err_msg) + return self.cas == nil + } + } + + func store(data: Data) throws -> String { + guard let scan_cas = self.cas else { + throw DependencyScanningError.casError("cannot store into CAS because CAS is not yet created") + } + let bytes = UnsafeMutablePointer.allocate(capacity: data.count) + data.copyBytes(to: bytes, count: data.count) + var casid: swiftscan_string_ref_t = swiftscan_string_ref_t() + try handleCASError { err_msg in + casid = api.swiftscan_cas_store(scan_cas, bytes, UInt32(data.count), &err_msg) + return casid.data == nil } - return SwiftScanCAS(cas: cas!, scanner: self) + return try toSwiftString(casid) + } + + private func getSwiftScanOutputKind(kind: FileType) -> swiftscan_output_kind_t { + switch (kind) { + case .object: + return SWIFTSCAN_OUTPUT_TYPE_OBJECT + case .swiftModule: + return SWIFTSCAN_OUTPUT_TYPE_SWIFTMODULE + case .swiftInterface: + return SWIFTSCAN_OUTPUT_TYPE_SWIFTINTERFACE + case .privateSwiftInterface: + return SWIFTSCAN_OUTPUT_TYPE_SWIFTPRIVATEINTERFACE + case .pcm: + return SWIFTSCAN_OUTPUT_TYPE_CLANG_MODULE + case .pch: + return SWIFTSCAN_OUTPUT_TYPE_CLANG_PCH + default: + fatalError("Unsupported") + } + } + + func computeCacheKeyForOutput(kind: FileType, commandLine: [String], input: String) throws -> String { + guard let scan_cas = self.cas else { + throw DependencyScanningError.casError("cannot compute CacheKey for compilation because CAS is not yet created") + } + var casid: swiftscan_string_ref_t = swiftscan_string_ref_t() + try handleCASError { err_msg in + withArrayOfCStrings(commandLine) { commandArray in + casid = api.swiftscan_compute_cache_key(scan_cas, + Int32(commandLine.count), + commandArray, + input.cString(using: String.Encoding.utf8), + getSwiftScanOutputKind(kind: kind), + &err_msg) + } + return casid.data == nil + } + return try toSwiftString(casid) } } @@ -502,39 +558,14 @@ private extension swiftscan_functions_t { 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_set_option = try loadOptional("swiftscan_cas_options_set_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_dispose = try loadOptional("swiftscan_cas_dispose") - self.swiftscan_cache_compute_key = try loadOptional("swiftscan_cache_compute_key") + self.swiftscan_compute_cache_key = + try loadOptional("swiftscan_compute_cache_key") 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_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") // Swift Overlay Dependencies self.swiftscan_swift_textual_detail_get_swift_overlay_dependencies = @@ -663,14 +694,13 @@ private extension swiftscan_functions_t { // TODO: Move to TSC? /// Perform an `action` passing it a `const char **` constructed out of `[String]` -func withArrayOfCStrings(_ strings: [String], - _ action: (UnsafeMutablePointer?>?) -> T) -> T +func withArrayOfCStrings(_ strings: [String], + _ action: (UnsafeMutablePointer?>?) -> Void) { let cstrings = strings.map { strdup($0) } + [nil] let unsafeCStrings = cstrings.map { UnsafePointer($0) } - let result = unsafeCStrings.withUnsafeBufferPointer { + let _ = unsafeCStrings.withUnsafeBufferPointer { action(UnsafeMutablePointer(mutating: $0.baseAddress)) } for ptr in cstrings { if let ptr = ptr { free(ptr) } } - return result } diff --git a/Sources/SwiftDriver/SwiftScan/SwiftScanCAS.swift b/Sources/SwiftDriver/SwiftScan/SwiftScanCAS.swift deleted file mode 100644 index 1ec9deefe..000000000 --- a/Sources/SwiftDriver/SwiftScan/SwiftScanCAS.swift +++ /dev/null @@ -1,322 +0,0 @@ -//===------------------------ SwiftScanCAS.swift --------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -@_implementationOnly import CSwiftScan -import struct Foundation.Data - -public final class CachedCompilation { - let ptr: swiftscan_cached_compilation_t - private let lib: SwiftScan - - init(_ ptr: swiftscan_cached_compilation_t, lib: SwiftScan) { - self.ptr = ptr - self.lib = lib - } - - public lazy var count: UInt32 = { - lib.api.swiftscan_cached_compilation_get_num_outputs(ptr) - }() - - public var isUncacheable: Bool { - lib.api.swiftscan_cached_compilation_is_uncacheable(ptr) - } - - public func makeGlobal() async throws -> Bool { - class CallbackContext { - func retain() -> UnsafeMutableRawPointer { - return Unmanaged.passRetained(self).toOpaque() - } - - let continuation: CheckedContinuation - let comp: CachedCompilation - init(_ continuation: CheckedContinuation, compilation: CachedCompilation) { - self.continuation = continuation - self.comp = compilation - } - } - - func callbackFunc(_ context: UnsafeMutableRawPointer?, _ error: swiftscan_string_ref_t) { - let obj = Unmanaged.fromOpaque(context!).takeRetainedValue() - if error.length != 0 { - if let err = try? obj.comp.lib.toSwiftString(error) { - obj.continuation.resume(throwing: DependencyScanningError.casError(err)) - } else { - obj.continuation.resume(throwing: DependencyScanningError.casError("unknown makeGlobal error")) - } - } - obj.continuation.resume(returning: true) - } - - return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in - let context = CallbackContext(continuation, compilation: self) - lib.api.swiftscan_cached_compilation_make_global_async(ptr, context.retain(), callbackFunc, nil) - } - } - - deinit { - lib.api.swiftscan_cached_compilation_dispose(ptr) - } -} - -extension CachedCompilation: Sequence { - public typealias Element = CachedOutput - public struct Iterator: IteratorProtocol { - public typealias Element = CachedOutput - let limit: UInt32 - let ptr: swiftscan_cached_compilation_t - let lib: SwiftScan - var idx: UInt32 = 0 - public mutating func next() -> CachedOutput? { - guard idx < self.limit else { return nil } - let output = self.lib.api.swiftscan_cached_compilation_get_output(self.ptr, idx) - idx += 1 - // output can never be nil. - return CachedOutput(output!, lib: self.lib) - } - } - public func makeIterator() -> Iterator { - return Iterator(limit: self.count, ptr: self.ptr, lib: self.lib) - } -} - -public final class CachedOutput { - let ptr: swiftscan_cached_output_t - private let lib: SwiftScan - - init(_ ptr: swiftscan_cached_output_t, lib: SwiftScan) { - self.ptr = ptr - self.lib = lib - } - - public func load() throws -> Bool { - try lib.handleCASError { err_msg in - lib.api.swiftscan_cached_output_load(ptr, &err_msg) - } - } - - public func load() async throws -> Bool { - class CallbackContext { - func retain() -> UnsafeMutableRawPointer { - return Unmanaged.passRetained(self).toOpaque() - } - - let continuation: CheckedContinuation - let output: CachedOutput - init(_ continuation: CheckedContinuation, output: CachedOutput) { - self.continuation = continuation - self.output = output - } - } - - func callbackFunc(_ context: UnsafeMutableRawPointer?, _ success: Bool, _ error: swiftscan_string_ref_t) { - let obj = Unmanaged.fromOpaque(context!).takeRetainedValue() - if error.length != 0 { - if let err = try? obj.output.lib.toSwiftString(error) { - obj.continuation.resume(throwing: DependencyScanningError.casError(err)) - } else { - obj.continuation.resume(throwing: DependencyScanningError.casError("unknown output loading error")) - } - } - obj.continuation.resume(returning: success) - } - - return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in - let context = CallbackContext(continuation, output: self) - lib.api.swiftscan_cached_output_load_async(ptr, context.retain(), callbackFunc, nil) - } - } - - public var isMaterialized: Bool { - lib.api.swiftscan_cached_output_is_materialized(ptr) - } - - public func getCASID() throws -> String { - let id = lib.api.swiftscan_cached_output_get_casid(ptr) - defer { lib.api.swiftscan_string_dispose(id) } - return try lib.toSwiftString(id) - } - - public func getOutputKindName() throws -> String { - let kind = lib.api.swiftscan_cached_output_get_name(ptr) - defer { lib.api.swiftscan_string_dispose(kind) } - return try lib.toSwiftString(kind) - } - - deinit { - lib.api.swiftscan_cached_output_dispose(ptr) - } -} - -public final class CacheReplayInstance { - let ptr: swiftscan_cache_replay_instance_t - private let lib: SwiftScan - - init(_ ptr: swiftscan_cache_replay_instance_t, lib: SwiftScan) { - self.ptr = ptr - self.lib = lib - } - - deinit { - lib.api.swiftscan_cache_replay_instance_dispose(ptr) - } -} - -public final class CacheReplayResult { - let ptr: swiftscan_cache_replay_result_t - private let lib: SwiftScan - - init(_ ptr: swiftscan_cache_replay_result_t, lib: SwiftScan) { - self.ptr = ptr - self.lib = lib - } - - public func getStdOut() throws -> String { - let str = lib.api.swiftscan_cache_replay_result_get_stdout(ptr) - return try lib.toSwiftString(str) - } - - public func getStdErr() throws -> String { - let str = lib.api.swiftscan_cache_replay_result_get_stderr(ptr) - return try lib.toSwiftString(str) - } - - deinit { - lib.api.swiftscan_cache_replay_result_dispose(ptr) - } -} - -public final class SwiftScanCAS { - let cas: swiftscan_cas_t - private let scanner: SwiftScan - deinit { - scanner.api.swiftscan_cas_dispose(cas) - } - - init(cas: swiftscan_cas_t, scanner: SwiftScan) { - self.cas = cas - self.scanner = scanner - } - - private func convert(compilation: swiftscan_cached_compilation_t?) -> CachedCompilation? { - return compilation?.convert(scanner) - } - private func convert(instance: swiftscan_cache_replay_instance_t?) -> CacheReplayInstance? { - return instance?.convert(scanner) - } - private func convert(result: swiftscan_cache_replay_result_t?) -> CacheReplayResult? { - return result?.convert(scanner) - } - - public func store(data: Data) throws -> String { - let bytes = UnsafeMutablePointer.allocate(capacity: data.count) - data.copyBytes(to: bytes, count: data.count) - let casid = try scanner.handleCASError { err_msg in - scanner.api.swiftscan_cas_store(cas, bytes, UInt32(data.count), &err_msg) - } - return try scanner.toSwiftString(casid) - } - - public func computeCacheKey(commandLine: [String], input: String) throws -> String { - let casid = try scanner.handleCASError { err_msg in - withArrayOfCStrings(commandLine) { commandArray in - scanner.api.swiftscan_cache_compute_key(cas, - Int32(commandLine.count), - commandArray, - input.cString(using: String.Encoding.utf8), - &err_msg) - } - } - return try scanner.toSwiftString(casid) - } - - public func createReplayInstance(commandLine: [String]) throws -> CacheReplayInstance { - let instance = try scanner.handleCASError { err_msg in - withArrayOfCStrings(commandLine) { commandArray in - scanner.api.swiftscan_cache_replay_instance_create(Int32(commandLine.count), - commandArray, - &err_msg) - } - } - // Never return nullptr when no error occurs. - guard let result = convert(instance: instance) else { - throw DependencyScanningError.casError("unexpected nil for replay instance") - } - return result - } - - public func queryCacheKey(_ key: String, globally: Bool) throws -> CachedCompilation? { - let result = try scanner.handleCASError { error in - scanner.api.swiftscan_cache_query(cas, key.cString(using: .utf8), globally, &error) - } - return convert(compilation: result) - } - - public func queryCacheKey(_ key: String, globally: Bool) async throws -> CachedCompilation? { - class CallbackContext { - func retain() -> UnsafeMutableRawPointer { - return Unmanaged.passRetained(self).toOpaque() - } - - let continuation: CheckedContinuation - let cas: SwiftScanCAS - init(_ continuation: CheckedContinuation, cas: SwiftScanCAS) { - self.continuation = continuation - self.cas = cas - } - } - - func callbackFunc(_ context: UnsafeMutableRawPointer?, _ comp: swiftscan_cached_compilation_t?, _ error: swiftscan_string_ref_t) { - let obj = Unmanaged.fromOpaque(context!).takeRetainedValue() - if error.length != 0 { - if let err = try? obj.cas.scanner.toSwiftString(error) { - obj.continuation.resume(throwing: DependencyScanningError.casError(err)) - } else { - obj.continuation.resume(throwing: DependencyScanningError.casError("unknown cache querying error")) - } - } - obj.continuation.resume(returning: obj.cas.convert(compilation: comp)) - } - - return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in - let context = CallbackContext(continuation, cas: self) - scanner.api.swiftscan_cache_query_async(cas, key.cString(using: .utf8), globally, context.retain(), callbackFunc, nil) - } - } - - public func replayCompilation(instance: CacheReplayInstance, compilation: CachedCompilation) throws -> CacheReplayResult { - let result = try scanner.handleCASError { err_msg in - scanner.api.swiftscan_cache_replay_compilation(instance.ptr, compilation.ptr, &err_msg) - } - guard let res = convert(result: result) else { - throw DependencyScanningError.casError("unexpected nil for cache_replay_result") - } - return res - } -} - -extension swiftscan_cached_compilation_t { - func convert(_ lib: SwiftScan) -> CachedCompilation { - return CachedCompilation(self, lib: lib) - } -} - -extension swiftscan_cache_replay_instance_t { - func convert(_ lib: SwiftScan) -> CacheReplayInstance { - return CacheReplayInstance(self, lib: lib) - } -} - -extension swiftscan_cache_replay_result_t { - func convert(_ lib: SwiftScan) -> CacheReplayResult { - return CacheReplayResult(self, lib: lib) - } -} diff --git a/Sources/SwiftDriver/Utilities/FileType.swift b/Sources/SwiftDriver/Utilities/FileType.swift index b55943a1c..8acbd145e 100644 --- a/Sources/SwiftDriver/Utilities/FileType.swift +++ b/Sources/SwiftDriver/Utilities/FileType.swift @@ -154,15 +154,6 @@ public enum FileType: String, Hashable, CaseIterable, Codable { /// API descriptor JSON case jsonAPIDescriptor - - /// Swift Module Summary - case moduleSummary = "swiftmodulesummary" - - /// Swift Module Semantic Info - case moduleSemanticInfo - - /// Cached Diagnostics - case cachedDiagnostics } extension FileType: CustomStringConvertible { @@ -250,15 +241,6 @@ extension FileType: CustomStringConvertible { case .jsonAPIDescriptor: return "api-descriptor-json" - - case .moduleSummary: - return "swift-module-summary" - - case .moduleSemanticInfo: - return "module-semantic-info" - - case .cachedDiagnostics: - return "cached-diagnostics" } } } @@ -278,8 +260,7 @@ extension FileType { .swiftInterface, .privateSwiftInterface, .swiftSourceInfoFile, .jsonDependencies, .clangModuleMap, .jsonTargetInfo, .jsonCompilerFeatures, .jsonSwiftArtifacts, .indexUnitOutputPath, .modDepCache, .jsonAPIBaseline, - .jsonABIBaseline, .swiftConstValues, .jsonAPIDescriptor, - .moduleSummary, .moduleSemanticInfo, .cachedDiagnostics: + .jsonABIBaseline, .swiftConstValues, .jsonAPIDescriptor: return false } } @@ -386,12 +367,6 @@ extension FileType { return "const-values" case .jsonAPIDescriptor: return "api-descriptor-json" - case .moduleSummary: - return "swiftmodulesummary" - case .moduleSemanticInfo: - return "module-semantic-info" - case .cachedDiagnostics: - return "cached-diagnostics" } } } @@ -404,7 +379,7 @@ extension FileType { .moduleTrace, .yamlOptimizationRecord, .swiftInterface, .privateSwiftInterface, .jsonDependencies, .clangModuleMap, .jsonCompilerFeatures, .jsonTargetInfo, .jsonSwiftArtifacts, .jsonAPIBaseline, .jsonABIBaseline, .swiftConstValues, - .jsonAPIDescriptor, .moduleSummary, .moduleSemanticInfo, .cachedDiagnostics: + .jsonAPIDescriptor: return true case .image, .object, .dSYM, .pch, .sib, .raw_sib, .swiftModule, .swiftDocumentation, .swiftSourceInfoFile, .llvmBitcode, .diagnostics, @@ -428,30 +403,8 @@ extension FileType { .modDepCache, .bitstreamOptimizationRecord, .pcm, .pch, .jsonDependencies, .clangModuleMap, .jsonCompilerFeatures, .jsonTargetInfo, .jsonSwiftArtifacts, .indexUnitOutputPath, .jsonAPIBaseline, .jsonABIBaseline, .swiftConstValues, - .jsonAPIDescriptor, .moduleSummary, .moduleSemanticInfo, .cachedDiagnostics: + .jsonAPIDescriptor: return false } } - - /// Returns true if the type can be cached as output. - var supportCaching: Bool { - switch self { - case .diagnostics, .emitModuleDiagnostics, // diagnostics are cached using cached diagnostics. - // Those are by-product from swift-driver and not considered outputs need caching. - .jsonSwiftArtifacts, .remap, .indexUnitOutputPath, .modDepCache, - // the remaining should not be an output from a caching swift job. - .swift, .image, .dSYM, .importedModules, .clangModuleMap, - .jsonCompilerFeatures, .jsonTargetInfo, .autolink: - return false - case .assembly, .llvmIR, .llvmBitcode, .object, .sil, .sib, .ast, - .dependencies, .emitModuleDependencies, .swiftModule, - .swiftDocumentation, .swiftInterface, .privateSwiftInterface, - .swiftSourceInfoFile, .raw_sil, .raw_sib, .objcHeader, .swiftDeps, .tbd, - .moduleTrace, .indexData, .yamlOptimizationRecord, - .bitstreamOptimizationRecord, .pcm, .pch, .jsonDependencies, - .jsonAPIBaseline, .jsonABIBaseline, .swiftConstValues, .jsonAPIDescriptor, - .moduleSummary, .moduleSemanticInfo, .cachedDiagnostics: - return true - } - } } diff --git a/Sources/SwiftDriver/Utilities/VirtualPath.swift b/Sources/SwiftDriver/Utilities/VirtualPath.swift index 665147850..12dda459c 100644 --- a/Sources/SwiftDriver/Utilities/VirtualPath.swift +++ b/Sources/SwiftDriver/Utilities/VirtualPath.swift @@ -331,11 +331,6 @@ extension VirtualPath { public static let standardOutput = Handle(-1) public static let standardInput = Handle(-2) -#if os(Windows) - public static let null = try! VirtualPath(path: "nul").intern() -#else - public static let null = try! VirtualPath(path: "/dev/null").intern() -#endif } /// An implementation of a concurrent path cache. @@ -715,7 +710,7 @@ extension TSCBasic.FileSystem { } } - @_spi(Testing) public func readFileContents(_ path: VirtualPath) throws -> ByteString { + func readFileContents(_ path: VirtualPath) throws -> ByteString { try resolvingVirtualPath(path, apply: readFileContents) } @@ -731,7 +726,7 @@ extension TSCBasic.FileSystem { } } - @_spi(Testing) public func removeFileTree(_ path: VirtualPath) throws { + func removeFileTree(_ path: VirtualPath) throws { try resolvingVirtualPath(path) { absolutePath in try self.removeFileTree(absolutePath) } diff --git a/Sources/SwiftOptions/Options.swift b/Sources/SwiftOptions/Options.swift index c580479fc..c234f47d4 100644 --- a/Sources/SwiftOptions/Options.swift +++ b/Sources/SwiftOptions/Options.swift @@ -33,7 +33,6 @@ extension Option { public static let analyzeRequirementMachine: Option = Option("-analyze-requirement-machine", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Print out requirement machine statistics at the end of the compilation job") public static let apiDiffDataDir: Option = Option("-api-diff-data-dir", .separate, attributes: [.frontend, .noInteractive, .doesNotAffectIncrementalBuild, .argumentIsPath], metaVar: "", helpText: "Load platform and version specific API migration data files from . Ignored if -api-diff-data-file is specified.") public static let apiDiffDataFile: Option = Option("-api-diff-data-file", .separate, attributes: [.frontend, .noInteractive, .doesNotAffectIncrementalBuild, .argumentIsPath], metaVar: "", helpText: "API migration data is from ") - public static let enableAppExtensionLibrary: Option = Option("-application-extension-library", .flag, attributes: [.frontend, .noInteractive], helpText: "Restrict code to those available for App Extension Libraries") public static let enableAppExtension: Option = Option("-application-extension", .flag, attributes: [.frontend, .noInteractive], helpText: "Restrict code to those available for App Extensions") public static let AssertConfig: Option = Option("-assert-config", .separate, attributes: [.frontend, .moduleInterface], helpText: "Specify the assert_configuration replacement. Possible values are Debug, Release, Unchecked, DisableReplacement.") public static let AssumeSingleThreaded: Option = Option("-assume-single-threaded", .flag, attributes: [.helpHidden, .frontend], helpText: "Assume that code will be executed in a single-threaded environment") @@ -80,6 +79,7 @@ extension Option { public static let clangHeaderExposeDecls: Option = Option("-clang-header-expose-decls=", .joined, attributes: [.helpHidden, .frontend, .noDriver], metaVar: "all-public|has-expose-attr", helpText: "Which declarations should be exposed in the generated clang header.") public static let clangHeaderExposeModule: Option = Option("-clang-header-expose-module", .separate, attributes: [.helpHidden, .frontend, .noDriver], metaVar: "=", helpText: "Allow the compiler to assume that APIs from the specified module are exposed to C/C++/Objective-C in another generated header, so that APIs in the current module that depend on declarations from the specified module can be exposed in the generated header.") public static let clangIncludeTreeRoot: Option = Option("-clang-include-tree-root", .separate, attributes: [.helpHidden, .frontend, .noDriver], metaVar: "", helpText: "Clang Include Tree CASID") + public static let clangIncludeTree: Option = Option("-clang-include-tree", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Use clang include tree") public static let clangScannerModuleCachePath: Option = Option("-clang-scanner-module-cache-path", .separate, attributes: [.frontend, .doesNotAffectIncrementalBuild, .argumentIsPath], helpText: "Specifies the Clang dependency scanner module cache path") public static let clangTarget: Option = Option("-clang-target", .separate, attributes: [.frontend], helpText: "Separately set the target we should use for internal Clang instance") public static let codeCompleteCallPatternHeuristics: Option = Option("-code-complete-call-pattern-heuristics", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Use heuristics to guess whether we want call pattern completions") @@ -114,6 +114,7 @@ extension Option { public static let debugForbidTypecheckPrefix: Option = Option("-debug-forbid-typecheck-prefix", .separate, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Triggers llvm fatal_error if typechecker tries to typecheck a decl with the provided prefix name") public static let debugGenericSignatures: Option = Option("-debug-generic-signatures", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Debug generic signatures") public static let debugInfoFormat: Option = Option("-debug-info-format=", .joined, attributes: [.frontend], helpText: "Specify the debug info format type to either 'dwarf' or 'codeview'") + public static let dwarfVersion: Option = Option("-dwarf-version=", .joined, attributes: [.frontend], helpText: "DWARF debug info version to produce if requested") public static let debugInfoStoreInvocation: Option = Option("-debug-info-store-invocation", .flag, attributes: [.frontend], helpText: "Emit the compiler invocation in the debug info.") public static let debugMapping: Option = Option("-debug-mapping", .flag, attributes: [.noDriver], helpText: "Dumping information for debug purposes") public static let debugMapping_: Option = Option("--debug-mapping", .flag, alias: Option.debugMapping, attributes: [.noDriver], helpText: "Dumping information for debug purposes") @@ -277,7 +278,6 @@ extension Option { public static let dumpTypeRefinementContexts: Option = Option("-dump-type-refinement-contexts", .flag, attributes: [.frontend, .noInteractive, .doesNotAffectIncrementalBuild], helpText: "Type-check input file(s) and dump type refinement contexts(s)", group: .modes) public static let dumpTypeWitnessSystems: Option = Option("-dump-type-witness-systems", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Enables dumping type witness systems from associated type inference") public static let dumpUsr: Option = Option("-dump-usr", .flag, attributes: [.frontend, .noInteractive], helpText: "Dump USR for each declaration reference") - public static let dwarfVersion: Option = Option("-dwarf-version=", .joined, attributes: [.frontend], metaVar: "", helpText: "DWARF debug info version to produce if requested") public static let D: Option = Option("-D", .joinedOrSeparate, attributes: [.frontend], helpText: "Marks a conditional compilation flag as true") public static let embedBitcodeMarker: Option = Option("-embed-bitcode-marker", .flag, attributes: [.frontend, .noInteractive], helpText: "Embed placeholder LLVM IR data as a marker") public static let embedBitcode: Option = Option("-embed-bitcode", .flag, attributes: [.frontend, .noInteractive], helpText: "Embed LLVM IR bitcode as data") @@ -584,7 +584,6 @@ extension Option { public static let module: Option = Option("-module", .separate, attributes: [.noDriver], metaVar: "", helpText: "Names of modules") public static let module_: Option = Option("--module", .separate, alias: Option.module, attributes: [.noDriver], metaVar: "", helpText: "Names of modules") public static let newDriverPath: Option = Option("-new-driver-path", .separate, attributes: [.helpHidden, .frontend, .noDriver], metaVar: "", helpText: "Path of the new driver to be used") - public static let noClangIncludeTree: Option = Option("-no-clang-include-tree", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Do not use clang include tree, fallback to use CAS filesystem to build clang modules") public static let noClangModuleBreadcrumbs: Option = Option("-no-clang-module-breadcrumbs", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Don't emit DWARF skeleton CUs for imported Clang modules. Use this when building a redistributable static archive.") public static let noColorDiagnostics: Option = Option("-no-color-diagnostics", .flag, attributes: [.frontend, .doesNotAffectIncrementalBuild], helpText: "Do not print diagnostics in color") public static let noEmitModuleSeparatelyWMO: Option = Option("-no-emit-module-separately-wmo", .flag, attributes: [.helpHidden], helpText: "Force emitting the swiftmodule in the same job in wmo builds") @@ -616,7 +615,7 @@ extension Option { public static let O: Option = Option("-O", .flag, attributes: [.frontend, .moduleInterface], helpText: "Compile with optimizations", group: .O) public static let o: Option = Option("-o", .joinedOrSeparate, attributes: [.frontend, .noInteractive, .autolinkExtract, .moduleWrap, .indent, .argumentIsPath, .cacheInvariant], metaVar: "", helpText: "Write output to ") public static let packageDescriptionVersion: Option = Option("-package-description-version", .separate, attributes: [.helpHidden, .frontend, .moduleInterface], metaVar: "", helpText: "The version number to be applied on the input for the PackageDescription availability kind") - public static let packageName: Option = Option("-package-name", .separate, attributes: [.frontend, .moduleInterface], helpText: "Name of the package the module belongs to") + public static let packageName: Option = Option("-package-name", .separate, attributes: [.frontend], helpText: "Name of the package the module belongs to") public static let parallelScan: Option = Option("-parallel-scan", .flag, attributes: [.frontend, .noDriver], helpText: "Perform dependency scanning in-parallel.") public static let parseAsLibrary: Option = Option("-parse-as-library", .flag, attributes: [.frontend, .noInteractive], helpText: "Parse the input file(s) as libraries, not scripts") public static let parseSil: Option = Option("-parse-sil", .flag, attributes: [.frontend, .noInteractive], helpText: "Parse the input file as SIL code, not Swift source") @@ -855,7 +854,6 @@ extension Option { Option.analyzeRequirementMachine, Option.apiDiffDataDir, Option.apiDiffDataFile, - Option.enableAppExtensionLibrary, Option.enableAppExtension, Option.AssertConfig, Option.AssumeSingleThreaded, @@ -902,6 +900,7 @@ extension Option { Option.clangHeaderExposeDecls, Option.clangHeaderExposeModule, Option.clangIncludeTreeRoot, + Option.clangIncludeTree, Option.clangScannerModuleCachePath, Option.clangTarget, Option.codeCompleteCallPatternHeuristics, @@ -936,6 +935,7 @@ extension Option { Option.debugForbidTypecheckPrefix, Option.debugGenericSignatures, Option.debugInfoFormat, + Option.dwarfVersion, Option.debugInfoStoreInvocation, Option.debugMapping, Option.debugMapping_, @@ -1099,7 +1099,6 @@ extension Option { Option.dumpTypeRefinementContexts, Option.dumpTypeWitnessSystems, Option.dumpUsr, - Option.dwarfVersion, Option.D, Option.embedBitcodeMarker, Option.embedBitcode, @@ -1406,7 +1405,6 @@ extension Option { Option.module, Option.module_, Option.newDriverPath, - Option.noClangIncludeTree, Option.noClangModuleBreadcrumbs, Option.noColorDiagnostics, Option.noEmitModuleSeparatelyWMO, diff --git a/Tests/SwiftDriverTests/CachingBuildTests.swift b/Tests/SwiftDriverTests/CachingBuildTests.swift index dd0f34713..0d5878def 100644 --- a/Tests/SwiftDriverTests/CachingBuildTests.swift +++ b/Tests/SwiftDriverTests/CachingBuildTests.swift @@ -75,63 +75,6 @@ throws { dependencyGraph: dependencyGraph) } -/// Checks that the output keys are in the action cache and also the output -/// can be replayed from CAS and identicial to the original output. -private func checkCASForResults(jobs: [Job], cas: SwiftScanCAS, fs: FileSystem) throws { - let expectation = XCTestExpectation(description: "Check CAS for output") - @Sendable - func replayAndVerifyOutput(_ job: Job, _ compilations: [CachedCompilation]) async throws { - func hashFile(_ file: VirtualPath) throws -> String { - // store the content in the CAS as a hashing function. - return try fs.readFileContents(file).withData { - try cas.store(data: $0) - } - } - let outputHashes = try job.outputs.map { - let hash = try hashFile($0.file) - // remove the original output after hashing the file. - try fs.removeFileTree($0.file) - return hash - } - let resolver = try ArgsResolver(fileSystem: fs) - let arguments: [String] = try resolver.resolveArgumentList(for: job.commandLine) - let instance = try cas.createReplayInstance(commandLine: arguments) - for compilation in compilations { - let _ = try cas.replayCompilation(instance: instance, compilation: compilation) - } - let replayHashes = try job.outputs.map { - try hashFile($0.file) - } - XCTAssertEqual(outputHashes, replayHashes, "replayed output is not identical to original") - } - Task { - defer { - expectation.fulfill() - } - for job in jobs { - if !job.kind.supportCaching { - continue - } - var compilations = [CachedCompilation]() - for (_, key) in job.outputCacheKeys { - if let compilation = try await cas.queryCacheKey(key, globally: false) { - for output in compilation { - XCTAssertTrue(output.isMaterialized, "Cached output not founded in CAS") - let success = try await output.load() - XCTAssertTrue(success, "Cached output not founded in CAS") - } - compilations.append(compilation) - } else { - XCTFail("Cached entry not found") - } - } - try await replayAndVerifyOutput(job, compilations) - } - } - let result = XCTWaiter.wait(for: [expectation], timeout: 10.0) - XCTAssertEqual(result, .completed) -} - /// Checks that the build job for the specified module contains the required options and inputs /// to build all of its dependencies explicitly private func checkCachingBuildJobDependencies(job: Job, @@ -163,6 +106,8 @@ private func checkCachingBuildJobDependencies(job: Job, XCTAssertTrue(job.inputs.contains(clangDependencyModuleMapPath)) XCTAssertTrue(job.commandLine.contains( .flag(String("-fmodule-file=\(dependencyId.moduleName)=\(clangDependencyModulePathString)")))) + XCTAssertTrue(job.commandLine.contains( + .flag(String("-fmodule-map-file=\(clangDependencyDetails.moduleMapPath.path.description)")))) XCTAssertTrue(job.commandLine.contains( .flag(String("-fmodule-file-cache-key")))) let cacheKey = try XCTUnwrap(clangDependencyDetails.moduleCacheKey) @@ -223,8 +168,16 @@ final class CachingBuildTests: XCTestCase { "-cache-compile-job", "-cas-path", casPath.nativePathString(escaped: true), "-import-objc-header", bridgingHeaderpath.nativePathString(escaped: true), main.nativePathString(escaped: true)] + sdkArgumentsForTesting) - guard driver.isFeatureSupported(.cache_compile_job) else { - throw XCTSkip("toolchain does not support caching.") + let dependencyOracle = InterModuleDependencyOracle() + let scanLibPath = try XCTUnwrap(driver.toolchain.lookupSwiftScanLib()) + guard try dependencyOracle + .verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) else { + XCTFail("Dependency scanner library not found") + return + } + guard try dependencyOracle.supportsCaching() else { + throw XCTSkip("libSwiftScan does not support caching.") } let jobs = try driver.planBuild() @@ -350,8 +303,16 @@ final class CachingBuildTests: XCTestCase { guard driver.supportExplicitModuleVerifyInterface() else { throw XCTSkip("-typecheck-module-from-interface doesn't support explicit build.") } - guard driver.isFeatureSupported(.cache_compile_job) else { - throw XCTSkip("toolchain does not support caching.") + let dependencyOracle = InterModuleDependencyOracle() + let scanLibPath = try XCTUnwrap(driver.toolchain.lookupSwiftScanLib()) + guard try dependencyOracle + .verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) else { + XCTFail("Dependency scanner library not found") + return + } + guard try dependencyOracle.supportsCaching() else { + throw XCTSkip("libSwiftScan does not support caching.") } let jobs = try driver.planBuild() @@ -481,17 +442,20 @@ final class CachingBuildTests: XCTestCase { "-working-directory", path.nativePathString(escaped: true), main.nativePathString(escaped: true)] + sdkArgumentsForTesting, env: ProcessEnv.vars) - guard driver.isFeatureSupported(.cache_compile_job) else { - throw XCTSkip("toolchain does not support caching.") + let dependencyOracle = InterModuleDependencyOracle() + let scanLibPath = try XCTUnwrap(driver.toolchain.lookupSwiftScanLib()) + guard try dependencyOracle + .verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) else { + XCTFail("Dependency scanner library not found") + return + } + guard try dependencyOracle.supportsCaching() else { + throw XCTSkip("libSwiftScan does not support caching.") } let jobs = try driver.planBuild() try driver.run(jobs: jobs) XCTAssertFalse(driver.diagnosticEngine.hasErrors) - guard let cas = driver.cas else { - XCTFail("CAS is not available") - return - } - try checkCASForResults(jobs: jobs, cas: cas, fs: driver.fileSystem) } } @@ -536,9 +500,6 @@ final class CachingBuildTests: XCTestCase { env: ProcessEnv.vars) // Ensure this tooling supports this functionality - guard fooBuildDriver.isFeatureSupported(.cache_compile_job) else { - throw XCTSkip("toolchain does not support caching.") - } let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(fooBuildDriver.toolchain.lookupSwiftScanLib()) guard try dependencyOracle @@ -550,6 +511,9 @@ final class CachingBuildTests: XCTestCase { guard try dependencyOracle.supportsBinaryModuleHeaderDependencies() else { throw XCTSkip("libSwiftScan does not support binary module header dependencies.") } + guard try dependencyOracle.supportsCaching() else { + throw XCTSkip("libSwiftScan does not support caching.") + } let fooJobs = try fooBuildDriver.planBuild() try fooBuildDriver.run(jobs: fooJobs) @@ -597,9 +561,6 @@ final class CachingBuildTests: XCTestCase { "-disable-clang-target", main.nativePathString(escaped: true)] + sdkArgumentsForTesting, env: ProcessEnv.vars) - guard driver.isFeatureSupported(.cache_compile_job) else { - throw XCTSkip("toolchain does not support caching.") - } let dependencyOracle = InterModuleDependencyOracle() let scanLibPath = try XCTUnwrap(driver.toolchain.lookupSwiftScanLib()) guard try dependencyOracle @@ -608,6 +569,9 @@ final class CachingBuildTests: XCTestCase { XCTFail("Dependency scanner library not found") return } + guard try dependencyOracle.supportsCaching() else { + throw XCTSkip("libSwiftScan does not support caching.") + } 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 @@ -697,68 +661,4 @@ final class CachingBuildTests: XCTestCase { XCTAssertEqual(diags[0].message, "CAS error encountered: conflicting CAS options used in scanning service") } } - - func testDependencyScanningPathRemap() throws { - // Create a simple test case. - try withTemporaryDirectory { path in - let main = path.appending(component: "testDependencyScanning.swift") - try localFileSystem.writeFileContents(main) { - $0.send("import C;") - $0.send("import E;") - $0.send("import G;") - } - - let cHeadersPath: AbsolutePath = - try testInputsPath.appending(component: "ExplicitModuleBuilds") - .appending(component: "CHeaders") - let swiftModuleInterfacesPath: AbsolutePath = - try testInputsPath.appending(component: "ExplicitModuleBuilds") - .appending(component: "Swift") - let casPath = path.appending(component: "cas") - let sdkArgumentsForTesting = (try? Driver.sdkArgumentsForTesting()) ?? [] - var driver = try Driver(args: ["swiftc", - "-I", cHeadersPath.nativePathString(escaped: true), - "-I", swiftModuleInterfacesPath.nativePathString(escaped: true), - "/tmp/Foo.o", "-v", - "-explicit-module-build", - "-cache-compile-job", "-cas-path", casPath.nativePathString(escaped: true), - "-working-directory", path.nativePathString(escaped: true), - "-disable-clang-target", "-scanner-prefix-map-sdk", "/^sdk", - "-scanner-prefix-map-toolchain", "/^toolchain", - "-scanner-prefix-map", testInputsPath.description + "=/^src", - "-scanner-prefix-map", path.description + "=/^tmp", - main.nativePathString(escaped: true)] + sdkArgumentsForTesting, - env: ProcessEnv.vars) - guard driver.isFrontendArgSupported(.scannerPrefixMap) else { - throw XCTSkip("frontend doesn't support prefix map") - } - let dependencyOracle = InterModuleDependencyOracle() - let scanLibPath = try XCTUnwrap(driver.toolchain.lookupSwiftScanLib()) - guard try dependencyOracle - .verifyOrCreateScannerInstance(fileSystem: localFileSystem, - swiftScanLibPath: scanLibPath) else { - XCTFail("Dependency scanner library not found") - return - } - let resolver = try ArgsResolver(fileSystem: localFileSystem) - let scannerCommand = try driver.dependencyScannerInvocationCommand().1.map { try resolver.resolve($0) } - - XCTAssertTrue(scannerCommand.contains("-scanner-prefix-map")) - XCTAssertTrue(scannerCommand.contains(try testInputsPath.description + "=/^src")) - - let jobs = try driver.planBuild() - for job in jobs { - if !job.kind.supportCaching { - continue - } - let command = try job.commandLine.map { try resolver.resolve($0) } - // Check all the arguments that are in the temporary directory are remapped. - // The only one that is not remapped should be the `-cas-path` that points to - // `casPath`. - XCTAssertFalse(command.contains { - return $0.starts(with: path.description) && $0 != casPath.description - }) - } - } - } }