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 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 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 { 76 Entry(const Rule* r, StringPiece s) : rule(r), suffix(s) {} 77 const Rule* rule; 78 StringPiece suffix; 79 }; 80 81 public: 82 RuleTrie() {} 83 ~RuleTrie() { 84 for (auto& p : children_) 85 delete p.second; 86 } 87 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 101 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 116 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 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 150 RuleMerger() 151 : primary_rule(nullptr), 152 parent(nullptr), 153 parent_sym(Symbol::IsUninitialized()), 154 is_double_colon(false) {} 155 156 void AddImplicitOutput(Symbol output, RuleMerger* merger) { 157 implicit_outputs.push_back(make_pair(output, merger)); 158 } 159 160 void SetImplicitOutput(Symbol output, Symbol p, const RuleMerger* merger) { 161 if (!merger->primary_rule) { 162 ERROR("*** implicit output `%s' on phony target `%s'", output.c_str(), 163 p.c_str()); 164 } 165 if (parent) { 166 ERROR_LOC(merger->primary_rule->cmd_loc(), 167 "*** implicit output `%s' of `%s' was already defined by `%s' " 168 "at %s:%d", 169 output.c_str(), p.c_str(), parent_sym.c_str(), 170 parent->primary_rule->cmd_loc()); 171 } 172 if (primary_rule) { 173 ERROR_LOC(primary_rule->cmd_loc(), 174 "*** implicit output `%s' may not have commands", 175 output.c_str()); 176 } 177 parent = merger; 178 parent_sym = p; 179 } 180 181 void AddRule(Symbol output, const Rule* r) { 182 if (rules.empty()) { 183 is_double_colon = r->is_double_colon; 184 } else if (is_double_colon != r->is_double_colon) { 185 ERROR_LOC(r->loc, "*** target file `%s' has both : and :: entries.", 186 output.c_str()); 187 } 188 189 if (primary_rule && !r->cmds.empty() && !IsSuffixRule(output) && 190 !r->is_double_colon) { 191 if (g_flags.werror_overriding_commands) { 192 ERROR_LOC(r->cmd_loc(), 193 "*** overriding commands for target `%s', previously defined " 194 "at %s:%d", 195 output.c_str(), LOCF(primary_rule->cmd_loc())); 196 } else { 197 WARN_LOC(r->cmd_loc(), "warning: overriding commands for target `%s'", 198 output.c_str()); 199 WARN_LOC(primary_rule->cmd_loc(), 200 "warning: ignoring old commands for target `%s'", 201 output.c_str()); 202 } 203 primary_rule = r; 204 } 205 if (!primary_rule && !r->cmds.empty()) { 206 primary_rule = r; 207 } 208 209 rules.push_back(r); 210 } 211 212 void FillDepNodeFromRule(Symbol output, const Rule* r, DepNode* n) const { 213 if (is_double_colon) 214 copy(r->cmds.begin(), r->cmds.end(), back_inserter(n->cmds)); 215 216 ApplyOutputPattern(*r, output, r->inputs, &n->actual_inputs); 217 ApplyOutputPattern(*r, output, r->order_only_inputs, 218 &n->actual_order_only_inputs); 219 220 if (r->output_patterns.size() >= 1) { 221 CHECK(r->output_patterns.size() == 1); 222 n->output_pattern = r->output_patterns[0]; 223 } 224 } 225 226 void FillDepNodeLoc(const Rule* r, DepNode* n) const { 227 n->loc = r->loc; 228 if (!r->cmds.empty() && r->cmd_lineno) 229 n->loc.lineno = r->cmd_lineno; 230 } 231 232 void FillDepNode(Symbol output, const Rule* pattern_rule, DepNode* n) const { 233 if (primary_rule) { 234 CHECK(!pattern_rule); 235 FillDepNodeFromRule(output, primary_rule, n); 236 FillDepNodeLoc(primary_rule, n); 237 n->cmds = primary_rule->cmds; 238 } else if (pattern_rule) { 239 FillDepNodeFromRule(output, pattern_rule, n); 240 FillDepNodeLoc(pattern_rule, n); 241 n->cmds = pattern_rule->cmds; 242 } 243 244 for (const Rule* r : rules) { 245 if (r == primary_rule) 246 continue; 247 FillDepNodeFromRule(output, r, n); 248 if (n->loc.filename == NULL) 249 n->loc = r->loc; 250 } 251 252 for (auto& implicit_output : implicit_outputs) { 253 n->implicit_outputs.push_back(implicit_output.first); 254 for (const Rule* r : implicit_output.second->rules) { 255 FillDepNodeFromRule(output, r, n); 256 } 257 } 258 } 259 }; 260 261 } // namespace 262 263 DepNode::DepNode(Symbol o, bool p, bool r) 264 : output(o), 265 has_rule(false), 266 is_default_target(false), 267 is_phony(p), 268 is_restat(r), 269 rule_vars(NULL), 270 depfile_var(NULL), 271 ninja_pool_var(NULL), 272 output_pattern(Symbol::IsUninitialized()) { 273 g_dep_node_pool->push_back(this); 274 } 275 276 class DepBuilder { 277 public: 278 DepBuilder(Evaluator* ev, 279 const vector<const Rule*>& rules, 280 const unordered_map<Symbol, Vars*>& rule_vars) 281 : ev_(ev), 282 rule_vars_(rule_vars), 283 implicit_rules_(new RuleTrie()), 284 first_rule_(Symbol::IsUninitialized{}), 285 depfile_var_name_(Intern(".KATI_DEPFILE")), 286 implicit_outputs_var_name_(Intern(".KATI_IMPLICIT_OUTPUTS")), 287 ninja_pool_var_name_(Intern(".KATI_NINJA_POOL")) { 288 ScopedTimeReporter tr("make dep (populate)"); 289 PopulateRules(rules); 290 // TODO? 291 // LOG_STAT("%zu variables", ev->mutable_vars()->size()); 292 LOG_STAT("%zu explicit rules", rules_.size()); 293 LOG_STAT("%zu implicit rules", implicit_rules_->size()); 294 LOG_STAT("%zu suffix rules", suffix_rules_.size()); 295 296 HandleSpecialTargets(); 297 } 298 299 void HandleSpecialTargets() { 300 Loc loc; 301 vector<Symbol> targets; 302 303 if (GetRuleInputs(Intern(".PHONY"), &targets, &loc)) { 304 for (Symbol t : targets) 305 phony_.insert(t); 306 } 307 if (GetRuleInputs(Intern(".KATI_RESTAT"), &targets, &loc)) { 308 for (Symbol t : targets) 309 restat_.insert(t); 310 } 311 if (GetRuleInputs(Intern(".SUFFIXES"), &targets, &loc)) { 312 if (targets.empty()) { 313 suffix_rules_.clear(); 314 } else { 315 WARN_LOC(loc, "kati doesn't support .SUFFIXES with prerequisites"); 316 } 317 } 318 319 // Note we can safely ignore .DELETE_ON_ERROR for --ninja mode. 320 static const char* kUnsupportedBuiltinTargets[] = {".DEFAULT", 321 ".PRECIOUS", 322 ".INTERMEDIATE", 323 ".SECONDARY", 324 ".SECONDEXPANSION", 325 ".IGNORE", 326 ".LOW_RESOLUTION_TIME", 327 ".SILENT", 328 ".EXPORT_ALL_VARIABLES", 329 ".NOTPARALLEL", 330 ".ONESHELL", 331 NULL}; 332 for (const char** p = kUnsupportedBuiltinTargets; *p; p++) { 333 if (GetRuleInputs(Intern(*p), &targets, &loc)) { 334 WARN_LOC(loc, "kati doesn't support %s", *p); 335 } 336 } 337 } 338 339 ~DepBuilder() {} 340 341 void Build(vector<Symbol> targets, vector<DepNode*>* nodes) { 342 if (!first_rule_.IsValid()) { 343 ERROR("*** No targets."); 344 } 345 346 if (!g_flags.gen_all_targets && targets.empty()) { 347 targets.push_back(first_rule_); 348 } 349 if (g_flags.gen_all_targets) { 350 unordered_set<Symbol> non_root_targets; 351 for (const auto& p : rules_) { 352 for (const Rule* r : p.second.rules) { 353 for (Symbol t : r->inputs) 354 non_root_targets.insert(t); 355 for (Symbol t : r->order_only_inputs) 356 non_root_targets.insert(t); 357 } 358 } 359 360 for (const auto& p : rules_) { 361 Symbol t = p.first; 362 if (!non_root_targets.count(t)) { 363 targets.push_back(p.first); 364 } 365 } 366 } 367 368 // TODO: LogStats? 369 370 for (Symbol target : targets) { 371 cur_rule_vars_.reset(new Vars); 372 ev_->set_current_scope(cur_rule_vars_.get()); 373 DepNode* n = BuildPlan(target, Intern("")); 374 nodes->push_back(n); 375 ev_->set_current_scope(NULL); 376 cur_rule_vars_.reset(NULL); 377 } 378 } 379 380 private: 381 bool Exists(Symbol target) { 382 auto found = rules_.find(target); 383 if (found != rules_.end()) 384 return true; 385 if (phony_.count(target)) 386 return true; 387 return ::Exists(target.str()); 388 } 389 390 bool GetRuleInputs(Symbol s, vector<Symbol>* o, Loc* l) { 391 auto found = rules_.find(s); 392 if (found == rules_.end()) 393 return false; 394 395 o->clear(); 396 CHECK(!found->second.rules.empty()); 397 *l = found->second.rules.front()->loc; 398 for (const Rule* r : found->second.rules) { 399 for (Symbol i : r->inputs) 400 o->push_back(i); 401 } 402 return true; 403 } 404 405 void PopulateRules(const vector<const Rule*>& rules) { 406 for (const Rule* rule : rules) { 407 if (rule->outputs.empty()) { 408 PopulateImplicitRule(rule); 409 } else { 410 PopulateExplicitRule(rule); 411 } 412 } 413 for (auto& p : suffix_rules_) { 414 reverse(p.second.begin(), p.second.end()); 415 } 416 for (auto& p : rules_) { 417 auto vars = LookupRuleVars(p.first); 418 if (!vars) { 419 continue; 420 } 421 auto var = vars->Lookup(implicit_outputs_var_name_); 422 if (!var->IsDefined()) { 423 continue; 424 } 425 426 string implicit_outputs; 427 var->Eval(ev_, &implicit_outputs); 428 429 for (StringPiece output : WordScanner(implicit_outputs)) { 430 Symbol sym = Intern(TrimLeadingCurdir(output)); 431 rules_[sym].SetImplicitOutput(sym, p.first, &p.second); 432 p.second.AddImplicitOutput(sym, &rules_[sym]); 433 } 434 } 435 } 436 437 bool PopulateSuffixRule(const Rule* rule, Symbol output) { 438 if (!IsSuffixRule(output)) 439 return false; 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 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 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 478 void PopulateImplicitRule(const Rule* rule) { 479 for (Symbol output_pattern : rule->output_patterns) { 480 if (output_pattern.str() != "%" || !IsIgnorableImplicitRule(rule)) 481 implicit_rules_->Add(output_pattern.str(), rule); 482 } 483 } 484 485 const RuleMerger* LookupRuleMerger(Symbol o) { 486 auto found = rules_.find(o); 487 if (found != rules_.end()) { 488 return &found->second; 489 } 490 return nullptr; 491 } 492 493 Vars* LookupRuleVars(Symbol o) { 494 auto found = rule_vars_.find(o); 495 if (found != rule_vars_.end()) 496 return found->second; 497 return nullptr; 498 } 499 500 bool CanPickImplicitRule(const Rule* rule, 501 Symbol output, 502 DepNode* n, 503 shared_ptr<Rule>* out_rule) { 504 Symbol matched(Symbol::IsUninitialized{}); 505 for (Symbol output_pattern : rule->output_patterns) { 506 Pattern pat(output_pattern.str()); 507 if (pat.Match(output.str())) { 508 bool ok = true; 509 for (Symbol input : rule->inputs) { 510 string buf; 511 pat.AppendSubst(output.str(), input.str(), &buf); 512 if (!Exists(Intern(buf))) { 513 ok = false; 514 break; 515 } 516 } 517 518 if (ok) { 519 matched = output_pattern; 520 break; 521 } 522 } 523 } 524 if (!matched.IsValid()) 525 return false; 526 527 *out_rule = make_shared<Rule>(*rule); 528 if ((*out_rule)->output_patterns.size() > 1) { 529 // We should mark all other output patterns as used. 530 Pattern pat(matched.str()); 531 for (Symbol output_pattern : rule->output_patterns) { 532 if (output_pattern == matched) 533 continue; 534 string buf; 535 pat.AppendSubst(output.str(), output_pattern.str(), &buf); 536 done_[Intern(buf)] = n; 537 } 538 (*out_rule)->output_patterns.clear(); 539 (*out_rule)->output_patterns.push_back(matched); 540 } 541 542 return true; 543 } 544 545 Vars* MergeImplicitRuleVars(Symbol output, Vars* vars) { 546 auto found = rule_vars_.find(output); 547 if (found == rule_vars_.end()) 548 return vars; 549 if (vars == NULL) 550 return found->second; 551 // TODO: leak. 552 Vars* r = new Vars(*found->second); 553 for (auto p : *vars) { 554 (*r)[p.first] = p.second; 555 } 556 return r; 557 } 558 559 bool PickRule(Symbol output, 560 DepNode* n, 561 const RuleMerger** out_rule_merger, 562 shared_ptr<Rule>* pattern_rule, 563 Vars** out_var) { 564 const RuleMerger* rule_merger = LookupRuleMerger(output); 565 Vars* vars = LookupRuleVars(output); 566 *out_rule_merger = rule_merger; 567 *out_var = vars; 568 if (rule_merger && rule_merger->primary_rule) { 569 for (auto implicit_output : rule_merger->implicit_outputs) { 570 vars = MergeImplicitRuleVars(implicit_output.first, vars); 571 } 572 *out_var = vars; 573 return true; 574 } 575 576 vector<const Rule*> irules; 577 implicit_rules_->Get(output.str(), &irules); 578 for (auto iter = irules.rbegin(); iter != irules.rend(); ++iter) { 579 if (!CanPickImplicitRule(*iter, output, n, pattern_rule)) 580 continue; 581 if (rule_merger) { 582 return true; 583 } 584 CHECK((*pattern_rule)->output_patterns.size() == 1); 585 vars = MergeImplicitRuleVars((*pattern_rule)->output_patterns[0], vars); 586 *out_var = vars; 587 return true; 588 } 589 590 StringPiece output_suffix = GetExt(output.str()); 591 if (output_suffix.get(0) != '.') 592 return rule_merger; 593 output_suffix = output_suffix.substr(1); 594 595 SuffixRuleMap::const_iterator found = suffix_rules_.find(output_suffix); 596 if (found == suffix_rules_.end()) 597 return rule_merger; 598 599 for (const shared_ptr<Rule>& irule : found->second) { 600 CHECK(irule->inputs.size() == 1); 601 Symbol input = ReplaceSuffix(output, irule->inputs[0]); 602 if (!Exists(input)) 603 continue; 604 605 *pattern_rule = irule; 606 if (rule_merger) 607 return true; 608 if (vars) { 609 CHECK(irule->outputs.size() == 1); 610 vars = MergeImplicitRuleVars(irule->outputs[0], vars); 611 *out_var = vars; 612 } 613 return true; 614 } 615 616 return rule_merger; 617 } 618 619 DepNode* BuildPlan(Symbol output, Symbol needed_by UNUSED) { 620 LOG("BuildPlan: %s for %s", output.c_str(), needed_by.c_str()); 621 622 auto found = done_.find(output); 623 if (found != done_.end()) { 624 return found->second; 625 } 626 627 DepNode* n = 628 new DepNode(output, phony_.count(output), restat_.count(output)); 629 done_[output] = n; 630 631 const RuleMerger* rule_merger = nullptr; 632 shared_ptr<Rule> pattern_rule; 633 Vars* vars; 634 if (!PickRule(output, n, &rule_merger, &pattern_rule, &vars)) { 635 return n; 636 } 637 if (rule_merger && rule_merger->parent) { 638 output = rule_merger->parent_sym; 639 done_[output] = n; 640 n->output = output; 641 if (!PickRule(output, n, &rule_merger, &pattern_rule, &vars)) { 642 return n; 643 } 644 } 645 if (rule_merger) 646 rule_merger->FillDepNode(output, pattern_rule.get(), n); 647 else 648 RuleMerger().FillDepNode(output, pattern_rule.get(), n); 649 650 vector<unique_ptr<ScopedVar>> sv; 651 if (vars) { 652 for (const auto& p : *vars) { 653 Symbol name = p.first; 654 RuleVar* var = reinterpret_cast<RuleVar*>(p.second); 655 CHECK(var); 656 Var* new_var = var->v(); 657 if (var->op() == AssignOp::PLUS_EQ) { 658 Var* old_var = ev_->LookupVar(name); 659 if (old_var->IsDefined()) { 660 // TODO: This would be incorrect and has a leak. 661 shared_ptr<string> s = make_shared<string>(); 662 old_var->Eval(ev_, s.get()); 663 if (!s->empty()) 664 *s += ' '; 665 new_var->Eval(ev_, s.get()); 666 new_var = new SimpleVar(*s, old_var->Origin()); 667 } 668 } else if (var->op() == AssignOp::QUESTION_EQ) { 669 Var* old_var = ev_->LookupVar(name); 670 if (old_var->IsDefined()) { 671 continue; 672 } 673 } 674 675 if (name == depfile_var_name_) { 676 n->depfile_var = new_var; 677 } else if (name == implicit_outputs_var_name_) { 678 } else if (name == ninja_pool_var_name_) { 679 n->ninja_pool_var = new_var; 680 } else { 681 sv.emplace_back(new ScopedVar(cur_rule_vars_.get(), name, new_var)); 682 } 683 } 684 } 685 686 for (Symbol output : n->implicit_outputs) { 687 done_[output] = n; 688 } 689 690 for (Symbol input : n->actual_inputs) { 691 DepNode* c = BuildPlan(input, output); 692 n->deps.push_back(c); 693 } 694 695 for (Symbol input : n->actual_order_only_inputs) { 696 DepNode* c = BuildPlan(input, output); 697 n->order_onlys.push_back(c); 698 } 699 700 n->has_rule = true; 701 n->is_default_target = first_rule_ == output; 702 if (cur_rule_vars_->empty()) { 703 n->rule_vars = NULL; 704 } else { 705 n->rule_vars = new Vars; 706 for (auto p : *cur_rule_vars_) { 707 n->rule_vars->insert(p); 708 } 709 } 710 711 return n; 712 } 713 714 Evaluator* ev_; 715 map<Symbol, RuleMerger> rules_; 716 const unordered_map<Symbol, Vars*>& rule_vars_; 717 unique_ptr<Vars> cur_rule_vars_; 718 719 unique_ptr<RuleTrie> implicit_rules_; 720 typedef unordered_map<StringPiece, vector<shared_ptr<Rule>>> SuffixRuleMap; 721 SuffixRuleMap suffix_rules_; 722 723 Symbol first_rule_; 724 unordered_map<Symbol, DepNode*> done_; 725 unordered_set<Symbol> phony_; 726 unordered_set<Symbol> restat_; 727 Symbol depfile_var_name_; 728 Symbol implicit_outputs_var_name_; 729 Symbol ninja_pool_var_name_; 730 }; 731 732 void MakeDep(Evaluator* ev, 733 const vector<const Rule*>& rules, 734 const unordered_map<Symbol, Vars*>& rule_vars, 735 const vector<Symbol>& targets, 736 vector<DepNode*>* nodes) { 737 DepBuilder db(ev, rules, rule_vars); 738 ScopedTimeReporter tr("make dep (build)"); 739 db.Build(targets, nodes); 740 } 741 742 void InitDepNodePool() { 743 g_dep_node_pool = new vector<DepNode*>; 744 } 745 746 void QuitDepNodePool() { 747 for (DepNode* n : *g_dep_node_pool) 748 delete n; 749 delete g_dep_node_pool; 750 } 751