diff options
author | Dan Willemsen <dwillemsen@google.com> | 2017-08-13 22:06:47 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@google.com> | 2017-08-15 13:38:37 -0700 |
commit | 72a8e01eeb69898315c6b03f62ec8ee2dbdd5bb8 (patch) | |
tree | 5d90b2721c237ea69aef33f838dbc62c5561abdd | |
parent | a62b43673f4b937b5258b492399e4e8e3625ef61 (diff) | |
download | kati-72a8e01eeb69898315c6b03f62ec8ee2dbdd5bb8.tar.gz |
Include implicit outputs in the DepNode graph
The last patch was good enough for simple use cases, but if a dependency
was added to the implicit output, Kati would create a phony rule in
addition to the implicit output.
This patch will cause the rules to be combined into a single DepNode,
combining any variables and dependencies.
Change-Id: I92c9e5b6fdb8bfe49d0cef0a5fa22def4acd6d99
-rw-r--r-- | dep.cc | 72 | ||||
-rw-r--r-- | dep.h | 2 | ||||
-rw-r--r-- | ninja.cc | 15 | ||||
-rw-r--r-- | testcase/ninja_implicit_output_var.sh | 35 | ||||
-rw-r--r-- | testcase/ninja_implicit_outputs.sh | 7 |
5 files changed, 114 insertions, 17 deletions
@@ -144,14 +144,39 @@ bool IsSuffixRule(Symbol output) { struct RuleMerger { vector<const Rule*> rules; + vector<pair<Symbol, RuleMerger*>> implicit_outputs; const Rule* primary_rule; + const RuleMerger* parent; + Symbol parent_sym; bool is_double_colon; RuleMerger() : primary_rule(nullptr), + parent(nullptr), + parent_sym(Symbol::IsUninitialized()), is_double_colon(false) { } + void AddImplicitOutput(Symbol output, RuleMerger *merger) { + implicit_outputs.push_back(make_pair(output, merger)); + } + + void SetImplicitOutput(Symbol output, Symbol p, const RuleMerger* merger) { + if (!merger->primary_rule) { + ERROR("*** implicit output `%s' on phony target `%s'", output.c_str(), p.c_str()); + } + if (parent) { + ERROR_LOC(merger->primary_rule->cmd_loc(), "*** implicit output `%s' of `%s' was already defined by `%s' at %s:%d", + output.c_str(), p.c_str(), parent_sym.c_str(), parent->primary_rule->cmd_loc()); + } + if (primary_rule) { + ERROR_LOC(primary_rule->cmd_loc(), "*** implicit output `%s' may not have commands", + output.c_str()); + } + parent = merger; + parent_sym = p; + } + void AddRule(Symbol output, const Rule* r) { if (rules.empty()) { is_double_colon = r->is_double_colon; @@ -226,6 +251,13 @@ struct RuleMerger { if (n->loc.filename == NULL) n->loc = r->loc; } + + for (auto& implicit_output : implicit_outputs) { + n->implicit_outputs.push_back(implicit_output.first); + for (const Rule* r : implicit_output.second->rules) { + FillDepNodeFromRule(output, r, n); + } + } } }; @@ -239,7 +271,6 @@ DepNode::DepNode(Symbol o, bool p, bool r) is_restat(r), rule_vars(NULL), depfile_var(NULL), - implicit_outputs_var(NULL), ninja_pool_var(NULL), output_pattern(Symbol::IsUninitialized()) { g_dep_node_pool->push_back(this); @@ -388,6 +419,25 @@ class DepBuilder { for (auto& p : suffix_rules_) { reverse(p.second.begin(), p.second.end()); } + for (auto& p : rules_) { + auto vars = LookupRuleVars(p.first); + if (!vars) { + continue; + } + auto var = vars->Lookup(implicit_outputs_var_name_); + if (!var->IsDefined()) { + continue; + } + + string implicit_outputs; + var->Eval(ev_, &implicit_outputs); + + for (StringPiece output : WordScanner(implicit_outputs)) { + Symbol sym = Intern(TrimLeadingCurdir(output)); + rules_[sym].SetImplicitOutput(sym, p.first, &p.second); + p.second.AddImplicitOutput(sym, &rules_[sym]); + } + } } bool PopulateSuffixRule(const Rule* rule, Symbol output) { @@ -519,8 +569,13 @@ class DepBuilder { Vars* vars = LookupRuleVars(output); *out_rule_merger = rule_merger; *out_var = vars; - if (rule_merger && rule_merger->primary_rule) + if (rule_merger && rule_merger->primary_rule) { + for (auto implicit_output : rule_merger->implicit_outputs) { + vars = MergeImplicitRuleVars(implicit_output.first, vars); + } + *out_var = vars; return true; + } vector<const Rule*> irules; implicit_rules_->Get(output.str(), &irules); @@ -586,6 +641,14 @@ class DepBuilder { if (!PickRule(output, n, &rule_merger, &pattern_rule, &vars)) { return n; } + if (rule_merger && rule_merger->parent) { + output = rule_merger->parent_sym; + done_[output] = n; + n->output = output; + if (!PickRule(output, n, &rule_merger, &pattern_rule, &vars)) { + return n; + } + } if (rule_merger) rule_merger->FillDepNode(output, pattern_rule.get(), n); else @@ -619,7 +682,6 @@ class DepBuilder { if (name == depfile_var_name_) { n->depfile_var = new_var; } else if (name == implicit_outputs_var_name_) { - n->implicit_outputs_var = new_var; } else if (name == ninja_pool_var_name_) { n->ninja_pool_var = new_var; } else { @@ -628,6 +690,10 @@ class DepBuilder { } } + for (Symbol output : n->implicit_outputs) { + done_[output] = n; + } + for (Symbol input : n->actual_inputs) { DepNode* c = BuildPlan(input, output); n->deps.push_back(c); @@ -41,11 +41,11 @@ struct DepNode { bool is_default_target; bool is_phony; bool is_restat; + vector<Symbol> implicit_outputs; vector<Symbol> actual_inputs; vector<Symbol> actual_order_only_inputs; Vars* rule_vars; Var* depfile_var; - Var* implicit_outputs_var; Var* ninja_pool_var; Symbol output_pattern; Loc loc; @@ -547,17 +547,10 @@ class NinjaGenerator { const DepNode* node = nn->node; string target = EscapeBuildTarget(node->output); *o << "build " << target; - if (node->implicit_outputs_var) { - string implicit_outputs; - node->implicit_outputs_var->Eval(ev_, &implicit_outputs); - - bool first = true; - for (StringPiece output : WordScanner(implicit_outputs)) { - if (first) { - *o << " |"; - first = false; - } - *o << " " << EscapeNinja(output.as_string()).c_str(); + if (!node->implicit_outputs.empty()) { + *o << " |"; + for (Symbol output : node->implicit_outputs) { + *o << " " << EscapeBuildTarget(output); } } *o << ": " << rule_name; diff --git a/testcase/ninja_implicit_output_var.sh b/testcase/ninja_implicit_output_var.sh new file mode 100644 index 0000000..63ef6b4 --- /dev/null +++ b/testcase/ninja_implicit_output_var.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Copyright 2015 Google Inc. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +mk="$@" + +cat <<EOF >Makefile +all: a + +a: + if ! [ -z "\$(VAR)" ]; then echo \$(VAR); fi +a: .KATI_IMPLICIT_OUTPUTS := b +b: VAR := OK +EOF + +${mk} -j1 +if [ -e ninja.sh ]; then + ./ninja.sh -j1 -w dupbuild=err; +else + echo OK +fi diff --git a/testcase/ninja_implicit_outputs.sh b/testcase/ninja_implicit_outputs.sh index eb9ef13..43c91a0 100644 --- a/testcase/ninja_implicit_outputs.sh +++ b/testcase/ninja_implicit_outputs.sh @@ -24,14 +24,17 @@ all: a b a b: touch A echo 1 >>A +d: a c: .KATI_IMPLICIT_OUTPUTS := d c: touch C echo 1 >>C + +c d: b EOF -$@ -j1 all c -if [ -e ninja.sh ]; then ./ninja.sh -j1 all d; fi +${mk} -j1 all d c +if [ -e ninja.sh ]; then ./ninja.sh -j1 -w dupbuild=err all d; fi echo "A:" cat A |