summaryrefslogtreecommitdiffstats
path: root/src/graph.cc
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2012-10-27 20:09:40 (GMT)
committerEvan Martin <martine@danga.com>2012-12-29 20:34:25 (GMT)
commit13dd08c1a03e5a8f4299816fbd3af1b6cb6d9642 (patch)
tree9564593d47936d2e47d88e344c2f6915ba8753a3 /src/graph.cc
parent3249938cdf574058a066436aea06b0541ded6958 (diff)
downloadNinja-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.cc81
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);