Skip to content

Commit 04b9f0d

Browse files
authored
Merge pull request #3957 from jrose-apple/swift-3.0-we-can-rebuild-them
[3.0] [Driver] Make sure to rebuild dependents when a dirty file fails.
2 parents fc5b4fe + 01eb46e commit 04b9f0d

30 files changed

+532
-79
lines changed

lib/Driver/Compilation.cpp

Lines changed: 67 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,69 @@ int Compilation::performJobsImpl() {
456456
llvm::errs() << Output;
457457
}
458458

459+
// In order to handle both old dependencies that have disappeared and new
460+
// dependencies that have arisen, we need to reload the dependency file.
461+
// Do this whether or not the build succeeded.
462+
SmallVector<const Job *, 16> Dependents;
463+
if (getIncrementalBuildEnabled()) {
464+
const CommandOutput &Output = FinishedCmd->getOutput();
465+
StringRef DependenciesFile =
466+
Output.getAdditionalOutputForType(types::TY_SwiftDeps);
467+
if (!DependenciesFile.empty() &&
468+
(ReturnCode == EXIT_SUCCESS || ReturnCode == EXIT_FAILURE)) {
469+
bool wasCascading = DepGraph.isMarked(FinishedCmd);
470+
471+
switch (DepGraph.loadFromPath(FinishedCmd, DependenciesFile)) {
472+
case DependencyGraphImpl::LoadResult::HadError:
473+
if (ReturnCode == EXIT_SUCCESS) {
474+
disableIncrementalBuild();
475+
for (const Job *Cmd : DeferredCommands)
476+
scheduleCommandIfNecessaryAndPossible(Cmd);
477+
DeferredCommands.clear();
478+
Dependents.clear();
479+
} // else, let the next build handle it.
480+
break;
481+
case DependencyGraphImpl::LoadResult::UpToDate:
482+
if (!wasCascading)
483+
break;
484+
SWIFT_FALLTHROUGH;
485+
case DependencyGraphImpl::LoadResult::AffectsDownstream:
486+
DepGraph.markTransitive(Dependents, FinishedCmd);
487+
break;
488+
}
489+
} else {
490+
// If there's a crash, assume the worst.
491+
switch (FinishedCmd->getCondition()) {
492+
case Job::Condition::NewlyAdded:
493+
// The job won't be treated as newly added next time. Conservatively
494+
// mark it as affecting other jobs, because some of them may have
495+
// completed already.
496+
DepGraph.markTransitive(Dependents, FinishedCmd);
497+
break;
498+
case Job::Condition::Always:
499+
// This applies to non-incremental tasks as well, but any incremental
500+
// task that shows up here has already been marked.
501+
break;
502+
case Job::Condition::RunWithoutCascading:
503+
// If this file changed, it might have been a non-cascading change and
504+
// it might not. Unfortunately, the interface hash has been updated or
505+
// compromised, so we don't actually know anymore; we have to
506+
// conservatively assume the changes could affect other files.
507+
DepGraph.markTransitive(Dependents, FinishedCmd);
508+
break;
509+
case Job::Condition::CheckDependencies:
510+
// If the only reason we're running this is because something else
511+
// changed, then we can trust the dependency graph as to whether it's
512+
// a cascading or non-cascading change. That is, if whatever /caused/
513+
// the error isn't supposed to affect other files, and whatever
514+
// /fixes/ the error isn't supposed to affect other files, then
515+
// there's no need to recompile any other inputs. If either of those
516+
// are false, we /do/ need to recompile other inputs.
517+
break;
518+
}
519+
}
520+
}
521+
459522
if (ReturnCode != EXIT_SUCCESS) {
460523
// The task failed, so return true without performing any further
461524
// dependency analysis.
@@ -481,39 +544,10 @@ int Compilation::performJobsImpl() {
481544
// might have been blocked.
482545
markFinished(FinishedCmd);
483546

484-
// In order to handle both old dependencies that have disappeared and new
485-
// dependencies that have arisen, we need to reload the dependency file.
486-
if (getIncrementalBuildEnabled()) {
487-
const CommandOutput &Output = FinishedCmd->getOutput();
488-
StringRef DependenciesFile =
489-
Output.getAdditionalOutputForType(types::TY_SwiftDeps);
490-
if (!DependenciesFile.empty()) {
491-
SmallVector<const Job *, 16> Dependents;
492-
bool wasCascading = DepGraph.isMarked(FinishedCmd);
493-
494-
switch (DepGraph.loadFromPath(FinishedCmd, DependenciesFile)) {
495-
case DependencyGraphImpl::LoadResult::HadError:
496-
disableIncrementalBuild();
497-
for (const Job *Cmd : DeferredCommands)
498-
scheduleCommandIfNecessaryAndPossible(Cmd);
499-
DeferredCommands.clear();
500-
Dependents.clear();
501-
break;
502-
case DependencyGraphImpl::LoadResult::UpToDate:
503-
if (!wasCascading)
504-
break;
505-
SWIFT_FALLTHROUGH;
506-
case DependencyGraphImpl::LoadResult::AffectsDownstream:
507-
DepGraph.markTransitive(Dependents, FinishedCmd);
508-
break;
509-
}
510-
511-
for (const Job *Cmd : Dependents) {
512-
DeferredCommands.erase(Cmd);
513-
noteBuilding(Cmd, "because of dependencies discovered later");
514-
scheduleCommandIfNecessaryAndPossible(Cmd);
515-
}
516-
}
547+
for (const Job *Cmd : Dependents) {
548+
DeferredCommands.erase(Cmd);
549+
noteBuilding(Cmd, "because of dependencies discovered later");
550+
scheduleCommandIfNecessaryAndPossible(Cmd);
517551
}
518552

519553
return TaskFinishedResponse::ContinueExecution;

lib/Driver/Driver.cpp

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,36 +1604,40 @@ handleCompileJobCondition(Job *J, CompileJobAction::InputInfo inputInfo,
16041604
return;
16051605
}
16061606

1607-
if (!alwaysRebuildDependents) {
1608-
// Default all non-newly added files to being rebuilt without cascading.
1609-
J->setCondition(Job::Condition::RunWithoutCascading);
1610-
}
1611-
1607+
bool hasValidModTime = false;
16121608
llvm::sys::fs::file_status inputStatus;
1613-
if (llvm::sys::fs::status(input, inputStatus))
1614-
return;
1615-
1616-
J->setInputModTime(inputStatus.getLastModificationTime());
1617-
if (J->getInputModTime() != inputInfo.previousModTime)
1618-
return;
1609+
if (!llvm::sys::fs::status(input, inputStatus)) {
1610+
J->setInputModTime(inputStatus.getLastModificationTime());
1611+
hasValidModTime = true;
1612+
}
16191613

16201614
Job::Condition condition;
1621-
switch (inputInfo.status) {
1622-
case CompileJobAction::InputInfo::UpToDate:
1623-
if (!llvm::sys::fs::exists(J->getOutput().getPrimaryOutputFilename()))
1615+
if (!hasValidModTime || J->getInputModTime() != inputInfo.previousModTime) {
1616+
if (alwaysRebuildDependents ||
1617+
inputInfo.status == CompileJobAction::InputInfo::NeedsCascadingBuild) {
1618+
condition = Job::Condition::Always;
1619+
} else {
16241620
condition = Job::Condition::RunWithoutCascading;
1625-
else
1626-
condition = Job::Condition::CheckDependencies;
1627-
break;
1628-
case CompileJobAction::InputInfo::NeedsCascadingBuild:
1629-
condition = Job::Condition::Always;
1630-
break;
1631-
case CompileJobAction::InputInfo::NeedsNonCascadingBuild:
1632-
condition = Job::Condition::RunWithoutCascading;
1633-
break;
1634-
case CompileJobAction::InputInfo::NewlyAdded:
1635-
llvm_unreachable("handled above");
1621+
}
1622+
} else {
1623+
switch (inputInfo.status) {
1624+
case CompileJobAction::InputInfo::UpToDate:
1625+
if (!llvm::sys::fs::exists(J->getOutput().getPrimaryOutputFilename()))
1626+
condition = Job::Condition::RunWithoutCascading;
1627+
else
1628+
condition = Job::Condition::CheckDependencies;
1629+
break;
1630+
case CompileJobAction::InputInfo::NeedsCascadingBuild:
1631+
condition = Job::Condition::Always;
1632+
break;
1633+
case CompileJobAction::InputInfo::NeedsNonCascadingBuild:
1634+
condition = Job::Condition::RunWithoutCascading;
1635+
break;
1636+
case CompileJobAction::InputInfo::NewlyAdded:
1637+
llvm_unreachable("handled above");
1638+
}
16361639
}
1640+
16371641
J->setCondition(condition);
16381642
}
16391643

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Dependencies after compilation:
2+
provides-top-level: [a]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Dependencies after compilation:
2+
depends-top-level: [a]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Dependencies after compilation:
2+
depends-top-level: [!private a]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"./main.swift": {
3+
"object": "./main.o",
4+
"swift-dependencies": "./main.swiftdeps"
5+
},
6+
"./crash.swift": {
7+
"object": "./crash.o",
8+
"swift-dependencies": "./crash.swiftdeps"
9+
},
10+
"./other.swift": {
11+
"object": "./other.o",
12+
"swift-dependencies": "./other.swiftdeps"
13+
},
14+
"": {
15+
"swift-dependencies": "./main~buildrecord.swiftdeps"
16+
}
17+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Dependencies after compilation:
2+
provides-top-level: [bad]
3+
interface-hash: "after"
4+
garbage: ""
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Dependencies before compilation:
2+
provides-top-level: [bad]
3+
interface-hash: "before"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Dependencies after compilation:
2+
depends-top-level: [bad]
3+
interface-hash: "after"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Dependencies before compilation:
2+
depends-top-level: [bad]
3+
interface-hash: "before"

0 commit comments

Comments
 (0)