diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index 323578c6b..fda7212cf 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -315,6 +315,10 @@ public struct Driver { /// Set during planning because needs the jobs to look at outputs. @_spi(Testing) public private(set) var incrementalCompilationState: IncrementalCompilationState? = nil + /// Nil if not running in explicit module build mode. + /// Set during planning. + var interModuleDependencyGraph: InterModuleDependencyGraph? = nil + /// The path of the SDK. public var absoluteSDKPath: AbsolutePath? { guard let path = frontendTargetInfo.sdkPath?.path else { @@ -1664,6 +1668,7 @@ extension Driver { try executor.execute( workload: .init(allJobs, incrementalCompilationState, + interModuleDependencyGraph, continueBuildingAfterErrors: continueBuildingAfterErrors), delegate: jobExecutionDelegate, numParallelJobs: numParallelJobs ?? 1, diff --git a/Sources/SwiftDriver/Execution/DriverExecutor.swift b/Sources/SwiftDriver/Execution/DriverExecutor.swift index 3968b1941..b93c45ad6 100644 --- a/Sources/SwiftDriver/Execution/DriverExecutor.swift +++ b/Sources/SwiftDriver/Execution/DriverExecutor.swift @@ -29,6 +29,7 @@ public protocol DriverExecutor { /// Execute multiple jobs, tracking job status using the provided execution delegate. /// Pass in the `IncrementalCompilationState` to allow for incremental compilation. + /// Pass in the `InterModuleDependencyGraph` to allow for module dependency tracking. func execute(workload: DriverExecutorWorkload, delegate: JobExecutionDelegate, numParallelJobs: Int, @@ -58,20 +59,24 @@ public struct DriverExecutorWorkload { case all([Job]) case incremental(IncrementalCompilationState) } + public let kind: Kind + public let interModuleDependencyGraph: InterModuleDependencyGraph? public init(_ allJobs: [Job], - _ incrementalCompilationState: IncrementalCompilationState?, - continueBuildingAfterErrors: Bool - ) { - self.continueBuildingAfterErrors = continueBuildingAfterErrors - self.kind = incrementalCompilationState - .map {.incremental($0)} - ?? .all(allJobs) + _ incrementalCompilationState: IncrementalCompilationState?, + _ interModuleDependencyGraph: InterModuleDependencyGraph?, + continueBuildingAfterErrors: Bool) { + self.continueBuildingAfterErrors = continueBuildingAfterErrors + self.kind = incrementalCompilationState + .map {.incremental($0)} + ?? .all(allJobs) + self.interModuleDependencyGraph = interModuleDependencyGraph } - static public func all(_ jobs: [Job]) -> Self { - .init(jobs, nil, continueBuildingAfterErrors: false) + static public func all(_ jobs: [Job], + _ interModuleDependencyGraph: InterModuleDependencyGraph? = nil) -> Self { + .init(jobs, nil, interModuleDependencyGraph, continueBuildingAfterErrors: false) } } @@ -114,7 +119,7 @@ extension DriverExecutor { recordedInputModificationDates: [TypedVirtualPath: TimePoint] ) throws { try execute( - workload: .all(jobs), + workload: .all(jobs, nil), delegate: delegate, numParallelJobs: numParallelJobs, forceResponseFiles: forceResponseFiles, diff --git a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift index ffb83cae0..47374b247 100644 --- a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift +++ b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift @@ -86,7 +86,7 @@ extension ModuleDependencyId: Codable { } /// Bridging header -public struct BridgingHeader: Codable { +public struct BridgingHeader: Codable, Hashable { var path: TextualVirtualPath /// The source files referenced by the bridging header. var sourceFiles: [TextualVirtualPath] @@ -95,7 +95,7 @@ public struct BridgingHeader: Codable { } /// Details specific to Swift modules. -public struct SwiftModuleDetails: Codable { +public struct SwiftModuleDetails: Codable, Hashable { /// The module interface from which this module was built, if any. public var moduleInterfacePath: TextualVirtualPath? @@ -141,7 +141,7 @@ public struct SwiftModuleDetails: Codable { } /// Details specific to Swift placeholder dependencies. -public struct SwiftPlaceholderModuleDetails: Codable { +public struct SwiftPlaceholderModuleDetails: Codable, Hashable { /// The path to the .swiftModuleDoc file. var moduleDocPath: TextualVirtualPath? @@ -150,7 +150,7 @@ public struct SwiftPlaceholderModuleDetails: Codable { } /// Details specific to Swift externally-pre-built modules. -public struct SwiftPrebuiltExternalModuleDetails: Codable { +public struct SwiftPrebuiltExternalModuleDetails: Codable, Hashable { /// The path to the already-compiled module that must be used instead of /// generating a job to build this module. public var compiledModulePath: TextualVirtualPath @@ -185,7 +185,7 @@ public struct SwiftPrebuiltExternalModuleDetails: Codable { } /// Details specific to Clang modules. -public struct ClangModuleDetails: Codable { +public struct ClangModuleDetails: Codable, Hashable { /// The path to the module map used to build this module. public var moduleMapPath: TextualVirtualPath @@ -215,7 +215,7 @@ public struct ClangModuleDetails: Codable { } } -public struct ModuleInfo: Codable { +public struct ModuleInfo: Codable, Hashable { /// The path for the module. public var modulePath: TextualVirtualPath @@ -229,7 +229,7 @@ public struct ModuleInfo: Codable { public var details: Details /// Specific details of a particular kind of module. - public enum Details { + public enum Details: Hashable { /// Swift modules may be built from a module interface, and may have /// a bridging header. case swift(SwiftModuleDetails) diff --git a/Sources/SwiftDriver/IncrementalCompilation/IncrementalCompilationState.swift b/Sources/SwiftDriver/IncrementalCompilation/IncrementalCompilationState.swift index 2be111fb7..461bc6a87 100644 --- a/Sources/SwiftDriver/IncrementalCompilation/IncrementalCompilationState.swift +++ b/Sources/SwiftDriver/IncrementalCompilation/IncrementalCompilationState.swift @@ -53,8 +53,7 @@ public final class IncrementalCompilationState { internal init( driver: inout Driver, jobsInPhases: JobsInPhases, - initialState: InitialStateForPlanning, - interModuleDependencyGraph: InterModuleDependencyGraph? + initialState: InitialStateForPlanning ) throws { let reporter = initialState.incrementalOptions.contains(.showIncremental) ? Reporter(diagnosticEngine: driver.diagnosticEngine, @@ -68,12 +67,12 @@ public final class IncrementalCompilationState { initialState: initialState, jobsInPhases: jobsInPhases, driver: driver, - interModuleDependencyGraph: interModuleDependencyGraph, + interModuleDependencyGraph: driver.interModuleDependencyGraph, reporter: reporter) .compute(batchJobFormer: &driver) self.info = initialState.graph.info - self.upToDateInterModuleDependencyGraph = interModuleDependencyGraph + self.upToDateInterModuleDependencyGraph = driver.interModuleDependencyGraph self.protectedState = ProtectedState( skippedCompileGroups: firstWave.initiallySkippedCompileGroups, initialState.graph, diff --git a/Sources/SwiftDriver/Jobs/Planning.swift b/Sources/SwiftDriver/Jobs/Planning.swift index 1b18dd2a0..52a4dcc96 100644 --- a/Sources/SwiftDriver/Jobs/Planning.swift +++ b/Sources/SwiftDriver/Jobs/Planning.swift @@ -103,7 +103,7 @@ extension Driver { try IncrementalCompilationState.computeIncrementalStateForPlanning(driver: &self) // For an explicit build, compute the inter-module dependency graph - let interModuleDependencyGraph = try computeInterModuleDependencyGraph(with: initialIncrementalState) + interModuleDependencyGraph = try computeInterModuleDependencyGraph(with: initialIncrementalState) // Compute the set of all jobs required to build this module let jobsInPhases = try computeJobsForPhasedStandardBuild(with: interModuleDependencyGraph) @@ -115,8 +115,7 @@ extension Driver { incrementalCompilationState = try IncrementalCompilationState(driver: &self, jobsInPhases: jobsInPhases, - initialState: initialState, - interModuleDependencyGraph: interModuleDependencyGraph) + initialState: initialState) } else { incrementalCompilationState = nil } @@ -139,19 +138,17 @@ extension Driver { private mutating func computeInterModuleDependencyGraph(with initialIncrementalState: IncrementalCompilationState.InitialStateForPlanning?) throws -> InterModuleDependencyGraph? { - let interModuleDependencyGraph: InterModuleDependencyGraph? if (parsedOptions.contains(.driverExplicitModuleBuild) || parsedOptions.contains(.explainModuleDependency)) && inputFiles.contains(where: { $0.type.isPartOfSwiftCompilation }) { // If the incremental build record's module dependency graph is up-to-date, we // can skip dependency scanning entirely. - interModuleDependencyGraph = + return try initialIncrementalState?.upToDatePriorInterModuleDependencyGraph ?? gatherModuleDependencies() } else { - interModuleDependencyGraph = nil + return nil } - return interModuleDependencyGraph } /// Construct a build plan consisting of *all* jobs required for building the current module (non-incrementally). diff --git a/Sources/swift-build-sdk-interfaces/main.swift b/Sources/swift-build-sdk-interfaces/main.swift index e34b4a6df..07eced80c 100644 --- a/Sources/swift-build-sdk-interfaces/main.swift +++ b/Sources/swift-build-sdk-interfaces/main.swift @@ -181,7 +181,7 @@ do { } } do { - try executor.execute(workload: DriverExecutorWorkload.init(jobs, nil, continueBuildingAfterErrors: true), + try executor.execute(workload: DriverExecutorWorkload.init(jobs, nil, nil, continueBuildingAfterErrors: true), delegate: delegate, numParallelJobs: 128) } catch { // Only fail when critical failures happened. @@ -191,7 +191,7 @@ do { } do { if !danglingJobs.isEmpty && delegate.shouldRunDanglingJobs { - try executor.execute(workload: DriverExecutorWorkload.init(danglingJobs, nil, continueBuildingAfterErrors: true), delegate: delegate, numParallelJobs: 128) + try executor.execute(workload: DriverExecutorWorkload.init(danglingJobs, nil, nil, continueBuildingAfterErrors: true), delegate: delegate, numParallelJobs: 128) } } catch { // Failing of dangling jobs don't fail the process.