Merge "Add a debug tool to show all (recursive) inputs to a given target."
diff --git a/doc/manual.asciidoc b/doc/manual.asciidoc
index c2b00db..7d36701 100644
--- a/doc/manual.asciidoc
+++ b/doc/manual.asciidoc
@@ -830,11 +830,11 @@
 `phony_output`, so that it's not possible to accidentally cause everything to
 rebuild on every run.
 +
-When `-w usesphonyoutputs=yes` is set on the ninja command line, it becomes an
+When `-o usesphonyoutputs=yes` is set on the ninja command line, it becomes an
 error for a `phony` rule to cause rebuilds, so that users can be found and
 migrated.
 +
-Properly using `phony_output` and turning on `-w usesphonyoutputs=yes` allows
+Properly using `phony_output` and turning on `-o usesphonyoutputs=yes` allows
 the `-w outputdir={err,warn}` (consider output files that are directories as
 errors/warnings), `-w missingoutfile={err,warn}` (error/warn when an output file
 does not exist after a successful rule execution), and `-w oldoutput={err,warn}`
diff --git a/src/build.cc b/src/build.cc
index 5a7221d..19121ee 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -535,12 +535,22 @@
   status_->BuildEdgeStarted(edge, start_time_millis);
 
   if (!edge->IsPhonyOutput()) {
-    // Create directories necessary for outputs.
-    // XXX: this will block; do we care?
     for (vector<Node*>::iterator o = edge->outputs_.begin();
          o != edge->outputs_.end(); ++o) {
+      // Create directories necessary for outputs.
+      // XXX: this will block; do we care?
       if (!disk_interface_->MakeDirs((*o)->path()))
         return false;
+
+      if (!(*o)->exists())
+        continue;
+
+      // Remove existing outputs for non-restat rules.
+      // XXX: this will block; do we care?
+      if (config_.pre_remove_output_files && !edge->IsRestat() && !config_.dry_run) {
+        if (disk_interface_->RemoveFile((*o)->path()) < 0)
+          return false;
+      }
     }
   }
 
@@ -603,13 +613,16 @@
     vector<Node*> nodes_cleaned;
 
     TimeStamp newest_input = 0;
+    Node* newest_input_node = nullptr;
     for (vector<Node*>::iterator i = edge->inputs_.begin();
          i != edge->inputs_.end() - edge->order_only_deps_; ++i) {
       TimeStamp input_mtime = (*i)->mtime();
       if (input_mtime == -1)
         return false;
-      if (input_mtime > newest_input)
+      if (input_mtime > newest_input) {
         newest_input = input_mtime;
+        newest_input_node = (*i);
+      }
     }
 
     for (vector<Node*>::iterator o = edge->outputs_.begin();
@@ -631,8 +644,10 @@
         } else if (!restat && new_mtime < newest_input) {
           if (!result->output.empty())
             result->output.append("\n");
-          result->output.append("ninja: Missing `restat`? An output file is older than the most recent input: ");
+          result->output.append("ninja: Missing `restat`? An output file is older than the most recent input:\n output: ");
           result->output.append((*o)->path());
+          result->output.append("\n  input: ");
+          result->output.append(newest_input_node->path());
           if (config_.old_output_should_err) {
             result->status = ExitFailure;
           }
diff --git a/src/build.h b/src/build.h
index fa11442..d5d7bc9 100644
--- a/src/build.h
+++ b/src/build.h
@@ -147,7 +147,8 @@
                   uses_phony_outputs(false),
                   output_directory_should_err(false),
                   missing_output_file_should_err(false),
-                  old_output_should_err(false) {}
+                  old_output_should_err(false),
+                  pre_remove_output_files(false) {}
 
   enum Verbosity {
     NORMAL,
@@ -184,6 +185,9 @@
   /// Whether an output with an older timestamp than the inputs should
   /// warn or print an error.
   bool old_output_should_err;
+
+  /// Whether to remove outputs before executing rule commands
+  bool pre_remove_output_files;
 };
 
 /// Builder wraps the build process: starting commands, updating status.
diff --git a/src/build_test.cc b/src/build_test.cc
index 2400f18..7571e3f 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -920,21 +920,15 @@
 "rule cc\n  command = cc $in\n  depfile = $out.d\n"
 "build foo.o: cc foo.c\n"));
 
