Merge pull request #1604 from jessemckenna/correct-cpu-count-over-64

Enable ninja to use > 64 CPUs on Windows
diff --git a/appveyor.yml b/appveyor.yml
index 4c64f29..04ed58e 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -16,7 +16,7 @@
     build_script:
       ps: "C:\\msys64\\usr\\bin\\bash -lc @\"\n
       pacman -S --quiet --noconfirm --needed re2c 2>&1\n
-      sed -i 's|cmd /c $ar cqs $out.tmp $in && move /Y $out.tmp $out|$ar crs $out $in|g' configure.py\n
+      sed -i 's|cmd /c `$ar cqs `$out.tmp `$in \\&\\& move /Y `$out.tmp `$out|`$ar crs `$out `$in|g' configure.py\n
       ./configure.py --bootstrap --platform mingw 2>&1\n
       ./ninja all\n
       ./ninja_test 2>&1\n
diff --git a/src/build.cc b/src/build.cc
index a055738..8ef88b5 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -139,7 +139,11 @@
          o != edge->outputs_.end(); ++o)
       outputs += (*o)->path() + " ";
 
-    printer_.PrintOnNewLine("FAILED: " + outputs + "\n");
+    if (printer_.supports_color()) {
+        printer_.PrintOnNewLine("\x1B[31m" "FAILED: " "\x1B[0m" + outputs + "\n");
+    } else {
+        printer_.PrintOnNewLine("FAILED: " + outputs + "\n");
+    }
     printer_.PrintOnNewLine(edge->EvaluateCommand() + "\n");
   }
 
diff --git a/src/disk_interface.cc b/src/disk_interface.cc
index d4c2fb0..dc297c4 100644
--- a/src/disk_interface.cc
+++ b/src/disk_interface.cc
@@ -202,19 +202,13 @@
   // that it doesn't exist.
   if (st.st_mtime == 0)
     return 1;
-#if defined(__APPLE__) && !defined(_POSIX_C_SOURCE)
+#if defined(_AIX)
+  return (int64_t)st.st_mtime * 1000000000LL + st.st_mtime_n;
+#elif defined(__APPLE__)
   return ((int64_t)st.st_mtimespec.tv_sec * 1000000000LL +
           st.st_mtimespec.tv_nsec);
-#elif (_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700 || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || \
-       defined(__BIONIC__) || (defined (__SVR4) && defined (__sun)) || defined(__FreeBSD__))
-  // For glibc, see "Timestamp files" in the Notes of http://www.kernel.org/doc/man-pages/online/pages/man2/stat.2.html
-  // newlib, uClibc and musl follow the kernel (or Cygwin) headers and define the right macro values above.
-  // For bsd, see https://github.com/freebsd/freebsd/blob/master/sys/sys/stat.h and similar
-  // For bionic, C and POSIX API is always enabled.
-  // For solaris, see https://docs.oracle.com/cd/E88353_01/html/E37841/stat-2.html.
+#elif defined(st_mtime) // A macro, so we're likely on modern POSIX.
   return (int64_t)st.st_mtim.tv_sec * 1000000000LL + st.st_mtim.tv_nsec;
-#elif defined(_AIX)
-  return (int64_t)st.st_mtime * 1000000000LL + st.st_mtime_n;
 #else
   return (int64_t)st.st_mtime * 1000000000LL + st.st_mtimensec;
 #endif
diff --git a/src/graph.cc b/src/graph.cc
index a90c049..376b911 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -323,19 +323,17 @@
 struct EdgeEnv : public Env {
   enum EscapeKind { kShellEscape, kDoNotEscape };
 
-  EdgeEnv(Edge* edge, EscapeKind escape)
+  EdgeEnv(const Edge* const edge, const EscapeKind escape)
       : edge_(edge), escape_in_out_(escape), recursive_(false) {}
   virtual string LookupVariable(const string& var);
 
   /// Given a span of Nodes, construct a list of paths suitable for a command
   /// line.
-  string MakePathList(vector<Node*>::iterator begin,
-                      vector<Node*>::iterator end,
-                      char sep);
+  std::string MakePathList(const Node* const* span, size_t size, char sep) const;
 
  private:
   vector<string> lookups_;
-  Edge* edge_;
+  const Edge* const edge_;
   EscapeKind escape_in_out_;
   bool recursive_;
 };
