34 struct CompareEdgesByOutput {
35 static bool cmp(
const Edge* a,
const Edge* b) {
40 for (
int i = 0; i < count; ++i) {
47 sort(ret->begin(), ret->end(), CompareEdgesByOutput::cmp);
55 "build out: cat mid\n" 56 "build mid: cat in\n"));
57 GetNode(
"mid")->MarkDirty();
58 GetNode(
"out")->MarkDirty();
64 Edge* edge = plan_.FindWork();
66 ASSERT_EQ(
"in", edge->inputs_[0]->path());
67 ASSERT_EQ(
"mid", edge->outputs_[0]->path());
73 edge = plan_.FindWork();
75 ASSERT_EQ(
"mid", edge->inputs_[0]->path());
76 ASSERT_EQ(
"out", edge->outputs_[0]->path());
81 edge = plan_.FindWork();
88 "build out: cat mid1 mid2\n" 89 "build mid1 mid2: cat in\n"));
90 GetNode(
"mid1")->MarkDirty();
91 GetNode(
"mid2")->MarkDirty();
92 GetNode(
"out")->MarkDirty();
100 edge = plan_.FindWork();
104 edge = plan_.FindWork();
108 edge = plan_.FindWork();
115 "build out: cat b1 b2\n" 118 "build a1 a2: cat in\n"));
119 GetNode(
"a1")->MarkDirty();
120 GetNode(
"a2")->MarkDirty();
121 GetNode(
"b1")->MarkDirty();
122 GetNode(
"b2")->MarkDirty();
123 GetNode(
"out")->MarkDirty();
125 EXPECT_TRUE(plan_.AddTarget(GetNode(
"out"), &err));
130 edge = plan_.FindWork();
134 edge = plan_.FindWork();
138 edge = plan_.FindWork();
142 edge = plan_.FindWork();
146 edge = plan_.FindWork();
153 "build out: cat a1 a2\n" 154 "build a1: cat mid\n" 155 "build a2: cat mid\n" 156 "build mid: cat in\n"));
157 GetNode(
"mid")->MarkDirty();
158 GetNode(
"a1")->MarkDirty();
159 GetNode(
"a2")->MarkDirty();
160 GetNode(
"out")->MarkDirty();
163 EXPECT_TRUE(plan_.AddTarget(GetNode(
"out"), &err));
168 edge = plan_.FindWork();
172 edge = plan_.FindWork();
176 edge = plan_.FindWork();
180 edge = plan_.FindWork();
184 edge = plan_.FindWork();
201 ASSERT_EQ(
"in", edge->inputs_[0]->path());
202 ASSERT_EQ(
"out1", edge->outputs_[0]->path());
211 ASSERT_EQ(
"in", edge->inputs_[0]->path());
212 ASSERT_EQ(
"out2", edge->outputs_[0]->path());
224 TestPoolWithDepthOne(
228 " command = cat $in > $out\n" 230 "build out1: poolcat in\n" 231 "build out2: poolcat in\n");
235 TestPoolWithDepthOne(
237 " command = cat $in > $out\n" 239 "build out1: poolcat in\n" 240 "build out2: poolcat in\n");
250 " command = cat $in > $out\n" 253 " command = cat $in > $out\n" 255 "build out1: foocat in\n" 256 "build out2: foocat in\n" 257 "build out3: foocat in\n" 258 "build outb1: bazcat in\n" 259 "build outb2: bazcat in\n" 260 "build outb3: bazcat in\n" 262 "build allTheThings: cat out1 out2 out3 outb1 outb2 outb3\n" 265 for (
int i = 0; i < 3; ++i) {
266 GetNode(
"out" +
string(1,
'1' + static_cast<char>(i)))->MarkDirty();
267 GetNode(
"outb" +
string(1,
'1' + static_cast<char>(i)))->MarkDirty();
269 GetNode(
"allTheThings")->MarkDirty();
272 EXPECT_TRUE(plan_.AddTarget(GetNode(
"allTheThings"), &err));
276 FindWorkSorted(&edges, 5);
278 for (
int i = 0; i < 4; ++i) {
279 Edge *edge = edges[i];
281 string base_name(i < 2 ?
"out" :
"outb");
286 Edge* edge = edges[4];
296 Edge* out3 = plan_.FindWork();
307 for (deque<Edge*>::iterator it = edges.begin(); it != edges.end(); ++it) {
311 Edge* last = plan_.FindWork();
326 " command = touch foo.cpp\n" 328 " command = touch bar.cpp\n" 330 " command = echo $out > $out\n" 331 "build foo.cpp.obj: echo foo.cpp || foo.cpp\n" 333 "build bar.cpp.obj: echo bar.cpp || bar.cpp\n" 335 "build libfoo.a: echo foo.cpp.obj bar.cpp.obj\n" 336 "build foo.cpp: gen_foo\n" 337 "build bar.cpp: gen_bar\n" 338 "build all: phony libfoo.a\n"));
339 GetNode(
"foo.cpp")->MarkDirty();
340 GetNode(
"foo.cpp.obj")->MarkDirty();
341 GetNode(
"bar.cpp")->MarkDirty();
342 GetNode(
"bar.cpp.obj")->MarkDirty();
343 GetNode(
"libfoo.a")->MarkDirty();
344 GetNode(
"all")->MarkDirty();
346 EXPECT_TRUE(plan_.AddTarget(GetNode(
"all"), &err));
352 deque<Edge*> initial_edges;
353 FindWorkSorted(&initial_edges, 2);
355 edge = initial_edges[1];
356 ASSERT_EQ(
"foo.cpp", edge->outputs_[0]->path());
359 edge = plan_.FindWork();
362 ASSERT_EQ(
"foo.cpp", edge->inputs_[0]->path());
363 ASSERT_EQ(
"foo.cpp", edge->inputs_[1]->path());
364 ASSERT_EQ(
"foo.cpp.obj", edge->outputs_[0]->path());
367 edge = initial_edges[0];
368 ASSERT_EQ(
"bar.cpp", edge->outputs_[0]->path());
371 edge = plan_.FindWork();
374 ASSERT_EQ(
"bar.cpp", edge->inputs_[0]->path());
375 ASSERT_EQ(
"bar.cpp", edge->inputs_[1]->path());
376 ASSERT_EQ(
"bar.cpp.obj", edge->outputs_[0]->path());
379 edge = plan_.FindWork();
382 ASSERT_EQ(
"foo.cpp.obj", edge->inputs_[0]->path());
383 ASSERT_EQ(
"bar.cpp.obj", edge->inputs_[1]->path());
384 ASSERT_EQ(
"libfoo.a", edge->outputs_[0]->path());
387 edge = plan_.FindWork();
390 ASSERT_EQ(
"libfoo.a", edge->inputs_[0]->path());
391 ASSERT_EQ(
"all", edge->outputs_[0]->path());
394 edge = plan_.FindWork();
404 " command = cat $in > $out\n" 406 "build out1: poolcat in\n" 407 "build out2: poolcat in\n"));
408 GetNode(
"out1")->MarkDirty();
409 GetNode(
"out2")->MarkDirty();
411 EXPECT_TRUE(plan_.AddTarget(GetNode(
"out1"), &err));
413 EXPECT_TRUE(plan_.AddTarget(GetNode(
"out2"), &err));
417 Edge* edge = plan_.FindWork();
419 ASSERT_EQ(
"in", edge->inputs_[0]->path());
420 ASSERT_EQ(
"out1", edge->outputs_[0]->path());
427 edge = plan_.FindWork();
429 ASSERT_EQ(
"in", edge->inputs_[0]->path());
430 ASSERT_EQ(
"out2", edge->outputs_[0]->path());
437 edge = plan_.FindWork();
451 virtual void Abort();
469 "build cat1: cat in1\n" 470 "build cat2: cat in1 in2\n" 471 "build cat12: cat cat1 cat2\n");
486 void RebuildTarget(
const string& target,
const char* manifest,
487 const char* log_path = NULL,
const char* deps_path = NULL,
488 State* state = NULL);
491 void Dirty(
const string& path);
508 const char* log_path,
const char* deps_path,
510 State local_state, *pstate = &local_state;
517 BuildLog build_log, *pbuild_log = NULL;
522 pbuild_log = &build_log;
525 DepsLog deps_log, *pdeps_log = NULL;
530 pdeps_log = &deps_log;
539 bool build_res = builder.
Build(&err);
555 edge->
rule().
name() ==
"cat_rsp_out" ||
558 edge->
rule().
name() ==
"touch-interrupt" ||
559 edge->
rule().
name() ==
"touch-fail-tick2") {
560 for (vector<Node*>::iterator out = edge->
outputs_.begin();
561 out != edge->
outputs_.end(); ++out) {
564 }
else if (edge->
rule().
name() ==
"true" ||
566 edge->
rule().
name() ==
"interrupt" ||
570 printf(
"unknown command\n");
585 if (edge->
rule().
name() ==
"interrupt" ||
586 edge->
rule().
name() ==
"touch-interrupt") {
591 if (edge->
rule().
name() ==
"console") {
600 if (edge->
rule().
name() ==
"fail" ||
645 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
646 EXPECT_EQ(
"cat in1 > cat1", command_runner_.commands_ran_[0]);
659 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
660 EXPECT_EQ(
"cat in1 > cat1", command_runner_.commands_ran_[0]);
669 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
672 EXPECT_TRUE((command_runner_.commands_ran_[0] ==
"cat in1 > cat1" &&
673 command_runner_.commands_ran_[1] ==
"cat in1 in2 > cat2") ||
674 (command_runner_.commands_ran_[1] ==
"cat in1 > cat1" &&
675 command_runner_.commands_ran_[0] ==
"cat in1 in2 > cat2"));
677 EXPECT_EQ(
"cat cat1 cat2 > cat12", command_runner_.commands_ran_[2]);
683 fs_.Create(
"in2",
"");
689 ASSERT_EQ(5u, command_runner_.commands_ran_.size());
690 EXPECT_EQ(
"cat in1 in2 > cat2", command_runner_.commands_ran_[3]);
691 EXPECT_EQ(
"cat cat1 cat2 > cat12", command_runner_.commands_ran_[4]);
697 " command = touch $out\n" 698 "build out1 out2: touch in.txt\n"));
700 fs_.Create(
"in.txt",
"");
707 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
708 EXPECT_EQ(
"touch out1 out2", command_runner_.commands_ran_[0]);
714 " command = touch $out $out.imp\n" 715 "build out | out.imp: touch in.txt\n"));
716 fs_.Create(
"in.txt",
"");
723 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
724 EXPECT_EQ(
"touch out out.imp", command_runner_.commands_ran_[0]);
732 " command = touch $out\n" 733 "build in1 otherfile: touch in\n" 734 "build out: touch in | in1\n"));
736 fs_.Create(
"in",
"");
738 fs_.Create(
"in1",
"");
752 "build c5: cat c4\n"));
754 fs_.Create(
"c1",
"");
761 ASSERT_EQ(4u, command_runner_.commands_ran_.size());
764 command_runner_.commands_ran_.clear();
772 fs_.Create(
"c3",
"");
774 command_runner_.commands_ran_.clear();
780 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
788 EXPECT_EQ(
"'in1', needed by 'cat1', missing and no known rule to make it",
796 EXPECT_EQ(
"unknown target: 'meow'", err);
804 "build subdir\\dir2\\file: cat in1\n"));
807 "build subdir/dir2/file: cat in1\n"));
809 EXPECT_TRUE(builder_.AddTarget(
"subdir/dir2/file", &err));
814 ASSERT_EQ(2u, fs_.directories_made_.size());
815 EXPECT_EQ(
"subdir", fs_.directories_made_[0]);
816 EXPECT_EQ(
"subdir/dir2", fs_.directories_made_[1]);
822 "rule cc\n command = cc $in\n depfile = $out.d\n" 823 "build fo$ o.o: cc foo.c\n"));
824 fs_.Create(
"foo.c",
"");
829 EXPECT_EQ(
"fo o.o.d", fs_.files_read_[0]);
834 int orig_edges = state_.edges_.size();
836 "rule cc\n command = cc $in\n depfile = $out.d\n" 837 "build foo.o: cc foo.c\n"));
838 Edge* edge = state_.edges_.back();
840 fs_.Create(
"foo.c",
"");
841 GetNode(
"bar.h")->MarkDirty();
842 fs_.Create(
"foo.o.d",
"foo.o: blah.h bar.h\n");
846 EXPECT_EQ(
"foo.o.d", fs_.files_read_[0]);
850 ASSERT_EQ(orig_edges + 3, (
int)state_.edges_.size());
861 "rule cc\n command = cc $in\n depfile = $out.d\n" 862 "build foo.o: cc foo.c\n"));
863 fs_.Create(
"foo.c",
"");
864 fs_.Create(
"foo.o.d",
"randomtext\n");
866 EXPECT_EQ(
"foo.o.d: expected ':' in depfile", err);
873 " command = touch $out\n" 875 "build b: touch || c\n" 876 "build a: touch | b || c\n"));
878 vector<Edge*> c_out = GetNode(
"c")->out_edges();
880 EXPECT_EQ(
"b", c_out[0]->outputs_[0]->path());
881 EXPECT_EQ(
"a", c_out[1]->outputs_[0]->path());
889 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
895 "rule cc\n command = cc $in\n depfile = $out.d\n" 896 "build foo.o: cc foo.c || otherfile\n"));
897 Edge* edge = state_.edges_.back();
899 fs_.Create(
"foo.c",
"");
900 fs_.Create(
"otherfile",
"");
901 fs_.Create(
"foo.o.d",
"foo.o: blah.h bar.h\n");
922 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
927 fs_.Create(
"foo.o.d",
"foo.o: blah.h bar.h\n");
930 fs_.Create(
"blah.h",
"");
931 fs_.Create(
"bar.h",
"");
932 command_runner_.commands_ran_.clear();
937 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
942 fs_.Create(
"foo.o.d",
"foo.o: blah.h bar.h\n");
945 fs_.Create(
"otherfile",
"");
946 command_runner_.commands_ran_.clear();
953 fs_.RemoveFile(
"bar.h");
954 command_runner_.commands_ran_.clear();
959 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
965 "rule cc\n command = cc $in\n" 966 "rule true\n command = true\n" 967 "build oo.h: cc oo.h.in\n" 968 "build foo.o: cc foo.c || oo.h\n"));
970 fs_.Create(
"foo.c",
"");
971 fs_.Create(
"oo.h.in",
"");
977 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
980 command_runner_.commands_ran_.clear();
987 fs_.RemoveFile(
"oo.h");
988 command_runner_.commands_ran_.clear();
993 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
994 ASSERT_EQ(
"cc oo.h.in", command_runner_.commands_ran_[0]);
999 fs_.Create(
"oo.h.in",
"");
1000 command_runner_.commands_ran_.clear();
1005 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
1006 ASSERT_EQ(
"cc oo.h.in", command_runner_.commands_ran_[0]);
1012 int orig_edges = state_.edges_.size();
1014 "rule cc\n command = cc $in\n depfile = $out.d\n" 1015 "build gen/stuff\\things/foo.o: cc x\\y/z\\foo.c\n"));
1016 Edge* edge = state_.edges_.back();
1018 fs_.Create(
"x/y/z/foo.c",
"");
1019 GetNode(
"bar.h")->MarkDirty();
1021 fs_.Create(
"gen/stuff\\things/foo.o.d",
1022 "gen\\stuff\\things\\foo.o: blah.h bar.h\n");
1023 EXPECT_TRUE(builder_.AddTarget(
"gen/stuff/things/foo.o", &err));
1027 EXPECT_EQ(
"gen/stuff\\things/foo.o.d", fs_.files_read_[0]);
1031 ASSERT_EQ(orig_edges + 3, (
int)state_.edges_.size());
1044 "build out: cat bar.cc\n" 1045 "build all: phony out\n"));
1046 fs_.Create(
"bar.cc",
"");
1055 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
1061 "build out: cat bar.cc\n" 1062 "build all: phony out\n"));
1063 fs_.Create(
"bar.cc",
"");
1064 fs_.Create(
"out",
"");
1077 "build a: phony a\n"));
1088 "build out1: fail\n"));
1095 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
1103 "build out1: fail\n" 1104 "build out2: fail\n" 1105 "build out3: fail\n" 1106 "build all: phony out1 out2 out3\n"));
1109 config_.failures_allowed = 3;
1116 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
1124 "build out1: fail\n" 1125 "build out2: fail\n" 1126 "build out3: fail\n" 1127 "build final: cat out1 out2 out3\n"));
1130 config_.failures_allowed = 11;
1137 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
1138 ASSERT_EQ(
"cannot make progress due to previous errors", err);
1147 " pool = failpool\n" 1148 "build out1: fail\n" 1149 "build out2: fail\n" 1150 "build out3: fail\n" 1151 "build final: cat out1 out2 out3\n"));
1154 config_.failures_allowed = 11;
1161 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
1162 ASSERT_EQ(
"cannot make progress due to previous errors", err);
1166 fs_.Create(
"x",
"");
1168 const char* manifest =
1172 " command = touch $out\n" 1173 " pool = some_pool\n" 1175 " command = touch grit\n" 1177 "build B.d.stamp: cc | x\n" 1178 "build C.stamp: touch B.d.stamp\n" 1179 "build final.stamp: touch || C.stamp\n";
1181 RebuildTarget(
"final.stamp", manifest);
1183 fs_.RemoveFile(
"B.d.stamp");
1186 RebuildTarget(
"final.stamp", manifest, NULL, NULL, &save_state);
1202 "build out1: cc in\n"));
1206 fs_.Create(
"in",
"");
1207 fs_.Create(
"out1",
"");
1215 command_runner_.commands_ran_.clear();
1225 "rule touch-fail-tick2\n" 1226 " command = touch-fail-tick2\n" 1227 "build out1: touch-fail-tick2 in\n"));
1231 fs_.Create(
"in",
"");
1237 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
1239 command_runner_.commands_ran_.clear();
1242 builder_.plan_.Reset();
1245 fs_.Create(
"in",
"");
1251 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
1253 command_runner_.commands_ran_.clear();
1256 builder_.plan_.Reset();
1264 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
1271 " command = touch\n" 1272 "build out1: touch\n" 1273 "build out2: touch in\n"));
1277 fs_.Create(
"in",
"");
1283 EXPECT_EQ(2u, command_runner_.commands_ran_.size());
1285 command_runner_.commands_ran_.clear();
1290 fs_.Create(
"in",
"");
1296 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
1307 "build out1: cc in\n" 1308 "build out2: true out1\n" 1309 "build out3: cat out2\n"));
1311 fs_.Create(
"out1",
"");
1312 fs_.Create(
"out2",
"");
1313 fs_.Create(
"out3",
"");
1317 fs_.Create(
"in",
"");
1327 EXPECT_EQ(
"[3/3]", builder_.status_->FormatProgressStatus(
"[%s/%t]",
1329 command_runner_.commands_ran_.clear();
1334 fs_.Create(
"in",
"");
1340 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
1344 command_runner_.commands_ran_.clear();
1352 fs_.Create(
"in",
"");
1356 command_runner_.commands_ran_.clear();
1361 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
1375 "build out1: true in\n" 1376 "build out2: cc out1\n"));
1378 fs_.Create(
"in",
"");
1379 fs_.Create(
"out2",
"");
1389 command_runner_.commands_ran_.clear();
1393 fs_.Create(
"in",
"");
1394 fs_.Create(
"out2",
"");
1402 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
1411 " command = touch\n" 1412 "build out1: true in\n" 1413 "build out2 out3: touch out1\n" 1414 "build out4: touch out2\n" 1418 fs_.Create(
"in",
"");
1425 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
1428 fs_.Create(
"in",
"");
1429 fs_.RemoveFile(
"out3");
1436 command_runner_.commands_ran_.clear();
1442 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
1451 " depfile = $out.d\n" 1455 "build out1: true in\n" 1456 "build out2: cc out1\n"));
1459 fs_.Create(
"in",
"");
1464 fs_.Create(
"out1.d",
"out1: will.be.deleted restat.file\n");
1465 fs_.Create(
"will.be.deleted",
"");
1466 fs_.Create(
"restat.file",
"");
1473 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
1479 ASSERT_EQ(restat_mtime, log_entry->mtime);
1483 fs_.RemoveFile(
"will.be.deleted");
1486 command_runner_.commands_ran_.clear();
1491 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
1494 log_entry = build_log_.LookupByOutput(
"out1");
1496 ASSERT_EQ(restat_mtime, log_entry->mtime);
1513 "build out1: cc in\n" 1514 "build out2: true out1\n" 1515 "build out3: cat out2\n"));
1517 fs_.Create(
"out1",
"");
1518 fs_.Create(
"out2",
"");
1519 fs_.Create(
"out3",
"");
1523 fs_.Create(
"in",
"");
1531 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
1540 " command = cat $rspfile > $out\n" 1541 " rspfile = $rspfile\n" 1542 " rspfile_content = $long_command\n" 1543 "rule cat_rsp_out\n" 1544 " command = cat $rspfile > $out\n" 1545 " rspfile = $out.rsp\n" 1546 " rspfile_content = $long_command\n" 1547 "build out1: cat in\n" 1548 "build out2: cat_rsp in\n" 1549 " rspfile = out 2.rsp\n" 1550 " long_command = Some very long command\n" 1551 "build out$ 3: cat_rsp_out in\n" 1552 " long_command = Some very long command\n"));
1554 fs_.Create(
"out1",
"");
1555 fs_.Create(
"out2",
"");
1556 fs_.Create(
"out 3",
"");
1560 fs_.Create(
"in",
"");
1570 size_t files_created = fs_.files_created_.size();
1571 size_t files_removed = fs_.files_removed_.size();
1574 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
1577 ASSERT_EQ(files_created + 2, fs_.files_created_.size());
1578 ASSERT_EQ(1u, fs_.files_created_.count(
"out 2.rsp"));
1579 ASSERT_EQ(1u, fs_.files_created_.count(
"out 3.rsp"));
1582 ASSERT_EQ(files_removed + 2, fs_.files_removed_.size());
1583 ASSERT_EQ(1u, fs_.files_removed_.count(
"out 2.rsp"));
1584 ASSERT_EQ(1u, fs_.files_removed_.count(
"out 3.rsp"));
1592 " rspfile = $rspfile\n" 1593 " rspfile_content = $long_command\n" 1594 "build out: fail in\n" 1595 " rspfile = out.rsp\n" 1596 " long_command = Another very long command\n"));
1598 fs_.Create(
"out",
"");
1600 fs_.Create(
"in",
"");
1606 size_t files_created = fs_.files_created_.size();
1607 size_t files_removed = fs_.files_removed_.size();
1611 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
1614 ASSERT_EQ(files_created + 1, fs_.files_created_.size());
1615 ASSERT_EQ(1u, fs_.files_created_.count(
"out.rsp"));
1618 ASSERT_EQ(files_removed, fs_.files_removed_.size());
1619 ASSERT_EQ(0u, fs_.files_removed_.count(
"out.rsp"));
1622 ASSERT_EQ(
"Another very long command", fs_.files_[
"out.rsp"].contents);
1630 " command = cat $rspfile > $out\n" 1631 " rspfile = $rspfile\n" 1632 " rspfile_content = $long_command\n" 1633 "build out: cat_rsp in\n" 1634 " rspfile = out.rsp\n" 1635 " long_command = Original very long command\n"));
1637 fs_.Create(
"out",
"");
1639 fs_.Create(
"in",
"");
1647 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
1650 command_runner_.commands_ran_.clear();
1661 "cat out.rsp > out;rspfile=Original very long command",
1662 log_entry->command_hash));
1663 log_entry->command_hash++;
1665 command_runner_.commands_ran_.clear();
1670 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
1676 " command = interrupt\n" 1677 "rule touch-interrupt\n" 1678 " command = touch-interrupt\n" 1679 "build out1: interrupt in1\n" 1680 "build out2: touch-interrupt in2\n"));
1682 fs_.Create(
"out1",
"");
1683 fs_.Create(
"out2",
"");
1685 fs_.Create(
"in1",
"");
1686 fs_.Create(
"in2",
"");
1708 const string kTooLongToStat(400,
'i');
1710 (
"build " + kTooLongToStat +
": cat in\n").c_str()));
1711 fs_.Create(
"in",
"");
1714 fs_.files_[kTooLongToStat].mtime = -1;
1715 fs_.files_[kTooLongToStat].stat_error =
"stat failed";
1718 EXPECT_FALSE(builder_.AddTarget(kTooLongToStat, &err));
1724 "build nonexistent: phony\n" 1725 "build out1: cat || nonexistent\n" 1726 "build out2: cat nonexistent\n"));
1727 fs_.Create(
"out1",
"");
1728 fs_.Create(
"out2",
"");
1739 command_runner_.commands_ran_.clear();
1745 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
1753 "build out: cc\n"));
1763 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
1767 status_.BuildStarted();
1770 status_.FormatProgressStatus(
"[%%/e%e]",
1776 status_.FormatProgressStatus(
"[%%/s%s/t%t/r%r/u%u/f%f]",
1782 "build bad_deps.o: cat in1\n" 1784 " depfile = in1.d\n"));
1787 EXPECT_TRUE(builder_.AddTarget(
"bad_deps.o", &err));
1792 fs_.Create(
"in1.d",
"AAA BBB");
1825 const char* manifest =
1826 "build out: cat in1\n" 1828 " depfile = in1.d\n";
1839 Builder builder(&state, config_, NULL, &deps_log, &fs_);
1843 fs_.Create(
"in1.d",
"out: in2");
1850 fs_.Create(
"in1.d",
"out: in2");
1862 fs_.Create(
"in2",
"");
1869 Builder builder(&state, config_, NULL, &deps_log, &fs_);
1870 builder.command_runner_.reset(&command_runner_);
1871 command_runner_.commands_ran_.clear();
1879 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
1881 builder.command_runner_.release();
1892 const char* manifest =
1893 "build out: cat in1\n" 1895 " depfile = in1.d\n";
1898 fs_.Create(
"in1",
"");
1899 fs_.Create(
"in1.d",
"out: ");
1910 Builder builder(&state, config_, NULL, &deps_log, &fs_);
1924 fs_.Create(
"in1",
"");
1925 fs_.Create(
"out",
"");
1939 Builder builder(&state, config_, NULL, &deps_log, &fs_);
1940 builder.command_runner_.reset(&command_runner_);
1941 command_runner_.commands_ran_.clear();
1946 fs_.Create(
"in1.d",
"out: ");
1953 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
1955 builder.command_runner_.release();
1960 const char* manifest =
1961 "build out: cat in1\n" 1963 " depfile = in1.d\n";
1965 fs_.Create(
"out",
"");
1967 fs_.Create(
"in1",
"");
1974 config_.dry_run =
true;
1975 Builder builder(&state, config_, NULL, NULL, &fs_);
1977 command_runner_.commands_ran_.clear();
1983 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
1994 "build header.h: true header.in\n" 1995 "build out: cat in1\n" 1996 " depfile = in1.d\n"));
1998 fs_.Create(
"header.h",
"");
1999 fs_.Create(
"in1.d",
"out: header.h");
2001 fs_.Create(
"header.in",
"");
2015 const char* manifest =
2019 "build header.h: true header.in\n" 2020 "build out: cat in1\n" 2022 " depfile = in1.d\n";
2033 Builder builder(&state, config_, NULL, &deps_log, &fs_);
2037 fs_.Create(
"in1.d",
"out: header.h");
2052 fs_.Create(
"header.in",
"");
2059 Builder builder(&state, config_, NULL, &deps_log, &fs_);
2060 builder.command_runner_.reset(&command_runner_);
2061 command_runner_.commands_ran_.clear();
2069 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
2071 builder.command_runner_.release();
2077 const char* manifest =
2078 "rule cc\n command = cc $in\n depfile = $out.d\n deps = gcc\n" 2079 "build fo$ o.o: cc foo.c\n";
2081 fs_.Create(
"foo.c",
"");
2092 Builder builder(&state, config_, NULL, &deps_log, &fs_);
2096 fs_.Create(
"fo o.o.d",
"fo\\ o.o: blah.h bar.h\n");
2113 Builder builder(&state, config_, NULL, &deps_log, &fs_);
2139 const char* manifest =
2140 "rule cc\n command = cc $in\n depfile = $out.d\n deps = gcc\n" 2141 "build a/b\\c\\d/e/fo$ o.o: cc x\\y/z\\foo.c\n";
2143 fs_.Create(
"x/y/z/foo.c",
"");
2154 Builder builder(&state, config_, NULL, &deps_log, &fs_);
2155 builder.command_runner_.reset(&command_runner_);
2156 EXPECT_TRUE(builder.AddTarget(
"a/b/c/d/e/fo o.o", &err));
2159 fs_.Create(
"a/b\\c\\d/e/fo o.o.d",
2160 "a\\b\\c\\d\\e\\fo\\ o.o: blah.h bar.h\n");
2165 builder.command_runner_.release();
2177 Builder builder(&state, config_, NULL, &deps_log, &fs_);
2178 builder.command_runner_.reset(&command_runner_);
2183 EXPECT_TRUE(builder.AddTarget(
"a/b/c/d/e/fo o.o", &err));
2197 builder.command_runner_.release();
2205 const char* manifest =
2209 "build header.h: true header.in\n" 2210 "build out: cat header.h\n" 2211 " depfile = out.d\n";
2213 fs_.Create(
"header.h",
"");
2215 fs_.Create(
"out",
"");
2216 fs_.Create(
"header.in",
"");
2222 RebuildTarget(
"out", manifest);
2223 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
2230 const char* manifest =
2234 "build header.h: true header.in\n" 2235 "build out: cat header.h\n" 2237 " depfile = out.d\n";
2240 fs_.Create(
"header.in",
"");
2241 fs_.Create(
"out.d",
"out: header.h");
2242 fs_.Create(
"header.h",
"");
2244 RebuildTarget(
"out", manifest,
"build_log",
"ninja_deps");
2245 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
2248 RebuildTarget(
"out", manifest,
"build_log",
"ninja_deps");
2249 ASSERT_EQ(0u, command_runner_.commands_ran_.size());
2255 fs_.Create(
"header.in",
"");
2258 RebuildTarget(
"out", manifest,
"build_log",
"ninja_deps2");
2259 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
2262 RebuildTarget(
"out", manifest,
"build_log",
"ninja_deps2");
2263 ASSERT_EQ(0u, command_runner_.commands_ran_.size());
2268 fs_.Create(
"header.in",
"");
2269 fs_.Create(
"out",
"");
2270 RebuildTarget(
"out", manifest,
"build_log",
"ninja_deps2");
2271 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
2274 RebuildTarget(
"out", manifest,
"build_log",
"ninja_deps2");
2275 ASSERT_EQ(0u, command_runner_.commands_ran_.size());
2280 const char* manifest =
2282 " command = cc $in\n" 2283 " depfile = $out.d\n" 2284 "build foo.o: cc foo.c\n";
2286 fs_.Create(
"foo.c",
"");
2287 fs_.Create(
"foo.o",
"");
2288 fs_.Create(
"header.h",
"");
2289 fs_.Create(
"foo.o.d",
"bar.o.d: header.h\n");
2291 RebuildTarget(
"foo.o", manifest,
"build_log",
"ninja_deps");
2292 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
2298 " command = console\n" 2300 "build cons: console in.txt\n"));
2302 fs_.Create(
"in.txt",
"");
2309 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
FakeCommandRunner command_runner_
An implementation of DiskInterface that uses an in-memory representation of disk state.
CommandRunner is an interface that wraps running the build subcommands.
FakeCommandRunner(VirtualFileSystem *fs)
void AssertParse(State *state, const char *input, ManifestParserOptions opts)
vector< Edge * > edges_
All the edges of the graph.
Node * GetNode(const string &path)
Short way to get a Node by its path from state_.
void TestPoolWithDepthOne(const char *test_case)
Plan stores the state of a build plan: what we intend to build, which steps we're ready to execute...
Node * GetNode(StringPiece path, uint64_t slash_bits)
void * builder_
Shadow parent class builder_ so we don't accidentally use it.
Pool * LookupPool(const string &pool_name)
The result of waiting for a command.
StringPiece represents a slice of a string whose memory is managed externally.
bool AddTarget(Node *node, string *err)
Add a target to our plan (including all its dependencies).
Information about a node in the dependency graph: the file, whether it's dirty, mtime, etc.
virtual bool IsPathDead(StringPiece s) const
Return if a given output is no longer part of the build manifest.
Fixture for tests involving Plan.
int now_
A simple fake timestamp for file operations.
virtual vector< Edge * > GetActiveEdges()
void Create(const string &path, const string &contents)
"Create" a file with contents.
An edge in the dependency graph; links between Nodes using Rules.
Store a log of every command ran for every build.
string EvaluateCommand(bool incl_rsp_file=false)
Expand all variables in a command and return it as a string.
A base test fixture that includes a State object with a builtin "cat" rule.
void AddCatRule(State *state)
Add a "cat" rule to state.
As build commands run they can output extra dependency information (e.g.
bool OpenForWrite(const string &path, const BuildLogUser &user, string *err)
bool OpenForWrite(const string &path, string *err)
Tests of builds involving deps logs necessarily must span multiple builds.
virtual bool WaitForCommand(Result *result)
Wait for a command to complete, or return false if interrupted.
void MarkMissing()
Mark the Node as already-stat()ed and missing.
bool Load(const string &path, State *state, string *err)
Fake implementation of CommandRunner, useful for tests.
void RebuildTarget(const string &target, const char *manifest, const char *log_path=NULL, const char *deps_path=NULL, State *state=NULL)
Rebuild target in the 'working tree' (fs_).
virtual bool CanRunMore()
auto_ptr< CommandRunner > command_runner_
void SetBuildLog(BuildLog *log)
Used for tests.
void FindWorkSorted(deque< Edge *> *ret, int count)
Because FindWork does not return Edges in any sort of predictable order,.
Builder wraps the build process: starting commands, updating status.
Tracks the status of a build: completion fraction, printing updates.
void Cleanup()
Clean up the temporary directory.
virtual bool StartCommand(Edge *edge)
#define ASSERT_NO_FATAL_FAILURE(a)
const string & name() const
const Rule & rule() const
void CreateAndEnter(const string &name)
Create a temporary directory and chdir into it.
Options (e.g. verbosity, parallelism) passed to a build.
Global state (file status) for a single run.
void Dirty(const string &path)
bool Load(const string &path, string *err)
Load the on-disk log.
bool Build(string *err)
Run the build.
bool more_to_do() const
Returns true if there's more work to be done.
void EdgeFinished(Edge *edge, EdgeResult result)
Mark an edge as done building (whether it succeeded or failed).
bool AlreadyUpToDate() const
Returns true if the build targets are already up to date.
vector< string > commands_ran_
void AssertHash(const char *expected, uint64_t actual)
Node * AddTarget(const string &name, string *err)
Can answer questions about the manifest for the BuildLog.
vector< Node * > outputs_