-  BuildConfig config(config_);
-  config.uses_phony_outputs = true;
-  Builder builder(&state_, config, nullptr, nullptr, &fs_, &status_, 0);
-  builder.command_runner_.reset(&command_runner_);
-  command_runner_.commands_ran_.clear();
+  config_.uses_phony_outputs = true;
 
   fs_.Create("foo.c", "");
   GetNode("bar.h")->MarkDirty();  // Mark bar.h as missing.
   fs_.Create("foo.o.d", "foo.o: blah.h bar.h\n");
-  EXPECT_TRUE(builder.AddTarget("foo.o", &err));
+  EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
   ASSERT_EQ("", err);
 
   ASSERT_TRUE(GetNode("bar.h")->in_edge()->phony_from_depfile_);
-
-  builder.command_runner_.release();
 }
 
 TEST_F(BuildTest, DepFileParseError) {
@@ -2400,18 +2394,13 @@
 
   config_.uses_phony_outputs = true;
 
-  Builder builder(&state_, config_, NULL, NULL, &fs_, &status_, 0);
-  builder.command_runner_.reset(&command_runner_);
-
   string err;
-  EXPECT_TRUE(builder.AddTarget("outdir", &err));
+  EXPECT_TRUE(builder_.AddTarget("outdir", &err));
   EXPECT_EQ("", err);
-  EXPECT_TRUE(builder.Build(&err));
+  EXPECT_TRUE(builder_.Build(&err));
   EXPECT_EQ("", err);
 
   EXPECT_EQ("ninja: outputs should be files, not directories: outdir", status_.last_output_);
-
-  builder.command_runner_.release();
 }
 
 TEST_F(BuildTest, OutputDirectoryError) {
@@ -2423,18 +2412,13 @@
   config_.uses_phony_outputs = true;
   config_.output_directory_should_err = true;
 
-  Builder builder(&state_, config_, NULL, NULL, &fs_, &status_, 0);
-  builder.command_runner_.reset(&command_runner_);
-
   string err;
-  EXPECT_TRUE(builder.AddTarget("outdir", &err));
+  EXPECT_TRUE(builder_.AddTarget("outdir", &err));
   EXPECT_EQ("", err);
-  EXPECT_FALSE(builder.Build(&err));
+  EXPECT_FALSE(builder_.Build(&err));
   EXPECT_EQ("subcommand failed", err);
 
   EXPECT_EQ("ninja: outputs should be files, not directories: outdir", status_.last_output_);
-
-  builder.command_runner_.release();
 }
 
 TEST_F(BuildTest, OutputFileMissingIgnore) {
@@ -2458,18 +2442,13 @@
 
   config_.uses_phony_outputs = true;
 
-  Builder builder(&state_, config_, NULL, NULL, &fs_, &status_, 0);
-  builder.command_runner_.reset(&command_runner_);
-
   string err;
-  EXPECT_TRUE(builder.AddTarget("outfile", &err));
+  EXPECT_TRUE(builder_.AddTarget("outfile", &err));
   EXPECT_EQ("", err);
-  EXPECT_TRUE(builder.Build(&err));
+  EXPECT_TRUE(builder_.Build(&err));
   EXPECT_EQ("", err);
 
   EXPECT_EQ("ninja: output file missing after successful execution: outfile", status_.last_output_);
-
-  builder.command_runner_.release();
 }
 
 TEST_F(BuildTest, OutputFileMissingError) {
@@ -2480,18 +2459,13 @@
   config_.uses_phony_outputs = true;
   config_.missing_output_file_should_err = true;
 
-  Builder builder(&state_, config_, NULL, NULL, &fs_, &status_, 0);
-  builder.command_runner_.reset(&command_runner_);
-
   string err;
-  EXPECT_TRUE(builder.AddTarget("outfile", &err));
+  EXPECT_TRUE(builder_.AddTarget("outfile", &err));
   EXPECT_EQ("", err);
-  EXPECT_FALSE(builder.Build(&err));
+  EXPECT_FALSE(builder_.Build(&err));
   EXPECT_EQ("subcommand failed", err);
 
   EXPECT_EQ("ninja: output file missing after successful execution: outfile", status_.last_output_);
-
-  builder.command_runner_.release();
 }
 
 TEST_F(BuildTest, OutputFileNotNeeded) {
@@ -2504,16 +2478,11 @@
   config_.uses_phony_outputs = true;
   config_.missing_output_file_should_err = true;
 
-  Builder builder(&state_, config_, NULL, NULL, &fs_, &status_, 0);
-  builder.command_runner_.reset(&command_runner_);
-
   string err;
-  EXPECT_TRUE(builder.AddTarget("outphony", &err));
+  EXPECT_TRUE(builder_.AddTarget("outphony", &err));
   EXPECT_EQ("", err);
-  EXPECT_TRUE(builder.Build(&err));
+  EXPECT_TRUE(builder_.Build(&err));
   EXPECT_EQ("", err);
-
-  builder.command_runner_.release();
 }
 
 TEST_F(BuildWithLogTest, OldOutputFileIgnored) {
@@ -2550,17 +2519,14 @@
 
   config_.uses_phony_outputs = true;
 
-  Builder builder(&state_, config_, &build_log_, NULL, &fs_, &status_, 0);
-  builder.command_runner_.reset(&command_runner_);
-
   fs_.Create("in", "");
   fs_.Tick();
   fs_.Create("out", "");
 
   string err;
-  EXPECT_TRUE(builder.AddTarget("out", &err));
+  EXPECT_TRUE(builder_.AddTarget("out", &err));
   EXPECT_EQ("", err);
-  EXPECT_TRUE(builder.Build(&err));
+  EXPECT_TRUE(builder_.Build(&err));
   EXPECT_EQ("", err);
 
   fs_.Tick();
@@ -2568,14 +2534,12 @@
 
   command_runner_.commands_ran_.clear();
   state_.Reset();
-  EXPECT_TRUE(builder.AddTarget("out", &err));
+  EXPECT_TRUE(builder_.AddTarget("out", &err));
   EXPECT_EQ("", err);
-  EXPECT_TRUE(builder.Build(&err));
+  EXPECT_TRUE(builder_.Build(&err));
   EXPECT_EQ("", err);
 
-  EXPECT_EQ("ninja: Missing `restat`? An output file is older than the most recent input: out", status_.last_output_);
-
-  builder.command_runner_.release();
+  EXPECT_EQ("ninja: Missing `restat`? An output file is older than the most recent input:\n output: out\n  input: in", status_.last_output_);
 }
 
 TEST_F(BuildWithLogTest, OldOutputFileError) {
@@ -2586,17 +2550,14 @@
   config_.uses_phony_outputs = true;
   config_.old_output_should_err = true;
 
-  Builder builder(&state_, config_, &build_log_, NULL, &fs_, &status_, 0);
-  builder.command_runner_.reset(&command_runner_);
-
   fs_.Create("in", "");
   fs_.Tick();
   fs_.Create("out", "");
 
   string err;
-  EXPECT_TRUE(builder.AddTarget("out", &err));
+  EXPECT_TRUE(builder_.AddTarget("out", &err));
   EXPECT_EQ("", err);
-  EXPECT_TRUE(builder.Build(&err));
+  EXPECT_TRUE(builder_.Build(&err));
   EXPECT_EQ("", err);
 
   fs_.Tick();
@@ -2604,14 +2565,12 @@
 
   command_runner_.commands_ran_.clear();
   state_.Reset();
-  EXPECT_TRUE(builder.AddTarget("out", &err));
+  EXPECT_TRUE(builder_.AddTarget("out", &err));
   EXPECT_EQ("", err);
-  EXPECT_FALSE(builder.Build(&err));
+  EXPECT_FALSE(builder_.Build(&err));
   EXPECT_EQ("subcommand failed", err);
 
-  EXPECT_EQ("ninja: Missing `restat`? An output file is older than the most recent input: out", status_.last_output_);
-
-  builder.command_runner_.release();
+  EXPECT_EQ("ninja: Missing `restat`? An output file is older than the most recent input:\n output: out\n  input: in", status_.last_output_);
 }
 
 TEST_F(BuildWithLogTest, OutputFileUpdated) {
@@ -2622,17 +2581,14 @@
   config_.uses_phony_outputs = true;
   config_.old_output_should_err = true;
 
-  Builder builder(&state_, config_, &build_log_, NULL, &fs_, &status_, 0);
-  builder.command_runner_.reset(&command_runner_);
-
   fs_.Create("in", "");
   fs_.Tick();
   fs_.Create("out", "");
 
   string err;
-  EXPECT_TRUE(builder.AddTarget("out", &err));
+  EXPECT_TRUE(builder_.AddTarget("out", &err));
   EXPECT_EQ("", err);
-  EXPECT_TRUE(builder.Build(&err));
+  EXPECT_TRUE(builder_.Build(&err));
   EXPECT_EQ("", err);
 
   fs_.Tick();
@@ -2640,14 +2596,12 @@
 
   command_runner_.commands_ran_.clear();
   state_.Reset();
-  EXPECT_TRUE(builder.AddTarget("out", &err));
+  EXPECT_TRUE(builder_.AddTarget("out", &err));
   EXPECT_EQ("", err);
-  EXPECT_TRUE(builder.Build(&err));
+  EXPECT_TRUE(builder_.Build(&err));
   EXPECT_EQ("", err);
 
   EXPECT_EQ("", status_.last_output_);
-
-  builder.command_runner_.release();
 }
 
 TEST_F(BuildWithDepsLogTest, MissingDepfileWarning) {
@@ -2700,4 +2654,57 @@
   EXPECT_EQ("depfile is missing", status_.last_output_);
 
   builder.command_runner_.release();
+}
+
+TEST_F(BuildTest, PreRemoveOutputs) {
+  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule touch\n  command = touch ${out}\n"
+"build out: touch in\n"
+"build out2: touch out\n"));
+
+  config_.uses_phony_outputs = true;
+  config_.pre_remove_output_files = true;
+
+  fs_.Create("out", "");
+  fs_.Tick();
+  fs_.Create("in", "");
+
+  string err;
+  EXPECT_TRUE(builder_.AddTarget("out2", &err));
+  EXPECT_EQ("", err);
+
+  fs_.files_created_.clear();
+
+  EXPECT_TRUE(builder_.Build(&err));
+  EXPECT_EQ("", err);
+
+  EXPECT_EQ(2u, command_runner_.commands_ran_.size());
+  EXPECT_EQ(2u, fs_.files_created_.size());
+  EXPECT_EQ(1u, fs_.files_removed_.size());
+}
+
+TEST_F(BuildTest, PreRemoveOutputsWithPhonyOutputs) {
+  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule phony_out\n"
+"  command = echo ${out}\n"
+"  phony_output = true\n"
+"build out: phony_out\n"));
+
+  config_.uses_phony_outputs = true;
+  config_.pre_remove_output_files = true;
+
+  fs_.Create("out", "");
+
+  string err;
+  EXPECT_TRUE(builder_.AddTarget("out", &err));
+  EXPECT_EQ("", err);
+
+  fs_.files_created_.clear();
+
+  EXPECT_TRUE(builder_.Build(&err));
+  EXPECT_EQ("", err);
+
+  EXPECT_EQ(1u, command_runner_.commands_ran_.size());
+  EXPECT_EQ(0u, fs_.files_created_.size());
+  EXPECT_EQ(0u, fs_.files_removed_.size());
 }
