@@ -337,28 +337,12 @@ public final class ClangCompileTaskAction: TaskAction, BuildValueValidatingTaskA
337
337
338
338
if lastResult == . succeeded {
339
339
// Verify the dependencies from the trace data.
340
- let payload : DependencyValidationInfo . Payload
341
- if let traceFilePath {
342
- let fs = executionDelegate. fs
343
- let traceData = try JSONDecoder ( ) . decode ( Array< TraceData> . self , from: Data ( fs. read ( traceFilePath) ) )
344
-
345
- var allFiles = Set < Path > ( )
346
- traceData. forEach { allFiles. formUnion ( Set ( $0. includes) ) }
347
- let ( imports, includes) = separateImportsFromIncludes ( allFiles)
348
- payload = . clangDependencies( imports: imports, includes: includes)
349
- } else {
350
- payload = . unsupported
351
- }
352
-
353
- if let dependencyValidationOutputPath {
354
- let validationInfo = DependencyValidationInfo ( payload: payload)
355
- _ = try executionDelegate. fs. writeIfChanged (
356
- dependencyValidationOutputPath,
357
- contents: ByteString (
358
- JSONEncoder ( outputFormatting: . sortedKeys) . encode ( validationInfo)
359
- )
360
- )
361
- }
340
+ try Self . handleDependencyValidation (
341
+ traceFilePath: traceFilePath,
342
+ dependencyValidationOutputPath: dependencyValidationOutputPath,
343
+ fileSystem: executionDelegate. fs,
344
+ isModular: true
345
+ )
362
346
}
363
347
364
348
return lastResult ?? . failed
@@ -368,30 +352,7 @@ public final class ClangCompileTaskAction: TaskAction, BuildValueValidatingTaskA
368
352
}
369
353
}
370
354
371
- // Clang's dependency tracing does not currently clearly distinguish modular imports from non-modular includes.
372
- // Until that gets fixed, just guess that if the file is contained in a framework, it comes from a module with
373
- // the same name. That is obviously not going to be reliable but it unblocks us from continuing experiments with
374
- // dependency specifications.
375
- private func separateImportsFromIncludes( _ files: Set < Path > ) -> ( [ DependencyValidationInfo . Import ] , [ Path ] ) {
376
- func findFrameworkName( _ file: Path ) -> String ? {
377
- if file. fileExtension == " framework " {
378
- return file. basenameWithoutSuffix
379
- }
380
- return file. dirname. isEmpty || file. dirname. isRoot ? nil : findFrameworkName ( file. dirname)
381
- }
382
- var moduleNames : [ String ] = [ ]
383
- var includeFiles : [ Path ] = [ ]
384
- for file in files {
385
- if let frameworkName = findFrameworkName ( file) {
386
- moduleNames. append ( frameworkName)
387
- } else {
388
- includeFiles. append ( file)
389
- }
390
- }
391
- let moduleDependencies = moduleNames. map { ModuleDependency ( name: $0, accessLevel: . Private, optional: false ) }
392
- let moduleImports = moduleDependencies. map { DependencyValidationInfo . Import ( dependency: $0, importLocations: [ ] ) }
393
- return ( moduleImports, includeFiles)
394
- }
355
+
395
356
396
357
/// Intended to be called during task dependency setup.
397
358
/// If remote caching is enabled along with integrated cache queries, it will request
@@ -512,6 +473,66 @@ public final class ClangCompileTaskAction: TaskAction, BuildValueValidatingTaskA
512
473
activityReporter: dynamicExecutionDelegate
513
474
)
514
475
}
476
+
477
+ /// Handles dependency validation by reading trace data and writing out DependencyValidationInfo.
478
+ /// This is shared between modular and non-modular compilation tasks.
479
+ fileprivate static func handleDependencyValidation(
480
+ traceFilePath: Path ? ,
481
+ dependencyValidationOutputPath: Path ? ,
482
+ fileSystem: any FSProxy ,
483
+ isModular: Bool
484
+ ) throws {
485
+ let payload : DependencyValidationInfo . Payload
486
+ if let traceFilePath {
487
+ let traceData = try JSONDecoder ( ) . decode ( Array< TraceData> . self , from: Data ( fileSystem. read ( traceFilePath) ) )
488
+ var allFiles = Set < Path > ( )
489
+ traceData. forEach { allFiles. formUnion ( Set ( $0. includes) ) }
490
+
491
+ if isModular {
492
+ let ( imports, includes) = separateImportsFromIncludes ( allFiles)
493
+ payload = . clangDependencies( imports: imports, includes: includes)
494
+ } else {
495
+ payload = . clangDependencies( imports: [ ] , includes: Array ( allFiles) )
496
+ }
497
+ } else {
498
+ payload = . unsupported
499
+ }
500
+
501
+ if let dependencyValidationOutputPath {
502
+ let validationInfo = DependencyValidationInfo ( payload: payload)
503
+ _ = try fileSystem. writeIfChanged (
504
+ dependencyValidationOutputPath,
505
+ contents: ByteString (
506
+ JSONEncoder ( outputFormatting: . sortedKeys) . encode ( validationInfo)
507
+ )
508
+ )
509
+ }
510
+ }
511
+
512
+ // Clang's dependency tracing does not currently clearly distinguish modular imports from non-modular includes.
513
+ // Until that gets fixed, just guess that if the file is contained in a framework, it comes from a module with
514
+ // the same name. That is obviously not going to be reliable but it unblocks us from continuing experiments with
515
+ // dependency specifications.
516
+ private static func separateImportsFromIncludes( _ files: Set < Path > ) -> ( [ DependencyValidationInfo . Import ] , [ Path ] ) {
517
+ func findFrameworkName( _ file: Path ) -> String ? {
518
+ if file. fileExtension == " framework " {
519
+ return file. basenameWithoutSuffix
520
+ }
521
+ return file. dirname. isEmpty || file. dirname. isRoot ? nil : findFrameworkName ( file. dirname)
522
+ }
523
+ var moduleNames : [ String ] = [ ]
524
+ var includeFiles : [ Path ] = [ ]
525
+ for file in files {
526
+ if let frameworkName = findFrameworkName ( file) {
527
+ moduleNames. append ( frameworkName)
528
+ } else {
529
+ includeFiles. append ( file)
530
+ }
531
+ }
532
+ let moduleDependencies = moduleNames. map { ModuleDependency ( name: $0, accessLevel: . Private, optional: false ) }
533
+ let moduleImports = moduleDependencies. map { DependencyValidationInfo . Import ( dependency: $0, importLocations: [ ] ) }
534
+ return ( moduleImports, includeFiles)
535
+ }
515
536
}
516
537
517
538
public final class ClangNonModularCompileTaskAction : TaskAction {
@@ -560,27 +581,12 @@ public final class ClangNonModularCompileTaskAction: TaskAction {
560
581
let execResult = processDelegate. commandResult ?? . failed
561
582
562
583
if execResult == . succeeded {
563
- let payload : DependencyValidationInfo . Payload
564
- if let traceFilePath {
565
- let fs = executionDelegate. fs
566
- let traceData = try JSONDecoder ( ) . decode ( Array< TraceData> . self , from: fs. readMemoryMapped ( traceFilePath) )
567
-
568
- var allFiles = Set < Path > ( )
569
- traceData. forEach { allFiles. formUnion ( Set ( $0. includes) ) }
570
- payload = . clangDependencies( imports: [ ] , includes: Array ( allFiles) )
571
- } else {
572
- payload = . unsupported
573
- }
574
-
575
- if let dependencyValidationOutputPath {
576
- let validationInfo = DependencyValidationInfo ( payload: payload)
577
- _ = try executionDelegate. fs. writeIfChanged (
578
- dependencyValidationOutputPath,
579
- contents: ByteString (
580
- JSONEncoder ( outputFormatting: . sortedKeys) . encode ( validationInfo)
581
- )
582
- )
583
- }
584
+ try ClangCompileTaskAction . handleDependencyValidation (
585
+ traceFilePath: traceFilePath,
586
+ dependencyValidationOutputPath: dependencyValidationOutputPath,
587
+ fileSystem: executionDelegate. fs,
588
+ isModular: false
589
+ )
584
590
}
585
591
586
592
return execResult
0 commit comments