@@ -260,6 +260,7 @@ internal extension InterModuleDependencyGraph {
260
260
/// between it and the root (source module being built by this driver
261
261
/// instance) must also be re-built.
262
262
func computeInvalidatedModuleDependencies( fileSystem: FileSystem ,
263
+ forRebuild: Bool ,
263
264
reporter: IncrementalCompilationState . Reporter ? = nil )
264
265
throws -> Set < ModuleDependencyId > {
265
266
let mainModuleInfo = mainModule
@@ -270,10 +271,13 @@ internal extension InterModuleDependencyGraph {
270
271
for dependencyId in mainModuleInfo. directDependencies ?? [ ] {
271
272
try outOfDateModuleScan ( from: dependencyId, visited: & visited,
272
273
modulesRequiringRebuild: & modulesRequiringRebuild,
273
- fileSystem: fileSystem, reporter: reporter)
274
+ fileSystem: fileSystem, forRebuild: forRebuild,
275
+ reporter: reporter)
274
276
}
275
277
276
- reporter? . reportExplicitDependencyReBuildSet ( Array ( modulesRequiringRebuild) )
278
+ if forRebuild {
279
+ reporter? . reportExplicitDependencyReBuildSet ( Array ( modulesRequiringRebuild) )
280
+ }
277
281
return modulesRequiringRebuild
278
282
}
279
283
@@ -284,46 +288,124 @@ internal extension InterModuleDependencyGraph {
284
288
visited: inout Set < ModuleDependencyId > ,
285
289
modulesRequiringRebuild: inout Set < ModuleDependencyId > ,
286
290
fileSystem: FileSystem ,
291
+ forRebuild: Bool ,
287
292
reporter: IncrementalCompilationState . Reporter ? = nil ) throws {
293
+ let reportOutOfDate = { ( name: String , reason: String ) in
294
+ if forRebuild {
295
+ reporter? . reportExplicitDependencyWillBeReBuilt ( sourceModuleId. moduleNameForDiagnostic, reason: reason)
296
+ } else {
297
+ reporter? . reportPriorExplicitDependencyStale ( sourceModuleId. moduleNameForDiagnostic, reason: reason)
298
+ }
299
+ }
300
+
288
301
let sourceModuleInfo = try moduleInfo ( of: sourceModuleId)
289
302
// Visit the module's dependencies
290
303
var hasOutOfDateModuleDependency = false
291
- var mostRecentlyUpdatedDependencyOutput : TimePoint = . zero
292
304
for dependencyId in sourceModuleInfo. directDependencies ?? [ ] {
293
305
// If we have not already visited this module, recurse.
294
306
if !visited. contains ( dependencyId) {
295
307
try outOfDateModuleScan ( from: dependencyId, visited: & visited,
296
308
modulesRequiringRebuild: & modulesRequiringRebuild,
297
- fileSystem: fileSystem, reporter: reporter)
309
+ fileSystem: fileSystem, forRebuild: forRebuild,
310
+ reporter: reporter)
298
311
}
299
312
// Even if we're not revisiting a dependency, we must check if it's already known to be out of date.
300
313
hasOutOfDateModuleDependency = hasOutOfDateModuleDependency || modulesRequiringRebuild. contains ( dependencyId)
301
-
302
- // Keep track of dependencies' output file time stamp to determine if it is newer than the current module.
303
- if let depOutputTimeStamp = try ? fileSystem. lastModificationTime ( for: VirtualPath . lookup ( moduleInfo ( of: dependencyId) . modulePath. path) ) ,
304
- depOutputTimeStamp > mostRecentlyUpdatedDependencyOutput {
305
- mostRecentlyUpdatedDependencyOutput = depOutputTimeStamp
306
- }
307
314
}
308
315
309
316
if hasOutOfDateModuleDependency {
310
- reporter? . reportExplicitDependencyWillBeReBuilt ( sourceModuleId. moduleNameForDiagnostic, reason: " Invalidated by downstream dependency " )
311
- modulesRequiringRebuild. insert ( sourceModuleId)
312
- } else if try ! IncrementalCompilationState. IncrementalDependencyAndInputSetup. verifyModuleDependencyUpToDate ( moduleID: sourceModuleId, moduleInfo: sourceModuleInfo,
313
- fileSystem: fileSystem, reporter: reporter) {
314
- reporter? . reportExplicitDependencyWillBeReBuilt ( sourceModuleId. moduleNameForDiagnostic, reason: " Out-of-date " )
317
+ reportOutOfDate ( sourceModuleId. moduleNameForDiagnostic, " Invalidated by downstream dependency " )
315
318
modulesRequiringRebuild. insert ( sourceModuleId)
316
- } else if let outputModTime = try ? fileSystem. lastModificationTime ( for: VirtualPath . lookup ( sourceModuleInfo. modulePath. path) ) ,
317
- outputModTime < mostRecentlyUpdatedDependencyOutput {
318
- // If a prior variant of this module dependnecy exists, and is older than any of its direct or transitive
319
- // module dependency outputs, it must also be re-built.
320
- reporter? . reportExplicitDependencyWillBeReBuilt ( sourceModuleId. moduleNameForDiagnostic, reason: " Has newer module dependency inputs " )
319
+ } else if try ! verifyModuleDependencyUpToDate( moduleID: sourceModuleId, fileSystem: fileSystem, reporter: reporter) {
320
+ reportOutOfDate ( sourceModuleId. moduleNameForDiagnostic, " Out-of-date " )
321
321
modulesRequiringRebuild. insert ( sourceModuleId)
322
322
}
323
323
324
324
// Now that we've determined if this module must be rebuilt, mark it as visited.
325
325
visited. insert ( sourceModuleId)
326
326
}
327
+
328
+ func verifyModuleDependencyUpToDate( moduleID: ModuleDependencyId ,
329
+ fileSystem: FileSystem ,
330
+ reporter: IncrementalCompilationState . Reporter ? ) throws -> Bool {
331
+ let checkedModuleInfo = try moduleInfo ( of: moduleID)
332
+ // Verify that the specified input exists and is older than the specified output
333
+ let verifyInputOlderThanOutputModTime : ( String , VirtualPath , TimePoint ) -> Bool =
334
+ { moduleName, inputPath, outputModTime in
335
+ guard let inputModTime =
336
+ try ? fileSystem. lastModificationTime ( for: inputPath) else {
337
+ reporter? . report ( " Unable to 'stat' \( inputPath. description) " )
338
+ return false
339
+ }
340
+ if inputModTime > outputModTime {
341
+ reporter? . reportExplicitDependencyOutOfDate ( moduleName,
342
+ inputPath: inputPath. description)
343
+ return false
344
+ }
345
+ return true
346
+ }
347
+
348
+ // Check if the output file exists
349
+ guard let outputModTime = try ? fileSystem. lastModificationTime ( for: VirtualPath . lookup ( checkedModuleInfo. modulePath. path) ) else {
350
+ reporter? . report ( " Module output not found: ' \( moduleID. moduleNameForDiagnostic) ' " )
351
+ return false
352
+ }
353
+
354
+ // Check if a dependency of this module has a newer output than this module
355
+ for dependencyId in checkedModuleInfo. directDependencies ?? [ ] {
356
+ let dependencyInfo = try moduleInfo ( of: dependencyId)
357
+ if !verifyInputOlderThanOutputModTime( moduleID. moduleName,
358
+ VirtualPath . lookup ( dependencyInfo. modulePath. path) ,
359
+ outputModTime) {
360
+ return false
361
+ }
362
+ }
363
+
364
+ // Check if any of the textual sources of this module are newer than this module
365
+ switch checkedModuleInfo. details {
366
+ case . swift( let swiftDetails) :
367
+ if let moduleInterfacePath = swiftDetails. moduleInterfacePath {
368
+ if !verifyInputOlderThanOutputModTime( moduleID. moduleName,
369
+ VirtualPath . lookup ( moduleInterfacePath. path) ,
370
+ outputModTime) {
371
+ return false
372
+ }
373
+ }
374
+ if let bridgingHeaderPath = swiftDetails. bridgingHeaderPath {
375
+ if !verifyInputOlderThanOutputModTime( moduleID. moduleName,
376
+ VirtualPath . lookup ( bridgingHeaderPath. path) ,
377
+ outputModTime) {
378
+ return false
379
+ }
380
+ }
381
+ for bridgingSourceFile in swiftDetails. bridgingSourceFiles ?? [ ] {
382
+ if !verifyInputOlderThanOutputModTime( moduleID. moduleName,
383
+ VirtualPath . lookup ( bridgingSourceFile. path) ,
384
+ outputModTime) {
385
+ return false
386
+ }
387
+ }
388
+ case . clang( _) :
389
+ for inputSourceFile in checkedModuleInfo. sourceFiles ?? [ ] {
390
+ if !verifyInputOlderThanOutputModTime( moduleID. moduleName,
391
+ try VirtualPath ( path: inputSourceFile) ,
392
+ outputModTime) {
393
+ return false
394
+ }
395
+ }
396
+ case . swiftPrebuiltExternal( _) :
397
+ // TODO: We have to give-up here until we have a way to verify the timestamp of the binary module.
398
+ // We can do better here by knowing if this module hasn't changed - which would allows us to not
399
+ // invalidate any of the dependencies that depend on it.
400
+ reporter? . report ( " Unable to verify binary module dependency up-to-date: \( moduleID. moduleNameForDiagnostic) " )
401
+ return false ;
402
+ case . swiftPlaceholder( _) :
403
+ // TODO: This should never ever happen. Hard error?
404
+ return false ;
405
+ }
406
+
407
+ return true
408
+ }
327
409
}
328
410
329
411
internal extension InterModuleDependencyGraph {
0 commit comments