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