Skip to content

Commit c9383cc

Browse files
Dependencies: refactor Clang task action dependencies handling to share code between modular and non-modular compiles
1 parent 4b8519a commit c9383cc

File tree

1 file changed

+73
-67
lines changed

1 file changed

+73
-67
lines changed

Sources/SWBTaskExecution/TaskActions/ClangCompileTaskAction.swift

Lines changed: 73 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -337,28 +337,12 @@ public final class ClangCompileTaskAction: TaskAction, BuildValueValidatingTaskA
337337

338338
if lastResult == .succeeded {
339339
// 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+
)
362346
}
363347

364348
return lastResult ?? .failed
@@ -368,30 +352,7 @@ public final class ClangCompileTaskAction: TaskAction, BuildValueValidatingTaskA
368352
}
369353
}
370354

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+
395356

396357
/// Intended to be called during task dependency setup.
397358
/// If remote caching is enabled along with integrated cache queries, it will request
@@ -512,6 +473,66 @@ public final class ClangCompileTaskAction: TaskAction, BuildValueValidatingTaskA
512473
activityReporter: dynamicExecutionDelegate
513474
)
514475
}
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+
}
515536
}
516537

517538
public final class ClangNonModularCompileTaskAction: TaskAction {
@@ -560,27 +581,12 @@ public final class ClangNonModularCompileTaskAction: TaskAction {
560581
let execResult = processDelegate.commandResult ?? .failed
561582

562583
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+
)
584590
}
585591

586592
return execResult

0 commit comments

Comments
 (0)