Skip to content

Commit be09eb4

Browse files
Merge pull request #1453 from cachemeifyoucan/eng/PR-swift-driver-path-remap-and-replay
[SwiftDriver] PathRemapping and Cache Replay Support
2 parents 14226b3 + 2de866d commit be09eb4

21 files changed

+978
-258
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ $ apt-get install libncurses-dev
156156
be found, e.g.:
157157

158158
```
159-
$ 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
159+
$ 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
160160
```
161161

162162
Then, run `makeOptions` and redirect the output to overwrite `Options.swift`:

Sources/CSwiftScan/include/swiftscan_header.h

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#include <stdint.h>
1919

2020
#define SWIFTSCAN_VERSION_MAJOR 0
21-
#define SWIFTSCAN_VERSION_MINOR 5
21+
#define SWIFTSCAN_VERSION_MINOR 6
2222

2323
//=== Public Scanner Data Types -------------------------------------------===//
2424

@@ -78,17 +78,15 @@ typedef struct swiftscan_scan_invocation_s *swiftscan_scan_invocation_t;
7878
typedef void *swiftscan_scanner_t;
7979

8080
//=== CAS/Caching Specification -------------------------------------------===//
81-
typedef struct swiftscan_cas_s *swiftscan_cas_t;
8281
typedef struct swiftscan_cas_options_s *swiftscan_cas_options_t;
83-
84-
typedef enum {
85-
SWIFTSCAN_OUTPUT_TYPE_OBJECT = 0,
86-
SWIFTSCAN_OUTPUT_TYPE_SWIFTMODULE = 1,
87-
SWIFTSCAN_OUTPUT_TYPE_SWIFTINTERFACE = 2,
88-
SWIFTSCAN_OUTPUT_TYPE_SWIFTPRIVATEINTERFACE = 3,
89-
SWIFTSCAN_OUTPUT_TYPE_CLANG_MODULE = 4,
90-
SWIFTSCAN_OUTPUT_TYPE_CLANG_PCH = 5
91-
} swiftscan_output_kind_t;
82+
typedef struct swiftscan_cas_s *swiftscan_cas_t;
83+
typedef struct swiftscan_cached_compilation_s *swiftscan_cached_compilation_t;
84+
typedef struct swiftscan_cached_output_s *swiftscan_cached_output_t;
85+
typedef struct swiftscan_cache_replay_instance_s
86+
*swiftscan_cache_replay_instance_t;
87+
typedef struct swiftscan_cache_replay_result_s *swiftscan_cache_replay_result_t;
88+
typedef struct swiftscan_cache_cancellation_token_s
89+
*swiftscan_cache_cancellation_token_t;
9290

9391
//=== libSwiftScan Functions ------------------------------------------------===//
9492

