@@ -134,11 +134,24 @@ 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 ( moduleDependencyGraph, 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
+ let emitModuleJobs = jobsInPhases. beforeCompiles. filter { $0. kind == . emitModule }
150
+ beforeCompileJobs = jobsInPhases. beforeCompiles. filter { $0. kind != . emitModule }
151
+ skippedNonCompileJobs. append ( contentsOf: emitModuleJobs)
152
+ } else {
153
+ beforeCompileJobs = jobsInPhases. beforeCompiles
154
+ }
142
155
143
156
// Schedule emitModule job together with verify module interface job.
144
157
let afterCompileJobs = jobsInPhases. afterCompiles. compactMap { job -> Job ? in
@@ -170,6 +183,38 @@ extension IncrementalCompilationState.FirstWaveComputer {
170
183
}
171
184
}
172
185
186
+ /// Figure out if the emit-module tasks are *not* mandatory.
187
+ /// This functionality only runs if there are not actual
188
+ /// compilation tasks to be run in this build, for example on an
189
+ /// emit-module-only build.
190
+ private func computeCanSkipEmitModuleTasks(
191
+ _ moduleDependencyGraph: ModuleDependencyGraph ,
192
+ _ buildRecord: BuildRecord
193
+ ) throws -> Bool {
194
+ guard let emitModuleJob = jobsInPhases. beforeCompiles. first ( where: { $0. kind == . emitModule } ) else {
195
+ return true
196
+ }
197
+
198
+ var oldestOutputModTime : TimePoint = . distantFuture
199
+ for output in emitModuleJob. outputs {
200
+ if try ! fileSystem. exists ( output. file) {
201
+ return false
202
+ }
203
+ let modTime = try fileSystem. lastModificationTime ( for: output. file)
204
+ if modTime < oldestOutputModTime {
205
+ oldestOutputModTime = modTime
206
+ }
207
+ }
208
+
209
+ for swiftInput in emitModuleJob. inputs. swiftSourceFiles {
210
+ if try fileSystem. lastModificationTime ( for: swiftInput. typedFile. file) > oldestOutputModTime {
211
+ return false
212
+ }
213
+ }
214
+
215
+ return true
216
+ }
217
+
173
218
/// Figure out which compilation inputs are *not* mandatory at the start
174
219
private func computeInitiallySkippedCompilationInputs(
175
220
inputsInvalidatedByExternals: TransitivelyInvalidatedSwiftSourceFileSet ,
@@ -178,7 +223,7 @@ extension IncrementalCompilationState.FirstWaveComputer {
178
223
) -> Set < TypedVirtualPath > {
179
224
let allCompileJobs = jobsInPhases. compileJobs
180
225
// Input == source file
181
- let changedInputs = computeChangedInputs ( moduleDependencyGraph , buildRecord)
226
+ let changedInputs = computeChangedInputs ( buildRecord)
182
227
183
228
if let reporter = reporter {
184
229
for input in inputsInvalidatedByExternals {
@@ -274,7 +319,6 @@ extension IncrementalCompilationState.FirstWaveComputer {
274
319
275
320
// Find the inputs that have changed since last compilation, or were marked as needed a build
276
321
private func computeChangedInputs(
277
- _ moduleDependencyGraph: ModuleDependencyGraph ,
278
322
_ outOfDateBuildRecord: BuildRecord
279
323
) -> [ ChangedInput ] {
280
324
jobsInPhases. compileJobs. compactMap { job in
0 commit comments