53 void CreateWin32MiniDump(_EXCEPTION_POINTERS* pep);
63 const char* input_file;
66 const char* working_dir;
72 bool dupe_edges_should_err;
75 bool phony_cycle_should_err;
79 bool depfile_distinct_target_lines_should_err;
85 NinjaMain(
const char* ninja_command,
const BuildConfig& config) :
86 ninja_command_(ninja_command), config_(config) {}
89 const char* ninja_command_;
107 typedef int (NinjaMain::*ToolFunc)(
const Options*, int,
char**);
111 Node* CollectTarget(
const char* cpath,
string* err);
114 bool CollectTargetsFromArgs(
int argc,
char* argv[],
115 vector<Node*>* targets,
string* err);
118 int ToolGraph(
const Options* options,
int argc,
char* argv[]);
119 int ToolQuery(
const Options* options,
int argc,
char* argv[]);
120 int ToolDeps(
const Options* options,
int argc,
char* argv[]);
121 int ToolBrowse(
const Options* options,
int argc,
char* argv[]);
122 int ToolMSVC(
const Options* options,
int argc,
char* argv[]);
123 int ToolTargets(
const Options* options,
int argc,
char* argv[]);
124 int ToolCommands(
const Options* options,
int argc,
char* argv[]);
125 int ToolClean(
const Options* options,
int argc,
char* argv[]);
126 int ToolCompilationDatabase(
const Options* options,
int argc,
char* argv[]);
127 int ToolRecompact(
const Options* options,
int argc,
char* argv[]);
128 int ToolUrtle(
const Options* options,
int argc,
char** argv);
132 bool OpenBuildLog(
bool recompact_only =
false);
136 bool OpenDepsLog(
bool recompact_only =
false);
140 bool EnsureBuildDirExists();
145 bool RebuildManifest(
const char* input_file,
string* err);
149 int RunBuild(
int argc,
char** argv);
170 Error(
"%s", err.c_str());
197 NinjaMain::ToolFunc func;
203 "usage: ninja [options] [targets...]\n" 205 "if targets are unspecified, builds the 'default' target (see manual).\n" 208 " --version print ninja version (\"%s\")\n" 209 " -v, --verbose show all command lines while building\n" 211 " -C DIR change to DIR before doing anything else\n" 212 " -f FILE specify input build file [default=build.ninja]\n" 214 " -j N run N jobs in parallel (0 means infinity) [default=%d on this system]\n" 215 " -k N keep going until N jobs fail (0 means infinity) [default=1]\n" 216 " -l N do not start new jobs if the load average is greater than N\n" 217 " -n dry run (don't run commands but act like they succeeded)\n" 219 " -d MODE enable debugging (use '-d list' to list modes)\n" 220 " -t TOOL run a subtool (use '-t list' to list subtools)\n" 221 " terminates toplevel options; further flags are passed to the tool\n" 222 " -w FLAG adjust warnings (use '-w list' to list warnings)\n",
227 int GuessParallelism() {
235 return processors + 2;
241 bool NinjaMain::RebuildManifest(
const char* input_file,
string* err) {
242 string path = input_file;
250 Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_);
251 if (!builder.AddTarget(node, err))
254 if (builder.AlreadyUpToDate())
257 if (!builder.Build(err))
262 if (!node->
dirty()) {
272 Node* NinjaMain::CollectTarget(
const char* cpath,
string* err) {
279 bool first_dependent =
false;
280 if (!path.empty() && path[path.size() - 1] ==
'^') {
281 path.resize(path.size() - 1);
282 first_dependent =
true;
287 if (first_dependent) {
289 *err =
"'" + path +
"' has no out edge";
295 Fatal(
"edge has no outputs");
303 if (path ==
"clean") {
304 *err +=
", did you mean 'ninja -t clean'?";
305 }
else if (path ==
"help") {
306 *err +=
", did you mean 'ninja -h'?";
310 *err +=
", did you mean '" + suggestion->
path() +
"'?";
317 bool NinjaMain::CollectTargetsFromArgs(
int argc,
char* argv[],
318 vector<Node*>* targets,
string* err) {
324 for (
int i = 0; i < argc; ++i) {
325 Node* node = CollectTarget(argv[i], err);
328 targets->push_back(node);
333 int NinjaMain::ToolGraph(
const Options* options,
int argc,
char* argv[]) {
336 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
337 Error(
"%s", err.c_str());
343 for (vector<Node*>::const_iterator n = nodes.begin(); n != nodes.end(); ++n)
350 int NinjaMain::ToolQuery(
const Options* options,
int argc,
char* argv[]) {
352 Error(
"expected a target to query");
356 for (
int i = 0; i < argc; ++i) {
358 Node* node = CollectTarget(argv[i], &err);
360 Error(
"%s", err.c_str());
364 printf(
"%s:\n", node->
path().c_str());
366 printf(
" input: %s\n", edge->
rule_->
name().c_str());
367 for (
int in = 0; in < (int)edge->
inputs_.size(); in++) {
368 const char* label =
"";
373 printf(
" %s%s\n", label, edge->
inputs_[in]->path().c_str());
376 printf(
" outputs:\n");
377 for (vector<Edge*>::const_iterator edge = node->
out_edges().begin();
378 edge != node->
out_edges().end(); ++edge) {
379 for (vector<Node*>::iterator out = (*edge)->outputs_.begin();
380 out != (*edge)->outputs_.end(); ++out) {
381 printf(
" %s\n", (*out)->path().c_str());
388 #if defined(NINJA_HAVE_BROWSE) 389 int NinjaMain::ToolBrowse(
const Options* options,
int argc,
char* argv[]) {
390 RunBrowsePython(&state_, ninja_command_, options->input_file, argc, argv);
395 int NinjaMain::ToolBrowse(
const Options*,
int,
char**) {
396 Fatal(
"browse tool not supported on this platform");
401 #if defined(_MSC_VER) 402 int NinjaMain::ToolMSVC(
const Options* options,
int argc,
char* argv[]) {
411 int ToolTargetsList(
const vector<Node*>& nodes,
int depth,
int indent) {
412 for (vector<Node*>::const_iterator n = nodes.begin();
415 for (
int i = 0; i < indent; ++i)
417 const char* target = (*n)->path().c_str();
418 if ((*n)->in_edge()) {
419 printf(
"%s: %s\n", target, (*n)->in_edge()->rule_->name().c_str());
420 if (depth > 1 || depth <= 0)
421 ToolTargetsList((*n)->in_edge()->inputs_, depth - 1, indent + 1);
423 printf(
"%s\n", target);
429 int ToolTargetsSourceList(
State* state) {
430 for (vector<Edge*>::iterator e = state->
edges_.begin();
431 e != state->
edges_.end(); ++e) {
432 for (vector<Node*>::iterator inps = (*e)->inputs_.begin();
433 inps != (*e)->inputs_.end(); ++inps) {
434 if (!(*inps)->in_edge())
435 printf(
"%s\n", (*inps)->path().c_str());
441 int ToolTargetsList(
State* state,
const string& rule_name) {
445 for (vector<Edge*>::iterator e = state->
edges_.begin();
446 e != state->
edges_.end(); ++e) {
447 if ((*e)->rule_->name() == rule_name) {
448 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
449 out_node != (*e)->outputs_.end(); ++out_node) {
450 rules.insert((*out_node)->path());
456 for (set<string>::const_iterator i = rules.begin();
457 i != rules.end(); ++i) {
458 printf(
"%s\n", (*i).c_str());
464 int ToolTargetsList(
State* state) {
465 for (vector<Edge*>::iterator e = state->
edges_.begin();
466 e != state->
edges_.end(); ++e) {
467 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
468 out_node != (*e)->outputs_.end(); ++out_node) {
470 (*out_node)->path().c_str(),
471 (*e)->rule_->name().c_str());
477 int NinjaMain::ToolDeps(
const Options* options,
int argc,
char** argv) {
480 for (vector<Node*>::const_iterator ni = deps_log_.
nodes().begin();
481 ni != deps_log_.
nodes().end(); ++ni) {
483 nodes.push_back(*ni);
487 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
488 Error(
"%s", err.c_str());
494 for (vector<Node*>::iterator it = nodes.begin(), end = nodes.end();
498 printf(
"%s: deps not found\n", (*it)->path().c_str());
505 Error(
"%s", err.c_str());
506 printf(
"%s: #deps %d, deps mtime %" PRId64 " (%s)\n",
508 (!mtime || mtime > deps->
mtime ?
"STALE":
"VALID"));
510 printf(
" %s\n", deps->
nodes[i]->
path().c_str());
517 int NinjaMain::ToolTargets(
const Options* options,
int argc,
char* argv[]) {
520 string mode = argv[0];
521 if (mode ==
"rule") {
526 return ToolTargetsSourceList(&state_);
528 return ToolTargetsList(&state_, rule);
529 }
else if (mode ==
"depth") {
531 depth = atoi(argv[1]);
532 }
else if (mode ==
"all") {
533 return ToolTargetsList(&state_);
535 const char* suggestion =
538 Error(
"unknown target tool mode '%s', did you mean '%s'?",
539 mode.c_str(), suggestion);
541 Error(
"unknown target tool mode '%s'", mode.c_str());
548 vector<Node*> root_nodes = state_.
RootNodes(&err);
550 return ToolTargetsList(root_nodes, depth, 0);
552 Error(
"%s", err.c_str());
561 if (!seen->insert(edge).second)
564 if (mode == PCM_All) {
565 for (vector<Node*>::iterator in = edge->
inputs_.begin();
566 in != edge->
inputs_.end(); ++in)
567 PrintCommands((*in)->in_edge(), seen, mode);
574 int NinjaMain::ToolCommands(
const Options* options,
int argc,
char* argv[]) {
584 while ((opt =
getopt(argc, argv, const_cast<char*>(
"hs"))) != -1) {
591 printf(
"usage: ninja -t commands [options] [targets]\n" 594 " -s only print the final command to build [target], not the whole chain\n" 604 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
605 Error(
"%s", err.c_str());
610 for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in)
611 PrintCommands((*in)->in_edge(), &seen, mode);
616 int NinjaMain::ToolClean(
const Options* options,
int argc,
char* argv[]) {
622 bool generator =
false;
623 bool clean_rules =
false;
627 while ((opt =
getopt(argc, argv, const_cast<char*>(
"hgr"))) != -1) {
637 printf(
"usage: ninja -t clean [options] [targets]\n" 640 " -g also clean files marked as ninja generator output\n" 641 " -r interpret targets as a list of rules to clean instead\n" 649 if (clean_rules && argc == 0) {
650 Error(
"expected a rule to clean");
654 Cleaner cleaner(&state_, config_);
657 return cleaner.CleanRules(argc, argv);
659 return cleaner.CleanTargets(argc, argv);
661 return cleaner.CleanAll(generator);
665 void EncodeJSONString(
const char *str) {
667 if (*str ==
'"' || *str ==
'\\')
680 if (mode == ECM_NORMAL)
687 size_t index = command.find(rspfile);
688 if (index == 0 || index == string::npos || command[index - 1] !=
'@')
691 string rspfile_content = edge->
GetBinding(
"rspfile_content");
692 size_t newline_index = 0;
693 while ((newline_index = rspfile_content.find(
'\n', newline_index)) !=
695 rspfile_content.replace(newline_index, 1, 1,
' ');
698 command.replace(index - 1, rspfile.length() + 1, rspfile_content);
702 int NinjaMain::ToolCompilationDatabase(
const Options* options,
int argc,
713 while ((opt =
getopt(argc, argv, const_cast<char*>(
"hx"))) != -1) {
716 eval_mode = ECM_EXPAND_RSPFILE;
722 "usage: ninja -t compdb [options] [rules]\n" 725 " -x expand @rspfile style response file invocations\n" 737 cwd.resize(cwd.size() + 1024);
739 }
while (!getcwd(&cwd[0], cwd.size()) && errno == ERANGE);
740 if (errno != 0 && errno != ERANGE) {
741 Error(
"cannot determine working directory: %s", strerror(errno));
746 for (vector<Edge*>::iterator e = state_.
edges_.begin();
747 e != state_.
edges_.end(); ++e) {
748 if ((*e)->inputs_.empty())
750 for (
int i = 0; i != argc; ++i) {
751 if ((*e)->rule_->name() == argv[i]) {
755 printf(
"\n {\n \"directory\": \"");
756 EncodeJSONString(&cwd[0]);
757 printf(
"\",\n \"command\": \"");
758 EncodeJSONString(EvaluateCommandWithRspfile(*e, eval_mode).c_str());
759 printf(
"\",\n \"file\": \"");
760 EncodeJSONString((*e)->inputs_[0]->path().c_str());
761 printf(
"\",\n \"output\": \"");
762 EncodeJSONString((*e)->outputs_[0]->path().c_str());
774 int NinjaMain::ToolRecompact(
const Options* options,
int argc,
char* argv[]) {
775 if (!EnsureBuildDirExists())
778 if (!OpenBuildLog(
true) ||
785 int NinjaMain::ToolUrtle(
const Options* options,
int argc,
char** argv) {
788 " 13 ,3;2!2;\n8 ,;<11!;\n5 `'<10!(2`'2!\n11 ,6;, `\\. `\\9 .,c13$ec,.\n6 " 789 ",2;11!>; `. ,;!2> .e8$2\".2 \"?7$e.\n <:<8!'` 2.3,.2` ,3!' ;,(?7\";2!2'<" 790 "; `?6$PF ,;,\n2 `'4!8;<!3'`2 3! ;,`'2`2'3!;4!`2.`!;2 3,2 .<!2'`).\n5 3`5" 791 "'2`9 `!2 `4!><3;5! J2$b,`!>;2!:2!`,d?b`!>\n26 `'-;,(<9!> $F3 )3.:!.2 d\"" 792 "2 ) !>\n30 7`2'<3!- \"=-='5 .2 `2-=\",!>\n25 .ze9$er2 .,cd16$bc.'\n22 .e" 793 "14$,26$.\n21 z45$c .\n20 J50$c\n20 14$P\"`?34$b\n20 14$ dbc `2\"?22$?7$c" 794 "\n20 ?18$c.6 4\"8?4\" c8$P\n9 .2,.8 \"20$c.3 ._14 J9$\n .2,2c9$bec,.2 `?" 795 "21$c.3`4%,3%,3 c8$P\"\n22$c2 2\"?21$bc2,.2` .2,c7$P2\",cb\n23$b bc,.2\"2" 796 "?14$2F2\"5?2\",J5$P\" ,zd3$\n24$ ?$3?%3 `2\"2?12$bcucd3$P3\"2 2=7$\n23$P" 797 "\" ,3;<5!>2;,. `4\"6?2\"2 ,9;, `\"?2$\n";
799 for (
const char* p = urtle; *p; p++) {
800 if (
'0' <= *p && *p <=
'9') {
801 count = count*10 + *p -
'0';
803 for (
int i = 0; i < max(count, 1); ++i)
813 const Tool* ChooseTool(
const string& tool_name) {
814 static const Tool kTools[] = {
815 {
"browse",
"browse dependency graph in a web browser",
816 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolBrowse },
817 #if defined(_MSC_VER) 818 {
"msvc",
"build helper for MSVC cl.exe (EXPERIMENTAL)",
819 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolMSVC },
821 {
"clean",
"clean built files",
822 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolClean },
823 {
"commands",
"list all commands required to rebuild given targets",
824 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCommands },
825 {
"deps",
"show dependencies stored in the deps log",
826 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolDeps },
827 {
"graph",
"output graphviz dot file for targets",
828 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolGraph },
829 {
"query",
"show inputs/outputs for a path",
830 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolQuery },
831 {
"targets",
"list targets by their rule or depth in the DAG",
832 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolTargets },
833 {
"compdb",
"dump JSON compilation database to stdout",
834 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCompilationDatabase },
835 {
"recompact",
"recompacts ninja-internal data structures",
836 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolRecompact },
838 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolUrtle },
839 { NULL, NULL, Tool::RUN_AFTER_FLAGS, NULL }
842 if (tool_name ==
"list") {
843 printf(
"ninja subtools:\n");
844 for (
const Tool* tool = &kTools[0]; tool->name; ++tool) {
846 printf(
"%10s %s\n", tool->name, tool->desc);
851 for (
const Tool* tool = &kTools[0]; tool->name; ++tool) {
852 if (tool->name == tool_name)
856 vector<const char*> words;
857 for (
const Tool* tool = &kTools[0]; tool->name; ++tool)
858 words.push_back(tool->name);
861 Fatal(
"unknown tool '%s', did you mean '%s'?",
862 tool_name.c_str(), suggestion);
864 Fatal(
"unknown tool '%s'", tool_name.c_str());
871 bool DebugEnable(
const string& name) {
872 if (name ==
"list") {
873 printf(
"debugging modes:\n" 874 " stats print operation counts/timing info\n" 875 " explain explain what caused a command to execute\n" 876 " keepdepfile don't delete depfiles after they're read by ninja\n" 877 " keeprsp don't delete @response files on success\n" 879 " nostatcache don't batch stat() calls per directory and cache them\n" 881 "multiple modes can be enabled via -d FOO -d BAR\n");
883 }
else if (name ==
"stats") {
886 }
else if (name ==
"explain") {
889 }
else if (name ==
"keepdepfile") {
892 }
else if (name ==
"keeprsp") {
895 }
else if (name ==
"nostatcache") {
899 const char* suggestion =
901 "stats",
"explain",
"keepdepfile",
"keeprsp",
902 "nostatcache", NULL);
904 Error(
"unknown debug setting '%s', did you mean '%s'?",
905 name.c_str(), suggestion);
907 Error(
"unknown debug setting '%s'", name.c_str());
915 bool WarningEnable(
const string& name, Options* options) {
916 if (name ==
"list") {
917 printf(
"warning flags:\n" 918 " dupbuild={err,warn} multiple build lines for one target\n" 919 " phonycycle={err,warn} phony build statement references itself\n" 920 " depfilemulti={err,warn} depfile has multiple output paths on separate lines\n" 923 }
else if (name ==
"dupbuild=err") {
924 options->dupe_edges_should_err =
true;
926 }
else if (name ==
"dupbuild=warn") {
927 options->dupe_edges_should_err =
false;
929 }
else if (name ==
"phonycycle=err") {
930 options->phony_cycle_should_err =
true;
932 }
else if (name ==
"phonycycle=warn") {
933 options->phony_cycle_should_err =
false;
935 }
else if (name ==
"depfilemulti=err") {
936 options->depfile_distinct_target_lines_should_err =
true;
938 }
else if (name ==
"depfilemulti=warn") {
939 options->depfile_distinct_target_lines_should_err =
false;
942 const char* suggestion =
944 "phonycycle=err",
"phonycycle=warn", NULL);
946 Error(
"unknown warning flag '%s', did you mean '%s'?",
947 name.c_str(), suggestion);
949 Error(
"unknown warning flag '%s'", name.c_str());
955 bool NinjaMain::OpenBuildLog(
bool recompact_only) {
956 string log_path =
".ninja_log";
957 if (!build_dir_.empty())
958 log_path = build_dir_ +
"/" + log_path;
961 if (!build_log_.
Load(log_path, &err)) {
962 Error(
"loading build log %s: %s", log_path.c_str(), err.c_str());
971 if (recompact_only) {
972 bool success = build_log_.
Recompact(log_path, *
this, &err);
974 Error(
"failed recompaction: %s", err.c_str());
980 Error(
"opening build log: %s", err.c_str());
990 bool NinjaMain::OpenDepsLog(
bool recompact_only) {
991 string path =
".ninja_deps";
992 if (!build_dir_.empty())
993 path = build_dir_ +
"/" + path;
996 if (!deps_log_.
Load(path, &state_, &err)) {
997 Error(
"loading deps log %s: %s", path.c_str(), err.c_str());
1006 if (recompact_only) {
1007 bool success = deps_log_.
Recompact(path, &err);
1009 Error(
"failed recompaction: %s", err.c_str());
1015 Error(
"opening deps log: %s", err.c_str());
1023 void NinjaMain::DumpMetrics() {
1027 int count = (int)state_.
paths_.size();
1028 int buckets = (int)state_.
paths_.bucket_count();
1029 printf(
"path->node hash load %.2f (%d entries / %d buckets)\n",
1030 count / (
double) buckets, count, buckets);
1033 bool NinjaMain::EnsureBuildDirExists() {
1035 if (!build_dir_.empty() && !config_.
dry_run) {
1036 if (!disk_interface_.
MakeDirs(build_dir_ +
"/.") && errno != EEXIST) {
1037 Error(
"creating build directory %s: %s",
1038 build_dir_.c_str(), strerror(errno));
1045 int NinjaMain::RunBuild(
int argc,
char** argv) {
1047 vector<Node*> targets;
1048 if (!CollectTargetsFromArgs(argc, argv, &targets, &err)) {
1049 Error(
"%s", err.c_str());
1055 Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_);
1056 for (
size_t i = 0; i < targets.size(); ++i) {
1057 if (!builder.AddTarget(targets[i], &err)) {
1059 Error(
"%s", err.c_str());
1071 if (builder.AlreadyUpToDate()) {
1072 printf(
"ninja: no work to do.\n");
1076 if (!builder.Build(&err)) {
1077 printf(
"ninja: build stopped: %s.\n", err.c_str());
1078 if (err.find(
"interrupted by user") != string::npos) {
1094 void TerminateHandler() {
1095 CreateWin32MiniDump(NULL);
1096 Fatal(
"terminate handler called");
1101 int ExceptionFilter(
unsigned int code,
struct _EXCEPTION_POINTERS *ep) {
1102 Error(
"exception: 0x%X", code);
1104 CreateWin32MiniDump(ep);
1105 return EXCEPTION_EXECUTE_HANDLER;
1112 int ReadFlags(
int* argc,
char*** argv,
1116 enum { OPT_VERSION = 1 };
1117 const option kLongOptions[] = {
1121 { NULL, 0, NULL, 0 }
1125 while (!options->tool &&
1126 (opt =
getopt_long(*argc, *argv,
"d:f:j:k:l:nt:vw:C:h", kLongOptions,
1130 if (!DebugEnable(
optarg))
1134 options->input_file =
optarg;
1138 int value = strtol(
optarg, &end, 10);
1139 if (*end != 0 || value < 0)
1140 Fatal(
"invalid -j parameter");
1144 config->
parallelism = value > 0 ? value : INT_MAX;
1149 int value = strtol(
optarg, &end, 10);
1151 Fatal(
"-k parameter not numeric; did you mean -k 0?");
1161 double value = strtod(
optarg, &end);
1163 Fatal(
"-l parameter not numeric: did you mean -l 0.0?");
1171 options->tool = ChooseTool(
optarg);
1179 if (!WarningEnable(
optarg, options))
1183 options->working_dir =
optarg;
1200 NORETURN void real_main(
int argc,
char** argv) {
1204 Options options = {};
1205 options.input_file =
"build.ninja";
1206 options.dupe_edges_should_err =
true;
1208 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
1209 const char* ninja_command = argv[0];
1211 int exit_code = ReadFlags(&argc, &argv, &options, &config);
1215 if (options.depfile_distinct_target_lines_should_err) {
1220 if (options.working_dir) {
1227 printf(
"ninja: Entering directory `%s'\n", options.working_dir);
1228 if (chdir(options.working_dir) < 0) {
1229 Fatal(
"chdir to '%s' - %s", options.working_dir, strerror(errno));
1233 if (options.tool && options.tool->when == Tool::RUN_AFTER_FLAGS) {
1236 NinjaMain ninja(ninja_command, config);
1237 exit((ninja.*options.tool->func)(&options, argc, argv));
1241 const int kCycleLimit = 100;
1242 for (
int cycle = 1; cycle <= kCycleLimit; ++cycle) {
1243 NinjaMain ninja(ninja_command, config);
1246 if (options.dupe_edges_should_err) {
1249 if (options.phony_cycle_should_err) {
1252 ManifestParser parser(&ninja.state_, &ninja.disk_interface_, parser_opts);
1254 if (!parser.Load(options.input_file, &err)) {
1255 Error(
"%s", err.c_str());
1259 if (options.tool && options.tool->when == Tool::RUN_AFTER_LOAD)
1260 exit((ninja.*options.tool->func)(&options, argc, argv));
1262 if (!ninja.EnsureBuildDirExists())
1265 if (!ninja.OpenBuildLog() || !ninja.OpenDepsLog())
1268 if (options.tool && options.tool->when == Tool::RUN_AFTER_LOGS)
1269 exit((ninja.*options.tool->func)(&options, argc, argv));
1272 if (ninja.RebuildManifest(options.input_file, &err)) {
1279 }
else if (!err.empty()) {
1280 Error(
"rebuilding '%s': %s", options.input_file, err.c_str());
1284 int result = ninja.RunBuild(argc, argv);
1286 ninja.DumpMetrics();
1290 Error(
"manifest '%s' still dirty after %d tries\n",
1291 options.input_file, kCycleLimit);
1298 #if defined(_MSC_VER) 1301 std::set_terminate(TerminateHandler);
1305 real_main(argc, argv);
1307 __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
1313 real_main(argc, argv);
const vector< Node * > & nodes() const
Used for tests.
void Report()
Print a summary report to stdout.
const char * SpellcheckStringV(const string &text, const vector< const char *> &words)
Given a misspelled string and a list of correct spellings, returns the closest match or NULL if there...
const vector< Edge * > & out_edges() const
const char * SpellcheckString(const char *text,...)
Like SpellcheckStringV, but takes a NULL-terminated list.
vector< Edge * > edges_
All the edges of the graph.
void Dump(const char *prefix="") const
bool Recompact(const string &path, const BuildLogUser &user, string *err)
Rewrite the known log entries, throwing away old data.
const string & path() const
double max_load_average
The maximum load average we must not exceed.
int MSVCHelperMain(int argc, char **argv)
bool CanonicalizePath(string *path, uint64_t *slash_bits, string *err)
Canonicalize a path like "foo/../bar.h" into just "bar.h".
PhonyCycleAction phony_cycle_action_
StringPiece represents a slice of a string whose memory is managed externally.
string GetUnescapedRspfile()
Like GetBinding("rspfile"), but without shell escaping.
bool MakeDirs(const string &path)
Create all the parent directories for path; like mkdir -p basename path.
Information about a node in the dependency graph: the file, whether it's dirty, mtime, etc.
Node * SpellcheckNode(const string &path)
An edge in the dependency graph; links between Nodes using Rules.
const char * kNinjaVersion
The version number of the current Ninja release.
Node * LookupNode(StringPiece path) const
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.
bool is_order_only(size_t index)
virtual bool IsPathDead(StringPiece s) const =0
Return if a given output is no longer part of the build manifest.
vector< Node * > DefaultNodes(string *error) const
As build commands run they can output extra dependency information (e.g.
bool OpenForWrite(const string &path, const BuildLogUser &user, string *err)
Implementation of DiskInterface that actually hits the disk.
bool OpenForWrite(const string &path, string *err)
bool is_implicit(size_t index)
void RunBrowsePython(State *state, const char *ninja_command, const char *input_file, int argc, char *argv[])
Run in "browse" mode, which execs a Python webserver.
int getopt_long(int argc, char **argv, const char *shortopts, const GETOPT_LONG_OPTION_T *longopts, int *longind)
Deps * GetDeps(Node *node)
DepfileDistinctTargetLinesAction depfile_distinct_target_lines_action_
vector< Node * > RootNodes(string *error) const
bool Load(const string &path, State *state, string *err)
virtual TimeStamp Stat(const string &path, string *err) const
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
int getopt(int argc, char **argv, char *optstring)
string PathDecanonicalized() const
Get |path()| but use slash_bits to convert back to original slash styles.
virtual string LookupVariable(const string &var)
bool Recompact(const string &path, string *err)
Rewrite the known log entries, throwing away old data.
int main(int argc, char **argv)
bool g_experimental_statcache
Builder wraps the build process: starting commands, updating status.
void Fatal(const char *msg,...)
Log a fatal message and exit.
The singleton that stores metrics and prints the report.
string GetBinding(const string &key)
Returns the shell-escaped value of |key|.
Runs the process of creating GraphViz .dot file output.
const string & name() const
void AllowStatCache(bool allow)
Whether stat information can be cached. Only has an effect on Windows.
Options (e.g. verbosity, parallelism) passed to a build.
Global state (file status) for a single run.
unsigned long long uint64_t
bool Load(const string &path, string *err)
Load the on-disk log.
void Warning(const char *msg,...)
Log a warning message.
DupeEdgeAction dupe_edge_action_
DepfileParserOptions depfile_parser_options
string AsString() const
Convert the slice into a full-fledged std::string, copying the data into a new string.
void AddTarget(Node *node)
void Error(const char *msg,...)
Log an error message.
bool IsDepsEntryLiveFor(Node *node)
Returns if the deps entry for a node is still reachable from the manifest.
Can answer questions about the manifest for the BuildLog.
vector< Node * > outputs_