summaryrefslogtreecommitdiffstats
path: root/src/graph.cc
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2017-05-19 00:34:51 (GMT)
committerColin Cross <ccross@android.com>2017-05-22 18:29:06 (GMT)
commit04d886b11041bb59d01df794cce7a1e8cad2250d (patch)
treee56630542064e75e205e85bd97dfd4f6fc693bcd /src/graph.cc
parenta127dda3ee92916ef459b3da7aa9f2920ff1a5ab (diff)
downloadNinja-04d886b11041bb59d01df794cce7a1e8cad2250d.zip
Ninja-04d886b11041bb59d01df794cce7a1e8cad2250d.tar.gz
Ninja-04d886b11041bb59d01df794cce7a1e8cad2250d.tar.bz2
Always rebuild on errors
https://groups.google.com/forum/#!msg/ninja-build/YQuGNrECI-4/ti-lAs9SPv8J discusses a case where an rule updates its output file and then fails. The next run of ninja considers the ouptut file clean and doesn't rebuild it. Always stat output files after they are built, and write the mtime into .ninja_log. Consider output files dirty if the recorded mtime is older than the most recent input file.
Diffstat (limited to 'src/graph.cc')
-rw-r--r--src/graph.cc26
1 files changed, 19 insertions, 7 deletions
diff --git a/src/graph.cc b/src/graph.cc
index 76d996b..27013d5 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -168,7 +168,7 @@ bool DependencyScan::RecomputeOutputDirty(Edge* edge,
bool used_restat = false;
if (edge->GetBindingBool("restat") && build_log() &&
(entry = build_log()->LookupByOutput(output->path()))) {
- output_mtime = entry->restat_mtime;
+ output_mtime = entry->mtime;
used_restat = true;
}
@@ -182,17 +182,29 @@ bool DependencyScan::RecomputeOutputDirty(Edge* edge,
}
}
- // May also be dirty due to the command changing since the last build.
- // But if this is a generator rule, the command changing does not make us
- // dirty.
- if (!edge->GetBindingBool("generator") && build_log()) {
+ if (build_log()) {
+ bool generator = edge->GetBindingBool("generator");
if (entry || (entry = build_log()->LookupByOutput(output->path()))) {
- if (BuildLog::LogEntry::HashCommand(command) != entry->command_hash) {
+ if (!generator &&
+ BuildLog::LogEntry::HashCommand(command) != entry->command_hash) {
+ // May also be dirty due to the command changing since the last build.
+ // But if this is a generator rule, the command changing does not make us
+ // dirty.
EXPLAIN("command line changed for %s", output->path().c_str());
return true;
}
+ if (entry->mtime < most_recent_input->mtime()) {
+ // May also be dirty due to the mtime in the log being older than the
+ // mtime of the most recent input. This can occur even when the mtime
+ // on disk is newer if a previous run wrote to the output file but
+ // exited with an error or was interrupted.
+ EXPLAIN("recorded mtime of %s older than most recent input %s (%d vs %d)",
+ output->path().c_str(), most_recent_input->path().c_str(),
+ entry->mtime, most_recent_input->mtime());
+ return true;
+ }
}
- if (!entry) {
+ if (!entry && !generator) {
EXPLAIN("command line not found in log for %s", output->path().c_str());
return true;
}