@@ -134,11 +134,23 @@ extension IncrementalCompilationState.FirstWaveComputer {
134
134
jobCreatingPch: jobCreatingPch)
135
135
136
136
// In the case where there are no compilation jobs to run on this build (no source-files were changed),
137
- // we can skip running `beforeCompiles` jobs if we also ensure that none of the `afterCompiles` jobs
138
- // have any dependencies on them.
139
- let skipAllJobs = batchedCompilationJobs. isEmpty ? !nonVerifyAfterCompileJobsDependOnBeforeCompileJobs( ) : false
140
- let beforeCompileJobs = skipAllJobs ? [ ] : jobsInPhases. beforeCompiles
141
- var skippedNonCompileJobs = skipAllJobs ? jobsInPhases. beforeCompiles : [ ]
137
+ // and the emit-module task does not need to be re-run, we can skip running `beforeCompiles` jobs if we
138
+ // also ensure that none of the `afterCompiles` jobs have any dependencies on them.
139
+ let skippingAllCompileJobs = batchedCompilationJobs. isEmpty
140
+ let skipEmitModuleJobs = skippingAllCompileJobs ? try computeCanSkipEmitModuleTasks ( buildRecord) : false
141
+ let skipAllJobs = skippingAllCompileJobs && skipEmitModuleJobs ? !nonVerifyAfterCompileJobsDependOnBeforeCompileJobs( ) : false
142
+
143
+ let beforeCompileJobs : [ Job ]
144
+ var skippedNonCompileJobs : [ Job ] = [ ]
145
+ if skipAllJobs {
146
+ beforeCompileJobs = [ ]
147
+ skippedNonCompileJobs = jobsInPhases. beforeCompiles
148
+ } else if skipEmitModuleJobs {
149
+ beforeCompileJobs = jobsInPhases. beforeCompiles. filter { $0. kind != . emitModule }
150
+ skippedNonCompileJobs. append ( contentsOf: jobsInPhases. beforeCompiles. filter { $0. kind == . emitModule } )
151
+ } else {
152
+ beforeCompileJobs = jobsInPhases. beforeCompiles
153
+ }
142
154
143
155
// Schedule emitModule job together with verify module interface job.
144
156
let afterCompileJobs = jobsInPhases. afterCompiles. compactMap { job -> Job ? in
@@ -170,6 +182,21 @@ extension IncrementalCompilationState.FirstWaveComputer {
170
182
}
171
183
}
172
184
185
+ /// Figure out if the emit-module tasks are *not* mandatory. This functionality only runs if there are not actual
186
+ /// compilation tasks to be run in this build, for example on an emit-module-only build.
187
+ private func computeCanSkipEmitModuleTasks( _ buildRecord: BuildRecord ) throws -> Bool {
188
+ guard let emitModuleJob = jobsInPhases. beforeCompiles. first ( where: { $0. kind == . emitModule } ) else {
189
+ return true
190
+ }
191
+ // If any of the outputs do not exist, they must be re-computed
192
+ guard try emitModuleJob. outputs. allSatisfy ( { try fileSystem. exists ( $0. file) } ) else {
193
+ return false
194
+ }
195
+ // Ensure that no output is older than any of the inputs
196
+ let oldestOutputModTime : TimePoint = try emitModuleJob. outputs. map { try fileSystem. lastModificationTime ( for: $0. file) } . min ( ) ?? . distantPast
197
+ return try emitModuleJob. inputs. swiftSourceFiles. allSatisfy ( { try fileSystem. lastModificationTime ( for: $0. typedFile. file) < oldestOutputModTime } )
198
+ }
199
+
173
200
/// Figure out which compilation inputs are *not* mandatory at the start
174
201
private func computeInitiallySkippedCompilationInputs(
175
202
inputsInvalidatedByExternals: TransitivelyInvalidatedSwiftSourceFileSet ,
@@ -178,7 +205,7 @@ extension IncrementalCompilationState.FirstWaveComputer {
178
205
) -> Set < TypedVirtualPath > {
179
206
let allCompileJobs = jobsInPhases. compileJobs
180
207
// Input == source file
181
- let changedInputs = computeChangedInputs ( moduleDependencyGraph , buildRecord)
208
+ let changedInputs = computeChangedInputs ( buildRecord)
182
209
183
210
if let reporter = reporter {
184
211
for input in inputsInvalidatedByExternals {
@@ -274,7 +301,6 @@ extension IncrementalCompilationState.FirstWaveComputer {
274
301
275
302
// Find the inputs that have changed since last compilation, or were marked as needed a build
276
303
private func computeChangedInputs(
277
- _ moduleDependencyGraph: ModuleDependencyGraph ,
278
304
_ outOfDateBuildRecord: BuildRecord
279
305
) -> [ ChangedInput ] {
280
306
jobsInPhases. compileJobs. compactMap { job in
0 commit comments