@@ -344,14 +342,11 @@
   if (var == "in" || var == "in_newline") {
     int explicit_deps_count = edge_->inputs_.size() - edge_->implicit_deps_ -
       edge_->order_only_deps_;
-    return MakePathList(edge_->inputs_.begin(),
-                        edge_->inputs_.begin() + explicit_deps_count,
+    return MakePathList(&edge_->inputs_[0], explicit_deps_count,
                         var == "in" ? ' ' : '\n');
   } else if (var == "out") {
     int explicit_outs_count = edge_->outputs_.size() - edge_->implicit_outs_;
-    return MakePathList(edge_->outputs_.begin(),
-                        edge_->outputs_.begin() + explicit_outs_count,
-                        ' ');
+    return MakePathList(&edge_->outputs_[0], explicit_outs_count, ' ');
   }
 
   if (recursive_) {
@@ -376,11 +371,10 @@
   return edge_->env_->LookupWithFallback(var, eval, this);
 }
 
-string EdgeEnv::MakePathList(vector<Node*>::iterator begin,
-                             vector<Node*>::iterator end,
-                             char sep) {
+std::string EdgeEnv::MakePathList(const Node* const* const span,
+                                  const size_t size, const char sep) const {
   string result;
-  for (vector<Node*>::iterator i = begin; i != end; ++i) {
+  for (const Node* const* i = span; i != span + size; ++i) {
     if (!result.empty())
       result.push_back(sep);
     const string& path = (*i)->PathDecanonicalized();
@@ -397,7 +391,7 @@
   return result;
 }
 
-string Edge::EvaluateCommand(bool incl_rsp_file) {
+std::string Edge::EvaluateCommand(const bool incl_rsp_file) const {
   string command = GetBinding("command");
   if (incl_rsp_file) {
     string rspfile_content = GetBinding("rspfile_content");
@@ -407,7 +401,7 @@
   return command;
 }
 
-string Edge::GetBinding(const string& key) {
+std::string Edge::GetBinding(const std::string& key) const {
   EdgeEnv env(this, EdgeEnv::kShellEscape);
   return env.LookupVariable(key);
 }
@@ -426,7 +420,7 @@
   return env.LookupVariable("dyndep");
 }
 
-string Edge::GetUnescapedRspfile() {
+std::string Edge::GetUnescapedRspfile() const {
   EdgeEnv env(this, EdgeEnv::kDoNotEscape);
   return env.LookupVariable("rspfile");
 }
diff --git a/src/graph.h b/src/graph.h
index 75edbc5..6122837 100644
--- a/src/graph.h
+++ b/src/graph.h
@@ -155,10 +155,10 @@
   /// Expand all variables in a command and return it as a string.
   /// If incl_rsp_file is enabled, the string will also contain the
   /// full contents of a response file (if applicable)
-  string EvaluateCommand(bool incl_rsp_file = false);
+  std::string EvaluateCommand(bool incl_rsp_file = false) const;
 
   /// Returns the shell-escaped value of |key|.
-  string GetBinding(const string& key);
+  std::string GetBinding(const string& key) const;
   bool GetBindingBool(const string& key);
 
   /// Like GetBinding("depfile"), but without shell escaping.
@@ -166,7 +166,7 @@
   /// Like GetBinding("dyndep"), but without shell escaping.
   string GetUnescapedDyndep();
   /// Like GetBinding("rspfile"), but without shell escaping.
-  string GetUnescapedRspfile();
+  std::string GetUnescapedRspfile() const;
 
   void Dump(const char* prefix="") const;
 
diff --git a/src/line_printer.cc b/src/line_printer.cc
index 55469d9..c93173e 100644
--- a/src/line_printer.cc
+++ b/src/line_printer.cc
@@ -58,7 +58,9 @@
   if (supports_color_) {
     DWORD mode;
     if (GetConsoleMode(console_, &mode)) {
-      SetConsoleMode(console_, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
+      if (!SetConsoleMode(console_, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
+        supports_color_ = false;
+      }
     }
   }
 #endif
diff --git a/src/ninja.cc b/src/ninja.cc
index a093cd1..c24f09d 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -732,7 +732,8 @@
   ECM_NORMAL,
   ECM_EXPAND_RSPFILE
 };
-string EvaluateCommandWithRspfile(Edge* edge, EvaluateCommandMode mode) {
+std::string EvaluateCommandWithRspfile(const Edge* edge,
+                                       const EvaluateCommandMode mode) {
   string command = edge->EvaluateCommand();
   if (mode == ECM_NORMAL)
     return command;
@@ -756,6 +757,19 @@
   return command;
 }
 
+void printCompdb(const char* const directory, const Edge* const edge,
+                 const EvaluateCommandMode eval_mode) {
+  printf("\n  {\n    \"directory\": \"");
+  EncodeJSONString(directory);
+  printf("\",\n    \"command\": \"");
+  EncodeJSONString(EvaluateCommandWithRspfile(edge, eval_mode).c_str());
+  printf("\",\n    \"file\": \"");
+  EncodeJSONString(edge->inputs_[0]->path().c_str());
+  printf("\",\n    \"output\": \"");
+  EncodeJSONString(edge->outputs_[0]->path().c_str());
+  printf("\"\n  }");
+}
+
 int NinjaMain::ToolCompilationDatabase(const Options* options, int argc,
                                        char* argv[]) {
   // The compdb tool uses getopt, and expects argv[0] to contain the name of
@@ -804,22 +818,21 @@
        e != state_.edges_.end(); ++e) {
     if ((*e)->inputs_.empty())
       continue;
-    for (int i = 0; i != argc; ++i) {
-      if ((*e)->rule_->name() == argv[i]) {
-        if (!first)
-          putchar(',');
-
-        printf("\n  {\n    \"directory\": \"");
-        EncodeJSONString(&cwd[0]);
-        printf("\",\n    \"command\": \"");
-        EncodeJSONString(EvaluateCommandWithRspfile(*e, eval_mode).c_str());
-        printf("\",\n    \"file\": \"");
-        EncodeJSONString((*e)->inputs_[0]->path().c_str());
-        printf("\",\n    \"output\": \"");
-        EncodeJSONString((*e)->outputs_[0]->path().c_str());
-        printf("\"\n  }");
-
-        first = false;
+    if (argc == 0) {
+      if (!first) {
+        putchar(',');
+      }
+      printCompdb(&cwd[0], *e, eval_mode);
+      first = false;
+    } else {
+      for (int i = 0; i != argc; ++i) {
+        if ((*e)->rule_->name() == argv[i]) {
+          if (!first) {
+            putchar(',');
+          }
+          printCompdb(&cwd[0], *e, eval_mode);
+          first = false;
+        }
       }
     }
   }
diff --git a/src/test.cc b/src/test.cc
index a9816bc..8ba2297 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -33,6 +33,15 @@
 #include "manifest_parser.h"
 #include "util.h"
 
+#ifdef _AIX
+extern "C" {
+        // GCC "helpfully" strips the definition of mkdtemp out on AIX.
+        // The function is still present, so if we define it ourselves
+        // it will work perfectly fine.
+        extern char* mkdtemp(char* name_template);
+}
+#endif
+
 namespace {
 
 #ifdef _WIN32