Skip to content

Commit 9e366d4

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 9cd5310 commit 9e366d4

File tree

13 files changed

+149
-229
lines changed

13 files changed

+149
-229
lines changed

Sources/SwiftDriver/Driver/Driver.swift

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

321-
/// Nil if not running in explicit module build mode.
322-
/// Set during planning.
323-
var interModuleDependencyGraph: InterModuleDependencyGraph? = nil
324-
325321
/// The path of the SDK.
326322
public var absoluteSDKPath: AbsolutePath? {
327323
guard let path = frontendTargetInfo.sdkPath?.path else {
@@ -1911,7 +1907,6 @@ extension Driver {
19111907
try executor.execute(
19121908
workload: .init(allJobs,
19131909
incrementalCompilationState,
1914-
interModuleDependencyGraph,
19151910
continueBuildingAfterErrors: continueBuildingAfterErrors),
19161911
delegate: jobExecutionDelegate,
19171912
numParallelJobs: numParallelJobs ?? 1,
@@ -1939,16 +1934,6 @@ extension Driver {
19391934
.warning("next compile won't be incremental; could not write dependency graph: \(error.localizedDescription)"))
19401935
/// Ensure that a bogus dependency graph is not used next time.
19411936
buildRecordInfo.removeBuildRecord()
1942-
buildRecordInfo.removeInterModuleDependencyGraph()
1943-
return
1944-
}
1945-
do {
1946-
try incrementalCompilationState.writeInterModuleDependencyGraph(buildRecordInfo)
1947-
} catch {
1948-
diagnosticEngine.emit(
1949-
.warning("next compile must run a full dependency scan; could not write inter-module dependency graph: \(error.localizedDescription)"))
1950-
buildRecordInfo.removeBuildRecord()
1951-
buildRecordInfo.removeInterModuleDependencyGraph()
19521937
return
19531938
}
19541939
}

Sources/SwiftDriver/Execution/DriverExecutor.swift

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

6363
public let kind: Kind
64-
public let interModuleDependencyGraph: InterModuleDependencyGraph?
6564

6665
public init(_ allJobs: [Job],
6766
_ incrementalCompilationState: IncrementalCompilationState?,
68-
_ interModuleDependencyGraph: InterModuleDependencyGraph?,
6967
continueBuildingAfterErrors: Bool) {
7068
self.continueBuildingAfterErrors = continueBuildingAfterErrors
7169
self.kind = incrementalCompilationState
7270
.map {.incremental($0)}
7371
?? .all(allJobs)
74-
self.interModuleDependencyGraph = interModuleDependencyGraph
7572
}
7673

77-
static public func all(_ jobs: [Job],
78-
_ interModuleDependencyGraph: InterModuleDependencyGraph? = nil) -> Self {
79-
.init(jobs, nil, interModuleDependencyGraph, continueBuildingAfterErrors: false)
74+
static public func all(_ jobs: [Job]) -> Self {
75+
.init(jobs, nil, continueBuildingAfterErrors: false)
8076
}
8177
}
8278

@@ -119,7 +115,7 @@ extension DriverExecutor {
119115
recordedInputModificationDates: [TypedVirtualPath: TimePoint]
120116
) throws {
121117
try execute(
122-
workload: .all(jobs, nil),
118+
workload: .all(jobs),
123119
delegate: delegate,
124120
numParallelJobs: numParallelJobs,
125121
forceResponseFiles: forceResponseFiles,

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/CommonDependencyOperations.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ internal extension InterModuleDependencyGraph {
281281
reporter: reporter)
282282
}
283283

284-
if forRebuild {
284+
if forRebuild && !modulesRequiringRebuild.isEmpty {
285285
reporter?.reportExplicitDependencyReBuildSet(Array(modulesRequiringRebuild))
286286
}
287287
return modulesRequiringRebuild

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,27 @@ 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+
if let serializationPath = buildRecordInfo?.dependencyScanSerializedResultPath {
152+
if isFrontendArgSupported(.validatePriorDependencyScanCache) {
153+
// Any compiler which supports "-validate-prior-dependency-scan-cache"
154+
// also supports "-load-dependency-scan-cache"
155+
// and "-serialize-dependency-scan-cache" and "-dependency-scan-cache-path"
156+
commandLine.appendFlag(.dependencyScanCachePath)
157+
commandLine.appendPath(serializationPath)
158+
commandLine.appendFlag(.reuseDependencyScanCache)
159+
commandLine.appendFlag(.validatePriorDependencyScanCache)
160+
commandLine.appendFlag(.serializeDependencyScanCache)
161+
}
162+
}
163+
}
164+
144165
// Pass on the input files
145166
commandLine.append(contentsOf: inputFiles.filter { $0.type == .swift }.map { .path($0.file) })
146167
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: 2 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

@@ -131,7 +128,9 @@ extension IncrementalCompilationState.FirstWaveComputer {
131128
// In the case where there are no compilation jobs to run on this build (no source-files were changed),
132129
// we can skip running `beforeCompiles` jobs if we also ensure that none of the `afterCompiles` jobs
133130
// have any dependencies on them.
131+
// ACTODO: If the beforeCompiles contains modules, invalidate all sources
134132
let skipAllJobs = batchedCompilationJobs.isEmpty ? !nonVerifyAfterCompileJobsDependOnBeforeCompileJobs() : false
133+
135134
let mandatoryJobsInOrder = skipAllJobs ? [] : jobsInPhases.beforeCompiles + batchedCompilationJobs
136135
return (initiallySkippedCompileGroups: initiallySkippedCompileGroups,
137136
mandatoryJobsInOrder: mandatoryJobsInOrder)

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.
@@ -293,11 +291,6 @@ extension IncrementalCompilationState {
293291
report("\(message): \(externalDependency.shortDescription)")
294292
}
295293

296-
// Emits a remark indicating a need for a dependency scanning invocation
297-
func reportExplicitBuildMustReScan(_ why: String) {
298-
report("Incremental build must re-run dependency scan: \(why)")
299-
}
300-
301294
func reportExplicitDependencyOutOfDate(_ moduleName: String,
302295
inputPath: String) {
303296
report("Dependency module \(moduleName) is older than input file \(inputPath)")
@@ -415,55 +408,6 @@ extension IncrementalCompilationState {
415408
}
416409
}
417410

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

Sources/SwiftDriver/IncrementalCompilation/IncrementalDependencyAndInputSetup.swift

Lines changed: 0 additions & 53 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,41 +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-
forRebuild: false,
124-
reporter: reporter).isEmpty else {
125-
reporter?.reportExplicitBuildMustReScan("Not all dependencies are up-to-date.")
126-
return nil
127-
}
128-
129-
reporter?.report("Confirmed prior inter-module dependency graph is up-to-date at: \(buildRecordInfo.interModuleDependencyGraphPath)")
130-
return priorInterModuleDependencyGraph
131-
}
132-
}
133-
13496
/// Builds the `InitialState`
13597
/// Also bundles up an bunch of configuration info
13698
extension IncrementalCompilationState {
@@ -195,23 +157,8 @@ extension IncrementalCompilationState {
195157
return nil
196158
}
197159

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

0 commit comments

Comments
 (0)