Skip to content

Commit 90ddf76

Browse files
committed
[Incremental Builds][Explicit Module Builds] Switch to using incremental dependency scanning
For Explicit Module Builds, have the driver configure the dependency scanner invocation to serialize its internal scanner cache state after a scan, and attempt to deserialize a prior build's scanner cache state, and validate its contents for an incremental re-scan.
1 parent 57caff8 commit 90ddf76

File tree

13 files changed

+159
-231
lines changed

13 files changed

+159
-231
lines changed

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -315,10 +315,6 @@ public struct Driver {
315315
/// Set during planning because needs the jobs to look at outputs.
316316
@_spi(Testing) public private(set) var incrementalCompilationState: IncrementalCompilationState? = nil
317317

318-
/// Nil if not running in explicit module build mode.
319-
/// Set during planning.
320-
var interModuleDependencyGraph: InterModuleDependencyGraph? = nil
321-
322318
/// The path of the SDK.
323319
public var absoluteSDKPath: AbsolutePath? {
324320
guard let path = frontendTargetInfo.sdkPath?.path else {
@@ -1908,7 +1904,6 @@ extension Driver {
19081904
try executor.execute(
19091905
workload: .init(allJobs,
19101906
incrementalCompilationState,
1911-
interModuleDependencyGraph,
19121907
continueBuildingAfterErrors: continueBuildingAfterErrors),
19131908
delegate: jobExecutionDelegate,
19141909
numParallelJobs: numParallelJobs ?? 1,
@@ -1936,16 +1931,6 @@ extension Driver {
19361931
.warning("next compile won't be incremental; could not write dependency graph: \(error.localizedDescription)"))
19371932
/// Ensure that a bogus dependency graph is not used next time.
19381933
buildRecordInfo.removeBuildRecord()
1939-
buildRecordInfo.removeInterModuleDependencyGraph()
1940-
return
1941-
}
1942-
do {
1943-
try incrementalCompilationState.writeInterModuleDependencyGraph(buildRecordInfo)
1944-
} catch {
1945-
diagnosticEngine.emit(
1946-
.warning("next compile must run a full dependency scan; could not write inter-module dependency graph: \(error.localizedDescription)"))
1947-
buildRecordInfo.removeBuildRecord()
1948-
buildRecordInfo.removeInterModuleDependencyGraph()
19491934
return
19501935
}
19511936
}

Sources/SwiftDriver/Execution/DriverExecutor.swift

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,22 +61,27 @@ public struct DriverExecutorWorkload {
6161
}
6262

6363
public let kind: Kind
64-
public let interModuleDependencyGraph: InterModuleDependencyGraph?
64+
65+
@available(*, deprecated, message: "use of 'interModuleDependencyGraph' on 'DriverExecutorWorkload' is deprecated")
66+
public let interModuleDependencyGraph: InterModuleDependencyGraph? = nil
6567

6668
public init(_ allJobs: [Job],
6769
_ incrementalCompilationState: IncrementalCompilationState?,
68-
_ interModuleDependencyGraph: InterModuleDependencyGraph?,
6970
continueBuildingAfterErrors: Bool) {
7071
self.continueBuildingAfterErrors = continueBuildingAfterErrors
7172
self.kind = incrementalCompilationState
7273
.map {.incremental($0)}
7374
?? .all(allJobs)
74-
self.interModuleDependencyGraph = interModuleDependencyGraph
7575
}
7676

77+
static public func all(_ jobs: [Job]) -> Self {
78+
.init(jobs, nil, continueBuildingAfterErrors: false)
79+
}
80+
81+
@available(*, deprecated, message: "use all(_ jobs: [Job]) instead")
7782
static public func all(_ jobs: [Job],
78-
_ interModuleDependencyGraph: InterModuleDependencyGraph? = nil) -> Self {
79-
.init(jobs, nil, interModuleDependencyGraph, continueBuildingAfterErrors: false)
83+
_ interModuleDependencyGraph: InterModuleDependencyGraph?) -> Self {
84+
.init(jobs, nil, continueBuildingAfterErrors: false)
8085
}
8186
}
8287

@@ -119,7 +124,7 @@ extension DriverExecutor {
119124
recordedInputModificationDates: [TypedVirtualPath: TimePoint]
120125
) throws {
121126
try execute(
122-
workload: .all(jobs, nil),
127+
workload: .all(jobs),
123128
delegate: delegate,
124129
numParallelJobs: numParallelJobs,
125130
forceResponseFiles: forceResponseFiles,

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/CommonDependencyOperations.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ internal extension InterModuleDependencyGraph {
174174
reporter: reporter)
175175
}
176176

177-
if forRebuild {
177+
if forRebuild && !modulesRequiringRebuild.isEmpty {
178178
reporter?.reportExplicitDependencyReBuildSet(Array(modulesRequiringRebuild))
179179
}
180180
return modulesRequiringRebuild

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,28 @@ public extension Driver {
141141
}
142142
}
143143

144+
if (parsedOptions.contains(.driverShowIncremental) ||
145+
parsedOptions.contains(.dependencyScanCacheRemarks)) &&
146+
isFrontendArgSupported(.dependencyScanCacheRemarks) {
147+
commandLine.appendFlag(.dependencyScanCacheRemarks)
148+
}
149+
150+
if shouldAttemptIncrementalCompilation &&
151+
parsedOptions.contains(.incrementalDependencyScan) {
152+
if let serializationPath = buildRecordInfo?.dependencyScanSerializedResultPath {
153+
if isFrontendArgSupported(.validatePriorDependencyScanCache) {
154+
// Any compiler which supports "-validate-prior-dependency-scan-cache"
155+
// also supports "-load-dependency-scan-cache"
156+
// and "-serialize-dependency-scan-cache" and "-dependency-scan-cache-path"
157+
commandLine.appendFlag(.dependencyScanCachePath)
158+
commandLine.appendPath(serializationPath)
159+
commandLine.appendFlag(.reuseDependencyScanCache)
160+
commandLine.appendFlag(.validatePriorDependencyScanCache)
161+
commandLine.appendFlag(.serializeDependencyScanCache)
162+
}
163+
}
164+
}
165+
144166
// Pass on the input files
145167
commandLine.append(contentsOf: inputFiles.filter { $0.type == .swift }.map { .path($0.file) })
146168
return (inputs, commandLine)

Sources/SwiftDriver/IncrementalCompilation/BuildRecordInfo.swift

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -177,29 +177,6 @@ import class Dispatch.DispatchQueue
177177
try? fileSystem.removeFileTree(absPath)
178178
}
179179

180-
func removeInterModuleDependencyGraph() {
181-
guard let absPath = interModuleDependencyGraphPath.absolutePath else {
182-
return
183-
}
184-
try? fileSystem.removeFileTree(absPath)
185-
}
186-
187-
func readPriorInterModuleDependencyGraph(
188-
reporter: IncrementalCompilationState.Reporter?
189-
) -> InterModuleDependencyGraph? {
190-
let decodedGraph: InterModuleDependencyGraph
191-
do {
192-
let contents = try fileSystem.readFileContents(interModuleDependencyGraphPath).cString
193-
decodedGraph = try JSONDecoder().decode(InterModuleDependencyGraph.self,
194-
from: Data(contents.utf8))
195-
} catch {
196-
return nil
197-
}
198-
reporter?.report("Read inter-module dependency graph", interModuleDependencyGraphPath)
199-
200-
return decodedGraph
201-
}
202-
203180
func jobFinished(job: Job, result: ProcessResult) {
204181
self.confinementQueue.sync {
205182
finishedJobResults.append(JobResult(job, result))
@@ -220,11 +197,11 @@ import class Dispatch.DispatchQueue
220197

221198
/// A build-record-relative path to the location of a serialized copy of the
222199
/// driver's inter-module dependency graph.
223-
var interModuleDependencyGraphPath: VirtualPath {
200+
var dependencyScanSerializedResultPath: VirtualPath {
224201
let filename = buildRecordPath.basenameWithoutExt
225202
return buildRecordPath
226203
.parentDirectory
227-
.appending(component: filename + ".moduledeps")
204+
.appending(component: filename + ".swiftmoduledeps")
228205
}
229206

230207
/// Directory to emit dot files into

Sources/SwiftDriver/IncrementalCompilation/FirstWaveComputer.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ extension IncrementalCompilationState {
2626
let showJobLifecycle: Bool
2727
let alwaysRebuildDependents: Bool
2828
let interModuleDependencyGraph: InterModuleDependencyGraph?
29-
let explicitModuleDependenciesGuaranteedUpToDate: Bool
3029
/// If non-null outputs information for `-driver-show-incremental` for input path
3130
private let reporter: Reporter?
3231

@@ -47,8 +46,6 @@ extension IncrementalCompilationState {
4746
self.alwaysRebuildDependents = initialState.incrementalOptions.contains(
4847
.alwaysRebuildDependents)
4948
self.interModuleDependencyGraph = interModuleDependencyGraph
50-
self.explicitModuleDependenciesGuaranteedUpToDate =
51-
initialState.upToDatePriorInterModuleDependencyGraph != nil ? true : false
5249
self.reporter = reporter
5350
}
5451

Sources/SwiftDriver/IncrementalCompilation/IncrementalCompilationState+Extensions.swift

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ extension IncrementalCompilationState {
5050
let graph: ModuleDependencyGraph
5151
/// Information about the last known compilation, incl. the location of build artifacts such as the dependency graph.
5252
let buildRecordInfo: BuildRecordInfo
53-
/// Record about the compiled module's explicit module dependencies from a prior compile.
54-
let upToDatePriorInterModuleDependencyGraph: InterModuleDependencyGraph?
5553
/// A set of inputs invalidated by external changes.
5654
let inputsInvalidatedByExternals: TransitivelyInvalidatedSwiftSourceFileSet
5755
/// Compiler options related to incremental builds.
@@ -287,11 +285,6 @@ extension IncrementalCompilationState {
287285
report("\(message): \(externalDependency.shortDescription)")
288286
}
289287

290-
// Emits a remark indicating a need for a dependency scanning invocation
291-
func reportExplicitBuildMustReScan(_ why: String) {
292-
report("Incremental build must re-run dependency scan: \(why)")
293-
}
294-
295288
func reportExplicitDependencyOutOfDate(_ moduleName: String,
296289
inputPath: String) {
297290
report("Dependency module \(moduleName) is older than input file \(inputPath)")
@@ -413,55 +406,6 @@ extension IncrementalCompilationState {
413406
}
414407
}
415408

416-
extension IncrementalCompilationState {
417-
enum WriteInterModuleDependencyGraphError: LocalizedError {
418-
case noDependencyGraph
419-
var errorDescription: String? {
420-
switch self {
421-
case .noDependencyGraph:
422-
return "No inter-module dependency graph present"
423-
}
424-
}
425-
}
426-
427-
func writeInterModuleDependencyGraph(_ buildRecordInfo: BuildRecordInfo?) throws {
428-
// If the explicit module build is not happening, there will not be a graph to write
429-
guard info.explicitModuleBuild else {
430-
return
431-
}
432-
guard let recordInfo = buildRecordInfo else {
433-
throw WriteDependencyGraphError.noBuildRecordInfo
434-
}
435-
guard let interModuleDependencyGraph = self.upToDateInterModuleDependencyGraph else {
436-
throw WriteInterModuleDependencyGraphError.noDependencyGraph
437-
}
438-
do {
439-
let encoder = JSONEncoder()
440-
#if os(Linux) || os(Android)
441-
encoder.outputFormatting = [.prettyPrinted]
442-
#else
443-
if #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) {
444-
encoder.outputFormatting = [.prettyPrinted, .withoutEscapingSlashes]
445-
}
446-
#endif
447-
let data = try encoder.encode(interModuleDependencyGraph)
448-
try fileSystem.writeFileContents(recordInfo.interModuleDependencyGraphPath,
449-
bytes: ByteString(data),
450-
atomically: true)
451-
} catch {
452-
throw IncrementalCompilationState.WriteDependencyGraphError.couldNotWrite(
453-
path: recordInfo.interModuleDependencyGraphPath, error: error)
454-
}
455-
456-
}
457-
458-
@_spi(Testing) public static func removeInterModuleDependencyGraphFile(_ driver: Driver) {
459-
if let path = driver.buildRecordInfo?.interModuleDependencyGraphPath {
460-
try? driver.fileSystem.removeFileTree(path)
461-
}
462-
}
463-
}
464-
465409
// MARK: - OutputFileMap
466410
extension OutputFileMap {
467411
func onlySourceFilesHaveSwiftDeps() -> Bool {

Sources/SwiftDriver/IncrementalCompilation/IncrementalCompilationState.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ public final class IncrementalCompilationState {
5353
internal init(
5454
driver: inout Driver,
5555
jobsInPhases: JobsInPhases,
56-
initialState: InitialStateForPlanning
56+
initialState: InitialStateForPlanning,
57+
interModuleDepGraph: InterModuleDependencyGraph?
5758
) throws {
5859
let reporter = initialState.incrementalOptions.contains(.showIncremental)
5960
? Reporter(diagnosticEngine: driver.diagnosticEngine,
@@ -64,12 +65,12 @@ public final class IncrementalCompilationState {
6465
initialState: initialState,
6566
jobsInPhases: jobsInPhases,
6667
driver: driver,
67-
interModuleDependencyGraph: driver.interModuleDependencyGraph,
68+
interModuleDependencyGraph: interModuleDepGraph,
6869
reporter: reporter)
6970
.compute(batchJobFormer: &driver)
7071

7172
self.info = initialState.graph.info
72-
self.upToDateInterModuleDependencyGraph = driver.interModuleDependencyGraph
73+
self.upToDateInterModuleDependencyGraph = interModuleDepGraph
7374
self.protectedState = ProtectedState(
7475
skippedCompileJobs: firstWave.initiallySkippedCompileJobs,
7576
initialState.graph,

Sources/SwiftDriver/IncrementalCompilation/IncrementalDependencyAndInputSetup.swift

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,6 @@ extension IncrementalCompilationState {
5858
).computeInitialStateForPlanning(driver: &driver)
5959
else {
6060
Self.removeDependencyGraphFile(driver)
61-
if options.contains(.explicitModuleBuild) {
62-
Self.removeInterModuleDependencyGraphFile(driver)
63-
}
6461
return nil
6562
}
6663

@@ -96,42 +93,6 @@ extension IncrementalCompilationState {
9693
}
9794
}
9895

99-
/// Validate if a prior inter-module dependency graph is still valid
100-
extension IncrementalCompilationState.IncrementalDependencyAndInputSetup {
101-
static func readAndValidatePriorInterModuleDependencyGraph(
102-
driver: inout Driver,
103-
buildRecordInfo: BuildRecordInfo,
104-
reporter: IncrementalCompilationState.Reporter?
105-
) throws -> InterModuleDependencyGraph? {
106-
// Attempt to read a serialized inter-module dependency graph from a prior build
107-
guard let priorInterModuleDependencyGraph =
108-
buildRecordInfo.readPriorInterModuleDependencyGraph(reporter: reporter),
109-
let priorImports = priorInterModuleDependencyGraph.mainModule.directDependencies?.map({ $0.moduleName }) else {
110-
reporter?.reportExplicitBuildMustReScan("Could not read inter-module dependency graph at \(buildRecordInfo.interModuleDependencyGraphPath)")
111-
return nil
112-
}
113-
114-
// Verify that import sets match
115-
let currentImports = try driver.performImportPrescan().imports
116-
guard Set(priorImports) == Set(currentImports) else {
117-
reporter?.reportExplicitBuildMustReScan("Target import set has changed.")
118-
return nil
119-
}
120-
121-
// Verify that each dependnecy is up-to-date with respect to its inputs
122-
guard try priorInterModuleDependencyGraph.computeInvalidatedModuleDependencies(fileSystem: buildRecordInfo.fileSystem,
123-
cas: driver.cas,
124-
forRebuild: false,
125-
reporter: reporter).isEmpty else {
126-
reporter?.reportExplicitBuildMustReScan("Not all dependencies are up-to-date.")
127-
return nil
128-
}
129-
130-
reporter?.report("Confirmed prior inter-module dependency graph is up-to-date at: \(buildRecordInfo.interModuleDependencyGraphPath)")
131-
return priorInterModuleDependencyGraph
132-
}
133-
}
134-
13596
/// Builds the `InitialState`
13697
/// Also bundles up an bunch of configuration info
13798
extension IncrementalCompilationState {
@@ -196,23 +157,8 @@ extension IncrementalCompilationState {
196157
return nil
197158
}
198159

199-
// If a valid build record could not be produced, do not bother here
200-
let priorInterModuleDependencyGraph: InterModuleDependencyGraph?
201-
if options.contains(.explicitModuleBuild) {
202-
if priors.graph.buildRecord.inputInfos.isEmpty {
203-
reporter?.report("Incremental compilation did not attempt to read inter-module dependency graph.")
204-
priorInterModuleDependencyGraph = nil
205-
} else {
206-
priorInterModuleDependencyGraph = try Self.readAndValidatePriorInterModuleDependencyGraph(
207-
driver: &driver, buildRecordInfo: buildRecordInfo, reporter: reporter)
208-
}
209-
} else {
210-
priorInterModuleDependencyGraph = nil
211-
}
212-
213160
return InitialStateForPlanning(
214161
graph: priors.graph, buildRecordInfo: buildRecordInfo,
215-
upToDatePriorInterModuleDependencyGraph: priorInterModuleDependencyGraph,
216162
inputsInvalidatedByExternals: priors.fileSet,
217163
incrementalOptions: options)
218164
}

0 commit comments

Comments
 (0)