Merge pull request #1474 from mathstuf/win32-invalid-parameter-help
Win32 invalid parameter help
diff --git a/HACKING.md b/HACKING.md
index 5c2469b..086940b 100644
--- a/HACKING.md
+++ b/HACKING.md
@@ -29,15 +29,15 @@
Visual Studio.
##### Using Visual Studio
-Assuming that you now have python installed, then the steps for building under
- Windows using Visual Studio are:
-
+Assuming that you now have Python installed, then the steps for building under
+Windows using Visual Studio are:
+
Clone and checkout the latest release (or whatever branch you want). You
can do this in either a command prompt or by opening a git bash prompt:
```
- $ git clone git://github.com/ninja-build/ninja.git && cd ninja
- $ git checkout release
+ $ git clone git://github.com/ninja-build/ninja.git && cd ninja
+ $ git checkout release
```
Then:
diff --git a/doc/manual.asciidoc b/doc/manual.asciidoc
index db164e7..7b1c3ba 100644
--- a/doc/manual.asciidoc
+++ b/doc/manual.asciidoc
@@ -593,7 +593,7 @@
to its stdout. Ninja then filters these lines from the displayed
output. No `depfile` attribute is necessary, but the localized string
in front of the the header file path. For instance
- `msvc_deps_prefix = Note: including file: `
+ `msvc_deps_prefix = Note: including file:`
for a English Visual Studio (the default). Should be globally defined.
+
----
diff --git a/misc/output_test.py b/misc/output_test.py
index 6a5b635..878de19 100755
--- a/misc/output_test.py
+++ b/misc/output_test.py
@@ -11,11 +11,14 @@
import tempfile
import unittest
-def run(build_ninja, flags='', pipe=False):
- env = dict(os.environ)
- if 'NINJA_STATUS' in env:
- del env['NINJA_STATUS']
- env['TERM'] = ''
+default_env = dict(os.environ)
+if 'NINJA_STATUS' in default_env:
+ del default_env['NINJA_STATUS']
+if 'CLICOLOR_FORCE' in default_env:
+ del default_env['CLICOLOR_FORCE']
+default_env['TERM'] = ''
+
+def run(build_ninja, flags='', pipe=False, env=default_env):
with tempfile.NamedTemporaryFile('w') as f:
f.write(build_ninja)
f.flush()
@@ -84,5 +87,13 @@
red
''')
+ # CLICOLOR_FORCE=1 can be used to disable escape code stripping.
+ env = default_env.copy()
+ env['CLICOLOR_FORCE'] = '1'
+ self.assertEqual(run(print_red, pipe=True, env=env),
+'''[1/1] echo a
+\x1b[31mred\x1b[0m
+''')
+
if __name__ == '__main__':
unittest.main()
diff --git a/src/browse.cc b/src/browse.cc
index 14900f8..c08c9f4 100644
--- a/src/browse.cc
+++ b/src/browse.cc
@@ -14,6 +14,7 @@
#include "browse.h"
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -57,7 +58,11 @@
}
command.push_back(NULL);
execvp(command[0], (char**)&command[0]);
- perror("ninja: execvp");
+ if (errno == ENOENT) {
+ printf("ninja: %s is required for the browse tool\n", NINJA_PYTHON);
+ } else {
+ perror("ninja: execvp");
+ }
} while (false);
_exit(1);
} else { // Child.
diff --git a/src/browse.py b/src/browse.py
index 64a16f2..1c9c39b 100755
--- a/src/browse.py
+++ b/src/browse.py
@@ -24,8 +24,10 @@
try:
import http.server as httpserver
+ import socketserver
except ImportError:
import BaseHTTPServer as httpserver
+ import SocketServer as socketserver
import argparse
import cgi
import os
@@ -205,10 +207,14 @@
parser.add_argument('initial_target', default='all', nargs='?',
help='Initial target to show (default %(default)s)')
+class HTTPServer(socketserver.ThreadingMixIn, httpserver.HTTPServer):
+ # terminate server immediately when Python exits.
+ daemon_threads = True
+
args = parser.parse_args()
port = args.port
hostname = args.hostname
-httpd = httpserver.HTTPServer((hostname,port), RequestHandler)
+httpd = HTTPServer((hostname,port), RequestHandler)
try:
if hostname == "":
hostname = socket.gethostname()
diff --git a/src/build.cc b/src/build.cc
index 6b33024..ed219fd 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -154,7 +154,6 @@
// (Launching subprocesses in pseudo ttys doesn't work because there are
// only a few hundred available on some systems, and ninja can launch
// thousands of parallel compile commands.)
- // TODO: There should be a flag to disable escape code stripping.
string final_output;
if (!printer_.supports_color())
final_output = StripAnsiEscapeCodes(output);
diff --git a/src/disk_interface.cc b/src/disk_interface.cc
index 7351715..d4c2fb0 100644
--- a/src/disk_interface.cc
+++ b/src/disk_interface.cc
@@ -35,14 +35,15 @@
string DirName(const string& path) {
#ifdef _WIN32
- const char kPathSeparators[] = "\\/";
+ static const char kPathSeparators[] = "\\/";
#else
- const char kPathSeparators[] = "/";
+ static const char kPathSeparators[] = "/";
#endif
+ static const char* const kEnd = kPathSeparators + sizeof(kPathSeparators) - 1;
+
string::size_type slash_pos = path.find_last_of(kPathSeparators);
if (slash_pos == string::npos)
return string(); // Nothing to do.
- const char* const kEnd = kPathSeparators + strlen(kPathSeparators);
while (slash_pos > 0 &&
std::find(kPathSeparators, kEnd, path[slash_pos - 1]) != kEnd)
--slash_pos;
diff --git a/src/line_printer.cc b/src/line_printer.cc
index a3a551e..953982a 100644
--- a/src/line_printer.cc
+++ b/src/line_printer.cc
@@ -18,6 +18,9 @@
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
+#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
+#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4
+#endif
#else
#include <unistd.h>
#include <sys/ioctl.h>
@@ -42,6 +45,19 @@
smart_terminal_ = GetConsoleScreenBufferInfo(console_, &csbi);
#endif
supports_color_ = smart_terminal_;
+ if (!supports_color_) {
+ const char* clicolor_force = getenv("CLICOLOR_FORCE");
+ supports_color_ = clicolor_force && string(clicolor_force) != "0";
+ }
+#ifdef _WIN32
+ // Try enabling ANSI escape sequence support on Windows 10 terminals.
+ if (supports_color_) {
+ DWORD mode;
+ if (GetConsoleMode(console_, &mode)) {
+ SetConsoleMode(console_, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
+ }
+ }
+#endif
}
void LinePrinter::Print(string to_print, LineType type) {
diff --git a/src/ninja.cc b/src/ninja.cc
index 8108f21..1267b03 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -206,11 +206,11 @@
" -C DIR change to DIR before doing anything else\n"
" -f FILE specify input build file [default=build.ninja]\n"
"\n"
-" -j N run N jobs in parallel [default=%d, derived from CPUs available]\n"
+" -j N run N jobs in parallel (0 means infinity) [default=%d, derived from CPUs available]\n"
" -k N keep going until N jobs fail (0 means infinity) [default=1]\n"
" -l N do not start new jobs if the load average is greater than N\n"
" -n dry run (don't run commands but act like they succeeded)\n"
-" -v show all command lines while building\n"
+" -v, --verbose show all command lines while building\n"
"\n"
" -d MODE enable debugging (use '-d list' to list modes)\n"
" -t TOOL run a subtool (use '-t list' to list subtools)\n"
@@ -387,7 +387,12 @@
// If we get here, the browse failed.
return 1;
}
-#endif // _WIN32
+#else
+int NinjaMain::ToolBrowse(const Options*, int, char**) {
+ Fatal("browse tool not supported on this platform");
+ return 1;
+}
+#endif
#if defined(_MSC_VER)
int NinjaMain::ToolMSVC(const Options* options, int argc, char* argv[]) {
@@ -803,10 +808,8 @@
/// Returns a Tool, or NULL if Ninja should exit.
const Tool* ChooseTool(const string& tool_name) {
static const Tool kTools[] = {
-#if defined(NINJA_HAVE_BROWSE)
{ "browse", "browse dependency graph in a web browser",
Tool::RUN_AFTER_LOAD, &NinjaMain::ToolBrowse },
-#endif
#if defined(_MSC_VER)
{ "msvc", "build helper for MSVC cl.exe (EXPERIMENTAL)",
Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolMSVC },
@@ -1102,6 +1105,7 @@
const option kLongOptions[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, OPT_VERSION },
+ { "verbose", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
};
@@ -1120,9 +1124,12 @@
case 'j': {
char* end;
int value = strtol(optarg, &end, 10);
- if (*end != 0 || value <= 0)
+ if (*end != 0 || value < 0)
Fatal("invalid -j parameter");
- config->parallelism = value;
+
+ // We want to run N jobs in parallel. For N = 0, INT_MAX
+ // is close enough to infinite for most sane builds.
+ config->parallelism = value > 0 ? value : INT_MAX;
break;
}
case 'k': {
diff --git a/src/util.cc b/src/util.cc
index 8e67fd9..47a5de2 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -346,9 +346,19 @@
return -errno;
}
+ struct stat st;
+ if (fstat(fileno(f), &st) < 0) {
+ err->assign(strerror(errno));
+ fclose(f);
+ return -errno;
+ }
+
+ // +1 is for the resize in ManifestParser::Load
+ contents->reserve(st.st_size + 1);
+
char buf[64 << 10];
size_t len;
- while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
+ while (!feof(f) && (len = fread(buf, 1, sizeof(buf), f)) > 0) {
contents->append(buf, len);
}
if (ferror(f)) {
@@ -577,7 +587,7 @@
string ElideMiddle(const string& str, size_t width) {
const int kMargin = 3; // Space for "...".
string result = str;
- if (result.size() + kMargin > width) {
+ if (result.size() > width) {
size_t elide_size = (width - kMargin) / 2;
result = result.substr(0, elide_size)
+ "..."
diff --git a/src/util_test.cc b/src/util_test.cc
index b4b7516..d97b48c 100644
--- a/src/util_test.cc
+++ b/src/util_test.cc
@@ -419,10 +419,12 @@
TEST(ElideMiddle, NothingToElide) {
string input = "Nothing to elide in this short string.";
EXPECT_EQ(input, ElideMiddle(input, 80));
+ EXPECT_EQ(input, ElideMiddle(input, 38));
}
TEST(ElideMiddle, ElideInTheMiddle) {
string input = "01234567890123456789";
string elided = ElideMiddle(input, 10);
EXPECT_EQ("012...789", elided);
+ EXPECT_EQ("01234567...23456789", ElideMiddle(input, 19));
}