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 "build.h" |
16 | |
17 | #include <assert.h> |
18 | |
19 | #include "build_log.h" |
20 | #include "deps_log.h" |
21 | #include "graph.h" |
22 | #include "status.h" |
23 | #include "test.h" |
24 | |
25 | using namespace std; |
26 | |
27 | struct CompareEdgesByOutput { |
28 | static bool cmp(const Edge* a, const Edge* b) { |
29 | return a->outputs_[0]->path() < b->outputs_[0]->path(); |
30 | } |
31 | }; |
32 | |
33 | /// Fixture for tests involving Plan. |
34 | // Though Plan doesn't use State, it's useful to have one around |
35 | // to create Nodes and Edges. |
36 | struct PlanTest : public StateTestWithBuiltinRules { |
37 | Plan plan_; |
38 | |
39 | /// Because FindWork does not return Edges in any sort of predictable order, |
40 | // provide a means to get available Edges in order and in a format which is |
41 | // easy to write tests around. |
42 | void FindWorkSorted(deque<Edge*>* ret, int count) { |
43 | for (int i = 0; i < count; ++i) { |
44 | ASSERT_TRUE(plan_.more_to_do()); |
45 | Edge* edge = plan_.FindWork(); |
46 | ASSERT_TRUE(edge); |
47 | ret->push_back(edge); |
48 | } |
49 | ASSERT_FALSE(plan_.FindWork()); |
50 | sort(ret->begin(), ret->end(), CompareEdgesByOutput::cmp); |
51 | } |
52 | |
53 | void TestPoolWithDepthOne(const char *test_case); |
54 | }; |
55 | |
56 | TEST_F(PlanTest, Basic) { |
57 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
58 | "build out: cat mid\n" |
59 | "build mid: cat in\n" )); |
60 | GetNode("mid" )->MarkDirty(); |
61 | GetNode("out" )->MarkDirty(); |
62 | string err; |
63 | EXPECT_TRUE(plan_.AddTarget(GetNode("out" ), &err)); |
64 | ASSERT_EQ("" , err); |
65 | ASSERT_TRUE(plan_.more_to_do()); |
66 | |
67 | Edge* edge = plan_.FindWork(); |
68 | ASSERT_TRUE(edge); |
69 | ASSERT_EQ("in" , edge->inputs_[0]->path()); |
70 | ASSERT_EQ("mid" , edge->outputs_[0]->path()); |
71 | |
72 | ASSERT_FALSE(plan_.FindWork()); |
73 | |
74 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
75 | ASSERT_EQ("" , err); |
76 | |
77 | edge = plan_.FindWork(); |
78 | ASSERT_TRUE(edge); |
79 | ASSERT_EQ("mid" , edge->inputs_[0]->path()); |
80 | ASSERT_EQ("out" , edge->outputs_[0]->path()); |
81 | |
82 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
83 | ASSERT_EQ("" , err); |
84 | |
85 | ASSERT_FALSE(plan_.more_to_do()); |
86 | edge = plan_.FindWork(); |
87 | ASSERT_EQ(0, edge); |
88 | } |
89 | |
90 | // Test that two outputs from one rule can be handled as inputs to the next. |
91 | TEST_F(PlanTest, DoubleOutputDirect) { |
92 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
93 | "build out: cat mid1 mid2\n" |
94 | "build mid1 mid2: cat in\n" )); |
95 | GetNode("mid1" )->MarkDirty(); |
96 | GetNode("mid2" )->MarkDirty(); |
97 | GetNode("out" )->MarkDirty(); |
98 | |
99 | string err; |
100 | EXPECT_TRUE(plan_.AddTarget(GetNode("out" ), &err)); |
101 | ASSERT_EQ("" , err); |
102 | ASSERT_TRUE(plan_.more_to_do()); |
103 | |
104 | Edge* edge; |
105 | edge = plan_.FindWork(); |
106 | ASSERT_TRUE(edge); // cat in |
107 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
108 | ASSERT_EQ("" , err); |
109 | |
110 | edge = plan_.FindWork(); |
111 | ASSERT_TRUE(edge); // cat mid1 mid2 |
112 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
113 | ASSERT_EQ("" , err); |
114 | |
115 | edge = plan_.FindWork(); |
116 | ASSERT_FALSE(edge); // done |
117 | } |
118 | |
119 | // Test that two outputs from one rule can eventually be routed to another. |
120 | TEST_F(PlanTest, DoubleOutputIndirect) { |
121 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
122 | "build out: cat b1 b2\n" |
123 | "build b1: cat a1\n" |
124 | "build b2: cat a2\n" |
125 | "build a1 a2: cat in\n" )); |
126 | GetNode("a1" )->MarkDirty(); |
127 | GetNode("a2" )->MarkDirty(); |
128 | GetNode("b1" )->MarkDirty(); |
129 | GetNode("b2" )->MarkDirty(); |
130 | GetNode("out" )->MarkDirty(); |
131 | string err; |
132 | EXPECT_TRUE(plan_.AddTarget(GetNode("out" ), &err)); |
133 | ASSERT_EQ("" , err); |
134 | ASSERT_TRUE(plan_.more_to_do()); |
135 | |
136 | Edge* edge; |
137 | edge = plan_.FindWork(); |
138 | ASSERT_TRUE(edge); // cat in |
139 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
140 | ASSERT_EQ("" , err); |
141 | |
142 | edge = plan_.FindWork(); |
143 | ASSERT_TRUE(edge); // cat a1 |
144 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
145 | ASSERT_EQ("" , err); |
146 | |
147 | edge = plan_.FindWork(); |
148 | ASSERT_TRUE(edge); // cat a2 |
149 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
150 | ASSERT_EQ("" , err); |
151 | |
152 | edge = plan_.FindWork(); |
153 | ASSERT_TRUE(edge); // cat b1 b2 |
154 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
155 | ASSERT_EQ("" , err); |
156 | |
157 | edge = plan_.FindWork(); |
158 | ASSERT_FALSE(edge); // done |
159 | } |
160 | |
161 | // Test that two edges from one output can both execute. |
162 | TEST_F(PlanTest, DoubleDependent) { |
163 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
164 | "build out: cat a1 a2\n" |
165 | "build a1: cat mid\n" |
166 | "build a2: cat mid\n" |
167 | "build mid: cat in\n" )); |
168 | GetNode("mid" )->MarkDirty(); |
169 | GetNode("a1" )->MarkDirty(); |
170 | GetNode("a2" )->MarkDirty(); |
171 | GetNode("out" )->MarkDirty(); |
172 | |
173 | string err; |
174 | EXPECT_TRUE(plan_.AddTarget(GetNode("out" ), &err)); |
175 | ASSERT_EQ("" , err); |
176 | ASSERT_TRUE(plan_.more_to_do()); |
177 | |
178 | Edge* edge; |
179 | edge = plan_.FindWork(); |
180 | ASSERT_TRUE(edge); // cat in |
181 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
182 | ASSERT_EQ("" , err); |
183 | |
184 | edge = plan_.FindWork(); |
185 | ASSERT_TRUE(edge); // cat mid |
186 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
187 | ASSERT_EQ("" , err); |
188 | |
189 | edge = plan_.FindWork(); |
190 | ASSERT_TRUE(edge); // cat mid |
191 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
192 | ASSERT_EQ("" , err); |
193 | |
194 | edge = plan_.FindWork(); |
195 | ASSERT_TRUE(edge); // cat a1 a2 |
196 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
197 | ASSERT_EQ("" , err); |
198 | |
199 | edge = plan_.FindWork(); |
200 | ASSERT_FALSE(edge); // done |
201 | } |
202 | |
203 | void PlanTest::TestPoolWithDepthOne(const char* test_case) { |
204 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, test_case)); |
205 | GetNode("out1" )->MarkDirty(); |
206 | GetNode("out2" )->MarkDirty(); |
207 | string err; |
208 | EXPECT_TRUE(plan_.AddTarget(GetNode("out1" ), &err)); |
209 | ASSERT_EQ("" , err); |
210 | EXPECT_TRUE(plan_.AddTarget(GetNode("out2" ), &err)); |
211 | ASSERT_EQ("" , err); |
212 | ASSERT_TRUE(plan_.more_to_do()); |
213 | |
214 | Edge* edge = plan_.FindWork(); |
215 | ASSERT_TRUE(edge); |
216 | ASSERT_EQ("in" , edge->inputs_[0]->path()); |
217 | ASSERT_EQ("out1" , edge->outputs_[0]->path()); |
218 | |
219 | // This will be false since poolcat is serialized |
220 | ASSERT_FALSE(plan_.FindWork()); |
221 | |
222 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
223 | ASSERT_EQ("" , err); |
224 | |
225 | edge = plan_.FindWork(); |
226 | ASSERT_TRUE(edge); |
227 | ASSERT_EQ("in" , edge->inputs_[0]->path()); |
228 | ASSERT_EQ("out2" , edge->outputs_[0]->path()); |
229 | |
230 | ASSERT_FALSE(plan_.FindWork()); |
231 | |
232 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
233 | ASSERT_EQ("" , err); |
234 | |
235 | ASSERT_FALSE(plan_.more_to_do()); |
236 | edge = plan_.FindWork(); |
237 | ASSERT_EQ(0, edge); |
238 | } |
239 | |
240 | TEST_F(PlanTest, PoolWithDepthOne) { |
241 | TestPoolWithDepthOne( |
242 | "pool foobar\n" |
243 | " depth = 1\n" |
244 | "rule poolcat\n" |
245 | " command = cat $in > $out\n" |
246 | " pool = foobar\n" |
247 | "build out1: poolcat in\n" |
248 | "build out2: poolcat in\n" ); |
249 | } |
250 | |
251 | TEST_F(PlanTest, ConsolePool) { |
252 | TestPoolWithDepthOne( |
253 | "rule poolcat\n" |
254 | " command = cat $in > $out\n" |
255 | " pool = console\n" |
256 | "build out1: poolcat in\n" |
257 | "build out2: poolcat in\n" ); |
258 | } |
259 | |
260 | TEST_F(PlanTest, PoolsWithDepthTwo) { |
261 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
262 | "pool foobar\n" |
263 | " depth = 2\n" |
264 | "pool bazbin\n" |
265 | " depth = 2\n" |
266 | "rule foocat\n" |
267 | " command = cat $in > $out\n" |
268 | " pool = foobar\n" |
269 | "rule bazcat\n" |
270 | " command = cat $in > $out\n" |
271 | " pool = bazbin\n" |
272 | "build out1: foocat in\n" |
273 | "build out2: foocat in\n" |
274 | "build out3: foocat in\n" |
275 | "build outb1: bazcat in\n" |
276 | "build outb2: bazcat in\n" |
277 | "build outb3: bazcat in\n" |
278 | " pool =\n" |
279 | "build allTheThings: cat out1 out2 out3 outb1 outb2 outb3\n" |
280 | )); |
281 | // Mark all the out* nodes dirty |
282 | for (int i = 0; i < 3; ++i) { |
283 | GetNode("out" + string(1, '1' + static_cast<char>(i)))->MarkDirty(); |
284 | GetNode("outb" + string(1, '1' + static_cast<char>(i)))->MarkDirty(); |
285 | } |
286 | GetNode("allTheThings" )->MarkDirty(); |
287 | |
288 | string err; |
289 | EXPECT_TRUE(plan_.AddTarget(GetNode("allTheThings" ), &err)); |
290 | ASSERT_EQ("" , err); |
291 | |
292 | deque<Edge*> edges; |
293 | FindWorkSorted(&edges, 5); |
294 | |
295 | for (int i = 0; i < 4; ++i) { |
296 | Edge *edge = edges[i]; |
297 | ASSERT_EQ("in" , edge->inputs_[0]->path()); |
298 | string base_name(i < 2 ? "out" : "outb" ); |
299 | ASSERT_EQ(base_name + string(1, '1' + (i % 2)), edge->outputs_[0]->path()); |
300 | } |
301 | |
302 | // outb3 is exempt because it has an empty pool |
303 | Edge* edge = edges[4]; |
304 | ASSERT_TRUE(edge); |
305 | ASSERT_EQ("in" , edge->inputs_[0]->path()); |
306 | ASSERT_EQ("outb3" , edge->outputs_[0]->path()); |
307 | |
308 | // finish out1 |
309 | plan_.EdgeFinished(edges.front(), Plan::kEdgeSucceeded, &err); |
310 | ASSERT_EQ("" , err); |
311 | edges.pop_front(); |
312 | |
313 | // out3 should be available |
314 | Edge* out3 = plan_.FindWork(); |
315 | ASSERT_TRUE(out3); |
316 | ASSERT_EQ("in" , out3->inputs_[0]->path()); |
317 | ASSERT_EQ("out3" , out3->outputs_[0]->path()); |
318 | |
319 | ASSERT_FALSE(plan_.FindWork()); |
320 | |
321 | plan_.EdgeFinished(out3, Plan::kEdgeSucceeded, &err); |
322 | ASSERT_EQ("" , err); |
323 | |
324 | ASSERT_FALSE(plan_.FindWork()); |
325 | |
326 | for (deque<Edge*>::iterator it = edges.begin(); it != edges.end(); ++it) { |
327 | plan_.EdgeFinished(*it, Plan::kEdgeSucceeded, &err); |
328 | ASSERT_EQ("" , err); |
329 | } |
330 | |
331 | Edge* last = plan_.FindWork(); |
332 | ASSERT_TRUE(last); |
333 | ASSERT_EQ("allTheThings" , last->outputs_[0]->path()); |
334 | |
335 | plan_.EdgeFinished(last, Plan::kEdgeSucceeded, &err); |
336 | ASSERT_EQ("" , err); |
337 | |
338 | ASSERT_FALSE(plan_.more_to_do()); |
339 | ASSERT_FALSE(plan_.FindWork()); |
340 | } |
341 | |
342 | TEST_F(PlanTest, PoolWithRedundantEdges) { |
343 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
344 | "pool compile\n" |
345 | " depth = 1\n" |
346 | "rule gen_foo\n" |
347 | " command = touch foo.cpp\n" |
348 | "rule gen_bar\n" |
349 | " command = touch bar.cpp\n" |
350 | "rule echo\n" |
351 | " command = echo $out > $out\n" |
352 | "build foo.cpp.obj: echo foo.cpp || foo.cpp\n" |
353 | " pool = compile\n" |
354 | "build bar.cpp.obj: echo bar.cpp || bar.cpp\n" |
355 | " pool = compile\n" |
356 | "build libfoo.a: echo foo.cpp.obj bar.cpp.obj\n" |
357 | "build foo.cpp: gen_foo\n" |
358 | "build bar.cpp: gen_bar\n" |
359 | "build all: phony libfoo.a\n" )); |
360 | GetNode("foo.cpp" )->MarkDirty(); |
361 | GetNode("foo.cpp.obj" )->MarkDirty(); |
362 | GetNode("bar.cpp" )->MarkDirty(); |
363 | GetNode("bar.cpp.obj" )->MarkDirty(); |
364 | GetNode("libfoo.a" )->MarkDirty(); |
365 | GetNode("all" )->MarkDirty(); |
366 | string err; |
367 | EXPECT_TRUE(plan_.AddTarget(GetNode("all" ), &err)); |
368 | ASSERT_EQ("" , err); |
369 | ASSERT_TRUE(plan_.more_to_do()); |
370 | |
371 | Edge* edge = NULL; |
372 | |
373 | deque<Edge*> initial_edges; |
374 | FindWorkSorted(&initial_edges, 2); |
375 | |
376 | edge = initial_edges[1]; // Foo first |
377 | ASSERT_EQ("foo.cpp" , edge->outputs_[0]->path()); |
378 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
379 | ASSERT_EQ("" , err); |
380 | |
381 | edge = plan_.FindWork(); |
382 | ASSERT_TRUE(edge); |
383 | ASSERT_FALSE(plan_.FindWork()); |
384 | ASSERT_EQ("foo.cpp" , edge->inputs_[0]->path()); |
385 | ASSERT_EQ("foo.cpp" , edge->inputs_[1]->path()); |
386 | ASSERT_EQ("foo.cpp.obj" , edge->outputs_[0]->path()); |
387 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
388 | ASSERT_EQ("" , err); |
389 | |
390 | edge = initial_edges[0]; // Now for bar |
391 | ASSERT_EQ("bar.cpp" , edge->outputs_[0]->path()); |
392 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
393 | ASSERT_EQ("" , err); |
394 | |
395 | edge = plan_.FindWork(); |
396 | ASSERT_TRUE(edge); |
397 | ASSERT_FALSE(plan_.FindWork()); |
398 | ASSERT_EQ("bar.cpp" , edge->inputs_[0]->path()); |
399 | ASSERT_EQ("bar.cpp" , edge->inputs_[1]->path()); |
400 | ASSERT_EQ("bar.cpp.obj" , edge->outputs_[0]->path()); |
401 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
402 | ASSERT_EQ("" , err); |
403 | |
404 | edge = plan_.FindWork(); |
405 | ASSERT_TRUE(edge); |
406 | ASSERT_FALSE(plan_.FindWork()); |
407 | ASSERT_EQ("foo.cpp.obj" , edge->inputs_[0]->path()); |
408 | ASSERT_EQ("bar.cpp.obj" , edge->inputs_[1]->path()); |
409 | ASSERT_EQ("libfoo.a" , edge->outputs_[0]->path()); |
410 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
411 | ASSERT_EQ("" , err); |
412 | |
413 | edge = plan_.FindWork(); |
414 | ASSERT_TRUE(edge); |
415 | ASSERT_FALSE(plan_.FindWork()); |
416 | ASSERT_EQ("libfoo.a" , edge->inputs_[0]->path()); |
417 | ASSERT_EQ("all" , edge->outputs_[0]->path()); |
418 | plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err); |
419 | ASSERT_EQ("" , err); |
420 | |
421 | edge = plan_.FindWork(); |
422 | ASSERT_FALSE(edge); |
423 | ASSERT_FALSE(plan_.more_to_do()); |
424 | } |
425 | |
426 | TEST_F(PlanTest, PoolWithFailingEdge) { |
427 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
428 | "pool foobar\n" |
429 | " depth = 1\n" |
430 | "rule poolcat\n" |
431 | " command = cat $in > $out\n" |
432 | " pool = foobar\n" |
433 | "build out1: poolcat in\n" |
434 | "build out2: poolcat in\n" )); |
435 | GetNode("out1" )->MarkDirty(); |
436 | GetNode("out2" )->MarkDirty(); |
437 | string err; |
438 | EXPECT_TRUE(plan_.AddTarget(GetNode("out1" ), &err)); |
439 | ASSERT_EQ("" , err); |
440 | EXPECT_TRUE(plan_.AddTarget(GetNode("out2" ), &err)); |
441 | ASSERT_EQ("" , err); |
442 | ASSERT_TRUE(plan_.more_to_do()); |
443 | |
444 | Edge* edge = plan_.FindWork(); |
445 | ASSERT_TRUE(edge); |
446 | ASSERT_EQ("in" , edge->inputs_[0]->path()); |
447 | ASSERT_EQ("out1" , edge->outputs_[0]->path()); |
448 | |
449 | // This will be false since poolcat is serialized |
450 | ASSERT_FALSE(plan_.FindWork()); |
451 | |
452 | plan_.EdgeFinished(edge, Plan::kEdgeFailed, &err); |
453 | ASSERT_EQ("" , err); |
454 | |
455 | edge = plan_.FindWork(); |
456 | ASSERT_TRUE(edge); |
457 | ASSERT_EQ("in" , edge->inputs_[0]->path()); |
458 | ASSERT_EQ("out2" , edge->outputs_[0]->path()); |
459 | |
460 | ASSERT_FALSE(plan_.FindWork()); |
461 | |
462 | plan_.EdgeFinished(edge, Plan::kEdgeFailed, &err); |
463 | ASSERT_EQ("" , err); |
464 | |
465 | ASSERT_TRUE(plan_.more_to_do()); // Jobs have failed |
466 | edge = plan_.FindWork(); |
467 | ASSERT_EQ(0, edge); |
468 | } |
469 | |
470 | /// Fake implementation of CommandRunner, useful for tests. |
471 | struct FakeCommandRunner : public CommandRunner { |
472 | explicit FakeCommandRunner(VirtualFileSystem* fs) : |
473 | max_active_edges_(1), fs_(fs) {} |
474 | |
475 | // CommandRunner impl |
476 | virtual bool CanRunMore() const; |
477 | virtual bool StartCommand(Edge* edge); |
478 | virtual bool WaitForCommand(Result* result); |
479 | virtual vector<Edge*> GetActiveEdges(); |
480 | virtual void Abort(); |
481 | |
482 | vector<string> commands_ran_; |
483 | vector<Edge*> active_edges_; |
484 | size_t max_active_edges_; |
485 | VirtualFileSystem* fs_; |
486 | }; |
487 | |
488 | struct BuildTest : public StateTestWithBuiltinRules, public BuildLogUser { |
489 | BuildTest() : config_(MakeConfig()), command_runner_(&fs_), status_(config_), |
490 | builder_(&state_, config_, NULL, NULL, &fs_, &status_, 0) { |
491 | } |
492 | |
493 | explicit BuildTest(DepsLog* log) |
494 | : config_(MakeConfig()), command_runner_(&fs_), status_(config_), |
495 | builder_(&state_, config_, NULL, log, &fs_, &status_, 0) {} |
496 | |
497 | virtual void SetUp() { |
498 | StateTestWithBuiltinRules::SetUp(); |
499 | |
500 | builder_.command_runner_.reset(&command_runner_); |
501 | AssertParse(&state_, |
502 | "build cat1: cat in1\n" |
503 | "build cat2: cat in1 in2\n" |
504 | "build cat12: cat cat1 cat2\n" ); |
505 | |
506 | fs_.Create("in1" , "" ); |
507 | fs_.Create("in2" , "" ); |
508 | } |
509 | |
510 | ~BuildTest() { |
511 | builder_.command_runner_.release(); |
512 | } |
513 | |
514 | virtual bool IsPathDead(StringPiece s) const { return false; } |
515 | |
516 | /// Rebuild target in the 'working tree' (fs_). |
517 | /// State of command_runner_ and logs contents (if specified) ARE MODIFIED. |
518 | /// Handy to check for NOOP builds, and higher-level rebuild tests. |
519 | void RebuildTarget(const string& target, const char* manifest, |
520 | const char* log_path = NULL, const char* deps_path = NULL, |
521 | State* state = NULL); |
522 | |
523 | // Mark a path dirty. |
524 | void Dirty(const string& path); |
525 | |
526 | BuildConfig MakeConfig() { |
527 | BuildConfig config; |
528 | config.verbosity = BuildConfig::QUIET; |
529 | return config; |
530 | } |
531 | |
532 | BuildConfig config_; |
533 | FakeCommandRunner command_runner_; |
534 | VirtualFileSystem fs_; |
535 | StatusPrinter status_; |
536 | Builder builder_; |
537 | }; |
538 | |
539 | void BuildTest::RebuildTarget(const string& target, const char* manifest, |
540 | const char* log_path, const char* deps_path, |
541 | State* state) { |
542 | State local_state, *pstate = &local_state; |
543 | if (state) |
544 | pstate = state; |
545 | ASSERT_NO_FATAL_FAILURE(AddCatRule(pstate)); |
546 | AssertParse(pstate, manifest); |
547 | |
548 | string err; |
549 | BuildLog build_log, *pbuild_log = NULL; |
550 | if (log_path) { |
551 | ASSERT_TRUE(build_log.Load(log_path, &err)); |
552 | ASSERT_TRUE(build_log.OpenForWrite(log_path, *this, &err)); |
553 | ASSERT_EQ("" , err); |
554 | pbuild_log = &build_log; |
555 | } |
556 | |
557 | DepsLog deps_log, *pdeps_log = NULL; |
558 | if (deps_path) { |
559 | ASSERT_TRUE(deps_log.Load(deps_path, pstate, &err)); |
560 | ASSERT_TRUE(deps_log.OpenForWrite(deps_path, &err)); |
561 | ASSERT_EQ("" , err); |
562 | pdeps_log = &deps_log; |
563 | } |
564 | |
565 | Builder builder(pstate, config_, pbuild_log, pdeps_log, &fs_, &status_, 0); |
566 | EXPECT_TRUE(builder.AddTarget(target, &err)); |
567 | |
568 | command_runner_.commands_ran_.clear(); |
569 | builder.command_runner_.reset(&command_runner_); |
570 | if (!builder.AlreadyUpToDate()) { |
571 | bool build_res = builder.Build(&err); |
572 | EXPECT_TRUE(build_res); |
573 | } |
574 | builder.command_runner_.release(); |
575 | } |
576 | |
577 | bool FakeCommandRunner::CanRunMore() const { |
578 | return active_edges_.size() < max_active_edges_; |
579 | } |
580 | |
581 | bool FakeCommandRunner::StartCommand(Edge* edge) { |
582 | assert(active_edges_.size() < max_active_edges_); |
583 | assert(find(active_edges_.begin(), active_edges_.end(), edge) |
584 | == active_edges_.end()); |
585 | commands_ran_.push_back(edge->EvaluateCommand()); |
586 | if (edge->rule().name() == "cat" || |
587 | edge->rule().name() == "cat_rsp" || |
588 | edge->rule().name() == "cat_rsp_out" || |
589 | edge->rule().name() == "cc" || |
590 | edge->rule().name() == "cp_multi_msvc" || |
591 | edge->rule().name() == "cp_multi_gcc" || |
592 | edge->rule().name() == "touch" || |
593 | edge->rule().name() == "touch-interrupt" || |
594 | edge->rule().name() == "touch-fail-tick2" ) { |
595 | for (vector<Node*>::iterator out = edge->outputs_.begin(); |
596 | out != edge->outputs_.end(); ++out) { |
597 | fs_->Create((*out)->path(), "" ); |
598 | } |
599 | } else if (edge->rule().name() == "true" || |
600 | edge->rule().name() == "fail" || |
601 | edge->rule().name() == "interrupt" || |
602 | edge->rule().name() == "console" ) { |
603 | // Don't do anything. |
604 | } else if (edge->rule().name() == "cp" ) { |
605 | assert(!edge->inputs_.empty()); |
606 | assert(edge->outputs_.size() == 1); |
607 | string content; |
608 | string err; |
609 | if (fs_->ReadFile(edge->inputs_[0]->path(), &content, &err) == |
610 | DiskInterface::Okay) |
611 | fs_->WriteFile(edge->outputs_[0]->path(), content); |
612 | } else if (edge->rule().name() == "touch-implicit-dep-out" ) { |
613 | string dep = edge->GetBinding("test_dependency" ); |
614 | fs_->Tick(); |
615 | fs_->Create(dep, "" ); |
616 | fs_->Tick(); |
617 | for (vector<Node*>::iterator out = edge->outputs_.begin(); |
618 | out != edge->outputs_.end(); ++out) { |
619 | fs_->Create((*out)->path(), "" ); |
620 | } |
621 | } else if (edge->rule().name() == "touch-out-implicit-dep" ) { |
622 | string dep = edge->GetBinding("test_dependency" ); |
623 | for (vector<Node*>::iterator out = edge->outputs_.begin(); |
624 | out != edge->outputs_.end(); ++out) { |
625 | fs_->Create((*out)->path(), "" ); |
626 | } |
627 | fs_->Tick(); |
628 | fs_->Create(dep, "" ); |
629 | } else if (edge->rule().name() == "generate-depfile" ) { |
630 | string dep = edge->GetBinding("test_dependency" ); |
631 | bool touch_dep = edge->GetBindingBool("touch_dependency" ); |
632 | string depfile = edge->GetUnescapedDepfile(); |
633 | if (touch_dep) { |
634 | fs_->Tick(); |
635 | fs_->Create(dep, "" ); |
636 | } |
637 | string contents; |
638 | for (vector<Node*>::iterator out = edge->outputs_.begin(); |
639 | out != edge->outputs_.end(); ++out) { |
640 | contents += (*out)->path() + ": " + dep + "\n" ; |
641 | fs_->Create((*out)->path(), "" ); |
642 | } |
643 | fs_->Create(depfile, contents); |
644 | } else if (edge->rule().name() == "long-cc" ) { |
645 | string dep = edge->GetBinding("test_dependency" ); |
646 | string depfile = edge->GetUnescapedDepfile(); |
647 | string contents; |
648 | for (vector<Node*>::iterator out = edge->outputs_.begin(); |
649 | out != edge->outputs_.end(); ++out) { |
650 | fs_->Tick(); |
651 | fs_->Tick(); |
652 | fs_->Tick(); |
653 | fs_->Create((*out)->path(), "" ); |
654 | contents += (*out)->path() + ": " + dep + "\n" ; |
655 | } |
656 | if (!dep.empty() && !depfile.empty()) |
657 | fs_->Create(depfile, contents); |
658 | } else { |
659 | printf("unknown command\n" ); |
660 | return false; |
661 | } |
662 | |
663 | active_edges_.push_back(edge); |
664 | |
665 | // Allow tests to control the order by the name of the first output. |
666 | sort(active_edges_.begin(), active_edges_.end(), |
667 | CompareEdgesByOutput::cmp); |
668 | |
669 | return true; |
670 | } |
671 | |
672 | bool FakeCommandRunner::WaitForCommand(Result* result) { |
673 | if (active_edges_.empty()) |
674 | return false; |
675 | |
676 | // All active edges were already completed immediately when started, |
677 | // so we can pick any edge here. Pick the last edge. Tests can |
678 | // control the order of edges by the name of the first output. |
679 | vector<Edge*>::iterator edge_iter = active_edges_.end() - 1; |
680 | |
681 | Edge* edge = *edge_iter; |
682 | result->edge = edge; |
683 | |
684 | if (edge->rule().name() == "interrupt" || |
685 | edge->rule().name() == "touch-interrupt" ) { |
686 | result->status = ExitInterrupted; |
687 | return true; |
688 | } |
689 | |
690 | if (edge->rule().name() == "console" ) { |
691 | if (edge->use_console()) |
692 | result->status = ExitSuccess; |
693 | else |
694 | result->status = ExitFailure; |
695 | active_edges_.erase(edge_iter); |
696 | return true; |
697 | } |
698 | |
699 | if (edge->rule().name() == "cp_multi_msvc" ) { |
700 | const std::string prefix = edge->GetBinding("msvc_deps_prefix" ); |
701 | for (std::vector<Node*>::iterator in = edge->inputs_.begin(); |
702 | in != edge->inputs_.end(); ++in) { |
703 | result->output += prefix + (*in)->path() + '\n'; |
704 | } |
705 | } |
706 | |
707 | if (edge->rule().name() == "fail" || |
708 | (edge->rule().name() == "touch-fail-tick2" && fs_->now_ == 2)) |
709 | result->status = ExitFailure; |
710 | else |
711 | result->status = ExitSuccess; |
712 | |
713 | // This rule simulates an external process modifying files while the build command runs. |
714 | // See TestInputMtimeRaceCondition and TestInputMtimeRaceConditionWithDepFile. |
715 | // Note: only the first and third time the rule is run per test is the file modified, so |
716 | // the test can verify that subsequent runs without the race have no work to do. |
717 | if (edge->rule().name() == "long-cc" ) { |
718 | string dep = edge->GetBinding("test_dependency" ); |
719 | if (fs_->now_ == 4) |
720 | fs_->files_[dep].mtime = 3; |
721 | if (fs_->now_ == 10) |
722 | fs_->files_[dep].mtime = 9; |
723 | } |
724 | |
725 | // Provide a way for test cases to verify when an edge finishes that |
726 | // some other edge is still active. This is useful for test cases |
727 | // covering behavior involving multiple active edges. |
728 | const string& verify_active_edge = edge->GetBinding("verify_active_edge" ); |
729 | if (!verify_active_edge.empty()) { |
730 | bool verify_active_edge_found = false; |
731 | for (vector<Edge*>::iterator i = active_edges_.begin(); |
732 | i != active_edges_.end(); ++i) { |
733 | if (!(*i)->outputs_.empty() && |
734 | (*i)->outputs_[0]->path() == verify_active_edge) { |
735 | verify_active_edge_found = true; |
736 | } |
737 | } |
738 | EXPECT_TRUE(verify_active_edge_found); |
739 | } |
740 | |
741 | active_edges_.erase(edge_iter); |
742 | return true; |
743 | } |
744 | |
745 | vector<Edge*> FakeCommandRunner::GetActiveEdges() { |
746 | return active_edges_; |
747 | } |
748 | |
749 | void FakeCommandRunner::Abort() { |
750 | active_edges_.clear(); |
751 | } |
752 | |
753 | void BuildTest::Dirty(const string& path) { |
754 | Node* node = GetNode(path); |
755 | node->MarkDirty(); |
756 | |
757 | // If it's an input file, mark that we've already stat()ed it and |
758 | // it's missing. |
759 | if (!node->in_edge()) |
760 | node->MarkMissing(); |
761 | } |
762 | |
763 | TEST_F(BuildTest, NoWork) { |
764 | string err; |
765 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
766 | } |
767 | |
768 | TEST_F(BuildTest, OneStep) { |
769 | // Given a dirty target with one ready input, |
770 | // we should rebuild the target. |
771 | Dirty("cat1" ); |
772 | string err; |
773 | EXPECT_TRUE(builder_.AddTarget("cat1" , &err)); |
774 | ASSERT_EQ("" , err); |
775 | EXPECT_TRUE(builder_.Build(&err)); |
776 | ASSERT_EQ("" , err); |
777 | |
778 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
779 | EXPECT_EQ("cat in1 > cat1" , command_runner_.commands_ran_[0]); |
780 | } |
781 | |
782 | TEST_F(BuildTest, OneStep2) { |
783 | // Given a target with one dirty input, |
784 | // we should rebuild the target. |
785 | Dirty("cat1" ); |
786 | string err; |
787 | EXPECT_TRUE(builder_.AddTarget("cat1" , &err)); |
788 | ASSERT_EQ("" , err); |
789 | EXPECT_TRUE(builder_.Build(&err)); |
790 | EXPECT_EQ("" , err); |
791 | |
792 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
793 | EXPECT_EQ("cat in1 > cat1" , command_runner_.commands_ran_[0]); |
794 | } |
795 | |
796 | TEST_F(BuildTest, TwoStep) { |
797 | string err; |
798 | EXPECT_TRUE(builder_.AddTarget("cat12" , &err)); |
799 | ASSERT_EQ("" , err); |
800 | EXPECT_TRUE(builder_.Build(&err)); |
801 | EXPECT_EQ("" , err); |
802 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
803 | // Depending on how the pointers work out, we could've ran |
804 | // the first two commands in either order. |
805 | EXPECT_TRUE((command_runner_.commands_ran_[0] == "cat in1 > cat1" && |
806 | command_runner_.commands_ran_[1] == "cat in1 in2 > cat2" ) || |
807 | (command_runner_.commands_ran_[1] == "cat in1 > cat1" && |
808 | command_runner_.commands_ran_[0] == "cat in1 in2 > cat2" )); |
809 | |
810 | EXPECT_EQ("cat cat1 cat2 > cat12" , command_runner_.commands_ran_[2]); |
811 | |
812 | fs_.Tick(); |
813 | |
814 | // Modifying in2 requires rebuilding one intermediate file |
815 | // and the final file. |
816 | fs_.Create("in2" , "" ); |
817 | state_.Reset(); |
818 | EXPECT_TRUE(builder_.AddTarget("cat12" , &err)); |
819 | ASSERT_EQ("" , err); |
820 | EXPECT_TRUE(builder_.Build(&err)); |
821 | ASSERT_EQ("" , err); |
822 | ASSERT_EQ(5u, command_runner_.commands_ran_.size()); |
823 | EXPECT_EQ("cat in1 in2 > cat2" , command_runner_.commands_ran_[3]); |
824 | EXPECT_EQ("cat cat1 cat2 > cat12" , command_runner_.commands_ran_[4]); |
825 | } |
826 | |
827 | TEST_F(BuildTest, TwoOutputs) { |
828 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
829 | "rule touch\n" |
830 | " command = touch $out\n" |
831 | "build out1 out2: touch in.txt\n" )); |
832 | |
833 | fs_.Create("in.txt" , "" ); |
834 | |
835 | string err; |
836 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
837 | ASSERT_EQ("" , err); |
838 | EXPECT_TRUE(builder_.Build(&err)); |
839 | EXPECT_EQ("" , err); |
840 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
841 | EXPECT_EQ("touch out1 out2" , command_runner_.commands_ran_[0]); |
842 | } |
843 | |
844 | TEST_F(BuildTest, ImplicitOutput) { |
845 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
846 | "rule touch\n" |
847 | " command = touch $out $out.imp\n" |
848 | "build out | out.imp: touch in.txt\n" )); |
849 | fs_.Create("in.txt" , "" ); |
850 | |
851 | string err; |
852 | EXPECT_TRUE(builder_.AddTarget("out.imp" , &err)); |
853 | ASSERT_EQ("" , err); |
854 | EXPECT_TRUE(builder_.Build(&err)); |
855 | EXPECT_EQ("" , err); |
856 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
857 | EXPECT_EQ("touch out out.imp" , command_runner_.commands_ran_[0]); |
858 | } |
859 | |
860 | // Test case from |
861 | // https://github.com/ninja-build/ninja/issues/148 |
862 | TEST_F(BuildTest, MultiOutIn) { |
863 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
864 | "rule touch\n" |
865 | " command = touch $out\n" |
866 | "build in1 otherfile: touch in\n" |
867 | "build out: touch in | in1\n" )); |
868 | |
869 | fs_.Create("in" , "" ); |
870 | fs_.Tick(); |
871 | fs_.Create("in1" , "" ); |
872 | |
873 | string err; |
874 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
875 | ASSERT_EQ("" , err); |
876 | EXPECT_TRUE(builder_.Build(&err)); |
877 | EXPECT_EQ("" , err); |
878 | } |
879 | |
880 | TEST_F(BuildTest, Chain) { |
881 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
882 | "build c2: cat c1\n" |
883 | "build c3: cat c2\n" |
884 | "build c4: cat c3\n" |
885 | "build c5: cat c4\n" )); |
886 | |
887 | fs_.Create("c1" , "" ); |
888 | |
889 | string err; |
890 | EXPECT_TRUE(builder_.AddTarget("c5" , &err)); |
891 | ASSERT_EQ("" , err); |
892 | EXPECT_TRUE(builder_.Build(&err)); |
893 | EXPECT_EQ("" , err); |
894 | ASSERT_EQ(4u, command_runner_.commands_ran_.size()); |
895 | |
896 | err.clear(); |
897 | command_runner_.commands_ran_.clear(); |
898 | state_.Reset(); |
899 | EXPECT_TRUE(builder_.AddTarget("c5" , &err)); |
900 | ASSERT_EQ("" , err); |
901 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
902 | |
903 | fs_.Tick(); |
904 | |
905 | fs_.Create("c3" , "" ); |
906 | err.clear(); |
907 | command_runner_.commands_ran_.clear(); |
908 | state_.Reset(); |
909 | EXPECT_TRUE(builder_.AddTarget("c5" , &err)); |
910 | ASSERT_EQ("" , err); |
911 | EXPECT_FALSE(builder_.AlreadyUpToDate()); |
912 | EXPECT_TRUE(builder_.Build(&err)); |
913 | ASSERT_EQ(2u, command_runner_.commands_ran_.size()); // 3->4, 4->5 |
914 | } |
915 | |
916 | TEST_F(BuildTest, MissingInput) { |
917 | // Input is referenced by build file, but no rule for it. |
918 | string err; |
919 | Dirty("in1" ); |
920 | EXPECT_FALSE(builder_.AddTarget("cat1" , &err)); |
921 | EXPECT_EQ("'in1', needed by 'cat1', missing and no known rule to make it" , |
922 | err); |
923 | } |
924 | |
925 | TEST_F(BuildTest, MissingTarget) { |
926 | // Target is not referenced by build file. |
927 | string err; |
928 | EXPECT_FALSE(builder_.AddTarget("meow" , &err)); |
929 | EXPECT_EQ("unknown target: 'meow'" , err); |
930 | } |
931 | |
932 | TEST_F(BuildTest, MissingInputTarget) { |
933 | // Target is a missing input file |
934 | string err; |
935 | Dirty("in1" ); |
936 | EXPECT_FALSE(builder_.AddTarget("in1" , &err)); |
937 | EXPECT_EQ("'in1' missing and no known rule to make it" , err); |
938 | } |
939 | |
940 | TEST_F(BuildTest, MakeDirs) { |
941 | string err; |
942 | |
943 | #ifdef _WIN32 |
944 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
945 | "build subdir\\dir2\\file: cat in1\n" )); |
946 | #else |
947 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
948 | "build subdir/dir2/file: cat in1\n" )); |
949 | #endif |
950 | EXPECT_TRUE(builder_.AddTarget("subdir/dir2/file" , &err)); |
951 | |
952 | EXPECT_EQ("" , err); |
953 | EXPECT_TRUE(builder_.Build(&err)); |
954 | ASSERT_EQ("" , err); |
955 | ASSERT_EQ(2u, fs_.directories_made_.size()); |
956 | EXPECT_EQ("subdir" , fs_.directories_made_[0]); |
957 | EXPECT_EQ("subdir/dir2" , fs_.directories_made_[1]); |
958 | } |
959 | |
960 | TEST_F(BuildTest, DepFileMissing) { |
961 | string err; |
962 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
963 | "rule cc\n command = cc $in\n depfile = $out.d\n" |
964 | "build fo$ o.o: cc foo.c\n" )); |
965 | fs_.Create("foo.c" , "" ); |
966 | |
967 | EXPECT_TRUE(builder_.AddTarget("fo o.o" , &err)); |
968 | ASSERT_EQ("" , err); |
969 | ASSERT_EQ(1u, fs_.files_read_.size()); |
970 | EXPECT_EQ("fo o.o.d" , fs_.files_read_[0]); |
971 | } |
972 | |
973 | TEST_F(BuildTest, DepFileOK) { |
974 | string err; |
975 | int orig_edges = state_.edges_.size(); |
976 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
977 | "rule cc\n command = cc $in\n depfile = $out.d\n" |
978 | "build foo.o: cc foo.c\n" )); |
979 | Edge* edge = state_.edges_.back(); |
980 | |
981 | fs_.Create("foo.c" , "" ); |
982 | GetNode("bar.h" )->MarkDirty(); // Mark bar.h as missing. |
983 | fs_.Create("foo.o.d" , "foo.o: blah.h bar.h\n" ); |
984 | EXPECT_TRUE(builder_.AddTarget("foo.o" , &err)); |
985 | ASSERT_EQ("" , err); |
986 | ASSERT_EQ(1u, fs_.files_read_.size()); |
987 | EXPECT_EQ("foo.o.d" , fs_.files_read_[0]); |
988 | |
989 | // Expect three new edges: one generating foo.o, and two more from |
990 | // loading the depfile. |
991 | ASSERT_EQ(orig_edges + 3, (int)state_.edges_.size()); |
992 | // Expect our edge to now have three inputs: foo.c and two headers. |
993 | ASSERT_EQ(3u, edge->inputs_.size()); |
994 | |
995 | // Expect the command line we generate to only use the original input. |
996 | ASSERT_EQ("cc foo.c" , edge->EvaluateCommand()); |
997 | } |
998 | |
999 | TEST_F(BuildTest, DepFileParseError) { |
1000 | string err; |
1001 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1002 | "rule cc\n command = cc $in\n depfile = $out.d\n" |
1003 | "build foo.o: cc foo.c\n" )); |
1004 | fs_.Create("foo.c" , "" ); |
1005 | fs_.Create("foo.o.d" , "randomtext\n" ); |
1006 | EXPECT_FALSE(builder_.AddTarget("foo.o" , &err)); |
1007 | EXPECT_EQ("foo.o.d: expected ':' in depfile" , err); |
1008 | } |
1009 | |
1010 | TEST_F(BuildTest, EncounterReadyTwice) { |
1011 | string err; |
1012 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1013 | "rule touch\n" |
1014 | " command = touch $out\n" |
1015 | "build c: touch\n" |
1016 | "build b: touch || c\n" |
1017 | "build a: touch | b || c\n" )); |
1018 | |
1019 | vector<Edge*> c_out = GetNode("c" )->out_edges(); |
1020 | ASSERT_EQ(2u, c_out.size()); |
1021 | EXPECT_EQ("b" , c_out[0]->outputs_[0]->path()); |
1022 | EXPECT_EQ("a" , c_out[1]->outputs_[0]->path()); |
1023 | |
1024 | fs_.Create("b" , "" ); |
1025 | EXPECT_TRUE(builder_.AddTarget("a" , &err)); |
1026 | ASSERT_EQ("" , err); |
1027 | |
1028 | EXPECT_TRUE(builder_.Build(&err)); |
1029 | ASSERT_EQ("" , err); |
1030 | ASSERT_EQ(2u, command_runner_.commands_ran_.size()); |
1031 | } |
1032 | |
1033 | TEST_F(BuildTest, OrderOnlyDeps) { |
1034 | string err; |
1035 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1036 | "rule cc\n command = cc $in\n depfile = $out.d\n" |
1037 | "build foo.o: cc foo.c || otherfile\n" )); |
1038 | Edge* edge = state_.edges_.back(); |
1039 | |
1040 | fs_.Create("foo.c" , "" ); |
1041 | fs_.Create("otherfile" , "" ); |
1042 | fs_.Create("foo.o.d" , "foo.o: blah.h bar.h\n" ); |
1043 | EXPECT_TRUE(builder_.AddTarget("foo.o" , &err)); |
1044 | ASSERT_EQ("" , err); |
1045 | |
1046 | // One explicit, two implicit, one order only. |
1047 | ASSERT_EQ(4u, edge->inputs_.size()); |
1048 | EXPECT_EQ(2, edge->implicit_deps_); |
1049 | EXPECT_EQ(1, edge->order_only_deps_); |
1050 | // Verify the inputs are in the order we expect |
1051 | // (explicit then implicit then orderonly). |
1052 | EXPECT_EQ("foo.c" , edge->inputs_[0]->path()); |
1053 | EXPECT_EQ("blah.h" , edge->inputs_[1]->path()); |
1054 | EXPECT_EQ("bar.h" , edge->inputs_[2]->path()); |
1055 | EXPECT_EQ("otherfile" , edge->inputs_[3]->path()); |
1056 | |
1057 | // Expect the command line we generate to only use the original input. |
1058 | ASSERT_EQ("cc foo.c" , edge->EvaluateCommand()); |
1059 | |
1060 | // explicit dep dirty, expect a rebuild. |
1061 | EXPECT_TRUE(builder_.Build(&err)); |
1062 | ASSERT_EQ("" , err); |
1063 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
1064 | |
1065 | fs_.Tick(); |
1066 | |
1067 | // Recreate the depfile, as it should have been deleted by the build. |
1068 | fs_.Create("foo.o.d" , "foo.o: blah.h bar.h\n" ); |
1069 | |
1070 | // implicit dep dirty, expect a rebuild. |
1071 | fs_.Create("blah.h" , "" ); |
1072 | fs_.Create("bar.h" , "" ); |
1073 | command_runner_.commands_ran_.clear(); |
1074 | state_.Reset(); |
1075 | EXPECT_TRUE(builder_.AddTarget("foo.o" , &err)); |
1076 | EXPECT_TRUE(builder_.Build(&err)); |
1077 | ASSERT_EQ("" , err); |
1078 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
1079 | |
1080 | fs_.Tick(); |
1081 | |
1082 | // Recreate the depfile, as it should have been deleted by the build. |
1083 | fs_.Create("foo.o.d" , "foo.o: blah.h bar.h\n" ); |
1084 | |
1085 | // order only dep dirty, no rebuild. |
1086 | fs_.Create("otherfile" , "" ); |
1087 | command_runner_.commands_ran_.clear(); |
1088 | state_.Reset(); |
1089 | EXPECT_TRUE(builder_.AddTarget("foo.o" , &err)); |
1090 | EXPECT_EQ("" , err); |
1091 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
1092 | |
1093 | // implicit dep missing, expect rebuild. |
1094 | fs_.RemoveFile("bar.h" ); |
1095 | command_runner_.commands_ran_.clear(); |
1096 | state_.Reset(); |
1097 | EXPECT_TRUE(builder_.AddTarget("foo.o" , &err)); |
1098 | EXPECT_TRUE(builder_.Build(&err)); |
1099 | ASSERT_EQ("" , err); |
1100 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
1101 | } |
1102 | |
1103 | TEST_F(BuildTest, RebuildOrderOnlyDeps) { |
1104 | string err; |
1105 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1106 | "rule cc\n command = cc $in\n" |
1107 | "rule true\n command = true\n" |
1108 | "build oo.h: cc oo.h.in\n" |
1109 | "build foo.o: cc foo.c || oo.h\n" )); |
1110 | |
1111 | fs_.Create("foo.c" , "" ); |
1112 | fs_.Create("oo.h.in" , "" ); |
1113 | |
1114 | // foo.o and order-only dep dirty, build both. |
1115 | EXPECT_TRUE(builder_.AddTarget("foo.o" , &err)); |
1116 | EXPECT_TRUE(builder_.Build(&err)); |
1117 | ASSERT_EQ("" , err); |
1118 | ASSERT_EQ(2u, command_runner_.commands_ran_.size()); |
1119 | |
1120 | // all clean, no rebuild. |
1121 | command_runner_.commands_ran_.clear(); |
1122 | state_.Reset(); |
1123 | EXPECT_TRUE(builder_.AddTarget("foo.o" , &err)); |
1124 | EXPECT_EQ("" , err); |
1125 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
1126 | |
1127 | // order-only dep missing, build it only. |
1128 | fs_.RemoveFile("oo.h" ); |
1129 | command_runner_.commands_ran_.clear(); |
1130 | state_.Reset(); |
1131 | EXPECT_TRUE(builder_.AddTarget("foo.o" , &err)); |
1132 | EXPECT_TRUE(builder_.Build(&err)); |
1133 | ASSERT_EQ("" , err); |
1134 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
1135 | ASSERT_EQ("cc oo.h.in" , command_runner_.commands_ran_[0]); |
1136 | |
1137 | fs_.Tick(); |
1138 | |
1139 | // order-only dep dirty, build it only. |
1140 | fs_.Create("oo.h.in" , "" ); |
1141 | command_runner_.commands_ran_.clear(); |
1142 | state_.Reset(); |
1143 | EXPECT_TRUE(builder_.AddTarget("foo.o" , &err)); |
1144 | EXPECT_TRUE(builder_.Build(&err)); |
1145 | ASSERT_EQ("" , err); |
1146 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
1147 | ASSERT_EQ("cc oo.h.in" , command_runner_.commands_ran_[0]); |
1148 | } |
1149 | |
1150 | #ifdef _WIN32 |
1151 | TEST_F(BuildTest, DepFileCanonicalize) { |
1152 | string err; |
1153 | int orig_edges = state_.edges_.size(); |
1154 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1155 | "rule cc\n command = cc $in\n depfile = $out.d\n" |
1156 | "build gen/stuff\\things/foo.o: cc x\\y/z\\foo.c\n" )); |
1157 | Edge* edge = state_.edges_.back(); |
1158 | |
1159 | fs_.Create("x/y/z/foo.c" , "" ); |
1160 | GetNode("bar.h" )->MarkDirty(); // Mark bar.h as missing. |
1161 | // Note, different slashes from manifest. |
1162 | fs_.Create("gen/stuff\\things/foo.o.d" , |
1163 | "gen\\stuff\\things\\foo.o: blah.h bar.h\n" ); |
1164 | EXPECT_TRUE(builder_.AddTarget("gen/stuff/things/foo.o" , &err)); |
1165 | ASSERT_EQ("" , err); |
1166 | ASSERT_EQ(1u, fs_.files_read_.size()); |
1167 | // The depfile path does not get Canonicalize as it seems unnecessary. |
1168 | EXPECT_EQ("gen/stuff\\things/foo.o.d" , fs_.files_read_[0]); |
1169 | |
1170 | // Expect three new edges: one generating foo.o, and two more from |
1171 | // loading the depfile. |
1172 | ASSERT_EQ(orig_edges + 3, (int)state_.edges_.size()); |
1173 | // Expect our edge to now have three inputs: foo.c and two headers. |
1174 | ASSERT_EQ(3u, edge->inputs_.size()); |
1175 | |
1176 | // Expect the command line we generate to only use the original input, and |
1177 | // using the slashes from the manifest. |
1178 | ASSERT_EQ("cc x\\y/z\\foo.c" , edge->EvaluateCommand()); |
1179 | } |
1180 | #endif |
1181 | |
1182 | TEST_F(BuildTest, Phony) { |
1183 | string err; |
1184 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1185 | "build out: cat bar.cc\n" |
1186 | "build all: phony out\n" )); |
1187 | fs_.Create("bar.cc" , "" ); |
1188 | |
1189 | EXPECT_TRUE(builder_.AddTarget("all" , &err)); |
1190 | ASSERT_EQ("" , err); |
1191 | |
1192 | // Only one command to run, because phony runs no command. |
1193 | EXPECT_FALSE(builder_.AlreadyUpToDate()); |
1194 | EXPECT_TRUE(builder_.Build(&err)); |
1195 | ASSERT_EQ("" , err); |
1196 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
1197 | } |
1198 | |
1199 | TEST_F(BuildTest, PhonyNoWork) { |
1200 | string err; |
1201 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1202 | "build out: cat bar.cc\n" |
1203 | "build all: phony out\n" )); |
1204 | fs_.Create("bar.cc" , "" ); |
1205 | fs_.Create("out" , "" ); |
1206 | |
1207 | EXPECT_TRUE(builder_.AddTarget("all" , &err)); |
1208 | ASSERT_EQ("" , err); |
1209 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
1210 | } |
1211 | |
1212 | // Test a self-referencing phony. Ideally this should not work, but |
1213 | // ninja 1.7 and below tolerated and CMake 2.8.12.x and 3.0.x both |
1214 | // incorrectly produce it. We tolerate it for compatibility. |
1215 | TEST_F(BuildTest, PhonySelfReference) { |
1216 | string err; |
1217 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1218 | "build a: phony a\n" )); |
1219 | |
1220 | EXPECT_TRUE(builder_.AddTarget("a" , &err)); |
1221 | ASSERT_EQ("" , err); |
1222 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
1223 | } |
1224 | |
1225 | // There are 6 different cases for phony rules: |
1226 | // |
1227 | // 1. output edge does not exist, inputs are not real |
1228 | // 2. output edge does not exist, no inputs |
1229 | // 3. output edge does not exist, inputs are real, newest mtime is M |
1230 | // 4. output edge is real, inputs are not real |
1231 | // 5. output edge is real, no inputs |
1232 | // 6. output edge is real, inputs are real, newest mtime is M |
1233 | // |
1234 | // Expected results : |
1235 | // 1. Edge is marked as clean, mtime is newest mtime of dependents. |
1236 | // Touching inputs will cause dependents to rebuild. |
1237 | // 2. Edge is marked as dirty, causing dependent edges to always rebuild |
1238 | // 3. Edge is marked as clean, mtime is newest mtime of dependents. |
1239 | // Touching inputs will cause dependents to rebuild. |
1240 | // 4. Edge is marked as clean, mtime is newest mtime of dependents. |
1241 | // Touching inputs will cause dependents to rebuild. |
1242 | // 5. Edge is marked as dirty, causing dependent edges to always rebuild |
1243 | // 6. Edge is marked as clean, mtime is newest mtime of dependents. |
1244 | // Touching inputs will cause dependents to rebuild. |
1245 | void TestPhonyUseCase(BuildTest* t, int i) { |
1246 | State& state_ = t->state_; |
1247 | Builder& builder_ = t->builder_; |
1248 | FakeCommandRunner& command_runner_ = t->command_runner_; |
1249 | VirtualFileSystem& fs_ = t->fs_; |
1250 | |
1251 | string err; |
1252 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1253 | "rule touch\n" |
1254 | " command = touch $out\n" |
1255 | "build notreal: phony blank\n" |
1256 | "build phony1: phony notreal\n" |
1257 | "build phony2: phony\n" |
1258 | "build phony3: phony blank\n" |
1259 | "build phony4: phony notreal\n" |
1260 | "build phony5: phony\n" |
1261 | "build phony6: phony blank\n" |
1262 | "\n" |
1263 | "build test1: touch phony1\n" |
1264 | "build test2: touch phony2\n" |
1265 | "build test3: touch phony3\n" |
1266 | "build test4: touch phony4\n" |
1267 | "build test5: touch phony5\n" |
1268 | "build test6: touch phony6\n" |
1269 | )); |
1270 | |
1271 | // Set up test. |
1272 | builder_.command_runner_.release(); // BuildTest owns the CommandRunner |
1273 | builder_.command_runner_.reset(&command_runner_); |
1274 | |
1275 | fs_.Create("blank" , "" ); // a "real" file |
1276 | EXPECT_TRUE(builder_.AddTarget("test1" , &err)); |
1277 | ASSERT_EQ("" , err); |
1278 | EXPECT_TRUE(builder_.AddTarget("test2" , &err)); |
1279 | ASSERT_EQ("" , err); |
1280 | EXPECT_TRUE(builder_.AddTarget("test3" , &err)); |
1281 | ASSERT_EQ("" , err); |
1282 | EXPECT_TRUE(builder_.AddTarget("test4" , &err)); |
1283 | ASSERT_EQ("" , err); |
1284 | EXPECT_TRUE(builder_.AddTarget("test5" , &err)); |
1285 | ASSERT_EQ("" , err); |
1286 | EXPECT_TRUE(builder_.AddTarget("test6" , &err)); |
1287 | ASSERT_EQ("" , err); |
1288 | EXPECT_TRUE(builder_.Build(&err)); |
1289 | ASSERT_EQ("" , err); |
1290 | |
1291 | string ci; |
1292 | ci += static_cast<char>('0' + i); |
1293 | |
1294 | // Tests 1, 3, 4, and 6 should rebuild when the input is updated. |
1295 | if (i != 2 && i != 5) { |
1296 | Node* testNode = t->GetNode("test" + ci); |
1297 | Node* phonyNode = t->GetNode("phony" + ci); |
1298 | Node* inputNode = t->GetNode("blank" ); |
1299 | |
1300 | state_.Reset(); |
1301 | TimeStamp startTime = fs_.now_; |
1302 | |
1303 | // Build number 1 |
1304 | EXPECT_TRUE(builder_.AddTarget("test" + ci, &err)); |
1305 | ASSERT_EQ("" , err); |
1306 | if (!builder_.AlreadyUpToDate()) |
1307 | EXPECT_TRUE(builder_.Build(&err)); |
1308 | ASSERT_EQ("" , err); |
1309 | |
1310 | // Touch the input file |
1311 | state_.Reset(); |
1312 | command_runner_.commands_ran_.clear(); |
1313 | fs_.Tick(); |
1314 | fs_.Create("blank" , "" ); // a "real" file |
1315 | EXPECT_TRUE(builder_.AddTarget("test" + ci, &err)); |
1316 | ASSERT_EQ("" , err); |
1317 | |
1318 | // Second build, expect testN edge to be rebuilt |
1319 | // and phonyN node's mtime to be updated. |
1320 | EXPECT_FALSE(builder_.AlreadyUpToDate()); |
1321 | EXPECT_TRUE(builder_.Build(&err)); |
1322 | ASSERT_EQ("" , err); |
1323 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
1324 | EXPECT_EQ(string("touch test" ) + ci, command_runner_.commands_ran_[0]); |
1325 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
1326 | |
1327 | TimeStamp inputTime = inputNode->mtime(); |
1328 | |
1329 | EXPECT_FALSE(phonyNode->exists()); |
1330 | EXPECT_FALSE(phonyNode->dirty()); |
1331 | |
1332 | EXPECT_GT(phonyNode->mtime(), startTime); |
1333 | EXPECT_EQ(phonyNode->mtime(), inputTime); |
1334 | ASSERT_TRUE(testNode->Stat(&fs_, &err)); |
1335 | EXPECT_TRUE(testNode->exists()); |
1336 | EXPECT_GT(testNode->mtime(), startTime); |
1337 | } else { |
1338 | // Tests 2 and 5: Expect dependents to always rebuild. |
1339 | |
1340 | state_.Reset(); |
1341 | command_runner_.commands_ran_.clear(); |
1342 | fs_.Tick(); |
1343 | command_runner_.commands_ran_.clear(); |
1344 | EXPECT_TRUE(builder_.AddTarget("test" + ci, &err)); |
1345 | ASSERT_EQ("" , err); |
1346 | EXPECT_FALSE(builder_.AlreadyUpToDate()); |
1347 | EXPECT_TRUE(builder_.Build(&err)); |
1348 | ASSERT_EQ("" , err); |
1349 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
1350 | EXPECT_EQ("touch test" + ci, command_runner_.commands_ran_[0]); |
1351 | |
1352 | state_.Reset(); |
1353 | command_runner_.commands_ran_.clear(); |
1354 | EXPECT_TRUE(builder_.AddTarget("test" + ci, &err)); |
1355 | ASSERT_EQ("" , err); |
1356 | EXPECT_FALSE(builder_.AlreadyUpToDate()); |
1357 | EXPECT_TRUE(builder_.Build(&err)); |
1358 | ASSERT_EQ("" , err); |
1359 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
1360 | EXPECT_EQ("touch test" + ci, command_runner_.commands_ran_[0]); |
1361 | } |
1362 | } |
1363 | |
1364 | TEST_F(BuildTest, PhonyUseCase1) { TestPhonyUseCase(this, 1); } |
1365 | TEST_F(BuildTest, PhonyUseCase2) { TestPhonyUseCase(this, 2); } |
1366 | TEST_F(BuildTest, PhonyUseCase3) { TestPhonyUseCase(this, 3); } |
1367 | TEST_F(BuildTest, PhonyUseCase4) { TestPhonyUseCase(this, 4); } |
1368 | TEST_F(BuildTest, PhonyUseCase5) { TestPhonyUseCase(this, 5); } |
1369 | TEST_F(BuildTest, PhonyUseCase6) { TestPhonyUseCase(this, 6); } |
1370 | |
1371 | TEST_F(BuildTest, Fail) { |
1372 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1373 | "rule fail\n" |
1374 | " command = fail\n" |
1375 | "build out1: fail\n" )); |
1376 | |
1377 | string err; |
1378 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
1379 | ASSERT_EQ("" , err); |
1380 | |
1381 | EXPECT_FALSE(builder_.Build(&err)); |
1382 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
1383 | ASSERT_EQ("subcommand failed" , err); |
1384 | } |
1385 | |
1386 | TEST_F(BuildTest, SwallowFailures) { |
1387 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1388 | "rule fail\n" |
1389 | " command = fail\n" |
1390 | "build out1: fail\n" |
1391 | "build out2: fail\n" |
1392 | "build out3: fail\n" |
1393 | "build all: phony out1 out2 out3\n" )); |
1394 | |
1395 | // Swallow two failures, die on the third. |
1396 | config_.failures_allowed = 3; |
1397 | |
1398 | string err; |
1399 | EXPECT_TRUE(builder_.AddTarget("all" , &err)); |
1400 | ASSERT_EQ("" , err); |
1401 | |
1402 | EXPECT_FALSE(builder_.Build(&err)); |
1403 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
1404 | ASSERT_EQ("subcommands failed" , err); |
1405 | } |
1406 | |
1407 | TEST_F(BuildTest, SwallowFailuresLimit) { |
1408 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1409 | "rule fail\n" |
1410 | " command = fail\n" |
1411 | "build out1: fail\n" |
1412 | "build out2: fail\n" |
1413 | "build out3: fail\n" |
1414 | "build final: cat out1 out2 out3\n" )); |
1415 | |
1416 | // Swallow ten failures; we should stop before building final. |
1417 | config_.failures_allowed = 11; |
1418 | |
1419 | string err; |
1420 | EXPECT_TRUE(builder_.AddTarget("final" , &err)); |
1421 | ASSERT_EQ("" , err); |
1422 | |
1423 | EXPECT_FALSE(builder_.Build(&err)); |
1424 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
1425 | ASSERT_EQ("cannot make progress due to previous errors" , err); |
1426 | } |
1427 | |
1428 | TEST_F(BuildTest, SwallowFailuresPool) { |
1429 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1430 | "pool failpool\n" |
1431 | " depth = 1\n" |
1432 | "rule fail\n" |
1433 | " command = fail\n" |
1434 | " pool = failpool\n" |
1435 | "build out1: fail\n" |
1436 | "build out2: fail\n" |
1437 | "build out3: fail\n" |
1438 | "build final: cat out1 out2 out3\n" )); |
1439 | |
1440 | // Swallow ten failures; we should stop before building final. |
1441 | config_.failures_allowed = 11; |
1442 | |
1443 | string err; |
1444 | EXPECT_TRUE(builder_.AddTarget("final" , &err)); |
1445 | ASSERT_EQ("" , err); |
1446 | |
1447 | EXPECT_FALSE(builder_.Build(&err)); |
1448 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
1449 | ASSERT_EQ("cannot make progress due to previous errors" , err); |
1450 | } |
1451 | |
1452 | TEST_F(BuildTest, PoolEdgesReadyButNotWanted) { |
1453 | fs_.Create("x" , "" ); |
1454 | |
1455 | const char* manifest = |
1456 | "pool some_pool\n" |
1457 | " depth = 4\n" |
1458 | "rule touch\n" |
1459 | " command = touch $out\n" |
1460 | " pool = some_pool\n" |
1461 | "rule cc\n" |
1462 | " command = touch grit\n" |
1463 | "\n" |
1464 | "build B.d.stamp: cc | x\n" |
1465 | "build C.stamp: touch B.d.stamp\n" |
1466 | "build final.stamp: touch || C.stamp\n" ; |
1467 | |
1468 | RebuildTarget("final.stamp" , manifest); |
1469 | |
1470 | fs_.RemoveFile("B.d.stamp" ); |
1471 | |
1472 | State save_state; |
1473 | RebuildTarget("final.stamp" , manifest, NULL, NULL, &save_state); |
1474 | EXPECT_GE(save_state.LookupPool("some_pool" )->current_use(), 0); |
1475 | } |
1476 | |
1477 | struct BuildWithLogTest : public BuildTest { |
1478 | BuildWithLogTest() { |
1479 | builder_.SetBuildLog(&build_log_); |
1480 | } |
1481 | |
1482 | BuildLog build_log_; |
1483 | }; |
1484 | |
1485 | TEST_F(BuildWithLogTest, ImplicitGeneratedOutOfDate) { |
1486 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1487 | "rule touch\n" |
1488 | " command = touch $out\n" |
1489 | " generator = 1\n" |
1490 | "build out.imp: touch | in\n" )); |
1491 | fs_.Create("out.imp" , "" ); |
1492 | fs_.Tick(); |
1493 | fs_.Create("in" , "" ); |
1494 | |
1495 | string err; |
1496 | |
1497 | EXPECT_TRUE(builder_.AddTarget("out.imp" , &err)); |
1498 | EXPECT_FALSE(builder_.AlreadyUpToDate()); |
1499 | |
1500 | EXPECT_TRUE(GetNode("out.imp" )->dirty()); |
1501 | } |
1502 | |
1503 | TEST_F(BuildWithLogTest, ImplicitGeneratedOutOfDate2) { |
1504 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1505 | "rule touch-implicit-dep-out\n" |
1506 | " command = sleep 1 ; touch $test_dependency ; sleep 1 ; touch $out\n" |
1507 | " generator = 1\n" |
1508 | "build out.imp: touch-implicit-dep-out | inimp inimp2\n" |
1509 | " test_dependency = inimp\n" )); |
1510 | fs_.Create("inimp" , "" ); |
1511 | fs_.Create("out.imp" , "" ); |
1512 | fs_.Tick(); |
1513 | fs_.Create("inimp2" , "" ); |
1514 | fs_.Tick(); |
1515 | |
1516 | string err; |
1517 | |
1518 | EXPECT_TRUE(builder_.AddTarget("out.imp" , &err)); |
1519 | EXPECT_FALSE(builder_.AlreadyUpToDate()); |
1520 | |
1521 | EXPECT_TRUE(builder_.Build(&err)); |
1522 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
1523 | |
1524 | command_runner_.commands_ran_.clear(); |
1525 | state_.Reset(); |
1526 | builder_.Cleanup(); |
1527 | builder_.plan_.Reset(); |
1528 | |
1529 | EXPECT_TRUE(builder_.AddTarget("out.imp" , &err)); |
1530 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
1531 | EXPECT_FALSE(GetNode("out.imp" )->dirty()); |
1532 | |
1533 | command_runner_.commands_ran_.clear(); |
1534 | state_.Reset(); |
1535 | builder_.Cleanup(); |
1536 | builder_.plan_.Reset(); |
1537 | |
1538 | fs_.Tick(); |
1539 | fs_.Create("inimp" , "" ); |
1540 | |
1541 | EXPECT_TRUE(builder_.AddTarget("out.imp" , &err)); |
1542 | EXPECT_FALSE(builder_.AlreadyUpToDate()); |
1543 | |
1544 | EXPECT_TRUE(builder_.Build(&err)); |
1545 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
1546 | |
1547 | command_runner_.commands_ran_.clear(); |
1548 | state_.Reset(); |
1549 | builder_.Cleanup(); |
1550 | builder_.plan_.Reset(); |
1551 | |
1552 | EXPECT_TRUE(builder_.AddTarget("out.imp" , &err)); |
1553 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
1554 | EXPECT_FALSE(GetNode("out.imp" )->dirty()); |
1555 | } |
1556 | |
1557 | TEST_F(BuildWithLogTest, NotInLogButOnDisk) { |
1558 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1559 | "rule cc\n" |
1560 | " command = cc\n" |
1561 | "build out1: cc in\n" )); |
1562 | |
1563 | // Create input/output that would be considered up to date when |
1564 | // not considering the command line hash. |
1565 | fs_.Create("in" , "" ); |
1566 | fs_.Create("out1" , "" ); |
1567 | string err; |
1568 | |
1569 | // Because it's not in the log, it should not be up-to-date until |
1570 | // we build again. |
1571 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
1572 | EXPECT_FALSE(builder_.AlreadyUpToDate()); |
1573 | |
1574 | command_runner_.commands_ran_.clear(); |
1575 | state_.Reset(); |
1576 | |
1577 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
1578 | EXPECT_TRUE(builder_.Build(&err)); |
1579 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
1580 | } |
1581 | |
1582 | TEST_F(BuildWithLogTest, RebuildAfterFailure) { |
1583 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1584 | "rule touch-fail-tick2\n" |
1585 | " command = touch-fail-tick2\n" |
1586 | "build out1: touch-fail-tick2 in\n" )); |
1587 | |
1588 | string err; |
1589 | |
1590 | fs_.Create("in" , "" ); |
1591 | |
1592 | // Run once successfully to get out1 in the log |
1593 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
1594 | EXPECT_TRUE(builder_.Build(&err)); |
1595 | EXPECT_EQ("" , err); |
1596 | EXPECT_EQ(1u, command_runner_.commands_ran_.size()); |
1597 | |
1598 | command_runner_.commands_ran_.clear(); |
1599 | state_.Reset(); |
1600 | builder_.Cleanup(); |
1601 | builder_.plan_.Reset(); |
1602 | |
1603 | fs_.Tick(); |
1604 | fs_.Create("in" , "" ); |
1605 | |
1606 | // Run again with a failure that updates the output file timestamp |
1607 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
1608 | EXPECT_FALSE(builder_.Build(&err)); |
1609 | EXPECT_EQ("subcommand failed" , err); |
1610 | EXPECT_EQ(1u, command_runner_.commands_ran_.size()); |
1611 | |
1612 | command_runner_.commands_ran_.clear(); |
1613 | state_.Reset(); |
1614 | builder_.Cleanup(); |
1615 | builder_.plan_.Reset(); |
1616 | |
1617 | fs_.Tick(); |
1618 | |
1619 | // Run again, should rerun even though the output file is up to date on disk |
1620 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
1621 | EXPECT_FALSE(builder_.AlreadyUpToDate()); |
1622 | EXPECT_TRUE(builder_.Build(&err)); |
1623 | EXPECT_EQ(1u, command_runner_.commands_ran_.size()); |
1624 | EXPECT_EQ("" , err); |
1625 | } |
1626 | |
1627 | TEST_F(BuildWithLogTest, RebuildWithNoInputs) { |
1628 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1629 | "rule touch\n" |
1630 | " command = touch\n" |
1631 | "build out1: touch\n" |
1632 | "build out2: touch in\n" )); |
1633 | |
1634 | string err; |
1635 | |
1636 | fs_.Create("in" , "" ); |
1637 | |
1638 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
1639 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
1640 | EXPECT_TRUE(builder_.Build(&err)); |
1641 | EXPECT_EQ("" , err); |
1642 | EXPECT_EQ(2u, command_runner_.commands_ran_.size()); |
1643 | |
1644 | command_runner_.commands_ran_.clear(); |
1645 | state_.Reset(); |
1646 | |
1647 | fs_.Tick(); |
1648 | |
1649 | fs_.Create("in" , "" ); |
1650 | |
1651 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
1652 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
1653 | EXPECT_TRUE(builder_.Build(&err)); |
1654 | EXPECT_EQ("" , err); |
1655 | EXPECT_EQ(1u, command_runner_.commands_ran_.size()); |
1656 | } |
1657 | |
1658 | TEST_F(BuildWithLogTest, RestatTest) { |
1659 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1660 | "rule true\n" |
1661 | " command = true\n" |
1662 | " restat = 1\n" |
1663 | "rule cc\n" |
1664 | " command = cc\n" |
1665 | " restat = 1\n" |
1666 | "build out1: cc in\n" |
1667 | "build out2: true out1\n" |
1668 | "build out3: cat out2\n" )); |
1669 | |
1670 | fs_.Create("out1" , "" ); |
1671 | fs_.Create("out2" , "" ); |
1672 | fs_.Create("out3" , "" ); |
1673 | |
1674 | fs_.Tick(); |
1675 | |
1676 | fs_.Create("in" , "" ); |
1677 | |
1678 | // Do a pre-build so that there's commands in the log for the outputs, |
1679 | // otherwise, the lack of an entry in the build log will cause out3 to rebuild |
1680 | // regardless of restat. |
1681 | string err; |
1682 | EXPECT_TRUE(builder_.AddTarget("out3" , &err)); |
1683 | ASSERT_EQ("" , err); |
1684 | EXPECT_TRUE(builder_.Build(&err)); |
1685 | ASSERT_EQ("" , err); |
1686 | EXPECT_EQ(3u, command_runner_.commands_ran_.size()); |
1687 | EXPECT_EQ(3u, builder_.plan_.command_edge_count()); |
1688 | command_runner_.commands_ran_.clear(); |
1689 | state_.Reset(); |
1690 | |
1691 | fs_.Tick(); |
1692 | |
1693 | fs_.Create("in" , "" ); |
1694 | // "cc" touches out1, so we should build out2. But because "true" does not |
1695 | // touch out2, we should cancel the build of out3. |
1696 | EXPECT_TRUE(builder_.AddTarget("out3" , &err)); |
1697 | ASSERT_EQ("" , err); |
1698 | EXPECT_TRUE(builder_.Build(&err)); |
1699 | ASSERT_EQ(2u, command_runner_.commands_ran_.size()); |
1700 | |
1701 | // If we run again, it should be a no-op, because the build log has recorded |
1702 | // that we've already built out2 with an input timestamp of 2 (from out1). |
1703 | command_runner_.commands_ran_.clear(); |
1704 | state_.Reset(); |
1705 | EXPECT_TRUE(builder_.AddTarget("out3" , &err)); |
1706 | ASSERT_EQ("" , err); |
1707 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
1708 | |
1709 | fs_.Tick(); |
1710 | |
1711 | fs_.Create("in" , "" ); |
1712 | |
1713 | // The build log entry should not, however, prevent us from rebuilding out2 |
1714 | // if out1 changes. |
1715 | command_runner_.commands_ran_.clear(); |
1716 | state_.Reset(); |
1717 | EXPECT_TRUE(builder_.AddTarget("out3" , &err)); |
1718 | ASSERT_EQ("" , err); |
1719 | EXPECT_TRUE(builder_.Build(&err)); |
1720 | ASSERT_EQ(2u, command_runner_.commands_ran_.size()); |
1721 | } |
1722 | |
1723 | TEST_F(BuildWithLogTest, RestatMissingFile) { |
1724 | // If a restat rule doesn't create its output, and the output didn't |
1725 | // exist before the rule was run, consider that behavior equivalent |
1726 | // to a rule that doesn't modify its existent output file. |
1727 | |
1728 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1729 | "rule true\n" |
1730 | " command = true\n" |
1731 | " restat = 1\n" |
1732 | "rule cc\n" |
1733 | " command = cc\n" |
1734 | "build out1: true in\n" |
1735 | "build out2: cc out1\n" )); |
1736 | |
1737 | fs_.Create("in" , "" ); |
1738 | fs_.Create("out2" , "" ); |
1739 | |
1740 | // Do a pre-build so that there's commands in the log for the outputs, |
1741 | // otherwise, the lack of an entry in the build log will cause out2 to rebuild |
1742 | // regardless of restat. |
1743 | string err; |
1744 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
1745 | ASSERT_EQ("" , err); |
1746 | EXPECT_TRUE(builder_.Build(&err)); |
1747 | ASSERT_EQ("" , err); |
1748 | command_runner_.commands_ran_.clear(); |
1749 | state_.Reset(); |
1750 | |
1751 | fs_.Tick(); |
1752 | fs_.Create("in" , "" ); |
1753 | fs_.Create("out2" , "" ); |
1754 | |
1755 | // Run a build, expect only the first command to run. |
1756 | // It doesn't touch its output (due to being the "true" command), so |
1757 | // we shouldn't run the dependent build. |
1758 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
1759 | ASSERT_EQ("" , err); |
1760 | EXPECT_TRUE(builder_.Build(&err)); |
1761 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
1762 | } |
1763 | |
1764 | TEST_F(BuildWithLogTest, RestatSingleDependentOutputDirty) { |
1765 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1766 | "rule true\n" |
1767 | " command = true\n" |
1768 | " restat = 1\n" |
1769 | "rule touch\n" |
1770 | " command = touch\n" |
1771 | "build out1: true in\n" |
1772 | "build out2 out3: touch out1\n" |
1773 | "build out4: touch out2\n" |
1774 | )); |
1775 | |
1776 | // Create the necessary files |
1777 | fs_.Create("in" , "" ); |
1778 | |
1779 | string err; |
1780 | EXPECT_TRUE(builder_.AddTarget("out4" , &err)); |
1781 | ASSERT_EQ("" , err); |
1782 | EXPECT_TRUE(builder_.Build(&err)); |
1783 | ASSERT_EQ("" , err); |
1784 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
1785 | |
1786 | fs_.Tick(); |
1787 | fs_.Create("in" , "" ); |
1788 | fs_.RemoveFile("out3" ); |
1789 | |
1790 | // Since "in" is missing, out1 will be built. Since "out3" is missing, |
1791 | // out2 and out3 will be built even though "in" is not touched when built. |
1792 | // Then, since out2 is rebuilt, out4 should be rebuilt -- the restat on the |
1793 | // "true" rule should not lead to the "touch" edge writing out2 and out3 being |
1794 | // cleard. |
1795 | command_runner_.commands_ran_.clear(); |
1796 | state_.Reset(); |
1797 | EXPECT_TRUE(builder_.AddTarget("out4" , &err)); |
1798 | ASSERT_EQ("" , err); |
1799 | EXPECT_TRUE(builder_.Build(&err)); |
1800 | ASSERT_EQ("" , err); |
1801 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
1802 | } |
1803 | |
1804 | // Test scenario, in which an input file is removed, but output isn't changed |
1805 | // https://github.com/ninja-build/ninja/issues/295 |
1806 | TEST_F(BuildWithLogTest, RestatMissingInput) { |
1807 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1808 | "rule true\n" |
1809 | " command = true\n" |
1810 | " depfile = $out.d\n" |
1811 | " restat = 1\n" |
1812 | "rule cc\n" |
1813 | " command = cc\n" |
1814 | "build out1: true in\n" |
1815 | "build out2: cc out1\n" )); |
1816 | |
1817 | // Create all necessary files |
1818 | fs_.Create("in" , "" ); |
1819 | |
1820 | // The implicit dependencies and the depfile itself |
1821 | // are newer than the output |
1822 | TimeStamp restat_mtime = fs_.Tick(); |
1823 | fs_.Create("out1.d" , "out1: will.be.deleted restat.file\n" ); |
1824 | fs_.Create("will.be.deleted" , "" ); |
1825 | fs_.Create("restat.file" , "" ); |
1826 | |
1827 | // Run the build, out1 and out2 get built |
1828 | string err; |
1829 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
1830 | ASSERT_EQ("" , err); |
1831 | EXPECT_TRUE(builder_.Build(&err)); |
1832 | ASSERT_EQ(2u, command_runner_.commands_ran_.size()); |
1833 | |
1834 | // See that an entry in the logfile is created, capturing |
1835 | // the right mtime |
1836 | BuildLog::LogEntry* log_entry = build_log_.LookupByOutput("out1" ); |
1837 | ASSERT_TRUE(NULL != log_entry); |
1838 | ASSERT_EQ(restat_mtime, log_entry->mtime); |
1839 | |
1840 | // Now remove a file, referenced from depfile, so that target becomes |
1841 | // dirty, but the output does not change |
1842 | fs_.RemoveFile("will.be.deleted" ); |
1843 | |
1844 | // Trigger the build again - only out1 gets built |
1845 | command_runner_.commands_ran_.clear(); |
1846 | state_.Reset(); |
1847 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
1848 | ASSERT_EQ("" , err); |
1849 | EXPECT_TRUE(builder_.Build(&err)); |
1850 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
1851 | |
1852 | // Check that the logfile entry remains correctly set |
1853 | log_entry = build_log_.LookupByOutput("out1" ); |
1854 | ASSERT_TRUE(NULL != log_entry); |
1855 | ASSERT_EQ(restat_mtime, log_entry->mtime); |
1856 | } |
1857 | |
1858 | TEST_F(BuildWithLogTest, RestatInputChangesDueToRule) { |
1859 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1860 | "rule generate-depfile\n" |
1861 | " command = sleep 1 ; touch $touch_dependency; touch $out ; echo \"$out: $test_dependency\" > $depfile\n" |
1862 | "build out1: generate-depfile || cat1\n" |
1863 | " test_dependency = in2\n" |
1864 | " touch_dependency = 1\n" |
1865 | " restat = 1\n" |
1866 | " depfile = out.d\n" )); |
1867 | |
1868 | // Perform the first build. out1 is a restat rule, so its recorded mtime in the build |
1869 | // log should be the time the command completes, not the time the command started. One |
1870 | // of out1's discovered dependencies will have a newer mtime than when out1 started |
1871 | // running, due to its command touching the dependency itself. |
1872 | string err; |
1873 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
1874 | ASSERT_EQ("" , err); |
1875 | EXPECT_TRUE(builder_.Build(&err)); |
1876 | ASSERT_EQ("" , err); |
1877 | EXPECT_EQ(2u, command_runner_.commands_ran_.size()); |
1878 | EXPECT_EQ(2u, builder_.plan_.command_edge_count()); |
1879 | BuildLog::LogEntry* log_entry = build_log_.LookupByOutput("out1" ); |
1880 | ASSERT_TRUE(NULL != log_entry); |
1881 | ASSERT_EQ(2u, log_entry->mtime); |
1882 | |
1883 | command_runner_.commands_ran_.clear(); |
1884 | state_.Reset(); |
1885 | builder_.Cleanup(); |
1886 | builder_.plan_.Reset(); |
1887 | |
1888 | fs_.Tick(); |
1889 | fs_.Create("in1" , "" ); |
1890 | |
1891 | // Touching a dependency of an order-only dependency of out1 should not cause out1 to |
1892 | // rebuild. If out1 were not a restat rule, then it would rebuild here because its |
1893 | // recorded mtime would have been an earlier mtime than its most recent input's (in2) |
1894 | // mtime |
1895 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
1896 | ASSERT_EQ("" , err); |
1897 | EXPECT_TRUE(!state_.GetNode("out1" , 0)->dirty()); |
1898 | EXPECT_TRUE(builder_.Build(&err)); |
1899 | ASSERT_EQ("" , err); |
1900 | EXPECT_EQ(1u, command_runner_.commands_ran_.size()); |
1901 | EXPECT_EQ(1u, builder_.plan_.command_edge_count()); |
1902 | } |
1903 | |
1904 | TEST_F(BuildWithLogTest, GeneratedPlainDepfileMtime) { |
1905 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1906 | "rule generate-depfile\n" |
1907 | " command = touch $out ; echo \"$out: $test_dependency\" > $depfile\n" |
1908 | "build out: generate-depfile\n" |
1909 | " test_dependency = inimp\n" |
1910 | " depfile = out.d\n" )); |
1911 | fs_.Create("inimp" , "" ); |
1912 | fs_.Tick(); |
1913 | |
1914 | string err; |
1915 | |
1916 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
1917 | EXPECT_FALSE(builder_.AlreadyUpToDate()); |
1918 | |
1919 | EXPECT_TRUE(builder_.Build(&err)); |
1920 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
1921 | |
1922 | command_runner_.commands_ran_.clear(); |
1923 | state_.Reset(); |
1924 | builder_.Cleanup(); |
1925 | builder_.plan_.Reset(); |
1926 | |
1927 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
1928 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
1929 | } |
1930 | |
1931 | struct BuildDryRun : public BuildWithLogTest { |
1932 | BuildDryRun() { |
1933 | config_.dry_run = true; |
1934 | } |
1935 | }; |
1936 | |
1937 | TEST_F(BuildDryRun, AllCommandsShown) { |
1938 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1939 | "rule true\n" |
1940 | " command = true\n" |
1941 | " restat = 1\n" |
1942 | "rule cc\n" |
1943 | " command = cc\n" |
1944 | " restat = 1\n" |
1945 | "build out1: cc in\n" |
1946 | "build out2: true out1\n" |
1947 | "build out3: cat out2\n" )); |
1948 | |
1949 | fs_.Create("out1" , "" ); |
1950 | fs_.Create("out2" , "" ); |
1951 | fs_.Create("out3" , "" ); |
1952 | |
1953 | fs_.Tick(); |
1954 | |
1955 | fs_.Create("in" , "" ); |
1956 | |
1957 | // "cc" touches out1, so we should build out2. But because "true" does not |
1958 | // touch out2, we should cancel the build of out3. |
1959 | string err; |
1960 | EXPECT_TRUE(builder_.AddTarget("out3" , &err)); |
1961 | ASSERT_EQ("" , err); |
1962 | EXPECT_TRUE(builder_.Build(&err)); |
1963 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
1964 | } |
1965 | |
1966 | // Test that RSP files are created when & where appropriate and deleted after |
1967 | // successful execution. |
1968 | TEST_F(BuildTest, RspFileSuccess) |
1969 | { |
1970 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
1971 | "rule cat_rsp\n" |
1972 | " command = cat $rspfile > $out\n" |
1973 | " rspfile = $rspfile\n" |
1974 | " rspfile_content = $long_command\n" |
1975 | "rule cat_rsp_out\n" |
1976 | " command = cat $rspfile > $out\n" |
1977 | " rspfile = $out.rsp\n" |
1978 | " rspfile_content = $long_command\n" |
1979 | "build out1: cat in\n" |
1980 | "build out2: cat_rsp in\n" |
1981 | " rspfile = out 2.rsp\n" |
1982 | " long_command = Some very long command\n" |
1983 | "build out$ 3: cat_rsp_out in\n" |
1984 | " long_command = Some very long command\n" )); |
1985 | |
1986 | fs_.Create("out1" , "" ); |
1987 | fs_.Create("out2" , "" ); |
1988 | fs_.Create("out 3" , "" ); |
1989 | |
1990 | fs_.Tick(); |
1991 | |
1992 | fs_.Create("in" , "" ); |
1993 | |
1994 | string err; |
1995 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
1996 | ASSERT_EQ("" , err); |
1997 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
1998 | ASSERT_EQ("" , err); |
1999 | EXPECT_TRUE(builder_.AddTarget("out 3" , &err)); |
2000 | ASSERT_EQ("" , err); |
2001 | |
2002 | size_t files_created = fs_.files_created_.size(); |
2003 | size_t files_removed = fs_.files_removed_.size(); |
2004 | |
2005 | EXPECT_TRUE(builder_.Build(&err)); |
2006 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
2007 | |
2008 | // The RSP files and temp file to acquire output mtimes were created |
2009 | ASSERT_EQ(files_created + 3, fs_.files_created_.size()); |
2010 | ASSERT_EQ(1u, fs_.files_created_.count("out 2.rsp" )); |
2011 | ASSERT_EQ(1u, fs_.files_created_.count("out 3.rsp" )); |
2012 | ASSERT_EQ(1u, fs_.files_created_.count(".ninja_lock" )); |
2013 | |
2014 | // The RSP files were removed |
2015 | ASSERT_EQ(files_removed + 2, fs_.files_removed_.size()); |
2016 | ASSERT_EQ(1u, fs_.files_removed_.count("out 2.rsp" )); |
2017 | ASSERT_EQ(1u, fs_.files_removed_.count("out 3.rsp" )); |
2018 | } |
2019 | |
2020 | // Test that RSP file is created but not removed for commands, which fail |
2021 | TEST_F(BuildTest, RspFileFailure) { |
2022 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2023 | "rule fail\n" |
2024 | " command = fail\n" |
2025 | " rspfile = $rspfile\n" |
2026 | " rspfile_content = $long_command\n" |
2027 | "build out: fail in\n" |
2028 | " rspfile = out.rsp\n" |
2029 | " long_command = Another very long command\n" )); |
2030 | |
2031 | fs_.Create("out" , "" ); |
2032 | fs_.Tick(); |
2033 | fs_.Create("in" , "" ); |
2034 | |
2035 | string err; |
2036 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
2037 | ASSERT_EQ("" , err); |
2038 | |
2039 | size_t files_created = fs_.files_created_.size(); |
2040 | size_t files_removed = fs_.files_removed_.size(); |
2041 | |
2042 | EXPECT_FALSE(builder_.Build(&err)); |
2043 | ASSERT_EQ("subcommand failed" , err); |
2044 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2045 | |
2046 | // The RSP file and temp file to acquire output mtimes were created |
2047 | ASSERT_EQ(files_created + 2, fs_.files_created_.size()); |
2048 | ASSERT_EQ(1u, fs_.files_created_.count("out.rsp" )); |
2049 | ASSERT_EQ(1u, fs_.files_created_.count(".ninja_lock" )); |
2050 | |
2051 | // The RSP file was NOT removed |
2052 | ASSERT_EQ(files_removed, fs_.files_removed_.size()); |
2053 | ASSERT_EQ(0u, fs_.files_removed_.count("out.rsp" )); |
2054 | |
2055 | // The RSP file contains what it should |
2056 | ASSERT_EQ("Another very long command" , fs_.files_["out.rsp" ].contents); |
2057 | } |
2058 | |
2059 | // Test that contents of the RSP file behaves like a regular part of |
2060 | // command line, i.e. triggers a rebuild if changed |
2061 | TEST_F(BuildWithLogTest, RspFileCmdLineChange) { |
2062 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2063 | "rule cat_rsp\n" |
2064 | " command = cat $rspfile > $out\n" |
2065 | " rspfile = $rspfile\n" |
2066 | " rspfile_content = $long_command\n" |
2067 | "build out: cat_rsp in\n" |
2068 | " rspfile = out.rsp\n" |
2069 | " long_command = Original very long command\n" )); |
2070 | |
2071 | fs_.Create("out" , "" ); |
2072 | fs_.Tick(); |
2073 | fs_.Create("in" , "" ); |
2074 | |
2075 | string err; |
2076 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
2077 | ASSERT_EQ("" , err); |
2078 | |
2079 | // 1. Build for the 1st time (-> populate log) |
2080 | EXPECT_TRUE(builder_.Build(&err)); |
2081 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2082 | |
2083 | // 2. Build again (no change) |
2084 | command_runner_.commands_ran_.clear(); |
2085 | state_.Reset(); |
2086 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
2087 | EXPECT_EQ("" , err); |
2088 | ASSERT_TRUE(builder_.AlreadyUpToDate()); |
2089 | |
2090 | // 3. Alter the entry in the logfile |
2091 | // (to simulate a change in the command line between 2 builds) |
2092 | BuildLog::LogEntry* log_entry = build_log_.LookupByOutput("out" ); |
2093 | ASSERT_TRUE(NULL != log_entry); |
2094 | ASSERT_NO_FATAL_FAILURE(AssertHash( |
2095 | "cat out.rsp > out;rspfile=Original very long command" , |
2096 | log_entry->command_hash)); |
2097 | log_entry->command_hash++; // Change the command hash to something else. |
2098 | // Now expect the target to be rebuilt |
2099 | command_runner_.commands_ran_.clear(); |
2100 | state_.Reset(); |
2101 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
2102 | EXPECT_EQ("" , err); |
2103 | EXPECT_TRUE(builder_.Build(&err)); |
2104 | EXPECT_EQ(1u, command_runner_.commands_ran_.size()); |
2105 | } |
2106 | |
2107 | TEST_F(BuildTest, InterruptCleanup) { |
2108 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2109 | "rule interrupt\n" |
2110 | " command = interrupt\n" |
2111 | "rule touch-interrupt\n" |
2112 | " command = touch-interrupt\n" |
2113 | "build out1: interrupt in1\n" |
2114 | "build out2: touch-interrupt in2\n" )); |
2115 | |
2116 | fs_.Create("out1" , "" ); |
2117 | fs_.Create("out2" , "" ); |
2118 | fs_.Tick(); |
2119 | fs_.Create("in1" , "" ); |
2120 | fs_.Create("in2" , "" ); |
2121 | |
2122 | // An untouched output of an interrupted command should be retained. |
2123 | string err; |
2124 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
2125 | EXPECT_EQ("" , err); |
2126 | EXPECT_FALSE(builder_.Build(&err)); |
2127 | EXPECT_EQ("interrupted by user" , err); |
2128 | builder_.Cleanup(); |
2129 | EXPECT_GT(fs_.Stat("out1" , &err), 0); |
2130 | err = "" ; |
2131 | |
2132 | // A touched output of an interrupted command should be deleted. |
2133 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
2134 | EXPECT_EQ("" , err); |
2135 | EXPECT_FALSE(builder_.Build(&err)); |
2136 | EXPECT_EQ("interrupted by user" , err); |
2137 | builder_.Cleanup(); |
2138 | EXPECT_EQ(0, fs_.Stat("out2" , &err)); |
2139 | } |
2140 | |
2141 | TEST_F(BuildTest, StatFailureAbortsBuild) { |
2142 | const string kTooLongToStat(400, 'i'); |
2143 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2144 | ("build " + kTooLongToStat + ": cat in\n" ).c_str())); |
2145 | fs_.Create("in" , "" ); |
2146 | |
2147 | // This simulates a stat failure: |
2148 | fs_.files_[kTooLongToStat].mtime = -1; |
2149 | fs_.files_[kTooLongToStat].stat_error = "stat failed" ; |
2150 | |
2151 | string err; |
2152 | EXPECT_FALSE(builder_.AddTarget(kTooLongToStat, &err)); |
2153 | EXPECT_EQ("stat failed" , err); |
2154 | } |
2155 | |
2156 | TEST_F(BuildTest, PhonyWithNoInputs) { |
2157 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2158 | "build nonexistent: phony\n" |
2159 | "build out1: cat || nonexistent\n" |
2160 | "build out2: cat nonexistent\n" )); |
2161 | fs_.Create("out1" , "" ); |
2162 | fs_.Create("out2" , "" ); |
2163 | |
2164 | // out1 should be up to date even though its input is dirty, because its |
2165 | // order-only dependency has nothing to do. |
2166 | string err; |
2167 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
2168 | ASSERT_EQ("" , err); |
2169 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
2170 | |
2171 | // out2 should still be out of date though, because its input is dirty. |
2172 | err.clear(); |
2173 | command_runner_.commands_ran_.clear(); |
2174 | state_.Reset(); |
2175 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
2176 | ASSERT_EQ("" , err); |
2177 | EXPECT_TRUE(builder_.Build(&err)); |
2178 | EXPECT_EQ("" , err); |
2179 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2180 | } |
2181 | |
2182 | TEST_F(BuildTest, DepsGccWithEmptyDepfileErrorsOut) { |
2183 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2184 | "rule cc\n" |
2185 | " command = cc\n" |
2186 | " deps = gcc\n" |
2187 | "build out: cc\n" )); |
2188 | Dirty("out" ); |
2189 | |
2190 | string err; |
2191 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
2192 | ASSERT_EQ("" , err); |
2193 | EXPECT_FALSE(builder_.AlreadyUpToDate()); |
2194 | |
2195 | EXPECT_FALSE(builder_.Build(&err)); |
2196 | ASSERT_EQ("subcommand failed" , err); |
2197 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2198 | } |
2199 | |
2200 | TEST_F(BuildTest, StatusFormatElapsed) { |
2201 | status_.BuildStarted(); |
2202 | // Before any task is done, the elapsed time must be zero. |
2203 | EXPECT_EQ("[%/e0.000]" , |
2204 | status_.FormatProgressStatus("[%%/e%e]" , 0)); |
2205 | } |
2206 | |
2207 | TEST_F(BuildTest, StatusFormatReplacePlaceholder) { |
2208 | EXPECT_EQ("[%/s0/t0/r0/u0/f0]" , |
2209 | status_.FormatProgressStatus("[%%/s%s/t%t/r%r/u%u/f%f]" , 0)); |
2210 | } |
2211 | |
2212 | TEST_F(BuildTest, FailedDepsParse) { |
2213 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2214 | "build bad_deps.o: cat in1\n" |
2215 | " deps = gcc\n" |
2216 | " depfile = in1.d\n" )); |
2217 | |
2218 | string err; |
2219 | EXPECT_TRUE(builder_.AddTarget("bad_deps.o" , &err)); |
2220 | ASSERT_EQ("" , err); |
2221 | |
2222 | // These deps will fail to parse, as they should only have one |
2223 | // path to the left of the colon. |
2224 | fs_.Create("in1.d" , "AAA BBB" ); |
2225 | |
2226 | EXPECT_FALSE(builder_.Build(&err)); |
2227 | EXPECT_EQ("subcommand failed" , err); |
2228 | } |
2229 | |
2230 | struct BuildWithQueryDepsLogTest : public BuildTest { |
2231 | BuildWithQueryDepsLogTest() : BuildTest(&log_) { |
2232 | } |
2233 | |
2234 | ~BuildWithQueryDepsLogTest() { |
2235 | log_.Close(); |
2236 | } |
2237 | |
2238 | virtual void SetUp() { |
2239 | BuildTest::SetUp(); |
2240 | |
2241 | temp_dir_.CreateAndEnter("BuildWithQueryDepsLogTest" ); |
2242 | |
2243 | std::string err; |
2244 | ASSERT_TRUE(log_.OpenForWrite("ninja_deps" , &err)); |
2245 | ASSERT_EQ("" , err); |
2246 | } |
2247 | |
2248 | ScopedTempDir temp_dir_; |
2249 | |
2250 | DepsLog log_; |
2251 | }; |
2252 | |
2253 | /// Test a MSVC-style deps log with multiple outputs. |
2254 | TEST_F(BuildWithQueryDepsLogTest, TwoOutputsDepFileMSVC) { |
2255 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2256 | "rule cp_multi_msvc\n" |
2257 | " command = echo 'using $in' && for file in $out; do cp $in $$file; done\n" |
2258 | " deps = msvc\n" |
2259 | " msvc_deps_prefix = using \n" |
2260 | "build out1 out2: cp_multi_msvc in1\n" )); |
2261 | |
2262 | std::string err; |
2263 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
2264 | ASSERT_EQ("" , err); |
2265 | EXPECT_TRUE(builder_.Build(&err)); |
2266 | EXPECT_EQ("" , err); |
2267 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2268 | EXPECT_EQ("echo 'using in1' && for file in out1 out2; do cp in1 $file; done" , command_runner_.commands_ran_[0]); |
2269 | |
2270 | Node* out1_node = state_.LookupNode("out1" ); |
2271 | DepsLog::Deps* out1_deps = log_.GetDeps(out1_node); |
2272 | EXPECT_EQ(1, out1_deps->node_count); |
2273 | EXPECT_EQ("in1" , out1_deps->nodes[0]->path()); |
2274 | |
2275 | Node* out2_node = state_.LookupNode("out2" ); |
2276 | DepsLog::Deps* out2_deps = log_.GetDeps(out2_node); |
2277 | EXPECT_EQ(1, out2_deps->node_count); |
2278 | EXPECT_EQ("in1" , out2_deps->nodes[0]->path()); |
2279 | } |
2280 | |
2281 | /// Test a GCC-style deps log with multiple outputs. |
2282 | TEST_F(BuildWithQueryDepsLogTest, TwoOutputsDepFileGCCOneLine) { |
2283 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2284 | "rule cp_multi_gcc\n" |
2285 | " command = echo '$out: $in' > in.d && for file in $out; do cp in1 $$file; done\n" |
2286 | " deps = gcc\n" |
2287 | " depfile = in.d\n" |
2288 | "build out1 out2: cp_multi_gcc in1 in2\n" )); |
2289 | |
2290 | std::string err; |
2291 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
2292 | ASSERT_EQ("" , err); |
2293 | fs_.Create("in.d" , "out1 out2: in1 in2" ); |
2294 | EXPECT_TRUE(builder_.Build(&err)); |
2295 | EXPECT_EQ("" , err); |
2296 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2297 | EXPECT_EQ("echo 'out1 out2: in1 in2' > in.d && for file in out1 out2; do cp in1 $file; done" , command_runner_.commands_ran_[0]); |
2298 | |
2299 | Node* out1_node = state_.LookupNode("out1" ); |
2300 | DepsLog::Deps* out1_deps = log_.GetDeps(out1_node); |
2301 | EXPECT_EQ(2, out1_deps->node_count); |
2302 | EXPECT_EQ("in1" , out1_deps->nodes[0]->path()); |
2303 | EXPECT_EQ("in2" , out1_deps->nodes[1]->path()); |
2304 | |
2305 | Node* out2_node = state_.LookupNode("out2" ); |
2306 | DepsLog::Deps* out2_deps = log_.GetDeps(out2_node); |
2307 | EXPECT_EQ(2, out2_deps->node_count); |
2308 | EXPECT_EQ("in1" , out2_deps->nodes[0]->path()); |
2309 | EXPECT_EQ("in2" , out2_deps->nodes[1]->path()); |
2310 | } |
2311 | |
2312 | /// Test a GCC-style deps log with multiple outputs using a line per input. |
2313 | TEST_F(BuildWithQueryDepsLogTest, TwoOutputsDepFileGCCMultiLineInput) { |
2314 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2315 | "rule cp_multi_gcc\n" |
2316 | " command = echo '$out: in1\\n$out: in2' > in.d && for file in $out; do cp in1 $$file; done\n" |
2317 | " deps = gcc\n" |
2318 | " depfile = in.d\n" |
2319 | "build out1 out2: cp_multi_gcc in1 in2\n" )); |
2320 | |
2321 | std::string err; |
2322 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
2323 | ASSERT_EQ("" , err); |
2324 | fs_.Create("in.d" , "out1 out2: in1\nout1 out2: in2" ); |
2325 | EXPECT_TRUE(builder_.Build(&err)); |
2326 | EXPECT_EQ("" , err); |
2327 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2328 | EXPECT_EQ("echo 'out1 out2: in1\\nout1 out2: in2' > in.d && for file in out1 out2; do cp in1 $file; done" , command_runner_.commands_ran_[0]); |
2329 | |
2330 | Node* out1_node = state_.LookupNode("out1" ); |
2331 | DepsLog::Deps* out1_deps = log_.GetDeps(out1_node); |
2332 | EXPECT_EQ(2, out1_deps->node_count); |
2333 | EXPECT_EQ("in1" , out1_deps->nodes[0]->path()); |
2334 | EXPECT_EQ("in2" , out1_deps->nodes[1]->path()); |
2335 | |
2336 | Node* out2_node = state_.LookupNode("out2" ); |
2337 | DepsLog::Deps* out2_deps = log_.GetDeps(out2_node); |
2338 | EXPECT_EQ(2, out2_deps->node_count); |
2339 | EXPECT_EQ("in1" , out2_deps->nodes[0]->path()); |
2340 | EXPECT_EQ("in2" , out2_deps->nodes[1]->path()); |
2341 | } |
2342 | |
2343 | /// Test a GCC-style deps log with multiple outputs using a line per output. |
2344 | TEST_F(BuildWithQueryDepsLogTest, TwoOutputsDepFileGCCMultiLineOutput) { |
2345 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2346 | "rule cp_multi_gcc\n" |
2347 | " command = echo 'out1: $in\\nout2: $in' > in.d && for file in $out; do cp in1 $$file; done\n" |
2348 | " deps = gcc\n" |
2349 | " depfile = in.d\n" |
2350 | "build out1 out2: cp_multi_gcc in1 in2\n" )); |
2351 | |
2352 | std::string err; |
2353 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
2354 | ASSERT_EQ("" , err); |
2355 | fs_.Create("in.d" , "out1: in1 in2\nout2: in1 in2" ); |
2356 | EXPECT_TRUE(builder_.Build(&err)); |
2357 | EXPECT_EQ("" , err); |
2358 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2359 | EXPECT_EQ("echo 'out1: in1 in2\\nout2: in1 in2' > in.d && for file in out1 out2; do cp in1 $file; done" , command_runner_.commands_ran_[0]); |
2360 | |
2361 | Node* out1_node = state_.LookupNode("out1" ); |
2362 | DepsLog::Deps* out1_deps = log_.GetDeps(out1_node); |
2363 | EXPECT_EQ(2, out1_deps->node_count); |
2364 | EXPECT_EQ("in1" , out1_deps->nodes[0]->path()); |
2365 | EXPECT_EQ("in2" , out1_deps->nodes[1]->path()); |
2366 | |
2367 | Node* out2_node = state_.LookupNode("out2" ); |
2368 | DepsLog::Deps* out2_deps = log_.GetDeps(out2_node); |
2369 | EXPECT_EQ(2, out2_deps->node_count); |
2370 | EXPECT_EQ("in1" , out2_deps->nodes[0]->path()); |
2371 | EXPECT_EQ("in2" , out2_deps->nodes[1]->path()); |
2372 | } |
2373 | |
2374 | /// Test a GCC-style deps log with multiple outputs mentioning only the main output. |
2375 | TEST_F(BuildWithQueryDepsLogTest, TwoOutputsDepFileGCCOnlyMainOutput) { |
2376 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2377 | "rule cp_multi_gcc\n" |
2378 | " command = echo 'out1: $in' > in.d && for file in $out; do cp in1 $$file; done\n" |
2379 | " deps = gcc\n" |
2380 | " depfile = in.d\n" |
2381 | "build out1 out2: cp_multi_gcc in1 in2\n" )); |
2382 | |
2383 | std::string err; |
2384 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
2385 | ASSERT_EQ("" , err); |
2386 | fs_.Create("in.d" , "out1: in1 in2" ); |
2387 | EXPECT_TRUE(builder_.Build(&err)); |
2388 | EXPECT_EQ("" , err); |
2389 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2390 | EXPECT_EQ("echo 'out1: in1 in2' > in.d && for file in out1 out2; do cp in1 $file; done" , command_runner_.commands_ran_[0]); |
2391 | |
2392 | Node* out1_node = state_.LookupNode("out1" ); |
2393 | DepsLog::Deps* out1_deps = log_.GetDeps(out1_node); |
2394 | EXPECT_EQ(2, out1_deps->node_count); |
2395 | EXPECT_EQ("in1" , out1_deps->nodes[0]->path()); |
2396 | EXPECT_EQ("in2" , out1_deps->nodes[1]->path()); |
2397 | |
2398 | Node* out2_node = state_.LookupNode("out2" ); |
2399 | DepsLog::Deps* out2_deps = log_.GetDeps(out2_node); |
2400 | EXPECT_EQ(2, out2_deps->node_count); |
2401 | EXPECT_EQ("in1" , out2_deps->nodes[0]->path()); |
2402 | EXPECT_EQ("in2" , out2_deps->nodes[1]->path()); |
2403 | } |
2404 | |
2405 | /// Test a GCC-style deps log with multiple outputs mentioning only the secondary output. |
2406 | TEST_F(BuildWithQueryDepsLogTest, TwoOutputsDepFileGCCOnlySecondaryOutput) { |
2407 | // Note: This ends up short-circuiting the node creation due to the primary |
2408 | // output not being present, but it should still work. |
2409 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2410 | "rule cp_multi_gcc\n" |
2411 | " command = echo 'out2: $in' > in.d && for file in $out; do cp in1 $$file; done\n" |
2412 | " deps = gcc\n" |
2413 | " depfile = in.d\n" |
2414 | "build out1 out2: cp_multi_gcc in1 in2\n" )); |
2415 | |
2416 | std::string err; |
2417 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
2418 | ASSERT_EQ("" , err); |
2419 | fs_.Create("in.d" , "out2: in1 in2" ); |
2420 | EXPECT_TRUE(builder_.Build(&err)); |
2421 | EXPECT_EQ("" , err); |
2422 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2423 | EXPECT_EQ("echo 'out2: in1 in2' > in.d && for file in out1 out2; do cp in1 $file; done" , command_runner_.commands_ran_[0]); |
2424 | |
2425 | Node* out1_node = state_.LookupNode("out1" ); |
2426 | DepsLog::Deps* out1_deps = log_.GetDeps(out1_node); |
2427 | EXPECT_EQ(2, out1_deps->node_count); |
2428 | EXPECT_EQ("in1" , out1_deps->nodes[0]->path()); |
2429 | EXPECT_EQ("in2" , out1_deps->nodes[1]->path()); |
2430 | |
2431 | Node* out2_node = state_.LookupNode("out2" ); |
2432 | DepsLog::Deps* out2_deps = log_.GetDeps(out2_node); |
2433 | EXPECT_EQ(2, out2_deps->node_count); |
2434 | EXPECT_EQ("in1" , out2_deps->nodes[0]->path()); |
2435 | EXPECT_EQ("in2" , out2_deps->nodes[1]->path()); |
2436 | } |
2437 | |
2438 | /// Tests of builds involving deps logs necessarily must span |
2439 | /// multiple builds. We reuse methods on BuildTest but not the |
2440 | /// builder_ it sets up, because we want pristine objects for |
2441 | /// each build. |
2442 | struct BuildWithDepsLogTest : public BuildTest { |
2443 | BuildWithDepsLogTest() {} |
2444 | |
2445 | virtual void SetUp() { |
2446 | BuildTest::SetUp(); |
2447 | |
2448 | temp_dir_.CreateAndEnter("BuildWithDepsLogTest" ); |
2449 | } |
2450 | |
2451 | virtual void TearDown() { |
2452 | temp_dir_.Cleanup(); |
2453 | } |
2454 | |
2455 | ScopedTempDir temp_dir_; |
2456 | |
2457 | /// Shadow parent class builder_ so we don't accidentally use it. |
2458 | void* builder_; |
2459 | }; |
2460 | |
2461 | /// Run a straightforward build where the deps log is used. |
2462 | TEST_F(BuildWithDepsLogTest, Straightforward) { |
2463 | string err; |
2464 | // Note: in1 was created by the superclass SetUp(). |
2465 | const char* manifest = |
2466 | "build out: cat in1\n" |
2467 | " deps = gcc\n" |
2468 | " depfile = in1.d\n" ; |
2469 | { |
2470 | State state; |
2471 | ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); |
2472 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
2473 | |
2474 | // Run the build once, everything should be ok. |
2475 | DepsLog deps_log; |
2476 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
2477 | ASSERT_EQ("" , err); |
2478 | |
2479 | Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0); |
2480 | builder.command_runner_.reset(&command_runner_); |
2481 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2482 | ASSERT_EQ("" , err); |
2483 | fs_.Create("in1.d" , "out: in2" ); |
2484 | EXPECT_TRUE(builder.Build(&err)); |
2485 | EXPECT_EQ("" , err); |
2486 | |
2487 | // The deps file should have been removed. |
2488 | EXPECT_EQ(0, fs_.Stat("in1.d" , &err)); |
2489 | // Recreate it for the next step. |
2490 | fs_.Create("in1.d" , "out: in2" ); |
2491 | deps_log.Close(); |
2492 | builder.command_runner_.release(); |
2493 | } |
2494 | |
2495 | { |
2496 | State state; |
2497 | ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); |
2498 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
2499 | |
2500 | // Touch the file only mentioned in the deps. |
2501 | fs_.Tick(); |
2502 | fs_.Create("in2" , "" ); |
2503 | |
2504 | // Run the build again. |
2505 | DepsLog deps_log; |
2506 | ASSERT_TRUE(deps_log.Load("ninja_deps" , &state, &err)); |
2507 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
2508 | |
2509 | Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0); |
2510 | builder.command_runner_.reset(&command_runner_); |
2511 | command_runner_.commands_ran_.clear(); |
2512 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2513 | ASSERT_EQ("" , err); |
2514 | EXPECT_TRUE(builder.Build(&err)); |
2515 | EXPECT_EQ("" , err); |
2516 | |
2517 | // We should have rebuilt the output due to in2 being |
2518 | // out of date. |
2519 | EXPECT_EQ(1u, command_runner_.commands_ran_.size()); |
2520 | |
2521 | builder.command_runner_.release(); |
2522 | } |
2523 | } |
2524 | |
2525 | /// Verify that obsolete dependency info causes a rebuild. |
2526 | /// 1) Run a successful build where everything has time t, record deps. |
2527 | /// 2) Move input/output to time t+1 -- despite files in alignment, |
2528 | /// should still need to rebuild due to deps at older time. |
2529 | TEST_F(BuildWithDepsLogTest, ObsoleteDeps) { |
2530 | string err; |
2531 | // Note: in1 was created by the superclass SetUp(). |
2532 | const char* manifest = |
2533 | "build out: cat in1\n" |
2534 | " deps = gcc\n" |
2535 | " depfile = in1.d\n" ; |
2536 | { |
2537 | // Run an ordinary build that gathers dependencies. |
2538 | fs_.Create("in1" , "" ); |
2539 | fs_.Create("in1.d" , "out: " ); |
2540 | |
2541 | State state; |
2542 | ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); |
2543 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
2544 | |
2545 | // Run the build once, everything should be ok. |
2546 | DepsLog deps_log; |
2547 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
2548 | ASSERT_EQ("" , err); |
2549 | |
2550 | Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0); |
2551 | builder.command_runner_.reset(&command_runner_); |
2552 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2553 | ASSERT_EQ("" , err); |
2554 | EXPECT_TRUE(builder.Build(&err)); |
2555 | EXPECT_EQ("" , err); |
2556 | |
2557 | deps_log.Close(); |
2558 | builder.command_runner_.release(); |
2559 | } |
2560 | |
2561 | // Push all files one tick forward so that only the deps are out |
2562 | // of date. |
2563 | fs_.Tick(); |
2564 | fs_.Create("in1" , "" ); |
2565 | fs_.Create("out" , "" ); |
2566 | |
2567 | // The deps file should have been removed, so no need to timestamp it. |
2568 | EXPECT_EQ(0, fs_.Stat("in1.d" , &err)); |
2569 | |
2570 | { |
2571 | State state; |
2572 | ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); |
2573 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
2574 | |
2575 | DepsLog deps_log; |
2576 | ASSERT_TRUE(deps_log.Load("ninja_deps" , &state, &err)); |
2577 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
2578 | |
2579 | Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0); |
2580 | builder.command_runner_.reset(&command_runner_); |
2581 | command_runner_.commands_ran_.clear(); |
2582 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2583 | ASSERT_EQ("" , err); |
2584 | |
2585 | // Recreate the deps file here because the build expects them to exist. |
2586 | fs_.Create("in1.d" , "out: " ); |
2587 | |
2588 | EXPECT_TRUE(builder.Build(&err)); |
2589 | EXPECT_EQ("" , err); |
2590 | |
2591 | // We should have rebuilt the output due to the deps being |
2592 | // out of date. |
2593 | EXPECT_EQ(1u, command_runner_.commands_ran_.size()); |
2594 | |
2595 | builder.command_runner_.release(); |
2596 | } |
2597 | } |
2598 | |
2599 | TEST_F(BuildWithDepsLogTest, DepsIgnoredInDryRun) { |
2600 | const char* manifest = |
2601 | "build out: cat in1\n" |
2602 | " deps = gcc\n" |
2603 | " depfile = in1.d\n" ; |
2604 | |
2605 | fs_.Create("out" , "" ); |
2606 | fs_.Tick(); |
2607 | fs_.Create("in1" , "" ); |
2608 | |
2609 | State state; |
2610 | ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); |
2611 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
2612 | |
2613 | // The deps log is NULL in dry runs. |
2614 | config_.dry_run = true; |
2615 | Builder builder(&state, config_, NULL, NULL, &fs_, &status_, 0); |
2616 | builder.command_runner_.reset(&command_runner_); |
2617 | command_runner_.commands_ran_.clear(); |
2618 | |
2619 | string err; |
2620 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2621 | ASSERT_EQ("" , err); |
2622 | EXPECT_TRUE(builder.Build(&err)); |
2623 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2624 | |
2625 | builder.command_runner_.release(); |
2626 | } |
2627 | |
2628 | TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceCondition) { |
2629 | string err; |
2630 | const char* manifest = |
2631 | "rule long-cc\n" |
2632 | " command = long-cc\n" |
2633 | "build out: long-cc in1\n" |
2634 | " test_dependency = in1\n" ; |
2635 | |
2636 | State state; |
2637 | ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); |
2638 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
2639 | |
2640 | BuildLog build_log; |
2641 | ASSERT_TRUE(build_log.Load("build_log" , &err)); |
2642 | ASSERT_TRUE(build_log.OpenForWrite("build_log" , *this, &err)); |
2643 | |
2644 | DepsLog deps_log; |
2645 | ASSERT_TRUE(deps_log.Load("ninja_deps" , &state, &err)); |
2646 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
2647 | |
2648 | BuildLog::LogEntry* log_entry = NULL; |
2649 | { |
2650 | Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0); |
2651 | builder.command_runner_.reset(&command_runner_); |
2652 | command_runner_.commands_ran_.clear(); |
2653 | |
2654 | // Run the build, out gets built, dep file is created |
2655 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2656 | ASSERT_EQ("" , err); |
2657 | EXPECT_TRUE(builder.Build(&err)); |
2658 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2659 | |
2660 | // See that an entry in the logfile is created. the input_mtime is 1 since that was |
2661 | // the mtime of in1 when the command was started |
2662 | log_entry = build_log.LookupByOutput("out" ); |
2663 | ASSERT_TRUE(NULL != log_entry); |
2664 | ASSERT_EQ(1u, log_entry->mtime); |
2665 | |
2666 | builder.command_runner_.release(); |
2667 | } |
2668 | |
2669 | { |
2670 | Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0); |
2671 | builder.command_runner_.reset(&command_runner_); |
2672 | command_runner_.commands_ran_.clear(); |
2673 | |
2674 | // Trigger the build again - "out" should rebuild despite having a newer mtime than |
2675 | // "in1", since "in1" was touched during the build of out (simulated by changing its |
2676 | // mtime in the the test builder's WaitForCommand() which runs before FinishCommand() |
2677 | command_runner_.commands_ran_.clear(); |
2678 | state.Reset(); |
2679 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2680 | ASSERT_EQ("" , err); |
2681 | EXPECT_TRUE(builder.Build(&err)); |
2682 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2683 | |
2684 | // Check that the logfile entry is still correct |
2685 | log_entry = build_log.LookupByOutput("out" ); |
2686 | ASSERT_TRUE(NULL != log_entry); |
2687 | ASSERT_TRUE(fs_.files_["in1" ].mtime < log_entry->mtime); |
2688 | builder.command_runner_.release(); |
2689 | } |
2690 | |
2691 | { |
2692 | Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0); |
2693 | builder.command_runner_.reset(&command_runner_); |
2694 | command_runner_.commands_ran_.clear(); |
2695 | |
2696 | // And a subsequent run should not have any work to do |
2697 | command_runner_.commands_ran_.clear(); |
2698 | state.Reset(); |
2699 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2700 | ASSERT_EQ("" , err); |
2701 | EXPECT_TRUE(builder.AlreadyUpToDate()); |
2702 | |
2703 | builder.command_runner_.release(); |
2704 | } |
2705 | } |
2706 | |
2707 | TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceConditionWithDepFile) { |
2708 | string err; |
2709 | const char* manifest = |
2710 | "rule long-cc\n" |
2711 | " command = long-cc\n" |
2712 | "build out: long-cc\n" |
2713 | " deps = gcc\n" |
2714 | " depfile = out.d\n" |
2715 | " test_dependency = header.h\n" ; |
2716 | |
2717 | fs_.Create("header.h" , "" ); |
2718 | |
2719 | State state; |
2720 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
2721 | |
2722 | BuildLog build_log; |
2723 | ASSERT_TRUE(build_log.Load("build_log" , &err)); |
2724 | ASSERT_TRUE(build_log.OpenForWrite("build_log" , *this, &err)); |
2725 | |
2726 | DepsLog deps_log; |
2727 | ASSERT_TRUE(deps_log.Load("ninja_deps" , &state, &err)); |
2728 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
2729 | |
2730 | { |
2731 | Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0); |
2732 | builder.command_runner_.reset(&command_runner_); |
2733 | |
2734 | // Run the build, out gets built, dep file is created |
2735 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2736 | ASSERT_EQ("" , err); |
2737 | EXPECT_TRUE(builder.Build(&err)); |
2738 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2739 | |
2740 | // See that an entry in the logfile is created. the mtime is 1 due to the command |
2741 | // starting when the file system's mtime was 1. |
2742 | BuildLog::LogEntry* log_entry = build_log.LookupByOutput("out" ); |
2743 | ASSERT_TRUE(NULL != log_entry); |
2744 | ASSERT_EQ(1u, log_entry->mtime); |
2745 | |
2746 | builder.command_runner_.release(); |
2747 | } |
2748 | |
2749 | { |
2750 | // Trigger the build again - "out" will rebuild since its newest input mtime (header.h) |
2751 | // is newer than the recorded mtime of out in the build log |
2752 | Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0); |
2753 | builder.command_runner_.reset(&command_runner_); |
2754 | command_runner_.commands_ran_.clear(); |
2755 | |
2756 | state.Reset(); |
2757 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2758 | ASSERT_EQ("" , err); |
2759 | EXPECT_TRUE(builder.Build(&err)); |
2760 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2761 | |
2762 | builder.command_runner_.release(); |
2763 | } |
2764 | |
2765 | { |
2766 | // Trigger the build again - "out" won't rebuild since the file wasn't updated during |
2767 | // the previous build |
2768 | Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0); |
2769 | builder.command_runner_.reset(&command_runner_); |
2770 | command_runner_.commands_ran_.clear(); |
2771 | |
2772 | state.Reset(); |
2773 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2774 | ASSERT_EQ("" , err); |
2775 | ASSERT_TRUE(builder.AlreadyUpToDate()); |
2776 | |
2777 | builder.command_runner_.release(); |
2778 | } |
2779 | |
2780 | // touch the header to trigger a rebuild |
2781 | fs_.Create("header.h" , "" ); |
2782 | ASSERT_EQ(fs_.now_, 7); |
2783 | |
2784 | { |
2785 | // Rebuild. This time, long-cc will cause header.h to be updated while the build is |
2786 | // in progress |
2787 | Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0); |
2788 | builder.command_runner_.reset(&command_runner_); |
2789 | command_runner_.commands_ran_.clear(); |
2790 | |
2791 | state.Reset(); |
2792 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2793 | ASSERT_EQ("" , err); |
2794 | EXPECT_TRUE(builder.Build(&err)); |
2795 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2796 | |
2797 | builder.command_runner_.release(); |
2798 | } |
2799 | |
2800 | { |
2801 | // Rebuild. Because header.h is now in the deplog for out, it should be detectable as |
2802 | // a change-while-in-progress and should cause a rebuild of out. |
2803 | Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0); |
2804 | builder.command_runner_.reset(&command_runner_); |
2805 | command_runner_.commands_ran_.clear(); |
2806 | |
2807 | state.Reset(); |
2808 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2809 | ASSERT_EQ("" , err); |
2810 | EXPECT_TRUE(builder.Build(&err)); |
2811 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
2812 | |
2813 | builder.command_runner_.release(); |
2814 | } |
2815 | |
2816 | { |
2817 | // This time, the header.h file was not updated during the build, so the target should |
2818 | // not be considered dirty. |
2819 | Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0); |
2820 | builder.command_runner_.reset(&command_runner_); |
2821 | command_runner_.commands_ran_.clear(); |
2822 | |
2823 | state.Reset(); |
2824 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2825 | ASSERT_EQ("" , err); |
2826 | EXPECT_TRUE(builder.AlreadyUpToDate()); |
2827 | |
2828 | builder.command_runner_.release(); |
2829 | } |
2830 | } |
2831 | |
2832 | /// Check that a restat rule generating a header cancels compilations correctly. |
2833 | TEST_F(BuildTest, RestatDepfileDependency) { |
2834 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
2835 | "rule true\n" |
2836 | " command = true\n" // Would be "write if out-of-date" in reality. |
2837 | " restat = 1\n" |
2838 | "build header.h: true header.in\n" |
2839 | "build out: cat in1\n" |
2840 | " depfile = in1.d\n" )); |
2841 | |
2842 | fs_.Create("header.h" , "" ); |
2843 | fs_.Create("in1.d" , "out: header.h" ); |
2844 | fs_.Tick(); |
2845 | fs_.Create("header.in" , "" ); |
2846 | |
2847 | string err; |
2848 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
2849 | ASSERT_EQ("" , err); |
2850 | EXPECT_TRUE(builder_.Build(&err)); |
2851 | EXPECT_EQ("" , err); |
2852 | } |
2853 | |
2854 | /// Check that a restat rule generating a header cancels compilations correctly, |
2855 | /// depslog case. |
2856 | TEST_F(BuildWithDepsLogTest, RestatDepfileDependencyDepsLog) { |
2857 | string err; |
2858 | // Note: in1 was created by the superclass SetUp(). |
2859 | const char* manifest = |
2860 | "rule true\n" |
2861 | " command = true\n" // Would be "write if out-of-date" in reality. |
2862 | " restat = 1\n" |
2863 | "build header.h: true header.in\n" |
2864 | "build out: cat in1\n" |
2865 | " deps = gcc\n" |
2866 | " depfile = in1.d\n" ; |
2867 | { |
2868 | State state; |
2869 | ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); |
2870 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
2871 | |
2872 | // Run the build once, everything should be ok. |
2873 | DepsLog deps_log; |
2874 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
2875 | ASSERT_EQ("" , err); |
2876 | |
2877 | Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0); |
2878 | builder.command_runner_.reset(&command_runner_); |
2879 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2880 | ASSERT_EQ("" , err); |
2881 | fs_.Create("in1.d" , "out: header.h" ); |
2882 | EXPECT_TRUE(builder.Build(&err)); |
2883 | EXPECT_EQ("" , err); |
2884 | |
2885 | deps_log.Close(); |
2886 | builder.command_runner_.release(); |
2887 | } |
2888 | |
2889 | { |
2890 | State state; |
2891 | ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); |
2892 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
2893 | |
2894 | // Touch the input of the restat rule. |
2895 | fs_.Tick(); |
2896 | fs_.Create("header.in" , "" ); |
2897 | |
2898 | // Run the build again. |
2899 | DepsLog deps_log; |
2900 | ASSERT_TRUE(deps_log.Load("ninja_deps" , &state, &err)); |
2901 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
2902 | |
2903 | Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0); |
2904 | builder.command_runner_.reset(&command_runner_); |
2905 | command_runner_.commands_ran_.clear(); |
2906 | EXPECT_TRUE(builder.AddTarget("out" , &err)); |
2907 | ASSERT_EQ("" , err); |
2908 | EXPECT_TRUE(builder.Build(&err)); |
2909 | EXPECT_EQ("" , err); |
2910 | |
2911 | // Rule "true" should have run again, but the build of "out" should have |
2912 | // been cancelled due to restat propagating through the depfile header. |
2913 | EXPECT_EQ(1u, command_runner_.commands_ran_.size()); |
2914 | |
2915 | builder.command_runner_.release(); |
2916 | } |
2917 | } |
2918 | |
2919 | TEST_F(BuildWithDepsLogTest, DepFileOKDepsLog) { |
2920 | string err; |
2921 | const char* manifest = |
2922 | "rule cc\n command = cc $in\n depfile = $out.d\n deps = gcc\n" |
2923 | "build fo$ o.o: cc foo.c\n" ; |
2924 | |
2925 | fs_.Create("foo.c" , "" ); |
2926 | |
2927 | { |
2928 | State state; |
2929 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
2930 | |
2931 | // Run the build once, everything should be ok. |
2932 | DepsLog deps_log; |
2933 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
2934 | ASSERT_EQ("" , err); |
2935 | |
2936 | Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0); |
2937 | builder.command_runner_.reset(&command_runner_); |
2938 | EXPECT_TRUE(builder.AddTarget("fo o.o" , &err)); |
2939 | ASSERT_EQ("" , err); |
2940 | fs_.Create("fo o.o.d" , "fo\\ o.o: blah.h bar.h\n" ); |
2941 | EXPECT_TRUE(builder.Build(&err)); |
2942 | EXPECT_EQ("" , err); |
2943 | |
2944 | deps_log.Close(); |
2945 | builder.command_runner_.release(); |
2946 | } |
2947 | |
2948 | { |
2949 | State state; |
2950 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
2951 | |
2952 | DepsLog deps_log; |
2953 | ASSERT_TRUE(deps_log.Load("ninja_deps" , &state, &err)); |
2954 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
2955 | ASSERT_EQ("" , err); |
2956 | |
2957 | Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0); |
2958 | builder.command_runner_.reset(&command_runner_); |
2959 | |
2960 | Edge* edge = state.edges_.back(); |
2961 | |
2962 | state.GetNode("bar.h" , 0)->MarkDirty(); // Mark bar.h as missing. |
2963 | EXPECT_TRUE(builder.AddTarget("fo o.o" , &err)); |
2964 | ASSERT_EQ("" , err); |
2965 | |
2966 | // Expect three new edges: one generating fo o.o, and two more from |
2967 | // loading the depfile. |
2968 | ASSERT_EQ(3u, state.edges_.size()); |
2969 | // Expect our edge to now have three inputs: foo.c and two headers. |
2970 | ASSERT_EQ(3u, edge->inputs_.size()); |
2971 | |
2972 | // Expect the command line we generate to only use the original input. |
2973 | ASSERT_EQ("cc foo.c" , edge->EvaluateCommand()); |
2974 | |
2975 | deps_log.Close(); |
2976 | builder.command_runner_.release(); |
2977 | } |
2978 | } |
2979 | |
2980 | TEST_F(BuildWithDepsLogTest, DiscoveredDepDuringBuildChanged) { |
2981 | string err; |
2982 | const char* manifest = |
2983 | "rule touch-out-implicit-dep\n" |
2984 | " command = touch $out ; sleep 1 ; touch $test_dependency\n" |
2985 | "rule generate-depfile\n" |
2986 | " command = touch $out ; echo \"$out: $test_dependency\" > $depfile\n" |
2987 | "build out1: touch-out-implicit-dep in1\n" |
2988 | " test_dependency = inimp\n" |
2989 | "build out2: generate-depfile in1 || out1\n" |
2990 | " test_dependency = inimp\n" |
2991 | " depfile = out2.d\n" |
2992 | " deps = gcc\n" ; |
2993 | |
2994 | fs_.Create("in1" , "" ); |
2995 | fs_.Tick(); |
2996 | |
2997 | BuildLog build_log; |
2998 | |
2999 | { |
3000 | State state; |
3001 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
3002 | |
3003 | DepsLog deps_log; |
3004 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
3005 | ASSERT_EQ("" , err); |
3006 | |
3007 | Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0); |
3008 | builder.command_runner_.reset(&command_runner_); |
3009 | EXPECT_TRUE(builder.AddTarget("out2" , &err)); |
3010 | EXPECT_FALSE(builder.AlreadyUpToDate()); |
3011 | |
3012 | EXPECT_TRUE(builder.Build(&err)); |
3013 | EXPECT_TRUE(builder.AlreadyUpToDate()); |
3014 | |
3015 | deps_log.Close(); |
3016 | builder.command_runner_.release(); |
3017 | } |
3018 | |
3019 | fs_.Tick(); |
3020 | fs_.Create("in1" , "" ); |
3021 | |
3022 | { |
3023 | State state; |
3024 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
3025 | |
3026 | DepsLog deps_log; |
3027 | ASSERT_TRUE(deps_log.Load("ninja_deps" , &state, &err)); |
3028 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
3029 | ASSERT_EQ("" , err); |
3030 | |
3031 | Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0); |
3032 | builder.command_runner_.reset(&command_runner_); |
3033 | EXPECT_TRUE(builder.AddTarget("out2" , &err)); |
3034 | EXPECT_FALSE(builder.AlreadyUpToDate()); |
3035 | |
3036 | EXPECT_TRUE(builder.Build(&err)); |
3037 | EXPECT_TRUE(builder.AlreadyUpToDate()); |
3038 | |
3039 | deps_log.Close(); |
3040 | builder.command_runner_.release(); |
3041 | } |
3042 | |
3043 | fs_.Tick(); |
3044 | |
3045 | { |
3046 | State state; |
3047 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
3048 | |
3049 | DepsLog deps_log; |
3050 | ASSERT_TRUE(deps_log.Load("ninja_deps" , &state, &err)); |
3051 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
3052 | ASSERT_EQ("" , err); |
3053 | |
3054 | Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0); |
3055 | builder.command_runner_.reset(&command_runner_); |
3056 | EXPECT_TRUE(builder.AddTarget("out2" , &err)); |
3057 | EXPECT_TRUE(builder.AlreadyUpToDate()); |
3058 | |
3059 | deps_log.Close(); |
3060 | builder.command_runner_.release(); |
3061 | } |
3062 | } |
3063 | |
3064 | #ifdef _WIN32 |
3065 | TEST_F(BuildWithDepsLogTest, DepFileDepsLogCanonicalize) { |
3066 | string err; |
3067 | const char* manifest = |
3068 | "rule cc\n command = cc $in\n depfile = $out.d\n deps = gcc\n" |
3069 | "build a/b\\c\\d/e/fo$ o.o: cc x\\y/z\\foo.c\n" ; |
3070 | |
3071 | fs_.Create("x/y/z/foo.c" , "" ); |
3072 | |
3073 | { |
3074 | State state; |
3075 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
3076 | |
3077 | // Run the build once, everything should be ok. |
3078 | DepsLog deps_log; |
3079 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
3080 | ASSERT_EQ("" , err); |
3081 | |
3082 | Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0); |
3083 | builder.command_runner_.reset(&command_runner_); |
3084 | EXPECT_TRUE(builder.AddTarget("a/b/c/d/e/fo o.o" , &err)); |
3085 | ASSERT_EQ("" , err); |
3086 | // Note, different slashes from manifest. |
3087 | fs_.Create("a/b\\c\\d/e/fo o.o.d" , |
3088 | "a\\b\\c\\d\\e\\fo\\ o.o: blah.h bar.h\n" ); |
3089 | EXPECT_TRUE(builder.Build(&err)); |
3090 | EXPECT_EQ("" , err); |
3091 | |
3092 | deps_log.Close(); |
3093 | builder.command_runner_.release(); |
3094 | } |
3095 | |
3096 | { |
3097 | State state; |
3098 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
3099 | |
3100 | DepsLog deps_log; |
3101 | ASSERT_TRUE(deps_log.Load("ninja_deps" , &state, &err)); |
3102 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
3103 | ASSERT_EQ("" , err); |
3104 | |
3105 | Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0); |
3106 | builder.command_runner_.reset(&command_runner_); |
3107 | |
3108 | Edge* edge = state.edges_.back(); |
3109 | |
3110 | state.GetNode("bar.h" , 0)->MarkDirty(); // Mark bar.h as missing. |
3111 | EXPECT_TRUE(builder.AddTarget("a/b/c/d/e/fo o.o" , &err)); |
3112 | ASSERT_EQ("" , err); |
3113 | |
3114 | // Expect three new edges: one generating fo o.o, and two more from |
3115 | // loading the depfile. |
3116 | ASSERT_EQ(3u, state.edges_.size()); |
3117 | // Expect our edge to now have three inputs: foo.c and two headers. |
3118 | ASSERT_EQ(3u, edge->inputs_.size()); |
3119 | |
3120 | // Expect the command line we generate to only use the original input. |
3121 | // Note, slashes from manifest, not .d. |
3122 | ASSERT_EQ("cc x\\y/z\\foo.c" , edge->EvaluateCommand()); |
3123 | |
3124 | deps_log.Close(); |
3125 | builder.command_runner_.release(); |
3126 | } |
3127 | } |
3128 | #endif |
3129 | |
3130 | /// Check that a restat rule doesn't clear an edge if the depfile is missing. |
3131 | /// Follows from: https://github.com/ninja-build/ninja/issues/603 |
3132 | TEST_F(BuildTest, RestatMissingDepfile) { |
3133 | const char* manifest = |
3134 | "rule true\n" |
3135 | " command = true\n" // Would be "write if out-of-date" in reality. |
3136 | " restat = 1\n" |
3137 | "build header.h: true header.in\n" |
3138 | "build out: cat header.h\n" |
3139 | " depfile = out.d\n" ; |
3140 | |
3141 | fs_.Create("header.h" , "" ); |
3142 | fs_.Tick(); |
3143 | fs_.Create("out" , "" ); |
3144 | fs_.Create("header.in" , "" ); |
3145 | |
3146 | // Normally, only 'header.h' would be rebuilt, as |
3147 | // its rule doesn't touch the output and has 'restat=1' set. |
3148 | // But we are also missing the depfile for 'out', |
3149 | // which should force its command to run anyway! |
3150 | RebuildTarget("out" , manifest); |
3151 | ASSERT_EQ(2u, command_runner_.commands_ran_.size()); |
3152 | } |
3153 | |
3154 | /// Check that a restat rule doesn't clear an edge if the deps are missing. |
3155 | /// https://github.com/ninja-build/ninja/issues/603 |
3156 | TEST_F(BuildWithDepsLogTest, RestatMissingDepfileDepslog) { |
3157 | string err; |
3158 | const char* manifest = |
3159 | "rule true\n" |
3160 | " command = true\n" // Would be "write if out-of-date" in reality. |
3161 | " restat = 1\n" |
3162 | "build header.h: true header.in\n" |
3163 | "build out: cat header.h\n" |
3164 | " deps = gcc\n" |
3165 | " depfile = out.d\n" ; |
3166 | |
3167 | // Build once to populate ninja deps logs from out.d |
3168 | fs_.Create("header.in" , "" ); |
3169 | fs_.Create("out.d" , "out: header.h" ); |
3170 | fs_.Create("header.h" , "" ); |
3171 | |
3172 | RebuildTarget("out" , manifest, "build_log" , "ninja_deps" ); |
3173 | ASSERT_EQ(2u, command_runner_.commands_ran_.size()); |
3174 | |
3175 | // Sanity: this rebuild should be NOOP |
3176 | RebuildTarget("out" , manifest, "build_log" , "ninja_deps" ); |
3177 | ASSERT_EQ(0u, command_runner_.commands_ran_.size()); |
3178 | |
3179 | // Touch 'header.in', blank dependencies log (create a different one). |
3180 | // Building header.h triggers 'restat' outputs cleanup. |
3181 | // Validate that out is rebuilt netherless, as deps are missing. |
3182 | fs_.Tick(); |
3183 | fs_.Create("header.in" , "" ); |
3184 | |
3185 | // (switch to a new blank deps_log "ninja_deps2") |
3186 | RebuildTarget("out" , manifest, "build_log" , "ninja_deps2" ); |
3187 | ASSERT_EQ(2u, command_runner_.commands_ran_.size()); |
3188 | |
3189 | // Sanity: this build should be NOOP |
3190 | RebuildTarget("out" , manifest, "build_log" , "ninja_deps2" ); |
3191 | ASSERT_EQ(0u, command_runner_.commands_ran_.size()); |
3192 | |
3193 | // Check that invalidating deps by target timestamp also works here |
3194 | // Repeat the test but touch target instead of blanking the log. |
3195 | fs_.Tick(); |
3196 | fs_.Create("header.in" , "" ); |
3197 | fs_.Create("out" , "" ); |
3198 | RebuildTarget("out" , manifest, "build_log" , "ninja_deps2" ); |
3199 | ASSERT_EQ(2u, command_runner_.commands_ran_.size()); |
3200 | |
3201 | // And this build should be NOOP again |
3202 | RebuildTarget("out" , manifest, "build_log" , "ninja_deps2" ); |
3203 | ASSERT_EQ(0u, command_runner_.commands_ran_.size()); |
3204 | } |
3205 | |
3206 | TEST_F(BuildTest, WrongOutputInDepfileCausesRebuild) { |
3207 | string err; |
3208 | const char* manifest = |
3209 | "rule cc\n" |
3210 | " command = cc $in\n" |
3211 | " depfile = $out.d\n" |
3212 | "build foo.o: cc foo.c\n" ; |
3213 | |
3214 | fs_.Create("foo.c" , "" ); |
3215 | fs_.Create("foo.o" , "" ); |
3216 | fs_.Create("header.h" , "" ); |
3217 | fs_.Create("foo.o.d" , "bar.o.d: header.h\n" ); |
3218 | |
3219 | RebuildTarget("foo.o" , manifest, "build_log" , "ninja_deps" ); |
3220 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
3221 | } |
3222 | |
3223 | TEST_F(BuildTest, Console) { |
3224 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3225 | "rule console\n" |
3226 | " command = console\n" |
3227 | " pool = console\n" |
3228 | "build cons: console in.txt\n" )); |
3229 | |
3230 | fs_.Create("in.txt" , "" ); |
3231 | |
3232 | string err; |
3233 | EXPECT_TRUE(builder_.AddTarget("cons" , &err)); |
3234 | ASSERT_EQ("" , err); |
3235 | EXPECT_TRUE(builder_.Build(&err)); |
3236 | EXPECT_EQ("" , err); |
3237 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
3238 | } |
3239 | |
3240 | TEST_F(BuildTest, DyndepMissingAndNoRule) { |
3241 | // Verify that we can diagnose when a dyndep file is missing and |
3242 | // has no rule to build it. |
3243 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3244 | "rule touch\n" |
3245 | " command = touch $out\n" |
3246 | "build out: touch || dd\n" |
3247 | " dyndep = dd\n" |
3248 | )); |
3249 | |
3250 | string err; |
3251 | EXPECT_FALSE(builder_.AddTarget("out" , &err)); |
3252 | EXPECT_EQ("loading 'dd': No such file or directory" , err); |
3253 | } |
3254 | |
3255 | TEST_F(BuildTest, DyndepReadyImplicitConnection) { |
3256 | // Verify that a dyndep file can be loaded immediately to discover |
3257 | // that one edge has an implicit output that is also an implicit |
3258 | // input of another edge. |
3259 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3260 | "rule touch\n" |
3261 | " command = touch $out $out.imp\n" |
3262 | "build tmp: touch || dd\n" |
3263 | " dyndep = dd\n" |
3264 | "build out: touch || dd\n" |
3265 | " dyndep = dd\n" |
3266 | )); |
3267 | fs_.Create("dd" , |
3268 | "ninja_dyndep_version = 1\n" |
3269 | "build out | out.imp: dyndep | tmp.imp\n" |
3270 | "build tmp | tmp.imp: dyndep\n" |
3271 | ); |
3272 | |
3273 | string err; |
3274 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
3275 | ASSERT_EQ("" , err); |
3276 | EXPECT_TRUE(builder_.Build(&err)); |
3277 | EXPECT_EQ("" , err); |
3278 | ASSERT_EQ(2u, command_runner_.commands_ran_.size()); |
3279 | EXPECT_EQ("touch tmp tmp.imp" , command_runner_.commands_ran_[0]); |
3280 | EXPECT_EQ("touch out out.imp" , command_runner_.commands_ran_[1]); |
3281 | } |
3282 | |
3283 | TEST_F(BuildTest, DyndepReadySyntaxError) { |
3284 | // Verify that a dyndep file can be loaded immediately to discover |
3285 | // and reject a syntax error in it. |
3286 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3287 | "rule touch\n" |
3288 | " command = touch $out\n" |
3289 | "build out: touch || dd\n" |
3290 | " dyndep = dd\n" |
3291 | )); |
3292 | fs_.Create("dd" , |
3293 | "build out: dyndep\n" |
3294 | ); |
3295 | |
3296 | string err; |
3297 | EXPECT_FALSE(builder_.AddTarget("out" , &err)); |
3298 | EXPECT_EQ("dd:1: expected 'ninja_dyndep_version = ...'\n" , err); |
3299 | } |
3300 | |
3301 | TEST_F(BuildTest, DyndepReadyCircular) { |
3302 | // Verify that a dyndep file can be loaded immediately to discover |
3303 | // and reject a circular dependency. |
3304 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3305 | "rule r\n" |
3306 | " command = unused\n" |
3307 | "build out: r in || dd\n" |
3308 | " dyndep = dd\n" |
3309 | "build in: r circ\n" |
3310 | )); |
3311 | fs_.Create("dd" , |
3312 | "ninja_dyndep_version = 1\n" |
3313 | "build out | circ: dyndep\n" |
3314 | ); |
3315 | fs_.Create("out" , "" ); |
3316 | |
3317 | string err; |
3318 | EXPECT_FALSE(builder_.AddTarget("out" , &err)); |
3319 | EXPECT_EQ("dependency cycle: circ -> in -> circ" , err); |
3320 | } |
3321 | |
3322 | TEST_F(BuildTest, DyndepBuild) { |
3323 | // Verify that a dyndep file can be built and loaded to discover nothing. |
3324 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3325 | "rule touch\n" |
3326 | " command = touch $out\n" |
3327 | "rule cp\n" |
3328 | " command = cp $in $out\n" |
3329 | "build dd: cp dd-in\n" |
3330 | "build out: touch || dd\n" |
3331 | " dyndep = dd\n" |
3332 | )); |
3333 | fs_.Create("dd-in" , |
3334 | "ninja_dyndep_version = 1\n" |
3335 | "build out: dyndep\n" |
3336 | ); |
3337 | |
3338 | string err; |
3339 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
3340 | EXPECT_EQ("" , err); |
3341 | |
3342 | size_t files_created = fs_.files_created_.size(); |
3343 | EXPECT_TRUE(builder_.Build(&err)); |
3344 | EXPECT_EQ("" , err); |
3345 | |
3346 | ASSERT_EQ(2u, command_runner_.commands_ran_.size()); |
3347 | EXPECT_EQ("cp dd-in dd" , command_runner_.commands_ran_[0]); |
3348 | EXPECT_EQ("touch out" , command_runner_.commands_ran_[1]); |
3349 | ASSERT_EQ(2u, fs_.files_read_.size()); |
3350 | EXPECT_EQ("dd-in" , fs_.files_read_[0]); |
3351 | EXPECT_EQ("dd" , fs_.files_read_[1]); |
3352 | ASSERT_EQ(3u + files_created, fs_.files_created_.size()); |
3353 | EXPECT_EQ(1u, fs_.files_created_.count("dd" )); |
3354 | EXPECT_EQ(1u, fs_.files_created_.count("out" )); |
3355 | EXPECT_EQ(1u, fs_.files_created_.count(".ninja_lock" )); |
3356 | } |
3357 | |
3358 | TEST_F(BuildTest, DyndepBuildSyntaxError) { |
3359 | // Verify that a dyndep file can be built and loaded to discover |
3360 | // and reject a syntax error in it. |
3361 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3362 | "rule touch\n" |
3363 | " command = touch $out\n" |
3364 | "rule cp\n" |
3365 | " command = cp $in $out\n" |
3366 | "build dd: cp dd-in\n" |
3367 | "build out: touch || dd\n" |
3368 | " dyndep = dd\n" |
3369 | )); |
3370 | fs_.Create("dd-in" , |
3371 | "build out: dyndep\n" |
3372 | ); |
3373 | |
3374 | string err; |
3375 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
3376 | EXPECT_EQ("" , err); |
3377 | |
3378 | EXPECT_FALSE(builder_.Build(&err)); |
3379 | EXPECT_EQ("dd:1: expected 'ninja_dyndep_version = ...'\n" , err); |
3380 | } |
3381 | |
3382 | TEST_F(BuildTest, DyndepBuildUnrelatedOutput) { |
3383 | // Verify that a dyndep file can have dependents that do not specify |
3384 | // it as their dyndep binding. |
3385 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3386 | "rule touch\n" |
3387 | " command = touch $out\n" |
3388 | "rule cp\n" |
3389 | " command = cp $in $out\n" |
3390 | "build dd: cp dd-in\n" |
3391 | "build unrelated: touch || dd\n" |
3392 | "build out: touch unrelated || dd\n" |
3393 | " dyndep = dd\n" |
3394 | )); |
3395 | fs_.Create("dd-in" , |
3396 | "ninja_dyndep_version = 1\n" |
3397 | "build out: dyndep\n" |
3398 | ); |
3399 | fs_.Tick(); |
3400 | fs_.Create("out" , "" ); |
3401 | |
3402 | string err; |
3403 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
3404 | EXPECT_EQ("" , err); |
3405 | |
3406 | EXPECT_TRUE(builder_.Build(&err)); |
3407 | EXPECT_EQ("" , err); |
3408 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
3409 | EXPECT_EQ("cp dd-in dd" , command_runner_.commands_ran_[0]); |
3410 | EXPECT_EQ("touch unrelated" , command_runner_.commands_ran_[1]); |
3411 | EXPECT_EQ("touch out" , command_runner_.commands_ran_[2]); |
3412 | } |
3413 | |
3414 | TEST_F(BuildTest, DyndepBuildDiscoverNewOutput) { |
3415 | // Verify that a dyndep file can be built and loaded to discover |
3416 | // a new output of an edge. |
3417 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3418 | "rule touch\n" |
3419 | " command = touch $out $out.imp\n" |
3420 | "rule cp\n" |
3421 | " command = cp $in $out\n" |
3422 | "build dd: cp dd-in\n" |
3423 | "build out: touch in || dd\n" |
3424 | " dyndep = dd\n" |
3425 | )); |
3426 | fs_.Create("in" , "" ); |
3427 | fs_.Create("dd-in" , |
3428 | "ninja_dyndep_version = 1\n" |
3429 | "build out | out.imp: dyndep\n" |
3430 | ); |
3431 | fs_.Tick(); |
3432 | fs_.Create("out" , "" ); |
3433 | |
3434 | string err; |
3435 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
3436 | EXPECT_EQ("" , err); |
3437 | |
3438 | EXPECT_TRUE(builder_.Build(&err)); |
3439 | EXPECT_EQ("" , err); |
3440 | ASSERT_EQ(2u, command_runner_.commands_ran_.size()); |
3441 | EXPECT_EQ("cp dd-in dd" , command_runner_.commands_ran_[0]); |
3442 | EXPECT_EQ("touch out out.imp" , command_runner_.commands_ran_[1]); |
3443 | } |
3444 | |
3445 | TEST_F(BuildTest, DyndepBuildDiscoverNewOutputWithMultipleRules1) { |
3446 | // Verify that a dyndep file can be built and loaded to discover |
3447 | // a new output of an edge that is already the output of another edge. |
3448 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3449 | "rule touch\n" |
3450 | " command = touch $out $out.imp\n" |
3451 | "rule cp\n" |
3452 | " command = cp $in $out\n" |
3453 | "build dd: cp dd-in\n" |
3454 | "build out1 | out-twice.imp: touch in\n" |
3455 | "build out2: touch in || dd\n" |
3456 | " dyndep = dd\n" |
3457 | )); |
3458 | fs_.Create("in" , "" ); |
3459 | fs_.Create("dd-in" , |
3460 | "ninja_dyndep_version = 1\n" |
3461 | "build out2 | out-twice.imp: dyndep\n" |
3462 | ); |
3463 | fs_.Tick(); |
3464 | fs_.Create("out1" , "" ); |
3465 | fs_.Create("out2" , "" ); |
3466 | |
3467 | string err; |
3468 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
3469 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
3470 | EXPECT_EQ("" , err); |
3471 | |
3472 | EXPECT_FALSE(builder_.Build(&err)); |
3473 | EXPECT_EQ("multiple rules generate out-twice.imp" , err); |
3474 | } |
3475 | |
3476 | TEST_F(BuildTest, DyndepBuildDiscoverNewOutputWithMultipleRules2) { |
3477 | // Verify that a dyndep file can be built and loaded to discover |
3478 | // a new output of an edge that is already the output of another |
3479 | // edge also discovered by dyndep. |
3480 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3481 | "rule touch\n" |
3482 | " command = touch $out $out.imp\n" |
3483 | "rule cp\n" |
3484 | " command = cp $in $out\n" |
3485 | "build dd1: cp dd1-in\n" |
3486 | "build out1: touch || dd1\n" |
3487 | " dyndep = dd1\n" |
3488 | "build dd2: cp dd2-in || dd1\n" // make order predictable for test |
3489 | "build out2: touch || dd2\n" |
3490 | " dyndep = dd2\n" |
3491 | )); |
3492 | fs_.Create("out1" , "" ); |
3493 | fs_.Create("out2" , "" ); |
3494 | fs_.Create("dd1-in" , |
3495 | "ninja_dyndep_version = 1\n" |
3496 | "build out1 | out-twice.imp: dyndep\n" |
3497 | ); |
3498 | fs_.Create("dd2-in" , "" ); |
3499 | fs_.Create("dd2" , |
3500 | "ninja_dyndep_version = 1\n" |
3501 | "build out2 | out-twice.imp: dyndep\n" |
3502 | ); |
3503 | fs_.Tick(); |
3504 | fs_.Create("out1" , "" ); |
3505 | fs_.Create("out2" , "" ); |
3506 | |
3507 | string err; |
3508 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
3509 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
3510 | EXPECT_EQ("" , err); |
3511 | |
3512 | EXPECT_FALSE(builder_.Build(&err)); |
3513 | EXPECT_EQ("multiple rules generate out-twice.imp" , err); |
3514 | } |
3515 | |
3516 | TEST_F(BuildTest, DyndepBuildDiscoverNewInput) { |
3517 | // Verify that a dyndep file can be built and loaded to discover |
3518 | // a new input to an edge. |
3519 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3520 | "rule touch\n" |
3521 | " command = touch $out\n" |
3522 | "rule cp\n" |
3523 | " command = cp $in $out\n" |
3524 | "build dd: cp dd-in\n" |
3525 | "build in: touch\n" |
3526 | "build out: touch || dd\n" |
3527 | " dyndep = dd\n" |
3528 | )); |
3529 | fs_.Create("dd-in" , |
3530 | "ninja_dyndep_version = 1\n" |
3531 | "build out: dyndep | in\n" |
3532 | ); |
3533 | fs_.Tick(); |
3534 | fs_.Create("out" , "" ); |
3535 | |
3536 | string err; |
3537 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
3538 | EXPECT_EQ("" , err); |
3539 | |
3540 | EXPECT_TRUE(builder_.Build(&err)); |
3541 | EXPECT_EQ("" , err); |
3542 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
3543 | EXPECT_EQ("cp dd-in dd" , command_runner_.commands_ran_[0]); |
3544 | EXPECT_EQ("touch in" , command_runner_.commands_ran_[1]); |
3545 | EXPECT_EQ("touch out" , command_runner_.commands_ran_[2]); |
3546 | } |
3547 | |
3548 | TEST_F(BuildTest, DyndepBuildDiscoverNewInputWithValidation) { |
3549 | // Verify that a dyndep file cannot contain the |@ validation |
3550 | // syntax. |
3551 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3552 | "rule touch\n" |
3553 | " command = touch $out\n" |
3554 | "rule cp\n" |
3555 | " command = cp $in $out\n" |
3556 | "build dd: cp dd-in\n" |
3557 | "build out: touch || dd\n" |
3558 | " dyndep = dd\n" |
3559 | )); |
3560 | fs_.Create("dd-in" , |
3561 | "ninja_dyndep_version = 1\n" |
3562 | "build out: dyndep |@ validation\n" |
3563 | ); |
3564 | |
3565 | string err; |
3566 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
3567 | EXPECT_EQ("" , err); |
3568 | |
3569 | EXPECT_FALSE(builder_.Build(&err)); |
3570 | |
3571 | string err_first_line = err.substr(0, err.find("\n" )); |
3572 | EXPECT_EQ("dd:2: expected newline, got '|@'" , err_first_line); |
3573 | } |
3574 | |
3575 | TEST_F(BuildTest, DyndepBuildDiscoverNewInputWithTransitiveValidation) { |
3576 | // Verify that a dyndep file can be built and loaded to discover |
3577 | // a new input to an edge that has a validation edge. |
3578 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3579 | "rule touch\n" |
3580 | " command = touch $out\n" |
3581 | "rule cp\n" |
3582 | " command = cp $in $out\n" |
3583 | "build dd: cp dd-in\n" |
3584 | "build in: touch |@ validation\n" |
3585 | "build validation: touch in out\n" |
3586 | "build out: touch || dd\n" |
3587 | " dyndep = dd\n" |
3588 | )); |
3589 | fs_.Create("dd-in" , |
3590 | "ninja_dyndep_version = 1\n" |
3591 | "build out: dyndep | in\n" |
3592 | ); |
3593 | fs_.Tick(); |
3594 | fs_.Create("out" , "" ); |
3595 | |
3596 | string err; |
3597 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
3598 | EXPECT_EQ("" , err); |
3599 | |
3600 | EXPECT_TRUE(builder_.Build(&err)); |
3601 | EXPECT_EQ("" , err); |
3602 | ASSERT_EQ(4u, command_runner_.commands_ran_.size()); |
3603 | EXPECT_EQ("cp dd-in dd" , command_runner_.commands_ran_[0]); |
3604 | EXPECT_EQ("touch in" , command_runner_.commands_ran_[1]); |
3605 | EXPECT_EQ("touch out" , command_runner_.commands_ran_[2]); |
3606 | EXPECT_EQ("touch validation" , command_runner_.commands_ran_[3]); |
3607 | } |
3608 | |
3609 | TEST_F(BuildTest, DyndepBuildDiscoverImplicitConnection) { |
3610 | // Verify that a dyndep file can be built and loaded to discover |
3611 | // that one edge has an implicit output that is also an implicit |
3612 | // input of another edge. |
3613 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3614 | "rule touch\n" |
3615 | " command = touch $out $out.imp\n" |
3616 | "rule cp\n" |
3617 | " command = cp $in $out\n" |
3618 | "build dd: cp dd-in\n" |
3619 | "build tmp: touch || dd\n" |
3620 | " dyndep = dd\n" |
3621 | "build out: touch || dd\n" |
3622 | " dyndep = dd\n" |
3623 | )); |
3624 | fs_.Create("dd-in" , |
3625 | "ninja_dyndep_version = 1\n" |
3626 | "build out | out.imp: dyndep | tmp.imp\n" |
3627 | "build tmp | tmp.imp: dyndep\n" |
3628 | ); |
3629 | |
3630 | string err; |
3631 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
3632 | ASSERT_EQ("" , err); |
3633 | EXPECT_TRUE(builder_.Build(&err)); |
3634 | EXPECT_EQ("" , err); |
3635 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
3636 | EXPECT_EQ("cp dd-in dd" , command_runner_.commands_ran_[0]); |
3637 | EXPECT_EQ("touch tmp tmp.imp" , command_runner_.commands_ran_[1]); |
3638 | EXPECT_EQ("touch out out.imp" , command_runner_.commands_ran_[2]); |
3639 | } |
3640 | |
3641 | TEST_F(BuildTest, DyndepBuildDiscoverOutputAndDepfileInput) { |
3642 | // Verify that a dyndep file can be built and loaded to discover |
3643 | // that one edge has an implicit output that is also reported by |
3644 | // a depfile as an input of another edge. |
3645 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3646 | "rule touch\n" |
3647 | " command = touch $out $out.imp\n" |
3648 | "rule cp\n" |
3649 | " command = cp $in $out\n" |
3650 | "build dd: cp dd-in\n" |
3651 | "build tmp: touch || dd\n" |
3652 | " dyndep = dd\n" |
3653 | "build out: cp tmp\n" |
3654 | " depfile = out.d\n" |
3655 | )); |
3656 | fs_.Create("out.d" , "out: tmp.imp\n" ); |
3657 | fs_.Create("dd-in" , |
3658 | "ninja_dyndep_version = 1\n" |
3659 | "build tmp | tmp.imp: dyndep\n" |
3660 | ); |
3661 | |
3662 | string err; |
3663 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
3664 | ASSERT_EQ("" , err); |
3665 | |
3666 | // Loading the depfile gave tmp.imp a phony input edge. |
3667 | ASSERT_TRUE(GetNode("tmp.imp" )->in_edge()->is_phony()); |
3668 | |
3669 | EXPECT_TRUE(builder_.Build(&err)); |
3670 | EXPECT_EQ("" , err); |
3671 | |
3672 | // Loading the dyndep file gave tmp.imp a real input edge. |
3673 | ASSERT_FALSE(GetNode("tmp.imp" )->in_edge()->is_phony()); |
3674 | |
3675 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
3676 | EXPECT_EQ("cp dd-in dd" , command_runner_.commands_ran_[0]); |
3677 | EXPECT_EQ("touch tmp tmp.imp" , command_runner_.commands_ran_[1]); |
3678 | EXPECT_EQ("cp tmp out" , command_runner_.commands_ran_[2]); |
3679 | EXPECT_EQ(1u, fs_.files_created_.count("tmp.imp" )); |
3680 | EXPECT_TRUE(builder_.AlreadyUpToDate()); |
3681 | } |
3682 | |
3683 | TEST_F(BuildTest, DyndepBuildDiscoverNowWantEdge) { |
3684 | // Verify that a dyndep file can be built and loaded to discover |
3685 | // that an edge is actually wanted due to a missing implicit output. |
3686 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3687 | "rule touch\n" |
3688 | " command = touch $out $out.imp\n" |
3689 | "rule cp\n" |
3690 | " command = cp $in $out\n" |
3691 | "build dd: cp dd-in\n" |
3692 | "build tmp: touch || dd\n" |
3693 | " dyndep = dd\n" |
3694 | "build out: touch tmp || dd\n" |
3695 | " dyndep = dd\n" |
3696 | )); |
3697 | fs_.Create("tmp" , "" ); |
3698 | fs_.Create("out" , "" ); |
3699 | fs_.Create("dd-in" , |
3700 | "ninja_dyndep_version = 1\n" |
3701 | "build out: dyndep\n" |
3702 | "build tmp | tmp.imp: dyndep\n" |
3703 | ); |
3704 | |
3705 | string err; |
3706 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
3707 | ASSERT_EQ("" , err); |
3708 | EXPECT_TRUE(builder_.Build(&err)); |
3709 | EXPECT_EQ("" , err); |
3710 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
3711 | EXPECT_EQ("cp dd-in dd" , command_runner_.commands_ran_[0]); |
3712 | EXPECT_EQ("touch tmp tmp.imp" , command_runner_.commands_ran_[1]); |
3713 | EXPECT_EQ("touch out out.imp" , command_runner_.commands_ran_[2]); |
3714 | } |
3715 | |
3716 | TEST_F(BuildTest, DyndepBuildDiscoverNowWantEdgeAndDependent) { |
3717 | // Verify that a dyndep file can be built and loaded to discover |
3718 | // that an edge and a dependent are actually wanted. |
3719 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3720 | "rule touch\n" |
3721 | " command = touch $out $out.imp\n" |
3722 | "rule cp\n" |
3723 | " command = cp $in $out\n" |
3724 | "build dd: cp dd-in\n" |
3725 | "build tmp: touch || dd\n" |
3726 | " dyndep = dd\n" |
3727 | "build out: touch tmp\n" |
3728 | )); |
3729 | fs_.Create("tmp" , "" ); |
3730 | fs_.Create("out" , "" ); |
3731 | fs_.Create("dd-in" , |
3732 | "ninja_dyndep_version = 1\n" |
3733 | "build tmp | tmp.imp: dyndep\n" |
3734 | ); |
3735 | |
3736 | string err; |
3737 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
3738 | ASSERT_EQ("" , err); |
3739 | EXPECT_TRUE(builder_.Build(&err)); |
3740 | EXPECT_EQ("" , err); |
3741 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
3742 | EXPECT_EQ("cp dd-in dd" , command_runner_.commands_ran_[0]); |
3743 | EXPECT_EQ("touch tmp tmp.imp" , command_runner_.commands_ran_[1]); |
3744 | EXPECT_EQ("touch out out.imp" , command_runner_.commands_ran_[2]); |
3745 | } |
3746 | |
3747 | TEST_F(BuildTest, DyndepBuildDiscoverCircular) { |
3748 | // Verify that a dyndep file can be built and loaded to discover |
3749 | // and reject a circular dependency. |
3750 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3751 | "rule r\n" |
3752 | " command = unused\n" |
3753 | "rule cp\n" |
3754 | " command = cp $in $out\n" |
3755 | "build dd: cp dd-in\n" |
3756 | "build out: r in || dd\n" |
3757 | " depfile = out.d\n" |
3758 | " dyndep = dd\n" |
3759 | "build in: r || dd\n" |
3760 | " dyndep = dd\n" |
3761 | )); |
3762 | fs_.Create("out.d" , "out: inimp\n" ); |
3763 | fs_.Create("dd-in" , |
3764 | "ninja_dyndep_version = 1\n" |
3765 | "build out | circ: dyndep\n" |
3766 | "build in: dyndep | circ\n" |
3767 | ); |
3768 | fs_.Create("out" , "" ); |
3769 | |
3770 | string err; |
3771 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
3772 | EXPECT_EQ("" , err); |
3773 | |
3774 | EXPECT_FALSE(builder_.Build(&err)); |
3775 | // Depending on how the pointers in Plan::ready_ work out, we could have |
3776 | // discovered the cycle from either starting point. |
3777 | EXPECT_TRUE(err == "dependency cycle: circ -> in -> circ" || |
3778 | err == "dependency cycle: in -> circ -> in" ); |
3779 | } |
3780 | |
3781 | TEST_F(BuildWithLogTest, DyndepBuildDiscoverRestat) { |
3782 | // Verify that a dyndep file can be built and loaded to discover |
3783 | // that an edge has a restat binding. |
3784 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3785 | "rule true\n" |
3786 | " command = true\n" |
3787 | "rule cp\n" |
3788 | " command = cp $in $out\n" |
3789 | "build dd: cp dd-in\n" |
3790 | "build out1: true in || dd\n" |
3791 | " dyndep = dd\n" |
3792 | "build out2: cat out1\n" )); |
3793 | |
3794 | fs_.Create("out1" , "" ); |
3795 | fs_.Create("out2" , "" ); |
3796 | fs_.Create("dd-in" , |
3797 | "ninja_dyndep_version = 1\n" |
3798 | "build out1: dyndep\n" |
3799 | " restat = 1\n" |
3800 | ); |
3801 | fs_.Tick(); |
3802 | fs_.Create("in" , "" ); |
3803 | |
3804 | // Do a pre-build so that there's commands in the log for the outputs, |
3805 | // otherwise, the lack of an entry in the build log will cause "out2" to |
3806 | // rebuild regardless of restat. |
3807 | string err; |
3808 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
3809 | ASSERT_EQ("" , err); |
3810 | EXPECT_TRUE(builder_.Build(&err)); |
3811 | ASSERT_EQ("" , err); |
3812 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
3813 | EXPECT_EQ("cp dd-in dd" , command_runner_.commands_ran_[0]); |
3814 | EXPECT_EQ("true" , command_runner_.commands_ran_[1]); |
3815 | EXPECT_EQ("cat out1 > out2" , command_runner_.commands_ran_[2]); |
3816 | |
3817 | command_runner_.commands_ran_.clear(); |
3818 | state_.Reset(); |
3819 | fs_.Tick(); |
3820 | fs_.Create("in" , "" ); |
3821 | |
3822 | // We touched "in", so we should build "out1". But because "true" does not |
3823 | // touch "out1", we should cancel the build of "out2". |
3824 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
3825 | ASSERT_EQ("" , err); |
3826 | EXPECT_TRUE(builder_.Build(&err)); |
3827 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
3828 | EXPECT_EQ("true" , command_runner_.commands_ran_[0]); |
3829 | } |
3830 | |
3831 | TEST_F(BuildTest, DyndepBuildDiscoverScheduledEdge) { |
3832 | // Verify that a dyndep file can be built and loaded to discover a |
3833 | // new input that itself is an output from an edge that has already |
3834 | // been scheduled but not finished. We should not re-schedule it. |
3835 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3836 | "rule touch\n" |
3837 | " command = touch $out $out.imp\n" |
3838 | "rule cp\n" |
3839 | " command = cp $in $out\n" |
3840 | "build out1 | out1.imp: touch\n" |
3841 | "build zdd: cp zdd-in\n" |
3842 | " verify_active_edge = out1\n" // verify out1 is active when zdd is finished |
3843 | "build out2: cp out1 || zdd\n" |
3844 | " dyndep = zdd\n" |
3845 | )); |
3846 | fs_.Create("zdd-in" , |
3847 | "ninja_dyndep_version = 1\n" |
3848 | "build out2: dyndep | out1.imp\n" |
3849 | ); |
3850 | |
3851 | // Enable concurrent builds so that we can load the dyndep file |
3852 | // while another edge is still active. |
3853 | command_runner_.max_active_edges_ = 2; |
3854 | |
3855 | // During the build "out1" and "zdd" should be built concurrently. |
3856 | // The fake command runner will finish these in reverse order |
3857 | // of the names of the first outputs, so "zdd" will finish first |
3858 | // and we will load the dyndep file while the edge for "out1" is |
3859 | // still active. This will add a new dependency on "out1.imp", |
3860 | // also produced by the active edge. The builder should not |
3861 | // re-schedule the already-active edge. |
3862 | |
3863 | string err; |
3864 | EXPECT_TRUE(builder_.AddTarget("out1" , &err)); |
3865 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
3866 | ASSERT_EQ("" , err); |
3867 | EXPECT_TRUE(builder_.Build(&err)); |
3868 | EXPECT_EQ("" , err); |
3869 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
3870 | // Depending on how the pointers in Plan::ready_ work out, the first |
3871 | // two commands may have run in either order. |
3872 | EXPECT_TRUE((command_runner_.commands_ran_[0] == "touch out1 out1.imp" && |
3873 | command_runner_.commands_ran_[1] == "cp zdd-in zdd" ) || |
3874 | (command_runner_.commands_ran_[1] == "touch out1 out1.imp" && |
3875 | command_runner_.commands_ran_[0] == "cp zdd-in zdd" )); |
3876 | EXPECT_EQ("cp out1 out2" , command_runner_.commands_ran_[2]); |
3877 | } |
3878 | |
3879 | TEST_F(BuildTest, DyndepTwoLevelDirect) { |
3880 | // Verify that a clean dyndep file can depend on a dirty dyndep file |
3881 | // and be loaded properly after the dirty one is built and loaded. |
3882 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3883 | "rule touch\n" |
3884 | " command = touch $out $out.imp\n" |
3885 | "rule cp\n" |
3886 | " command = cp $in $out\n" |
3887 | "build dd1: cp dd1-in\n" |
3888 | "build out1 | out1.imp: touch || dd1\n" |
3889 | " dyndep = dd1\n" |
3890 | "build dd2: cp dd2-in || dd1\n" // direct order-only dep on dd1 |
3891 | "build out2: touch || dd2\n" |
3892 | " dyndep = dd2\n" |
3893 | )); |
3894 | fs_.Create("out1.imp" , "" ); |
3895 | fs_.Create("out2" , "" ); |
3896 | fs_.Create("out2.imp" , "" ); |
3897 | fs_.Create("dd1-in" , |
3898 | "ninja_dyndep_version = 1\n" |
3899 | "build out1: dyndep\n" |
3900 | ); |
3901 | fs_.Create("dd2-in" , "" ); |
3902 | fs_.Create("dd2" , |
3903 | "ninja_dyndep_version = 1\n" |
3904 | "build out2 | out2.imp: dyndep | out1.imp\n" |
3905 | ); |
3906 | |
3907 | // During the build dd1 should be built and loaded. The RecomputeDirty |
3908 | // called as a result of loading dd1 should not cause dd2 to be loaded |
3909 | // because the builder will never get a chance to update the build plan |
3910 | // to account for dd2. Instead dd2 should only be later loaded once the |
3911 | // builder recognizes that it is now ready (as its order-only dependency |
3912 | // on dd1 has been satisfied). This test case verifies that each dyndep |
3913 | // file is loaded to update the build graph independently. |
3914 | |
3915 | string err; |
3916 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
3917 | ASSERT_EQ("" , err); |
3918 | EXPECT_TRUE(builder_.Build(&err)); |
3919 | EXPECT_EQ("" , err); |
3920 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
3921 | EXPECT_EQ("cp dd1-in dd1" , command_runner_.commands_ran_[0]); |
3922 | EXPECT_EQ("touch out1 out1.imp" , command_runner_.commands_ran_[1]); |
3923 | EXPECT_EQ("touch out2 out2.imp" , command_runner_.commands_ran_[2]); |
3924 | } |
3925 | |
3926 | TEST_F(BuildTest, DyndepTwoLevelIndirect) { |
3927 | // Verify that dyndep files can add to an edge new implicit inputs that |
3928 | // correspond to implicit outputs added to other edges by other dyndep |
3929 | // files on which they (order-only) depend. |
3930 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3931 | "rule touch\n" |
3932 | " command = touch $out $out.imp\n" |
3933 | "rule cp\n" |
3934 | " command = cp $in $out\n" |
3935 | "build dd1: cp dd1-in\n" |
3936 | "build out1: touch || dd1\n" |
3937 | " dyndep = dd1\n" |
3938 | "build dd2: cp dd2-in || out1\n" // indirect order-only dep on dd1 |
3939 | "build out2: touch || dd2\n" |
3940 | " dyndep = dd2\n" |
3941 | )); |
3942 | fs_.Create("out1.imp" , "" ); |
3943 | fs_.Create("out2" , "" ); |
3944 | fs_.Create("out2.imp" , "" ); |
3945 | fs_.Create("dd1-in" , |
3946 | "ninja_dyndep_version = 1\n" |
3947 | "build out1 | out1.imp: dyndep\n" |
3948 | ); |
3949 | fs_.Create("dd2-in" , "" ); |
3950 | fs_.Create("dd2" , |
3951 | "ninja_dyndep_version = 1\n" |
3952 | "build out2 | out2.imp: dyndep | out1.imp\n" |
3953 | ); |
3954 | |
3955 | // During the build dd1 should be built and loaded. Then dd2 should |
3956 | // be built and loaded. Loading dd2 should cause the builder to |
3957 | // recognize that out2 needs to be built even though it was originally |
3958 | // clean without dyndep info. |
3959 | |
3960 | string err; |
3961 | EXPECT_TRUE(builder_.AddTarget("out2" , &err)); |
3962 | ASSERT_EQ("" , err); |
3963 | EXPECT_TRUE(builder_.Build(&err)); |
3964 | EXPECT_EQ("" , err); |
3965 | ASSERT_EQ(3u, command_runner_.commands_ran_.size()); |
3966 | EXPECT_EQ("cp dd1-in dd1" , command_runner_.commands_ran_[0]); |
3967 | EXPECT_EQ("touch out1 out1.imp" , command_runner_.commands_ran_[1]); |
3968 | EXPECT_EQ("touch out2 out2.imp" , command_runner_.commands_ran_[2]); |
3969 | } |
3970 | |
3971 | TEST_F(BuildTest, DyndepTwoLevelDiscoveredReady) { |
3972 | // Verify that a dyndep file can discover a new input whose |
3973 | // edge also has a dyndep file that is ready to load immediately. |
3974 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
3975 | "rule touch\n" |
3976 | " command = touch $out\n" |
3977 | "rule cp\n" |
3978 | " command = cp $in $out\n" |
3979 | "build dd0: cp dd0-in\n" |
3980 | "build dd1: cp dd1-in\n" |
3981 | "build in: touch\n" |
3982 | "build tmp: touch || dd0\n" |
3983 | " dyndep = dd0\n" |
3984 | "build out: touch || dd1\n" |
3985 | " dyndep = dd1\n" |
3986 | )); |
3987 | fs_.Create("dd1-in" , |
3988 | "ninja_dyndep_version = 1\n" |
3989 | "build out: dyndep | tmp\n" |
3990 | ); |
3991 | fs_.Create("dd0-in" , "" ); |
3992 | fs_.Create("dd0" , |
3993 | "ninja_dyndep_version = 1\n" |
3994 | "build tmp: dyndep | in\n" |
3995 | ); |
3996 | fs_.Tick(); |
3997 | fs_.Create("out" , "" ); |
3998 | |
3999 | string err; |
4000 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
4001 | EXPECT_EQ("" , err); |
4002 | |
4003 | EXPECT_TRUE(builder_.Build(&err)); |
4004 | EXPECT_EQ("" , err); |
4005 | ASSERT_EQ(4u, command_runner_.commands_ran_.size()); |
4006 | EXPECT_EQ("cp dd1-in dd1" , command_runner_.commands_ran_[0]); |
4007 | EXPECT_EQ("touch in" , command_runner_.commands_ran_[1]); |
4008 | EXPECT_EQ("touch tmp" , command_runner_.commands_ran_[2]); |
4009 | EXPECT_EQ("touch out" , command_runner_.commands_ran_[3]); |
4010 | } |
4011 | |
4012 | TEST_F(BuildTest, DyndepTwoLevelDiscoveredDirty) { |
4013 | // Verify that a dyndep file can discover a new input whose |
4014 | // edge also has a dyndep file that needs to be built. |
4015 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
4016 | "rule touch\n" |
4017 | " command = touch $out\n" |
4018 | "rule cp\n" |
4019 | " command = cp $in $out\n" |
4020 | "build dd0: cp dd0-in\n" |
4021 | "build dd1: cp dd1-in\n" |
4022 | "build in: touch\n" |
4023 | "build tmp: touch || dd0\n" |
4024 | " dyndep = dd0\n" |
4025 | "build out: touch || dd1\n" |
4026 | " dyndep = dd1\n" |
4027 | )); |
4028 | fs_.Create("dd1-in" , |
4029 | "ninja_dyndep_version = 1\n" |
4030 | "build out: dyndep | tmp\n" |
4031 | ); |
4032 | fs_.Create("dd0-in" , |
4033 | "ninja_dyndep_version = 1\n" |
4034 | "build tmp: dyndep | in\n" |
4035 | ); |
4036 | fs_.Tick(); |
4037 | fs_.Create("out" , "" ); |
4038 | |
4039 | string err; |
4040 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
4041 | EXPECT_EQ("" , err); |
4042 | |
4043 | EXPECT_TRUE(builder_.Build(&err)); |
4044 | EXPECT_EQ("" , err); |
4045 | ASSERT_EQ(5u, command_runner_.commands_ran_.size()); |
4046 | EXPECT_EQ("cp dd1-in dd1" , command_runner_.commands_ran_[0]); |
4047 | EXPECT_EQ("cp dd0-in dd0" , command_runner_.commands_ran_[1]); |
4048 | EXPECT_EQ("touch in" , command_runner_.commands_ran_[2]); |
4049 | EXPECT_EQ("touch tmp" , command_runner_.commands_ran_[3]); |
4050 | EXPECT_EQ("touch out" , command_runner_.commands_ran_[4]); |
4051 | } |
4052 | |
4053 | TEST_F(BuildTest, Validation) { |
4054 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
4055 | "build out: cat in |@ validate\n" |
4056 | "build validate: cat in2\n" )); |
4057 | |
4058 | fs_.Create("in" , "" ); |
4059 | fs_.Create("in2" , "" ); |
4060 | |
4061 | string err; |
4062 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
4063 | EXPECT_EQ("" , err); |
4064 | |
4065 | EXPECT_TRUE(builder_.Build(&err)); |
4066 | EXPECT_EQ("" , err); |
4067 | |
4068 | EXPECT_EQ(2u, command_runner_.commands_ran_.size()); |
4069 | |
4070 | // Test touching "in" only rebuilds "out" ("validate" doesn't depend on |
4071 | // "out"). |
4072 | fs_.Tick(); |
4073 | fs_.Create("in" , "" ); |
4074 | |
4075 | err.clear(); |
4076 | command_runner_.commands_ran_.clear(); |
4077 | state_.Reset(); |
4078 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
4079 | ASSERT_EQ("" , err); |
4080 | |
4081 | EXPECT_TRUE(builder_.Build(&err)); |
4082 | EXPECT_EQ("" , err); |
4083 | |
4084 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
4085 | EXPECT_EQ("cat in > out" , command_runner_.commands_ran_[0]); |
4086 | |
4087 | // Test touching "in2" only rebuilds "validate" ("out" doesn't depend on |
4088 | // "validate"). |
4089 | fs_.Tick(); |
4090 | fs_.Create("in2" , "" ); |
4091 | |
4092 | err.clear(); |
4093 | command_runner_.commands_ran_.clear(); |
4094 | state_.Reset(); |
4095 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
4096 | ASSERT_EQ("" , err); |
4097 | |
4098 | EXPECT_TRUE(builder_.Build(&err)); |
4099 | EXPECT_EQ("" , err); |
4100 | |
4101 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
4102 | EXPECT_EQ("cat in2 > validate" , command_runner_.commands_ran_[0]); |
4103 | } |
4104 | |
4105 | TEST_F(BuildTest, ValidationDependsOnOutput) { |
4106 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
4107 | "build out: cat in |@ validate\n" |
4108 | "build validate: cat in2 | out\n" )); |
4109 | |
4110 | fs_.Create("in" , "" ); |
4111 | fs_.Create("in2" , "" ); |
4112 | |
4113 | string err; |
4114 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
4115 | EXPECT_EQ("" , err); |
4116 | |
4117 | EXPECT_TRUE(builder_.Build(&err)); |
4118 | EXPECT_EQ("" , err); |
4119 | |
4120 | EXPECT_EQ(2u, command_runner_.commands_ran_.size()); |
4121 | |
4122 | // Test touching "in" rebuilds "out" and "validate". |
4123 | fs_.Tick(); |
4124 | fs_.Create("in" , "" ); |
4125 | |
4126 | err.clear(); |
4127 | command_runner_.commands_ran_.clear(); |
4128 | state_.Reset(); |
4129 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
4130 | ASSERT_EQ("" , err); |
4131 | |
4132 | EXPECT_TRUE(builder_.Build(&err)); |
4133 | EXPECT_EQ("" , err); |
4134 | |
4135 | EXPECT_EQ(2u, command_runner_.commands_ran_.size()); |
4136 | |
4137 | // Test touching "in2" only rebuilds "validate" ("out" doesn't depend on |
4138 | // "validate"). |
4139 | fs_.Tick(); |
4140 | fs_.Create("in2" , "" ); |
4141 | |
4142 | err.clear(); |
4143 | command_runner_.commands_ran_.clear(); |
4144 | state_.Reset(); |
4145 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
4146 | ASSERT_EQ("" , err); |
4147 | |
4148 | EXPECT_TRUE(builder_.Build(&err)); |
4149 | EXPECT_EQ("" , err); |
4150 | |
4151 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
4152 | EXPECT_EQ("cat in2 > validate" , command_runner_.commands_ran_[0]); |
4153 | } |
4154 | |
4155 | TEST_F(BuildWithDepsLogTest, ValidationThroughDepfile) { |
4156 | const char* manifest = |
4157 | "build out: cat in |@ validate\n" |
4158 | "build validate: cat in2 | out\n" |
4159 | "build out2: cat in3\n" |
4160 | " deps = gcc\n" |
4161 | " depfile = out2.d\n" ; |
4162 | |
4163 | string err; |
4164 | |
4165 | { |
4166 | fs_.Create("in" , "" ); |
4167 | fs_.Create("in2" , "" ); |
4168 | fs_.Create("in3" , "" ); |
4169 | fs_.Create("out2.d" , "out: out" ); |
4170 | |
4171 | State state; |
4172 | ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); |
4173 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
4174 | |
4175 | DepsLog deps_log; |
4176 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
4177 | ASSERT_EQ("" , err); |
4178 | |
4179 | Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0); |
4180 | builder.command_runner_.reset(&command_runner_); |
4181 | |
4182 | EXPECT_TRUE(builder.AddTarget("out2" , &err)); |
4183 | ASSERT_EQ("" , err); |
4184 | |
4185 | EXPECT_TRUE(builder.Build(&err)); |
4186 | EXPECT_EQ("" , err); |
4187 | |
4188 | // On the first build, only the out2 command is run. |
4189 | ASSERT_EQ(command_runner_.commands_ran_.size(), 1); |
4190 | EXPECT_EQ("cat in3 > out2" , command_runner_.commands_ran_[0]); |
4191 | |
4192 | // The deps file should have been removed. |
4193 | EXPECT_EQ(0, fs_.Stat("out2.d" , &err)); |
4194 | |
4195 | deps_log.Close(); |
4196 | builder.command_runner_.release(); |
4197 | } |
4198 | |
4199 | fs_.Tick(); |
4200 | command_runner_.commands_ran_.clear(); |
4201 | |
4202 | { |
4203 | fs_.Create("in2" , "" ); |
4204 | fs_.Create("in3" , "" ); |
4205 | |
4206 | State state; |
4207 | ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); |
4208 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); |
4209 | |
4210 | DepsLog deps_log; |
4211 | ASSERT_TRUE(deps_log.Load("ninja_deps" , &state, &err)); |
4212 | ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps" , &err)); |
4213 | ASSERT_EQ("" , err); |
4214 | |
4215 | Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0); |
4216 | builder.command_runner_.reset(&command_runner_); |
4217 | |
4218 | EXPECT_TRUE(builder.AddTarget("out2" , &err)); |
4219 | ASSERT_EQ("" , err); |
4220 | |
4221 | EXPECT_TRUE(builder.Build(&err)); |
4222 | EXPECT_EQ("" , err); |
4223 | |
4224 | // The out and validate actions should have been run as well as out2. |
4225 | ASSERT_EQ(command_runner_.commands_ran_.size(), 3); |
4226 | // out has to run first, as both out2 and validate depend on it. |
4227 | EXPECT_EQ("cat in > out" , command_runner_.commands_ran_[0]); |
4228 | |
4229 | deps_log.Close(); |
4230 | builder.command_runner_.release(); |
4231 | } |
4232 | } |
4233 | |
4234 | TEST_F(BuildTest, ValidationCircular) { |
4235 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
4236 | "build out: cat in |@ out2\n" |
4237 | "build out2: cat in2 |@ out\n" )); |
4238 | |
4239 | fs_.Create("in" , "" ); |
4240 | fs_.Create("in2" , "" ); |
4241 | |
4242 | string err; |
4243 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
4244 | EXPECT_EQ("" , err); |
4245 | |
4246 | EXPECT_TRUE(builder_.Build(&err)); |
4247 | EXPECT_EQ("" , err); |
4248 | |
4249 | EXPECT_EQ(2u, command_runner_.commands_ran_.size()); |
4250 | |
4251 | // Test touching "in" rebuilds "out". |
4252 | fs_.Tick(); |
4253 | fs_.Create("in" , "" ); |
4254 | |
4255 | err.clear(); |
4256 | command_runner_.commands_ran_.clear(); |
4257 | state_.Reset(); |
4258 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
4259 | ASSERT_EQ("" , err); |
4260 | |
4261 | EXPECT_TRUE(builder_.Build(&err)); |
4262 | EXPECT_EQ("" , err); |
4263 | |
4264 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
4265 | EXPECT_EQ("cat in > out" , command_runner_.commands_ran_[0]); |
4266 | |
4267 | // Test touching "in2" rebuilds "out2". |
4268 | fs_.Tick(); |
4269 | fs_.Create("in2" , "" ); |
4270 | |
4271 | err.clear(); |
4272 | command_runner_.commands_ran_.clear(); |
4273 | state_.Reset(); |
4274 | EXPECT_TRUE(builder_.AddTarget("out" , &err)); |
4275 | ASSERT_EQ("" , err); |
4276 | |
4277 | EXPECT_TRUE(builder_.Build(&err)); |
4278 | EXPECT_EQ("" , err); |
4279 | |
4280 | ASSERT_EQ(1u, command_runner_.commands_ran_.size()); |
4281 | EXPECT_EQ("cat in2 > out2" , command_runner_.commands_ran_[0]); |
4282 | } |
4283 | |
4284 | TEST_F(BuildTest, ValidationWithCircularDependency) { |
4285 | ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, |
4286 | "build out: cat in |@ validate\n" |
4287 | "build validate: cat validate_in | out\n" |
4288 | "build validate_in: cat validate\n" )); |
4289 | |
4290 | fs_.Create("in" , "" ); |
4291 | |
4292 | string err; |
4293 | EXPECT_FALSE(builder_.AddTarget("out" , &err)); |
4294 | EXPECT_EQ("dependency cycle: validate -> validate_in -> validate" , err); |
4295 | } |
4296 | |