Skip to content

Commit 2b01735

Browse files
authored
Merge pull request #468 from davidungar/merge-kinds-rb
[Incremental] Next step towards cross-module incremental dependencies
2 parents 534f841 + ad28b65 commit 2b01735

13 files changed

+402
-320
lines changed

Sources/SwiftDriver/IncrementalCompilation/DependencyKey.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ import Foundation
2424
}
2525
}
2626

27+
/// Since the integration surfaces all externalDependencies to be processed later,
28+
/// a combination of the dependency and fingerprint are needed.
29+
public struct FingerprintedExternalDependency: Hashable, Equatable {
30+
let externalDependency: ExternalDependency
31+
let fingerprint: String?
32+
init(_ externalDependency: ExternalDependency, _ fingerprint: String?) {
33+
self.externalDependency = externalDependency
34+
self.fingerprint = fingerprint
35+
}
36+
var isIncremental: Bool { fingerprint != nil }
37+
}
2738

2839
/// A `DependencyKey` carries all of the information necessary to uniquely
2940
/// identify a dependency node in the graph, and serves as a point of identity
@@ -113,6 +124,13 @@ public struct DependencyKey: Hashable, CustomStringConvertible {
113124
///
114125
/// The `name` of the file is a path to the `swiftdeps` file named in
115126
/// the output file map for a given Swift file.
127+
///
128+
/// If the filename is a swiftmodule, and if it was built by a compilation with
129+
/// `-enable-experimental-cross-module-incremental-build`, the swiftmodule file
130+
/// contains a special section with swiftdeps information for the module
131+
/// in it. In that case the enclosing node should have a fingerprint.
132+
///
133+
116134
case sourceFileProvide(name: String)
117135
/// A "nominal" type that is used, or defined by this file.
118136
///

Sources/SwiftDriver/IncrementalCompilation/IncrementalCompilationState.swift

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -305,14 +305,6 @@ extension IncrementalCompilationState {
305305
reporter: reporter)
306306

307307
let externallyChangedInputs = computeExternallyChangedInputs(
308-
forIncrementalExternalDependencies: false,
309-
buildTime: outOfDateBuildRecord.buildTime,
310-
fileSystem: fileSystem,
311-
moduleDependencyGraph: moduleDependencyGraph,
312-
reporter: moduleDependencyGraph.reporter)
313-
314-
let incrementallyExternallyChangedInputs = computeExternallyChangedInputs(
315-
forIncrementalExternalDependencies: true,
316308
buildTime: outOfDateBuildRecord.buildTime,
317309
fileSystem: fileSystem,
318310
moduleDependencyGraph: moduleDependencyGraph,
@@ -327,9 +319,9 @@ extension IncrementalCompilationState {
327319
// Combine to obtain the inputs that definitely must be recompiled.
328320
let definitelyRequiredInputs =
329321
Set(changedInputs.map({ $0.filePath }) +
330-
externallyChangedInputs + incrementallyExternallyChangedInputs +
331-
inputsHavingMalformedDependencySources
332-
+ inputsMissingOutputs)
322+
externallyChangedInputs +
323+
inputsHavingMalformedDependencySources +
324+
inputsMissingOutputs)
333325
if let reporter = reporter {
334326
for scheduledInput in definitelyRequiredInputs.sorted(by: {$0.file.name < $1.file.name}) {
335327
reporter.report("Queuing (initial):", scheduledInput)
@@ -426,26 +418,23 @@ extension IncrementalCompilationState {
426418

427419
/// Any files dependent on modified files from other modules must be compiled, too.
428420
private static func computeExternallyChangedInputs(
429-
forIncrementalExternalDependencies: Bool,
430421
buildTime: Date,
431422
fileSystem: FileSystem,
432423
moduleDependencyGraph: ModuleDependencyGraph,
433424
reporter: IncrementalCompilationState.Reporter?
434-
) -> [TypedVirtualPath] {
435-
var externalDependencySources = Set<ModuleDependencyGraph.DependencySource>()
436-
let extDeps = forIncrementalExternalDependencies
437-
? moduleDependencyGraph.incrementalExternalDependencies
438-
: moduleDependencyGraph.externalDependencies
439-
for extDep in extDeps {
425+
) -> [TypedVirtualPath] {
426+
var externalDependencySources = Set<DependencySource>()
427+
for extDepAndPrint in moduleDependencyGraph.fingerprintedExternalDependencies {
428+
let extDep = extDepAndPrint.externalDependency
440429
let extModTime = extDep.file.flatMap {try? fileSystem.getFileInfo($0).modTime}
441430
?? Date.distantFuture
442431
if extModTime >= buildTime {
443-
for dependent in moduleDependencyGraph.untracedDependents(of: extDep, isIncremental: forIncrementalExternalDependencies) {
432+
for dependent in moduleDependencyGraph.untracedDependents(of: extDepAndPrint) {
444433
guard let dependencySource = dependent.dependencySource else {
445434
fatalError("Dependent \(dependent) does not have dependencies file!")
446435
}
447436
reporter?.report(
448-
"Queuing because of \(forIncrementalExternalDependencies ? "incremental " : "")external dependency on newer \(extDep.file?.basename ?? "extDep?")",
437+
"Queuing because of external dependency on newer \(extDep.file?.basename ?? "extDep?")",
449438
dependencySource.typedFile)
450439
externalDependencySources.insert(dependencySource)
451440
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//===------- ExternalDependencyHolder.swift -------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Foundation
14+
15+
/// Encapsulates the invariant required for anything with a DependencyKey and an fingerprint
16+
protocol KeyAndFingerprintEnforcer {
17+
var key: DependencyKey {get}
18+
var fingerprint: String? {get}
19+
}
20+
extension KeyAndFingerprintEnforcer {
21+
func verifyKeyAndFingerprint() throws {
22+
guard case .externalDepend(let externalDependency) = key.designator
23+
else {
24+
return
25+
}
26+
guard key.aspect == .interface else {
27+
throw KeyAndFingerprintEnforcerError.externalDepsMustBeInterface(externalDependency)
28+
}
29+
guard let file = externalDependency.file else {
30+
throw KeyAndFingerprintEnforcerError.noFile(externalDependency)
31+
}
32+
guard let fingerprint = self.fingerprint,
33+
file.extension == FileType.swiftModule.rawValue
34+
else {
35+
return
36+
}
37+
throw KeyAndFingerprintEnforcerError.onlySwiftModulesHaveFingerprints(externalDependency, fingerprint)
38+
}
39+
}
40+
enum KeyAndFingerprintEnforcerError: LocalizedError {
41+
case externalDepsMustBeInterface(ExternalDependency)
42+
case noFile(ExternalDependency)
43+
case onlySwiftModulesHaveFingerprints(ExternalDependency, String)
44+
45+
var errorDescription: String? {
46+
switch self {
47+
case let .externalDepsMustBeInterface(externalDependency):
48+
return "Aspect of external dependency must be interface: \(externalDependency)"
49+
case let .noFile(externalDependency):
50+
return "External dependency must point to a file: \(externalDependency)"
51+
case let .onlySwiftModulesHaveFingerprints(externalDependency, fingerprint):
52+
return "An external dependency with a fingerprint (\(fingerprint)) must point to a swiftmodule file: \(externalDependency)"
53+
}
54+
}
55+
}

0 commit comments

Comments
 (0)