aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@google.com>2017-08-13 22:06:47 -0700
committerDan Willemsen <dwillemsen@google.com>2017-08-15 13:38:37 -0700
commit72a8e01eeb69898315c6b03f62ec8ee2dbdd5bb8 (patch)
tree5d90b2721c237ea69aef33f838dbc62c5561abdd
parenta62b43673f4b937b5258b492399e4e8e3625ef61 (diff)
downloadandroid_build_kati-72a8e01eeb69898315c6b03f62ec8ee2dbdd5bb8.tar.gz
android_build_kati-72a8e01eeb69898315c6b03f62ec8ee2dbdd5bb8.tar.bz2
android_build_kati-72a8e01eeb69898315c6b03f62ec8ee2dbdd5bb8.zip
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.cc72
-rw-r--r--dep.h2
-rw-r--r--ninja.cc15
-rw-r--r--testcase/ninja_implicit_output_var.sh35
-rw-r--r--testcase/ninja_implicit_outputs.sh7
5 files changed, 114 insertions, 17 deletions
diff --git a/dep.cc b/dep.cc
index fec36b4..16aeeec 100644
--- a/dep.cc
+++ b/dep.cc
@@ -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);
diff --git a/dep.h b/dep.h
index b6f25e1..c42b380 100644
--- a/dep.h
+++ b/dep.h
@@ -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;
diff --git a/ninja.cc b/ninja.cc
index 35eb789..0d7acc9 100644
--- a/ninja.cc
+++ b/ninja.cc
@@ -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