@@ -281,18 +279,74 @@ typedef struct {
281279
const char *path);
282280
void (*swiftscan_cas_options_set_plugin_path)(swiftscan_cas_options_t options,
283281
const char *path);
284-
bool (*swiftscan_cas_options_set_option)(swiftscan_cas_options_t options,
285-
const char *name, const char *value,
286-
swiftscan_string_ref_t *error);
282+
bool (*swiftscan_cas_options_set_plugin_option)(
283+
swiftscan_cas_options_t options, const char *name, const char *value,
284+
swiftscan_string_ref_t *error);
287285
swiftscan_cas_t (*swiftscan_cas_create_from_options)(
288286
swiftscan_cas_options_t options, swiftscan_string_ref_t *error);
289287
void (*swiftscan_cas_dispose)(swiftscan_cas_t cas);
290288
swiftscan_string_ref_t (*swiftscan_cas_store)(swiftscan_cas_t cas,
291289
uint8_t *data, unsigned size,
292290
swiftscan_string_ref_t *error);
293-
swiftscan_string_ref_t (*swiftscan_compute_cache_key)(
294-
swiftscan_cas_t cas, int argc, const char *argv, const char *input,
295-
swiftscan_output_kind_t, swiftscan_string_ref_t *error);
291+
swiftscan_string_ref_t (*swiftscan_cache_compute_key)(
292+
swiftscan_cas_t cas, int argc, const char **argv, const char *input,
293+
swiftscan_string_ref_t *error);
294+
295+
//=== Scanner Caching Query/Replay Operations -----------------------------===//
296+
swiftscan_cached_compilation_t (*swiftscan_cache_query)(
297+
swiftscan_cas_t cas, const char *key, bool globally,
298+
swiftscan_string_ref_t *error);
299+
void (*swiftscan_cache_query_async)(
300+
swiftscan_cas_t cas, const char *key, bool globally, void *ctx,
301+
void (*callback)(void *ctx, swiftscan_cached_compilation_t,
302+
swiftscan_string_ref_t error),
303+
swiftscan_cache_cancellation_token_t *);
304+
305+
306+
unsigned (*swiftscan_cached_compilation_get_num_outputs)(
307+
swiftscan_cached_compilation_t);
308+
swiftscan_cached_output_t (*swiftscan_cached_compilation_get_output)(
309+
swiftscan_cached_compilation_t, unsigned idx);
310+
bool (*swiftscan_cached_compilation_is_uncacheable)(
311+
swiftscan_cached_compilation_t);
312+
void (*swiftscan_cached_compilation_make_global_async)(
313+
swiftscan_cached_compilation_t, void *ctx,
314+
void (*callback)(void *ctx, swiftscan_string_ref_t error),
315+
swiftscan_cache_cancellation_token_t *);
316+
void (*swiftscan_cached_compilation_dispose)(swiftscan_cached_compilation_t);
317+
318+
bool (*swiftscan_cached_output_load)(swiftscan_cached_output_t,
319+
swiftscan_string_ref_t *error);
320+
void (*swiftscan_cached_output_load_async)(
321+
swiftscan_cached_output_t, void *ctx,
322+
void (*callback)(void *ctx, bool success, swiftscan_string_ref_t error),
323+
swiftscan_cache_cancellation_token_t *);
324+
bool (*swiftscan_cached_output_is_materialized)(swiftscan_cached_output_t);
325+
swiftscan_string_ref_t (*swiftscan_cached_output_get_casid)(
326+
swiftscan_cached_output_t);
327+
swiftscan_string_ref_t (*swiftscan_cached_output_get_name)(
328+
swiftscan_cached_output_t);
329+
void (*swiftscan_cached_output_dispose)(swiftscan_cached_output_t);
330+
331+
void (*swiftscan_cache_action_cancel)(swiftscan_cache_cancellation_token_t);
332+
void (*swiftscan_cache_cancellation_token_dispose)(
333+
swiftscan_cache_cancellation_token_t);
334+
335+
swiftscan_cache_replay_instance_t (*swiftscan_cache_replay_instance_create)(
336+
int argc, const char **argv, swiftscan_string_ref_t *error);
337+
void (*swiftscan_cache_replay_instance_dispose)(
338+
swiftscan_cache_replay_instance_t);
339+
340+
swiftscan_cache_replay_result_t (*swiftscan_cache_replay_compilation)(
341+
swiftscan_cache_replay_instance_t, swiftscan_cached_compilation_t,
342+
swiftscan_string_ref_t *error);
343+
344+
swiftscan_string_ref_t (*swiftscan_cache_replay_result_get_stdout)(
345+
swiftscan_cache_replay_result_t);
346+
swiftscan_string_ref_t (*swiftscan_cache_replay_result_get_stderr)(
347+
swiftscan_cache_replay_result_t);
348+
void (*swiftscan_cache_replay_result_dispose)(
349+
swiftscan_cache_replay_result_t);
296350

297351
} swiftscan_functions_t;
298352

