summaryrefslogtreecommitdiffstats
path: root/src/build.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/build.cc')
-rw-r--r--src/build.cc75
1 files changed, 40 insertions, 35 deletions
diff --git a/src/build.cc b/src/build.cc
index fb5890a..2e29232 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -270,19 +270,11 @@ bool Plan::CleanNode(DependencyScan* scan, Node* node, string* err) {
#define MEM_FN mem_fn // mem_fun was removed in C++17.
#endif
if (find_if(begin, end, MEM_FN(&Node::dirty)) == end) {
- // Recompute most_recent_input.
- Node* most_recent_input = NULL;
- for (vector<Node*>::iterator i = begin; i != end; ++i) {
- if (!most_recent_input || (*i)->mtime() > most_recent_input->mtime())
- most_recent_input = *i;
- }
-
// Now, this edge is dirty if any of the outputs are dirty.
// If the edge isn't dirty, clean the outputs and mark the edge as not
// wanted.
bool outputs_dirty = false;
- if (!scan->RecomputeOutputsDirty(*oe, most_recent_input,
- &outputs_dirty, err)) {
+ if (!scan->RecomputeOutputsDirty(*oe, &outputs_dirty, err)) {
return false;
}
if (!outputs_dirty) {
@@ -696,6 +688,20 @@ bool Builder::StartEdge(Edge* edge, string* err) {
return false;
}
+ // Find the most recent mtime of any (existing) non-order-only input
+ Node* most_recent_input = NULL;
+ for (vector<Node*>::iterator i = edge->inputs_.begin();
+ i != edge->inputs_.end() - edge->order_only_deps_; ++i) {
+ if (!(*i)->Stat(disk_interface_, err))
+ return false;
+ if (!most_recent_input || (*i)->mtime() > most_recent_input->mtime())
+ most_recent_input = *i;
+ }
+
+ edge->most_recent_input_ = most_recent_input;
+ if (most_recent_input)
+ edge->most_recent_input_mtime_ = most_recent_input->mtime();
+
// start command computing and run it
if (!command_runner_->StartCommand(edge)) {
err->assign("command '" + edge->EvaluateCommand() + "' failed.");
@@ -744,20 +750,18 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {
return plan_.EdgeFinished(edge, Plan::kEdgeFailed, err);
}
- // Restat the edge outputs
- TimeStamp output_mtime = 0;
- bool restat = edge->GetBindingBool("restat");
+ TimeStamp most_recent_input_mtime = 0;
if (!config_.dry_run) {
+ // Restat the edge outputs
bool node_cleaned = false;
-
for (vector<Node*>::iterator o = edge->outputs_.begin();
o != edge->outputs_.end(); ++o) {
- TimeStamp new_mtime = disk_interface_->Stat((*o)->path(), err);
+ TimeStamp old_mtime = (*o)->mtime();
+ (*o)->Stat(disk_interface_, err);
+ TimeStamp new_mtime = (*o)->mtime();
if (new_mtime == -1)
return false;
- if (new_mtime > output_mtime)
- output_mtime = new_mtime;
- if ((*o)->mtime() == new_mtime && restat) {
+ if (old_mtime == new_mtime && edge->GetBindingBool("restat")) {
// The rule command did not change the output. Propagate the clean
// state through the build graph.
// Note that this also applies to nonexistent outputs (mtime == 0).
@@ -767,33 +771,34 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {
}
}
- if (node_cleaned) {
- TimeStamp restat_mtime = 0;
- // If any output was cleaned, find the most recent mtime of any
- // (existing) non-order-only input or the depfile.
- for (vector<Node*>::iterator i = edge->inputs_.begin();
- i != edge->inputs_.end() - edge->order_only_deps_; ++i) {
- TimeStamp input_mtime = disk_interface_->Stat((*i)->path(), err);
- if (input_mtime == -1)
- return false;
- if (input_mtime > restat_mtime)
- restat_mtime = input_mtime;
- }
+ // Use the time from the most recent input that was computed when the edge was
+ // started, not the mtime of the node as it is now. There could have been other edges
+ // that restat'd the input node and detected a change, but for *this* edge, we want
+ // the mtime as it was when the command began.
+ most_recent_input_mtime = edge->most_recent_input_mtime_;
+
+ // If there were any added deps, compute the most recent input mtime
+ for (vector<Node*>::iterator i = deps_nodes.begin();
+ i != deps_nodes.end(); ++i) {
+ (*i)->StatIfNecessary(disk_interface_, err);
+ if ((*i)->mtime() > most_recent_input_mtime)
+ most_recent_input_mtime = (*i)->mtime();
+ }
+ if (node_cleaned) {
+ // If any output was cleaned, take into account the mtime of the depfile
string depfile = edge->GetUnescapedDepfile();
- if (restat_mtime != 0 && deps_type.empty() && !depfile.empty()) {
+ if (most_recent_input_mtime != 0 && deps_type.empty() && !depfile.empty()) {
TimeStamp depfile_mtime = disk_interface_->Stat(depfile, err);
if (depfile_mtime == -1)
return false;
- if (depfile_mtime > restat_mtime)
- restat_mtime = depfile_mtime;
+ if (depfile_mtime > most_recent_input_mtime)
+ most_recent_input_mtime = depfile_mtime;
}
// The total number of edges in the plan may have changed as a result
// of a restat.
status_->PlanHasTotalEdges(plan_.command_edge_count());
-
- output_mtime = restat_mtime;
}
}
@@ -807,7 +812,7 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {
if (scan_.build_log()) {
if (!scan_.build_log()->RecordCommand(edge, start_time_millis,
- end_time_millis, output_mtime)) {
+ end_time_millis, most_recent_input_mtime)) {
*err = string("Error writing to build log: ") + strerror(errno);
return false;
}