62 void CreateWin32MiniDump(_EXCEPTION_POINTERS* pep);
72 const char* input_file;
75 const char* working_dir;
81 bool dupe_edges_should_err;
84 bool phony_cycle_should_err;
90 NinjaMain(
const char* ninja_command,
const BuildConfig& config) :
91 ninja_command_(ninja_command), config_(config),
95 const char* ninja_command_;
113 typedef int (NinjaMain::*ToolFunc)(
const Options*, int,
char**);
117 Node* CollectTarget(
const char* cpath,
string* err);
120 bool CollectTargetsFromArgs(
int argc,
char* argv[],
121 vector<Node*>* targets,
string* err);
124 int ToolGraph(
const Options* options,
int argc,
char* argv[]);
125 int ToolQuery(
const Options* options,
int argc,
char* argv[]);
126 int ToolDeps(
const Options* options,
int argc,
char* argv[]);
127 int ToolMissingDeps(
const Options* options,
int argc,
char* argv[]);
128 int ToolBrowse(
const Options* options,
int argc,
char* argv[]);
129 int ToolMSVC(
const Options* options,
int argc,
char* argv[]);
130 int ToolTargets(
const Options* options,
int argc,
char* argv[]);
131 int ToolCommands(
const Options* options,
int argc,
char* argv[]);
132 int ToolInputs(
const Options* options,
int argc,
char* argv[]);
133 int ToolClean(
const Options* options,
int argc,
char* argv[]);
134 int ToolCleanDead(
const Options* options,
int argc,
char* argv[]);
135 int ToolCompilationDatabase(
const Options* options,
int argc,
char* argv[]);
136 int ToolRecompact(
const Options* options,
int argc,
char* argv[]);
137 int ToolRestat(
const Options* options,
int argc,
char* argv[]);
138 int ToolUrtle(
const Options* options,
int argc,
char** argv);
139 int ToolRules(
const Options* options,
int argc,
char* argv[]);
140 int ToolWinCodePage(
const Options* options,
int argc,
char* argv[]);
144 bool OpenBuildLog(
bool recompact_only =
false);
148 bool OpenDepsLog(
bool recompact_only =
false);
152 bool EnsureBuildDirExists();
157 bool RebuildManifest(
const char* input_file,
string* err,
Status* status);
161 int RunBuild(
int argc,
char** argv,
Status* status);
182 Error(
"%s", err.c_str());
211 NinjaMain::ToolFunc func;
217 "usage: ninja [options] [targets...]\n" 219 "if targets are unspecified, builds the 'default' target (see manual).\n" 222 " --version print ninja version (\"%s\")\n" 223 " -v, --verbose show all command lines while building\n" 224 " --quiet don't show progress status, just command output\n" 226 " -C DIR change to DIR before doing anything else\n" 227 " -f FILE specify input build file [default=build.ninja]\n" 229 " -j N run N jobs in parallel (0 means infinity) [default=%d on this system]\n" 230 " -k N keep going until N jobs fail (0 means infinity) [default=1]\n" 231 " -l N do not start new jobs if the load average is greater than N\n" 232 " -n dry run (don't run commands but act like they succeeded)\n" 234 " -d MODE enable debugging (use '-d list' to list modes)\n" 235 " -t TOOL run a subtool (use '-t list' to list subtools)\n" 236 " terminates toplevel options; further flags are passed to the tool\n" 237 " -w FLAG adjust warnings (use '-w list' to list warnings)\n",
242 int GuessParallelism() {
250 return processors + 2;
256 bool NinjaMain::RebuildManifest(
const char* input_file,
string* err,
258 string path = input_file;
269 Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_,
270 status, start_time_millis_);
271 if (!builder.AddTarget(node, err))
274 if (builder.AlreadyUpToDate())
277 if (!builder.Build(err))
282 if (!node->
dirty()) {
292 Node* NinjaMain::CollectTarget(
const char* cpath,
string* err) {
302 bool first_dependent =
false;
303 if (!path.empty() && path[path.size() - 1] ==
'^') {
304 path.resize(path.size() - 1);
305 first_dependent =
true;
310 if (first_dependent) {
314 *err =
"'" + path +
"' has no out edge";
322 Fatal(
"edge has no outputs");
331 if (path ==
"clean") {
332 *err +=
", did you mean 'ninja -t clean'?";
333 }
else if (path ==
"help") {
334 *err +=
", did you mean 'ninja -h'?";
338 *err +=
", did you mean '" + suggestion->
path() +
"'?";
345 bool NinjaMain::CollectTargetsFromArgs(
int argc,
char* argv[],
346 vector<Node*>* targets,
string* err) {
352 for (
int i = 0; i < argc; ++i) {
353 Node* node = CollectTarget(argv[i], err);
356 targets->push_back(node);
361 int NinjaMain::ToolGraph(
const Options* options,
int argc,
char* argv[]) {
364 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
365 Error(
"%s", err.c_str());
369 GraphViz graph(&state_, &disk_interface_);
371 for (vector<Node*>::const_iterator n = nodes.begin(); n != nodes.end(); ++n)
378 int NinjaMain::ToolQuery(
const Options* options,
int argc,
char* argv[]) {
380 Error(
"expected a target to query");
386 for (
int i = 0; i < argc; ++i) {
388 Node* node = CollectTarget(argv[i], &err);
390 Error(
"%s", err.c_str());
394 printf(
"%s:\n", node->
path().c_str());
397 if (!dyndep_loader.LoadDyndeps(edge->
dyndep_, &err)) {
401 printf(
" input: %s\n", edge->
rule_->
name().c_str());
402 for (
int in = 0; in < (int)edge->
inputs_.size(); in++) {
403 const char* label =
"";
408 printf(
" %s%s\n", label, edge->
inputs_[in]->path().c_str());
411 printf(
" validations:\n");
412 for (std::vector<Node*>::iterator validation = edge->
validations_.begin();
414 printf(
" %s\n", (*validation)->path().c_str());
418 printf(
" outputs:\n");
419 for (vector<Edge*>::const_iterator edge = node->
out_edges().begin();
420 edge != node->
out_edges().end(); ++edge) {
421 for (vector<Node*>::iterator out = (*edge)->outputs_.begin();
422 out != (*edge)->outputs_.end(); ++out) {
423 printf(
" %s\n", (*out)->path().c_str());
427 if (!validation_edges.empty()) {
428 printf(
" validation for:\n");
429 for (std::vector<Edge*>::const_iterator edge = validation_edges.begin();
430 edge != validation_edges.end(); ++edge) {
431 for (vector<Node*>::iterator out = (*edge)->outputs_.begin();
432 out != (*edge)->outputs_.end(); ++out) {
433 printf(
" %s\n", (*out)->path().c_str());
441 #if defined(NINJA_HAVE_BROWSE) 442 int NinjaMain::ToolBrowse(
const Options* options,
int argc,
char* argv[]) {
443 RunBrowsePython(&state_, ninja_command_, options->input_file, argc, argv);
448 int NinjaMain::ToolBrowse(
const Options*,
int,
char**) {
449 Fatal(
"browse tool not supported on this platform");
455 int NinjaMain::ToolMSVC(
const Options* options,
int argc,
char* argv[]) {
464 int ToolTargetsList(
const vector<Node*>& nodes,
int depth,
int indent) {
465 for (vector<Node*>::const_iterator n = nodes.begin();
468 for (
int i = 0; i < indent; ++i)
470 const char* target = (*n)->path().c_str();
471 if ((*n)->in_edge()) {
472 printf(
"%s: %s\n", target, (*n)->in_edge()->rule_->name().c_str());
473 if (depth > 1 || depth <= 0)
474 ToolTargetsList((*n)->in_edge()->inputs_, depth - 1, indent + 1);
476 printf(
"%s\n", target);
482 int ToolTargetsSourceList(
State* state) {
483 for (vector<Edge*>::iterator e = state->
edges_.begin();
484 e != state->
edges_.end(); ++e) {
485 for (vector<Node*>::iterator inps = (*e)->inputs_.begin();
486 inps != (*e)->inputs_.end(); ++inps) {
487 if (!(*inps)->in_edge())
488 printf(
"%s\n", (*inps)->path().c_str());
494 int ToolTargetsList(
State* state,
const string& rule_name) {
498 for (vector<Edge*>::iterator e = state->
edges_.begin();
499 e != state->
edges_.end(); ++e) {
500 if ((*e)->rule_->name() == rule_name) {
501 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
502 out_node != (*e)->outputs_.end(); ++out_node) {
503 rules.insert((*out_node)->path());
509 for (set<string>::const_iterator i = rules.begin();
510 i != rules.end(); ++i) {
511 printf(
"%s\n", (*i).c_str());
517 int ToolTargetsList(
State* state) {
518 for (vector<Edge*>::iterator e = state->
edges_.begin();
519 e != state->
edges_.end(); ++e) {
520 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
521 out_node != (*e)->outputs_.end(); ++out_node) {
523 (*out_node)->path().c_str(),
524 (*e)->rule_->name().c_str());
530 int NinjaMain::ToolDeps(
const Options* options,
int argc,
char** argv) {
533 for (vector<Node*>::const_iterator ni = deps_log_.
nodes().begin();
534 ni != deps_log_.
nodes().end(); ++ni) {
536 nodes.push_back(*ni);
540 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
541 Error(
"%s", err.c_str());
547 for (vector<Node*>::iterator it = nodes.begin(), end = nodes.end();
551 printf(
"%s: deps not found\n", (*it)->path().c_str());
558 Error(
"%s", err.c_str());
559 printf(
"%s: #deps %d, deps mtime %" PRId64 " (%s)\n",
561 (!mtime || mtime > deps->
mtime ?
"STALE":
"VALID"));
563 printf(
" %s\n", deps->
nodes[i]->
path().c_str());
570 int NinjaMain::ToolMissingDeps(
const Options* options,
int argc,
char** argv) {
573 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
574 Error(
"%s", err.c_str());
581 for (vector<Node*>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
582 scanner.ProcessNode(*it);
584 scanner.PrintStats();
585 if (scanner.HadMissingDeps())
590 int NinjaMain::ToolTargets(
const Options* options,
int argc,
char* argv[]) {
593 string mode = argv[0];
594 if (mode ==
"rule") {
599 return ToolTargetsSourceList(&state_);
601 return ToolTargetsList(&state_, rule);
602 }
else if (mode ==
"depth") {
604 depth = atoi(argv[1]);
605 }
else if (mode ==
"all") {
606 return ToolTargetsList(&state_);
608 const char* suggestion =
611 Error(
"unknown target tool mode '%s', did you mean '%s'?",
612 mode.c_str(), suggestion);
614 Error(
"unknown target tool mode '%s'", mode.c_str());
621 vector<Node*> root_nodes = state_.
RootNodes(&err);
623 return ToolTargetsList(root_nodes, depth, 0);
625 Error(
"%s", err.c_str());
630 int NinjaMain::ToolRules(
const Options* options,
int argc,
char* argv[]) {
638 bool print_description =
false;
642 while ((opt =
getopt(argc, argv, const_cast<char*>(
"hd"))) != -1) {
645 print_description =
true;
649 printf(
"usage: ninja -t rules [options]\n" 652 " -d also print the description of the rule\n" 653 " -h print this message\n" 663 typedef map<string, const Rule*> Rules;
665 for (Rules::const_iterator i = rules.begin(); i != rules.end(); ++i) {
666 printf(
"%s", i->first.c_str());
667 if (print_description) {
668 const Rule* rule = i->second;
670 if (description != NULL) {
671 printf(
": %s", description->
Unparse().c_str());
680 int NinjaMain::ToolWinCodePage(
const Options* options,
int argc,
char* argv[]) {
682 printf(
"usage: ninja -t wincodepage\n");
685 printf(
"Build file encoding: %s\n", GetACP() == CP_UTF8?
"UTF-8" :
"ANSI");
694 if (!seen->insert(edge).second)
697 if (mode == PCM_All) {
698 for (vector<Node*>::iterator in = edge->
inputs_.begin();
699 in != edge->
inputs_.end(); ++in)
700 PrintCommands((*in)->in_edge(), seen, mode);
707 int NinjaMain::ToolCommands(
const Options* options,
int argc,
char* argv[]) {
717 while ((opt =
getopt(argc, argv, const_cast<char*>(
"hs"))) != -1) {
724 printf(
"usage: ninja -t commands [options] [targets]\n" 727 " -s only print the final command to build [target], not the whole chain\n" 737 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
738 Error(
"%s", err.c_str());
743 for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in)
744 PrintCommands((*in)->in_edge(), &seen, mode);
749 void CollectInputs(
Edge* edge, std::set<Edge*>* seen,
750 std::vector<std::string>* result) {
753 if (!seen->insert(edge).second)
756 for (vector<Node*>::iterator in = edge->
inputs_.begin();
757 in != edge->
inputs_.end(); ++in)
758 CollectInputs((*in)->in_edge(), seen, result);
765 int NinjaMain::ToolInputs(
const Options* options,
int argc,
char* argv[]) {
773 { NULL, 0, NULL, 0 } };
774 while ((opt =
getopt_long(argc, argv,
"h", kLongOptions, NULL)) != -1) {
780 "Usage '-t inputs [options] [targets]\n" 782 "List all inputs used for a set of targets. Note that this includes\n" 783 "explicit, implicit and order-only inputs, but not validation ones.\n\n" 785 " -h, --help Print this message.\n");
795 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
796 Error(
"%s", err.c_str());
800 std::set<Edge*> seen;
801 std::vector<std::string> result;
802 for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in)
803 CollectInputs((*in)->in_edge(), &seen, &result);
806 std::sort(result.begin(), result.end());
807 result.erase(std::unique(result.begin(), result.end()), result.end());
809 for (
size_t n = 0; n < result.size(); ++n)
810 puts(result[n].c_str());
815 int NinjaMain::ToolClean(
const Options* options,
int argc,
char* argv[]) {
821 bool generator =
false;
822 bool clean_rules =
false;
826 while ((opt =
getopt(argc, argv, const_cast<char*>(
"hgr"))) != -1) {
836 printf(
"usage: ninja -t clean [options] [targets]\n" 839 " -g also clean files marked as ninja generator output\n" 840 " -r interpret targets as a list of rules to clean instead\n" 848 if (clean_rules && argc == 0) {
849 Error(
"expected a rule to clean");
853 Cleaner cleaner(&state_, config_, &disk_interface_);
856 return cleaner.CleanRules(argc, argv);
858 return cleaner.CleanTargets(argc, argv);
860 return cleaner.CleanAll(generator);
864 int NinjaMain::ToolCleanDead(
const Options* options,
int argc,
char* argv[]) {
865 Cleaner cleaner(&state_, config_, &disk_interface_);
866 return cleaner.CleanDead(build_log_.
entries());
873 std::string EvaluateCommandWithRspfile(
const Edge* edge,
876 if (mode == ECM_NORMAL)
883 size_t index = command.find(rspfile);
884 if (index == 0 || index == string::npos || command[index - 1] !=
'@')
887 string rspfile_content = edge->
GetBinding(
"rspfile_content");
888 size_t newline_index = 0;
889 while ((newline_index = rspfile_content.find(
'\n', newline_index)) !=
891 rspfile_content.replace(newline_index, 1, 1,
' ');
894 command.replace(index - 1, rspfile.length() + 1, rspfile_content);
898 void printCompdb(
const char*
const directory,
const Edge*
const edge,
900 printf(
"\n {\n \"directory\": \"");
902 printf(
"\",\n \"command\": \"");
904 printf(
"\",\n \"file\": \"");
906 printf(
"\",\n \"output\": \"");
911 int NinjaMain::ToolCompilationDatabase(
const Options* options,
int argc,
922 while ((opt =
getopt(argc, argv, const_cast<char*>(
"hx"))) != -1) {
925 eval_mode = ECM_EXPAND_RSPFILE;
931 "usage: ninja -t compdb [options] [rules]\n" 934 " -x expand @rspfile style response file invocations\n" 944 char* success = NULL;
947 cwd.resize(cwd.size() + 1024);
949 success = getcwd(&cwd[0], cwd.size());
950 }
while (!success && errno == ERANGE);
952 Error(
"cannot determine working directory: %s", strerror(errno));
957 for (vector<Edge*>::iterator e = state_.
edges_.begin();
958 e != state_.
edges_.end(); ++e) {
959 if ((*e)->inputs_.empty())
965 printCompdb(&cwd[0], *e, eval_mode);
968 for (
int i = 0; i != argc; ++i) {
969 if ((*e)->rule_->name() == argv[i]) {
973 printCompdb(&cwd[0], *e, eval_mode);
984 int NinjaMain::ToolRecompact(
const Options* options,
int argc,
char* argv[]) {
985 if (!EnsureBuildDirExists())
988 if (!OpenBuildLog(
true) ||
995 int NinjaMain::ToolRestat(
const Options* options,
int argc,
char* argv[]) {
1003 while ((opt =
getopt(argc, argv, const_cast<char*>(
"h"))) != -1) {
1007 printf(
"usage: ninja -t restat [outputs]\n");
1014 if (!EnsureBuildDirExists())
1017 string log_path =
".ninja_log";
1018 if (!build_dir_.empty())
1019 log_path = build_dir_ +
"/" + log_path;
1024 Error(
"loading build log %s: %s", log_path.c_str(), err.c_str());
1025 return EXIT_FAILURE;
1029 return EXIT_SUCCESS;
1037 bool success = build_log_.
Restat(log_path, disk_interface_, argc, argv, &err);
1039 Error(
"failed recompaction: %s", err.c_str());
1040 return EXIT_FAILURE;
1045 Error(
"opening build log: %s", err.c_str());
1046 return EXIT_FAILURE;
1050 return EXIT_SUCCESS;
1053 int NinjaMain::ToolUrtle(
const Options* options,
int argc,
char** argv) {
1056 " 13 ,3;2!2;\n8 ,;<11!;\n5 `'<10!(2`'2!\n11 ,6;, `\\. `\\9 .,c13$ec,.\n6 " 1057 ",2;11!>; `. ,;!2> .e8$2\".2 \"?7$e.\n <:<8!'` 2.3,.2` ,3!' ;,(?7\";2!2'<" 1058 "; `?6$PF ,;,\n2 `'4!8;<!3'`2 3! ;,`'2`2'3!;4!`2.`!;2 3,2 .<!2'`).\n5 3`5" 1059 "'2`9 `!2 `4!><3;5! J2$b,`!>;2!:2!`,d?b`!>\n26 `'-;,(<9!> $F3 )3.:!.2 d\"" 1060 "2 ) !>\n30 7`2'<3!- \"=-='5 .2 `2-=\",!>\n25 .ze9$er2 .,cd16$bc.'\n22 .e" 1061 "14$,26$.\n21 z45$c .\n20 J50$c\n20 14$P\"`?34$b\n20 14$ dbc `2\"?22$?7$c" 1062 "\n20 ?18$c.6 4\"8?4\" c8$P\n9 .2,.8 \"20$c.3 ._14 J9$\n .2,2c9$bec,.2 `?" 1063 "21$c.3`4%,3%,3 c8$P\"\n22$c2 2\"?21$bc2,.2` .2,c7$P2\",cb\n23$b bc,.2\"2" 1064 "?14$2F2\"5?2\",J5$P\" ,zd3$\n24$ ?$3?%3 `2\"2?12$bcucd3$P3\"2 2=7$\n23$P" 1065 "\" ,3;<5!>2;,. `4\"6?2\"2 ,9;, `\"?2$\n";
1067 for (
const char* p = urtle; *p; p++) {
1068 if (
'0' <= *p && *p <=
'9') {
1069 count = count*10 + *p -
'0';
1071 for (
int i = 0; i < max(count, 1); ++i)
1081 const Tool* ChooseTool(
const string& tool_name) {
1082 static const Tool kTools[] = {
1083 {
"browse",
"browse dependency graph in a web browser",
1084 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolBrowse },
1086 {
"msvc",
"build helper for MSVC cl.exe (DEPRECATED)",
1087 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolMSVC },
1089 {
"clean",
"clean built files",
1090 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolClean },
1091 {
"commands",
"list all commands required to rebuild given targets",
1092 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCommands },
1093 {
"inputs",
"list all inputs required to rebuild given targets",
1094 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolInputs},
1095 {
"deps",
"show dependencies stored in the deps log",
1096 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolDeps },
1097 {
"missingdeps",
"check deps log dependencies on generated files",
1098 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolMissingDeps },
1099 {
"graph",
"output graphviz dot file for targets",
1100 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolGraph },
1101 {
"query",
"show inputs/outputs for a path",
1102 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolQuery },
1103 {
"targets",
"list targets by their rule or depth in the DAG",
1104 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolTargets },
1105 {
"compdb",
"dump JSON compilation database to stdout",
1106 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCompilationDatabase },
1107 {
"recompact",
"recompacts ninja-internal data structures",
1108 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolRecompact },
1109 {
"restat",
"restats all outputs in the build log",
1110 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolRestat },
1111 {
"rules",
"list all rules",
1112 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolRules },
1113 {
"cleandead",
"clean built files that are no longer produced by the manifest",
1114 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolCleanDead },
1116 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolUrtle },
1118 {
"wincodepage",
"print the Windows code page used by ninja",
1119 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolWinCodePage },
1121 { NULL, NULL, Tool::RUN_AFTER_FLAGS, NULL }
1124 if (tool_name ==
"list") {
1125 printf(
"ninja subtools:\n");
1126 for (
const Tool* tool = &kTools[0]; tool->name; ++tool) {
1128 printf(
"%11s %s\n", tool->name, tool->desc);
1133 for (
const Tool* tool = &kTools[0]; tool->name; ++tool) {
1134 if (tool->name == tool_name)
1138 vector<const char*> words;
1139 for (
const Tool* tool = &kTools[0]; tool->name; ++tool)
1140 words.push_back(tool->name);
1143 Fatal(
"unknown tool '%s', did you mean '%s'?",
1144 tool_name.c_str(), suggestion);
1146 Fatal(
"unknown tool '%s'", tool_name.c_str());
1153 bool DebugEnable(
const string& name) {
1154 if (name ==
"list") {
1155 printf(
"debugging modes:\n" 1156 " stats print operation counts/timing info\n" 1157 " explain explain what caused a command to execute\n" 1158 " keepdepfile don't delete depfiles after they're read by ninja\n" 1159 " keeprsp don't delete @response files on success\n" 1161 " nostatcache don't batch stat() calls per directory and cache them\n" 1163 "multiple modes can be enabled via -d FOO -d BAR\n");
1165 }
else if (name ==
"stats") {
1168 }
else if (name ==
"explain") {
1171 }
else if (name ==
"keepdepfile") {
1174 }
else if (name ==
"keeprsp") {
1177 }
else if (name ==
"nostatcache") {
1181 const char* suggestion =
1183 "stats",
"explain",
"keepdepfile",
"keeprsp",
1184 "nostatcache", NULL);
1186 Error(
"unknown debug setting '%s', did you mean '%s'?",
1187 name.c_str(), suggestion);
1189 Error(
"unknown debug setting '%s'", name.c_str());
1197 bool WarningEnable(
const string& name, Options* options) {
1198 if (name ==
"list") {
1199 printf(
"warning flags:\n" 1200 " phonycycle={err,warn} phony build statement references itself\n" 1203 }
else if (name ==
"dupbuild=err") {
1204 options->dupe_edges_should_err =
true;
1206 }
else if (name ==
"dupbuild=warn") {
1207 options->dupe_edges_should_err =
false;
1209 }
else if (name ==
"phonycycle=err") {
1210 options->phony_cycle_should_err =
true;
1212 }
else if (name ==
"phonycycle=warn") {
1213 options->phony_cycle_should_err =
false;
1215 }
else if (name ==
"depfilemulti=err" ||
1216 name ==
"depfilemulti=warn") {
1217 Warning(
"deprecated warning 'depfilemulti'");
1220 const char* suggestion =
1222 "phonycycle=err",
"phonycycle=warn", NULL);
1224 Error(
"unknown warning flag '%s', did you mean '%s'?",
1225 name.c_str(), suggestion);
1227 Error(
"unknown warning flag '%s'", name.c_str());
1233 bool NinjaMain::OpenBuildLog(
bool recompact_only) {
1234 string log_path =
".ninja_log";
1235 if (!build_dir_.empty())
1236 log_path = build_dir_ +
"/" + log_path;
1241 Error(
"loading build log %s: %s", log_path.c_str(), err.c_str());
1250 if (recompact_only) {
1254 bool success = build_log_.
Recompact(log_path, *
this, &err);
1256 Error(
"failed recompaction: %s", err.c_str());
1262 Error(
"opening build log: %s", err.c_str());
1272 bool NinjaMain::OpenDepsLog(
bool recompact_only) {
1273 string path =
".ninja_deps";
1274 if (!build_dir_.empty())
1275 path = build_dir_ +
"/" + path;
1280 Error(
"loading deps log %s: %s", path.c_str(), err.c_str());
1289 if (recompact_only) {
1293 bool success = deps_log_.
Recompact(path, &err);
1295 Error(
"failed recompaction: %s", err.c_str());
1301 Error(
"opening deps log: %s", err.c_str());
1309 void NinjaMain::DumpMetrics() {
1313 int count = (int)state_.
paths_.size();
1314 int buckets = (int)state_.
paths_.bucket_count();
1315 printf(
"path->node hash load %.2f (%d entries / %d buckets)\n",
1316 count / (
double) buckets, count, buckets);
1319 bool NinjaMain::EnsureBuildDirExists() {
1321 if (!build_dir_.empty() && !config_.
dry_run) {
1322 if (!disk_interface_.
MakeDirs(build_dir_ +
"/.") && errno != EEXIST) {
1323 Error(
"creating build directory %s: %s",
1324 build_dir_.c_str(), strerror(errno));
1331 int NinjaMain::RunBuild(
int argc,
char** argv,
Status* status) {
1333 vector<Node*> targets;
1334 if (!CollectTargetsFromArgs(argc, argv, &targets, &err)) {
1335 status->
Error(
"%s", err.c_str());
1341 Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_,
1342 status, start_time_millis_);
1343 for (
size_t i = 0; i < targets.size(); ++i) {
1344 if (!builder.AddTarget(targets[i], &err)) {
1346 status->
Error(
"%s", err.c_str());
1358 if (builder.AlreadyUpToDate()) {
1359 status->
Info(
"no work to do.");
1363 if (!builder.Build(&err)) {
1364 status->
Info(
"build stopped: %s.", err.c_str());
1365 if (err.find(
"interrupted by user") != string::npos) {
1381 void TerminateHandler() {
1382 CreateWin32MiniDump(NULL);
1383 Fatal(
"terminate handler called");
1388 int ExceptionFilter(
unsigned int code,
struct _EXCEPTION_POINTERS *ep) {
1389 Error(
"exception: 0x%X", code);
1391 CreateWin32MiniDump(ep);
1392 return EXCEPTION_EXECUTE_HANDLER;
1397 class DeferGuessParallelism {
1403 : config(config), needGuess(true) {}
1411 ~DeferGuessParallelism() { Refresh(); }
1416 int ReadFlags(
int* argc,
char*** argv,
1418 DeferGuessParallelism deferGuessParallelism(config);
1420 enum { OPT_VERSION = 1, OPT_QUIET = 2 };
1421 const option kLongOptions[] = {
1426 { NULL, 0, NULL, 0 }
1430 while (!options->tool &&
1431 (opt =
getopt_long(*argc, *argv,
"d:f:j:k:l:nt:vw:C:h", kLongOptions,
1435 if (!DebugEnable(
optarg))
1439 options->input_file =
optarg;
1443 int value = strtol(
optarg, &end, 10);
1444 if (*end != 0 || value < 0)
1445 Fatal(
"invalid -j parameter");
1449 config->
parallelism = value > 0 ? value : INT_MAX;
1450 deferGuessParallelism.needGuess =
false;
1455 int value = strtol(
optarg, &end, 10);
1457 Fatal(
"-k parameter not numeric; did you mean -k 0?");
1467 double value = strtod(
optarg, &end);
1469 Fatal(
"-l parameter not numeric: did you mean -l 0.0?");
1477 options->tool = ChooseTool(
optarg);
1488 if (!WarningEnable(
optarg, options))
1492 options->working_dir =
optarg;
1499 deferGuessParallelism.Refresh();
1510 NORETURN void real_main(
int argc,
char** argv) {
1514 Options options = {};
1515 options.input_file =
"build.ninja";
1516 options.dupe_edges_should_err =
true;
1518 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
1519 const char* ninja_command = argv[0];
1521 int exit_code = ReadFlags(&argc, &argv, &options, &config);
1527 if (options.working_dir) {
1534 status->
Info(
"Entering directory `%s'", options.working_dir);
1535 if (chdir(options.working_dir) < 0) {
1536 Fatal(
"chdir to '%s' - %s", options.working_dir, strerror(errno));
1540 if (options.tool && options.tool->when == Tool::RUN_AFTER_FLAGS) {
1543 NinjaMain ninja(ninja_command, config);
1544 exit((ninja.*options.tool->func)(&options, argc, argv));
1548 const int kCycleLimit = 100;
1549 for (
int cycle = 1; cycle <= kCycleLimit; ++cycle) {
1550 NinjaMain ninja(ninja_command, config);
1553 if (options.dupe_edges_should_err) {
1556 if (options.phony_cycle_should_err) {
1559 ManifestParser parser(&ninja.state_, &ninja.disk_interface_, parser_opts);
1561 if (!parser.Load(options.input_file, &err)) {
1562 status->
Error(
"%s", err.c_str());
1566 if (options.tool && options.tool->when == Tool::RUN_AFTER_LOAD)
1567 exit((ninja.*options.tool->func)(&options, argc, argv));
1569 if (!ninja.EnsureBuildDirExists())
1572 if (!ninja.OpenBuildLog() || !ninja.OpenDepsLog())
1575 if (options.tool && options.tool->when == Tool::RUN_AFTER_LOGS)
1576 exit((ninja.*options.tool->func)(&options, argc, argv));
1579 if (ninja.RebuildManifest(options.input_file, &err, status)) {
1586 }
else if (!err.empty()) {
1587 status->
Error(
"rebuilding '%s': %s", options.input_file, err.c_str());
1591 int result = ninja.RunBuild(argc, argv, status);
1593 ninja.DumpMetrics();
1597 status->
Error(
"manifest '%s' still dirty after %d tries, perhaps system time is not set",
1598 options.input_file, kCycleLimit);
1605 #if defined(_MSC_VER) 1608 std::set_terminate(TerminateHandler);
1612 real_main(argc, argv);
1614 __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
1620 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.
std::vector< Node * > validations_
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.
Node * GetFirstReverseDepsNode(Node *node)
int64_t GetTimeMillis()
Get the current time as relative to some epoch.
std::vector< Node * > outputs_
void PrintJSONString(const std::string &in)
Implementation of the Status interface that prints the status as human-readable strings to stdout...
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.
static LinePrinter printer
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.
signed long long int64_t
A 64-bit integer type.
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 invocable 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)
Abstract interface to object that tracks the status of a build: completion fraction, printing updates.
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.
void Warning(const char *msg, va_list ap)
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.
virtual void Info(const char *msg,...)=0
void AllowStatCache(bool allow)
Whether stat information can be cached. Only has an effect on Windows.
const std::vector< Edge * > & validation_out_edges() const
const std::vector< Edge * > & out_edges() const
void CanonicalizePath(string *path, uint64_t *slash_bits)
std::string Unparse() const
Options (e.g. verbosity, parallelism) passed to a build.
Global state (file status) for a single run.
void Error(const char *msg, va_list ap)
unsigned long long uint64_t
std::vector< Edge * > edges_
All the edges of the graph.
virtual std::string LookupVariable(const std::string &var)
void CollectInputs(bool shell_escape, std::vector< std::string > *out) const
A tokenized string that contains variable references.
DupeEdgeAction dupe_edge_action_
std::set< Edge *, EdgeCmp > EdgeSet
virtual void Error(const char *msg,...)=0
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.