summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNico Weber <nicolasweber@gmx.de>2015-03-20 21:11:31 -0700
committerNico Weber <nicolasweber@gmx.de>2015-03-21 08:17:02 -0700
commit4d44291739222e453421a237ff77d9e5daaa3dd4 (patch)
tree7cac0876b7ced30ee7034d72874848c1a5dfdeea
parenteb7167d456b8ef2dad3846ca2ba6438b060518c9 (diff)
downloadninja-4d44291739222e453421a237ff77d9e5daaa3dd4.tar.gz
Recover slowdown for cyclic rule bindings fix.
-rw-r--r--src/graph.cc26
1 files changed, 17 insertions, 9 deletions
diff --git a/src/graph.cc b/src/graph.cc
index 41055ec..d99c8bd 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -217,7 +217,7 @@ struct EdgeEnv : public Env {
enum EscapeKind { kShellEscape, kDoNotEscape };
EdgeEnv(Edge* edge, EscapeKind escape)
- : edge_(edge), escape_in_out_(escape) {}
+ : edge_(edge), escape_in_out_(escape), recursive_(false) {}
virtual string LookupVariable(const string& var);
/// Given a span of Nodes, construct a list of paths suitable for a command
@@ -226,9 +226,11 @@ struct EdgeEnv : public Env {
vector<Node*>::iterator end,
char sep);
+ private:
vector<string> lookups_;
Edge* edge_;
EscapeKind escape_in_out_;
+ bool recursive_;
};
string EdgeEnv::LookupVariable(const string& var) {
@@ -244,19 +246,25 @@ string EdgeEnv::LookupVariable(const string& var) {
' ');
}
- vector<string>::const_iterator it;
- if ((it = find(lookups_.begin(), lookups_.end(), var)) != lookups_.end()) {
- string cycle;
- for (; it != lookups_.end(); ++it)
- cycle.append(*it + " -> ");
- cycle.append(var);
- Fatal(("cycle in rule variables: " + cycle).c_str());
+ if (recursive_) {
+ vector<string>::const_iterator it;
+ if ((it = find(lookups_.begin(), lookups_.end(), var)) != lookups_.end()) {
+ string cycle;
+ for (; it != lookups_.end(); ++it)
+ cycle.append(*it + " -> ");
+ cycle.append(var);
+ Fatal(("cycle in rule variables: " + cycle).c_str());
+ }
}
// See notes on BindingEnv::LookupWithFallback.
const EvalString* eval = edge_->rule_->GetBinding(var);
- if (eval)
+ if (recursive_ && eval)
lookups_.push_back(var);
+
+ // In practice, variables defined on rules never use another rule variable.
+ // For performance, only start checking for cycles after the first lookup.
+ recursive_ = true;
return edge_->env_->LookupWithFallback(var, eval, this);
}