41 map<string, EvalString>::const_iterator i = bindings_.find(key);
42 if (i == bindings_.end())
49 return var ==
"command" ||
51 var ==
"description" ||
57 var ==
"rspfile_content";
65 if (!dep_loader_.LoadDeps(edge, err)) {
73 Node* most_recent_input = NULL;
74 for (vector<Node*>::iterator i = edge->
inputs_.begin();
75 i != edge->
inputs_.end(); ++i) {
76 if ((*i)->StatIfNecessary(disk_interface_)) {
78 if (!RecomputeDirty(
in_edge, err))
83 EXPLAIN(
"%s has no in-edge and is missing", (*i)->path().c_str());
84 (*i)->set_dirty(!(*i)->exists());
98 EXPLAIN(
"%s is dirty", (*i)->path().c_str());
101 if (!most_recent_input || (*i)->
mtime() > most_recent_input->
mtime()) {
102 most_recent_input = *i;
111 dirty = RecomputeOutputsDirty(edge, most_recent_input);
115 for (vector<Node*>::iterator i = edge->
outputs_.begin();
117 (*i)->StatIfNecessary(disk_interface_);
134 Node* most_recent_input) {
136 for (vector<Node*>::iterator i = edge->
outputs_.begin();
138 (*i)->StatIfNecessary(disk_interface_);
139 if (RecomputeOutputDirty(edge, most_recent_input, command, *i))
146 Node* most_recent_input,
147 const string& command,
159 EXPLAIN(
"output %s doesn't exist", output->
path().c_str());
164 if (most_recent_input && output->
mtime() < most_recent_input->
mtime()) {
171 bool used_restat =
false;
173 (entry = build_log()->LookupByOutput(output->
path()))) {
178 if (output_mtime < most_recent_input->
mtime()) {
179 EXPLAIN(
"%soutput %s older than most recent input %s " 181 used_restat ?
"restat of " :
"", output->
path().c_str(),
182 most_recent_input->
path().c_str(),
183 output_mtime, most_recent_input->
mtime());
192 if (entry || (entry = build_log()->LookupByOutput(output->
path()))) {
194 EXPLAIN(
"command line changed for %s", output->
path().c_str());
199 EXPLAIN(
"command line not found in log for %s", output->
path().c_str());
208 for (vector<Node*>::const_iterator i = inputs_.begin();
209 i != inputs_.end(); ++i) {
210 if ((*i)->in_edge() && !(*i)->in_edge()->outputs_ready())
221 : edge_(edge), escape_in_out_(escape) {}
222 virtual string LookupVariable(
const string& var);
226 string MakePathList(vector<Node*>::iterator begin,
227 vector<Node*>::iterator end,
235 if (var ==
"in" || var ==
"in_newline") {
236 int explicit_deps_count = edge_->inputs_.size() - edge_->implicit_deps_ -
237 edge_->order_only_deps_;
238 return MakePathList(edge_->inputs_.begin(),
239 edge_->inputs_.begin() + explicit_deps_count,
240 var ==
"in" ?
' ' :
'\n');
241 }
else if (var ==
"out") {
242 return MakePathList(edge_->outputs_.begin(),
243 edge_->outputs_.end(),
248 const EvalString* eval = edge_->rule_->GetBinding(var);
249 return edge_->env_->LookupWithFallback(var, eval,
this);
253 vector<Node*>::iterator end,
256 for (vector<Node*>::iterator i = begin; i != end; ++i) {
258 result.push_back(sep);
259 const string&
path = (*i)->path();
260 if (escape_in_out_ == kShellEscape) {
274 string command = GetBinding(
"command");
276 string rspfile_content = GetBinding(
"rspfile_content");
277 if (!rspfile_content.empty())
278 command +=
";rspfile=" + rspfile_content;
289 return !GetBinding(key).empty();
303 printf(
"%s[ ", prefix);
304 for (vector<Node*>::const_iterator i = inputs_.begin();
305 i != inputs_.end() && *i != NULL; ++i) {
306 printf(
"%s ", (*i)->path().c_str());
308 printf(
"--%s-> ", rule_->name().c_str());
309 for (vector<Node*>::const_iterator i = outputs_.begin();
310 i != outputs_.end() && *i != NULL; ++i) {
311 printf(
"%s ", (*i)->path().c_str());
314 if (!pool_->name().empty()) {
315 printf(
"(in pool '%s')", pool_->name().c_str());
318 printf(
"(null pool?)");
320 printf(
"] 0x%p\n",
this);
332 printf(
"%s <%s 0x%p> mtime: %d%s, (:%s), ",
333 prefix,
path().c_str(),
this,
335 dirty() ?
" dirty" :
" clean");
339 printf(
"no in-edge\n");
341 printf(
" out edges:\n");
342 for (vector<Edge*>::const_iterator e =
out_edges().begin();
343 e !=
out_edges().end() && *e != NULL; ++e) {
350 if (!deps_type.empty())
351 return LoadDepsFromLog(edge, err);
354 if (!depfile.empty())
355 return LoadDepFile(edge, depfile, err);
364 string content = disk_interface_->ReadFile(path, err);
366 *err =
"loading '" + path +
"': " + *err;
370 if (content.empty()) {
371 EXPLAIN(
"depfile '%s' is missing", path.c_str());
377 if (!depfile.
Parse(&content, &depfile_err)) {
378 *err = path +
": " + depfile_err;
385 if (opath != depfile.
out_) {
386 *err =
"expected depfile '" + path +
"' to mention '" +
392 vector<Node*>::iterator implicit_dep =
393 PreallocateSpace(edge, depfile.
ins_.size());
396 for (vector<StringPiece>::iterator i = depfile.
ins_.begin();
397 i != depfile.
ins_.end(); ++i, ++implicit_dep) {
401 Node* node = state_->GetNode(*i);
402 *implicit_dep = node;
404 CreatePhonyInEdge(node);
415 EXPLAIN(
"deps for '%s' are missing", output->
path().c_str());
421 EXPLAIN(
"stored deps info out of date for for '%s' (%d vs %d)",
426 vector<Node*>::iterator implicit_dep =
428 for (
int i = 0; i < deps->
node_count; ++i, ++implicit_dep) {
430 *implicit_dep = node;
432 CreatePhonyInEdge(node);
451 phony_edge->
outputs_.push_back(node);
An Env for an Edge, providing $in and $out.
void Dump(const char *prefix="") const
static bool IsReservedBinding(const string &var)
bool LoadDeps(Edge *edge, string *err)
Load implicit dependencies for edge.
bool RecomputeOutputDirty(Edge *edge, Node *most_recent_input, const string &command, Node *output)
Recompute whether a given single output should be marked dirty.
Parser for the dependency information emitted by gcc's -M flags.
void GetWin32EscapedString(const string &input, string *result)
bool RecomputeDirty(Edge *edge, string *err)
Examine inputs, outputs, and command lines to judge whether an edge needs to be re-run, and update outputs_ready_ and each outputs' |dirty_| state accordingly.
StringPiece represents a slice of a string whose memory is managed externally.
string GetUnescapedRspfile()
Like GetBinding("rspfile"), but without shell escaping.
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 ...
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.
virtual string LookupVariable(const string &var)
Interface for accessing the disk.
bool RecomputeOutputsDirty(Edge *edge, Node *most_recent_input)
Recompute whether any output of the edge is dirty.
bool GetBindingBool(const string &key)
string AsString() const
Convert the slice into a full-fledged std::string, copying the data into a new string.
void Dump(const char *prefix="") const
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 is_order_only(size_t index)
EscapeKind escape_in_out_
bool CanonicalizePath(string *path, string *err)
Canonicalize a path like "foo/../bar.h" into just "bar.h".
const EvalString * GetBinding(const string &key) const
bool Stat(DiskInterface *disk_interface)
Return true if the file exists (mtime_ got a value).
bool LoadDepFile(Edge *edge, const string &path, string *err)
Load implicit dependencies for edge from a depfile attribute.
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.
const string & path() const
void AddBinding(const string &key, const EvalString &val)
string GetBinding(const string &key)
Returns the shell-escaped value of |key|.
static uint64_t HashCommand(StringPiece command)
bool LoadDepsFromLog(Edge *edge, string *err)
Load implicit dependencies for edge from the DepsLog.
void set_in_edge(Edge *edge)
bool AllInputsReady() const
Return true if all inputs' in-edges are ready.
string GetUnescapedDepfile()
Like GetBinding("depfile"), but without shell escaping.
virtual TimeStamp Stat(const string &path) const =0
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
EdgeEnv(Edge *edge, EscapeKind escape)
A tokenized string that contains variable references.
An interface for a scope for variable (e.g. "$foo") lookups.
const vector< Edge * > & out_edges() const
static const Rule kPhonyRule
vector< Node * > outputs_