\ No newline at end of file
diff --git a/src/ninja.cc b/src/ninja.cc
index d350544..c84342d 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -233,6 +233,7 @@
 "  -d MODE  enable debugging (use '-d list' to list modes)\n"
 "  -t TOOL  run a subtool (use '-t list' to list subtools)\n"
 "    terminates toplevel options; further flags are passed to the tool\n"
+"  -o FLAG  adjust options (use '-o list' to list options)\n"
 "  -w FLAG  adjust warnings (use '-w list' to list warnings)\n"
 #ifndef _WIN32
 "\n"
@@ -1091,8 +1092,7 @@
 "  phonycycle={err,warn}  phony build statement references itself\n"
 "  missingdepfile={err,warn}  how to treat missing depfiles\n"
 "\n"
-"  usesphonyoutputs={yes,no}  whether the generate uses 'phony_output's so \n"
-"                             that the following warnings work\n"
+" requires -o usesphonyoutputs=yes\n"
 "  outputdir={err,warn}  how to treat outputs that are directories\n"
 "  missingoutfile={err,warn}  how to treat missing output files\n"
 "  oldoutput={err,warn}  how to treat output files older than their inputs\n");
@@ -1115,12 +1115,6 @@
   } else if (name == "missingdepfile=warn") {
     config->missing_depfile_should_err = false;
     return true;
-  } else if (name == "usesphonyoutputs=yes") {
-    config->uses_phony_outputs = true;
-    return true;
-  } else if (name == "usesphonyoutputs=no") {
-    config->uses_phony_outputs = false;
-    return true;
   } else if (name == "outputdir=err") {
     config->output_directory_should_err = true;
     return true;
@@ -1144,7 +1138,6 @@
         SpellcheckString(name.c_str(), "dupbuild=err", "dupbuild=warn",
                          "phonycycle=err", "phonycycle=warn",
                          "missingdepfile=err", "missingdepfile=warn",
-                         "usesphonyoutputs=yes", "usesphonyoutputs=no",
                          "outputdir=err", "outputdir=warn",
                          "missingoutfile=err", "missingoutfile=warn",
                          "oldoutput=err", "oldoutput=warn", NULL);
@@ -1158,6 +1151,46 @@
   }
 }
 
