@@ -237,13 +237,25 @@ extension LLBuildManifestBuilder {
237
237
private func addSwiftDriverJobs( for targetDescription: SwiftTargetBuildDescription ,
238
238
jobs: [ Job ] , inputs: [ Node ] ,
239
239
resolver: ArgsResolver ,
240
- isMainModule: ( Job ) -> Bool ) throws {
240
+ isMainModule: ( Job ) -> Bool ,
241
+ uniqueExplicitDependencyTracker: UniqueExplicitDependencyJobTracker ? = nil ) throws {
241
242
// Add build jobs to the manifest
242
243
for job in jobs {
243
244
let tool = try resolver. resolve ( . path( job. tool) )
244
245
let commandLine = try job. commandLine. map { try resolver. resolve ( $0) }
245
246
let arguments = [ tool] + commandLine
246
247
248
+ // Check if an explicit pre-build dependency job has already been
249
+ // added as a part of this build.
250
+ if let uniqueDependencyTracker = uniqueExplicitDependencyTracker,
251
+ job. isExplicitDependencyPreBuildJob {
252
+ if try ! uniqueDependencyTracker. registerExplicitDependencyBuildJob ( job) {
253
+ // This is a duplicate of a previously-seen identical job.
254
+ // Skip adding it to the manifest
255
+ continue
256
+ }
257
+ }
258
+
247
259
let jobInputs = try job. inputs. map { try $0. resolveToNode ( ) }
248
260
let jobOutputs = try job. outputs. map { try $0. resolveToNode ( ) }
249
261
@@ -320,6 +332,11 @@ extension LLBuildManifestBuilder {
320
332
// modules across targets' Driver instances.
321
333
let dependencyOracle = InterModuleDependencyOracle ( )
322
334
335
+ // Explicit dependency pre-build jobs may be common to multiple targets.
336
+ // We de-duplicate them here to avoid adding identical entries to the
337
+ // downstream LLBuild manifest
338
+ let explicitDependencyJobTracker = UniqueExplicitDependencyJobTracker ( )
339
+
323
340
// Create commands for all target descriptions in the plan.
324
341
for dependency in allPackageDependencies. reversed ( ) {
325
342
guard case . target( let target, _) = dependency else {
@@ -346,7 +363,8 @@ extension LLBuildManifestBuilder {
346
363
switch description {
347
364
case . swift( let desc) :
348
365
try self . createExplicitSwiftTargetCompileCommand ( description: desc,
349
- dependencyOracle: dependencyOracle)
366
+ dependencyOracle: dependencyOracle,
367
+ explicitDependencyJobTracker: explicitDependencyJobTracker)
350
368
case . clang( let desc) :
351
369
try self . createClangCompileCommand ( desc)
352
370
}
@@ -355,7 +373,8 @@ extension LLBuildManifestBuilder {
355
373
356
374
private func createExplicitSwiftTargetCompileCommand(
357
375
description: SwiftTargetBuildDescription ,
358
- dependencyOracle: InterModuleDependencyOracle
376
+ dependencyOracle: InterModuleDependencyOracle ,
377
+ explicitDependencyJobTracker: UniqueExplicitDependencyJobTracker ?
359
378
) throws {
360
379
// Inputs.
361
380
let inputs = try self . computeSwiftCompileCmdInputs ( description)
@@ -367,7 +386,8 @@ extension LLBuildManifestBuilder {
367
386
368
387
// Commands.
369
388
try addExplicitBuildSwiftCmds ( description, inputs: inputs,
370
- dependencyOracle: dependencyOracle)
389
+ dependencyOracle: dependencyOracle,
390
+ explicitDependencyJobTracker: explicitDependencyJobTracker)
371
391
372
392
self . addTargetCmd ( description, cmdOutputs: cmdOutputs)
373
393
self . addModuleWrapCmd ( description)
@@ -376,7 +396,8 @@ extension LLBuildManifestBuilder {
376
396
private func addExplicitBuildSwiftCmds(
377
397
_ targetDescription: SwiftTargetBuildDescription ,
378
398
inputs: [ Node ] ,
379
- dependencyOracle: InterModuleDependencyOracle
399
+ dependencyOracle: InterModuleDependencyOracle ,
400
+ explicitDependencyJobTracker: UniqueExplicitDependencyJobTracker ? = nil
380
401
) throws {
381
402
// Pass the driver its external dependencies (target dependencies)
382
403
var dependencyModulePathMap : SwiftDriver . ExternalTargetModulePathMap = [ : ]
@@ -399,7 +420,8 @@ extension LLBuildManifestBuilder {
399
420
interModuleDependencyOracle: dependencyOracle)
400
421
let jobs = try driver. planBuild ( )
401
422
try addSwiftDriverJobs ( for: targetDescription, jobs: jobs, inputs: inputs, resolver: resolver,
402
- isMainModule: { driver. isExplicitMainModuleJob ( job: $0) } )
423
+ isMainModule: { driver. isExplicitMainModuleJob ( job: $0) } ,
424
+ uniqueExplicitDependencyTracker: explicitDependencyJobTracker)
403
425
}
404
426
405
427
/// Collect a map from all target dependencies of the specified target to the build planning artifacts for said dependency,
@@ -631,7 +653,34 @@ extension LLBuildManifestBuilder {
631
653
}
632
654
}
633
655
634
- // MARK: - Compile C-family
656
+ fileprivate extension SwiftDriver . Job {
657
+ var isExplicitDependencyPreBuildJob : Bool {
658
+ return ( kind == . emitModule &&
659
+ inputs. contains { $0. file. extension == " swiftinterface " } ) ||
660
+ kind == . generatePCM
661
+ }
662
+ }
663
+
664
+ /// A simple mechanism to keep track of already-known explicit module pre-build jobs.
665
+ /// It uses the output filename of the job (either a `.swiftmodule` or a `.pcm`) for uniqueness,
666
+ /// because the SwiftDriver encodes the module's context hash into this filename. Any two jobs
667
+ /// producing an binary module file with an identical name are therefore duplicate
668
+ fileprivate class UniqueExplicitDependencyJobTracker {
669
+ private var uniqueDependencyModuleIDSet : Set < Int > = [ ]
670
+
671
+ /// Registers the input Job with the tracker. Returns `false` if this job is already known
672
+ func registerExplicitDependencyBuildJob( _ job: SwiftDriver . Job ) throws -> Bool {
673
+ guard job. isExplicitDependencyPreBuildJob,
674
+ let soleOutput = job. outputs. spm_only else {
675
+ throw InternalError ( " Expected explicit module dependency build job " )
676
+ }
677
+ let jobUniqueID = soleOutput. file. basename. hashValue
678
+ let ( new, _) = uniqueDependencyModuleIDSet. insert ( jobUniqueID)
679
+ return new
680
+ }
681
+ }
682
+
683
+ // MARK:- Compile C-family
635
684
636
685
extension LLBuildManifestBuilder {
637
686
/// Create a llbuild target for a Clang target description.
0 commit comments