You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I was studying the BindingEnv::LookupWithFallback function today, and I noticed some curious behavior:
rule cc
command = echo cc
build test1: cc
build test2: cc
not_used = blank
command = echo parent
Output:
$ ninja test1
[1/1] echo parent
parent
$ ninja test2
[1/1] echo cc
cc
Edge lookups should happen in this order:
/// This is tricky. Edges want lookup scope to go in this order:
/// 1) value set on edge itself (edge_->env_)
/// 2) value set on rule, with expansion in the edge's scope
/// 3) value set on enclosing scope of edge (edge_->env_->parent_)
/// This function takes as parameters the necessary info to do (2).
However, there's an optimization in the manifest parser that's changing the behavior:
// Bindings on edges are rare, so allocate per-edge envs only when needed.bool has_indent_token = lexer_.PeekToken(Lexer::INDENT);
BindingEnv* env = has_indent_token ? new BindingEnv(env_) : env_;
while (has_indent_token) {
...
env->AddBinding(key, val.Evaluate(env_));
...
}
Edge* edge = state_->AddEdge(rule);
edge->env_ = env;
If the edge has no bindings, then edge->env_ is actually its enclosing scope, which changes the lookup order to something like:
value set directly on the edge's enclosing scope
value set on the rule, with expansion in the edge's scope
value set on the edge's grandparent scope
The text was updated successfully, but these errors were encountered:
The documented behavior at https://ninja-build.org/manual.html is:
1. Special built-in variables ($in, $out).
2. Build-level variables from the build block.
3. Rule-level variables from the rule block (i.e. $command). (Note
from the above discussion on expansion that these are expanded
"late", and may make use of in-scope bindings like $in.)
4. File-level variables from the file that the build line was in.
5. Variables from the file that included that file using the subninja
keyword.
Due to ninja-build/ninja#1516, ninja's
actual behavior depends on whether or not the edge has any bindings.
If it does, it behaves as 1, 2, 3, 4, 5 as documented. If it doesn't,
it behaves as 1, (2 empty), 4, 3, 5.
Previously, we looked up a variable first in the edge's bindings,
then the file's bindings, and then the rule's bindings. This is 1,
2, 4, 5, 3, which roughly corresponded to ninja's behavior for edges
with no bindings.
Rather than try to match ninja's quirk, just implement the documented
order.
I'm curious about how this will be resolved so I can match the behavior in my ninja clone.
In samurai, I was previously looking up variables in the edge, then parent, then grandparent, then rule, which matches ninja's behavior when there are no edge bindings and no relevant grandparent bindings.
As of the above commit, I'm now using the documented evaluation rules, but I'm worried there might be projects out there that rely on the quirky behavior to build correctly.
I was studying the
BindingEnv::LookupWithFallback
function today, and I noticed some curious behavior:Output:
Edge lookups should happen in this order:
However, there's an optimization in the manifest parser that's changing the behavior:
If the edge has no bindings, then
edge->env_
is actually its enclosing scope, which changes the lookup order to something like:The text was updated successfully, but these errors were encountered: