Home | History | Annotate | Download | only in kati
      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 "log.h"
     29 #include "rule.h"
     30 #include "stats.h"
     31 #include "strutil.h"
     32 #include "symtab.h"
     33 #include "timeutil.h"
     34 #include "var.h"
     35 
     36 namespace {
     37 
     38 static vector<DepNode*>* g_dep_node_pool;
     39 
     40 static Symbol ReplaceSuffix(Symbol s, Symbol newsuf) {
     41   string r;
     42   AppendString(StripExt(s.str()), &r);
     43   r += '.';
     44   AppendString(newsuf.str(), &r);
     45   return Intern(r);
     46 }
     47 
     48 void ApplyOutputPattern(const Rule& r,
     49                         Symbol output,
     50                         const vector<Symbol>& inputs,
     51                         vector<Symbol>* out_inputs) {
     52   if (inputs.empty())
     53     return;
     54   if (r.is_suffix_rule) {
     55     for (Symbol input : inputs) {
     56       out_inputs->push_back(ReplaceSuffix(output, input));
     57     }
     58     return;
     59   }
     60   if (r.output_patterns.empty()) {
     61     copy(inputs.begin(), inputs.end(), back_inserter(*out_inputs));
     62     return;
     63   }
     64   CHECK(r.output_patterns.size() == 1);
     65   Pattern pat(r.output_patterns[0].str());
     66   for (Symbol input : inputs) {
     67     string buf;
     68     pat.AppendSubst(output.str(), input.str(), &buf);
     69     out_inputs->push_back(Intern(buf));
     70   }
     71 }
     72 
     73 class RuleTrie {
     74   struct Entry {
     75     Entry(const Rule* r, StringPiece s)
     76         : rule(r), suffix(s) {
     77     }
     78     const Rule* rule;
     79     StringPiece suffix;
     80   };
     81 
     82  public:
     83   RuleTrie() {}
     84   ~RuleTrie() {
     85     for (auto& p : children_)
     86       delete p.second;
     87   }
     88 
     89   void Add(StringPiece name, const Rule* rule) {
     90     if (name.empty() || name[0] == '%') {
     91       rules_.push_back(Entry(rule, name));
     92       return;
     93     }
     94     const char c = name[0];
     95     auto p = children_.emplace(c, nullptr);
     96     if (p.second) {
     97       p.first->second = new RuleTrie();
     98     }
     99     p.first->second->Add(name.substr(1), rule);
    100   }
    101 
    102   void Get(StringPiece name, vector<const Rule*>* rules) const {
    103     for (const Entry& ent : rules_) {
    104       if ((ent.suffix.empty() && name.empty()) ||
    105           HasSuffix(name, ent.suffix.substr(1))) {
    106         rules->push_back(ent.rule);
    107       }
    108     }
    109     if (name.empty())
    110       return;
    111     auto found = children_.find(name[0]);
    112     if (found != children_.end()) {
    113       found->second->Get(name.substr(1), rules);
    114     }
    115   }
    116 
    117   size_t size() const {
    118     size_t r = rules_.size();
    119     for (const auto& c : children_)
    120       r += c.second->size();
    121     return r;
    122   }
    123 
    124  private:
    125   vector<Entry> rules_;
    126   unordered_map<char, RuleTrie*> children_;
    127 };
    128 
    129 
    130 bool IsSuffixRule(Symbol output) {
    131   if (output.empty() || output.str()[0] != '.')
    132     return false;
    133   const StringPiece rest = StringPiece(output.str()).substr(1);
    134   size_t dot_index = rest.find('.');
    135   // If there is only a single dot or the third dot, this is not a
    136   // suffix rule.
    137   if (dot_index == string::npos ||
    138       rest.substr(dot_index+1).find('.') != string::npos) {
    139     return false;
    140   }
    141   return true;
    142 }
    143 
    144 struct RuleMerger {
    145   vector<const Rule*> rules;
    146   const Rule* primary_rule;
    147   bool is_double_colon;
    148 
    149   RuleMerger()
    150       : primary_rule(nullptr),
    151         is_double_colon(false) {
    152   }
    153 
    154   void AddRule(Symbol output, const Rule* r) {
    155     if (rules.empty()) {
    156       is_double_colon = r->is_double_colon;
    157     } else if (is_double_colon != r->is_double_colon) {
    158       ERROR("%s:%d: *** target file `%s' has both : and :: entries.",
    159             LOCF(r->loc), output.c_str());
    160     }
    161 
    162     if (primary_rule && !r->cmds.empty() &&
    163         !IsSuffixRule(output) && !r->is_double_colon) {
    164       WARN("%s:%d: warning: overriding commands for target `%s'",
    165            LOCF(r->cmd_loc()), output.c_str());
    166       WARN("%s:%d: warning: ignoring old commands for target `%s'",
    167            LOCF(primary_rule->cmd_loc()), output.c_str());
    168       primary_rule = r;
    169     }
    170     if (!primary_rule && !r->cmds.empty()) {
    171       primary_rule = r;
    172     }
    173 
    174     rules.push_back(r);
    175   }
    176 
    177   void FillDepNodeFromRule(Symbol output,
    178                            const Rule* r,
    179                            DepNode* n) const {
    180     if (is_double_colon)
    181       copy(r->cmds.begin(), r->cmds.end(), back_inserter(n->cmds));
    182 
    183     ApplyOutputPattern(*r, output, r->inputs, &n->actual_inputs);
    184     ApplyOutputPattern(*r, output, r->order_only_inputs,
    185                        &n->actual_order_only_inputs);
    186 
    187     if (r->output_patterns.size() >= 1) {
    188       CHECK(r->output_patterns.size() == 1);
    189       n->output_pattern = r->output_patterns[0];
    190     }
    191   }
    192 
    193   void FillDepNodeLoc(const Rule* r, DepNode* n) const {
    194     n->loc = r->loc;
    195     if (!r->cmds.empty() && r->cmd_lineno)
    196       n->loc.lineno = r->cmd_lineno;
    197   }
    198 
    199   void FillDepNode(Symbol output,
    200                    const Rule* pattern_rule,
    201                    DepNode* n) const {
    202     if (primary_rule) {
    203       CHECK(!pattern_rule);
    204       FillDepNodeFromRule(output, primary_rule, n);
    205       FillDepNodeLoc(primary_rule, n);
    206       n->cmds = primary_rule->cmds;
    207     } else if (pattern_rule) {
    208       FillDepNodeFromRule(output, pattern_rule, n);
    209       FillDepNodeLoc(pattern_rule, n);
    210       n->cmds = pattern_rule->cmds;
    211     }
    212 
    213     for (const Rule* r : rules) {
    214       if (r == primary_rule)
    215         continue;
    216       FillDepNodeFromRule(output, r, n);
    217     }
    218   }
    219 };
    220 
    221 }  // namespace
    222 
    223 DepNode::DepNode(Symbol o, bool p, bool r)
    224     : output(o),
    225       has_rule(false),
    226       is_default_target(false),
    227       is_phony(p),
    228       is_restat(r),
    229       rule_vars(NULL),
    230       depfile_var(NULL),
    231       output_pattern(Symbol::IsUninitialized()) {
    232   g_dep_node_pool->push_back(this);
    233 }
    234 
    235 class DepBuilder {
    236  public:
    237   DepBuilder(Evaluator* ev,
    238              const vector<const Rule*>& rules,
    239              const unordered_map<Symbol, Vars*>& rule_vars)
    240       : ev_(ev),
    241         rule_vars_(rule_vars),
    242         implicit_rules_(new RuleTrie()),
    243         first_rule_(Symbol::IsUninitialized{}),
    244         depfile_var_name_(Intern(".KATI_DEPFILE")) {
    245     ScopedTimeReporter tr("make dep (populate)");
    246     PopulateRules(rules);
    247     // TODO?
    248     //LOG_STAT("%zu variables", ev->mutable_vars()->size());
    249     LOG_STAT("%zu explicit rules", rules_.size());
    250     LOG_STAT("%zu implicit rules", implicit_rules_->size());
    251     LOG_STAT("%zu suffix rules", suffix_rules_.size());
    252 
    253     HandleSpecialTargets();
    254   }
    255 
    256   void HandleSpecialTargets() {
    257     Loc loc;
    258     vector<Symbol> targets;
    259 
    260     if (GetRuleInputs(Intern(".PHONY"), &targets, &loc)) {
    261       for (Symbol t : targets)
    262         phony_.insert(t);
    263     }
    264     if (GetRuleInputs(Intern(".KATI_RESTAT"), &targets, &loc)) {
    265       for (Symbol t : targets)
    266         restat_.insert(t);
    267     }
    268     if (GetRuleInputs(Intern(".SUFFIXES"), &targets, &loc)) {
    269       if (targets.empty()) {
    270         suffix_rules_.clear();
    271       } else {
    272         WARN("%s:%d: kati doesn't support .SUFFIXES with prerequisites",
    273              LOCF(loc));
    274       }
    275     }
    276 
    277     // Note we can safely ignore .DELETE_ON_ERROR for --ninja mode.
    278     static const char* kUnsupportedBuiltinTargets[] = {
    279       ".DEFAULT",
    280       ".PRECIOUS",
    281       ".INTERMEDIATE",
    282       ".SECONDARY",
    283       ".SECONDEXPANSION",
    284       ".IGNORE",
    285       ".LOW_RESOLUTION_TIME",
    286       ".SILENT",
    287       ".EXPORT_ALL_VARIABLES",
    288       ".NOTPARALLEL",
    289       ".ONESHELL",
    290       ".POSIX",
    291       NULL
    292     };
    293     for (const char** p = kUnsupportedBuiltinTargets; *p; p++) {
    294       if (GetRuleInputs(Intern(*p), &targets, &loc)) {
    295         WARN("%s:%d: kati doesn't support %s", LOCF(loc), *p);
    296       }
    297     }
    298   }
    299 
    300   ~DepBuilder() {
    301   }
    302 
    303   void Build(vector<Symbol> targets, vector<DepNode*>* nodes) {
    304     if (!first_rule_.IsValid()) {
    305       ERROR("*** No targets.");
    306     }
    307 
    308     if (!g_flags.gen_all_targets && targets.empty()) {
    309       targets.push_back(first_rule_);
    310     }
    311     if (g_flags.gen_all_targets) {
    312       unordered_set<Symbol> non_root_targets;
    313       for (const auto& p : rules_) {
    314         for (const Rule* r : p.second.rules) {
    315           for (Symbol t : r->inputs)
    316             non_root_targets.insert(t);
    317           for (Symbol t : r->order_only_inputs)
    318             non_root_targets.insert(t);
    319         }
    320       }
    321 
    322       for (const auto& p : rules_) {
    323         Symbol t = p.first;
    324         if (!non_root_targets.count(t)) {
    325           targets.push_back(p.first);
    326         }
    327       }
    328     }
    329 
    330     // TODO: LogStats?
    331 
    332     for (Symbol target : targets) {
    333       cur_rule_vars_.reset(new Vars);
    334       ev_->set_current_scope(cur_rule_vars_.get());
    335       DepNode* n = BuildPlan(target, Intern(""));
    336       nodes->push_back(n);
    337       ev_->set_current_scope(NULL);
    338       cur_rule_vars_.reset(NULL);
    339     }
    340   }
    341 
    342  private:
    343   bool Exists(Symbol target) {
    344     auto found = rules_.find(target);
    345     if (found != rules_.end())
    346       return true;
    347     if (phony_.count(target))
    348       return true;
    349     return ::Exists(target.str());
    350   }
    351 
    352   bool GetRuleInputs(Symbol s, vector<Symbol>* o, Loc* l) {
    353     auto found = rules_.find(s);
    354     if (found == rules_.end())
    355       return false;
    356 
    357     o->clear();
    358     CHECK(!found->second.rules.empty());
    359     *l = found->second.rules.front()->loc;
    360     for (const Rule* r : found->second.rules) {
    361       for (Symbol i : r->inputs)
    362         o->push_back(i);
    363     }
    364     return true;
    365   }
    366 
    367   void PopulateRules(const vector<const Rule*>& rules) {
    368     for (const Rule* rule : rules) {
    369       if (rule->outputs.empty()) {
    370         PopulateImplicitRule(rule);
    371       } else {
    372         PopulateExplicitRule(rule);
    373       }
    374     }
    375     for (auto& p : suffix_rules_) {
    376       reverse(p.second.begin(), p.second.end());
    377     }
    378   }
    379 
    380   bool PopulateSuffixRule(const Rule* rule, Symbol output) {
    381     if (!IsSuffixRule(output))
    382       return false;
    383 
    384     const StringPiece rest = StringPiece(output.str()).substr(1);
    385     size_t dot_index = rest.find('.');
    386 
    387     StringPiece input_suffix = rest.substr(0, dot_index);
    388     StringPiece output_suffix = rest.substr(dot_index+1);
    389     shared_ptr<Rule> r = make_shared<Rule>(*rule);
    390     r->inputs.clear();
    391     r->inputs.push_back(Intern(input_suffix));
    392     r->is_suffix_rule = true;
    393     suffix_rules_[output_suffix].push_back(r);
    394     return true;
    395   }
    396 
    397   void PopulateExplicitRule(const Rule* rule) {
    398     for (Symbol output : rule->outputs) {
    399       if (!first_rule_.IsValid() && output.get(0) != '.') {
    400         first_rule_ = output;
    401       }
    402       rules_[output].AddRule(output, rule);
    403       PopulateSuffixRule(rule, output);
    404     }
    405   }
    406 
    407   static bool IsIgnorableImplicitRule(const Rule* rule) {
    408     // As kati doesn't have RCS/SCCS related default rules, we can
    409     // safely ignore suppression for them.
    410     if (rule->inputs.size() != 1)
    411       return false;
    412     if (!rule->order_only_inputs.empty())
    413       return false;
    414     if (!rule->cmds.empty())
    415       return false;
    416     const string& i = rule->inputs[0].str();
    417     return (i == "RCS/%,v" || i == "RCS/%" || i == "%,v" ||
    418             i == "s.%" || i == "SCCS/s.%");
    419   }
    420 
    421   void PopulateImplicitRule(const Rule* rule) {
    422     for (Symbol output_pattern : rule->output_patterns) {
    423       if (output_pattern.str() != "%" || !IsIgnorableImplicitRule(rule))
    424         implicit_rules_->Add(output_pattern.str(), rule);
    425     }
    426   }
    427 
    428   const RuleMerger* LookupRuleMerger(Symbol o) {
    429     auto found = rules_.find(o);
    430     if (found != rules_.end()) {
    431       return &found->second;
    432     }
    433     return nullptr;
    434   }
    435 
    436   Vars* LookupRuleVars(Symbol o) {
    437     auto found = rule_vars_.find(o);
    438     if (found != rule_vars_.end())
    439       return found->second;
    440     return nullptr;
    441   }
    442 
    443   bool CanPickImplicitRule(const Rule* rule, Symbol output, DepNode* n,
    444                            shared_ptr<Rule>* out_rule) {
    445     Symbol matched(Symbol::IsUninitialized{});
    446     for (Symbol output_pattern : rule->output_patterns) {
    447       Pattern pat(output_pattern.str());
    448       if (pat.Match(output.str())) {
    449         bool ok = true;
    450         for (Symbol input : rule->inputs) {
    451           string buf;
    452           pat.AppendSubst(output.str(), input.str(), &buf);
    453           if (!Exists(Intern(buf))) {
    454             ok = false;
    455             break;
    456           }
    457         }
    458 
    459         if (ok) {
    460           matched = output_pattern;
    461           break;
    462         }
    463       }
    464     }
    465     if (!matched.IsValid())
    466       return false;
    467 
    468     *out_rule = make_shared<Rule>(*rule);
    469     if ((*out_rule)->output_patterns.size() > 1) {
    470       // We should mark all other output patterns as used.
    471       Pattern pat(matched.str());
    472       for (Symbol output_pattern : rule->output_patterns) {
    473         if (output_pattern == matched)
    474           continue;
    475         string buf;
    476         pat.AppendSubst(output.str(), output_pattern.str(), &buf);
    477         done_[Intern(buf)] = n;
    478       }
    479       (*out_rule)->output_patterns.clear();
    480       (*out_rule)->output_patterns.push_back(matched);
    481     }
    482 
    483     return true;
    484   }
    485 
    486   Vars* MergeImplicitRuleVars(Symbol output, Vars* vars) {
    487     auto found = rule_vars_.find(output);
    488     if (found == rule_vars_.end())
    489       return vars;
    490     if (vars == NULL)
    491       return found->second;
    492     // TODO: leak.
    493     Vars* r = new Vars(*found->second);
    494     for (auto p : *vars) {
    495       (*r)[p.first] = p.second;
    496     }
    497     return r;
    498   }
    499 
    500   bool PickRule(Symbol output,
    501                 DepNode* n,
    502                 const RuleMerger** out_rule_merger,
    503                 shared_ptr<Rule>* pattern_rule,
    504                 Vars** out_var) {
    505     const RuleMerger* rule_merger = LookupRuleMerger(output);
    506     Vars* vars = LookupRuleVars(output);
    507     *out_rule_merger = rule_merger;
    508     *out_var = vars;
    509     if (rule_merger && rule_merger->primary_rule)
    510       return true;
    511 
    512     vector<const Rule*> irules;
    513     implicit_rules_->Get(output.str(), &irules);
    514     for (auto iter = irules.rbegin(); iter != irules.rend(); ++iter) {
    515       if (!CanPickImplicitRule(*iter, output, n, pattern_rule))
    516         continue;
    517       if (rule_merger) {
    518         return true;
    519       }
    520       CHECK((*pattern_rule)->output_patterns.size() == 1);
    521       vars = MergeImplicitRuleVars((*pattern_rule)->output_patterns[0], vars);
    522       *out_var = vars;
    523       return true;
    524     }
    525 
    526     StringPiece output_suffix = GetExt(output.str());
    527     if (output_suffix.get(0) != '.')
    528       return rule_merger;
    529     output_suffix = output_suffix.substr(1);
    530 
    531     SuffixRuleMap::const_iterator found = suffix_rules_.find(output_suffix);
    532     if (found == suffix_rules_.end())
    533       return rule_merger;
    534 
    535     for (shared_ptr<Rule> irule : found->second) {
    536       CHECK(irule->inputs.size() == 1);
    537       Symbol input = ReplaceSuffix(output, irule->inputs[0]);
    538       if (!Exists(input))
    539         continue;
    540 
    541       *pattern_rule = irule;
    542       if (rule_merger)
    543         return true;
    544       if (vars) {
    545         CHECK(irule->outputs.size() == 1);
    546         vars = MergeImplicitRuleVars(irule->outputs[0], vars);
    547         *out_var = vars;
    548       }
    549       return true;
    550     }
    551 
    552     return rule_merger;
    553   }
    554 
    555   DepNode* BuildPlan(Symbol output, Symbol needed_by UNUSED) {
    556     LOG("BuildPlan: %s for %s",
    557         output.c_str(),
    558         needed_by.c_str());
    559 
    560     auto found = done_.find(output);
    561     if (found != done_.end()) {
    562       return found->second;
    563     }
    564 
    565     DepNode* n = new DepNode(output,
    566                              phony_.count(output),
    567                              restat_.count(output));
    568     done_[output] = n;
    569 
    570     const RuleMerger* rule_merger = nullptr;
    571     shared_ptr<Rule> pattern_rule;
    572     Vars* vars;
    573     if (!PickRule(output, n, &rule_merger, &pattern_rule, &vars)) {
    574       return n;
    575     }
    576     if (rule_merger)
    577       rule_merger->FillDepNode(output, pattern_rule.get(), n);
    578     else
    579       RuleMerger().FillDepNode(output, pattern_rule.get(), n);
    580 
    581     vector<unique_ptr<ScopedVar>> sv;
    582     if (vars) {
    583       for (const auto& p : *vars) {
    584         Symbol name = p.first;
    585         RuleVar* var = reinterpret_cast<RuleVar*>(p.second);
    586         CHECK(var);
    587         Var* new_var = var->v();
    588         if (var->op() == AssignOp::PLUS_EQ) {
    589           Var* old_var = ev_->LookupVar(name);
    590           if (old_var->IsDefined()) {
    591             // TODO: This would be incorrect and has a leak.
    592             shared_ptr<string> s = make_shared<string>();
    593             old_var->Eval(ev_, s.get());
    594             if (!s->empty())
    595               *s += ' ';
    596             new_var->Eval(ev_, s.get());
    597             new_var = new SimpleVar(*s, old_var->Origin());
    598           }
    599         } else if (var->op() == AssignOp::QUESTION_EQ) {
    600           Var* old_var = ev_->LookupVar(name);
    601           if (old_var->IsDefined()) {
    602             continue;
    603           }
    604         }
    605 
    606         if (name == depfile_var_name_) {
    607           n->depfile_var = new_var;
    608         } else {
    609           sv.emplace_back(new ScopedVar(cur_rule_vars_.get(), name, new_var));
    610         }
    611       }
    612     }
    613 
    614     for (Symbol input : n->actual_inputs) {
    615       DepNode* c = BuildPlan(input, output);
    616       n->deps.push_back(c);
    617     }
    618 
    619     for (Symbol input : n->actual_order_only_inputs) {
    620       DepNode* c = BuildPlan(input, output);
    621       n->order_onlys.push_back(c);
    622     }
    623 
    624     n->has_rule = true;
    625     n->is_default_target = first_rule_ == output;
    626     if (cur_rule_vars_->empty()) {
    627       n->rule_vars = NULL;
    628     } else {
    629       n->rule_vars = new Vars;
    630       for (auto p : *cur_rule_vars_) {
    631         n->rule_vars->insert(p);
    632       }
    633     }
    634 
    635     return n;
    636   }
    637 
    638   Evaluator* ev_;
    639   map<Symbol, RuleMerger> rules_;
    640   const unordered_map<Symbol, Vars*>& rule_vars_;
    641   unique_ptr<Vars> cur_rule_vars_;
    642 
    643   unique_ptr<RuleTrie> implicit_rules_;
    644   typedef unordered_map<StringPiece, vector<shared_ptr<Rule>>> SuffixRuleMap;
    645   SuffixRuleMap suffix_rules_;
    646 
    647   Symbol first_rule_;
    648   unordered_map<Symbol, DepNode*> done_;
    649   unordered_set<Symbol> phony_;
    650   unordered_set<Symbol> restat_;
    651   Symbol depfile_var_name_;
    652 };
    653 
    654 void MakeDep(Evaluator* ev,
    655              const vector<const Rule*>& rules,
    656              const unordered_map<Symbol, Vars*>& rule_vars,
    657              const vector<Symbol>& targets,
    658              vector<DepNode*>* nodes) {
    659   DepBuilder db(ev, rules, rule_vars);
    660   ScopedTimeReporter tr("make dep (build)");
    661   db.Build(targets, nodes);
    662 }
    663 
    664 void InitDepNodePool() {
    665   g_dep_node_pool = new vector<DepNode*>;
    666 }
    667 
    668 void QuitDepNodePool() {
    669   for (DepNode* n : *g_dep_node_pool)
    670     delete n;
    671   delete g_dep_node_pool;
    672 }
    673