summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2013-02-17 23:13:35 (GMT)
committerEvan Martin <martine@danga.com>2013-04-08 22:02:32 (GMT)
commit149e8d8d5d2b043fa53f9f8b74fff893ea1819df (patch)
tree93c41d13b33be468c61f586f1c25fe637341e29a
parent5031940a8fa5c0c7a76a4bb7fffdb4526713ce7c (diff)
downloadNinja-149e8d8d5d2b043fa53f9f8b74fff893ea1819df.zip
Ninja-149e8d8d5d2b043fa53f9f8b74fff893ea1819df.tar.gz
Ninja-149e8d8d5d2b043fa53f9f8b74fff893ea1819df.tar.bz2
use logged deps mtime in dirty calculation
The idea here is that it's possible for a build to complete (writing its output) but then for Ninja to get interrupted before writing out the updated dependency information. In that case the mtime stored in the deps log (if any) will match the previous output, and we'll know we need to rebuild the output just to get the deps updated.
-rw-r--r--src/build.cc2
-rw-r--r--src/graph.cc20
-rw-r--r--src/graph.h8
3 files changed, 21 insertions, 9 deletions
diff --git a/src/build.cc b/src/build.cc
index df208af..ecde4df 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -516,7 +516,7 @@ void Plan::CleanNode(DependencyScan* scan, Node* node) {
if (!(*ni)->dirty())
continue;
- if (scan->RecomputeOutputDirty(*ei, most_recent_input,
+ if (scan->RecomputeOutputDirty(*ei, most_recent_input, 0,
command, *ni)) {
(*ni)->MarkDirty();
all_outputs_clean = false;
diff --git a/src/graph.cc b/src/graph.cc
index b11973f..5cc491b 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -61,7 +61,8 @@ bool DependencyScan::RecomputeDirty(Edge* edge, string* err) {
bool dirty = false;
edge->outputs_ready_ = true;
- if (!dep_loader_.LoadDeps(edge, err)) {
+ TimeStamp deps_mtime = 0;
+ if (!dep_loader_.LoadDeps(edge, &deps_mtime, err)) {
if (!err->empty())
return false;
// Failed to load dependency info: rebuild to regenerate it.
@@ -112,7 +113,8 @@ bool DependencyScan::RecomputeDirty(Edge* edge, string* err) {
for (vector<Node*>::iterator i = edge->outputs_.begin();
i != edge->outputs_.end(); ++i) {
(*i)->StatIfNecessary(disk_interface_);
- if (RecomputeOutputDirty(edge, most_recent_input, command, *i)) {
+ if (RecomputeOutputDirty(edge, most_recent_input, deps_mtime,
+ command, *i)) {
dirty = true;
break;
}
@@ -141,6 +143,7 @@ bool DependencyScan::RecomputeDirty(Edge* edge, string* err) {
bool DependencyScan::RecomputeOutputDirty(Edge* edge,
Node* most_recent_input,
+ TimeStamp deps_mtime,
const string& command,
Node* output) {
if (edge->is_phony()) {
@@ -182,6 +185,12 @@ bool DependencyScan::RecomputeOutputDirty(Edge* edge,
}
}
+ // Dirty if the output is newer than the deps.
+ if (deps_mtime && output->mtime() > deps_mtime) {
+ EXPLAIN("stored deps info out of date for for %s", output->path().c_str());
+ return true;
+ }
+
// 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.
@@ -322,10 +331,10 @@ void Node::Dump(const char* prefix) const {
}
}
-bool ImplicitDepLoader::LoadDeps(Edge* edge, string* err) {
+bool ImplicitDepLoader::LoadDeps(Edge* edge, TimeStamp* mtime, string* err) {
string deps_type = edge->GetBinding("deps");
if (!deps_type.empty()) {
- if (!LoadDepsFromLog(edge, err)) {
+ if (!LoadDepsFromLog(edge, mtime, err)) {
if (!err->empty())
return false;
EXPLAIN("deps for %s are missing", edge->outputs_[0]->path().c_str());
@@ -396,7 +405,8 @@ bool ImplicitDepLoader::LoadDepFile(Edge* edge, const string& path,
return true;
}
-bool ImplicitDepLoader::LoadDepsFromLog(Edge* edge, string* err) {
+bool ImplicitDepLoader::LoadDepsFromLog(Edge* edge, TimeStamp* deps_mtime,
+ string* err) {
DepsLog::Deps* deps = deps_log_->GetDeps(edge->outputs_[0]);
if (!deps)
return false;
diff --git a/src/graph.h b/src/graph.h
index 650a83e..428ba01 100644
--- a/src/graph.h
+++ b/src/graph.h
@@ -192,9 +192,10 @@ struct ImplicitDepLoader {
DiskInterface* disk_interface)
: state_(state), disk_interface_(disk_interface), deps_log_(deps_log) {}
- /// Load implicit dependencies for \a edge.
+ /// Load implicit dependencies for \a edge. May fill in \a mtime with
+ /// the timestamp of the loaded information.
/// @return false on error (without filling \a err if info is just missing).
- bool LoadDeps(Edge* edge, string* err);
+ bool LoadDeps(Edge* edge, TimeStamp* mtime, string* err);
DepsLog* deps_log() const {
return deps_log_;
@@ -207,7 +208,7 @@ struct ImplicitDepLoader {
/// Load implicit dependencies for \a edge from the DepsLog.
/// @return false on error (without filling \a err if info is just missing).
- bool LoadDepsFromLog(Edge* edge, string* err);
+ bool LoadDepsFromLog(Edge* edge, TimeStamp* mtime, string* err);
/// Preallocate \a count spaces in the input array on \a edge, returning
/// an iterator pointing at the first new space.
@@ -242,6 +243,7 @@ struct DependencyScan {
/// Recompute whether a given single output should be marked dirty.
/// Returns true if so.
bool RecomputeOutputDirty(Edge* edge, Node* most_recent_input,
+ TimeStamp deps_mtime,
const string& command, Node* output);
BuildLog* build_log() const {