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