@@ -45,6 +45,8 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
45
45
/// Whether we are using the integrated driver via libSwiftDriver shared lib
46
46
private let integratedDriver : Bool
47
47
private let mainModuleName : String ?
48
+ private let enableCAS : Bool
49
+ private let swiftScanOracle : InterModuleDependencyOracle
48
50
49
51
/// Clang PCM names contain a hash of the command-line arguments that were used to build them.
50
52
/// We avoid re-running the hash computation with the use of this cache
@@ -55,14 +57,23 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
55
57
56
58
public init ( dependencyGraph: InterModuleDependencyGraph ,
57
59
toolchain: Toolchain ,
60
+ dependencyOracle: InterModuleDependencyOracle ,
58
61
integratedDriver: Bool = true ,
59
- supportsExplicitInterfaceBuild: Bool = false ) throws {
62
+ supportsExplicitInterfaceBuild: Bool = false ,
63
+ enableCAS: Bool = false ) throws {
60
64
self . dependencyGraph = dependencyGraph
61
65
self . toolchain = toolchain
66
+ self . swiftScanOracle = dependencyOracle
62
67
self . integratedDriver = integratedDriver
63
68
self . mainModuleName = dependencyGraph. mainModuleName
64
69
self . reachabilityMap = try dependencyGraph. computeTransitiveClosure ( )
65
70
self . supportsExplicitInterfaceBuild = supportsExplicitInterfaceBuild
71
+ self . enableCAS = enableCAS
72
+ }
73
+
74
+ /// Supports resolving bridging header pch command from swiftScan.
75
+ public func supportsBridgingHeaderPCHCommand( ) throws -> Bool {
76
+ return try swiftScanOracle. supportsBridgingHeaderPCHCommand ( )
66
77
}
67
78
68
79
/// Generate build jobs for all dependencies of the main module.
@@ -235,7 +246,12 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
235
246
inputs. append ( TypedVirtualPath ( file: dependencyModule. modulePath. path,
236
247
type: . swiftModule) )
237
248
238
- for headerDep in dependencyModule. prebuiltHeaderDependencyPaths ?? [ ] {
249
+ let prebuiltHeaderDependencyPaths = dependencyModule. prebuiltHeaderDependencyPaths ?? [ ]
250
+ if enableCAS && !prebuiltHeaderDependencyPaths. isEmpty {
251
+ throw Driver . Error. unsupportedConfigurationForCaching ( " module \( dependencyModule. moduleName) has prebuilt header dependency " )
252
+ }
253
+
254
+ for headerDep in prebuiltHeaderDependencyPaths {
239
255
commandLine. appendFlags ( [ " -Xcc " , " -include-pch " , " -Xcc " ] )
240
256
commandLine. appendPath ( VirtualPath . lookup ( headerDep. path) )
241
257
inputs. append ( TypedVirtualPath ( file: headerDep. path, type: . pch) )
@@ -256,11 +272,21 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
256
272
257
273
// Swift Main Module dependencies are passed encoded in a JSON file as described by
258
274
// SwiftModuleArtifactInfo
259
- if moduleId. moduleName == mainModuleName {
275
+ guard moduleId == . swift( dependencyGraph. mainModuleName) else { return }
276
+ let dependencyFileContent =
277
+ try serializeModuleDependencies ( for: moduleId,
278
+ swiftDependencyArtifacts: swiftDependencyArtifacts,
279
+ clangDependencyArtifacts: clangDependencyArtifacts)
280
+ if enableCAS {
281
+ // When using a CAS, write JSON into CAS and pass the ID on command-line.
282
+ let casID = try swiftScanOracle. store ( data: dependencyFileContent)
283
+ commandLine. appendFlag ( " -explicit-swift-module-map-file " )
284
+ commandLine. appendFlag ( casID)
285
+ } else {
286
+ // Write JSON to a file and add the JSON artifacts to command-line and inputs.
260
287
let dependencyFile =
261
- try serializeModuleDependencies ( for: moduleId,
262
- swiftDependencyArtifacts: swiftDependencyArtifacts,
263
- clangDependencyArtifacts: clangDependencyArtifacts)
288
+ VirtualPath . createUniqueTemporaryFileWithKnownContents ( . init( " \( moduleId. moduleName) -dependencies.json " ) ,
289
+ dependencyFileContent)
264
290
commandLine. appendFlag ( " -explicit-swift-module-map-file " )
265
291
commandLine. appendPath ( dependencyFile)
266
292
inputs. append ( TypedVirtualPath ( file: dependencyFile. intern ( ) ,
@@ -280,13 +306,15 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
280
306
let isFramework : Bool
281
307
swiftModulePath = . init( file: dependencyInfo. modulePath. path,
282
308
type: . swiftModule)
283
- isFramework = try dependencyGraph. swiftModuleDetails ( of: dependencyId) . isFramework ?? false
309
+ let swiftModuleDetails = try dependencyGraph. swiftModuleDetails ( of: dependencyId)
310
+ isFramework = swiftModuleDetails. isFramework ?? false
284
311
// Accumulate the required information about this dependency
285
312
// TODO: add .swiftdoc and .swiftsourceinfo for this module.
286
313
swiftDependencyArtifacts. append (
287
314
SwiftModuleArtifactInfo ( name: dependencyId. moduleName,
288
315
modulePath: TextualVirtualPath ( path: swiftModulePath. fileHandle) ,
289
- isFramework: isFramework) )
316
+ isFramework: isFramework,
317
+ moduleCacheKey: swiftModuleDetails. moduleCacheKey) )
290
318
case . clang:
291
319
let dependencyInfo = try dependencyGraph. moduleInfo ( of: dependencyId)
292
320
let dependencyClangModuleDetails =
@@ -295,7 +323,8 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
295
323
clangDependencyArtifacts. append (
296
324
ClangModuleArtifactInfo ( name: dependencyId. moduleName,
297
325
modulePath: TextualVirtualPath ( path: dependencyInfo. modulePath. path) ,
298
- moduleMapPath: dependencyClangModuleDetails. moduleMapPath) )
326
+ moduleMapPath: dependencyClangModuleDetails. moduleMapPath,
327
+ moduleCacheKey: dependencyClangModuleDetails. moduleCacheKey) )
299
328
case . swiftPrebuiltExternal:
300
329
let prebuiltModuleDetails = try dependencyGraph. swiftPrebuiltDetails ( of: dependencyId)
301
330
let compiledModulePath = prebuiltModuleDetails. compiledModulePath
@@ -308,7 +337,8 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
308
337
SwiftModuleArtifactInfo ( name: dependencyId. moduleName,
309
338
modulePath: TextualVirtualPath ( path: swiftModulePath. fileHandle) ,
310
339
headerDependencies: prebuiltModuleDetails. headerDependencyPaths,
311
- isFramework: isFramework) )
340
+ isFramework: isFramework,
341
+ moduleCacheKey: prebuiltModuleDetails. moduleCacheKey) )
312
342
case . swiftPlaceholder:
313
343
fatalError ( " Unresolved placeholder dependencies at planning stage: \( dependencyId) of \( moduleId) " )
314
344
}
@@ -354,6 +384,11 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
354
384
public mutating func resolveMainModuleDependencies( inputs: inout [ TypedVirtualPath ] ,
355
385
commandLine: inout [ Job . ArgTemplate ] ) throws {
356
386
let mainModuleId : ModuleDependencyId = . swift( dependencyGraph. mainModuleName)
387
+
388
+ let mainModuleDetails = try dependencyGraph. swiftModuleDetails ( of: mainModuleId)
389
+ if let additionalArgs = mainModuleDetails. commandLine {
390
+ additionalArgs. forEach { commandLine. appendFlag ( $0) }
391
+ }
357
392
commandLine. appendFlags ( " -disable-implicit-swift-modules " ,
358
393
" -Xcc " , " -fno-implicit-modules " ,
359
394
" -Xcc " , " -fno-implicit-module-maps " )
@@ -367,11 +402,6 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
367
402
public mutating func resolveBridgingHeaderDependencies( inputs: inout [ TypedVirtualPath ] ,
368
403
commandLine: inout [ Job . ArgTemplate ] ) throws {
369
404
let mainModuleId : ModuleDependencyId = . swift( dependencyGraph. mainModuleName)
370
- // Prohibit the frontend from implicitly building textual modules into binary modules.
371
- commandLine. appendFlags ( " -disable-implicit-swift-modules " ,
372
- " -Xcc " , " -fno-implicit-modules " ,
373
- " -Xcc " , " -fno-implicit-module-maps " )
374
-
375
405
var swiftDependencyArtifacts : [ SwiftModuleArtifactInfo ] = [ ]
376
406
var clangDependencyArtifacts : [ ClangModuleArtifactInfo ] = [ ]
377
407
let mainModuleDetails = try dependencyGraph. swiftModuleDetails ( of: mainModuleId)
@@ -409,28 +439,46 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
409
439
inputs. append ( clangModuleMapPath)
410
440
}
411
441
442
+ // Return if depscanner provided build commands.
443
+ if let scannerPCHArgs = mainModuleDetails. bridgingPchCommandLine {
444
+ scannerPCHArgs. forEach { commandLine. appendFlag ( $0) }
445
+ return
446
+ }
447
+
448
+ assert ( !enableCAS, " Caching build should always return command-line from scanner " )
449
+ // Prohibit the frontend from implicitly building textual modules into binary modules.
450
+ commandLine. appendFlags ( " -disable-implicit-swift-modules " ,
451
+ " -Xcc " , " -fno-implicit-modules " ,
452
+ " -Xcc " , " -fno-implicit-module-maps " )
453
+
454
+ let dependencyFileContent =
455
+ try serializeModuleDependencies ( for: mainModuleId,
456
+ swiftDependencyArtifacts: swiftDependencyArtifacts,
457
+ clangDependencyArtifacts: clangDependencyArtifacts)
458
+
412
459
let dependencyFile =
413
- try serializeModuleDependencies ( for: mainModuleId,
414
- swiftDependencyArtifacts: swiftDependencyArtifacts,
415
- clangDependencyArtifacts: clangDependencyArtifacts)
460
+ VirtualPath . createUniqueTemporaryFileWithKnownContents ( . init( " \( mainModuleId. moduleName) -dependencies.json " ) ,
461
+ dependencyFileContent)
416
462
commandLine. appendFlag ( " -explicit-swift-module-map-file " )
417
463
commandLine. appendPath ( dependencyFile)
418
464
inputs. append ( TypedVirtualPath ( file: dependencyFile. intern ( ) ,
419
465
type: . jsonSwiftArtifacts) )
420
466
}
421
467
422
- /// Store the output file artifacts for a given module in a JSON file, return the file's path .
468
+ /// Serialize the output file artifacts for a given module in JSON format .
423
469
private func serializeModuleDependencies( for moduleId: ModuleDependencyId ,
424
470
swiftDependencyArtifacts: [ SwiftModuleArtifactInfo ] ,
425
471
clangDependencyArtifacts: [ ClangModuleArtifactInfo ]
426
- ) throws -> VirtualPath {
472
+ ) throws -> Data {
473
+ // The module dependency map in CAS needs to be stable.
474
+ // Sort the dependencies by name.
427
475
let allDependencyArtifacts : [ ModuleDependencyArtifactInfo ] =
428
- swiftDependencyArtifacts. map { ModuleDependencyArtifactInfo . swift ( $0) } +
429
- clangDependencyArtifacts. map { ModuleDependencyArtifactInfo . clang ( $0) }
476
+ swiftDependencyArtifacts. sorted ( ) . map { ModuleDependencyArtifactInfo . swift ( $0) } +
477
+ clangDependencyArtifacts. sorted ( ) . map { ModuleDependencyArtifactInfo . clang ( $0) }
430
478
let encoder = JSONEncoder ( )
431
- encoder . outputFormatting = [ . prettyPrinted ]
432
- let contents = try encoder . encode ( allDependencyArtifacts )
433
- return VirtualPath . createUniqueTemporaryFileWithKnownContents ( . init ( " \( moduleId . moduleName ) -dependencies.json " ) , contents )
479
+ // Use sorted key to ensure the order of the keys is stable.
480
+ encoder . outputFormatting = [ . prettyPrinted , . sortedKeys ]
481
+ return try encoder . encode ( allDependencyArtifacts )
434
482
}
435
483
436
484
private func getPCMHashParts( pcmArgs: [ String ] , contextHash: String ) -> [ String ] {
0 commit comments