From 85740c2ddbb2aa0d523c997187442385a191fb64 Mon Sep 17 00:00:00 2001
From: Peter Collingbourne <peter@pcc.me.uk>
Date: Sat, 27 Aug 2011 02:25:57 +0100
Subject: Support for rebuilding and reloading manifest files

This introduces support for rebuilding the top-level manifest file
using a provided build statement, and reloading it before building
the user-requested targets.
---
 doc/manual.asciidoc |  4 ++++
 src/build_log.h     |  1 +
 src/ninja.cc        | 29 +++++++++++++++++++++++++++++
 3 files changed, 34 insertions(+)

diff --git a/doc/manual.asciidoc b/doc/manual.asciidoc
index 112aac5..8ab2195 100644
--- a/doc/manual.asciidoc
+++ b/doc/manual.asciidoc
@@ -253,6 +253,10 @@ statement to the rule (for example, if the rule needs "the file
 extension of the first input"), pass that through as an extra
 variable, like how `cflags` is passed above.
 
+If the top-level Ninja file is specified as an output of any build
+statement and it is out of date, Ninja will rebuild and reload it
+before building the targets requested by the user.
+
 
 The `phony` rule
 ~~~~~~~~~~~~~~~~
diff --git a/src/build_log.h b/src/build_log.h
index 81a745f..f45cbde 100644
--- a/src/build_log.h
+++ b/src/build_log.h
@@ -32,6 +32,7 @@ struct Edge;
 ///    from it
 struct BuildLog {
   BuildLog();
+  ~BuildLog() { Close(); }
 
   void SetConfig(BuildConfig* config) { config_ = config; }
   bool OpenForWrite(const string& path, string* err);
diff --git a/src/ninja.cc b/src/ninja.cc
index 8f972f3..cdaab3a 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -109,6 +109,21 @@ struct RealFileReader : public ManifestParser::FileReader {
   }
 };
 
+bool RebuildManifest(State* state, const BuildConfig& config,
+                     const char* input_file, string* err) {
+  string path = input_file;
+  CanonicalizePath(&path);
+  Node* node = state->LookupNode(path);
+  if (!node)
+    return false;
+
+  Builder manifest_builder(state, config);
+  if (!manifest_builder.AddTarget(node, err))
+    return false;
+
+  return manifest_builder.Build(err);
+}
+
 bool CollectTargetsFromArgs(State* state, int argc, char* argv[],
                             vector<Node*>* targets, string* err) {
   if (argc == 0) {
@@ -398,6 +413,9 @@ int main(int argc, char** argv) {
     }
   }
 
+  bool rebuilt_manifest = false;
+
+reload:
   State state;
   RealFileReader file_reader;
   ManifestParser parser(&state, &file_reader);
@@ -450,6 +468,17 @@ int main(int argc, char** argv) {
     return 1;
   }
 
+  if (!rebuilt_manifest) { // Don't get caught in an infinite loop by a rebuild
+                           // target that is never up to date.
+    if (RebuildManifest(&state, config, input_file, &err)) {
+      rebuilt_manifest = true;
+      goto reload;
+    } else if (!err.empty()) {
+      Error("rebuilding '%s': %s", input_file, err.c_str());
+      return 1;
+    }
+  }
+
   vector<Node*> targets;
   if (!CollectTargetsFromArgs(&state, argc, argv, &targets, &err)) {
     Error("%s", err.c_str());
-- 
cgit v0.12

