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