50 EXPLAIN(
"%s has no in-edge and is missing", node->
path().c_str());
65 stack->push_back(node);
72 for (vector<Node*>::iterator o = edge->
outputs_.begin();
87 Node* most_recent_input = NULL;
88 for (vector<Node*>::iterator i = edge->
inputs_.begin();
89 i != edge->
inputs_.end(); ++i) {
95 if (
Edge* in_edge = (*i)->in_edge()) {
96 if (!in_edge->outputs_ready_)
104 EXPLAIN(
"%s is dirty", (*i)->path().c_str());
107 if (!most_recent_input || (*i)->
mtime() > most_recent_input->
mtime()) {
108 most_recent_input = *i;
121 for (vector<Node*>::iterator o = edge->
outputs_.begin();
138 assert(stack->back() == node);
146 assert(edge != NULL);
153 vector<Node*>::iterator start = stack->begin();
154 while (start != stack->end() && (*start)->in_edge() != edge)
156 assert(start != stack->end());
167 *err =
"dependency cycle: ";
168 for (vector<Node*>::const_iterator i = start; i != stack->end(); ++i) {
169 err->append((*i)->path());
172 err->append((*start)->path());
177 err->append(
" [-w phonycycle=err]");
184 bool* outputs_dirty,
string* err) {
186 for (vector<Node*>::iterator o = edge->
outputs_.begin();
189 *outputs_dirty =
true;
197 Node* most_recent_input,
198 const string& command,
204 EXPLAIN(
"output %s of phony edge with no inputs doesn't exist",
205 output->
path().c_str());
215 EXPLAIN(
"output %s doesn't exist", output->
path().c_str());
220 if (most_recent_input && output->
mtime() < most_recent_input->
mtime()) {
227 bool used_restat =
false;
230 output_mtime = entry->
mtime;
234 if (output_mtime < most_recent_input->mtime()) {
235 EXPLAIN(
"%soutput %s older than most recent input %s " 237 used_restat ?
"restat of " :
"", output->
path().c_str(),
238 most_recent_input->
path().c_str(),
239 output_mtime, most_recent_input->
mtime());
246 if (entry || (entry =
build_log()->LookupByOutput(output->
path()))) {
252 EXPLAIN(
"command line changed for %s", output->
path().c_str());
255 if (most_recent_input && entry->
mtime < most_recent_input->
mtime()) {
260 EXPLAIN(
"recorded mtime of %s older than most recent input %s (%" PRId64 " vs %" PRId64 ")",
261 output->
path().c_str(), most_recent_input->
path().c_str(),
266 if (!entry && !generator) {
267 EXPLAIN(
"command line not found in log for %s", output->
path().c_str());
276 for (vector<Node*>::const_iterator i =
inputs_.begin();
278 if ((*i)->in_edge() && !(*i)->in_edge()->outputs_ready())
295 vector<Node*>::iterator end,
306 if (var ==
"in" || var ==
"in_newline") {
311 var ==
"in" ?
' ' :
'\n');
312 }
else if (var ==
"out") {
320 vector<string>::const_iterator it;
324 cycle.append(*it +
" -> ");
326 Fatal((
"cycle in rule variables: " + cycle).c_str());
342 vector<Node*>::iterator end,
345 for (vector<Node*>::iterator i = begin; i != end; ++i) {
347 result.push_back(sep);
348 const string& path = (*i)->PathDecanonicalized();
365 string rspfile_content =
GetBinding(
"rspfile_content");
366 if (!rspfile_content.empty())
367 command +=
";rspfile=" + rspfile_content;
392 printf(
"%s[ ", prefix);
393 for (vector<Node*>::const_iterator i =
inputs_.begin();
394 i !=
inputs_.end() && *i != NULL; ++i) {
395 printf(
"%s ", (*i)->path().c_str());
397 printf(
"--%s-> ",
rule_->
name().c_str());
398 for (vector<Node*>::const_iterator i =
outputs_.begin();
399 i !=
outputs_.end() && *i != NULL; ++i) {
400 printf(
"%s ", (*i)->path().c_str());
404 printf(
"(in pool '%s')",
pool_->
name().c_str());
407 printf(
"(null pool?)");
409 printf(
"] 0x%p\n",
this);
430 string result =
path;
433 for (
char* c = &result[0]; (c = strchr(c,
'/')) != NULL;) {
444 printf(
"%s <%s 0x%p> mtime: %" PRId64 "%s, (:%s), ",
445 prefix,
path().c_str(),
this,
447 dirty() ?
" dirty" :
" clean");
451 printf(
"no in-edge\n");
453 printf(
" out edges:\n");
454 for (vector<Edge*>::const_iterator e =
out_edges().begin();
455 e !=
out_edges().end() && *e != NULL; ++e) {
462 if (!deps_type.empty())
466 if (!depfile.empty())
485 *err =
"loading '" + path +
"': " + *err;
489 if (content.empty()) {
490 EXPLAIN(
"depfile '%s' is missing", path.c_str());
498 if (!depfile.
Parse(&content, &depfile_err)) {
499 *err = path +
": " + depfile_err;
505 &depfile.
out_.
len_, &unused, err)) {
506 *err = path +
": " + *err;
514 if (opath != depfile.
out_) {
515 EXPLAIN(
"expected depfile '%s' to mention '%s', got '%s'", path.c_str(),
521 vector<Node*>::iterator implicit_dep =
525 for (vector<StringPiece>::iterator i = depfile.
ins_.begin();
526 i != depfile.
ins_.end(); ++i, ++implicit_dep) {
533 *implicit_dep = node;
546 EXPLAIN(
"deps for '%s' are missing", output->
path().c_str());
557 vector<Node*>::iterator implicit_dep =
559 for (
int i = 0; i < deps->
node_count; ++i, ++implicit_dep) {
561 *implicit_dep = node;
582 phony_edge->
outputs_.push_back(node);
An Env for an Edge, providing $in and $out.
bool LoadDeps(Edge *edge, string *err)
Load implicit dependencies for edge.
const vector< Edge * > & out_edges() const
void Dump(const char *prefix="") const
const string & path() const
bool RecomputeOutputDirty(Edge *edge, Node *most_recent_input, const string &command, Node *output)
Recompute whether a given single output should be marked dirty.
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)
Canonicalize a path like "foo/../bar.h" into just "bar.h".
Node * GetNode(StringPiece path, uint64_t slash_bits)
DepfileParserOptions const * depfile_parser_options_
void GetWin32EscapedString(const string &input, string *result)
StringPiece represents a slice of a string whose memory is managed externally.
string GetUnescapedRspfile()
Like GetBinding("rspfile"), but without shell escaping.
void set_dirty(bool dirty)
Information about a node in the dependency graph: the file, whether it's dirty, mtime, etc.
bool Parse(string *content, string *err)
Parse an input file.
void GetShellEscapedString(const string &input, string *result)
Appends |input| to |*result|, escaping according to the whims of either Bash, or Win32's CommandLineT...
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)
ImplicitDepLoader dep_loader_
Interface for accessing the disk.
uint64_t slash_bits() const
bool GetBindingBool(const string &key)
void AddOutEdge(Edge *edge)
An edge in the dependency graph; links between Nodes using Rules.
string EvaluateCommand(bool incl_rsp_file=false)
Expand all variables in a command and return it as a string.
bool RecomputeOutputsDirty(Edge *edge, Node *most_recent_input, bool *dirty, string *err)
Recompute whether any output of the edge is dirty, if so sets |*dirty|.
bool is_order_only(size_t index)
vector< string > lookups_
EscapeKind escape_in_out_
Edge * AddEdge(const Rule *rule)
bool VerifyDAG(Node *node, vector< Node *> *stack, string *err)
const string & name() const
bool LoadDepFile(Edge *edge, const string &path, string *err)
Load implicit dependencies for edge from a depfile attribute.
DiskInterface * disk_interface_
string MakePathList(vector< Node *>::iterator begin, vector< Node *>::iterator end, char sep)
Given a span of Nodes, construct a list of paths suitable for a command line.
Deps * GetDeps(Node *node)
string PathDecanonicalized() const
Get |path()| but use slash_bits to convert back to original slash styles.
BuildLog * build_log() const
virtual TimeStamp Stat(const string &path, string *err) const =0
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
string LookupWithFallback(const string &var, const EvalString *eval, Env *env)
This is tricky.
const EvalString * GetBinding(const string &key) const
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...
vector< StringPiece > ins_
TimeStamp mtime_
Possible values of mtime_: -1: file hasn't been examined 0: we looked, and file doesn't exist >0: act...
#define METRIC_RECORD(name)
The primary interface to metrics.
virtual Status ReadFile(const string &path, string *contents, string *err)=0
Read and store in given string.
bool status_known() const
void Fatal(const char *msg,...)
Log a fatal message and exit.
string GetBinding(const string &key)
Returns the shell-escaped value of |key|.
static uint64_t HashCommand(StringPiece command)
LogEntry * LookupByOutput(const string &path)
Lookup a previously-run command by its output path.
bool LoadDepsFromLog(Edge *edge, string *err)
Load implicit dependencies for edge from the DepsLog.
const string & name() const
bool Stat(DiskInterface *disk_interface, string *err)
Return false on error.
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
DiskInterface * disk_interface_
string GetUnescapedDepfile()
Like GetBinding("depfile"), but without shell escaping.
bool RecomputeDirty(Node *node, string *err)
Update the |dirty_| state of the given node by inspecting its input edge.
EdgeEnv(Edge *edge, EscapeKind escape)
A tokenized string that contains variable references.
An interface for a scope for variable (e.g. "$foo") lookups.
string AsString() const
Convert the slice into a full-fledged std::string, copying the data into a new string.
bool StatIfNecessary(DiskInterface *disk_interface, string *err)
Return false on error.
static const Rule kPhonyRule
vector< Node * > outputs_