summaryrefslogtreecommitdiffstats
path: root/src/graph.cc
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2011-09-19 01:56:15 (GMT)
committerPeter Collingbourne <peter@pcc.me.uk>2011-10-24 00:16:38 (GMT)
commit0efbbbf67a94452919084765e87106e7748274cb (patch)
tree21c8c5a13b70d7f287b2f569a35f6a03a7f1c19d /src/graph.cc
parent386cbf6c7e49c88b87f54619b06670ea9f66c8a5 (diff)
downloadNinja-0efbbbf67a94452919084765e87106e7748274cb.zip
Ninja-0efbbbf67a94452919084765e87106e7748274cb.tar.gz
Ninja-0efbbbf67a94452919084765e87106e7748274cb.tar.bz2
Implement restat rules
A restat rule is a rule which is capable of pruning the build tree depending on the timestamps of its outputs before and after a build. After a restat rule is rebuilt, Ninja will re-stat each output file to obtain its current timestamp. If the timestamp is unchanged from when Ninja initially stat'ed the file before starting the build, Ninja will mark that output file as clean, and recursively for each reverse dependency of the output file, recompute its dirty status. Ninja then stores the most recent timestamp of any input file in the build log entry associated with the output file. This timestamp will be treated by future invocations of Ninja as the output file's modification time instead of the output file's actual modification time for the purpose of deciding whether it is dirty (but not whether its reverse dependencies are dirty).
Diffstat (limited to 'src/graph.cc')
-rw-r--r--src/graph.cc23
1 files changed, 18 insertions, 5 deletions
diff --git a/src/graph.cc b/src/graph.cc
index 9df6ecb..d13b10c 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -100,18 +100,31 @@ void Edge::RecomputeOutputDirty(BuildLog* build_log, time_t most_recent_input,
return;
}
+ BuildLog::LogEntry* entry = 0;
// Output is dirty if we're dirty, we're missing the output,
// or if it's older than the most recent input mtime.
- if (dirty || !output->file_->exists() ||
- output->file_->mtime_ < most_recent_input) {
+ if (dirty || !output->file_->exists()) {
output->dirty_ = true;
- } else {
+ } else if (output->file_->mtime_ < most_recent_input) {
+ // If this is a restat rule, we may have cleaned the output with a restat
+ // rule in a previous run and stored the most recent input mtime in the
+ // build log. Use that mtime instead, so that the file will only be
+ // considered dirty if an input was modified since the previous run.
+ if (rule_->restat_ && build_log &&
+ (entry = build_log->LookupByOutput(output->file_->path_))) {
+ if (entry->restat_mtime < most_recent_input)
+ output->dirty_ = true;
+ } else {
+ output->dirty_ = true;
+ }
+ }
+
+ if (!output->dirty_) {
// 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.
- BuildLog::LogEntry* entry;
if (!rule_->generator_ && build_log &&
- (entry = build_log->LookupByOutput(output->file_->path_))) {
+ (entry || (entry = build_log->LookupByOutput(output->file_->path_)))) {
if (command != entry->command)
output->dirty_ = true;
}