56 void CreateWin32MiniDump(_EXCEPTION_POINTERS* pep);
66 const char* input_file;
69 const char* working_dir;
75 bool dupe_edges_should_err;
78 bool phony_cycle_should_err;
84 NinjaMain(
const char* ninja_command,
const BuildConfig& config) :
85 ninja_command_(ninja_command), config_(config) {}
88 const char* ninja_command_;
106 typedef int (NinjaMain::*ToolFunc)(
const Options*, int,
char**);
110 Node* CollectTarget(
const char* cpath,
string* err);
113 bool CollectTargetsFromArgs(
int argc,
char* argv[],
114 vector<Node*>* targets,
string* err);
117 int ToolGraph(
const Options* options,
int argc,
char* argv[]);
118 int ToolQuery(
const Options* options,
int argc,
char* argv[]);
119 int ToolDeps(
const Options* options,
int argc,
char* argv[]);
120 int ToolBrowse(
const Options* options,
int argc,
char* argv[]);
121 int ToolMSVC(
const Options* options,
int argc,
char* argv[]);
122 int ToolTargets(
const Options* options,
int argc,
char* argv[]);
123 int ToolCommands(
const Options* options,
int argc,
char* argv[]);
124 int ToolClean(
const Options* options,
int argc,
char* argv[]);
125 int ToolCleanDead(
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 ToolRestat(
const Options* options,
int argc,
char* argv[]);
129 int ToolUrtle(
const Options* options,
int argc,
char** argv);
130 int ToolRules(
const Options* options,
int argc,
char* argv[]);
134 bool OpenBuildLog(
bool recompact_only =
false);
138 bool OpenDepsLog(
bool recompact_only =
false);
142 bool EnsureBuildDirExists();
147 bool RebuildManifest(
const char* input_file,
string* err);
151 int RunBuild(
int argc,
char** argv);
172 Error(
"%s", err.c_str());
199 NinjaMain::ToolFunc func;
205 "usage: ninja [options] [targets...]\n" 207 "if targets are unspecified, builds the 'default' target (see manual).\n" 210 " --version print ninja version (\"%s\")\n" 211 " -v, --verbose show all command lines while building\n" 213 " -C DIR change to DIR before doing anything else\n" 214 " -f FILE specify input build file [default=build.ninja]\n" 216 " -j N run N jobs in parallel (0 means infinity) [default=%d on this system]\n" 217 " -k N keep going until N jobs fail (0 means infinity) [default=1]\n" 218 " -l N do not start new jobs if the load average is greater than N\n" 219 " -n dry run (don't run commands but act like they succeeded)\n" 221 " -d MODE enable debugging (use '-d list' to list modes)\n" 222 " -t TOOL run a subtool (use '-t list' to list subtools)\n" 223 " terminates toplevel options; further flags are passed to the tool\n" 224 " -w FLAG adjust warnings (use '-w list' to list warnings)\n",
229 int GuessParallelism() {
237 return processors + 2;
243 bool NinjaMain::RebuildManifest(
const char* input_file,
string* err) {
244 string path = input_file;
252 Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_);
253 if (!builder.AddTarget(node, err))
256 if (builder.AlreadyUpToDate())
259 if (!builder.Build(err))
264 if (!node->
dirty()) {
274 Node* NinjaMain::CollectTarget(
const char* cpath,
string* err) {
281 bool first_dependent =
false;
282 if (!path.empty() && path[path.size() - 1] ==
'^') {
283 path.resize(path.size() - 1);
284 first_dependent =
true;
289 if (first_dependent) {
291 *err =
"'" + path +
"' has no out edge";
297 Fatal(
"edge has no outputs");
305 if (path ==
"clean") {
306 *err +=
", did you mean 'ninja -t clean'?";
307 }
else if (path ==
"help") {
308 *err +=
", did you mean 'ninja -h'?";
312 *err +=
", did you mean '" + suggestion->
path() +
"'?";
319 bool NinjaMain::CollectTargetsFromArgs(
int argc,
char* argv[],
320 vector<Node*>* targets,
string* err) {
326 for (
int i = 0; i < argc; ++i) {
327 Node* node = CollectTarget(argv[i], err);
330 targets->push_back(node);
335 int NinjaMain::ToolGraph(
const Options* options,
int argc,
char* argv[]) {
338 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
339 Error(
"%s", err.c_str());
343 GraphViz graph(&state_, &disk_interface_);
345 for (vector<Node*>::const_iterator n = nodes.begin(); n != nodes.end(); ++n)
352 int NinjaMain::ToolQuery(
const Options* options,
int argc,
char* argv[]) {
354 Error(
"expected a target to query");
360 for (
int i = 0; i < argc; ++i) {
362 Node* node = CollectTarget(argv[i], &err);
364 Error(
"%s", err.c_str());
368 printf(
"%s:\n", node->
path().c_str());
371 if (!dyndep_loader.LoadDyndeps(edge->
dyndep_, &err)) {
375 printf(
" input: %s\n", edge->
rule_->
name().c_str());
376 for (
int in = 0; in < (int)edge->
inputs_.size(); in++) {
377 const char* label =
"";
382 printf(
" %s%s\n", label, edge->
inputs_[in]->path().c_str());
385 printf(
" outputs:\n");
386 for (vector<Edge*>::const_iterator edge = node->
out_edges().begin();
387 edge != node->
out_edges().end(); ++edge) {
388 for (vector<Node*>::iterator out = (*edge)->outputs_.begin();
389 out != (*edge)->outputs_.end(); ++out) {
390 printf(
" %s\n", (*out)->path().c_str());
397 #if defined(NINJA_HAVE_BROWSE) 398 int NinjaMain::ToolBrowse(
const Options* options,
int argc,
char* argv[]) {
399 RunBrowsePython(&state_, ninja_command_, options->input_file, argc, argv);
404 int NinjaMain::ToolBrowse(
const Options*,
int,
char**) {
405 Fatal(
"browse tool not supported on this platform");
410 #if defined(_MSC_VER) 411 int NinjaMain::ToolMSVC(
const Options* options,
int argc,
char* argv[]) {
420 int ToolTargetsList(
const vector<Node*>& nodes,
int depth,
int indent) {
421 for (vector<Node*>::const_iterator n = nodes.begin();
424 for (
int i = 0; i < indent; ++i)
426 const char* target = (*n)->path().c_str();
427 if ((*n)->in_edge()) {
428 printf(
"%s: %s\n", target, (*n)->in_edge()->rule_->name().c_str());
429 if (depth > 1 || depth <= 0)
430 ToolTargetsList((*n)->in_edge()->inputs_, depth - 1, indent + 1);
432 printf(
"%s\n", target);
438 int ToolTargetsSourceList(
State* state) {
439 for (vector<Edge*>::iterator e = state->
edges_.begin();
440 e != state->
edges_.end(); ++e) {
441 for (vector<Node*>::iterator inps = (*e)->inputs_.begin();
442 inps != (*e)->inputs_.end(); ++inps) {
443 if (!(*inps)->in_edge())
444 printf(
"%s\n", (*inps)->path().c_str());
450 int ToolTargetsList(
State* state,
const string& rule_name) {
454 for (vector<Edge*>::iterator e = state->
edges_.begin();
455 e != state->
edges_.end(); ++e) {
456 if ((*e)->rule_->name() == rule_name) {
457 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
458 out_node != (*e)->outputs_.end(); ++out_node) {
459 rules.insert((*out_node)->path());
465 for (set<string>::const_iterator i = rules.begin();
466 i != rules.end(); ++i) {
467 printf(
"%s\n", (*i).c_str());
473 int ToolTargetsList(
State* state) {
474 for (vector<Edge*>::iterator e = state->
edges_.begin();
475 e != state->
edges_.end(); ++e) {
476 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
477 out_node != (*e)->outputs_.end(); ++out_node) {
479 (*out_node)->path().c_str(),
480 (*e)->rule_->name().c_str());
486 int NinjaMain::ToolDeps(
const Options* options,
int argc,
char** argv) {
489 for (vector<Node*>::const_iterator ni = deps_log_.
nodes().begin();
490 ni != deps_log_.
nodes().end(); ++ni) {
492 nodes.push_back(*ni);
496 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
497 Error(
"%s", err.c_str());
503 for (vector<Node*>::iterator it = nodes.begin(), end = nodes.end();
507 printf(
"%s: deps not found\n", (*it)->path().c_str());
514 Error(
"%s", err.c_str());
515 printf(
"%s: #deps %d, deps mtime %" PRId64 " (%s)\n",
517 (!mtime || mtime > deps->
mtime ?
"STALE":
"VALID"));
519 printf(
" %s\n", deps->
nodes[i]->
path().c_str());
526 int NinjaMain::ToolTargets(
const Options* options,
int argc,
char* argv[]) {
529 string mode = argv[0];
530 if (mode ==
"rule") {
535 return ToolTargetsSourceList(&state_);
537 return ToolTargetsList(&state_, rule);
538 }
else if (mode ==
"depth") {
540 depth = atoi(argv[1]);
541 }
else if (mode ==
"all") {
542 return ToolTargetsList(&state_);
544 const char* suggestion =
547 Error(
"unknown target tool mode '%s', did you mean '%s'?",
548 mode.c_str(), suggestion);
550 Error(
"unknown target tool mode '%s'", mode.c_str());
557 vector<Node*> root_nodes = state_.
RootNodes(&err);
559 return ToolTargetsList(root_nodes, depth, 0);
561 Error(
"%s", err.c_str());
566 int NinjaMain::ToolRules(
const Options* options,
int argc,
char* argv[]) {
574 bool print_description =
false;
578 while ((opt =
getopt(argc, argv, const_cast<char*>(
"hd"))) != -1) {
581 print_description =
true;
585 printf(
"usage: ninja -t rules [options]\n" 588 " -d also print the description of the rule\n" 589 " -h print this message\n" 599 typedef map<string, const Rule*> Rules;
601 for (Rules::const_iterator i = rules.begin(); i != rules.end(); ++i) {
602 printf(
"%s", i->first.c_str());
603 if (print_description) {
604 const Rule* rule = i->second;
606 if (description != NULL) {
607 printf(
": %s", description->
Unparse().c_str());
619 if (!seen->insert(edge).second)
622 if (mode == PCM_All) {
623 for (vector<Node*>::iterator in = edge->
inputs_.begin();
624 in != edge->
inputs_.end(); ++in)
625 PrintCommands((*in)->in_edge(), seen, mode);
632 int NinjaMain::ToolCommands(
const Options* options,
int argc,
char* argv[]) {
642 while ((opt =
getopt(argc, argv, const_cast<char*>(
"hs"))) != -1) {
649 printf(
"usage: ninja -t commands [options] [targets]\n" 652 " -s only print the final command to build [target], not the whole chain\n" 662 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
663 Error(
"%s", err.c_str());
668 for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in)
669 PrintCommands((*in)->in_edge(), &seen, mode);
674 int NinjaMain::ToolClean(
const Options* options,
int argc,
char* argv[]) {
680 bool generator =
false;
681 bool clean_rules =
false;
685 while ((opt =
getopt(argc, argv, const_cast<char*>(
"hgr"))) != -1) {
695 printf(
"usage: ninja -t clean [options] [targets]\n" 698 " -g also clean files marked as ninja generator output\n" 699 " -r interpret targets as a list of rules to clean instead\n" 707 if (clean_rules && argc == 0) {
708 Error(
"expected a rule to clean");
712 Cleaner cleaner(&state_, config_, &disk_interface_);
715 return cleaner.CleanRules(argc, argv);
717 return cleaner.CleanTargets(argc, argv);
719 return cleaner.CleanAll(generator);
723 int NinjaMain::ToolCleanDead(
const Options* options,
int argc,
char* argv[]) {
724 Cleaner cleaner(&state_, config_, &disk_interface_);
725 return cleaner.CleanDead(build_log_.
entries());
728 void EncodeJSONString(
const char *str) {
730 if (*str ==
'"' || *str ==
'\\')
741 std::string EvaluateCommandWithRspfile(
const Edge* edge,
744 if (mode == ECM_NORMAL)
751 size_t index = command.find(rspfile);
752 if (index == 0 || index == string::npos || command[index - 1] !=
'@')
755 string rspfile_content = edge->
GetBinding(
"rspfile_content");
756 size_t newline_index = 0;
757 while ((newline_index = rspfile_content.find(
'\n', newline_index)) !=
759 rspfile_content.replace(newline_index, 1, 1,
' ');
762 command.replace(index - 1, rspfile.length() + 1, rspfile_content);
766 void printCompdb(
const char*
const directory,
const Edge*
const edge,
768 printf(
"\n {\n \"directory\": \"");
769 EncodeJSONString(directory);
770 printf(
"\",\n \"command\": \"");
771 EncodeJSONString(EvaluateCommandWithRspfile(edge, eval_mode).c_str());
772 printf(
"\",\n \"file\": \"");
773 EncodeJSONString(edge->
inputs_[0]->path().c_str());
774 printf(
"\",\n \"output\": \"");
775 EncodeJSONString(edge->
outputs_[0]->path().c_str());
779 int NinjaMain::ToolCompilationDatabase(
const Options* options,
int argc,
790 while ((opt =
getopt(argc, argv, const_cast<char*>(
"hx"))) != -1) {
793 eval_mode = ECM_EXPAND_RSPFILE;
799 "usage: ninja -t compdb [options] [rules]\n" 802 " -x expand @rspfile style response file invocations\n" 812 char* success = NULL;
815 cwd.resize(cwd.size() + 1024);
817 success = getcwd(&cwd[0], cwd.size());
818 }
while (!success && errno == ERANGE);
820 Error(
"cannot determine working directory: %s", strerror(errno));
825 for (vector<Edge*>::iterator e = state_.
edges_.begin();
826 e != state_.
edges_.end(); ++e) {
827 if ((*e)->inputs_.empty())
833 printCompdb(&cwd[0], *e, eval_mode);
836 for (
int i = 0; i != argc; ++i) {
837 if ((*e)->rule_->name() == argv[i]) {
841 printCompdb(&cwd[0], *e, eval_mode);
852 int NinjaMain::ToolRecompact(
const Options* options,
int argc,
char* argv[]) {
853 if (!EnsureBuildDirExists())
863 int NinjaMain::ToolRestat(
const Options* options,
int argc,
char* argv[]) {
871 while ((opt =
getopt(argc, argv, const_cast<char*>(
"h"))) != -1) {
875 printf(
"usage: ninja -t restat [outputs]\n");
882 if (!EnsureBuildDirExists())
885 string log_path =
".ninja_log";
886 if (!build_dir_.empty())
887 log_path = build_dir_ +
"/" + log_path;
892 Error(
"loading build log %s: %s", log_path.c_str(), err.c_str());
905 bool success = build_log_.
Restat(log_path, disk_interface_, argc, argv, &err);
907 Error(
"failed recompaction: %s", err.c_str());
913 Error(
"opening build log: %s", err.c_str());
921 int NinjaMain::ToolUrtle(
const Options* options,
int argc,
char** argv) {
924 " 13 ,3;2!2;\n8 ,;<11!;\n5 `'<10!(2`'2!\n11 ,6;, `\\. `\\9 .,c13$ec,.\n6 " 925 ",2;11!>; `. ,;!2> .e8$2\".2 \"?7$e.\n <:<8!'` 2.3,.2` ,3!' ;,(?7\";2!2'<" 926 "; `?6$PF ,;,\n2 `'4!8;<!3'`2 3! ;,`'2`2'3!;4!`2.`!;2 3,2 .<!2'`).\n5 3`5" 927 "'2`9 `!2 `4!><3;5! J2$b,`!>;2!:2!`,d?b`!>\n26 `'-;,(<9!> $F3 )3.:!.2 d\"" 928 "2 ) !>\n30 7`2'<3!- \"=-='5 .2 `2-=\",!>\n25 .ze9$er2 .,cd16$bc.'\n22 .e" 929 "14$,26$.\n21 z45$c .\n20 J50$c\n20 14$P\"`?34$b\n20 14$ dbc `2\"?22$?7$c" 930 "\n20 ?18$c.6 4\"8?4\" c8$P\n9 .2,.8 \"20$c.3 ._14 J9$\n .2,2c9$bec,.2 `?" 931 "21$c.3`4%,3%,3 c8$P\"\n22$c2 2\"?21$bc2,.2` .2,c7$P2\",cb\n23$b bc,.2\"2" 932 "?14$2F2\"5?2\",J5$P\" ,zd3$\n24$ ?$3?%3 `2\"2?12$bcucd3$P3\"2 2=7$\n23$P" 933 "\" ,3;<5!>2;,. `4\"6?2\"2 ,9;, `\"?2$\n";
935 for (
const char* p = urtle; *p; p++) {
936 if (
'0' <= *p && *p <=
'9') {
937 count = count*10 + *p -
'0';
939 for (
int i = 0; i < max(count, 1); ++i)
949 const Tool* ChooseTool(
const string& tool_name) {
950 static const Tool kTools[] = {
951 {
"browse",
"browse dependency graph in a web browser",
952 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolBrowse },
953 #if defined(_MSC_VER) 954 {
"msvc",
"build helper for MSVC cl.exe (EXPERIMENTAL)",
955 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolMSVC },
957 {
"clean",
"clean built files",
958 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolClean },
959 {
"commands",
"list all commands required to rebuild given targets",
960 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCommands },
961 {
"deps",
"show dependencies stored in the deps log",
962 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolDeps },
963 {
"graph",
"output graphviz dot file for targets",
964 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolGraph },
965 {
"query",
"show inputs/outputs for a path",
966 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolQuery },
967 {
"targets",
"list targets by their rule or depth in the DAG",
968 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolTargets },
969 {
"compdb",
"dump JSON compilation database to stdout",
970 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCompilationDatabase },
971 {
"recompact",
"recompacts ninja-internal data structures",
972 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolRecompact },
973 {
"restat",
"restats all outputs in the build log",
974 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolRestat },
975 {
"rules",
"list all rules",
976 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolRules },
977 {
"cleandead",
"clean built files that are no longer produced by the manifest",
978 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolCleanDead },
980 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolUrtle },
981 { NULL, NULL, Tool::RUN_AFTER_FLAGS, NULL }
984 if (tool_name ==
"list") {
985 printf(
"ninja subtools:\n");
986 for (
const Tool* tool = &kTools[0]; tool->name; ++tool) {
988 printf(
"%10s %s\n", tool->name, tool->desc);
993 for (
const Tool* tool = &kTools[0]; tool->name; ++tool) {
994 if (tool->name == tool_name)
998 vector<const char*> words;
999 for (
const Tool* tool = &kTools[0]; tool->name; ++tool)
1000 words.push_back(tool->name);
1003 Fatal(
"unknown tool '%s', did you mean '%s'?",
1004 tool_name.c_str(), suggestion);
1006 Fatal(
"unknown tool '%s'", tool_name.c_str());
1013 bool DebugEnable(
const string& name) {
1014 if (name ==
"list") {
1015 printf(
"debugging modes:\n" 1016 " stats print operation counts/timing info\n" 1017 " explain explain what caused a command to execute\n" 1018 " keepdepfile don't delete depfiles after they're read by ninja\n" 1019 " keeprsp don't delete @response files on success\n" 1021 " nostatcache don't batch stat() calls per directory and cache them\n" 1023 "multiple modes can be enabled via -d FOO -d BAR\n");
1025 }
else if (name ==
"stats") {
1028 }
else if (name ==
"explain") {
1031 }
else if (name ==
"keepdepfile") {
1034 }
else if (name ==
"keeprsp") {
1037 }
else if (name ==
"nostatcache") {
1041 const char* suggestion =
1043 "stats",
"explain",
"keepdepfile",
"keeprsp",
1044 "nostatcache", NULL);
1046 Error(
"unknown debug setting '%s', did you mean '%s'?",
1047 name.c_str(), suggestion);
1049 Error(
"unknown debug setting '%s'", name.c_str());
1057 bool WarningEnable(
const string& name, Options* options) {
1058 if (name ==
"list") {
1059 printf(
"warning flags:\n" 1060 " dupbuild={err,warn} multiple build lines for one target\n" 1061 " phonycycle={err,warn} phony build statement references itself\n" 1064 }
else if (name ==
"dupbuild=err") {
1065 options->dupe_edges_should_err =
true;
1067 }
else if (name ==
"dupbuild=warn") {
1068 options->dupe_edges_should_err =
false;
1070 }
else if (name ==
"phonycycle=err") {
1071 options->phony_cycle_should_err =
true;
1073 }
else if (name ==
"phonycycle=warn") {
1074 options->phony_cycle_should_err =
false;
1076 }
else if (name ==
"depfilemulti=err" ||
1077 name ==
"depfilemulti=warn") {
1078 Warning(
"deprecated warning 'depfilemulti'");
1081 const char* suggestion =
1083 "phonycycle=err",
"phonycycle=warn", NULL);
1085 Error(
"unknown warning flag '%s', did you mean '%s'?",
1086 name.c_str(), suggestion);
1088 Error(
"unknown warning flag '%s'", name.c_str());
1094 bool NinjaMain::OpenBuildLog(
bool recompact_only) {
1095 string log_path =
".ninja_log";
1096 if (!build_dir_.empty())
1097 log_path = build_dir_ +
"/" + log_path;
1102 Error(
"loading build log %s: %s", log_path.c_str(), err.c_str());
1111 if (recompact_only) {
1115 bool success = build_log_.
Recompact(log_path, *
this, &err);
1117 Error(
"failed recompaction: %s", err.c_str());
1123 Error(
"opening build log: %s", err.c_str());
1133 bool NinjaMain::OpenDepsLog(
bool recompact_only) {
1134 string path =
".ninja_deps";
1135 if (!build_dir_.empty())
1136 path = build_dir_ +
"/" + path;
1141 Error(
"loading deps log %s: %s", path.c_str(), err.c_str());
1150 if (recompact_only) {
1154 bool success = deps_log_.
Recompact(path, &err);
1156 Error(
"failed recompaction: %s", err.c_str());
1162 Error(
"opening deps log: %s", err.c_str());
1170 void NinjaMain::DumpMetrics() {
1174 int count = (int)state_.
paths_.size();
1175 int buckets = (int)state_.
paths_.bucket_count();
1176 printf(
"path->node hash load %.2f (%d entries / %d buckets)\n",
1177 count / (
double) buckets, count, buckets);
1180 bool NinjaMain::EnsureBuildDirExists() {
1182 if (!build_dir_.empty() && !config_.
dry_run) {
1183 if (!disk_interface_.
MakeDirs(build_dir_ +
"/.") && errno != EEXIST) {
1184 Error(
"creating build directory %s: %s",
1185 build_dir_.c_str(), strerror(errno));
1192 int NinjaMain::RunBuild(
int argc,
char** argv) {
1194 vector<Node*> targets;
1195 if (!CollectTargetsFromArgs(argc, argv, &targets, &err)) {
1196 Error(
"%s", err.c_str());
1202 Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_);
1203 for (
size_t i = 0; i < targets.size(); ++i) {
1204 if (!builder.AddTarget(targets[i], &err)) {
1206 Error(
"%s", err.c_str());
1218 if (builder.AlreadyUpToDate()) {
1219 printf(
"ninja: no work to do.\n");
1223 if (!builder.Build(&err)) {
1224 printf(
"ninja: build stopped: %s.\n", err.c_str());
1225 if (err.find(
"interrupted by user") != string::npos) {
1241 void TerminateHandler() {
1242 CreateWin32MiniDump(NULL);
1243 Fatal(
"terminate handler called");
1248 int ExceptionFilter(
unsigned int code,
struct _EXCEPTION_POINTERS *ep) {
1249 Error(
"exception: 0x%X", code);
1251 CreateWin32MiniDump(ep);
1252 return EXCEPTION_EXECUTE_HANDLER;
1259 int ReadFlags(
int* argc,
char*** argv,
1263 enum { OPT_VERSION = 1 };
1264 const option kLongOptions[] = {
1268 { NULL, 0, NULL, 0 }
1272 while (!options->tool &&
1273 (opt =
getopt_long(*argc, *argv,
"d:f:j:k:l:nt:vw:C:h", kLongOptions,
1277 if (!DebugEnable(
optarg))
1281 options->input_file =
optarg;
1285 int value = strtol(
optarg, &end, 10);
1286 if (*end != 0 || value < 0)
1287 Fatal(
"invalid -j parameter");
1291 config->
parallelism = value > 0 ? value : INT_MAX;
1296 int value = strtol(
optarg, &end, 10);
1298 Fatal(
"-k parameter not numeric; did you mean -k 0?");
1308 double value = strtod(
optarg, &end);
1310 Fatal(
"-l parameter not numeric: did you mean -l 0.0?");
1318 options->tool = ChooseTool(
optarg);
1326 if (!WarningEnable(
optarg, options))
1330 options->working_dir =
optarg;
1347 NORETURN void real_main(
int argc,
char** argv) {
1351 Options options = {};
1352 options.input_file =
"build.ninja";
1353 options.dupe_edges_should_err =
true;
1355 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
1356 const char* ninja_command = argv[0];
1358 int exit_code = ReadFlags(&argc, &argv, &options, &config);
1362 if (options.working_dir) {
1369 printf(
"ninja: Entering directory `%s'\n", options.working_dir);
1370 if (chdir(options.working_dir) < 0) {
1371 Fatal(
"chdir to '%s' - %s", options.working_dir, strerror(errno));
1375 if (options.tool && options.tool->when == Tool::RUN_AFTER_FLAGS) {
1378 NinjaMain ninja(ninja_command, config);
1379 exit((ninja.*options.tool->func)(&options, argc, argv));
1383 const int kCycleLimit = 100;
1384 for (
int cycle = 1; cycle <= kCycleLimit; ++cycle) {
1385 NinjaMain ninja(ninja_command, config);
1388 if (options.dupe_edges_should_err) {
1391 if (options.phony_cycle_should_err) {
1394 ManifestParser parser(&ninja.state_, &ninja.disk_interface_, parser_opts);
1396 if (!parser.Load(options.input_file, &err)) {
1397 Error(
"%s", err.c_str());
1401 if (options.tool && options.tool->when == Tool::RUN_AFTER_LOAD)
1402 exit((ninja.*options.tool->func)(&options, argc, argv));
1404 if (!ninja.EnsureBuildDirExists())
1407 if (!ninja.OpenBuildLog() || !ninja.OpenDepsLog())
1410 if (options.tool && options.tool->when == Tool::RUN_AFTER_LOGS)
1411 exit((ninja.*options.tool->func)(&options, argc, argv));
1414 if (ninja.RebuildManifest(options.input_file, &err)) {
1421 }
else if (!err.empty()) {
1422 Error(
"rebuilding '%s': %s", options.input_file, err.c_str());
1426 int result = ninja.RunBuild(argc, argv);
1428 ninja.DumpMetrics();
1432 Error(
"manifest '%s' still dirty after %d tries\n",
1433 options.input_file, kCycleLimit);
1440 #if defined(_MSC_VER) 1443 std::set_terminate(TerminateHandler);
1447 real_main(argc, argv);
1449 __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
1455 real_main(argc, argv);
bool OpenForWrite(const std::string &path, const BuildLogUser &user, std::string *err)
Prepares writing to the log file without actually opening it - that will happen when/if it's needed...
bool Recompact(const std::string &path, const BuildLogUser &user, std::string *err)
Rewrite the known log entries, throwing away old data.
bool dyndep_pending() const
void Report()
Print a summary report to stdout.
const char * SpellcheckStringV(const string &text, const vector< const char *> &words)
const Entries & entries() const
std::string AsString() const
Convert the slice into a full-fledged std::string, copying the data into a new string.
Node * SpellcheckNode(const std::string &path)
LoadStatus Load(const std::string &path, std::string *err)
Load the on-disk log.
const char * SpellcheckString(const char *text,...)
Like SpellcheckStringV, but takes a NULL-terminated list.
const std::map< std::string, const Rule * > & GetRules() const
void Dump(const char *prefix="") const
const EvalString * GetBinding(const std::string &key) const
const std::vector< Node * > & nodes() const
Used for tests.
double max_load_average
The maximum load average we must not exceed.
int MSVCHelperMain(int argc, char **argv)
bool Restat(StringPiece path, const DiskInterface &disk_interface, int output_count, char **outputs, std::string *err)
Restat all outputs in the log.
bool CanonicalizePath(string *path, uint64_t *slash_bits, string *err)
PhonyCycleAction phony_cycle_action_
StringPiece represents a slice of a string whose memory is managed externally.
const std::string & name() const
Information about a node in the dependency graph: the file, whether it's dirty, mtime, etc.
virtual TimeStamp Stat(const std::string &path, std::string *err) const
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
std::vector< Node * > outputs_
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.
std::string PathDecanonicalized() const
Get |path()| but use slash_bits to convert back to original slash styles.
std::vector< Node * > RootNodes(std::string *error) const
bool is_order_only(size_t index)
LoadStatus Load(const std::string &path, State *state, std::string *err)
const std::string & path() const
bool Recompact(const std::string &path, std::string *err)
Rewrite the known log entries, throwing away old data.
As build commands run they can output extra dependency information (e.g.
Implementation of DiskInterface that actually hits the disk.
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)
An invokable build command and associated metadata (description, etc.).
Deps * GetDeps(Node *node)
std::string GetUnescapedRspfile() const
Like GetBinding("rspfile"), but without shell escaping.
int getopt(int argc, char **argv, char *optstring)
DyndepLoader loads dynamically discovered dependencies, as referenced via the "dyndep" attribute in b...
int main(int argc, char **argv)
bool OpenForWrite(const std::string &path, std::string *err)
std::vector< Node * > inputs_
bool g_experimental_statcache
Builder wraps the build process: starting commands, updating status.
std::string GetBinding(const std::string &key) const
Returns the shell-escaped value of |key|.
void Fatal(const char *msg,...)
Log a fatal message and exit.
std::vector< Node * > DefaultNodes(std::string *error) const
The singleton that stores metrics and prints the report.
bool MakeDirs(const std::string &path)
Create all the parent directories for path; like mkdir -p basename path.
Runs the process of creating GraphViz .dot file output.
std::string EvaluateCommand(bool incl_rsp_file=false) const
Expand all variables in a command and return it as a string.
void AllowStatCache(bool allow)
Whether stat information can be cached. Only has an effect on Windows.
const std::vector< Edge * > & out_edges() const
std::string Unparse() const
Options (e.g. verbosity, parallelism) passed to a build.
Global state (file status) for a single run.
unsigned long long uint64_t
std::vector< Edge * > edges_
All the edges of the graph.
virtual std::string LookupVariable(const std::string &var)
A tokenized string that contains variable references.
void Warning(const char *msg,...)
Log a warning message.
DupeEdgeAction dupe_edge_action_
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.