// Return true if the file exists (mtime_ got a value).
bool Stat(StatHelper* stat_helper);
+ // Return true if we needed to stat.
+ bool StatIfNecessary(StatHelper* stat_helper) {
+ if (status_known())
+ return false;
+ Stat(stat_helper);
+ return true;
+ }
+
+ bool exists() const {
+ assert(status_known());
+ return mtime_ != 0;
+ }
+
+ bool status_known() const {
+ return mtime_ == -1;
+ }
+
string path_;
// Possible values of mtime_:
// -1: file hasn't been examined
Edge() : rule_(NULL), env_(NULL) {}
void MarkDirty(Node* node);
- void RecomputeDirty();
+ void RecomputeDirty(StatHelper* stat_helper);
string EvaluateCommand(); // XXX move to env, take env ptr
Rule* rule_;
};
void FileStat::Touch(int mtime) {
+ mtime_ = mtime;
if (node_)
node_->MarkDirty();
}
(*i)->MarkDirty(this);
}
-void Edge::RecomputeDirty() {
- assert(!outputs_.empty());
+void Edge::RecomputeDirty(StatHelper* stat_helper) {
+ bool missing_input = false;
- time_t min_mtime = outputs_[0]->file_->mtime_;
- for (vector<Node*>::iterator i = outputs_.begin(); i != outputs_.end(); ++i) {
- min_mtime = min(min_mtime, (*i)->file_->mtime_);
+ time_t most_recent_input = 1;
+ for (vector<Node*>::iterator i = inputs_.begin(); i != inputs_.end(); ++i) {
+ if ((*i)->file_->StatIfNecessary(stat_helper)) {
+ if (Edge* edge = (*i)->in_edge_)
+ edge->RecomputeDirty(stat_helper);
+ }
+ if (!(*i)->file_->exists())
+ missing_input = true;
+ else if ((*i)->file_->mtime_ > most_recent_input)
+ most_recent_input = (*i)->file_->mtime_;
}
- for (vector<Node*>::iterator i = inputs_.begin(); i != inputs_.end(); ++i) {
- if ((*i)->file_->mtime_ > min_mtime) {
- MarkDirty(*i);
- break;
+ assert(!outputs_.empty());
+ for (vector<Node*>::iterator i = outputs_.begin(); i != outputs_.end(); ++i) {
+ assert((*i)->file_->status_known());
+ if (missing_input || (*i)->file_->mtime_ < most_recent_input) {
+ (*i)->dirty_ = true;
}
}
}
}
}
-void StatCache::Reload() {
- StatHelper stat_helper;
- set<Edge*> leaf_edges;
- for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) {
- bool exists = i->second->Stat(&stat_helper);
- Node* node = i->second->node_;
- node->dirty_ = !exists;
- if (!node->in_edge_) {
- for (vector<Edge*>::iterator j = node->out_edges_.begin();
- j != node->out_edges_.end(); ++j) {
- leaf_edges.insert(*j);
- }
- }
- }
-
- for (set<Edge*>::iterator i = leaf_edges.begin(); i != leaf_edges.end(); ++i) {
- (*i)->RecomputeDirty();
- }
-}
-
struct State : public EvalString::Env {
StatCache stat_cache_;
map<string, Rule*> rules_;
bool Plan::AddTarget(Node* node) {
if (!node->dirty())
return false;
+
Edge* edge = node->in_edge_;
assert(edge); // Only nodes with in-edges can be dirty.