Sources/SwiftDriver/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ add_library(SwiftDriver
1818
SwiftScan/DependencyGraphBuilder.swift
1919
SwiftScan/Loader.swift
2020
SwiftScan/SwiftScan.swift
21+
SwiftScan/SwiftScanCAS.swift
2122

2223
Driver/CompilerMode.swift
2324
Driver/DebugInfo.swift

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,10 @@ public struct Driver {
224224
/// Should use file lists for inputs (number of inputs exceeds `fileListThreshold`).
225225
let shouldUseInputFileList: Bool
226226

227-
/// VirtualPath for shared all sources file list. `nil` if unused.
228-
@_spi(Testing) public let allSourcesFileList: VirtualPath?
227+
/// VirtualPath for shared all sources file list. `nil` if unused. This is used as a cache for
228+
/// the file list computed during CompileJob creation and only holds valid to be query by tests
229+
/// after planning to build.
230+
@_spi(Testing) public var allSourcesFileList: VirtualPath? = nil
229231

230232
/// The mode in which the compiler will execute.
231233
@_spi(Testing) public let compilerMode: CompilerMode
@@ -272,6 +274,43 @@ public struct Driver {
272274
let enableCaching: Bool
273275
let useClangIncludeTree: Bool
274276

277+
/// CAS instance used for compilation.
278+
public var cas: SwiftScanCAS? = nil
279+
280+
/// Is swift caching enabled.
281+
lazy var isCachingEnabled: Bool = {
282+
return enableCaching && isFeatureSupported(.cache_compile_job)
283+
}()
284+
285+
/// Scanner prefix mapping.
286+
let scannerPrefixMap: [AbsolutePath: AbsolutePath]
287+
let scannerPrefixMapSDK: AbsolutePath?
288+
let scannerPrefixMapToolchain: AbsolutePath?
289+
lazy var prefixMapping: [(AbsolutePath, AbsolutePath)] = {
290+
var mapping: [(AbsolutePath, AbsolutePath)] = scannerPrefixMap.map {
291+
return ($0.key, $0.value)
292+
}
293+
do {
294+
guard isFrontendArgSupported(.scannerPrefixMap) else {
295+
return []
296+
}
297+
if let sdkMapping = scannerPrefixMapSDK,
298+
let sdkPath = absoluteSDKPath {
299+
mapping.append((sdkPath, sdkMapping))
300+
}
301+
if let toolchainMapping = scannerPrefixMapToolchain {
302+
let toolchainPath = try toolchain.executableDir.parentDirectory // usr
303+
.parentDirectory // toolchain
304+
mapping.append((toolchainPath, toolchainMapping))
305+
}
306+
// The mapping needs to be sorted so the mapping is determinisitic.
307+
// The sorting order is reversed so /tmp/tmp is preferred over /tmp in remapping.
308+
return mapping.sorted { $0.0 > $1.0 }
309+
} catch {
310+
return mapping.sorted { $0.0 > $1.0 }
311+
}
312+
}()
313+
275314
/// Code & data for incremental compilation. Nil if not running in incremental mode.
276315
/// Set during planning because needs the jobs to look at outputs.
277316
@_spi(Testing) public private(set) var incrementalCompilationState: IncrementalCompilationState? = nil
@@ -385,6 +424,7 @@ public struct Driver {
385424
@_spi(Testing)
386425
public enum KnownCompilerFeature: String {
387426
case emit_abi_descriptor = "emit-abi-descriptor"
427+
case cache_compile_job = "cache-compile-job"
388428
}
389429

390430
lazy var sdkPath: VirtualPath? = {
@@ -597,7 +637,18 @@ public struct Driver {
597637

598638
let cachingEnableOverride = parsedOptions.hasArgument(.driverExplicitModuleBuild) && env.keys.contains("SWIFT_ENABLE_CACHING")
599639
self.enableCaching = parsedOptions.hasArgument(.cacheCompileJob) || cachingEnableOverride
600-
self.useClangIncludeTree = enableCaching && env.keys.contains("SWIFT_CACHING_USE_INCLUDE_TREE")
640+
self.useClangIncludeTree = !parsedOptions.hasArgument(.noClangIncludeTree) && !env.keys.contains("SWIFT_CACHING_USE_CLANG_CAS_FS")
641+
self.scannerPrefixMap = try Self.computeScanningPrefixMapper(&parsedOptions)
642+
if let sdkMapping = parsedOptions.getLastArgument(.scannerPrefixMapSdk)?.asSingle {
643+
self.scannerPrefixMapSDK = try AbsolutePath(validating: sdkMapping)
644+
} else {
645+
self.scannerPrefixMapSDK = nil
646+
}
647+
if let toolchainMapping = parsedOptions.getLastArgument(.scannerPrefixMapToolchain)?.asSingle {
648+
self.scannerPrefixMapToolchain = try AbsolutePath(validating: toolchainMapping)
649+
} else {
650+
self.scannerPrefixMapToolchain = nil
651+
}
601652

602653
// Compute the working directory.
603654
workingDirectory = try parsedOptions.getLastArgument(.workingDirectory).map { workingDirectoryArg in
@@ -678,13 +729,6 @@ public struct Driver {
678729

679730
self.fileListThreshold = try Self.computeFileListThreshold(&self.parsedOptions, diagnosticsEngine: diagnosticsEngine)
680731
self.shouldUseInputFileList = inputFiles.count > fileListThreshold
681-
if shouldUseInputFileList {
682-
let swiftInputs = inputFiles.filter(\.type.isPartOfSwiftCompilation)
683-
self.allSourcesFileList = try VirtualPath.createUniqueFilelist(RelativePath(validating: "sources"),
684-
.list(swiftInputs.map(\.file)))
685-
} else {
686-
self.allSourcesFileList = nil
687-
}
688732

689733
self.lto = Self.ltoKind(&parsedOptions, diagnosticsEngine: diagnosticsEngine)
690734
// Figure out the primary outputs from the driver.
@@ -3524,4 +3568,18 @@ extension Driver {
35243568
}
35253569
return options
35263570
}
3571+
3572+
static func computeScanningPrefixMapper(_ parsedOptions: inout ParsedOptions) throws -> [AbsolutePath: AbsolutePath] {
3573+
var mapping: [AbsolutePath: AbsolutePath] = [:]
3574+
for opt in parsedOptions.arguments(for: .scannerPrefixMap) {
3575+
let pluginArg = opt.argument.asSingle.split(separator: "=", maxSplits: 1)
3576+
if pluginArg.count != 2 {
3577+
throw Error.invalidArgumentValue(Option.scannerPrefixMap.spelling, opt.argument.asSingle)
3578+
}
3579+
let key = try AbsolutePath(validating: String(pluginArg[0]))
3580+
let value = try AbsolutePath(validating: String(pluginArg[1]))
3581+
mapping[key] = value
3582+
}
3583+
return mapping
3584+
}
35273585
}

Sources/SwiftDriver/Execution/ArgsResolver.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,16 @@ public final class ArgsResolver {
6565
public func resolveArgumentList(for job: Job, useResponseFiles: ResponseFileHandling = .heuristic)
6666
throws -> ([String], usingResponseFile: Bool) {
6767
let tool = try resolve(.path(job.tool))
68-
var arguments = [tool] + (try job.commandLine.map { try resolve($0) })
68+
var arguments = [tool] + (try resolveArgumentList(for: job.commandLine))
6969
let usingResponseFile = try createResponseFileIfNeeded(for: job, resolvedArguments: &arguments,
7070
useResponseFiles: useResponseFiles)
7171
return (arguments, usingResponseFile)
7272
}
7373

74+
public func resolveArgumentList(for commandLine: [Job.ArgTemplate]) throws -> [String] {
75+
return try commandLine.map { try resolve($0) }
76+
}
77+
7478
@available(*, deprecated, message: "use resolveArgumentList(for:,useResponseFiles:,quotePaths:)")
7579
public func resolveArgumentList(for job: Job, forceResponseFiles: Bool,
7680
quotePaths: Bool = false) throws -> [String] {

0 commit comments

Comments
 (0)