@@ -134,11 +134,24 @@ extension IncrementalCompilationState.FirstWaveComputer {
134134 jobCreatingPch: jobCreatingPch)
135135
136136 // 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+ }
142155
143156 // Schedule emitModule job together with verify module interface job.
144157 let afterCompileJobs = jobsInPhases. afterCompiles. compactMap { job -> Job ? in
@@ -170,6 +183,38 @@ extension IncrementalCompilationState.FirstWaveComputer {
170183 }
171184 }
172185
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+
173218 /// Figure out which compilation inputs are *not* mandatory at the start
174219 private func computeInitiallySkippedCompilationInputs(
175220 inputsInvalidatedByExternals: TransitivelyInvalidatedSwiftSourceFileSet ,
@@ -178,7 +223,7 @@ extension IncrementalCompilationState.FirstWaveComputer {
178223 ) -> Set < TypedVirtualPath > {
179224 let allCompileJobs = jobsInPhases. compileJobs
180225 // Input == source file
181- let changedInputs = computeChangedInputs ( moduleDependencyGraph , buildRecord)
226+ let changedInputs = computeChangedInputs ( buildRecord)
182227
183228 if let reporter = reporter {
184229 for input in inputsInvalidatedByExternals {
@@ -274,7 +319,6 @@ extension IncrementalCompilationState.FirstWaveComputer {
274319
275320 // Find the inputs that have changed since last compilation, or were marked as needed a build
276321 private func computeChangedInputs(
277- _ moduleDependencyGraph: ModuleDependencyGraph ,
278322 _ outOfDateBuildRecord: BuildRecord
279323 ) -> [ ChangedInput ] {
280324 jobsInPhases. compileJobs. compactMap { job in
0 commit comments