@@ -13,6 +13,9 @@ import TSCBasic
13
13
import Foundation
14
14
import SwiftOptions
15
15
public class IncrementalCompilationState {
16
+ /// Whether cross-module incrementality is enabled
17
+ private let isCrossModuleIncrementalBuildEnabled : Bool
18
+
16
19
/// The oracle for deciding what depends on what. Applies to this whole module.
17
20
private let moduleDependencyGraph : ModuleDependencyGraph
18
21
@@ -56,6 +59,11 @@ public class IncrementalCompilationState {
56
59
self . reporter = nil
57
60
}
58
61
62
+ self . isCrossModuleIncrementalBuildEnabled =
63
+ driver. parsedOptions. contains ( . enableExperimentalCrossModuleIncrementalBuild)
64
+ reporter? . report (
65
+ " \( self . isCrossModuleIncrementalBuildEnabled ? " Enabling " : " Disabling " ) incremental cross-module building " )
66
+
59
67
60
68
guard let ( outputFileMap, buildRecordInfo, outOfDateBuildRecord)
61
69
= try driver. getBuildInfo ( self . reporter)
@@ -66,13 +74,13 @@ public class IncrementalCompilationState {
66
74
guard let (
67
75
moduleDependencyGraph,
68
76
inputsHavingMalformedDependencySources: inputsHavingMalformedDependencySources
69
- ) =
70
- Self . computeModuleDependencyGraph (
71
- buildRecordInfo ,
72
- outOfDateBuildRecord ,
73
- outputFileMap ,
74
- & driver ,
75
- self . reporter )
77
+ ) = Self . computeModuleDependencyGraph (
78
+ buildRecordInfo ,
79
+ outOfDateBuildRecord ,
80
+ outputFileMap ,
81
+ & driver ,
82
+ self . reporter ,
83
+ isCrossModuleIncrementalBuildEnabled : isCrossModuleIncrementalBuildEnabled )
76
84
else {
77
85
return nil
78
86
}
@@ -99,15 +107,16 @@ public class IncrementalCompilationState {
99
107
_ outOfDateBuildRecord: BuildRecord ,
100
108
_ outputFileMap: OutputFileMap ,
101
109
_ driver: inout Driver ,
102
- _ reporter: Reporter ?
110
+ _ reporter: Reporter ? ,
111
+ isCrossModuleIncrementalBuildEnabled: Bool
103
112
)
104
113
-> ( ModuleDependencyGraph ,
105
114
inputsHavingMalformedDependencySources: [ TypedVirtualPath ] ) ?
106
115
{
107
116
let diagnosticEngine = driver. diagnosticEngine
108
117
guard let (
109
118
moduleDependencyGraph,
110
- inputsAndMalformedDependencySources : inputsAndMalformedDependencySources
119
+ inputsAndMalformedSwiftDeps : inputsAndMalformedSwiftDeps
111
120
) =
112
121
ModuleDependencyGraph . buildInitialGraph (
113
122
diagnosticEngine: diagnosticEngine,
@@ -117,20 +126,22 @@ public class IncrementalCompilationState {
117
126
parsedOptions: & driver. parsedOptions,
118
127
remarkDisabled: Diagnostic . Message. remark_incremental_compilation_has_been_disabled,
119
128
reporter: reporter,
120
- fileSystem: driver. fileSystem)
129
+ fileSystem: driver. fileSystem,
130
+ isCrossModuleIncrementalBuildEnabled: isCrossModuleIncrementalBuildEnabled
131
+ )
121
132
else {
122
133
return nil
123
134
}
124
135
// Preserve legacy behavior,
125
136
// but someday, just ensure inputsAndMalformedDependencySources are compiled
126
- if let badDependencySource = inputsAndMalformedDependencySources . first? . 1 {
137
+ if let badSwiftDeps = inputsAndMalformedSwiftDeps . first? . 1 {
127
138
diagnosticEngine. emit (
128
139
. remark_incremental_compilation_has_been_disabled(
129
- because: " malformed dependencies file ' \( badDependencySource ) ' " )
140
+ because: " malformed dependencies file ' \( badSwiftDeps ) ' " )
130
141
)
131
142
return nil
132
143
}
133
- let inputsHavingMalformedDependencySources = inputsAndMalformedDependencySources . map { $0. 0 }
144
+ let inputsHavingMalformedDependencySources = inputsAndMalformedSwiftDeps . map { $0. 0 }
134
145
return ( moduleDependencyGraph,
135
146
inputsHavingMalformedDependencySources: inputsHavingMalformedDependencySources)
136
147
}
@@ -282,6 +293,7 @@ extension IncrementalCompilationState {
282
293
alwaysRebuildDependents: Bool ,
283
294
reporter: IncrementalCompilationState . Reporter ?
284
295
) -> Set < TypedVirtualPath > {
296
+ // Input == source file
285
297
let changedInputs = Self . computeChangedInputs (
286
298
groups: allGroups,
287
299
buildRecordInfo: buildRecordInfo,
@@ -290,7 +302,15 @@ extension IncrementalCompilationState {
290
302
fileSystem: fileSystem,
291
303
reporter: reporter)
292
304
293
- let externalDependents = computeExternallyDependentInputs (
305
+ let externallyChangedInputs = computeExternallyChangedInputs (
306
+ forIncrementalExternalDependencies: false ,
307
+ buildTime: outOfDateBuildRecord. buildTime,
308
+ fileSystem: fileSystem,
309
+ moduleDependencyGraph: moduleDependencyGraph,
310
+ reporter: moduleDependencyGraph. reporter)
311
+
312
+ let incrementallyExternallyChangedInputs = computeExternallyChangedInputs (
313
+ forIncrementalExternalDependencies: true ,
294
314
buildTime: outOfDateBuildRecord. buildTime,
295
315
fileSystem: fileSystem,
296
316
moduleDependencyGraph: moduleDependencyGraph,
@@ -304,12 +324,13 @@ extension IncrementalCompilationState {
304
324
305
325
// Combine to obtain the inputs that definitely must be recompiled.
306
326
let definitelyRequiredInputs =
307
- Set ( changedInputs. map ( { $0. filePath } ) + externalDependents +
327
+ Set ( changedInputs. map ( { $0. filePath } ) +
328
+ externallyChangedInputs + incrementallyExternallyChangedInputs +
308
329
inputsHavingMalformedDependencySources
309
330
+ inputsMissingOutputs)
310
331
if let reporter = reporter {
311
332
for scheduledInput in definitelyRequiredInputs. sorted ( by: { $0. file. name < $1. file. name} ) {
312
- reporter. report ( " Queuing (initial): " , path : scheduledInput)
333
+ reporter. report ( " Queuing (initial): " , scheduledInput)
313
334
}
314
335
}
315
336
@@ -319,7 +340,7 @@ extension IncrementalCompilationState {
319
340
// as each first wave job finished.
320
341
let speculativeInputs = computeSpeculativeInputs (
321
342
changedInputs: changedInputs,
322
- externalDependents: externalDependents ,
343
+ externalDependents: externallyChangedInputs ,
323
344
inputsMissingOutputs: Set ( inputsMissingOutputs) ,
324
345
moduleDependencyGraph: moduleDependencyGraph,
325
346
alwaysRebuildDependents: alwaysRebuildDependents,
@@ -328,7 +349,7 @@ extension IncrementalCompilationState {
328
349
329
350
if let reporter = reporter {
330
351
for dependent in speculativeInputs. sorted ( by: { $0. file. name < $1. file. name} ) {
331
- reporter. report ( " Queuing because of the initial set: " , path : dependent)
352
+ reporter. report ( " Queuing because of the initial set: " , dependent)
332
353
}
333
354
}
334
355
let immediatelyCompiledInputs = definitelyRequiredInputs. union ( speculativeInputs)
@@ -337,7 +358,7 @@ extension IncrementalCompilationState {
337
358
. subtracting ( immediatelyCompiledInputs)
338
359
if let reporter = reporter {
339
360
for skippedInput in skippedInputs. sorted ( by: { $0. file. name < $1. file. name} ) {
340
- reporter. report ( " Skipping input: " , path : skippedInput)
361
+ reporter. report ( " Skipping input: " , skippedInput)
341
362
}
342
363
}
343
364
return skippedInputs
@@ -383,17 +404,17 @@ extension IncrementalCompilationState {
383
404
384
405
switch previousCompilationStatus {
385
406
case . upToDate where datesMatch:
386
- reporter? . report ( " May skip current input: " , path : input)
407
+ reporter? . report ( " May skip current input: " , input)
387
408
return nil
388
409
389
410
case . upToDate:
390
- reporter? . report ( " Scheduing changed input " , path : input)
411
+ reporter? . report ( " Scheduing changed input " , input)
391
412
case . newlyAdded:
392
- reporter? . report ( " Scheduling new " , path : input)
413
+ reporter? . report ( " Scheduling new " , input)
393
414
case . needsCascadingBuild:
394
- reporter? . report ( " Scheduling cascading build " , path : input)
415
+ reporter? . report ( " Scheduling cascading build " , input)
395
416
case . needsNonCascadingBuild:
396
- reporter? . report ( " Scheduling noncascading build " , path : input)
417
+ reporter? . report ( " Scheduling noncascading build " , input)
397
418
}
398
419
return ChangedInput ( filePath: input,
399
420
status: previousCompilationStatus,
@@ -402,25 +423,28 @@ extension IncrementalCompilationState {
402
423
}
403
424
404
425
/// Any files dependent on modified files from other modules must be compiled, too.
405
- private static func computeExternallyDependentInputs(
426
+ private static func computeExternallyChangedInputs(
427
+ forIncrementalExternalDependencies: Bool ,
406
428
buildTime: Date ,
407
429
fileSystem: FileSystem ,
408
430
moduleDependencyGraph: ModuleDependencyGraph ,
409
431
reporter: IncrementalCompilationState . Reporter ?
410
432
) -> [ TypedVirtualPath ] {
411
433
var externalDependencySources = Set < ModuleDependencyGraph . DependencySource > ( )
412
- for extDep in moduleDependencyGraph. externalDependencies {
413
- let extModTime = extDep. file. flatMap {
414
- try ? fileSystem. getFileInfo ( $0) . modTime}
434
+ let extDeps = forIncrementalExternalDependencies
435
+ ? moduleDependencyGraph. incrementalExternalDependencies
436
+ : moduleDependencyGraph. externalDependencies
437
+ for extDep in extDeps {
438
+ let extModTime = extDep. file. flatMap { try ? fileSystem. getFileInfo ( $0) . modTime}
415
439
?? Date . distantFuture
416
440
if extModTime >= buildTime {
417
- for dependent in moduleDependencyGraph. untracedDependents ( of: extDep) {
441
+ for dependent in moduleDependencyGraph. untracedDependents ( of: extDep, isIncremental : forIncrementalExternalDependencies ) {
418
442
guard let dependencySource = dependent. dependencySource else {
419
- fatalError ( " Dependent \( dependent) does not have dependencies source file! " )
443
+ fatalError ( " Dependent \( dependent) does not have dependencies file! " )
420
444
}
421
445
reporter? . report (
422
- " Queuing because of external dependency on newer \( extDep. file? . basename ?? " extDep? " ) " ,
423
- path : TypedVirtualPath ( file : dependencySource. file , type : . swiftDeps ) )
446
+ " Queuing because of \( forIncrementalExternalDependencies ? " incremental " : " " ) external dependency on newer \( extDep. file? . basename ?? " extDep? " ) " ,
447
+ dependencySource. typedFile )
424
448
externalDependencySources. insert ( dependencySource)
425
449
}
426
450
}
@@ -457,7 +481,7 @@ extension IncrementalCompilationState {
457
481
for dep in dependentsOfOneFile where !cascadingFileSet. contains ( dep) {
458
482
if dependentFiles. insert ( dep) . 0 {
459
483
reporter? . report (
460
- " Immediately scheduling dependent on \( cascadingFile. file. basename) " , path : dep)
484
+ " Immediately scheduling dependent on \( cascadingFile. file. basename) " , dep)
461
485
}
462
486
}
463
487
}
@@ -536,7 +560,8 @@ extension IncrementalCompilationState {
536
560
537
561
if let reporter = self . reporter {
538
562
for input in discoveredInputs {
539
- reporter. report ( " Queuing because of dependencies discovered later: " , path: input)
563
+ reporter. report (
564
+ " Queuing because of dependencies discovered later: " , input)
540
565
}
541
566
}
542
567
let newJobs = try getJobsFor ( discoveredCompilationInputs: discoveredInputs)
@@ -561,7 +586,8 @@ extension IncrementalCompilationState {
561
586
if let found = moduleDependencyGraph. findSourcesToCompileAfterCompiling ( input, on: self . driver. fileSystem) {
562
587
return found
563
588
}
564
- self . reporter? . report ( " Failed to read some dependencies source; compiling everything " , path: input)
589
+ self . reporter? . report (
590
+ " Failed to read some dependencies source; compiling everything " , input)
565
591
return Array ( skippedCompileGroups. keys)
566
592
}
567
593
)
@@ -579,11 +605,11 @@ extension IncrementalCompilationState {
579
605
let primaryInputs = group. compileJob. primaryInputs
580
606
assert ( primaryInputs. count == 1 )
581
607
assert ( primaryInputs [ 0 ] == input)
582
- self . reporter? . report ( " Scheduling discovered " , path : input)
608
+ self . reporter? . report ( " Scheduling discovered " , input)
583
609
return group. allJobs ( )
584
610
}
585
611
else {
586
- self . reporter? . report ( " Tried to schedule discovered input again " , path : input)
612
+ self . reporter? . report ( " Tried to schedule discovered input again " , input)
587
613
return [ ]
588
614
}
589
615
}
@@ -627,20 +653,38 @@ extension IncrementalCompilationState {
627
653
///
628
654
/// - Parameters:
629
655
/// - message: The message to emit in the remark.
630
- /// - path: If non-nil, the path of an output for an incremental job.
631
- func report( _ message: String , path: TypedVirtualPath ? = nil ) {
632
- guard let outputFileMap = outputFileMap,
633
- let path = path,
656
+ /// - path: If non-nil, the path of some file. If the output for an incremental job, will print out the
657
+ /// source and object files.
658
+ func report( _ message: String , _ path: TypedVirtualPath ? ) {
659
+ guard let path = path,
660
+ let outputFileMap = outputFileMap,
634
661
let input = path. type == . swift ? path. file : outputFileMap. getInput ( outputFile: path. file)
635
662
else {
636
- diagnosticEngine . emit ( . remark_incremental_compilation ( because : message) )
663
+ report ( message, path ? . file )
637
664
return
638
665
}
639
666
let output = outputFileMap. getOutput ( inputFile: path. file, outputType: . object)
640
667
let compiling = " {compile: \( output. basename) <= \( input. basename) } "
641
668
diagnosticEngine. emit ( . remark_incremental_compilation( because: " \( message) \( compiling) " ) )
642
669
}
643
670
671
+ /// Entry point for a simple path, won't print the compile job, path could be anything.
672
+ func report( _ message: String , _ path: VirtualPath ? ) {
673
+ guard let path = path
674
+ else {
675
+ report ( message)
676
+ diagnosticEngine. emit ( . remark_incremental_compilation( because: message) )
677
+ return
678
+ }
679
+ diagnosticEngine. emit ( . remark_incremental_compilation( because: " \( message) ' \( path. name) ' " ) )
680
+ }
681
+
682
+ /// Entry point if no path.
683
+ func report( _ message: String ) {
684
+ diagnosticEngine. emit ( . remark_incremental_compilation( because: message) )
685
+ }
686
+
687
+
644
688
// Emits a remark indicating incremental compilation has been disabled.
645
689
func reportDisablingIncrementalBuild( _ why: String ) {
646
690
report ( " Disabling incremental build: \( why) " )
0 commit comments