Skip to content

Commit 889da74

Browse files
author
David Ungar
committed
add ability to test minor number change, and also increment it
1 parent d47a1f2 commit 889da74

File tree

7 files changed

+126
-17
lines changed

7 files changed

+126
-17
lines changed

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ public struct Driver {
207207
/// Info needed to write and maybe read the build record.
208208
/// Only present when the driver will be writing the record.
209209
/// Only used for reading when compiling incrementally.
210-
let buildRecordInfo: BuildRecordInfo?
210+
@_spi(Testing) public let buildRecordInfo: BuildRecordInfo?
211211

212212
/// A build-record-relative path to the location of a serialized copy of the
213213
/// driver's dependency graph.

Sources/SwiftDriver/IncrementalCompilation/BuildRecordInfo.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import SwiftOptions
3636
let buildRecordPath: VirtualPath
3737
let fileSystem: FileSystem
3838
let currentArgsHash: String
39-
let actualSwiftVersion: String
39+
@_spi(Testing) public let actualSwiftVersion: String
4040
let timeBeforeFirstJob: Date
4141
let diagnosticEngine: DiagnosticsEngine
4242
let compilationInputModificationDates: [TypedVirtualPath: Date]

Sources/SwiftDriver/IncrementalCompilation/IncrementalDependencyAndInputSetup.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,14 @@ extension IncrementalCompilationState.IncrementalDependencyAndInputSetup {
218218
do {
219219
graphIfPresent = try ModuleDependencyGraph.read( from: dependencyGraphPath, info: self)
220220
}
221+
catch ModuleDependencyGraph.ReadError.mismatchedSerializedGraphVersion {
222+
diagnosticEngine.emit(
223+
warning: "Will not do cross-module incremental builds, wrong version of priors at '\(dependencyGraphPath)'")
224+
graphIfPresent = nil
225+
}
221226
catch {
222227
diagnosticEngine.emit(
223-
warning: "Could not read \(dependencyGraphPath), will not do cross-module incremental builds")
228+
warning: "Will not do cross-module incremental builds, could not read priors at '\(dependencyGraphPath)'")
224229
graphIfPresent = nil
225230
}
226231
guard let graph = graphIfPresent

Sources/SwiftDriver/IncrementalCompilation/ModuleDependencyGraph.swift

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,9 @@ extension ModuleDependencyGraph {
447447
///
448448
/// - WARNING: You *must* increment the minor version number when making any
449449
/// changes to the underlying serialization format.
450-
fileprivate static let version = Version(1, 0, 0)
450+
///
451+
/// - Minor number 1: Don't serialize the `inputDepedencySourceMap`
452+
@_spi(Testing) public static let serializedGraphVersion = Version(1, 1, 0)
451453

452454
/// The IDs of the records used by the module dependency graph.
453455
fileprivate enum RecordID: UInt64 {
@@ -481,10 +483,11 @@ extension ModuleDependencyGraph {
481483
}
482484
}
483485

484-
fileprivate enum ReadError: Error {
486+
@_spi(Testing) public enum ReadError: Error {
485487
case badMagic
486488
case noRecordBlock
487489
case malformedMetadataRecord
490+
case mismatchedSerializedGraphVersion
488491
case unexpectedMetadataRecord
489492
case malformedFingerprintRecord
490493
case malformedIdentifierRecord
@@ -666,9 +669,9 @@ extension ModuleDependencyGraph {
666669
guard let major = visitor.majorVersion,
667670
let minor = visitor.minorVersion,
668671
visitor.compilerVersionString != nil,
669-
Version(Int(major), Int(minor), 0) == Self.version
672+
Version(Int(major), Int(minor), 0) == Self.serializedGraphVersion
670673
else {
671-
throw ReadError.malformedMetadataRecord
674+
throw ReadError.mismatchedSerializedGraphVersion
672675
}
673676
let graph = visitor.finalizeGraph()
674677
info.reporter?.report("Read dependency graph", path)
@@ -691,13 +694,17 @@ extension ModuleDependencyGraph {
691694
/// - fileSystem: The file system for this location.
692695
/// - compilerVersion: A string containing version information for the
693696
/// driver used to create this file.
697+
/// - mockSerializedGraphVersion: Overrides the standard version for testing
694698
/// - Returns: true if had error
695699
@_spi(Testing) public func write(
696700
to path: VirtualPath,
697701
on fileSystem: FileSystem,
698-
compilerVersion: String
702+
compilerVersion: String,
703+
mockSerializedGraphVersion: Version? = nil
699704
) throws {
700-
let data = ModuleDependencyGraph.Serializer.serialize(self, compilerVersion)
705+
let data = ModuleDependencyGraph.Serializer.serialize(
706+
self, compilerVersion,
707+
mockSerializedGraphVersion ?? Self.serializedGraphVersion)
701708

702709
do {
703710
try fileSystem.writeFileContents(path,
@@ -711,6 +718,7 @@ extension ModuleDependencyGraph {
711718

712719
fileprivate final class Serializer {
713720
let compilerVersion: String
721+
let serializedGraphVersion: Version
714722
let stream = BitstreamWriter()
715723
private var abbreviations = [RecordID: Bitstream.AbbreviationID]()
716724
private var identifiersToWrite = [String]()
@@ -719,8 +727,10 @@ extension ModuleDependencyGraph {
719727
fileprivate private(set) var nodeIDs = [Node: Int]()
720728
private var lastNodeID: Int = 0
721729

722-
private init(compilerVersion: String) {
730+
private init(compilerVersion: String,
731+
serializedGraphVersion: Version) {
723732
self.compilerVersion = compilerVersion
733+
self.serializedGraphVersion = serializedGraphVersion
724734
}
725735

726736
private func emitSignature() {
@@ -765,10 +775,8 @@ extension ModuleDependencyGraph {
765775
private func writeMetadata() {
766776
self.stream.writeRecord(self.abbreviations[.metadata]!, {
767777
$0.append(RecordID.metadata)
768-
// Major version
769-
$0.append(1 as UInt32)
770-
// Minor version
771-
$0.append(0 as UInt32)
778+
$0.append(serializedGraphVersion.majorForWriting)
779+
$0.append(serializedGraphVersion.minorForWriting)
772780
},
773781
blob: self.compilerVersion)
774782
}
@@ -903,9 +911,12 @@ extension ModuleDependencyGraph {
903911

904912
public static func serialize(
905913
_ graph: ModuleDependencyGraph,
906-
_ compilerVersion: String
914+
_ compilerVersion: String,
915+
_ serializedGraphVersion: Version
907916
) -> ByteString {
908-
let serializer = Serializer(compilerVersion: compilerVersion)
917+
let serializer = Serializer(
918+
compilerVersion: compilerVersion,
919+
serializedGraphVersion: serializedGraphVersion)
909920
serializer.emitSignature()
910921
serializer.writeBlockInfoBlock()
911922

@@ -1067,3 +1078,16 @@ extension Set where Element == FingerprintedExternalDependency {
10671078
self == other
10681079
}
10691080
}
1081+
1082+
fileprivate extension Version {
1083+
var majorForWriting: UInt32 {
1084+
let r = UInt32(Int64(major))
1085+
assert(Int(r) == Int(major))
1086+
return r
1087+
}
1088+
var minorForWriting: UInt32 {
1089+
let r = UInt32(Int64(minor))
1090+
assert(Int(r) == Int(minor))
1091+
return r
1092+
}
1093+
}

Tests/SwiftDriverTests/DependencyGraphSerializationTests.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,36 @@
1313
import XCTest
1414
@_spi(Testing) import SwiftDriver
1515
import TSCBasic
16+
import TSCUtility
1617

1718
class DependencyGraphSerializationTests: XCTestCase, ModuleDependencyGraphMocker {
1819
static let mockGraphCreator = MockModuleDependencyGraphCreator(maxIndex: 12)
1920

21+
/// Unit test of the `ModuleDependencyGraph` serialization
22+
///
23+
/// Ensure that a round-trip fails when the minor version number changes
24+
func testSerializedVersionChangeDetection() throws {
25+
let mockPath = VirtualPath.absolute(AbsolutePath("/module-dependency-graph"))
26+
let fs = InMemoryFileSystem()
27+
let graph = Self.mockGraphCreator.mockUpAGraph()
28+
let currentVersion = ModuleDependencyGraph.serializedGraphVersion
29+
try graph.write(
30+
to: mockPath,
31+
on: fs,
32+
compilerVersion: "Swift 99",
33+
mockSerializedGraphVersion: currentVersion.withAlteredMinor)
34+
do {
35+
_ = try ModuleDependencyGraph.read(from: mockPath,
36+
info: .mock(fileSystem: fs))
37+
XCTFail("Should have thrown an exception")
38+
}
39+
catch ModuleDependencyGraph.ReadError.mismatchedSerializedGraphVersion {
40+
}
41+
catch {
42+
XCTFail("Threw an unexpected exception: \(error.localizedDescription)")
43+
}
44+
}
45+
2046
func roundTrip(_ graph: ModuleDependencyGraph) throws {
2147
let mockPath = VirtualPath.absolute(AbsolutePath("/module-dependency-graph"))
2248
let fs = InMemoryFileSystem()

Tests/SwiftDriverTests/Helpers/MockingIncrementalCompilation.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
@_spi(Testing) import SwiftDriver
1414
import TSCBasic
15+
import TSCUtility
1516
import Foundation
1617
import XCTest
1718

@@ -50,6 +51,12 @@ extension ModuleDependencyGraph {
5051
}
5152
}
5253

54+
extension Version {
55+
var withAlteredMinor: Self {
56+
Self(major, minor + 1, patch)
57+
}
58+
}
59+
5360
// MARK: - mocking
5461

5562
extension TypedVirtualPath {

Tests/SwiftDriverTests/IncrementalCompilationTests.swift

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212
import XCTest
1313
import TSCBasic
14+
import TSCUtility
1415

1516
@_spi(Testing) import SwiftDriver
1617
import SwiftOptions
@@ -297,6 +298,35 @@ extension IncrementalCompilationTests {
297298
try checkReactionToTouchingSymlinks(checkDiagnostics: true)
298299
try checkReactionToTouchingSymlinkTargets(checkDiagnostics: true)
299300
}
301+
302+
/// Ensure that the driver can detect and then recover from a priors version mismatch
303+
func testPriorsVersionDetectionAndRecovery() throws {
304+
#if !os(Linux)
305+
// create a baseline priors
306+
try buildInitialState(checkDiagnostics: true)
307+
let driver = try checkNullBuild(checkDiagnostics: true)
308+
309+
// Read the priors, change the minor version, and write it back out
310+
let outputFileMap = try driver.moduleDependencyGraph().info.outputFileMap
311+
let info = IncrementalCompilationState.IncrementalDependencyAndInputSetup
312+
.mock(outputFileMap: outputFileMap)
313+
let priorsWithOldVersion = try ModuleDependencyGraph.read(
314+
from: .absolute(priorsPath),
315+
info: info)
316+
// let priorsModTime = try localFileSystem.getFileInfo(priorsPath).modTime
317+
let compilerVersion = try XCTUnwrap(driver.buildRecordInfo).actualSwiftVersion
318+
let incrementedVersion = ModuleDependencyGraph.serializedGraphVersion.withAlteredMinor
319+
try priorsWithOldVersion?.write(to: .absolute(priorsPath),
320+
on: localFileSystem,
321+
compilerVersion: compilerVersion,
322+
mockSerializedGraphVersion: incrementedVersion)
323+
// Reset mod time to priors modTime on newly-written priors
324+
// in order to support a future priors mod-time check
325+
326+
try checkReactionToObsoletePriors()
327+
try checkNullBuild(checkDiagnostics: true)
328+
#endif
329+
}
300330
}
301331

302332
// MARK: - Test adding an input
@@ -454,10 +484,11 @@ extension IncrementalCompilationTests {
454484
/// - Parameters:
455485
/// - checkDiagnostics: If true verify the diagnostics
456486
/// - extraArguments: Additional command-line arguments
487+
@discardableResult
457488
private func checkNullBuild(
458489
checkDiagnostics: Bool = false,
459490
extraArguments: [String] = []
460-
) throws {
491+
) throws -> Driver {
461492
try doABuild(
462493
"as is",
463494
checkDiagnostics: checkDiagnostics,
@@ -829,6 +860,19 @@ extension IncrementalCompilationTests {
829860
return graph
830861
}
831862

863+
private func checkReactionToObsoletePriors() throws {
864+
try doABuild(
865+
"check reaction to obsolete priors",
866+
checkDiagnostics: true,
867+
extraArguments: [],
868+
whenAutolinking: autolinkLifecycleExpectedDiags) {
869+
couldNotReadPriors
870+
createdGraphFromSwiftdeps
871+
enablingCrossModule
872+
skippingAll("main", "other")
873+
}
874+
}
875+
832876
private func checkReactionToTouchingSymlinks(
833877
checkDiagnostics: Bool = false,
834878
extraArguments: [String] = []
@@ -1145,6 +1189,9 @@ extension DiagVerifiable {
11451189
@DiagsBuilder var readGraph: [Diagnostic.Message] {
11461190
"Incremental compilation: Read dependency graph"
11471191
}
1192+
@DiagsBuilder var couldNotReadPriors: [Diagnostic.Message] {
1193+
.warning("Will not do cross-module incremental builds, wrong version of priors at '")
1194+
}
11481195
// MARK: - dependencies
11491196
@DiagsBuilder func fingerprintChanged(_ aspect: DependencyKey.DeclAspect, _ input: String) -> [Diagnostic.Message] {
11501197
"Incremental compilation: Fingerprint changed for \(aspect) of source file \(input).swiftdeps in \(input).swiftdeps"

0 commit comments

Comments
 (0)