@@ -45,6 +45,8 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
4545 /// Whether we are using the integrated driver via libSwiftDriver shared lib
4646 private let integratedDriver : Bool
4747 private let mainModuleName : String ?
48+ private let enableCAS : Bool
49+ private let swiftScanOracle : InterModuleDependencyOracle
4850
4951 /// Clang PCM names contain a hash of the command-line arguments that were used to build them.
5052 /// We avoid re-running the hash computation with the use of this cache
@@ -55,14 +57,18 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
5557
5658 public init ( dependencyGraph: InterModuleDependencyGraph ,
5759 toolchain: Toolchain ,
60+ dependencyOracle: InterModuleDependencyOracle ,
5861 integratedDriver: Bool = true ,
59- supportsExplicitInterfaceBuild: Bool = false ) throws {
62+ supportsExplicitInterfaceBuild: Bool = false ,
63+ enableCAS: Bool = false ) throws {
6064 self . dependencyGraph = dependencyGraph
6165 self . toolchain = toolchain
66+ self . swiftScanOracle = dependencyOracle
6267 self . integratedDriver = integratedDriver
6368 self . mainModuleName = dependencyGraph. mainModuleName
6469 self . reachabilityMap = try dependencyGraph. computeTransitiveClosure ( )
6570 self . supportsExplicitInterfaceBuild = supportsExplicitInterfaceBuild
71+ self . enableCAS = enableCAS
6672 }
6773
6874 /// Generate build jobs for all dependencies of the main module.
@@ -136,7 +142,8 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
136142 // Resolve all dependency module inputs for this Swift module
137143 try resolveExplicitModuleDependencies ( moduleId: moduleId,
138144 inputs: & inputs,
139- commandLine: & commandLine)
145+ commandLine: & commandLine,
146+ isMainModule: false )
140147
141148 // Build the .swiftinterfaces file using a list of command line options specified in the
142149 // `details` field.
@@ -192,7 +199,8 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
192199
193200 // Resolve all dependency module inputs for this Clang module
194201 try resolveExplicitModuleDependencies ( moduleId: moduleId, inputs: & inputs,
195- commandLine: & commandLine)
202+ commandLine: & commandLine,
203+ isMainModule: false )
196204
197205 let moduleMapPath = moduleDetails. moduleMapPath. path
198206 let modulePCMPath = moduleInfo. modulePath
@@ -221,7 +229,8 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
221229 /// to use explicitly-built module dependencies.
222230 private mutating func resolveExplicitModuleDependencies( moduleId: ModuleDependencyId ,
223231 inputs: inout [ TypedVirtualPath ] ,
224- commandLine: inout [ Job . ArgTemplate ] ) throws {
232+ commandLine: inout [ Job . ArgTemplate ] ,
233+ isMainModule: Bool ) throws {
225234 // Prohibit the frontend from implicitly building textual modules into binary modules.
226235 var swiftDependencyArtifacts : [ SwiftModuleArtifactInfo ] = [ ]
227236 var clangDependencyArtifacts : [ ClangModuleArtifactInfo ] = [ ]
@@ -256,15 +265,24 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
256265
257266 // Swift Main Module dependencies are passed encoded in a JSON file as described by
258267 // SwiftModuleArtifactInfo
259- if moduleId. moduleName == mainModuleName {
260- let dependencyFile =
261- try serializeModuleDependencies ( for: moduleId,
262- swiftDependencyArtifacts: swiftDependencyArtifacts,
263- clangDependencyArtifacts: clangDependencyArtifacts)
264- commandLine. appendFlag ( " -explicit-swift-module-map-file " )
265- commandLine. appendPath ( dependencyFile)
266- inputs. append ( TypedVirtualPath ( file: dependencyFile. intern ( ) ,
267- type: . jsonSwiftArtifacts) )
268+ if isMainModule {
269+ if enableCAS {
270+ let dependencyFile =
271+ try serializeModuleDependenciesToCAS ( for: moduleId,
272+ swiftDependencyArtifacts: swiftDependencyArtifacts,
273+ clangDependencyArtifacts: clangDependencyArtifacts)
274+ commandLine. appendFlag ( " -explicit-swift-module-map-file " )
275+ commandLine. appendFlag ( dependencyFile)
276+ } else {
277+ let dependencyFile =
278+ try serializeModuleDependencies ( for: moduleId,
279+ swiftDependencyArtifacts: swiftDependencyArtifacts,
280+ clangDependencyArtifacts: clangDependencyArtifacts)
281+ commandLine. appendFlag ( " -explicit-swift-module-map-file " )
282+ commandLine. appendPath ( dependencyFile)
283+ inputs. append ( TypedVirtualPath ( file: dependencyFile. intern ( ) ,
284+ type: . jsonSwiftArtifacts) )
285+ }
268286 }
269287 }
270288
@@ -280,13 +298,15 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
280298 let isFramework : Bool
281299 swiftModulePath = . init( file: dependencyInfo. modulePath. path,
282300 type: . swiftModule)
283- isFramework = try dependencyGraph. swiftModuleDetails ( of: dependencyId) . isFramework ?? false
301+ let swiftModuleDetails = try dependencyGraph. swiftModuleDetails ( of: dependencyId)
302+ isFramework = swiftModuleDetails. isFramework ?? false
284303 // Accumulate the required information about this dependency
285304 // TODO: add .swiftdoc and .swiftsourceinfo for this module.
286305 swiftDependencyArtifacts. append (
287306 SwiftModuleArtifactInfo ( name: dependencyId. moduleName,
288307 modulePath: TextualVirtualPath ( path: swiftModulePath. fileHandle) ,
289- isFramework: isFramework) )
308+ isFramework: isFramework,
309+ moduleCacheKey: swiftModuleDetails. moduleCacheKey) )
290310 case . clang:
291311 let dependencyInfo = try dependencyGraph. moduleInfo ( of: dependencyId)
292312 let dependencyClangModuleDetails =
@@ -295,7 +315,8 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
295315 clangDependencyArtifacts. append (
296316 ClangModuleArtifactInfo ( name: dependencyId. moduleName,
297317 modulePath: TextualVirtualPath ( path: dependencyInfo. modulePath. path) ,
298- moduleMapPath: dependencyClangModuleDetails. moduleMapPath) )
318+ moduleMapPath: dependencyClangModuleDetails. moduleMapPath,
319+ moduleCacheKey: dependencyClangModuleDetails. moduleCacheKey) )
299320 case . swiftPrebuiltExternal:
300321 let prebuiltModuleDetails = try dependencyGraph. swiftPrebuiltDetails ( of: dependencyId)
301322 let compiledModulePath = prebuiltModuleDetails. compiledModulePath
@@ -308,7 +329,8 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
308329 SwiftModuleArtifactInfo ( name: dependencyId. moduleName,
309330 modulePath: TextualVirtualPath ( path: swiftModulePath. fileHandle) ,
310331 headerDependencies: prebuiltModuleDetails. headerDependencyPaths,
311- isFramework: isFramework) )
332+ isFramework: isFramework,
333+ moduleCacheKey: prebuiltModuleDetails. moduleCacheKey) )
312334 case . swiftPlaceholder:
313335 fatalError ( " Unresolved placeholder dependencies at planning stage: \( dependencyId) of \( moduleId) " )
314336 }
@@ -354,24 +376,25 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
354376 public mutating func resolveMainModuleDependencies( inputs: inout [ TypedVirtualPath ] ,
355377 commandLine: inout [ Job . ArgTemplate ] ) throws {
356378 let mainModuleId : ModuleDependencyId = . swift( dependencyGraph. mainModuleName)
379+
380+ let mainModuleDetails = try dependencyGraph. swiftModuleDetails ( of: mainModuleId)
381+ if let additionalArgs = mainModuleDetails. commandLine {
382+ additionalArgs. forEach { commandLine. appendFlag ( $0) }
383+ }
357384 commandLine. appendFlags ( " -disable-implicit-swift-modules " ,
358385 " -Xcc " , " -fno-implicit-modules " ,
359386 " -Xcc " , " -fno-implicit-module-maps " )
360387 try resolveExplicitModuleDependencies ( moduleId: mainModuleId,
361388 inputs: & inputs,
362- commandLine: & commandLine)
389+ commandLine: & commandLine,
390+ isMainModule: true )
363391 }
364392
365393 /// Resolve all module dependencies of the main module and add them to the lists of
366394 /// inputs and command line flags.
367395 public mutating func resolveBridgingHeaderDependencies( inputs: inout [ TypedVirtualPath ] ,
368396 commandLine: inout [ Job . ArgTemplate ] ) throws {
369397 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-
375398 var swiftDependencyArtifacts : [ SwiftModuleArtifactInfo ] = [ ]
376399 var clangDependencyArtifacts : [ ClangModuleArtifactInfo ] = [ ]
377400 let mainModuleDetails = try dependencyGraph. swiftModuleDetails ( of: mainModuleId)
@@ -409,14 +432,34 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
409432 inputs. append ( clangModuleMapPath)
410433 }
411434
412- let dependencyFile =
413- try serializeModuleDependencies ( for: mainModuleId,
414- swiftDependencyArtifacts: swiftDependencyArtifacts,
415- clangDependencyArtifacts: clangDependencyArtifacts)
416- commandLine. appendFlag ( " -explicit-swift-module-map-file " )
417- commandLine. appendPath ( dependencyFile)
418- inputs. append ( TypedVirtualPath ( file: dependencyFile. intern ( ) ,
419- type: . jsonSwiftArtifacts) )
435+ // Return if depscanner provided build commands.
436+ if enableCAS, let scannerPCHArgs = mainModuleDetails. bridgingPchCommandLine {
437+ scannerPCHArgs. forEach { commandLine. appendFlag ( $0) }
438+ return
439+ }
440+
441+ // Prohibit the frontend from implicitly building textual modules into binary modules.
442+ commandLine. appendFlags ( " -disable-implicit-swift-modules " ,
443+ " -Xcc " , " -fno-implicit-modules " ,
444+ " -Xcc " , " -fno-implicit-module-maps " )
445+
446+ if enableCAS {
447+ let dependencyFile =
448+ try serializeModuleDependenciesToCAS ( for: mainModuleId,
449+ swiftDependencyArtifacts: swiftDependencyArtifacts,
450+ clangDependencyArtifacts: clangDependencyArtifacts)
451+ commandLine. appendFlag ( " -explicit-swift-module-map-file " )
452+ commandLine. appendFlag ( dependencyFile)
453+ } else {
454+ let dependencyFile =
455+ try serializeModuleDependencies ( for: mainModuleId,
456+ swiftDependencyArtifacts: swiftDependencyArtifacts,
457+ clangDependencyArtifacts: clangDependencyArtifacts)
458+ commandLine. appendFlag ( " -explicit-swift-module-map-file " )
459+ commandLine. appendPath ( dependencyFile)
460+ inputs. append ( TypedVirtualPath ( file: dependencyFile. intern ( ) ,
461+ type: . jsonSwiftArtifacts) )
462+ }
420463 }
421464
422465 /// Store the output file artifacts for a given module in a JSON file, return the file's path.
@@ -433,6 +476,22 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
433476 return VirtualPath . createUniqueTemporaryFileWithKnownContents ( . init( " \( moduleId. moduleName) -dependencies.json " ) , contents)
434477 }
435478
479+ private func serializeModuleDependenciesToCAS( for moduleId: ModuleDependencyId ,
480+ swiftDependencyArtifacts: [ SwiftModuleArtifactInfo ] ,
481+ clangDependencyArtifacts: [ ClangModuleArtifactInfo ]
482+ ) throws -> String {
483+ // The module dependency map in CAS needs to be stable.
484+ // Sort the dependencies by name.
485+ let allDependencyArtifacts : [ ModuleDependencyArtifactInfo ] =
486+ swiftDependencyArtifacts. sorted ( ) . map { ModuleDependencyArtifactInfo . swift ( $0) } +
487+ clangDependencyArtifacts. sorted ( ) . map { ModuleDependencyArtifactInfo . clang ( $0) }
488+ let encoder = JSONEncoder ( )
489+ // Use sorted key to ensure the order of the keys is stable.
490+ encoder. outputFormatting = [ . prettyPrinted, . sortedKeys]
491+ let contents = try encoder. encode ( allDependencyArtifacts)
492+ return try swiftScanOracle. store ( data: contents)
493+ }
494+
436495 private func getPCMHashParts( pcmArgs: [ String ] , contextHash: String ) -> [ String ] {
437496 var results : [ String ] = [ ]
438497 results. append ( contextHash)
0 commit comments