diff options
author | Evan Martin <martine@danga.com> | 2012-10-27 20:09:40 (GMT) |
---|---|---|
committer | Evan Martin <martine@danga.com> | 2012-12-29 20:34:25 (GMT) |
commit | 13dd08c1a03e5a8f4299816fbd3af1b6cb6d9642 (patch) | |
tree | 9564593d47936d2e47d88e344c2f6915ba8753a3 /src/graph.cc | |
parent | 3249938cdf574058a066436aea06b0541ded6958 (diff) | |
download | Ninja-13dd08c1a03e5a8f4299816fbd3af1b6cb6d9642.zip Ninja-13dd08c1a03e5a8f4299816fbd3af1b6cb6d9642.tar.gz Ninja-13dd08c1a03e5a8f4299816fbd3af1b6cb6d9642.tar.bz2 |
rearrange handling of builtin bindings to make rules simpler
Now, a 'build' block can override any special binding like 'command'
or 'description' if it needs to.
Diffstat (limited to 'src/graph.cc')
-rw-r--r-- | src/graph.cc | 81 |
1 files changed, 45 insertions, 36 deletions
diff --git a/src/graph.cc b/src/graph.cc index f9b9c6f..380ca7c 100644 --- a/src/graph.cc +++ b/src/graph.cc @@ -32,16 +32,40 @@ bool Node::Stat(DiskInterface* disk_interface) { return mtime_ > 0; } +void Rule::AddBinding(const string& key, const EvalString& val) { + bindings_[key] = val; +} + +const EvalString* Rule::GetBinding(const string& key) const { + map<string, EvalString>::const_iterator i = bindings_.find(key); + if (i == bindings_.end()) + return NULL; + return &i->second; +} + +// static +bool Rule::IsReservedBinding(const string& var) { + return var == "command" || + var == "depfile" || + var == "description" || + var == "generator" || + var == "pool" || + var == "restat" || + var == "rspfile" || + var == "rspfile_content"; +} + bool DependencyScan::RecomputeDirty(Edge* edge, string* err) { bool dirty = false; edge->outputs_ready_ = true; - if (!edge->rule_->depfile().empty()) { - if (!LoadDepFile(edge, err)) { + string depfile = edge->GetBinding("depfile"); + if (!depfile.empty()) { + if (!LoadDepFile(edge, depfile, err)) { if (!err->empty()) return false; EXPLAIN("Edge targets are dirty because depfile '%s' is missing", - edge->EvaluateDepFile().c_str()); + depfile.c_str()); dirty = true; } } @@ -142,7 +166,7 @@ bool DependencyScan::RecomputeOutputDirty(Edge* edge, // build log. Use that mtime instead, so that the file will only be // considered dirty if an input was modified since the previous run. TimeStamp most_recent_stamp = most_recent_input->mtime(); - if (edge->rule_->restat() && build_log() && + if (edge->GetBindingBool("restat") && build_log() && (entry = build_log()->LookupByOutput(output->path()))) { if (entry->restat_mtime < most_recent_stamp) { EXPLAIN("restat of output %s older than most recent input %s " @@ -162,7 +186,7 @@ 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->rule_->generator() && build_log()) { + if (!edge->GetBindingBool("generator") && build_log()) { if (entry || (entry = build_log()->LookupByOutput(output->path()))) { if (BuildLog::LogEntry::HashCommand(command) != entry->command_hash) { EXPLAIN("command line changed for %s", output->path().c_str()); @@ -212,11 +236,11 @@ string EdgeEnv::LookupVariable(const string& var) { return MakePathList(edge_->outputs_.begin(), edge_->outputs_.end(), ' '); - } else if (edge_->env_) { - return edge_->env_->LookupVariable(var); - } else { - return string(); } + + // See notes on BindingEnv::LookupWithFallback. + const EvalString* eval = edge_->rule_->GetBinding(var); + return edge_->env_->LookupWithFallback(var, eval, this); } string EdgeEnv::MakePathList(vector<Node*>::iterator begin, @@ -239,40 +263,26 @@ string EdgeEnv::MakePathList(vector<Node*>::iterator begin, } string Edge::EvaluateCommand(bool incl_rsp_file) { - EdgeEnv env(this); - string command = rule_->command().Evaluate(&env); - if (incl_rsp_file && HasRspFile()) - command += ";rspfile=" + GetRspFileContent(); + string command = GetBinding("command"); + if (incl_rsp_file) { + string rspfile_content = GetBinding("rspfile_content"); + if (!rspfile_content.empty()) + command += ";rspfile=" + rspfile_content; + } return command; } -string Edge::EvaluateDepFile() { +string Edge::GetBinding(const string& key) { EdgeEnv env(this); - return rule_->depfile().Evaluate(&env); + return env.LookupVariable(key); } -string Edge::GetDescription() { - EdgeEnv env(this); - return rule_->description().Evaluate(&env); -} - -bool Edge::HasRspFile() { - return !rule_->rspfile().empty(); -} - -string Edge::GetRspFile() { - EdgeEnv env(this); - return rule_->rspfile().Evaluate(&env); -} - -string Edge::GetRspFileContent() { - EdgeEnv env(this); - return rule_->rspfile_content().Evaluate(&env); +bool Edge::GetBindingBool(const string& key) { + return !GetBinding(key).empty(); } -bool DependencyScan::LoadDepFile(Edge* edge, string* err) { +bool DependencyScan::LoadDepFile(Edge* edge, const string& path, string* err) { METRIC_RECORD("depfile load"); - string path = edge->EvaluateDepFile(); string content = disk_interface_->ReadFile(path, err); if (!err->empty()) return false; @@ -317,8 +327,7 @@ bool DependencyScan::LoadDepFile(Edge* edge, string* err) { // create one; this makes us not abort if the input is missing, // but instead will rebuild in that circumstance. if (!node->in_edge()) { - Edge* phony_edge = state_->AddEdge(&State::kPhonyRule, - &State::kDefaultPool); + Edge* phony_edge = state_->AddEdge(&State::kPhonyRule); node->set_in_edge(phony_edge); phony_edge->outputs_.push_back(node); |