Ninja
|
00001 // Copyright 2011 Google Inc. All Rights Reserved. 00002 // 00003 // Licensed under the Apache License, Version 2.0 (the "License"); 00004 // you may not use this file except in compliance with the License. 00005 // You may obtain a copy of the License at 00006 // 00007 // http://www.apache.org/licenses/LICENSE-2.0 00008 // 00009 // Unless required by applicable law or agreed to in writing, software 00010 // distributed under the License is distributed on an "AS IS" BASIS, 00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 // See the License for the specific language governing permissions and 00013 // limitations under the License. 00014 00015 #include <errno.h> 00016 #include <limits.h> 00017 #include <stdio.h> 00018 #include <stdlib.h> 00019 #include <string.h> 00020 00021 #ifdef _WIN32 00022 #include "getopt.h" 00023 #include <direct.h> 00024 #include <windows.h> 00025 #else 00026 #include <getopt.h> 00027 #include <unistd.h> 00028 #endif 00029 00030 #include "browse.h" 00031 #include "build.h" 00032 #include "build_log.h" 00033 #include "deps_log.h" 00034 #include "clean.h" 00035 #include "disk_interface.h" 00036 #include "explain.h" 00037 #include "graph.h" 00038 #include "graphviz.h" 00039 #include "manifest_parser.h" 00040 #include "metrics.h" 00041 #include "state.h" 00042 #include "util.h" 00043 #include "version.h" 00044 00045 #ifdef _MSC_VER 00046 // Defined in msvc_helper_main-win32.cc. 00047 int MSVCHelperMain(int argc, char** argv); 00048 00049 // Defined in minidump-win32.cc. 00050 void CreateWin32MiniDump(_EXCEPTION_POINTERS* pep); 00051 #endif 00052 00053 namespace { 00054 00055 struct Tool; 00056 00057 /// Command-line options. 00058 struct Options { 00059 /// Build file to load. 00060 const char* input_file; 00061 00062 /// Directory to change into before running. 00063 const char* working_dir; 00064 00065 /// Tool to run rather than building. 00066 const Tool* tool; 00067 }; 00068 00069 /// The Ninja main() loads up a series of data structures; various tools need 00070 /// to poke into these, so store them as fields on an object. 00071 struct NinjaMain { 00072 NinjaMain(const char* ninja_command, const BuildConfig& config) : 00073 ninja_command_(ninja_command), config_(config) {} 00074 00075 /// Command line used to run Ninja. 00076 const char* ninja_command_; 00077 00078 /// Build configuration set from flags (e.g. parallelism). 00079 const BuildConfig& config_; 00080 00081 /// Loaded state (rules, nodes). 00082 State state_; 00083 00084 /// Functions for accesssing the disk. 00085 RealDiskInterface disk_interface_; 00086 00087 /// The build directory, used for storing the build log etc. 00088 string build_dir_; 00089 00090 BuildLog build_log_; 00091 DepsLog deps_log_; 00092 00093 /// The type of functions that are the entry points to tools (subcommands). 00094 typedef int (NinjaMain::*ToolFunc)(int, char**); 00095 00096 /// Get the Node for a given command-line path, handling features like 00097 /// spell correction. 00098 Node* CollectTarget(const char* cpath, string* err); 00099 00100 /// CollectTarget for all command-line arguments, filling in \a targets. 00101 bool CollectTargetsFromArgs(int argc, char* argv[], 00102 vector<Node*>* targets, string* err); 00103 00104 // The various subcommands, run via "-t XXX". 00105 int ToolGraph(int argc, char* argv[]); 00106 int ToolQuery(int argc, char* argv[]); 00107 int ToolBrowse(int argc, char* argv[]); 00108 int ToolMSVC(int argc, char* argv[]); 00109 int ToolTargets(int argc, char* argv[]); 00110 int ToolCommands(int argc, char* argv[]); 00111 int ToolClean(int argc, char* argv[]); 00112 int ToolCompilationDatabase(int argc, char* argv[]); 00113 int ToolUrtle(int argc, char** argv); 00114 00115 /// Open the build log. 00116 /// @return false on error. 00117 bool OpenBuildLog(); 00118 00119 /// Open the deps log: load it, then open for writing. 00120 /// @return false on error. 00121 bool OpenDepsLog(); 00122 00123 /// Ensure the build directory exists, creating it if necessary. 00124 /// @return false on error. 00125 bool EnsureBuildDirExists(); 00126 00127 /// Rebuild the manifest, if necessary. 00128 /// Fills in \a err on error. 00129 /// @return true if the manifest was rebuilt. 00130 bool RebuildManifest(const char* input_file, string* err); 00131 00132 /// Build the targets listed on the command line. 00133 /// @return an exit code. 00134 int RunBuild(int argc, char** argv); 00135 00136 /// Dump the output requested by '-d stats'. 00137 void DumpMetrics(); 00138 }; 00139 00140 /// Subtools, accessible via "-t foo". 00141 struct Tool { 00142 /// Short name of the tool. 00143 const char* name; 00144 00145 /// Description (shown in "-t list"). 00146 const char* desc; 00147 00148 /// When to run the tool. 00149 enum { 00150 /// Run after parsing the command-line flags (as early as possible). 00151 RUN_AFTER_FLAGS, 00152 00153 /// Run after loading build.ninja. 00154 RUN_AFTER_LOAD, 00155 00156 /// Run after loading the build/deps logs. 00157 RUN_AFTER_LOGS, 00158 } when; 00159 00160 /// Implementation of the tool. 00161 NinjaMain::ToolFunc func; 00162 }; 00163 00164 /// Print usage information. 00165 void Usage(const BuildConfig& config) { 00166 fprintf(stderr, 00167 "usage: ninja [options] [targets...]\n" 00168 "\n" 00169 "if targets are unspecified, builds the 'default' target (see manual).\n" 00170 "\n" 00171 "options:\n" 00172 " --version print ninja version (\"%s\")\n" 00173 "\n" 00174 " -C DIR change to DIR before doing anything else\n" 00175 " -f FILE specify input build file [default=build.ninja]\n" 00176 "\n" 00177 " -j N run N jobs in parallel [default=%d, derived from CPUs available]\n" 00178 " -l N do not start new jobs if the load average is greater than N\n" 00179 #ifdef _WIN32 00180 " (not yet implemented on Windows)\n" 00181 #endif 00182 " -k N keep going until N jobs fail [default=1]\n" 00183 " -n dry run (don't run commands but act like they succeeded)\n" 00184 " -v show all command lines while building\n" 00185 "\n" 00186 " -d MODE enable debugging (use -d list to list modes)\n" 00187 " -t TOOL run a subtool (use -t list to list subtools)\n" 00188 " terminates toplevel options; further flags are passed to the tool\n", 00189 kNinjaVersion, config.parallelism); 00190 } 00191 00192 /// Choose a default value for the -j (parallelism) flag. 00193 int GuessParallelism() { 00194 switch (int processors = GetProcessorCount()) { 00195 case 0: 00196 case 1: 00197 return 2; 00198 case 2: 00199 return 3; 00200 default: 00201 return processors + 2; 00202 } 00203 } 00204 00205 /// An implementation of ManifestParser::FileReader that actually reads 00206 /// the file. 00207 struct RealFileReader : public ManifestParser::FileReader { 00208 virtual bool ReadFile(const string& path, string* content, string* err) { 00209 return ::ReadFile(path, content, err) == 0; 00210 } 00211 }; 00212 00213 /// Rebuild the build manifest, if necessary. 00214 /// Returns true if the manifest was rebuilt. 00215 bool NinjaMain::RebuildManifest(const char* input_file, string* err) { 00216 string path = input_file; 00217 if (!CanonicalizePath(&path, err)) 00218 return false; 00219 Node* node = state_.LookupNode(path); 00220 if (!node) 00221 return false; 00222 00223 Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_); 00224 if (!builder.AddTarget(node, err)) 00225 return false; 00226 00227 if (builder.AlreadyUpToDate()) 00228 return false; // Not an error, but we didn't rebuild. 00229 if (!builder.Build(err)) 00230 return false; 00231 00232 // The manifest was only rebuilt if it is now dirty (it may have been cleaned 00233 // by a restat). 00234 return node->dirty(); 00235 } 00236 00237 Node* NinjaMain::CollectTarget(const char* cpath, string* err) { 00238 string path = cpath; 00239 if (!CanonicalizePath(&path, err)) 00240 return NULL; 00241 00242 // Special syntax: "foo.cc^" means "the first output of foo.cc". 00243 bool first_dependent = false; 00244 if (!path.empty() && path[path.size() - 1] == '^') { 00245 path.resize(path.size() - 1); 00246 first_dependent = true; 00247 } 00248 00249 Node* node = state_.LookupNode(path); 00250 if (node) { 00251 if (first_dependent) { 00252 if (node->out_edges().empty()) { 00253 *err = "'" + path + "' has no out edge"; 00254 return NULL; 00255 } 00256 Edge* edge = node->out_edges()[0]; 00257 if (edge->outputs_.empty()) { 00258 edge->Dump(); 00259 Fatal("edge has no outputs"); 00260 } 00261 node = edge->outputs_[0]; 00262 } 00263 return node; 00264 } else { 00265 *err = "unknown target '" + path + "'"; 00266 00267 if (path == "clean") { 00268 *err += ", did you mean 'ninja -t clean'?"; 00269 } else if (path == "help") { 00270 *err += ", did you mean 'ninja -h'?"; 00271 } else { 00272 Node* suggestion = state_.SpellcheckNode(path); 00273 if (suggestion) { 00274 *err += ", did you mean '" + suggestion->path() + "'?"; 00275 } 00276 } 00277 return NULL; 00278 } 00279 } 00280 00281 bool NinjaMain::CollectTargetsFromArgs(int argc, char* argv[], 00282 vector<Node*>* targets, string* err) { 00283 if (argc == 0) { 00284 *targets = state_.DefaultNodes(err); 00285 return err->empty(); 00286 } 00287 00288 for (int i = 0; i < argc; ++i) { 00289 Node* node = CollectTarget(argv[i], err); 00290 if (node == NULL) 00291 return false; 00292 targets->push_back(node); 00293 } 00294 return true; 00295 } 00296 00297 int NinjaMain::ToolGraph(int argc, char* argv[]) { 00298 vector<Node*> nodes; 00299 string err; 00300 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) { 00301 Error("%s", err.c_str()); 00302 return 1; 00303 } 00304 00305 GraphViz graph; 00306 graph.Start(); 00307 for (vector<Node*>::const_iterator n = nodes.begin(); n != nodes.end(); ++n) 00308 graph.AddTarget(*n); 00309 graph.Finish(); 00310 00311 return 0; 00312 } 00313 00314 int NinjaMain::ToolQuery(int argc, char* argv[]) { 00315 if (argc == 0) { 00316 Error("expected a target to query"); 00317 return 1; 00318 } 00319 00320 for (int i = 0; i < argc; ++i) { 00321 string err; 00322 Node* node = CollectTarget(argv[i], &err); 00323 if (!node) { 00324 Error("%s", err.c_str()); 00325 return 1; 00326 } 00327 00328 printf("%s:\n", node->path().c_str()); 00329 if (Edge* edge = node->in_edge()) { 00330 printf(" input: %s\n", edge->rule_->name().c_str()); 00331 for (int in = 0; in < (int)edge->inputs_.size(); in++) { 00332 const char* label = ""; 00333 if (edge->is_implicit(in)) 00334 label = "| "; 00335 else if (edge->is_order_only(in)) 00336 label = "|| "; 00337 printf(" %s%s\n", label, edge->inputs_[in]->path().c_str()); 00338 } 00339 } 00340 printf(" outputs:\n"); 00341 for (vector<Edge*>::const_iterator edge = node->out_edges().begin(); 00342 edge != node->out_edges().end(); ++edge) { 00343 for (vector<Node*>::iterator out = (*edge)->outputs_.begin(); 00344 out != (*edge)->outputs_.end(); ++out) { 00345 printf(" %s\n", (*out)->path().c_str()); 00346 } 00347 } 00348 } 00349 return 0; 00350 } 00351 00352 #if !defined(_WIN32) && !defined(NINJA_BOOTSTRAP) 00353 int NinjaMain::ToolBrowse(int argc, char* argv[]) { 00354 if (argc < 1) { 00355 Error("expected a target to browse"); 00356 return 1; 00357 } 00358 RunBrowsePython(&state_, ninja_command_, argv[0]); 00359 // If we get here, the browse failed. 00360 return 1; 00361 } 00362 #endif // _WIN32 00363 00364 #if defined(_MSC_VER) 00365 int NinjaMain::ToolMSVC(int argc, char* argv[]) { 00366 // Reset getopt: push one argument onto the front of argv, reset optind. 00367 argc++; 00368 argv--; 00369 optind = 0; 00370 return MSVCHelperMain(argc, argv); 00371 } 00372 #endif 00373 00374 int ToolTargetsList(const vector<Node*>& nodes, int depth, int indent) { 00375 for (vector<Node*>::const_iterator n = nodes.begin(); 00376 n != nodes.end(); 00377 ++n) { 00378 for (int i = 0; i < indent; ++i) 00379 printf(" "); 00380 const char* target = (*n)->path().c_str(); 00381 if ((*n)->in_edge()) { 00382 printf("%s: %s\n", target, (*n)->in_edge()->rule_->name().c_str()); 00383 if (depth > 1 || depth <= 0) 00384 ToolTargetsList((*n)->in_edge()->inputs_, depth - 1, indent + 1); 00385 } else { 00386 printf("%s\n", target); 00387 } 00388 } 00389 return 0; 00390 } 00391 00392 int ToolTargetsSourceList(State* state) { 00393 for (vector<Edge*>::iterator e = state->edges_.begin(); 00394 e != state->edges_.end(); ++e) { 00395 for (vector<Node*>::iterator inps = (*e)->inputs_.begin(); 00396 inps != (*e)->inputs_.end(); ++inps) { 00397 if (!(*inps)->in_edge()) 00398 printf("%s\n", (*inps)->path().c_str()); 00399 } 00400 } 00401 return 0; 00402 } 00403 00404 int ToolTargetsList(State* state, const string& rule_name) { 00405 set<string> rules; 00406 00407 // Gather the outputs. 00408 for (vector<Edge*>::iterator e = state->edges_.begin(); 00409 e != state->edges_.end(); ++e) { 00410 if ((*e)->rule_->name() == rule_name) { 00411 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin(); 00412 out_node != (*e)->outputs_.end(); ++out_node) { 00413 rules.insert((*out_node)->path()); 00414 } 00415 } 00416 } 00417 00418 // Print them. 00419 for (set<string>::const_iterator i = rules.begin(); 00420 i != rules.end(); ++i) { 00421 printf("%s\n", (*i).c_str()); 00422 } 00423 00424 return 0; 00425 } 00426 00427 int ToolTargetsList(State* state) { 00428 for (vector<Edge*>::iterator e = state->edges_.begin(); 00429 e != state->edges_.end(); ++e) { 00430 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin(); 00431 out_node != (*e)->outputs_.end(); ++out_node) { 00432 printf("%s: %s\n", 00433 (*out_node)->path().c_str(), 00434 (*e)->rule_->name().c_str()); 00435 } 00436 } 00437 return 0; 00438 } 00439 00440 int NinjaMain::ToolTargets(int argc, char* argv[]) { 00441 int depth = 1; 00442 if (argc >= 1) { 00443 string mode = argv[0]; 00444 if (mode == "rule") { 00445 string rule; 00446 if (argc > 1) 00447 rule = argv[1]; 00448 if (rule.empty()) 00449 return ToolTargetsSourceList(&state_); 00450 else 00451 return ToolTargetsList(&state_, rule); 00452 } else if (mode == "depth") { 00453 if (argc > 1) 00454 depth = atoi(argv[1]); 00455 } else if (mode == "all") { 00456 return ToolTargetsList(&state_); 00457 } else { 00458 const char* suggestion = 00459 SpellcheckString(mode.c_str(), "rule", "depth", "all", NULL); 00460 if (suggestion) { 00461 Error("unknown target tool mode '%s', did you mean '%s'?", 00462 mode.c_str(), suggestion); 00463 } else { 00464 Error("unknown target tool mode '%s'", mode.c_str()); 00465 } 00466 return 1; 00467 } 00468 } 00469 00470 string err; 00471 vector<Node*> root_nodes = state_.RootNodes(&err); 00472 if (err.empty()) { 00473 return ToolTargetsList(root_nodes, depth, 0); 00474 } else { 00475 Error("%s", err.c_str()); 00476 return 1; 00477 } 00478 } 00479 00480 void PrintCommands(Edge* edge, set<Edge*>* seen) { 00481 if (!edge) 00482 return; 00483 if (!seen->insert(edge).second) 00484 return; 00485 00486 for (vector<Node*>::iterator in = edge->inputs_.begin(); 00487 in != edge->inputs_.end(); ++in) 00488 PrintCommands((*in)->in_edge(), seen); 00489 00490 if (!edge->is_phony()) 00491 puts(edge->EvaluateCommand().c_str()); 00492 } 00493 00494 int NinjaMain::ToolCommands(int argc, char* argv[]) { 00495 vector<Node*> nodes; 00496 string err; 00497 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) { 00498 Error("%s", err.c_str()); 00499 return 1; 00500 } 00501 00502 set<Edge*> seen; 00503 for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in) 00504 PrintCommands((*in)->in_edge(), &seen); 00505 00506 return 0; 00507 } 00508 00509 int NinjaMain::ToolClean(int argc, char* argv[]) { 00510 // The clean tool uses getopt, and expects argv[0] to contain the name of 00511 // the tool, i.e. "clean". 00512 argc++; 00513 argv--; 00514 00515 bool generator = false; 00516 bool clean_rules = false; 00517 00518 optind = 1; 00519 int opt; 00520 while ((opt = getopt(argc, argv, const_cast<char*>("hgr"))) != -1) { 00521 switch (opt) { 00522 case 'g': 00523 generator = true; 00524 break; 00525 case 'r': 00526 clean_rules = true; 00527 break; 00528 case 'h': 00529 default: 00530 printf("usage: ninja -t clean [options] [targets]\n" 00531 "\n" 00532 "options:\n" 00533 " -g also clean files marked as ninja generator output\n" 00534 " -r interpret targets as a list of rules to clean instead\n" 00535 ); 00536 return 1; 00537 } 00538 } 00539 argv += optind; 00540 argc -= optind; 00541 00542 if (clean_rules && argc == 0) { 00543 Error("expected a rule to clean"); 00544 return 1; 00545 } 00546 00547 Cleaner cleaner(&state_, config_); 00548 if (argc >= 1) { 00549 if (clean_rules) 00550 return cleaner.CleanRules(argc, argv); 00551 else 00552 return cleaner.CleanTargets(argc, argv); 00553 } else { 00554 return cleaner.CleanAll(generator); 00555 } 00556 } 00557 00558 void EncodeJSONString(const char *str) { 00559 while (*str) { 00560 if (*str == '"' || *str == '\\') 00561 putchar('\\'); 00562 putchar(*str); 00563 str++; 00564 } 00565 } 00566 00567 int NinjaMain::ToolCompilationDatabase(int argc, char* argv[]) { 00568 bool first = true; 00569 vector<char> cwd; 00570 00571 do { 00572 cwd.resize(cwd.size() + 1024); 00573 errno = 0; 00574 } while (!getcwd(&cwd[0], cwd.size()) && errno == ERANGE); 00575 if (errno != 0 && errno != ERANGE) { 00576 Error("cannot determine working directory: %s", strerror(errno)); 00577 return 1; 00578 } 00579 00580 putchar('['); 00581 for (vector<Edge*>::iterator e = state_.edges_.begin(); 00582 e != state_.edges_.end(); ++e) { 00583 for (int i = 0; i != argc; ++i) { 00584 if ((*e)->rule_->name() == argv[i]) { 00585 if (!first) 00586 putchar(','); 00587 00588 printf("\n {\n \"directory\": \""); 00589 EncodeJSONString(&cwd[0]); 00590 printf("\",\n \"command\": \""); 00591 EncodeJSONString((*e)->EvaluateCommand().c_str()); 00592 printf("\",\n \"file\": \""); 00593 EncodeJSONString((*e)->inputs_[0]->path().c_str()); 00594 printf("\"\n }"); 00595 00596 first = false; 00597 } 00598 } 00599 } 00600 00601 puts("\n]"); 00602 return 0; 00603 } 00604 00605 int NinjaMain::ToolUrtle(int argc, char** argv) { 00606 // RLE encoded. 00607 const char* urtle = 00608 " 13 ,3;2!2;\n8 ,;<11!;\n5 `'<10!(2`'2!\n11 ,6;, `\\. `\\9 .,c13$ec,.\n6 " 00609 ",2;11!>; `. ,;!2> .e8$2\".2 \"?7$e.\n <:<8!'` 2.3,.2` ,3!' ;,(?7\";2!2'<" 00610 "; `?6$PF ,;,\n2 `'4!8;<!3'`2 3! ;,`'2`2'3!;4!`2.`!;2 3,2 .<!2'`).\n5 3`5" 00611 "'2`9 `!2 `4!><3;5! J2$b,`!>;2!:2!`,d?b`!>\n26 `'-;,(<9!> $F3 )3.:!.2 d\"" 00612 "2 ) !>\n30 7`2'<3!- \"=-='5 .2 `2-=\",!>\n25 .ze9$er2 .,cd16$bc.'\n22 .e" 00613 "14$,26$.\n21 z45$c .\n20 J50$c\n20 14$P\"`?34$b\n20 14$ dbc `2\"?22$?7$c" 00614 "\n20 ?18$c.6 4\"8?4\" c8$P\n9 .2,.8 \"20$c.3 ._14 J9$\n .2,2c9$bec,.2 `?" 00615 "21$c.3`4%,3%,3 c8$P\"\n22$c2 2\"?21$bc2,.2` .2,c7$P2\",cb\n23$b bc,.2\"2" 00616 "?14$2F2\"5?2\",J5$P\" ,zd3$\n24$ ?$3?%3 `2\"2?12$bcucd3$P3\"2 2=7$\n23$P" 00617 "\" ,3;<5!>2;,. `4\"6?2\"2 ,9;, `\"?2$\n"; 00618 int count = 0; 00619 for (const char* p = urtle; *p; p++) { 00620 if ('0' <= *p && *p <= '9') { 00621 count = count*10 + *p - '0'; 00622 } else { 00623 for (int i = 0; i < std::max(count, 1); ++i) 00624 printf("%c", *p); 00625 count = 0; 00626 } 00627 } 00628 return 0; 00629 } 00630 00631 /// Find the function to execute for \a tool_name and return it via \a func. 00632 /// Returns a Tool, or NULL if Ninja should exit. 00633 const Tool* ChooseTool(const string& tool_name) { 00634 static const Tool kTools[] = { 00635 #if !defined(_WIN32) && !defined(NINJA_BOOTSTRAP) 00636 { "browse", "browse dependency graph in a web browser", 00637 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolBrowse }, 00638 #endif 00639 #if defined(_MSC_VER) 00640 { "msvc", "build helper for MSVC cl.exe (EXPERIMENTAL)", 00641 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolMSVC }, 00642 #endif 00643 { "clean", "clean built files", 00644 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolClean }, 00645 { "commands", "list all commands required to rebuild given targets", 00646 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCommands }, 00647 { "graph", "output graphviz dot file for targets", 00648 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolGraph }, 00649 { "query", "show inputs/outputs for a path", 00650 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolQuery }, 00651 { "targets", "list targets by their rule or depth in the DAG", 00652 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolTargets }, 00653 { "compdb", "dump JSON compilation database to stdout", 00654 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCompilationDatabase }, 00655 { "urtle", NULL, 00656 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolUrtle }, 00657 { NULL, NULL, Tool::RUN_AFTER_FLAGS, NULL } 00658 }; 00659 00660 if (tool_name == "list") { 00661 printf("ninja subtools:\n"); 00662 for (const Tool* tool = &kTools[0]; tool->name; ++tool) { 00663 if (tool->desc) 00664 printf("%10s %s\n", tool->name, tool->desc); 00665 } 00666 return NULL; 00667 } 00668 00669 for (const Tool* tool = &kTools[0]; tool->name; ++tool) { 00670 if (tool->name == tool_name) 00671 return tool; 00672 } 00673 00674 vector<const char*> words; 00675 for (const Tool* tool = &kTools[0]; tool->name; ++tool) 00676 words.push_back(tool->name); 00677 const char* suggestion = SpellcheckStringV(tool_name, words); 00678 if (suggestion) { 00679 Fatal("unknown tool '%s', did you mean '%s'?", 00680 tool_name.c_str(), suggestion); 00681 } else { 00682 Fatal("unknown tool '%s'", tool_name.c_str()); 00683 } 00684 return NULL; // Not reached. 00685 } 00686 00687 /// Enable a debugging mode. Returns false if Ninja should exit instead 00688 /// of continuing. 00689 bool DebugEnable(const string& name) { 00690 if (name == "list") { 00691 printf("debugging modes:\n" 00692 " stats print operation counts/timing info\n" 00693 " explain explain what caused a command to execute\n" 00694 "multiple modes can be enabled via -d FOO -d BAR\n"); 00695 return false; 00696 } else if (name == "stats") { 00697 g_metrics = new Metrics; 00698 return true; 00699 } else if (name == "explain") { 00700 g_explaining = true; 00701 return true; 00702 } else { 00703 const char* suggestion = 00704 SpellcheckString(name.c_str(), "stats", "explain", NULL); 00705 if (suggestion) { 00706 Error("unknown debug setting '%s', did you mean '%s'?", 00707 name.c_str(), suggestion); 00708 } else { 00709 Error("unknown debug setting '%s'", name.c_str()); 00710 } 00711 return false; 00712 } 00713 } 00714 00715 bool NinjaMain::OpenBuildLog() { 00716 string log_path = ".ninja_log"; 00717 if (!build_dir_.empty()) 00718 log_path = build_dir_ + "/" + log_path; 00719 00720 string err; 00721 if (!build_log_.Load(log_path, &err)) { 00722 Error("loading build log %s: %s", log_path.c_str(), err.c_str()); 00723 return false; 00724 } 00725 if (!err.empty()) { 00726 // Hack: Load() can return a warning via err by returning true. 00727 Warning("%s", err.c_str()); 00728 err.clear(); 00729 } 00730 00731 if (!config_.dry_run) { 00732 if (!build_log_.OpenForWrite(log_path, &err)) { 00733 Error("opening build log: %s", err.c_str()); 00734 return false; 00735 } 00736 } 00737 00738 return true; 00739 } 00740 00741 /// Open the deps log: load it, then open for writing. 00742 /// @return false on error. 00743 bool NinjaMain::OpenDepsLog() { 00744 string path = ".ninja_deps"; 00745 if (!build_dir_.empty()) 00746 path = build_dir_ + "/" + path; 00747 00748 string err; 00749 if (!deps_log_.Load(path, &state_, &err)) { 00750 Error("loading deps log %s: %s", path.c_str(), err.c_str()); 00751 return false; 00752 } 00753 if (!err.empty()) { 00754 // Hack: Load() can return a warning via err by returning true. 00755 Warning("%s", err.c_str()); 00756 err.clear(); 00757 } 00758 00759 if (!config_.dry_run) { 00760 if (!deps_log_.OpenForWrite(path, &err)) { 00761 Error("opening deps log: %s", err.c_str()); 00762 return false; 00763 } 00764 } 00765 00766 return true; 00767 } 00768 00769 void NinjaMain::DumpMetrics() { 00770 g_metrics->Report(); 00771 00772 printf("\n"); 00773 int count = (int)state_.paths_.size(); 00774 int buckets = (int)state_.paths_.bucket_count(); 00775 printf("path->node hash load %.2f (%d entries / %d buckets)\n", 00776 count / (double) buckets, count, buckets); 00777 } 00778 00779 bool NinjaMain::EnsureBuildDirExists() { 00780 build_dir_ = state_.bindings_.LookupVariable("builddir"); 00781 if (!build_dir_.empty() && !config_.dry_run) { 00782 if (!disk_interface_.MakeDirs(build_dir_ + "/.") && errno != EEXIST) { 00783 Error("creating build directory %s: %s", 00784 build_dir_.c_str(), strerror(errno)); 00785 return false; 00786 } 00787 } 00788 return true; 00789 } 00790 00791 int NinjaMain::RunBuild(int argc, char** argv) { 00792 string err; 00793 vector<Node*> targets; 00794 if (!CollectTargetsFromArgs(argc, argv, &targets, &err)) { 00795 Error("%s", err.c_str()); 00796 return 1; 00797 } 00798 00799 Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_); 00800 for (size_t i = 0; i < targets.size(); ++i) { 00801 if (!builder.AddTarget(targets[i], &err)) { 00802 if (!err.empty()) { 00803 Error("%s", err.c_str()); 00804 return 1; 00805 } else { 00806 // Added a target that is already up-to-date; not really 00807 // an error. 00808 } 00809 } 00810 } 00811 00812 if (builder.AlreadyUpToDate()) { 00813 printf("ninja: no work to do.\n"); 00814 return 0; 00815 } 00816 00817 if (!builder.Build(&err)) { 00818 printf("ninja: build stopped: %s.\n", err.c_str()); 00819 if (err.find("interrupted by user") != string::npos) { 00820 return 2; 00821 } 00822 return 1; 00823 } 00824 00825 return 0; 00826 } 00827 00828 #ifdef _MSC_VER 00829 00830 /// This handler processes fatal crashes that you can't catch 00831 /// Test example: C++ exception in a stack-unwind-block 00832 /// Real-world example: ninja launched a compiler to process a tricky 00833 /// C++ input file. The compiler got itself into a state where it 00834 /// generated 3 GB of output and caused ninja to crash. 00835 void TerminateHandler() { 00836 CreateWin32MiniDump(NULL); 00837 Fatal("terminate handler called"); 00838 } 00839 00840 /// On Windows, we want to prevent error dialogs in case of exceptions. 00841 /// This function handles the exception, and writes a minidump. 00842 int ExceptionFilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) { 00843 Error("exception: 0x%X", code); // e.g. EXCEPTION_ACCESS_VIOLATION 00844 fflush(stderr); 00845 CreateWin32MiniDump(ep); 00846 return EXCEPTION_EXECUTE_HANDLER; 00847 } 00848 00849 #endif // _MSC_VER 00850 00851 /// Parse argv for command-line options. 00852 /// Returns an exit code, or -1 if Ninja should continue. 00853 int ReadFlags(int* argc, char*** argv, 00854 Options* options, BuildConfig* config) { 00855 config->parallelism = GuessParallelism(); 00856 00857 enum { OPT_VERSION = 1 }; 00858 const option kLongOptions[] = { 00859 { "help", no_argument, NULL, 'h' }, 00860 { "version", no_argument, NULL, OPT_VERSION }, 00861 { NULL, 0, NULL, 0 } 00862 }; 00863 00864 int opt; 00865 while (!options->tool && 00866 (opt = getopt_long(*argc, *argv, "d:f:j:k:l:nt:vC:h", kLongOptions, 00867 NULL)) != -1) { 00868 switch (opt) { 00869 case 'd': 00870 if (!DebugEnable(optarg)) 00871 return 1; 00872 break; 00873 case 'f': 00874 options->input_file = optarg; 00875 break; 00876 case 'j': { 00877 char* end; 00878 int value = strtol(optarg, &end, 10); 00879 if (*end != 0 || value <= 0) 00880 Fatal("invalid -j parameter"); 00881 config->parallelism = value; 00882 break; 00883 } 00884 case 'k': { 00885 char* end; 00886 int value = strtol(optarg, &end, 10); 00887 if (*end != 0) 00888 Fatal("-k parameter not numeric; did you mean -k 0?"); 00889 00890 // We want to go until N jobs fail, which means we should allow 00891 // N failures and then stop. For N <= 0, INT_MAX is close enough 00892 // to infinite for most sane builds. 00893 config->failures_allowed = value > 0 ? value : INT_MAX; 00894 break; 00895 } 00896 case 'l': { 00897 char* end; 00898 double value = strtod(optarg, &end); 00899 if (end == optarg) 00900 Fatal("-l parameter not numeric: did you mean -l 0.0?"); 00901 config->max_load_average = value; 00902 break; 00903 } 00904 case 'n': 00905 config->dry_run = true; 00906 break; 00907 case 't': 00908 options->tool = ChooseTool(optarg); 00909 if (!options->tool) 00910 return 0; 00911 break; 00912 case 'v': 00913 config->verbosity = BuildConfig::VERBOSE; 00914 break; 00915 case 'C': 00916 options->working_dir = optarg; 00917 break; 00918 case OPT_VERSION: 00919 printf("%s\n", kNinjaVersion); 00920 return 0; 00921 case 'h': 00922 default: 00923 Usage(*config); 00924 return 1; 00925 } 00926 } 00927 *argv += optind; 00928 *argc -= optind; 00929 00930 return -1; 00931 } 00932 00933 int real_main(int argc, char** argv) { 00934 BuildConfig config; 00935 Options options = {}; 00936 options.input_file = "build.ninja"; 00937 00938 setvbuf(stdout, NULL, _IOLBF, BUFSIZ); 00939 00940 int exit_code = ReadFlags(&argc, &argv, &options, &config); 00941 if (exit_code >= 0) 00942 return exit_code; 00943 00944 if (options.tool && options.tool->when == Tool::RUN_AFTER_FLAGS) { 00945 // None of the RUN_AFTER_FLAGS actually use a NinjaMain, but it's needed 00946 // by other tools. 00947 NinjaMain ninja(argv[0], config); 00948 return (ninja.*options.tool->func)(argc, argv); 00949 } 00950 00951 if (options.working_dir) { 00952 // The formatting of this string, complete with funny quotes, is 00953 // so Emacs can properly identify that the cwd has changed for 00954 // subsequent commands. 00955 // Don't print this if a tool is being used, so that tool output 00956 // can be piped into a file without this string showing up. 00957 if (!options.tool) 00958 printf("ninja: Entering directory `%s'\n", options.working_dir); 00959 if (chdir(options.working_dir) < 0) { 00960 Fatal("chdir to '%s' - %s", options.working_dir, strerror(errno)); 00961 } 00962 } 00963 00964 // The build can take up to 2 passes: one to rebuild the manifest, then 00965 // another to build the desired target. 00966 for (int cycle = 0; cycle < 2; ++cycle) { 00967 NinjaMain ninja(argv[0], config); 00968 00969 RealFileReader file_reader; 00970 ManifestParser parser(&ninja.state_, &file_reader); 00971 string err; 00972 if (!parser.Load(options.input_file, &err)) { 00973 Error("%s", err.c_str()); 00974 return 1; 00975 } 00976 00977 if (options.tool && options.tool->when == Tool::RUN_AFTER_LOAD) 00978 return (ninja.*options.tool->func)(argc, argv); 00979 00980 if (!ninja.EnsureBuildDirExists()) 00981 return 1; 00982 00983 if (!ninja.OpenBuildLog() || !ninja.OpenDepsLog()) 00984 return 1; 00985 00986 if (options.tool && options.tool->when == Tool::RUN_AFTER_LOGS) 00987 return (ninja.*options.tool->func)(argc, argv); 00988 00989 // The first time through, attempt to rebuild the manifest before 00990 // building anything else. 00991 if (cycle == 0) { 00992 if (ninja.RebuildManifest(options.input_file, &err)) { 00993 // Start the build over with the new manifest. 00994 continue; 00995 } else if (!err.empty()) { 00996 Error("rebuilding '%s': %s", options.input_file, err.c_str()); 00997 return 1; 00998 } 00999 } 01000 01001 int result = ninja.RunBuild(argc, argv); 01002 if (g_metrics) 01003 ninja.DumpMetrics(); 01004 return result; 01005 } 01006 01007 return 1; // Shouldn't be reached. 01008 } 01009 01010 } // anonymous namespace 01011 01012 int main(int argc, char** argv) { 01013 #if !defined(NINJA_BOOTSTRAP) && defined(_MSC_VER) 01014 // Set a handler to catch crashes not caught by the __try..__except 01015 // block (e.g. an exception in a stack-unwind-block). 01016 set_terminate(TerminateHandler); 01017 __try { 01018 // Running inside __try ... __except suppresses any Windows error 01019 // dialogs for errors such as bad_alloc. 01020 return real_main(argc, argv); 01021 } 01022 __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) { 01023 // Common error situations return exitCode=1. 2 was chosen to 01024 // indicate a more serious problem. 01025 return 2; 01026 } 01027 #else 01028 return real_main(argc, argv); 01029 #endif 01030 }