+/// Set an option flag.  Returns false if Ninja should exit instead  of
+/// continuing.
+bool OptionEnable(const string& name, Options* options, BuildConfig* config) {
+  if (name == "list") {
+    printf("option flags:\n"
+"  usesphonyoutputs={yes,no}  whether the generate uses 'phony_output's so \n"
+"                             that these warnings work:\n"
+"                                outputdir\n"
+"                                missingoutfile\n"
+"                                oldoutput\n"
+"  preremoveoutputs={yes,no}  whether to remove outputs before running rule\n");
+    return false;
+  } else if (name == "usesphonyoutputs=yes") {
+    config->uses_phony_outputs = true;
+    return true;
+  } else if (name == "usesphonyoutputs=no") {
+    config->uses_phony_outputs = false;
+    return true;
+  } else if (name == "preremoveoutputs=yes") {
+    config->pre_remove_output_files = true;
+    return true;
+  } else if (name == "preremoveoutputs=no") {
+    config->pre_remove_output_files = false;
+    return true;
+  } else {
+    const char* suggestion =
+        SpellcheckString(name.c_str(),
+                         "usesphonyoutputs=yes", "usesphonyoutputs=no",
+                         "preremoveoutputs=yes", "preremoveoutputs=no",
+                         NULL);
+    if (suggestion) {
+      Error("unknown option flag '%s', did you mean '%s'?",
+            name.c_str(), suggestion);
+    } else {
+      Error("unknown option flag '%s'", name.c_str());
+    }
+    return false;
+  }
+}
+
 bool NinjaMain::OpenBuildLog(bool recompact_only) {
   string log_path = ".ninja_log";
   if (!build_dir_.empty())
@@ -1332,7 +1365,7 @@
 
   int opt;
   while (!options->tool &&
-         (opt = getopt_long(*argc, *argv, "d:f:j:k:l:mnt:vw:C:ph", kLongOptions,
+         (opt = getopt_long(*argc, *argv, "d:f:j:k:l:mnt:vw:o:C:ph", kLongOptions,
                             NULL)) != -1) {
     switch (opt) {
       case 'd':
@@ -1388,6 +1421,10 @@
         if (!WarningEnable(optarg, options, config))
           return 1;
         break;
+      case 'o':
+        if (!OptionEnable(optarg, options, config))
+          return 1;
+        break;
       case 'C':
         options->working_dir = optarg;
         break;
@@ -1416,6 +1453,10 @@
     Fatal("only one of --frontend or --frontend_file may be specified.");
   }
 
+  if (config->pre_remove_output_files && !config->uses_phony_outputs) {
+    Fatal("preremoveoutputs=yes requires usesphonyoutputs=yes.");
+  }
+
   return -1;
 }