diff options
Diffstat (limited to 'src/ninja.cc')
-rw-r--r-- | src/ninja.cc | 61 |
1 files changed, 50 insertions, 11 deletions
diff --git a/src/ninja.cc b/src/ninja.cc index 25eafe8..54de7b9 100644 --- a/src/ninja.cc +++ b/src/ninja.cc @@ -233,7 +233,7 @@ int GuessParallelism() { /// Returns true if the manifest was rebuilt. bool NinjaMain::RebuildManifest(const char* input_file, string* err) { string path = input_file; - unsigned int slash_bits; // Unused because this path is only used for lookup. + uint64_t slash_bits; // Unused because this path is only used for lookup. if (!CanonicalizePath(&path, &slash_bits, err)) return false; Node* node = state_.LookupNode(path); @@ -247,15 +247,24 @@ bool NinjaMain::RebuildManifest(const char* input_file, string* err) { if (builder.AlreadyUpToDate()) return false; // Not an error, but we didn't rebuild. - // Even if the manifest was cleaned by a restat rule, claim that it was - // rebuilt. Not doing so can lead to crashes, see - // https://github.com/ninja-build/ninja/issues/874 - return builder.Build(err); + if (!builder.Build(err)) + return false; + + // The manifest was only rebuilt if it is now dirty (it may have been cleaned + // by a restat). + if (!node->dirty()) { + // Reset the state to prevent problems like + // https://github.com/ninja-build/ninja/issues/874 + state_.Reset(); + return false; + } + + return true; } Node* NinjaMain::CollectTarget(const char* cpath, string* err) { string path = cpath; - unsigned int slash_bits; + uint64_t slash_bits; if (!CanonicalizePath(&path, &slash_bits, err)) return NULL; @@ -533,21 +542,51 @@ int NinjaMain::ToolTargets(const Options* options, int argc, char* argv[]) { } } -void PrintCommands(Edge* edge, set<Edge*>* seen) { +enum PrintCommandMode { PCM_Single, PCM_All }; +void PrintCommands(Edge* edge, set<Edge*>* seen, PrintCommandMode mode) { if (!edge) return; if (!seen->insert(edge).second) return; - for (vector<Node*>::iterator in = edge->inputs_.begin(); - in != edge->inputs_.end(); ++in) - PrintCommands((*in)->in_edge(), seen); + if (mode == PCM_All) { + for (vector<Node*>::iterator in = edge->inputs_.begin(); + in != edge->inputs_.end(); ++in) + PrintCommands((*in)->in_edge(), seen, mode); + } if (!edge->is_phony()) puts(edge->EvaluateCommand().c_str()); } int NinjaMain::ToolCommands(const Options* options, int argc, char* argv[]) { + // The clean tool uses getopt, and expects argv[0] to contain the name of + // the tool, i.e. "commands". + ++argc; + --argv; + + PrintCommandMode mode = PCM_All; + + optind = 1; + int opt; + while ((opt = getopt(argc, argv, const_cast<char*>("hs"))) != -1) { + switch (opt) { + case 's': + mode = PCM_Single; + break; + case 'h': + default: + printf("usage: ninja -t commands [options] [targets]\n" +"\n" +"options:\n" +" -s only print the final command to build [target], not the whole chain\n" + ); + return 1; + } + } + argv += optind; + argc -= optind; + vector<Node*> nodes; string err; if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) { @@ -557,7 +596,7 @@ int NinjaMain::ToolCommands(const Options* options, int argc, char* argv[]) { set<Edge*> seen; for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in) - PrintCommands((*in)->in_edge(), &seen); + PrintCommands((*in)->in_edge(), &seen, mode); return 0; } |