Skip to content

Commit 2e75932

Browse files
Merge pull request #1422 from cachemeifyoucan/eng/PR-swift-driver-plugin-cas-support
[Caching] Support pluginCAS in swiftDriver
2 parents 357be49 + bb0a153 commit 2e75932

File tree

7 files changed

+149
-42
lines changed

7 files changed

+149
-42
lines changed

Sources/CSwiftScan/include/swiftscan_header.h

Lines changed: 18 additions & 8 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 4
21+
#define SWIFTSCAN_VERSION_MINOR 5
2222

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

@@ -79,6 +79,7 @@ typedef void *swiftscan_scanner_t;
7979

8080
//=== CAS/Caching Specification -------------------------------------------===//
8181
typedef struct swiftscan_cas_s *swiftscan_cas_t;
82+
typedef struct swiftscan_cas_options_s *swiftscan_cas_options_t;
8283

8384
typedef enum {
8485
SWIFTSCAN_OUTPUT_TYPE_OBJECT = 0,
@@ -274,15 +275,24 @@ typedef struct {
274275
void (*swiftscan_scanner_cache_reset)(swiftscan_scanner_t scanner);
275276

276277
//=== Scanner CAS Operations ----------------------------------------------===//
277-
swiftscan_cas_t (*swiftscan_cas_create)(const char *path);
278+
swiftscan_cas_options_t (*swiftscan_cas_options_create)(void);
279+
void (*swiftscan_cas_options_dispose)(swiftscan_cas_options_t options);
280+
void (*swiftscan_cas_options_set_ondisk_path)(swiftscan_cas_options_t options,
281+
const char *path);
282+
void (*swiftscan_cas_options_set_plugin_path)(swiftscan_cas_options_t options,
283+
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);
287+
swiftscan_cas_t (*swiftscan_cas_create_from_options)(
288+
swiftscan_cas_options_t options, swiftscan_string_ref_t *error);
278289
void (*swiftscan_cas_dispose)(swiftscan_cas_t cas);
279290
swiftscan_string_ref_t (*swiftscan_cas_store)(swiftscan_cas_t cas,
280-
uint8_t *data, unsigned size);
281-
swiftscan_string_ref_t (*swiftscan_compute_cache_key)(swiftscan_cas_t cas,
282-
int argc,
283-
const char *argv,
284-
const char *input,
285-
swiftscan_output_kind_t);
291+
uint8_t *data, unsigned size,
292+
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);
286296

287297
} swiftscan_functions_t;
288298

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,6 @@ public struct Driver {
270270
/// CAS/Caching related options.
271271
let enableCaching: Bool
272272
let useClangIncludeTree: Bool
273-
let casPath: String
274273

275274
/// Code & data for incremental compilation. Nil if not running in incremental mode.
276275
/// Set during planning because needs the jobs to look at outputs.
@@ -595,13 +594,6 @@ public struct Driver {
595594
let cachingEnableOverride = parsedOptions.hasArgument(.driverExplicitModuleBuild) && env.keys.contains("SWIFT_ENABLE_CACHING")
596595
self.enableCaching = parsedOptions.hasArgument(.cacheCompileJob) || cachingEnableOverride
597596
self.useClangIncludeTree = enableCaching && env.keys.contains("SWIFT_CACHING_USE_INCLUDE_TREE")
598-
if let casPathOpt = parsedOptions.getLastArgument(.casPath)?.asSingle {
599-
self.casPath = casPathOpt.description
600-
} else if let cacheEnv = env["CCHROOT"] {
601-
self.casPath = cacheEnv
602-
} else {
603-
self.casPath = ""
604-
}
605597

606598
// Compute the working directory.
607599
workingDirectory = try parsedOptions.getLastArgument(.workingDirectory).map { workingDirectoryArg in
@@ -3470,3 +3462,32 @@ extension Driver {
34703462
return try VirtualPath.intern(path: moduleName.appendingFileTypeExtension(type))
34713463
}
34723464
}
3465+
3466+
// CAS and Caching.
3467+
extension Driver {
3468+
mutating func getCASPluginPath() throws -> AbsolutePath? {
3469+
if let pluginOpt = parsedOptions.getLastArgument(.casPluginOption)?.asSingle {
3470+
return try AbsolutePath(validating: pluginOpt.description)
3471+
}
3472+
return try toolchain.lookupToolchainCASPluginLib()
3473+
}
3474+
3475+
mutating func getOnDiskCASPath() throws -> AbsolutePath? {
3476+
if let casPathOpt = parsedOptions.getLastArgument(.casPath)?.asSingle {
3477+
return try AbsolutePath(validating: casPathOpt.description)
3478+
}
3479+
return nil;
3480+
}
3481+
3482+
mutating func getCASPluginOptions() throws -> [(String, String)] {
3483+
var options : [(String, String)] = []
3484+
for opt in parsedOptions.arguments(for: .casPluginOption) {
3485+
let pluginArg = opt.argument.asSingle.split(separator: "=", maxSplits: 1)
3486+
if pluginArg.count != 2 {
3487+
throw Error.invalidArgumentValue(Option.casPluginOption.spelling, opt.argument.asSingle)
3488+
}
3489+
options.append((String(pluginArg[0]), String(pluginArg[1])))
3490+
}
3491+
return options
3492+
}
3493+
}

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,11 @@ public class InterModuleDependencyOracle {
171171
return diags.isEmpty ? nil : diags
172172
}
173173

174-
public func createCAS(path: String) throws {
174+
public func createCAS(pluginPath: AbsolutePath?, onDiskPath: AbsolutePath?, pluginOptions: [(String, String)]) throws {
175175
guard let swiftScan = swiftScanLibInstance else {
176176
fatalError("Attempting to reset scanner cache with no scanner instance.")
177177
}
178-
try swiftScan.createCAS(casPath: path)
178+
try swiftScan.createCAS(pluginPath: pluginPath?.pathString, onDiskPath: onDiskPath?.pathString, pluginOptions: pluginOptions)
179179
}
180180

181181
public func store(data: Data) throws -> String {

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,9 @@ public extension Driver {
167167
}
168168
}
169169
if !fallbackToFrontend && enableCaching {
170-
try interModuleDependencyOracle.createCAS(path: casPath)
170+
try interModuleDependencyOracle.createCAS(pluginPath: try getCASPluginPath(),
171+
onDiskPath: try getOnDiskCASPath(),
172+
pluginOptions: try getCASPluginOptions())
171173
}
172174
return fallbackToFrontend
173175
}

Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -336,13 +336,16 @@ extension Driver {
336336
// CAS related options.
337337
if enableCaching {
338338
commandLine.appendFlag(.cacheCompileJob)
339-
if !casPath.isEmpty {
339+
if let casPath = try getOnDiskCASPath() {
340340
commandLine.appendFlag(.casPath)
341-
commandLine.appendFlag(casPath)
341+
commandLine.appendFlag(casPath.pathString)
342+
}
343+
if let pluginPath = try getCASPluginPath() {
344+
commandLine.appendFlag(.casPluginPath)
345+
commandLine.appendFlag(pluginPath.pathString)
342346
}
343-
try commandLine.appendLast(.cacheRemarks, from: &parsedOptions)
344-
try commandLine.appendLast(.casPluginPath, from: &parsedOptions)
345347
try commandLine.appendAll(.casPluginOption, from: &parsedOptions)
348+
try commandLine.appendLast(.cacheRemarks, from: &parsedOptions)
346349
}
347350
if useClangIncludeTree {
348351
commandLine.appendFlag(.clangIncludeTree)

Sources/SwiftDriver/SwiftScan/SwiftScan.swift

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public enum DependencyScanningError: Error, DiagnosticData {
2525
case missingRequiredSymbol(String)
2626
case dependencyScanFailed
2727
case failedToInstantiateScanner
28-
case failedToInstantiateCAS
28+
case casError(String)
2929
case missingField(String)
3030
case moduleNameDecodeFailure(String)
3131
case unsupportedDependencyDetailsKind(Int)
@@ -42,8 +42,8 @@ public enum DependencyScanningError: Error, DiagnosticData {
4242
return "libSwiftScan dependency scan query failed"
4343
case .failedToInstantiateScanner:
4444
return "libSwiftScan failed to create scanner instance"
45-
case .failedToInstantiateCAS:
46-
return "libSwiftScan failed to create CAS"
45+
case .casError(let reason):
46+
return "libSwiftScan CAS error: \(reason)"
4747
case .missingField(let fieldName):
4848
return "libSwiftScan scan result missing required field: `\(fieldName)`"
4949
case .moduleNameDecodeFailure(let encodedName):
@@ -285,7 +285,12 @@ internal extension swiftscan_diagnostic_severity_t {
285285
// Caching is currently not supported on Windows hosts.
286286
return false
287287
#else
288-
return api.swiftscan_cas_create != nil &&
288+
return api.swiftscan_cas_options_create != nil &&
289+
api.swiftscan_cas_options_dispose != nil &&
290+
api.swiftscan_cas_options_set_ondisk_path != nil &&
291+
api.swiftscan_cas_options_set_plugin_path != nil &&
292+
api.swiftscan_cas_options_set_option != nil &&
293+
api.swiftscan_cas_create_from_options != nil &&
289294
api.swiftscan_cas_dispose != nil &&
290295
api.swiftscan_compute_cache_key != nil &&
291296
api.swiftscan_cas_store != nil &&
@@ -387,20 +392,48 @@ internal extension swiftscan_diagnostic_severity_t {
387392
}
388393
}
389394

390-
func createCAS(casPath: String) throws {
391-
self.cas = api.swiftscan_cas_create(casPath.cString(using: String.Encoding.utf8))
392-
guard self.cas != nil else {
393-
throw DependencyScanningError.failedToInstantiateCAS
395+
private func handleCASError(_ closure: (inout swiftscan_string_ref_t) -> Bool) throws {
396+
var err_msg : swiftscan_string_ref_t = swiftscan_string_ref_t()
397+
guard !closure(&err_msg) else {
398+
let err_str = try toSwiftString(err_msg)
399+
api.swiftscan_string_dispose(err_msg)
400+
throw DependencyScanningError.casError(err_str)
401+
}
402+
}
403+
404+
func createCAS(pluginPath: String?, onDiskPath: String?, pluginOptions: [(String, String)]) throws {
405+
let casOpts = api.swiftscan_cas_options_create()
406+
defer {
407+
api.swiftscan_cas_options_dispose(casOpts)
408+
}
409+
if let path = pluginPath {
410+
api.swiftscan_cas_options_set_plugin_path(casOpts, path)
411+
}
412+
if let path = onDiskPath {
413+
api.swiftscan_cas_options_set_ondisk_path(casOpts, path)
414+
}
415+
for (name, value) in pluginOptions {
416+
try handleCASError { err_msg in
417+
return api.swiftscan_cas_options_set_option(casOpts, name, value, &err_msg)
418+
}
419+
}
420+
try handleCASError { err_msg in
421+
self.cas = api.swiftscan_cas_create_from_options(casOpts, &err_msg)
422+
return self.cas == nil
394423
}
395424
}
396425

397426
func store(data: Data) throws -> String {
398427
guard let scan_cas = self.cas else {
399-
throw DependencyScanningError.failedToInstantiateCAS
428+
throw DependencyScanningError.casError("cannot store into CAS because CAS is not yet created")
400429
}
401430
let bytes = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
402431
data.copyBytes(to: bytes, count: data.count)
403-
let casid = api.swiftscan_cas_store(scan_cas, bytes, UInt32(data.count))
432+
var casid: swiftscan_string_ref_t = swiftscan_string_ref_t()
433+
try handleCASError { err_msg in
434+
casid = api.swiftscan_cas_store(scan_cas, bytes, UInt32(data.count), &err_msg)
435+
return casid.data == nil
436+
}
404437
return try toSwiftString(casid)
405438
}
406439

@@ -425,15 +458,19 @@ internal extension swiftscan_diagnostic_severity_t {
425458

426459
func computeCacheKeyForOutput(kind: FileType, commandLine: [String], input: String) throws -> String {
427460
guard let scan_cas = self.cas else {
428-
throw DependencyScanningError.failedToInstantiateCAS
461+
throw DependencyScanningError.casError("cannot compute CacheKey for compilation because CAS is not yet created")
429462
}
430-
var casid : swiftscan_string_ref_t = swiftscan_string_ref_t()
431-
withArrayOfCStrings(commandLine) { commandArray in
432-
casid = api.swiftscan_compute_cache_key(scan_cas,
433-
Int32(commandLine.count),
434-
commandArray,
435-
input.cString(using: String.Encoding.utf8),
436-
getSwiftScanOutputKind(kind: kind))
463+
var casid: swiftscan_string_ref_t = swiftscan_string_ref_t()
464+
try handleCASError { err_msg in
465+
withArrayOfCStrings(commandLine) { commandArray in
466+
casid = api.swiftscan_compute_cache_key(scan_cas,
467+
Int32(commandLine.count),
468+
commandArray,
469+
input.cString(using: String.Encoding.utf8),
470+
getSwiftScanOutputKind(kind: kind),
471+
&err_msg)
472+
}
473+
return casid.data == nil
437474
}
438475
return try toSwiftString(casid)
439476
}
@@ -518,7 +555,12 @@ private extension swiftscan_functions_t {
518555
self.swiftscan_clang_detail_get_module_cache_key =
519556
try loadOptional("swiftscan_clang_detail_get_module_cache_key")
520557

521-
self.swiftscan_cas_create = try loadOptional("swiftscan_cas_create")
558+
self.swiftscan_cas_options_create = try loadOptional("swiftscan_cas_options_create")
559+
self.swiftscan_cas_options_set_plugin_path = try loadOptional("swiftscan_cas_options_set_plugin_path")
560+
self.swiftscan_cas_options_set_ondisk_path = try loadOptional("swiftscan_cas_options_set_ondisk_path")
561+
self.swiftscan_cas_options_set_option = try loadOptional("swiftscan_cas_options_set_option")
562+
self.swiftscan_cas_options_dispose = try loadOptional("swiftscan_cas_options_dispose")
563+
self.swiftscan_cas_create_from_options = try loadOptional("swiftscan_cas_create_from_options")
522564
self.swiftscan_cas_dispose = try loadOptional("swiftscan_cas_dispose")
523565
self.swiftscan_compute_cache_key =
524566
try loadOptional("swiftscan_compute_cache_key")

Sources/SwiftDriver/Toolchains/Toolchain.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,35 @@ extension Toolchain {
284284
#endif
285285
}
286286

287+
/// Looks for the executable in the `SWIFT_DRIVER_TOOLCHAIN_CASPLUGIN_LIB` environment variable, if found nothing,
288+
/// looks in the `lib` relative to the compiler executable.
289+
@_spi(Testing) public func lookupToolchainCASPluginLib() throws -> AbsolutePath? {
290+
if let overrideString = env["SWIFT_DRIVER_TOOLCHAIN_CASPLUGIN_LIB"],
291+
let path = try? AbsolutePath(validating: overrideString) {
292+
return path
293+
}
294+
#if os(Windows)
295+
return nil
296+
#else
297+
// Try to look for libToolchainCASPlugin in the developer dir, if found,
298+
// prefer using that. Otherwise, just return nil, and auto fallback to
299+
// builtin CAS.
300+
let libraryName = sharedLibraryName("libToolchainCASPlugin")
301+
let compilerPath = try getToolPath(.swiftCompiler)
302+
let developerPath = compilerPath.parentDirectory // bin
303+
.parentDirectory // toolchain root
304+
.parentDirectory // toolchains
305+
.parentDirectory // developer
306+
let libraryPath = developerPath.appending(component: "usr")
307+
.appending(component: "lib")
308+
.appending(component: libraryName)
309+
if fileSystem.isFile(libraryPath) {
310+
return libraryPath
311+
}
312+
return nil
313+
#endif
314+
}
315+
287316
private func xcrunFind(executable: String) throws -> AbsolutePath {
288317
let xcrun = "xcrun"
289318
guard lookupExecutablePath(filename: xcrun, searchPaths: searchPaths) != nil else {

0 commit comments

Comments
 (0)