• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 Google Inc. All rights reserved
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // +build ignore
16 
17 #include "dep.h"
18 
19 #include <algorithm>
20 #include <iterator>
21 #include <map>
22 #include <memory>
23 #include <unordered_map>
24 #include <unordered_set>
25 
26 #include "eval.h"
27 #include "fileutil.h"
28 #include "flags.h"
29 #include "log.h"
30 #include "rule.h"
31 #include "stats.h"
32 #include "strutil.h"
33 #include "symtab.h"
34 #include "timeutil.h"
35 #include "var.h"
36 
37 namespace {
38 
39 static vector<DepNode*>* g_dep_node_pool;
40 
ReplaceSuffix(Symbol s,Symbol newsuf)41 static Symbol ReplaceSuffix(Symbol s, Symbol newsuf) {
42   string r;
43   AppendString(StripExt(s.str()), &r);
44   r += '.';
45   AppendString(newsuf.str(), &r);
46   return Intern(r);
47 }
48 
ApplyOutputPattern(const Rule & r,Symbol output,const vector<Symbol> & inputs,vector<Symbol> * out_inputs)49 void ApplyOutputPattern(const Rule& r,
50                         Symbol output,
51                         const vector<Symbol>& inputs,
52                         vector<Symbol>* out_inputs) {
53   if (inputs.empty())
54     return;
55   if (r.is_suffix_rule) {
56     for (Symbol input : inputs) {
57       out_inputs->push_back(ReplaceSuffix(output, input));
58     }
59     return;
60   }
61   if (r.output_patterns.empty()) {
62     copy(inputs.begin(), inputs.end(), back_inserter(*out_inputs));
63     return;
64   }
65   CHECK(r.output_patterns.size() == 1);
66   Pattern pat(r.output_patterns[0].str());
67   for (Symbol input : inputs) {
68     string buf;
69     pat.AppendSubst(output.str(), input.str(), &buf);
70     out_inputs->push_back(Intern(buf));
71   }
72 }
73 
74 class RuleTrie {
75   struct Entry {
Entry__anoned188aec0111::RuleTrie::Entry76     Entry(const Rule* r, StringPiece s) : rule(r), suffix(s) {}
77     const Rule* rule;
78     StringPiece suffix;
79   };
80 
81  public:
RuleTrie()82   RuleTrie() {}
~RuleTrie()83   ~RuleTrie() {
84     for (auto& p : children_)
85       delete p.second;
86   }
87 
Add(StringPiece name,const Rule * rule)88   void Add(StringPiece name, const Rule* rule) {
89     if (name.empty() || name[0] == '%') {
90       rules_.push_back(Entry(rule, name));
91       return;
92     }
93     const char c = name[0];
94     auto p = children_.emplace(c, nullptr);
95     if (p.second) {
96       p.first->second = new RuleTrie();
97     }
98     p.first->second->Add(name.substr(1), rule);
99   }
100 
Get(StringPiece name,vector<const Rule * > * rules) const101   void Get(StringPiece name, vector<const Rule*>* rules) const {
102     for (const Entry& ent : rules_) {
103       if ((ent.suffix.empty() && name.empty()) ||
104           HasSuffix(name, ent.suffix.substr(1))) {
105         rules->push_back(ent.rule);
106       }
107     }
108     if (name.empty())
109       return;
110     auto found = children_.find(name[0]);
111     if (found != children_.end()) {
112       found->second->Get(name.substr(1), rules);
113     }
114   }
115 
size() const116   size_t size() const {
117     size_t r = rules_.size();
118     for (const auto& c : children_)
119       r += c.second->size();
120     return r;
121   }
122 
123  private:
124   vector<Entry> rules_;
125   unordered_map<char, RuleTrie*> children_;
126 };
127 
IsSuffixRule(Symbol output)128 bool IsSuffixRule(Symbol output) {
129   if (output.empty() || output.str()[0] != '.')
130     return false;
131   const StringPiece rest = StringPiece(output.str()).substr(1);
132   size_t dot_index = rest.find('.');
133   // If there is only a single dot or the third dot, this is not a
134   // suffix rule.
135   if (dot_index == string::npos ||
136       rest.substr(dot_index + 1).find('.') != string::npos) {
137     return false;
138   }
139   return true;
140 }
141 
142 struct RuleMerger {
143   vector<const Rule*> rules;
144   vector<pair<Symbol, RuleMerger*>> implicit_outputs;
145   const Rule* primary_rule;
146   const RuleMerger* parent;
147   Symbol parent_sym;
148   bool is_double_colon;
149 
RuleMerger__anoned188aec0111::RuleMerger150   RuleMerger()
151       : primary_rule(nullptr), parent(nullptr), is_double_colon(false) {}
152 
AddImplicitOutput__anoned188aec0111::RuleMerger153   void AddImplicitOutput(Symbol output, RuleMerger* merger) {
154     implicit_outputs.push_back(make_pair(output, merger));
155   }
156 
SetImplicitOutput__anoned188aec0111::RuleMerger157   void SetImplicitOutput(Symbol output, Symbol p, const RuleMerger* merger) {
158     if (!merger->primary_rule) {
159       ERROR("*** implicit output `%s' on phony target `%s'", output.c_str(),
160             p.c_str());
161     }
162     if (parent) {
163       ERROR_LOC(merger->primary_rule->cmd_loc(),
164                 "*** implicit output `%s' of `%s' was already defined by `%s' "
165                 "at %s:%d",
166                 output.c_str(), p.c_str(), parent_sym.c_str(),
167                 LOCF(parent->primary_rule->cmd_loc()));
168     }
169     if (primary_rule) {
170       ERROR_LOC(primary_rule->cmd_loc(),
171                 "*** implicit output `%s' may not have commands",
172                 output.c_str());
173     }
174     parent = merger;
175     parent_sym = p;
176   }
177 
AddRule__anoned188aec0111::RuleMerger178   void AddRule(Symbol output, const Rule* r) {
179     if (rules.empty()) {
180       is_double_colon = r->is_double_colon;
181     } else if (is_double_colon != r->is_double_colon) {
182       ERROR_LOC(r->loc, "*** target file `%s' has both : and :: entries.",
183                 output.c_str());
184     }
185 
186     if (primary_rule && !r->cmds.empty() && !IsSuffixRule(output) &&
187         !r->is_double_colon) {
188       if (g_flags.werror_overriding_commands) {
189         ERROR_LOC(r->cmd_loc(),
190                   "*** overriding commands for target `%s', previously defined "
191                   "at %s:%d",
192                   output.c_str(), LOCF(primary_rule->cmd_loc()));
193       } else {
194         WARN_LOC(r->cmd_loc(), "warning: overriding commands for target `%s'",
195                  output.c_str());
196         WARN_LOC(primary_rule->cmd_loc(),
197                  "warning: ignoring old commands for target `%s'",
198                  output.c_str());
199       }
200       primary_rule = r;
201     }
202     if (!primary_rule && !r->cmds.empty()) {
203       primary_rule = r;
204     }
205 
206     rules.push_back(r);
207   }
208 
FillDepNodeFromRule__anoned188aec0111::RuleMerger209   void FillDepNodeFromRule(Symbol output, const Rule* r, DepNode* n) const {
210     if (is_double_colon)
211       copy(r->cmds.begin(), r->cmds.end(), back_inserter(n->cmds));
212 
213     ApplyOutputPattern(*r, output, r->inputs, &n->actual_inputs);
214     ApplyOutputPattern(*r, output, r->order_only_inputs,
215                        &n->actual_order_only_inputs);
216 
217     if (r->output_patterns.size() >= 1) {
218       CHECK(r->output_patterns.size() == 1);
219       n->output_pattern = r->output_patterns[0];
220     }
221   }
222 
FillDepNodeLoc__anoned188aec0111::RuleMerger223   void FillDepNodeLoc(const Rule* r, DepNode* n) const {
224     n->loc = r->loc;
225     if (!r->cmds.empty() && r->cmd_lineno)
226       n->loc.lineno = r->cmd_lineno;
227   }
228 
FillDepNode__anoned188aec0111::RuleMerger229   void FillDepNode(Symbol output, const Rule* pattern_rule, DepNode* n) const {
230     if (primary_rule) {
231       CHECK(!pattern_rule);
232       FillDepNodeFromRule(output, primary_rule, n);
233       FillDepNodeLoc(primary_rule, n);
234       n->cmds = primary_rule->cmds;
235     } else if (pattern_rule) {
236       FillDepNodeFromRule(output, pattern_rule, n);
237       FillDepNodeLoc(pattern_rule, n);
238       n->cmds = pattern_rule->cmds;
239     }
240 
241     for (const Rule* r : rules) {
242       if (r == primary_rule)
243         continue;
244       FillDepNodeFromRule(output, r, n);
245       if (n->loc.filename == NULL)
246         n->loc = r->loc;
247     }
248 
249     for (auto& implicit_output : implicit_outputs) {
250       n->implicit_outputs.push_back(implicit_output.first);
251       for (const Rule* r : implicit_output.second->rules) {
252         FillDepNodeFromRule(output, r, n);
253       }
254     }
255   }
256 };
257 
258 }  // namespace
259 
DepNode(Symbol o,bool p,bool r)260 DepNode::DepNode(Symbol o, bool p, bool r)
261     : output(o),
262       has_rule(false),
263       is_default_target(false),
264       is_phony(p),
265       is_restat(r),
266       rule_vars(NULL),
267       depfile_var(NULL),
268       ninja_pool_var(NULL) {
269   g_dep_node_pool->push_back(this);
270 }
271 
272 class DepBuilder {
273  public:
DepBuilder(Evaluator * ev,const vector<const Rule * > & rules,const unordered_map<Symbol,Vars * > & rule_vars)274   DepBuilder(Evaluator* ev,
275              const vector<const Rule*>& rules,
276              const unordered_map<Symbol, Vars*>& rule_vars)
277       : ev_(ev),
278         rule_vars_(rule_vars),
279         implicit_rules_(new RuleTrie()),
280         depfile_var_name_(Intern(".KATI_DEPFILE")),
281         implicit_outputs_var_name_(Intern(".KATI_IMPLICIT_OUTPUTS")),
282         ninja_pool_var_name_(Intern(".KATI_NINJA_POOL")) {
283     ScopedTimeReporter tr("make dep (populate)");
284     PopulateRules(rules);
285     // TODO?
286     // LOG_STAT("%zu variables", ev->mutable_vars()->size());
287     LOG_STAT("%zu explicit rules", rules_.size());
288     LOG_STAT("%zu implicit rules", implicit_rules_->size());
289     LOG_STAT("%zu suffix rules", suffix_rules_.size());
290 
291     HandleSpecialTargets();
292   }
293 
HandleSpecialTargets()294   void HandleSpecialTargets() {
295     Loc loc;
296     vector<Symbol> targets;
297 
298     if (GetRuleInputs(Intern(".PHONY"), &targets, &loc)) {
299       for (Symbol t : targets)
300         phony_.insert(t);
301     }
302     if (GetRuleInputs(Intern(".KATI_RESTAT"), &targets, &loc)) {
303       for (Symbol t : targets)
304         restat_.insert(t);
305     }
306     if (GetRuleInputs(Intern(".SUFFIXES"), &targets, &loc)) {
307       if (targets.empty()) {
308         suffix_rules_.clear();
309       } else {
310         WARN_LOC(loc, "kati doesn't support .SUFFIXES with prerequisites");
311       }
312     }
313 
314     // Note we can safely ignore .DELETE_ON_ERROR for --ninja mode.
315     static const char* kUnsupportedBuiltinTargets[] = {".DEFAULT",
316                                                        ".PRECIOUS",
317                                                        ".INTERMEDIATE",
318                                                        ".SECONDARY",
319                                                        ".SECONDEXPANSION",
320                                                        ".IGNORE",
321                                                        ".LOW_RESOLUTION_TIME",
322                                                        ".SILENT",
323                                                        ".EXPORT_ALL_VARIABLES",
324                                                        ".NOTPARALLEL",
325                                                        ".ONESHELL",
326                                                        NULL};
327     for (const char** p = kUnsupportedBuiltinTargets; *p; p++) {
328       if (GetRuleInputs(Intern(*p), &targets, &loc)) {
329         WARN_LOC(loc, "kati doesn't support %s", *p);
330       }
331     }
332   }
333 
~DepBuilder()334   ~DepBuilder() {}
335 
Build(vector<Symbol> targets,vector<NamedDepNode> * nodes)336   void Build(vector<Symbol> targets, vector<NamedDepNode>* nodes) {
337     if (!first_rule_.IsValid()) {
338       ERROR("*** No targets.");
339     }
340 
341     if (!g_flags.gen_all_targets && targets.empty()) {
342       targets.push_back(first_rule_);
343     }
344     if (g_flags.gen_all_targets) {
345       SymbolSet non_root_targets;
346       for (const auto& p : rules_) {
347         if (p.first.get(0) == '.')
348           continue;
349         for (const Rule* r : p.second.rules) {
350           for (Symbol t : r->inputs)
351             non_root_targets.insert(t);
352           for (Symbol t : r->order_only_inputs)
353             non_root_targets.insert(t);
354         }
355       }
356 
357       for (const auto& p : rules_) {
358         Symbol t = p.first;
359         if (!non_root_targets.exists(t) && t.get(0) != '.') {
360           targets.push_back(p.first);
361         }
362       }
363     }
364 
365     // TODO: LogStats?
366 
367     for (Symbol target : targets) {
368       cur_rule_vars_.reset(new Vars);
369       ev_->set_current_scope(cur_rule_vars_.get());
370       DepNode* n = BuildPlan(target, Intern(""));
371       nodes->push_back({target, n});
372       ev_->set_current_scope(NULL);
373       cur_rule_vars_.reset(NULL);
374     }
375   }
376 
377  private:
Exists(Symbol target)378   bool Exists(Symbol target) {
379     return (rules_.find(target) != rules_.end()) || phony_.exists(target) ||
380            ::Exists(target.str());
381   }
382 
GetRuleInputs(Symbol s,vector<Symbol> * o,Loc * l)383   bool GetRuleInputs(Symbol s, vector<Symbol>* o, Loc* l) {
384     auto found = rules_.find(s);
385     if (found == rules_.end())
386       return false;
387 
388     o->clear();
389     CHECK(!found->second.rules.empty());
390     *l = found->second.rules.front()->loc;
391     for (const Rule* r : found->second.rules) {
392       for (Symbol i : r->inputs)
393         o->push_back(i);
394     }
395     return true;
396   }
397 
PopulateRules(const vector<const Rule * > & rules)398   void PopulateRules(const vector<const Rule*>& rules) {
399     for (const Rule* rule : rules) {
400       if (rule->outputs.empty()) {
401         PopulateImplicitRule(rule);
402       } else {
403         PopulateExplicitRule(rule);
404       }
405     }
406     for (auto& p : suffix_rules_) {
407       reverse(p.second.begin(), p.second.end());
408     }
409     for (auto& p : rules_) {
410       auto vars = LookupRuleVars(p.first);
411       if (!vars) {
412         continue;
413       }
414       auto var = vars->Lookup(implicit_outputs_var_name_);
415       if (!var->IsDefined()) {
416         continue;
417       }
418 
419       string implicit_outputs;
420       var->Eval(ev_, &implicit_outputs);
421 
422       for (StringPiece output : WordScanner(implicit_outputs)) {
423         Symbol sym = Intern(TrimLeadingCurdir(output));
424         rules_[sym].SetImplicitOutput(sym, p.first, &p.second);
425         p.second.AddImplicitOutput(sym, &rules_[sym]);
426       }
427     }
428   }
429 
PopulateSuffixRule(const Rule * rule,Symbol output)430   bool PopulateSuffixRule(const Rule* rule, Symbol output) {
431     if (!IsSuffixRule(output))
432       return false;
433 
434     if (g_flags.werror_suffix_rules) {
435       ERROR_LOC(rule->loc, "*** suffix rules are obsolete: %s", output.c_str());
436     } else if (g_flags.warn_suffix_rules) {
437       WARN_LOC(rule->loc, "warning: suffix rules are deprecated: %s",
438                output.c_str());
439     }
440 
441     const StringPiece rest = StringPiece(output.str()).substr(1);
442     size_t dot_index = rest.find('.');
443 
444     StringPiece input_suffix = rest.substr(0, dot_index);
445     StringPiece output_suffix = rest.substr(dot_index + 1);
446     shared_ptr<Rule> r = make_shared<Rule>(*rule);
447     r->inputs.clear();
448     r->inputs.push_back(Intern(input_suffix));
449     r->is_suffix_rule = true;
450     suffix_rules_[output_suffix].push_back(r);
451     return true;
452   }
453 
PopulateExplicitRule(const Rule * rule)454   void PopulateExplicitRule(const Rule* rule) {
455     for (Symbol output : rule->outputs) {
456       if (!first_rule_.IsValid() && output.get(0) != '.') {
457         first_rule_ = output;
458       }
459       rules_[output].AddRule(output, rule);
460       PopulateSuffixRule(rule, output);
461     }
462   }
463 
IsIgnorableImplicitRule(const Rule * rule)464   static bool IsIgnorableImplicitRule(const Rule* rule) {
465     // As kati doesn't have RCS/SCCS related default rules, we can
466     // safely ignore suppression for them.
467     if (rule->inputs.size() != 1)
468       return false;
469     if (!rule->order_only_inputs.empty())
470       return false;
471     if (!rule->cmds.empty())
472       return false;
473     const string& i = rule->inputs[0].str();
474     return (i == "RCS/%,v" || i == "RCS/%" || i == "%,v" || i == "s.%" ||
475             i == "SCCS/s.%");
476   }
477 
PopulateImplicitRule(const Rule * rule)478   void PopulateImplicitRule(const Rule* rule) {
479     for (Symbol output_pattern : rule->output_patterns) {
480       if (output_pattern.str() != "%" || !IsIgnorableImplicitRule(rule)) {
481         if (g_flags.werror_implicit_rules) {
482           ERROR_LOC(rule->loc, "*** implicit rules are obsolete: %s",
483                     output_pattern.c_str());
484         } else if (g_flags.warn_implicit_rules) {
485           WARN_LOC(rule->loc, "warning: implicit rules are deprecated: %s",
486                    output_pattern.c_str());
487         }
488 
489         implicit_rules_->Add(output_pattern.str(), rule);
490       }
491     }
492   }
493 
LookupRuleMerger(Symbol o)494   const RuleMerger* LookupRuleMerger(Symbol o) {
495     auto found = rules_.find(o);
496     if (found != rules_.end()) {
497       return &found->second;
498     }
499     return nullptr;
500   }
501 
LookupRuleVars(Symbol o)502   Vars* LookupRuleVars(Symbol o) {
503     auto found = rule_vars_.find(o);
504     if (found != rule_vars_.end())
505       return found->second;
506     return nullptr;
507   }
508 
CanPickImplicitRule(const Rule * rule,Symbol output,DepNode * n,shared_ptr<Rule> * out_rule)509   bool CanPickImplicitRule(const Rule* rule,
510                            Symbol output,
511                            DepNode* n,
512                            shared_ptr<Rule>* out_rule) {
513     Symbol matched;
514     for (Symbol output_pattern : rule->output_patterns) {
515       Pattern pat(output_pattern.str());
516       if (pat.Match(output.str())) {
517         bool ok = true;
518         for (Symbol input : rule->inputs) {
519           string buf;
520           pat.AppendSubst(output.str(), input.str(), &buf);
521           if (!Exists(Intern(buf))) {
522             ok = false;
523             break;
524           }
525         }
526 
527         if (ok) {
528           matched = output_pattern;
529           break;
530         }
531       }
532     }
533     if (!matched.IsValid())
534       return false;
535 
536     *out_rule = make_shared<Rule>(*rule);
537     if ((*out_rule)->output_patterns.size() > 1) {
538       // We should mark all other output patterns as used.
539       Pattern pat(matched.str());
540       for (Symbol output_pattern : rule->output_patterns) {
541         if (output_pattern == matched)
542           continue;
543         string buf;
544         pat.AppendSubst(output.str(), output_pattern.str(), &buf);
545         done_[Intern(buf)] = n;
546       }
547       (*out_rule)->output_patterns.clear();
548       (*out_rule)->output_patterns.push_back(matched);
549     }
550 
551     return true;
552   }
553 
MergeImplicitRuleVars(Symbol output,Vars * vars)554   Vars* MergeImplicitRuleVars(Symbol output, Vars* vars) {
555     auto found = rule_vars_.find(output);
556     if (found == rule_vars_.end())
557       return vars;
558     if (vars == NULL)
559       return found->second;
560     // TODO: leak.
561     Vars* r = new Vars(*found->second);
562     for (auto p : *vars) {
563       (*r)[p.first] = p.second;
564     }
565     return r;
566   }
567 
PickRule(Symbol output,DepNode * n,const RuleMerger ** out_rule_merger,shared_ptr<Rule> * pattern_rule,Vars ** out_var)568   bool PickRule(Symbol output,
569                 DepNode* n,
570                 const RuleMerger** out_rule_merger,
571                 shared_ptr<Rule>* pattern_rule,
572                 Vars** out_var) {
573     const RuleMerger* rule_merger = LookupRuleMerger(output);
574     Vars* vars = LookupRuleVars(output);
575     *out_rule_merger = rule_merger;
576     *out_var = vars;
577     if (rule_merger && rule_merger->primary_rule) {
578       for (auto implicit_output : rule_merger->implicit_outputs) {
579         vars = MergeImplicitRuleVars(implicit_output.first, vars);
580       }
581       *out_var = vars;
582       return true;
583     }
584 
585     vector<const Rule*> irules;
586     implicit_rules_->Get(output.str(), &irules);
587     for (auto iter = irules.rbegin(); iter != irules.rend(); ++iter) {
588       if (!CanPickImplicitRule(*iter, output, n, pattern_rule))
589         continue;
590       if (rule_merger) {
591         return true;
592       }
593       CHECK((*pattern_rule)->output_patterns.size() == 1);
594       vars = MergeImplicitRuleVars((*pattern_rule)->output_patterns[0], vars);
595       *out_var = vars;
596       return true;
597     }
598 
599     StringPiece output_suffix = GetExt(output.str());
600     if (output_suffix.get(0) != '.')
601       return rule_merger;
602     output_suffix = output_suffix.substr(1);
603 
604     SuffixRuleMap::const_iterator found = suffix_rules_.find(output_suffix);
605     if (found == suffix_rules_.end())
606       return rule_merger;
607 
608     for (const shared_ptr<Rule>& irule : found->second) {
609       CHECK(irule->inputs.size() == 1);
610       Symbol input = ReplaceSuffix(output, irule->inputs[0]);
611       if (!Exists(input))
612         continue;
613 
614       *pattern_rule = irule;
615       if (rule_merger)
616         return true;
617       if (vars) {
618         CHECK(irule->outputs.size() == 1);
619         vars = MergeImplicitRuleVars(irule->outputs[0], vars);
620         *out_var = vars;
621       }
622       return true;
623     }
624 
625     return rule_merger;
626   }
627 
BuildPlan(Symbol output,Symbol needed_by UNUSED)628   DepNode* BuildPlan(Symbol output, Symbol needed_by UNUSED) {
629     LOG("BuildPlan: %s for %s", output.c_str(), needed_by.c_str());
630 
631     auto found = done_.find(output);
632     if (found != done_.end()) {
633       return found->second;
634     }
635 
636     DepNode* n =
637         new DepNode(output, phony_.exists(output), restat_.exists(output));
638     done_[output] = n;
639 
640     const RuleMerger* rule_merger = nullptr;
641     shared_ptr<Rule> pattern_rule;
642     Vars* vars;
643     if (!PickRule(output, n, &rule_merger, &pattern_rule, &vars)) {
644       return n;
645     }
646     if (rule_merger && rule_merger->parent) {
647       output = rule_merger->parent_sym;
648       done_[output] = n;
649       n->output = output;
650       if (!PickRule(output, n, &rule_merger, &pattern_rule, &vars)) {
651         return n;
652       }
653     }
654     if (rule_merger)
655       rule_merger->FillDepNode(output, pattern_rule.get(), n);
656     else
657       RuleMerger().FillDepNode(output, pattern_rule.get(), n);
658 
659     vector<unique_ptr<ScopedVar>> sv;
660     if (vars) {
661       for (const auto& p : *vars) {
662         Symbol name = p.first;
663         Var* var = p.second;
664         CHECK(var);
665         Var* new_var = var;
666         if (var->op() == AssignOp::PLUS_EQ) {
667           Var* old_var = ev_->LookupVar(name);
668           if (old_var->IsDefined()) {
669             // TODO: This would be incorrect and has a leak.
670             shared_ptr<string> s = make_shared<string>();
671             old_var->Eval(ev_, s.get());
672             if (!s->empty())
673               *s += ' ';
674             new_var->Eval(ev_, s.get());
675             new_var = new SimpleVar(*s, old_var->Origin());
676           }
677         } else if (var->op() == AssignOp::QUESTION_EQ) {
678           Var* old_var = ev_->LookupVar(name);
679           if (old_var->IsDefined()) {
680             continue;
681           }
682         }
683 
684         if (name == depfile_var_name_) {
685           n->depfile_var = new_var;
686         } else if (name == implicit_outputs_var_name_) {
687         } else if (name == ninja_pool_var_name_) {
688           n->ninja_pool_var = new_var;
689         } else {
690           sv.emplace_back(new ScopedVar(cur_rule_vars_.get(), name, new_var));
691         }
692       }
693     }
694 
695     if (g_flags.warn_phony_looks_real && n->is_phony &&
696         output.str().find("/") != string::npos) {
697       if (g_flags.werror_phony_looks_real) {
698         ERROR_LOC(
699             n->loc,
700             "*** PHONY target \"%s\" looks like a real file (contains a \"/\")",
701             output.c_str());
702       } else {
703         WARN_LOC(n->loc,
704                  "warning: PHONY target \"%s\" looks like a real file "
705                  "(contains a \"/\")",
706                  output.c_str());
707       }
708     }
709 
710     if (!g_flags.writable.empty() && !n->is_phony) {
711       bool found = false;
712       for (const auto& w : g_flags.writable) {
713         if (StringPiece(output.str()).starts_with(w)) {
714           found = true;
715           break;
716         }
717       }
718       if (!found) {
719         if (g_flags.werror_writable) {
720           ERROR_LOC(n->loc, "*** writing to readonly directory: \"%s\"",
721                     output.c_str());
722         } else {
723           WARN_LOC(n->loc, "warning: writing to readonly directory: \"%s\"",
724                    output.c_str());
725         }
726       }
727     }
728 
729     for (Symbol output : n->implicit_outputs) {
730       done_[output] = n;
731 
732       if (g_flags.warn_phony_looks_real && n->is_phony &&
733           output.str().find("/") != string::npos) {
734         if (g_flags.werror_phony_looks_real) {
735           ERROR_LOC(n->loc,
736                     "*** PHONY target \"%s\" looks like a real file (contains "
737                     "a \"/\")",
738                     output.c_str());
739         } else {
740           WARN_LOC(n->loc,
741                    "warning: PHONY target \"%s\" looks like a real file "
742                    "(contains a \"/\")",
743                    output.c_str());
744         }
745       }
746 
747       if (!g_flags.writable.empty() && !n->is_phony) {
748         bool found = false;
749         for (const auto& w : g_flags.writable) {
750           if (StringPiece(output.str()).starts_with(w)) {
751             found = true;
752             break;
753           }
754         }
755         if (!found) {
756           if (g_flags.werror_writable) {
757             ERROR_LOC(n->loc, "*** writing to readonly directory: \"%s\"",
758                       output.c_str());
759           } else {
760             WARN_LOC(n->loc, "warning: writing to readonly directory: \"%s\"",
761                      output.c_str());
762           }
763         }
764       }
765     }
766 
767     for (Symbol input : n->actual_inputs) {
768       DepNode* c = BuildPlan(input, output);
769       n->deps.push_back({input, c});
770 
771       bool is_phony = c->is_phony;
772       if (!is_phony && !c->has_rule && g_flags.top_level_phony) {
773         is_phony = input.str().find("/") == string::npos;
774       }
775       if (!n->is_phony && is_phony) {
776         if (g_flags.werror_real_to_phony) {
777           ERROR_LOC(n->loc,
778                     "*** real file \"%s\" depends on PHONY target \"%s\"",
779                     output.c_str(), input.c_str());
780         } else if (g_flags.warn_real_to_phony) {
781           WARN_LOC(n->loc,
782                    "warning: real file \"%s\" depends on PHONY target \"%s\"",
783                    output.c_str(), input.c_str());
784         }
785       }
786     }
787 
788     for (Symbol input : n->actual_order_only_inputs) {
789       DepNode* c = BuildPlan(input, output);
790       n->order_onlys.push_back({input, c});
791     }
792 
793     n->has_rule = true;
794     n->is_default_target = first_rule_ == output;
795     if (cur_rule_vars_->empty()) {
796       n->rule_vars = NULL;
797     } else {
798       n->rule_vars = new Vars;
799       for (auto p : *cur_rule_vars_) {
800         n->rule_vars->insert(p);
801       }
802     }
803 
804     return n;
805   }
806 
807   Evaluator* ev_;
808   map<Symbol, RuleMerger> rules_;
809   const unordered_map<Symbol, Vars*>& rule_vars_;
810   unique_ptr<Vars> cur_rule_vars_;
811 
812   unique_ptr<RuleTrie> implicit_rules_;
813   typedef unordered_map<StringPiece, vector<shared_ptr<Rule>>> SuffixRuleMap;
814   SuffixRuleMap suffix_rules_;
815 
816   Symbol first_rule_;
817   unordered_map<Symbol, DepNode*> done_;
818   SymbolSet phony_;
819   SymbolSet restat_;
820   Symbol depfile_var_name_;
821   Symbol implicit_outputs_var_name_;
822   Symbol ninja_pool_var_name_;
823 };
824 
MakeDep(Evaluator * ev,const vector<const Rule * > & rules,const unordered_map<Symbol,Vars * > & rule_vars,const vector<Symbol> & targets,vector<NamedDepNode> * nodes)825 void MakeDep(Evaluator* ev,
826              const vector<const Rule*>& rules,
827              const unordered_map<Symbol, Vars*>& rule_vars,
828              const vector<Symbol>& targets,
829              vector<NamedDepNode>* nodes) {
830   DepBuilder db(ev, rules, rule_vars);
831   ScopedTimeReporter tr("make dep (build)");
832   db.Build(targets, nodes);
833 }
834 
InitDepNodePool()835 void InitDepNodePool() {
836   g_dep_node_pool = new vector<DepNode*>;
837 }
838 
QuitDepNodePool()839 void QuitDepNodePool() {
840   for (DepNode* n : *g_dep_node_pool)
841     delete n;
842   delete g_dep_node_pool;
843 }
844