34 return (mtime_ = disk_interface->
Stat(path_, err)) != -1;
39 return RecomputeDirty(node, &stack, err);
53 EXPLAIN(
"%s has no in-edge and is missing", node->
path().c_str());
63 if (!VerifyDAG(node, stack, err))
68 stack->push_back(node);
87 if (!RecomputeDirty(edge->
dyndep_, stack, err))
93 if (!LoadDyndeps(edge->
dyndep_, err))
100 for (vector<Node*>::iterator o = edge->
outputs_.begin();
102 if (!(*o)->StatIfNecessary(disk_interface_, err))
109 if (!dep_loader_.LoadDeps(edge, err)) {
119 Node* most_recent_input = NULL;
120 for (vector<Node*>::iterator i = edge->
inputs_.begin();
121 i != edge->
inputs_.end(); ++i) {
123 if (!RecomputeDirty(*i, stack, err))
127 if (
Edge* in_edge = (*i)->in_edge()) {
128 if (!in_edge->outputs_ready_)
136 EXPLAIN(
"%s is dirty", (*i)->path().c_str());
139 if (!most_recent_input || (*i)->mtime() > most_recent_input->
mtime()) {
140 most_recent_input = *i;
149 if (!RecomputeOutputsDirty(edge, most_recent_input, &dirty, err))
153 for (vector<Node*>::iterator o = edge->
outputs_.begin();
170 assert(stack->back() == node);
178 assert(edge != NULL);
185 vector<Node*>::iterator start = stack->begin();
186 while (start != stack->end() && (*start)->in_edge() != edge)
188 assert(start != stack->end());
199 *err =
"dependency cycle: ";
200 for (vector<Node*>::const_iterator i = start; i != stack->end(); ++i) {
201 err->append((*i)->path());
204 err->append((*start)->path());
209 err->append(
" [-w phonycycle=err]");
216 bool* outputs_dirty,
string* err) {
218 for (vector<Node*>::iterator o = edge->
outputs_.begin();
220 if (RecomputeOutputDirty(edge, most_recent_input, command, *o)) {
221 *outputs_dirty =
true;
229 const Node* most_recent_input,
230 const string& command,
236 EXPLAIN(
"output %s of phony edge with no inputs doesn't exist",
237 output->
path().c_str());
247 EXPLAIN(
"output %s doesn't exist", output->
path().c_str());
252 if (most_recent_input && output->
mtime() < most_recent_input->
mtime()) {
259 bool used_restat =
false;
261 (entry = build_log()->LookupByOutput(output->
path()))) {
262 output_mtime = entry->
mtime;
266 if (output_mtime < most_recent_input->mtime()) {
267 EXPLAIN(
"%soutput %s older than most recent input %s " 269 used_restat ?
"restat of " :
"", output->
path().c_str(),
270 most_recent_input->
path().c_str(),
271 output_mtime, most_recent_input->
mtime());
278 if (entry || (entry = build_log()->LookupByOutput(output->
path()))) {
284 EXPLAIN(
"command line changed for %s", output->
path().c_str());
287 if (most_recent_input && entry->
mtime < most_recent_input->
mtime()) {
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(),
298 if (!entry && !generator) {
299 EXPLAIN(
"command line not found in log for %s", output->
path().c_str());
308 return dyndep_loader_.LoadDyndeps(node, err);
313 return dyndep_loader_.LoadDyndeps(node, ddf, err);
317 for (vector<Node*>::const_iterator i = inputs_.begin();
318 i != inputs_.end(); ++i) {
319 if ((*i)->in_edge() && !(*i)->in_edge()->outputs_ready())
330 : edge_(edge), escape_in_out_(escape), recursive_(false) {}
331 virtual string LookupVariable(
const string& var);
335 std::string MakePathList(
const Node*
const* span,
size_t size,
char sep)
const;
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,
351 return MakePathList(&edge_->inputs_[0], explicit_deps_count,
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,
' ');
360 vector<string>::const_iterator it;
361 if ((it = find(lookups_.begin(), lookups_.end(), var)) != lookups_.end()) {
363 for (; it != lookups_.end(); ++it)
364 cycle.append(*it +
" -> ");
366 Fatal((
"cycle in rule variables: " + cycle).c_str());
371 const EvalString* eval = edge_->rule_->GetBinding(var);
372 if (recursive_ && eval)
373 lookups_.push_back(var);
378 return edge_->env_->LookupWithFallback(var, eval,
this);
382 const size_t size,
const char sep)
const {
384 for (
const Node*
const* i = span; i != span + size; ++i) {
386 result.push_back(sep);
387 const string& path = (*i)->PathDecanonicalized();
388 if (escape_in_out_ == kShellEscape) {
402 string command = GetBinding(
"command");
404 string rspfile_content = GetBinding(
"rspfile_content");
405 if (!rspfile_content.empty())
406 command +=
";rspfile=" + rspfile_content;
417 return !GetBinding(key).empty();
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());
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());
447 if (!pool_->name().empty()) {
448 printf(
"(in pool '%s')", pool_->name().c_str());
451 printf(
"(null pool?)");
453 printf(
"] 0x%p\n",
this);
468 return is_phony() && outputs_.size() == 1 && implicit_outs_ == 0 &&
474 string result = path;
477 for (
char* c = &result[0]; (c = strchr(c,
'/')) != NULL;) {
478 if (slash_bits & mask)
488 printf(
"%s <%s 0x%p> mtime: %" PRId64 "%s, (:%s), ",
489 prefix, path().c_str(),
this,
490 mtime(), mtime() ?
"" :
" (:missing)",
491 dirty() ?
" dirty" :
" clean");
493 in_edge()->Dump(
"in-edge: ");
495 printf(
"no in-edge\n");
497 printf(
" out edges:\n");
498 for (vector<Edge*>::const_iterator e = out_edges().begin();
499 e != out_edges().end() && *e != NULL; ++e) {
506 if (!deps_type.empty())
507 return LoadDepsFromLog(edge, err);
510 if (!depfile.empty())
511 return LoadDepFile(edge, depfile, err);
518 matches(std::vector<StringPiece>::iterator i) : i_(i) {}
525 std::vector<StringPiece>::iterator
i_;
533 switch (disk_interface_->ReadFile(path, &content, err)) {
540 *err =
"loading '" + path +
"': " + *err;
544 if (content.empty()) {
545 EXPLAIN(
"depfile '%s' is missing", path.c_str());
550 ? *depfile_parser_options_
553 if (!depfile.
Parse(&content, &depfile_err)) {
554 *err = path +
": " + depfile_err;
558 if (depfile.
outs_.empty()) {
559 *err = path +
": no outputs declared";
564 std::vector<StringPiece>::iterator primary_out = depfile.
outs_.begin();
566 &primary_out->len_, &unused, err)) {
567 *err = path +
": " + *err;
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());
582 for (std::vector<StringPiece>::iterator o = depfile.
outs_.begin();
583 o != depfile.
outs_.end(); ++o) {
586 *err = path +
": depfile mentions '" + o->AsString() +
"' as an output, but no such output was declared";
592 vector<Node*>::iterator implicit_dep =
593 PreallocateSpace(edge, depfile.
ins_.size());
596 for (vector<StringPiece>::iterator i = depfile.
ins_.begin();
597 i != depfile.
ins_.end(); ++i, ++implicit_dep) {
603 Node* node = state_->GetNode(*i, slash_bits);
604 *implicit_dep = node;
606 CreatePhonyInEdge(node);
615 DepsLog::Deps* deps = deps_log_ ? deps_log_->GetDeps(output) : NULL;
617 EXPLAIN(
"deps for '%s' are missing", output->
path().c_str());
628 vector<Node*>::iterator implicit_dep =
630 for (
int i = 0; i < deps->
node_count; ++i, ++implicit_dep) {
632 *implicit_dep = node;
634 CreatePhonyInEdge(node);
653 phony_edge->
outputs_.push_back(node);
bool dyndep_pending() const
An Env for an Edge, providing $in and $out.
bool Stat(DiskInterface *disk_interface, std::string *err)
Return false on error.
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.
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.
void Dump(const char *prefix="") const
Store data loaded from one dyndep file.
void Dump(const char *prefix="") const
Parser for the dependency information emitted by gcc's -M flags.
bool CanonicalizePath(string *path, uint64_t *slash_bits, string *err)
void GetWin32EscapedString(const string &input, string *result)
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|.
StringPiece represents a slice of a string whose memory is managed externally.
void set_dirty(bool dirty)
Information about a node in the dependency graph: the file, whether it's dirty, mtime, etc.
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)
bool outputs_ready() const
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 ...
virtual string LookupVariable(const string &var)
Interface for accessing the disk.
bool StatIfNecessary(DiskInterface *disk_interface, std::string *err)
Return false on error.
bool LoadDyndeps(Node *node, std::string *err) const
Load a dyndep file from the given node's path and update the build graph with the new information...
std::vector< Node * > outputs_
void AddOutEdge(Edge *edge)
bool LoadDepsFromLog(Edge *edge, std::string *err)
Load implicit dependencies for edge from the DepsLog.
An edge in the dependency graph; links between Nodes using Rules.
bool LoadDepFile(Edge *edge, const std::string &path, std::string *err)
Load implicit dependencies for edge from a depfile attribute.
std::string PathDecanonicalized() const
Get |path()| but use slash_bits to convert back to original slash styles.
std::vector< StringPiece > outs_
bool is_order_only(size_t index)
const std::string & path() const
vector< string > lookups_
EscapeKind escape_in_out_
std::vector< StringPiece > ins_
std::string GetUnescapedRspfile() const
Like GetBinding("rspfile"), but without shell escaping.
bool VerifyDAG(Node *node, std::vector< Node *> *stack, std::string *err)
void CreatePhonyInEdge(Node *node)
If we don't have a edge that generates this input already, create one; this makes us not abort if the...
bool LoadDeps(Edge *edge, std::string *err)
Load implicit dependencies for edge.
#define METRIC_RECORD(name)
The primary interface to metrics.
std::vector< Node * > inputs_
std::string GetUnescapedDepfile() const
Like GetBinding("depfile"), but without shell escaping.
bool status_known() const
std::vector< StringPiece >::iterator i_
EdgeEnv(const Edge *const edge, const EscapeKind escape)
std::string GetBinding(const std::string &key) const
Returns the shell-escaped value of |key|.
void Fatal(const char *msg,...)
Log a fatal message and exit.
static uint64_t HashCommand(StringPiece command)
bool operator()(const Node *node) const
std::string EvaluateCommand(bool incl_rsp_file=false) const
Expand all variables in a command and return it as a string.
bool AllInputsReady() const
Return true if all inputs' in-edges are ready.
bool maybe_phonycycle_diagnostic() const
void set_in_edge(Edge *edge)
unsigned long long uint64_t
matches(std::vector< StringPiece >::iterator i)
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
A tokenized string that contains variable references.
An interface for a scope for variable (e.g. "$foo") lookups.
std::string GetUnescapedDyndep() const
Like GetBinding("dyndep"), but without shell escaping.
static const Rule kPhonyRule