Line | Count | Source (jump to first uncovered line) |
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 <deque> |
19 | | #include <assert.h> |
20 | | #include <stdio.h> |
21 | | |
22 | | #include "build_log.h" |
23 | | #include "debug_flags.h" |
24 | | #include "depfile_parser.h" |
25 | | #include "deps_log.h" |
26 | | #include "disk_interface.h" |
27 | | #include "manifest_parser.h" |
28 | | #include "metrics.h" |
29 | | #include "state.h" |
30 | | #include "util.h" |
31 | | |
32 | | using namespace std; |
33 | | |
34 | 0 | bool Node::Stat(DiskInterface* disk_interface, string* err) { |
35 | 0 | METRIC_RECORD("node stat"); |
36 | 0 | mtime_ = disk_interface->Stat(path_, err); |
37 | 0 | if (mtime_ == -1) { |
38 | 0 | return false; |
39 | 0 | } |
40 | 0 | exists_ = (mtime_ != 0) ? ExistenceStatusExists : ExistenceStatusMissing; |
41 | 0 | return true; |
42 | 0 | } |
43 | | |
44 | 0 | void Node::UpdatePhonyMtime(TimeStamp mtime) { |
45 | 0 | if (!exists()) { |
46 | 0 | mtime_ = std::max(mtime_, mtime); |
47 | 0 | } |
48 | 0 | } |
49 | | |
50 | | bool DependencyScan::RecomputeDirty(Node* initial_node, |
51 | | std::vector<Node*>* validation_nodes, |
52 | 0 | string* err) { |
53 | 0 | std::vector<Node*> stack; |
54 | 0 | std::vector<Node*> new_validation_nodes; |
55 | |
|
56 | 0 | std::deque<Node*> nodes(1, initial_node); |
57 | | |
58 | | // RecomputeNodeDirty might return new validation nodes that need to be |
59 | | // checked for dirty state, keep a queue of nodes to visit. |
60 | 0 | while (!nodes.empty()) { |
61 | 0 | Node* node = nodes.front(); |
62 | 0 | nodes.pop_front(); |
63 | |
|
64 | 0 | stack.clear(); |
65 | 0 | new_validation_nodes.clear(); |
66 | |
|
67 | 0 | if (!RecomputeNodeDirty(node, &stack, &new_validation_nodes, err)) |
68 | 0 | return false; |
69 | 0 | nodes.insert(nodes.end(), new_validation_nodes.begin(), |
70 | 0 | new_validation_nodes.end()); |
71 | 0 | if (!new_validation_nodes.empty()) { |
72 | 0 | assert(validation_nodes && |
73 | 0 | "validations require RecomputeDirty to be called with validation_nodes"); |
74 | 0 | validation_nodes->insert(validation_nodes->end(), |
75 | 0 | new_validation_nodes.begin(), |
76 | 0 | new_validation_nodes.end()); |
77 | 0 | } |
78 | 0 | } |
79 | | |
80 | 0 | return true; |
81 | 0 | } |
82 | | |
83 | | bool DependencyScan::RecomputeNodeDirty(Node* node, std::vector<Node*>* stack, |
84 | | std::vector<Node*>* validation_nodes, |
85 | 0 | string* err) { |
86 | 0 | Edge* edge = node->in_edge(); |
87 | 0 | if (!edge) { |
88 | | // If we already visited this leaf node then we are done. |
89 | 0 | if (node->status_known()) |
90 | 0 | return true; |
91 | | // This node has no in-edge; it is dirty if it is missing. |
92 | 0 | if (!node->StatIfNecessary(disk_interface_, err)) |
93 | 0 | return false; |
94 | 0 | if (!node->exists()) |
95 | 0 | EXPLAIN("%s has no in-edge and is missing", node->path().c_str()); |
96 | 0 | node->set_dirty(!node->exists()); |
97 | 0 | return true; |
98 | 0 | } |
99 | | |
100 | | // If we already finished this edge then we are done. |
101 | 0 | if (edge->mark_ == Edge::VisitDone) |
102 | 0 | return true; |
103 | | |
104 | | // If we encountered this edge earlier in the call stack we have a cycle. |
105 | 0 | if (!VerifyDAG(node, stack, err)) |
106 | 0 | return false; |
107 | | |
108 | | // Mark the edge temporarily while in the call stack. |
109 | 0 | edge->mark_ = Edge::VisitInStack; |
110 | 0 | stack->push_back(node); |
111 | |
|
112 | 0 | bool dirty = false; |
113 | 0 | edge->outputs_ready_ = true; |
114 | 0 | edge->deps_missing_ = false; |
115 | |
|
116 | 0 | if (!edge->deps_loaded_) { |
117 | | // This is our first encounter with this edge. |
118 | | // If there is a pending dyndep file, visit it now: |
119 | | // * If the dyndep file is ready then load it now to get any |
120 | | // additional inputs and outputs for this and other edges. |
121 | | // Once the dyndep file is loaded it will no longer be pending |
122 | | // if any other edges encounter it, but they will already have |
123 | | // been updated. |
124 | | // * If the dyndep file is not ready then since is known to be an |
125 | | // input to this edge, the edge will not be considered ready below. |
126 | | // Later during the build the dyndep file will become ready and be |
127 | | // loaded to update this edge before it can possibly be scheduled. |
128 | 0 | if (edge->dyndep_ && edge->dyndep_->dyndep_pending()) { |
129 | 0 | if (!RecomputeNodeDirty(edge->dyndep_, stack, validation_nodes, err)) |
130 | 0 | return false; |
131 | | |
132 | 0 | if (!edge->dyndep_->in_edge() || |
133 | 0 | edge->dyndep_->in_edge()->outputs_ready()) { |
134 | | // The dyndep file is ready, so load it now. |
135 | 0 | if (!LoadDyndeps(edge->dyndep_, err)) |
136 | 0 | return false; |
137 | 0 | } |
138 | 0 | } |
139 | 0 | } |
140 | | |
141 | | // Load output mtimes so we can compare them to the most recent input below. |
142 | 0 | for (vector<Node*>::iterator o = edge->outputs_.begin(); |
143 | 0 | o != edge->outputs_.end(); ++o) { |
144 | 0 | if (!(*o)->StatIfNecessary(disk_interface_, err)) |
145 | 0 | return false; |
146 | 0 | } |
147 | | |
148 | 0 | if (!edge->deps_loaded_) { |
149 | | // This is our first encounter with this edge. Load discovered deps. |
150 | 0 | edge->deps_loaded_ = true; |
151 | 0 | if (!dep_loader_.LoadDeps(edge, err)) { |
152 | 0 | if (!err->empty()) |
153 | 0 | return false; |
154 | | // Failed to load dependency info: rebuild to regenerate it. |
155 | | // LoadDeps() did EXPLAIN() already, no need to do it here. |
156 | 0 | dirty = edge->deps_missing_ = true; |
157 | 0 | } |
158 | 0 | } |
159 | | |
160 | | // Store any validation nodes from the edge for adding to the initial |
161 | | // nodes. Don't recurse into them, that would trigger the dependency |
162 | | // cycle detector if the validation node depends on this node. |
163 | | // RecomputeDirty will add the validation nodes to the initial nodes |
164 | | // and recurse into them. |
165 | 0 | validation_nodes->insert(validation_nodes->end(), |
166 | 0 | edge->validations_.begin(), edge->validations_.end()); |
167 | | |
168 | | // Visit all inputs; we're dirty if any of the inputs are dirty. |
169 | 0 | Node* most_recent_input = NULL; |
170 | 0 | for (vector<Node*>::iterator i = edge->inputs_.begin(); |
171 | 0 | i != edge->inputs_.end(); ++i) { |
172 | | // Visit this input. |
173 | 0 | if (!RecomputeNodeDirty(*i, stack, validation_nodes, err)) |
174 | 0 | return false; |
175 | | |
176 | | // If an input is not ready, neither are our outputs. |
177 | 0 | if (Edge* in_edge = (*i)->in_edge()) { |
178 | 0 | if (!in_edge->outputs_ready_) |
179 | 0 | edge->outputs_ready_ = false; |
180 | 0 | } |
181 | |
|
182 | 0 | if (!edge->is_order_only(i - edge->inputs_.begin())) { |
183 | | // If a regular input is dirty (or missing), we're dirty. |
184 | | // Otherwise consider mtime. |
185 | 0 | if ((*i)->dirty()) { |
186 | 0 | EXPLAIN("%s is dirty", (*i)->path().c_str()); |
187 | 0 | dirty = true; |
188 | 0 | } else { |
189 | 0 | if (!most_recent_input || (*i)->mtime() > most_recent_input->mtime()) { |
190 | 0 | most_recent_input = *i; |
191 | 0 | } |
192 | 0 | } |
193 | 0 | } |
194 | 0 | } |
195 | | |
196 | | // We may also be dirty due to output state: missing outputs, out of |
197 | | // date outputs, etc. Visit all outputs and determine whether they're dirty. |
198 | 0 | if (!dirty) |
199 | 0 | if (!RecomputeOutputsDirty(edge, most_recent_input, &dirty, err)) |
200 | 0 | return false; |
201 | | |
202 | | // Finally, visit each output and update their dirty state if necessary. |
203 | 0 | for (vector<Node*>::iterator o = edge->outputs_.begin(); |
204 | 0 | o != edge->outputs_.end(); ++o) { |
205 | 0 | if (dirty) |
206 | 0 | (*o)->MarkDirty(); |
207 | 0 | } |
208 | | |
209 | | // If an edge is dirty, its outputs are normally not ready. (It's |
210 | | // possible to be clean but still not be ready in the presence of |
211 | | // order-only inputs.) |
212 | | // But phony edges with no inputs have nothing to do, so are always |
213 | | // ready. |
214 | 0 | if (dirty && !(edge->is_phony() && edge->inputs_.empty())) |
215 | 0 | edge->outputs_ready_ = false; |
216 | | |
217 | | // Mark the edge as finished during this walk now that it will no longer |
218 | | // be in the call stack. |
219 | 0 | edge->mark_ = Edge::VisitDone; |
220 | 0 | assert(stack->back() == node); |
221 | 0 | stack->pop_back(); |
222 | |
|
223 | 0 | return true; |
224 | 0 | } |
225 | | |
226 | 0 | bool DependencyScan::VerifyDAG(Node* node, vector<Node*>* stack, string* err) { |
227 | 0 | Edge* edge = node->in_edge(); |
228 | 0 | assert(edge != NULL); |
229 | | |
230 | | // If we have no temporary mark on the edge then we do not yet have a cycle. |
231 | 0 | if (edge->mark_ != Edge::VisitInStack) |
232 | 0 | return true; |
233 | | |
234 | | // We have this edge earlier in the call stack. Find it. |
235 | 0 | vector<Node*>::iterator start = stack->begin(); |
236 | 0 | while (start != stack->end() && (*start)->in_edge() != edge) |
237 | 0 | ++start; |
238 | 0 | assert(start != stack->end()); |
239 | | |
240 | | // Make the cycle clear by reporting its start as the node at its end |
241 | | // instead of some other output of the starting edge. For example, |
242 | | // running 'ninja b' on |
243 | | // build a b: cat c |
244 | | // build c: cat a |
245 | | // should report a -> c -> a instead of b -> c -> a. |
246 | 0 | *start = node; |
247 | | |
248 | | // Construct the error message rejecting the cycle. |
249 | 0 | *err = "dependency cycle: "; |
250 | 0 | for (vector<Node*>::const_iterator i = start; i != stack->end(); ++i) { |
251 | 0 | err->append((*i)->path()); |
252 | 0 | err->append(" -> "); |
253 | 0 | } |
254 | 0 | err->append((*start)->path()); |
255 | |
|
256 | 0 | if ((start + 1) == stack->end() && edge->maybe_phonycycle_diagnostic()) { |
257 | | // The manifest parser would have filtered out the self-referencing |
258 | | // input if it were not configured to allow the error. |
259 | 0 | err->append(" [-w phonycycle=err]"); |
260 | 0 | } |
261 | |
|
262 | 0 | return false; |
263 | 0 | } |
264 | | |
265 | | bool DependencyScan::RecomputeOutputsDirty(Edge* edge, Node* most_recent_input, |
266 | 0 | bool* outputs_dirty, string* err) { |
267 | 0 | string command = edge->EvaluateCommand(/*incl_rsp_file=*/true); |
268 | 0 | for (vector<Node*>::iterator o = edge->outputs_.begin(); |
269 | 0 | o != edge->outputs_.end(); ++o) { |
270 | 0 | if (RecomputeOutputDirty(edge, most_recent_input, command, *o)) { |
271 | 0 | *outputs_dirty = true; |
272 | 0 | return true; |
273 | 0 | } |
274 | 0 | } |
275 | 0 | return true; |
276 | 0 | } |
277 | | |
278 | | bool DependencyScan::RecomputeOutputDirty(const Edge* edge, |
279 | | const Node* most_recent_input, |
280 | | const string& command, |
281 | 0 | Node* output) { |
282 | 0 | if (edge->is_phony()) { |
283 | | // Phony edges don't write any output. Outputs are only dirty if |
284 | | // there are no inputs and we're missing the output. |
285 | 0 | if (edge->inputs_.empty() && !output->exists()) { |
286 | 0 | EXPLAIN("output %s of phony edge with no inputs doesn't exist", |
287 | 0 | output->path().c_str()); |
288 | 0 | return true; |
289 | 0 | } |
290 | | |
291 | | // Update the mtime with the newest input. Dependents can thus call mtime() |
292 | | // on the fake node and get the latest mtime of the dependencies |
293 | 0 | if (most_recent_input) { |
294 | 0 | output->UpdatePhonyMtime(most_recent_input->mtime()); |
295 | 0 | } |
296 | | |
297 | | // Phony edges are clean, nothing to do |
298 | 0 | return false; |
299 | 0 | } |
300 | | |
301 | | // Dirty if we're missing the output. |
302 | 0 | if (!output->exists()) { |
303 | 0 | EXPLAIN("output %s doesn't exist", output->path().c_str()); |
304 | 0 | return true; |
305 | 0 | } |
306 | | |
307 | 0 | BuildLog::LogEntry* entry = 0; |
308 | | |
309 | | // If this is a restat rule, we may have cleaned the output in a |
310 | | // previous run and stored the command start time in the build log. |
311 | | // We don't want to consider a restat rule's outputs as dirty unless |
312 | | // an input changed since the last run, so we'll skip checking the |
313 | | // output file's actual mtime and simply check the recorded mtime from |
314 | | // the log against the most recent input's mtime (see below) |
315 | 0 | bool used_restat = false; |
316 | 0 | if (edge->GetBindingBool("restat") && build_log() && |
317 | 0 | (entry = build_log()->LookupByOutput(output->path()))) { |
318 | 0 | used_restat = true; |
319 | 0 | } |
320 | | |
321 | | // Dirty if the output is older than the input. |
322 | 0 | if (!used_restat && most_recent_input && output->mtime() < most_recent_input->mtime()) { |
323 | 0 | EXPLAIN("output %s older than most recent input %s " |
324 | 0 | "(%" PRId64 " vs %" PRId64 ")", |
325 | 0 | output->path().c_str(), |
326 | 0 | most_recent_input->path().c_str(), |
327 | 0 | output->mtime(), most_recent_input->mtime()); |
328 | 0 | return true; |
329 | 0 | } |
330 | | |
331 | 0 | if (build_log()) { |
332 | 0 | bool generator = edge->GetBindingBool("generator"); |
333 | 0 | if (entry || (entry = build_log()->LookupByOutput(output->path()))) { |
334 | 0 | if (!generator && |
335 | 0 | BuildLog::LogEntry::HashCommand(command) != entry->command_hash) { |
336 | | // May also be dirty due to the command changing since the last build. |
337 | | // But if this is a generator rule, the command changing does not make us |
338 | | // dirty. |
339 | 0 | EXPLAIN("command line changed for %s", output->path().c_str()); |
340 | 0 | return true; |
341 | 0 | } |
342 | 0 | if (most_recent_input && entry->mtime < most_recent_input->mtime()) { |
343 | | // May also be dirty due to the mtime in the log being older than the |
344 | | // mtime of the most recent input. This can occur even when the mtime |
345 | | // on disk is newer if a previous run wrote to the output file but |
346 | | // exited with an error or was interrupted. If this was a restat rule, |
347 | | // then we only check the recorded mtime against the most recent input |
348 | | // mtime and ignore the actual output's mtime above. |
349 | 0 | EXPLAIN("recorded mtime of %s older than most recent input %s (%" PRId64 " vs %" PRId64 ")", |
350 | 0 | output->path().c_str(), most_recent_input->path().c_str(), |
351 | 0 | entry->mtime, most_recent_input->mtime()); |
352 | 0 | return true; |
353 | 0 | } |
354 | 0 | } |
355 | 0 | if (!entry && !generator) { |
356 | 0 | EXPLAIN("command line not found in log for %s", output->path().c_str()); |
357 | 0 | return true; |
358 | 0 | } |
359 | 0 | } |
360 | | |
361 | 0 | return false; |
362 | 0 | } |
363 | | |
364 | 0 | bool DependencyScan::LoadDyndeps(Node* node, string* err) const { |
365 | 0 | return dyndep_loader_.LoadDyndeps(node, err); |
366 | 0 | } |
367 | | |
368 | | bool DependencyScan::LoadDyndeps(Node* node, DyndepFile* ddf, |
369 | 0 | string* err) const { |
370 | 0 | return dyndep_loader_.LoadDyndeps(node, ddf, err); |
371 | 0 | } |
372 | | |
373 | 0 | bool Edge::AllInputsReady() const { |
374 | 0 | for (vector<Node*>::const_iterator i = inputs_.begin(); |
375 | 0 | i != inputs_.end(); ++i) { |
376 | 0 | if ((*i)->in_edge() && !(*i)->in_edge()->outputs_ready()) |
377 | 0 | return false; |
378 | 0 | } |
379 | 0 | return true; |
380 | 0 | } |
381 | | |
382 | | /// An Env for an Edge, providing $in and $out. |
383 | | struct EdgeEnv : public Env { |
384 | | enum EscapeKind { kShellEscape, kDoNotEscape }; |
385 | | |
386 | | EdgeEnv(const Edge* const edge, const EscapeKind escape) |
387 | 85 | : edge_(edge), escape_in_out_(escape), recursive_(false) {} |
388 | | virtual string LookupVariable(const string& var); |
389 | | |
390 | | /// Given a span of Nodes, construct a list of paths suitable for a command |
391 | | /// line. |
392 | | std::string MakePathList(const Node* const* span, size_t size, char sep) const; |
393 | | |
394 | | private: |
395 | | std::vector<std::string> lookups_; |
396 | | const Edge* const edge_; |
397 | | EscapeKind escape_in_out_; |
398 | | bool recursive_; |
399 | | }; |
400 | | |
401 | 256 | string EdgeEnv::LookupVariable(const string& var) { |
402 | 256 | if (var == "in" || var == "in_newline") { |
403 | 105 | int explicit_deps_count = edge_->inputs_.size() - edge_->implicit_deps_ - |
404 | 105 | edge_->order_only_deps_; |
405 | 105 | return MakePathList(edge_->inputs_.data(), explicit_deps_count, |
406 | 105 | var == "in" ? ' ' : '\n'); |
407 | 151 | } else if (var == "out") { |
408 | 0 | int explicit_outs_count = edge_->outputs_.size() - edge_->implicit_outs_; |
409 | 0 | return MakePathList(&edge_->outputs_[0], explicit_outs_count, ' '); |
410 | 0 | } |
411 | | |
412 | | // Technical note about the lookups_ vector. |
413 | | // |
414 | | // This is used to detect cycles during recursive variable expansion |
415 | | // which can be seen as a graph traversal problem. Consider the following |
416 | | // example: |
417 | | // |
418 | | // rule something |
419 | | // command = $foo $foo $var1 |
420 | | // var1 = $var2 |
421 | | // var2 = $var3 |
422 | | // var3 = $var1 |
423 | | // foo = FOO |
424 | | // |
425 | | // Each variable definition can be seen as a node in a graph that looks |
426 | | // like the following: |
427 | | // |
428 | | // command --> foo |
429 | | // | |
430 | | // v |
431 | | // var1 <-----. |
432 | | // | | |
433 | | // v | |
434 | | // var2 ---> var3 |
435 | | // |
436 | | // The lookups_ vector is used as a stack of visited nodes/variables |
437 | | // during recursive expansion. Entering a node adds an item to the |
438 | | // stack, leaving the node removes it. |
439 | | // |
440 | | // The recursive_ flag is used as a small performance optimization |
441 | | // to never record the starting node in the stack when beginning a new |
442 | | // expansion, since in most cases, expansions are not recursive |
443 | | // at all. |
444 | | // |
445 | 151 | if (recursive_) { |
446 | 66 | auto it = std::find(lookups_.begin(), lookups_.end(), var); |
447 | 66 | if (it != lookups_.end()) { |
448 | 0 | std::string cycle; |
449 | 0 | for (; it != lookups_.end(); ++it) |
450 | 0 | cycle.append(*it + " -> "); |
451 | 0 | cycle.append(var); |
452 | 0 | Fatal(("cycle in rule variables: " + cycle).c_str()); |
453 | 0 | } |
454 | 66 | } |
455 | | |
456 | | // See notes on BindingEnv::LookupWithFallback. |
457 | 151 | const EvalString* eval = edge_->rule_->GetBinding(var); |
458 | 151 | bool record_varname = recursive_ && eval; |
459 | 151 | if (record_varname) |
460 | 0 | lookups_.push_back(var); |
461 | | |
462 | | // In practice, variables defined on rules never use another rule variable. |
463 | | // For performance, only start checking for cycles after the first lookup. |
464 | 151 | recursive_ = true; |
465 | 151 | std::string result = edge_->env_->LookupWithFallback(var, eval, this); |
466 | 151 | if (record_varname) |
467 | 0 | lookups_.pop_back(); |
468 | 151 | return result; |
469 | 151 | } |
470 | | |
471 | | std::string EdgeEnv::MakePathList(const Node* const* const span, |
472 | 105 | const size_t size, const char sep) const { |
473 | 105 | string result; |
474 | 3.66M | for (const Node* const* i = span; i != span + size; ++i) { |
475 | 3.66M | if (!result.empty()) |
476 | 3.66M | result.push_back(sep); |
477 | 3.66M | const string& path = (*i)->PathDecanonicalized(); |
478 | 3.66M | if (escape_in_out_ == kShellEscape) { |
479 | | #ifdef _WIN32 |
480 | | GetWin32EscapedString(path, &result); |
481 | | #else |
482 | 0 | GetShellEscapedString(path, &result); |
483 | 0 | #endif |
484 | 3.66M | } else { |
485 | 3.66M | result.append(path); |
486 | 3.66M | } |
487 | 3.66M | } |
488 | 105 | return result; |
489 | 105 | } |
490 | | |
491 | | void Edge::CollectInputs(bool shell_escape, |
492 | 0 | std::vector<std::string>* out) const { |
493 | 0 | for (std::vector<Node*>::const_iterator it = inputs_.begin(); |
494 | 0 | it != inputs_.end(); ++it) { |
495 | 0 | std::string path = (*it)->PathDecanonicalized(); |
496 | 0 | if (shell_escape) { |
497 | 0 | std::string unescaped; |
498 | 0 | unescaped.swap(path); |
499 | | #ifdef _WIN32 |
500 | | GetWin32EscapedString(unescaped, &path); |
501 | | #else |
502 | 0 | GetShellEscapedString(unescaped, &path); |
503 | 0 | #endif |
504 | 0 | } |
505 | 0 | #if __cplusplus >= 201103L |
506 | 0 | out->push_back(std::move(path)); |
507 | | #else |
508 | | out->push_back(path); |
509 | | #endif |
510 | 0 | } |
511 | 0 | } |
512 | | |
513 | 0 | std::string Edge::EvaluateCommand(const bool incl_rsp_file) const { |
514 | 0 | string command = GetBinding("command"); |
515 | 0 | if (incl_rsp_file) { |
516 | 0 | string rspfile_content = GetBinding("rspfile_content"); |
517 | 0 | if (!rspfile_content.empty()) |
518 | 0 | command += ";rspfile=" + rspfile_content; |
519 | 0 | } |
520 | 0 | return command; |
521 | 0 | } |
522 | | |
523 | 50 | std::string Edge::GetBinding(const std::string& key) const { |
524 | 50 | EdgeEnv env(this, EdgeEnv::kShellEscape); |
525 | 50 | return env.LookupVariable(key); |
526 | 50 | } |
527 | | |
528 | 0 | bool Edge::GetBindingBool(const string& key) const { |
529 | 0 | return !GetBinding(key).empty(); |
530 | 0 | } |
531 | | |
532 | 0 | string Edge::GetUnescapedDepfile() const { |
533 | 0 | EdgeEnv env(this, EdgeEnv::kDoNotEscape); |
534 | 0 | return env.LookupVariable("depfile"); |
535 | 0 | } |
536 | | |
537 | 35 | string Edge::GetUnescapedDyndep() const { |
538 | 35 | EdgeEnv env(this, EdgeEnv::kDoNotEscape); |
539 | 35 | return env.LookupVariable("dyndep"); |
540 | 35 | } |
541 | | |
542 | 0 | std::string Edge::GetUnescapedRspfile() const { |
543 | 0 | EdgeEnv env(this, EdgeEnv::kDoNotEscape); |
544 | 0 | return env.LookupVariable("rspfile"); |
545 | 0 | } |
546 | | |
547 | 0 | void Edge::Dump(const char* prefix) const { |
548 | 0 | printf("%s[ ", prefix); |
549 | 0 | for (vector<Node*>::const_iterator i = inputs_.begin(); |
550 | 0 | i != inputs_.end() && *i != NULL; ++i) { |
551 | 0 | printf("%s ", (*i)->path().c_str()); |
552 | 0 | } |
553 | 0 | printf("--%s-> ", rule_->name().c_str()); |
554 | 0 | for (vector<Node*>::const_iterator i = outputs_.begin(); |
555 | 0 | i != outputs_.end() && *i != NULL; ++i) { |
556 | 0 | printf("%s ", (*i)->path().c_str()); |
557 | 0 | } |
558 | 0 | if (!validations_.empty()) { |
559 | 0 | printf(" validations "); |
560 | 0 | for (std::vector<Node*>::const_iterator i = validations_.begin(); |
561 | 0 | i != validations_.end() && *i != NULL; ++i) { |
562 | 0 | printf("%s ", (*i)->path().c_str()); |
563 | 0 | } |
564 | 0 | } |
565 | 0 | if (pool_) { |
566 | 0 | if (!pool_->name().empty()) { |
567 | 0 | printf("(in pool '%s')", pool_->name().c_str()); |
568 | 0 | } |
569 | 0 | } else { |
570 | 0 | printf("(null pool?)"); |
571 | 0 | } |
572 | 0 | printf("] 0x%p\n", this); |
573 | 0 | } |
574 | | |
575 | 35 | bool Edge::is_phony() const { |
576 | 35 | return rule_ == &State::kPhonyRule; |
577 | 35 | } |
578 | | |
579 | 0 | bool Edge::use_console() const { |
580 | 0 | return pool() == &State::kConsolePool; |
581 | 0 | } |
582 | | |
583 | 35 | bool Edge::maybe_phonycycle_diagnostic() const { |
584 | | // CMake 2.8.12.x and 3.0.x produced self-referencing phony rules |
585 | | // of the form "build a: phony ... a ...". Restrict our |
586 | | // "phonycycle" diagnostic option to the form it used. |
587 | 35 | return is_phony() && outputs_.size() == 1 && implicit_outs_ == 0 && |
588 | 35 | implicit_deps_ == 0; |
589 | 35 | } |
590 | | |
591 | | // static |
592 | 3.66M | string Node::PathDecanonicalized(const string& path, uint64_t slash_bits) { |
593 | 3.66M | string result = path; |
594 | | #ifdef _WIN32 |
595 | | uint64_t mask = 1; |
596 | | for (char* c = &result[0]; (c = strchr(c, '/')) != NULL;) { |
597 | | if (slash_bits & mask) |
598 | | *c = '\\'; |
599 | | c++; |
600 | | mask <<= 1; |
601 | | } |
602 | | #endif |
603 | 3.66M | return result; |
604 | 3.66M | } |
605 | | |
606 | 0 | void Node::Dump(const char* prefix) const { |
607 | 0 | printf("%s <%s 0x%p> mtime: %" PRId64 "%s, (:%s), ", |
608 | 0 | prefix, path().c_str(), this, |
609 | 0 | mtime(), exists() ? "" : " (:missing)", |
610 | 0 | dirty() ? " dirty" : " clean"); |
611 | 0 | if (in_edge()) { |
612 | 0 | in_edge()->Dump("in-edge: "); |
613 | 0 | } else { |
614 | 0 | printf("no in-edge\n"); |
615 | 0 | } |
616 | 0 | printf(" out edges:\n"); |
617 | 0 | for (vector<Edge*>::const_iterator e = out_edges().begin(); |
618 | 0 | e != out_edges().end() && *e != NULL; ++e) { |
619 | 0 | (*e)->Dump(" +- "); |
620 | 0 | } |
621 | 0 | if (!validation_out_edges().empty()) { |
622 | 0 | printf(" validation out edges:\n"); |
623 | 0 | for (std::vector<Edge*>::const_iterator e = validation_out_edges().begin(); |
624 | 0 | e != validation_out_edges().end() && *e != NULL; ++e) { |
625 | 0 | (*e)->Dump(" +- "); |
626 | 0 | } |
627 | 0 | } |
628 | 0 | } |
629 | | |
630 | 0 | bool ImplicitDepLoader::LoadDeps(Edge* edge, string* err) { |
631 | 0 | string deps_type = edge->GetBinding("deps"); |
632 | 0 | if (!deps_type.empty()) |
633 | 0 | return LoadDepsFromLog(edge, err); |
634 | | |
635 | 0 | string depfile = edge->GetUnescapedDepfile(); |
636 | 0 | if (!depfile.empty()) |
637 | 0 | return LoadDepFile(edge, depfile, err); |
638 | | |
639 | | // No deps to load. |
640 | 0 | return true; |
641 | 0 | } |
642 | | |
643 | | struct matches { |
644 | 0 | explicit matches(std::vector<StringPiece>::iterator i) : i_(i) {} |
645 | | |
646 | 0 | bool operator()(const Node* node) const { |
647 | 0 | StringPiece opath = StringPiece(node->path()); |
648 | 0 | return *i_ == opath; |
649 | 0 | } |
650 | | |
651 | | std::vector<StringPiece>::iterator i_; |
652 | | }; |
653 | | |
654 | | bool ImplicitDepLoader::LoadDepFile(Edge* edge, const string& path, |
655 | 0 | string* err) { |
656 | 0 | METRIC_RECORD("depfile load"); |
657 | | // Read depfile content. Treat a missing depfile as empty. |
658 | 0 | string content; |
659 | 0 | switch (disk_interface_->ReadFile(path, &content, err)) { |
660 | 0 | case DiskInterface::Okay: |
661 | 0 | break; |
662 | 0 | case DiskInterface::NotFound: |
663 | 0 | err->clear(); |
664 | 0 | break; |
665 | 0 | case DiskInterface::OtherError: |
666 | 0 | *err = "loading '" + path + "': " + *err; |
667 | 0 | return false; |
668 | 0 | } |
669 | | // On a missing depfile: return false and empty *err. |
670 | 0 | if (content.empty()) { |
671 | 0 | EXPLAIN("depfile '%s' is missing", path.c_str()); |
672 | 0 | return false; |
673 | 0 | } |
674 | | |
675 | 0 | DepfileParser depfile(depfile_parser_options_ |
676 | 0 | ? *depfile_parser_options_ |
677 | 0 | : DepfileParserOptions()); |
678 | 0 | string depfile_err; |
679 | 0 | if (!depfile.Parse(&content, &depfile_err)) { |
680 | 0 | *err = path + ": " + depfile_err; |
681 | 0 | return false; |
682 | 0 | } |
683 | | |
684 | 0 | if (depfile.outs_.empty()) { |
685 | 0 | *err = path + ": no outputs declared"; |
686 | 0 | return false; |
687 | 0 | } |
688 | | |
689 | 0 | uint64_t unused; |
690 | 0 | std::vector<StringPiece>::iterator primary_out = depfile.outs_.begin(); |
691 | 0 | CanonicalizePath(const_cast<char*>(primary_out->str_), &primary_out->len_, |
692 | 0 | &unused); |
693 | | |
694 | | // Check that this depfile matches the edge's output, if not return false to |
695 | | // mark the edge as dirty. |
696 | 0 | Node* first_output = edge->outputs_[0]; |
697 | 0 | StringPiece opath = StringPiece(first_output->path()); |
698 | 0 | if (opath != *primary_out) { |
699 | 0 | EXPLAIN("expected depfile '%s' to mention '%s', got '%s'", path.c_str(), |
700 | 0 | first_output->path().c_str(), primary_out->AsString().c_str()); |
701 | 0 | return false; |
702 | 0 | } |
703 | | |
704 | | // Ensure that all mentioned outputs are outputs of the edge. |
705 | 0 | for (std::vector<StringPiece>::iterator o = depfile.outs_.begin(); |
706 | 0 | o != depfile.outs_.end(); ++o) { |
707 | 0 | matches m(o); |
708 | 0 | if (std::find_if(edge->outputs_.begin(), edge->outputs_.end(), m) == edge->outputs_.end()) { |
709 | 0 | *err = path + ": depfile mentions '" + o->AsString() + "' as an output, but no such output was declared"; |
710 | 0 | return false; |
711 | 0 | } |
712 | 0 | } |
713 | | |
714 | 0 | return ProcessDepfileDeps(edge, &depfile.ins_, err); |
715 | 0 | } |
716 | | |
717 | | bool ImplicitDepLoader::ProcessDepfileDeps( |
718 | 0 | Edge* edge, std::vector<StringPiece>* depfile_ins, std::string* err) { |
719 | | // Preallocate space in edge->inputs_ to be filled in below. |
720 | 0 | vector<Node*>::iterator implicit_dep = |
721 | 0 | PreallocateSpace(edge, depfile_ins->size()); |
722 | | |
723 | | // Add all its in-edges. |
724 | 0 | for (std::vector<StringPiece>::iterator i = depfile_ins->begin(); |
725 | 0 | i != depfile_ins->end(); ++i, ++implicit_dep) { |
726 | 0 | uint64_t slash_bits; |
727 | 0 | CanonicalizePath(const_cast<char*>(i->str_), &i->len_, &slash_bits); |
728 | 0 | Node* node = state_->GetNode(*i, slash_bits); |
729 | 0 | *implicit_dep = node; |
730 | 0 | node->AddOutEdge(edge); |
731 | 0 | CreatePhonyInEdge(node); |
732 | 0 | } |
733 | |
|
734 | 0 | return true; |
735 | 0 | } |
736 | | |
737 | 0 | bool ImplicitDepLoader::LoadDepsFromLog(Edge* edge, string* err) { |
738 | | // NOTE: deps are only supported for single-target edges. |
739 | 0 | Node* output = edge->outputs_[0]; |
740 | 0 | DepsLog::Deps* deps = deps_log_ ? deps_log_->GetDeps(output) : NULL; |
741 | 0 | if (!deps) { |
742 | 0 | EXPLAIN("deps for '%s' are missing", output->path().c_str()); |
743 | 0 | return false; |
744 | 0 | } |
745 | | |
746 | | // Deps are invalid if the output is newer than the deps. |
747 | 0 | if (output->mtime() > deps->mtime) { |
748 | 0 | EXPLAIN("stored deps info out of date for '%s' (%" PRId64 " vs %" PRId64 ")", |
749 | 0 | output->path().c_str(), deps->mtime, output->mtime()); |
750 | 0 | return false; |
751 | 0 | } |
752 | | |
753 | 0 | vector<Node*>::iterator implicit_dep = |
754 | 0 | PreallocateSpace(edge, deps->node_count); |
755 | 0 | for (int i = 0; i < deps->node_count; ++i, ++implicit_dep) { |
756 | 0 | Node* node = deps->nodes[i]; |
757 | 0 | *implicit_dep = node; |
758 | 0 | node->AddOutEdge(edge); |
759 | 0 | CreatePhonyInEdge(node); |
760 | 0 | } |
761 | 0 | return true; |
762 | 0 | } |
763 | | |
764 | | vector<Node*>::iterator ImplicitDepLoader::PreallocateSpace(Edge* edge, |
765 | 0 | int count) { |
766 | 0 | edge->inputs_.insert(edge->inputs_.end() - edge->order_only_deps_, |
767 | 0 | (size_t)count, 0); |
768 | 0 | edge->implicit_deps_ += count; |
769 | 0 | return edge->inputs_.end() - edge->order_only_deps_ - count; |
770 | 0 | } |
771 | | |
772 | 0 | void ImplicitDepLoader::CreatePhonyInEdge(Node* node) { |
773 | 0 | if (node->in_edge()) |
774 | 0 | return; |
775 | | |
776 | 0 | Edge* phony_edge = state_->AddEdge(&State::kPhonyRule); |
777 | 0 | phony_edge->generated_by_dep_loader_ = true; |
778 | 0 | node->set_in_edge(phony_edge); |
779 | 0 | phony_edge->outputs_.push_back(node); |
780 | | |
781 | | // RecomputeDirty might not be called for phony_edge if a previous call |
782 | | // to RecomputeDirty had caused the file to be stat'ed. Because previous |
783 | | // invocations of RecomputeDirty would have seen this node without an |
784 | | // input edge (and therefore ready), we have to set outputs_ready_ to true |
785 | | // to avoid a potential stuck build. If we do call RecomputeDirty for |
786 | | // this node, it will simply set outputs_ready_ to the correct value. |
787 | 0 | phony_edge->outputs_ready_ = true; |
788 | 0 | } |