• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 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 #include "graph.h"
16 
17 #include <algorithm>
18 #include <assert.h>
19 #include <stdio.h>
20 
21 #include "build_log.h"
22 #include "debug_flags.h"
23 #include "depfile_parser.h"
24 #include "deps_log.h"
25 #include "disk_interface.h"
26 #include "manifest_parser.h"
27 #include "metrics.h"
28 #include "state.h"
29 #include "util.h"
30 
Stat(DiskInterface * disk_interface,string * err)31 bool Node::Stat(DiskInterface* disk_interface, string* err) {
32   return (mtime_ = disk_interface->Stat(path_, err)) != -1;
33 }
34 
RecomputeDirty(Node * node,string * err)35 bool DependencyScan::RecomputeDirty(Node* node, string* err) {
36   vector<Node*> stack;
37   return RecomputeDirty(node, &stack, err);
38 }
39 
RecomputeDirty(Node * node,vector<Node * > * stack,string * err)40 bool DependencyScan::RecomputeDirty(Node* node, vector<Node*>* stack,
41                                     string* err) {
42   Edge* edge = node->in_edge();
43   if (!edge) {
44     // If we already visited this leaf node then we are done.
45     if (node->status_known())
46       return true;
47     // This node has no in-edge; it is dirty if it is missing.
48     if (!node->StatIfNecessary(disk_interface_, err))
49       return false;
50     if (!node->exists())
51       EXPLAIN("%s has no in-edge and is missing", node->path().c_str());
52     node->set_dirty(!node->exists());
53     return true;
54   }
55 
56   // If we already finished this edge then we are done.
57   if (edge->mark_ == Edge::VisitDone)
58     return true;
59 
60   // If we encountered this edge earlier in the call stack we have a cycle.
61   if (!VerifyDAG(node, stack, err))
62     return false;
63 
64   // Mark the edge temporarily while in the call stack.
65   edge->mark_ = Edge::VisitInStack;
66   stack->push_back(node);
67 
68   bool dirty = false;
69   edge->outputs_ready_ = true;
70   edge->deps_missing_ = false;
71 
72   if (!edge->deps_loaded_) {
73     // This is our first encounter with this edge.
74     // If there is a pending dyndep file, visit it now:
75     // * If the dyndep file is ready then load it now to get any
76     //   additional inputs and outputs for this and other edges.
77     //   Once the dyndep file is loaded it will no longer be pending
78     //   if any other edges encounter it, but they will already have
79     //   been updated.
80     // * If the dyndep file is not ready then since is known to be an
81     //   input to this edge, the edge will not be considered ready below.
82     //   Later during the build the dyndep file will become ready and be
83     //   loaded to update this edge before it can possibly be scheduled.
84     if (edge->dyndep_ && edge->dyndep_->dyndep_pending()) {
85       if (!RecomputeDirty(edge->dyndep_, stack, err))
86         return false;
87 
88       if (!edge->dyndep_->in_edge() ||
89           edge->dyndep_->in_edge()->outputs_ready()) {
90         // The dyndep file is ready, so load it now.
91         if (!LoadDyndeps(edge->dyndep_, err))
92           return false;
93       }
94     }
95   }
96 
97   // Load output mtimes so we can compare them to the most recent input below.
98   for (vector<Node*>::iterator o = edge->outputs_.begin();
99        o != edge->outputs_.end(); ++o) {
100     if (!(*o)->StatIfNecessary(disk_interface_, err))
101       return false;
102   }
103 
104   if (!edge->deps_loaded_) {
105     // This is our first encounter with this edge.  Load discovered deps.
106     edge->deps_loaded_ = true;
107     if (!dep_loader_.LoadDeps(edge, err)) {
108       if (!err->empty())
109         return false;
110       // Failed to load dependency info: rebuild to regenerate it.
111       // LoadDeps() did EXPLAIN() already, no need to do it here.
112       dirty = edge->deps_missing_ = true;
113     }
114   }
115 
116   // Visit all inputs; we're dirty if any of the inputs are dirty.
117   Node* most_recent_input = NULL;
118   for (vector<Node*>::iterator i = edge->inputs_.begin();
119        i != edge->inputs_.end(); ++i) {
120     // Visit this input.
121     if (!RecomputeDirty(*i, stack, err))
122       return false;
123 
124     // If an input is not ready, neither are our outputs.
125     if (Edge* in_edge = (*i)->in_edge()) {
126       if (!in_edge->outputs_ready_)
127         edge->outputs_ready_ = false;
128     }
129 
130     if (!edge->is_order_only(i - edge->inputs_.begin())) {
131       // If a regular input is dirty (or missing), we're dirty.
132       // Otherwise consider mtime.
133       if ((*i)->dirty()) {
134         EXPLAIN("%s is dirty", (*i)->path().c_str());
135         dirty = true;
136       } else {
137         if (!most_recent_input || (*i)->mtime() > most_recent_input->mtime()) {
138           most_recent_input = *i;
139         }
140       }
141     }
142   }
143 
144   // We may also be dirty due to output state: missing outputs, out of
145   // date outputs, etc.  Visit all outputs and determine whether they're dirty.
146   if (!dirty)
147     if (!RecomputeOutputsDirty(edge, most_recent_input, &dirty, err))
148       return false;
149 
150   // Finally, visit each output and update their dirty state if necessary.
151   for (vector<Node*>::iterator o = edge->outputs_.begin();
152        o != edge->outputs_.end(); ++o) {
153     if (dirty)
154       (*o)->MarkDirty();
155   }
156 
157   // If an edge is dirty, its outputs are normally not ready.  (It's
158   // possible to be clean but still not be ready in the presence of
159   // order-only inputs.)
160   // But phony edges with no inputs have nothing to do, so are always
161   // ready.
162   if (dirty && !(edge->is_phony() && edge->inputs_.empty()))
163     edge->outputs_ready_ = false;
164 
165   // Mark the edge as finished during this walk now that it will no longer
166   // be in the call stack.
167   edge->mark_ = Edge::VisitDone;
168   assert(stack->back() == node);
169   stack->pop_back();
170 
171   return true;
172 }
173 
VerifyDAG(Node * node,vector<Node * > * stack,string * err)174 bool DependencyScan::VerifyDAG(Node* node, vector<Node*>* stack, string* err) {
175   Edge* edge = node->in_edge();
176   assert(edge != NULL);
177 
178   // If we have no temporary mark on the edge then we do not yet have a cycle.
179   if (edge->mark_ != Edge::VisitInStack)
180     return true;
181 
182   // We have this edge earlier in the call stack.  Find it.
183   vector<Node*>::iterator start = stack->begin();
184   while (start != stack->end() && (*start)->in_edge() != edge)
185     ++start;
186   assert(start != stack->end());
187 
188   // Make the cycle clear by reporting its start as the node at its end
189   // instead of some other output of the starting edge.  For example,
190   // running 'ninja b' on
191   //   build a b: cat c
192   //   build c: cat a
193   // should report a -> c -> a instead of b -> c -> a.
194   *start = node;
195 
196   // Construct the error message rejecting the cycle.
197   *err = "dependency cycle: ";
198   for (vector<Node*>::const_iterator i = start; i != stack->end(); ++i) {
199     err->append((*i)->path());
200     err->append(" -> ");
201   }
202   err->append((*start)->path());
203 
204   if ((start + 1) == stack->end() && edge->maybe_phonycycle_diagnostic()) {
205     // The manifest parser would have filtered out the self-referencing
206     // input if it were not configured to allow the error.
207     err->append(" [-w phonycycle=err]");
208   }
209 
210   return false;
211 }
212 
RecomputeOutputsDirty(Edge * edge,Node * most_recent_input,bool * outputs_dirty,string * err)213 bool DependencyScan::RecomputeOutputsDirty(Edge* edge, Node* most_recent_input,
214                                            bool* outputs_dirty, string* err) {
215   string command = edge->EvaluateCommand(/*incl_rsp_file=*/true);
216   for (vector<Node*>::iterator o = edge->outputs_.begin();
217        o != edge->outputs_.end(); ++o) {
218     if (RecomputeOutputDirty(edge, most_recent_input, command, *o)) {
219       *outputs_dirty = true;
220       return true;
221     }
222   }
223   return true;
224 }
225 
RecomputeOutputDirty(const Edge * edge,const Node * most_recent_input,const string & command,Node * output)226 bool DependencyScan::RecomputeOutputDirty(const Edge* edge,
227                                           const Node* most_recent_input,
228                                           const string& command,
229                                           Node* output) {
230   if (edge->is_phony()) {
231     // Phony edges don't write any output.  Outputs are only dirty if
232     // there are no inputs and we're missing the output.
233     if (edge->inputs_.empty() && !output->exists()) {
234       EXPLAIN("output %s of phony edge with no inputs doesn't exist",
235               output->path().c_str());
236       return true;
237     }
238     return false;
239   }
240 
241   BuildLog::LogEntry* entry = 0;
242 
243   // Dirty if we're missing the output.
244   if (!output->exists()) {
245     EXPLAIN("output %s doesn't exist", output->path().c_str());
246     return true;
247   }
248 
249   // Dirty if the output is older than the input.
250   if (most_recent_input && output->mtime() < most_recent_input->mtime()) {
251     TimeStamp output_mtime = output->mtime();
252 
253     // If this is a restat rule, we may have cleaned the output with a restat
254     // rule in a previous run and stored the most recent input mtime in the
255     // build log.  Use that mtime instead, so that the file will only be
256     // considered dirty if an input was modified since the previous run.
257     bool used_restat = false;
258     if (edge->GetBindingBool("restat") && build_log() &&
259         (entry = build_log()->LookupByOutput(output->path()))) {
260       output_mtime = entry->mtime;
261       used_restat = true;
262     }
263 
264     if (output_mtime < most_recent_input->mtime()) {
265       EXPLAIN("%soutput %s older than most recent input %s "
266               "(%" PRId64 " vs %" PRId64 ")",
267               used_restat ? "restat of " : "", output->path().c_str(),
268               most_recent_input->path().c_str(),
269               output_mtime, most_recent_input->mtime());
270       return true;
271     }
272   }
273 
274   if (build_log()) {
275     bool generator = edge->GetBindingBool("generator");
276     if (entry || (entry = build_log()->LookupByOutput(output->path()))) {
277       if (!generator &&
278           BuildLog::LogEntry::HashCommand(command) != entry->command_hash) {
279         // May also be dirty due to the command changing since the last build.
280         // But if this is a generator rule, the command changing does not make us
281         // dirty.
282         EXPLAIN("command line changed for %s", output->path().c_str());
283         return true;
284       }
285       if (most_recent_input && entry->mtime < most_recent_input->mtime()) {
286         // May also be dirty due to the mtime in the log being older than the
287         // mtime of the most recent input.  This can occur even when the mtime
288         // on disk is newer if a previous run wrote to the output file but
289         // exited with an error or was interrupted.
290         EXPLAIN("recorded mtime of %s older than most recent input %s (%" PRId64 " vs %" PRId64 ")",
291                 output->path().c_str(), most_recent_input->path().c_str(),
292                 entry->mtime, most_recent_input->mtime());
293         return true;
294       }
295     }
296     if (!entry && !generator) {
297       EXPLAIN("command line not found in log for %s", output->path().c_str());
298       return true;
299     }
300   }
301 
302   return false;
303 }
304 
LoadDyndeps(Node * node,string * err) const305 bool DependencyScan::LoadDyndeps(Node* node, string* err) const {
306   return dyndep_loader_.LoadDyndeps(node, err);
307 }
308 
LoadDyndeps(Node * node,DyndepFile * ddf,string * err) const309 bool DependencyScan::LoadDyndeps(Node* node, DyndepFile* ddf,
310                                  string* err) const {
311   return dyndep_loader_.LoadDyndeps(node, ddf, err);
312 }
313 
AllInputsReady() const314 bool Edge::AllInputsReady() const {
315   for (vector<Node*>::const_iterator i = inputs_.begin();
316        i != inputs_.end(); ++i) {
317     if ((*i)->in_edge() && !(*i)->in_edge()->outputs_ready())
318       return false;
319   }
320   return true;
321 }
322 
323 /// An Env for an Edge, providing $in and $out.
324 struct EdgeEnv : public Env {
325   enum EscapeKind { kShellEscape, kDoNotEscape };
326 
EdgeEnvEdgeEnv327   EdgeEnv(const Edge* const edge, const EscapeKind escape)
328       : edge_(edge), escape_in_out_(escape), recursive_(false) {}
329   virtual string LookupVariable(const string& var);
330 
331   /// Given a span of Nodes, construct a list of paths suitable for a command
332   /// line.
333   std::string MakePathList(const Node* const* span, size_t size, char sep) const;
334 
335  private:
336   vector<string> lookups_;
337   const Edge* const edge_;
338   EscapeKind escape_in_out_;
339   bool recursive_;
340 };
341 
LookupVariable(const string & var)342 string EdgeEnv::LookupVariable(const string& var) {
343   if (var == "in" || var == "in_newline") {
344     int explicit_deps_count = edge_->inputs_.size() - edge_->implicit_deps_ -
345       edge_->order_only_deps_;
346 #if __cplusplus >= 201103L
347     return MakePathList(edge_->inputs_.data(), explicit_deps_count,
348 #else
349     return MakePathList(&edge_->inputs_[0], explicit_deps_count,
350 #endif
351                         var == "in" ? ' ' : '\n');
352   } else if (var == "out") {
353     int explicit_outs_count = edge_->outputs_.size() - edge_->implicit_outs_;
354     return MakePathList(&edge_->outputs_[0], explicit_outs_count, ' ');
355   }
356 
357   if (recursive_) {
358     vector<string>::const_iterator it;
359     if ((it = find(lookups_.begin(), lookups_.end(), var)) != lookups_.end()) {
360       string cycle;
361       for (; it != lookups_.end(); ++it)
362         cycle.append(*it + " -> ");
363       cycle.append(var);
364       Fatal(("cycle in rule variables: " + cycle).c_str());
365     }
366   }
367 
368   // See notes on BindingEnv::LookupWithFallback.
369   const EvalString* eval = edge_->rule_->GetBinding(var);
370   if (recursive_ && eval)
371     lookups_.push_back(var);
372 
373   // In practice, variables defined on rules never use another rule variable.
374   // For performance, only start checking for cycles after the first lookup.
375   recursive_ = true;
376   return edge_->env_->LookupWithFallback(var, eval, this);
377 }
378 
MakePathList(const Node * const * const span,const size_t size,const char sep) const379 std::string EdgeEnv::MakePathList(const Node* const* const span,
380                                   const size_t size, const char sep) const {
381   string result;
382   for (const Node* const* i = span; i != span + size; ++i) {
383     if (!result.empty())
384       result.push_back(sep);
385     const string& path = (*i)->PathDecanonicalized();
386     if (escape_in_out_ == kShellEscape) {
387 #ifdef _WIN32
388       GetWin32EscapedString(path, &result);
389 #else
390       GetShellEscapedString(path, &result);
391 #endif
392     } else {
393       result.append(path);
394     }
395   }
396   return result;
397 }
398 
EvaluateCommand(const bool incl_rsp_file) const399 std::string Edge::EvaluateCommand(const bool incl_rsp_file) const {
400   string command = GetBinding("command");
401   if (incl_rsp_file) {
402     string rspfile_content = GetBinding("rspfile_content");
403     if (!rspfile_content.empty())
404       command += ";rspfile=" + rspfile_content;
405   }
406   return command;
407 }
408 
GetBinding(const std::string & key) const409 std::string Edge::GetBinding(const std::string& key) const {
410   EdgeEnv env(this, EdgeEnv::kShellEscape);
411   return env.LookupVariable(key);
412 }
413 
GetBindingBool(const string & key) const414 bool Edge::GetBindingBool(const string& key) const {
415   return !GetBinding(key).empty();
416 }
417 
GetUnescapedDepfile() const418 string Edge::GetUnescapedDepfile() const {
419   EdgeEnv env(this, EdgeEnv::kDoNotEscape);
420   return env.LookupVariable("depfile");
421 }
422 
GetUnescapedDyndep() const423 string Edge::GetUnescapedDyndep() const {
424   EdgeEnv env(this, EdgeEnv::kDoNotEscape);
425   return env.LookupVariable("dyndep");
426 }
427 
GetUnescapedRspfile() const428 std::string Edge::GetUnescapedRspfile() const {
429   EdgeEnv env(this, EdgeEnv::kDoNotEscape);
430   return env.LookupVariable("rspfile");
431 }
432 
Dump(const char * prefix) const433 void Edge::Dump(const char* prefix) const {
434   printf("%s[ ", prefix);
435   for (vector<Node*>::const_iterator i = inputs_.begin();
436        i != inputs_.end() && *i != NULL; ++i) {
437     printf("%s ", (*i)->path().c_str());
438   }
439   printf("--%s-> ", rule_->name().c_str());
440   for (vector<Node*>::const_iterator i = outputs_.begin();
441        i != outputs_.end() && *i != NULL; ++i) {
442     printf("%s ", (*i)->path().c_str());
443   }
444   if (pool_) {
445     if (!pool_->name().empty()) {
446       printf("(in pool '%s')", pool_->name().c_str());
447     }
448   } else {
449     printf("(null pool?)");
450   }
451   printf("] 0x%p\n", this);
452 }
453 
is_phony() const454 bool Edge::is_phony() const {
455   return rule_ == &State::kPhonyRule;
456 }
457 
use_console() const458 bool Edge::use_console() const {
459   return pool() == &State::kConsolePool;
460 }
461 
maybe_phonycycle_diagnostic() const462 bool Edge::maybe_phonycycle_diagnostic() const {
463   // CMake 2.8.12.x and 3.0.x produced self-referencing phony rules
464   // of the form "build a: phony ... a ...".   Restrict our
465   // "phonycycle" diagnostic option to the form it used.
466   return is_phony() && outputs_.size() == 1 && implicit_outs_ == 0 &&
467       implicit_deps_ == 0;
468 }
469 
470 // static
PathDecanonicalized(const string & path,uint64_t slash_bits)471 string Node::PathDecanonicalized(const string& path, uint64_t slash_bits) {
472   string result = path;
473 #ifdef _WIN32
474   uint64_t mask = 1;
475   for (char* c = &result[0]; (c = strchr(c, '/')) != NULL;) {
476     if (slash_bits & mask)
477       *c = '\\';
478     c++;
479     mask <<= 1;
480   }
481 #endif
482   return result;
483 }
484 
Dump(const char * prefix) const485 void Node::Dump(const char* prefix) const {
486   printf("%s <%s 0x%p> mtime: %" PRId64 "%s, (:%s), ",
487          prefix, path().c_str(), this,
488          mtime(), mtime() ? "" : " (:missing)",
489          dirty() ? " dirty" : " clean");
490   if (in_edge()) {
491     in_edge()->Dump("in-edge: ");
492   } else {
493     printf("no in-edge\n");
494   }
495   printf(" out edges:\n");
496   for (vector<Edge*>::const_iterator e = out_edges().begin();
497        e != out_edges().end() && *e != NULL; ++e) {
498     (*e)->Dump(" +- ");
499   }
500 }
501 
LoadDeps(Edge * edge,string * err)502 bool ImplicitDepLoader::LoadDeps(Edge* edge, string* err) {
503   string deps_type = edge->GetBinding("deps");
504   if (!deps_type.empty())
505     return LoadDepsFromLog(edge, err);
506 
507   string depfile = edge->GetUnescapedDepfile();
508   if (!depfile.empty())
509     return LoadDepFile(edge, depfile, err);
510 
511   // No deps to load.
512   return true;
513 }
514 
515 struct matches {
matchesmatches516   matches(std::vector<StringPiece>::iterator i) : i_(i) {}
517 
operator ()matches518   bool operator()(const Node* node) const {
519     StringPiece opath = StringPiece(node->path());
520     return *i_ == opath;
521   }
522 
523   std::vector<StringPiece>::iterator i_;
524 };
525 
LoadDepFile(Edge * edge,const string & path,string * err)526 bool ImplicitDepLoader::LoadDepFile(Edge* edge, const string& path,
527                                     string* err) {
528   METRIC_RECORD("depfile load");
529   // Read depfile content.  Treat a missing depfile as empty.
530   string content;
531   switch (disk_interface_->ReadFile(path, &content, err)) {
532   case DiskInterface::Okay:
533     break;
534   case DiskInterface::NotFound:
535     err->clear();
536     break;
537   case DiskInterface::OtherError:
538     *err = "loading '" + path + "': " + *err;
539     return false;
540   }
541   // On a missing depfile: return false and empty *err.
542   if (content.empty()) {
543     EXPLAIN("depfile '%s' is missing", path.c_str());
544     return false;
545   }
546 
547   DepfileParser depfile(depfile_parser_options_
548                         ? *depfile_parser_options_
549                         : DepfileParserOptions());
550   string depfile_err;
551   if (!depfile.Parse(&content, &depfile_err)) {
552     *err = path + ": " + depfile_err;
553     return false;
554   }
555 
556   if (depfile.outs_.empty()) {
557     *err = path + ": no outputs declared";
558     return false;
559   }
560 
561   uint64_t unused;
562   std::vector<StringPiece>::iterator primary_out = depfile.outs_.begin();
563   if (!CanonicalizePath(const_cast<char*>(primary_out->str_),
564                         &primary_out->len_, &unused, err)) {
565     *err = path + ": " + *err;
566     return false;
567   }
568 
569   // Check that this depfile matches the edge's output, if not return false to
570   // mark the edge as dirty.
571   Node* first_output = edge->outputs_[0];
572   StringPiece opath = StringPiece(first_output->path());
573   if (opath != *primary_out) {
574     EXPLAIN("expected depfile '%s' to mention '%s', got '%s'", path.c_str(),
575             first_output->path().c_str(), primary_out->AsString().c_str());
576     return false;
577   }
578 
579   // Ensure that all mentioned outputs are outputs of the edge.
580   for (std::vector<StringPiece>::iterator o = depfile.outs_.begin();
581        o != depfile.outs_.end(); ++o) {
582     matches m(o);
583     if (std::find_if(edge->outputs_.begin(), edge->outputs_.end(), m) == edge->outputs_.end()) {
584       *err = path + ": depfile mentions '" + o->AsString() + "' as an output, but no such output was declared";
585       return false;
586     }
587   }
588 
589   // Preallocate space in edge->inputs_ to be filled in below.
590   vector<Node*>::iterator implicit_dep =
591       PreallocateSpace(edge, depfile.ins_.size());
592 
593   // Add all its in-edges.
594   for (vector<StringPiece>::iterator i = depfile.ins_.begin();
595        i != depfile.ins_.end(); ++i, ++implicit_dep) {
596     uint64_t slash_bits;
597     if (!CanonicalizePath(const_cast<char*>(i->str_), &i->len_, &slash_bits,
598                           err))
599       return false;
600 
601     Node* node = state_->GetNode(*i, slash_bits);
602     *implicit_dep = node;
603     node->AddOutEdge(edge);
604     CreatePhonyInEdge(node);
605   }
606 
607   return true;
608 }
609 
LoadDepsFromLog(Edge * edge,string * err)610 bool ImplicitDepLoader::LoadDepsFromLog(Edge* edge, string* err) {
611   // NOTE: deps are only supported for single-target edges.
612   Node* output = edge->outputs_[0];
613   DepsLog::Deps* deps = deps_log_ ? deps_log_->GetDeps(output) : NULL;
614   if (!deps) {
615     EXPLAIN("deps for '%s' are missing", output->path().c_str());
616     return false;
617   }
618 
619   // Deps are invalid if the output is newer than the deps.
620   if (output->mtime() > deps->mtime) {
621     EXPLAIN("stored deps info out of date for '%s' (%" PRId64 " vs %" PRId64 ")",
622             output->path().c_str(), deps->mtime, output->mtime());
623     return false;
624   }
625 
626   vector<Node*>::iterator implicit_dep =
627       PreallocateSpace(edge, deps->node_count);
628   for (int i = 0; i < deps->node_count; ++i, ++implicit_dep) {
629     Node* node = deps->nodes[i];
630     *implicit_dep = node;
631     node->AddOutEdge(edge);
632     CreatePhonyInEdge(node);
633   }
634   return true;
635 }
636 
PreallocateSpace(Edge * edge,int count)637 vector<Node*>::iterator ImplicitDepLoader::PreallocateSpace(Edge* edge,
638                                                             int count) {
639   edge->inputs_.insert(edge->inputs_.end() - edge->order_only_deps_,
640                        (size_t)count, 0);
641   edge->implicit_deps_ += count;
642   return edge->inputs_.end() - edge->order_only_deps_ - count;
643 }
644 
CreatePhonyInEdge(Node * node)645 void ImplicitDepLoader::CreatePhonyInEdge(Node* node) {
646   if (node->in_edge())
647     return;
648 
649   Edge* phony_edge = state_->AddEdge(&State::kPhonyRule);
650   node->set_in_edge(phony_edge);
651   phony_edge->outputs_.push_back(node);
652 
653   // RecomputeDirty might not be called for phony_edge if a previous call
654   // to RecomputeDirty had caused the file to be stat'ed.  Because previous
655   // invocations of RecomputeDirty would have seen this node without an
656   // input edge (and therefore ready), we have to set outputs_ready_ to true
657   // to avoid a potential stuck build.  If we do call RecomputeDirty for
658   // this node, it will simply set outputs_ready_ to the correct value.
659   phony_edge->outputs_ready_ = true;
660 }
661