Skip to content

Commit eeb8739

Browse files
committed
Update incremental build hash to encode option arguments and ordering
Otherwise, changing the argument to an option which affects incremental builds, or the relative ordering of multiple options affecting incremental builds won't correctly rebuild all of the sources. rdar://96556787
1 parent aa10427 commit eeb8739

File tree

2 files changed

+75
-2
lines changed

2 files changed

+75
-2
lines changed

Sources/SwiftDriver/IncrementalCompilation/BuildRecordInfo.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,7 @@ import SwiftOptions
109109
var parsedOptions = parsedOptionsArg
110110
let hashInput = parsedOptions
111111
.filter { $0.option.affectsIncrementalBuild && $0.option.kind != .input}
112-
.map { $0.option.spelling }
113-
.sorted()
112+
.map { $0.description } // The description includes the spelling of the option itself and, if present, its argument(s).
114113
.joined()
115114
return SHA256().hash(hashInput).hexadecimalRepresentation
116115
}

Tests/SwiftDriverTests/IncrementalCompilationTests.swift

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,74 @@ extension IncrementalCompilationTests {
537537
}
538538
}
539539

540+
// MARK: - Incremental argument hashing tests
541+
extension IncrementalCompilationTests {
542+
func testNullBuildWhenAddingAndRemovingArgumentsNotAffectingIncrementalBuilds() throws {
543+
// Adding, removing, or changing the arguments of options which don't affect incremental builds should result in a null build.
544+
try buildInitialState(extraArguments: ["-driver-batch-size-limit", "5", "-debug-diagnostic-names"])
545+
let driver = try checkNullBuild(extraArguments: ["-driver-batch-size-limit", "10", "-diagnostic-style", "swift"])
546+
let mandatoryJobs = try XCTUnwrap(driver.incrementalCompilationState?.mandatoryJobsInOrder)
547+
XCTAssertTrue(mandatoryJobs.isEmpty)
548+
}
549+
550+
func testChangingOptionArgumentLeadsToRecompile() throws {
551+
// If an option affects incremental builds, changing only the argument should trigger a full recompile.
552+
try buildInitialState(extraArguments: ["-user-module-version", "1.0"])
553+
try doABuild(
554+
"change user module version",
555+
checkDiagnostics: true,
556+
extraArguments: ["-user-module-version", "1.1"],
557+
whenAutolinking: autolinkLifecycleExpectedDiags
558+
) {
559+
enablingCrossModule
560+
differentArgsPassed
561+
disablingIncrementalDifferentArgsPassed
562+
createdGraphFromSwiftdeps
563+
findingBatchingCompiling("main", "other")
564+
reading(deps: "main", "other")
565+
schedLinking
566+
}
567+
}
568+
569+
func testOptionReorderingLeadsToRecompile() throws {
570+
// Reordering options which affect incremental builds should trigger a full recompile.
571+
try buildInitialState(extraArguments: ["-warnings-as-errors", "-no-warnings-as-errors"])
572+
try doABuild(
573+
"change user module version",
574+
checkDiagnostics: true,
575+
extraArguments: ["-no-warnings-as-errors", "-warnings-as-errors"],
576+
whenAutolinking: autolinkLifecycleExpectedDiags
577+
) {
578+
enablingCrossModule
579+
differentArgsPassed
580+
disablingIncrementalDifferentArgsPassed
581+
createdGraphFromSwiftdeps
582+
findingBatchingCompiling("main", "other")
583+
reading(deps: "main", "other")
584+
schedLinking
585+
}
586+
}
587+
588+
func testArgumentReorderingLeadsToRecompile() throws {
589+
// Reordering the arguments of an option which affect incremental builds should trigger a full recompile.
590+
try buildInitialState(extraArguments: ["-Ifoo", "-Ibar"])
591+
try doABuild(
592+
"change user module version",
593+
checkDiagnostics: true,
594+
extraArguments: ["-Ibar", "-Ifoo"],
595+
whenAutolinking: autolinkLifecycleExpectedDiags
596+
) {
597+
enablingCrossModule
598+
differentArgsPassed
599+
disablingIncrementalDifferentArgsPassed
600+
createdGraphFromSwiftdeps
601+
findingBatchingCompiling("main", "other")
602+
reading(deps: "main", "other")
603+
schedLinking
604+
}
605+
}
606+
}
607+
540608
// MARK: - Incremental test stages
541609
extension IncrementalCompilationTests {
542610
/// Setup the initial post-build state.
@@ -1390,6 +1458,12 @@ extension DiagVerifiable {
13901458
@DiagsBuilder var disablingIncrementalCannotReadBuildRecord: [Diagnostic.Message] {
13911459
"Incremental compilation: Disabling incremental build: could not read build record"
13921460
}
1461+
@DiagsBuilder var differentArgsPassed: [Diagnostic.Message] {
1462+
"Incremental compilation: Incremental compilation has been disabled, because different arguments were passed to the compiler"
1463+
}
1464+
@DiagsBuilder var disablingIncrementalDifferentArgsPassed: [Diagnostic.Message] {
1465+
"Incremental compilation: Disabling incremental build: different arguments were passed to the compiler"
1466+
}
13931467
@DiagsBuilder var missingMainDependencyEntry: [Diagnostic.Message] {
13941468
.warning("ignoring -incremental; output file map has no master dependencies entry (\"swift-dependencies\" under \"\")")
13951469
}

0 commit comments

Comments
 (0)