summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml1
-rw-r--r--HACKING.md2
-rw-r--r--README4
-rwxr-xr-xconfigure.py33
-rw-r--r--doc/README.md11
-rw-r--r--doc/dblatex.xsl7
-rw-r--r--doc/docbook.xsl22
-rw-r--r--doc/manual.asciidoc35
-rw-r--r--doc/style.css6
-rw-r--r--misc/bash-completion5
-rw-r--r--misc/ninja_syntax.py5
-rwxr-xr-xmisc/ninja_syntax_test.py6
-rw-r--r--misc/zsh-completion6
-rw-r--r--src/build.cc8
-rw-r--r--src/debug_flags.cc2
-rw-r--r--src/debug_flags.h2
-rw-r--r--src/eval_env.cc5
-rw-r--r--src/eval_env.h4
-rw-r--r--src/includes_normalize_test.cc10
-rw-r--r--src/manifest_parser.cc8
-rw-r--r--src/manifest_parser.h9
-rw-r--r--src/manifest_parser_test.cc106
-rw-r--r--src/ninja.cc27
-rw-r--r--src/subprocess-win32.cc2
-rw-r--r--src/subprocess_test.cc4
-rw-r--r--src/test.cc4
26 files changed, 216 insertions, 118 deletions
diff --git a/.travis.yml b/.travis.yml
index 544db6f..216b8b0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,3 +1,4 @@
+sudo: false
language: cpp
compiler:
- gcc
diff --git a/HACKING.md b/HACKING.md
index d8cb2a2..c544615 100644
--- a/HACKING.md
+++ b/HACKING.md
@@ -20,7 +20,7 @@ You should end up with a `ninja` binary (or `ninja.exe`) in the source root.
On Windows, you'll need to install Python to run `configure.py`, and
run everything under a Visual Studio Tools Command Prompt (or after
running `vcvarsall` in a normal command prompt). See below if you
-want to use mingw or some other compiler instead using Visual Studio.
+want to use mingw or some other compiler instead of Visual Studio.
### Adjusting build flags
diff --git a/README b/README
index 59d7ff9..a1535ff 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
Ninja is a small build system with a focus on speed.
-http://ninja-build.org/
+https://ninja-build.org/
-See the manual -- http://ninja-build.org/manual.html or
+See the manual -- https://ninja-build.org/manual.html or
doc/manual.asciidoc included in the distribution -- for background
and more details.
diff --git a/configure.py b/configure.py
index 0710ea2..1c97db7 100755
--- a/configure.py
+++ b/configure.py
@@ -83,7 +83,7 @@ class Platform(object):
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out, err = popen.communicate()
- return b'/FS ' in out
+ return b'/FS' in out
def is_windows(self):
return self.is_mingw() or self.is_msvc()
@@ -265,11 +265,11 @@ if platform.is_msvc():
objext = '.obj'
def src(filename):
- return os.path.join('$sourcedir', 'src', filename)
+ return os.path.join('$root', 'src', filename)
def built(filename):
return os.path.join('$builddir', filename)
def doc(filename):
- return os.path.join('$sourcedir', 'doc', filename)
+ return os.path.join('$root', 'doc', filename)
def cc(name, **kwargs):
return n.build(built(name + objext), 'cxx', src(name + '.c'), **kwargs)
def cxx(name, **kwargs):
@@ -281,7 +281,12 @@ def binary(name):
return exe
return name
-n.variable('sourcedir', sourcedir)
+root = sourcedir
+if root == os.getcwd():
+ # In the common case where we're building directly in the source
+ # tree, simplify all the paths to just be cwd-relative.
+ root = '.'
+n.variable('root', root)
n.variable('builddir', 'build')
n.variable('cxx', CXX)
if platform.is_msvc():
@@ -321,11 +326,11 @@ if platform.is_msvc():
else:
cflags = ['-g', '-Wall', '-Wextra',
'-Wno-deprecated',
+ '-Wno-missing-field-initializers',
'-Wno-unused-parameter',
'-fno-rtti',
'-fno-exceptions',
'-fvisibility=hidden', '-pipe',
- '-Wno-missing-field-initializers',
'-DNINJA_PYTHON="%s"' % options.with_python]
if options.debug:
cflags += ['-D_GLIBCXX_DEBUG', '-D_GLIBCXX_DEBUG_PEDANTIC']
@@ -592,13 +597,19 @@ n.rule('asciidoc',
n.rule('xsltproc',
command='xsltproc --nonet doc/docbook.xsl $in > $out',
description='XSLTPROC $out')
-xml = n.build(built('manual.xml'), 'asciidoc', doc('manual.asciidoc'))
-manual = n.build(doc('manual.html'), 'xsltproc', xml,
- implicit=doc('style.css'))
+docbookxml = n.build(built('manual.xml'), 'asciidoc', doc('manual.asciidoc'))
+manual = n.build(doc('manual.html'), 'xsltproc', docbookxml,
+ implicit=[doc('style.css'), doc('docbook.xsl')])
n.build('manual', 'phony',
order_only=manual)
n.newline()
+n.rule('dblatex',
+ command='dblatex -q -o $out -p doc/dblatex.xsl $in',
+ description='DBLATEX $out')
+n.build(doc('manual.pdf'), 'dblatex', docbookxml,
+ implicit=[doc('dblatex.xsl')])
+
n.comment('Generate Doxygen.')
n.rule('doxygen',
command='doxygen $in',
@@ -618,12 +629,12 @@ n.newline()
if not host.is_mingw():
n.comment('Regenerate build files if build script changes.')
n.rule('configure',
- command='${configure_env}%s $sourcedir/configure.py $configure_args' %
+ command='${configure_env}%s $root/configure.py $configure_args' %
options.with_python,
generator=True)
n.build('build.ninja', 'configure',
- implicit=['$sourcedir/configure.py',
- os.path.normpath('$sourcedir/misc/ninja_syntax.py')])
+ implicit=['$root/configure.py',
+ os.path.normpath('$root/misc/ninja_syntax.py')])
n.newline()
n.default(ninja)
diff --git a/doc/README.md b/doc/README.md
new file mode 100644
index 0000000..6afe5d4
--- /dev/null
+++ b/doc/README.md
@@ -0,0 +1,11 @@
+This directory contains the Ninja manual and support files used in
+building it. Here's a brief overview of how it works.
+
+The source text, `manual.asciidoc`, is written in the AsciiDoc format.
+AsciiDoc can generate HTML but it doesn't look great; instead, we use
+AsciiDoc to generate the Docbook XML format and then provide our own
+Docbook XSL tweaks to produce HTML from that.
+
+In theory using AsciiDoc and DocBook allows us to produce nice PDF
+documentation etc. In reality it's not clear anyone wants that, but the
+build rules are in place to generate it if you install dblatex.
diff --git a/doc/dblatex.xsl b/doc/dblatex.xsl
new file mode 100644
index 0000000..c0da212
--- /dev/null
+++ b/doc/dblatex.xsl
@@ -0,0 +1,7 @@
+<!-- This custom XSL tweaks the dblatex XML settings. -->
+<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>
+ <!-- These parameters disable the list of collaborators and revisions.
+ Together remove a useless page from the front matter. -->
+ <xsl:param name='doc.collab.show'>0</xsl:param>
+ <xsl:param name='latex.output.revhistory'>0</xsl:param>
+</xsl:stylesheet>
diff --git a/doc/docbook.xsl b/doc/docbook.xsl
index 8afdc8c..19cc126 100644
--- a/doc/docbook.xsl
+++ b/doc/docbook.xsl
@@ -1,15 +1,29 @@
-<!-- This soup of XML is the minimum customization necessary to make the
- autogenerated manual look ok. -->
+<!-- This custom XSL tweaks the DocBook XML -> HTML settings to produce
+ an OK-looking manual. -->
<!DOCTYPE xsl:stylesheet [
<!ENTITY css SYSTEM "style.css">
]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'>
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
+
+ <!-- Embed our stylesheet as the user-provided <head> content. -->
<xsl:template name="user.head.content"><style>&css;</style></xsl:template>
+
+ <!-- Remove the body.attributes block, which specifies a bunch of
+ useless bgcolor etc. attrs on the <body> tag. -->
<xsl:template name="body.attributes"></xsl:template>
- <xsl:param name="generate.toc" select="'book toc'"/>
- <xsl:param name="chapter.autolabel" select="0" />
+
+ <!-- Specify that in "book" form (which we're using), we only want a
+ single table of contents at the beginning of the document. -->
+ <xsl:param name="generate.toc">book toc</xsl:param>
+
+ <!-- Don't put the "Chapter 1." prefix on the "chapters". -->
+ <xsl:param name="chapter.autolabel">0</xsl:param>
+
+ <!-- Use <ul> for the table of contents. By default DocBook uses a
+ <dl>, which makes no semantic sense. I imagine they just did
+ it because it looks nice? -->
<xsl:param name="toc.list.type">ul</xsl:param>
<xsl:output method="html" encoding="utf-8" indent="no"
diff --git a/doc/manual.asciidoc b/doc/manual.asciidoc
index 3c193f1..ab5c945 100644
--- a/doc/manual.asciidoc
+++ b/doc/manual.asciidoc
@@ -1,5 +1,5 @@
-Ninja
-=====
+The Ninja build system
+======================
Introduction
@@ -717,7 +717,6 @@ spaces within a token must be escaped.
There is only one escape character, `$`, and it has the following
behaviors:
-[horizontal]
`$` followed by a newline:: escape the newline (continue the current line
across a line break).
@@ -782,11 +781,9 @@ A `rule` block contains a list of `key = value` declarations that
affect the processing of the rule. Here is a full list of special
keys.
-`command` (_required_):: the command line to run. This string (after
- $variables are expanded) is passed directly to `sh -c` without
- interpretation by Ninja. Each `rule` may have only one `command`
- declaration. To specify multiple commands use `&&` (or similar) to
- concatenate operations.
+`command` (_required_):: the command line to run. Each `rule` may
+ have only one `command` declaration. See <<ref_rule_command,the next
+ section>> for more details on quoting and executing multiple commands.
`depfile`:: path to an optional `Makefile` that contains extra
_implicit dependencies_ (see <<ref_dependencies,the reference on
@@ -854,6 +851,27 @@ rule link
build myapp.exe: link a.obj b.obj [possibly many other .obj files]
----
+[[ref_rule_command]]
+Interpretation of the `command` variable
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Fundamentally, command lines behave differently on Unixes and Windows.
+
+On Unixes, commands are arrays of arguments. The Ninja `command`
+variable is passed directly to `sh -c`, which is then responsible for
+interpreting that string into an argv array. Therefore the quoting
+rules are those of the shell, and you can use all the normal shell
+operators, like `&&` to chain multiple commands, or `VAR=value cmd` to
+set environment variables.
+
+On Windows, commands are strings, so Ninja passes the `command` string
+directly to `CreateProcess`. (In the common case of simply executing
+a compiler this means there is less overhead.) Consequently the
+quoting rules are deterimined by the called program, which on Windows
+are usually provided by the C library. If you need shell
+interpretation of the command (such as the use of `&&` to chain
+multiple commands), make the command execute the Windows shell by
+prefixing the command with `cmd /c`.
+
[[ref_dependencies]]
Build dependencies
~~~~~~~~~~~~~~~~~~
@@ -954,4 +972,3 @@ Variable declarations indented in a `build` block are scoped to the
5. Variables from the file that included that file using the
`subninja` keyword.
-
diff --git a/doc/style.css b/doc/style.css
index 5d14a1c..9976c03 100644
--- a/doc/style.css
+++ b/doc/style.css
@@ -24,12 +24,6 @@ div.chapter {
margin-top: 4em;
border-top: solid 2px black;
}
-.section .title {
- font-size: 1.3em;
-}
-.section .section .title {
- font-size: 1.2em;
-}
p {
margin-top: 0;
}
diff --git a/misc/bash-completion b/misc/bash-completion
index 0536760..e604cd4 100644
--- a/misc/bash-completion
+++ b/misc/bash-completion
@@ -49,9 +49,8 @@ _ninja_target() {
C) eval dir="$OPTARG" ;;
esac
done;
- targets_command="eval ninja -C \"${dir}\" -t targets all"
- targets=$(${targets_command} 2>/dev/null | awk -F: '{print $1}')
- COMPREPLY=($(compgen -W "$targets" -- "$cur"))
+ targets_command="eval ninja -C \"${dir}\" -t targets all 2>/dev/null | cut -d: -f1"
+ COMPREPLY=($(compgen -W '`${targets_command}`' -- "$cur"))
fi
return
}
diff --git a/misc/ninja_syntax.py b/misc/ninja_syntax.py
index 8673518..73d2209 100644
--- a/misc/ninja_syntax.py
+++ b/misc/ninja_syntax.py
@@ -21,8 +21,9 @@ class Writer(object):
def newline(self):
self.output.write('\n')
- def comment(self, text):
- for line in textwrap.wrap(text, self.width - 2):
+ def comment(self, text, has_path=False):
+ for line in textwrap.wrap(text, self.width - 2, break_long_words=False,
+ break_on_hyphens=False):
self.output.write('# ' + line + '\n')
def variable(self, key, value, indent=0):
diff --git a/misc/ninja_syntax_test.py b/misc/ninja_syntax_test.py
index 36b2e7b..c9755b8 100755
--- a/misc/ninja_syntax_test.py
+++ b/misc/ninja_syntax_test.py
@@ -45,6 +45,12 @@ class TestLineWordWrap(unittest.TestCase):
INDENT + 'y']) + '\n',
self.out.getvalue())
+ def test_comment_wrap(self):
+ # Filenames shoud not be wrapped
+ self.n.comment('Hello /usr/local/build-tools/bin')
+ self.assertEqual('# Hello\n# /usr/local/build-tools/bin\n',
+ self.out.getvalue())
+
def test_short_words_indented(self):
# Test that indent is taking into acount when breaking subsequent lines.
# The second line should not be ' to tree', as that's longer than the
diff --git a/misc/zsh-completion b/misc/zsh-completion
index fd9b3a7..446e269 100644
--- a/misc/zsh-completion
+++ b/misc/zsh-completion
@@ -22,9 +22,8 @@ __get_targets() {
then
eval dir="${opt_args[-C]}"
fi
- targets_command="ninja -C \"${dir}\" -t targets"
- eval ${targets_command} 2>/dev/null | while read -r a b; do echo $a | cut -d ':' -f1; done;
-
+ targets_command="ninja -C \"${dir}\" -t targets all"
+ eval ${targets_command} 2>/dev/null | cut -d: -f1
}
__get_tools() {
@@ -66,4 +65,3 @@ _arguments \
'-d+[Enable debugging (use -d list to list modes)]:modes:__modes' \
'-t+[Run a subtool (use -t list to list subtools)]:tools:__tools' \
'*::targets:__targets'
-
diff --git a/src/build.cc b/src/build.cc
index 0e9a399..ab2460a 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -892,9 +892,11 @@ bool Builder::ExtractDeps(CommandRunner::Result* result,
deps_nodes->push_back(state_->GetNode(*i, slash_bits));
}
- if (disk_interface_->RemoveFile(depfile) < 0) {
- *err = string("deleting depfile: ") + strerror(errno) + string("\n");
- return false;
+ if (!g_keep_depfile) {
+ if (disk_interface_->RemoveFile(depfile) < 0) {
+ *err = string("deleting depfile: ") + strerror(errno) + string("\n");
+ return false;
+ }
}
} else {
Fatal("unknown deps type '%s'", deps_type.c_str());
diff --git a/src/debug_flags.cc b/src/debug_flags.cc
index 8065001..44b14c4 100644
--- a/src/debug_flags.cc
+++ b/src/debug_flags.cc
@@ -14,6 +14,8 @@
bool g_explaining = false;
+bool g_keep_depfile = false;
+
bool g_keep_rsp = false;
bool g_experimental_statcache = true;
diff --git a/src/debug_flags.h b/src/debug_flags.h
index 7965585..e08a43b 100644
--- a/src/debug_flags.h
+++ b/src/debug_flags.h
@@ -24,6 +24,8 @@
extern bool g_explaining;
+extern bool g_keep_depfile;
+
extern bool g_keep_rsp;
extern bool g_experimental_statcache;
diff --git a/src/eval_env.cc b/src/eval_env.cc
index e991d21..8817a87 100644
--- a/src/eval_env.cc
+++ b/src/eval_env.cc
@@ -55,7 +55,7 @@ void Rule::AddBinding(const string& key, const EvalString& val) {
}
const EvalString* Rule::GetBinding(const string& key) const {
- map<string, EvalString>::const_iterator i = bindings_.find(key);
+ Bindings::const_iterator i = bindings_.find(key);
if (i == bindings_.end())
return NULL;
return &i->second;
@@ -71,7 +71,8 @@ bool Rule::IsReservedBinding(const string& var) {
var == "pool" ||
var == "restat" ||
var == "rspfile" ||
- var == "rspfile_content";
+ var == "rspfile_content" ||
+ var == "msvc_deps_prefix";
}
const map<string, const Rule*>& BindingEnv::GetRules() const {
diff --git a/src/eval_env.h b/src/eval_env.h
index 28c4d16..999ce42 100644
--- a/src/eval_env.h
+++ b/src/eval_env.h
@@ -57,7 +57,6 @@ struct Rule {
const string& name() const { return name_; }
- typedef map<string, EvalString> Bindings;
void AddBinding(const string& key, const EvalString& val);
static bool IsReservedBinding(const string& var);
@@ -69,7 +68,8 @@ struct Rule {
friend struct ManifestParser;
string name_;
- map<string, EvalString> bindings_;
+ typedef map<string, EvalString> Bindings;
+ Bindings bindings_;
};
/// An Env which contains a mapping of variables to values
diff --git a/src/includes_normalize_test.cc b/src/includes_normalize_test.cc
index aba25d0..f18795c 100644
--- a/src/includes_normalize_test.cc
+++ b/src/includes_normalize_test.cc
@@ -30,15 +30,15 @@ string GetCurDir() {
return parts[parts.size() - 1];
}
-string NormalizeAndCheckNoError(const std::string& input) {
+string NormalizeAndCheckNoError(const string& input) {
string result, err;
EXPECT_TRUE(IncludesNormalize::Normalize(input.c_str(), NULL, &result, &err));
EXPECT_EQ("", err);
return result;
}
-string NormalizeRelativeAndCheckNoError(const std::string& input,
- const std::string& relative_to) {
+string NormalizeRelativeAndCheckNoError(const string& input,
+ const string& relative_to) {
string result, err;
EXPECT_TRUE(IncludesNormalize::Normalize(input.c_str(), relative_to.c_str(),
&result, &err));
@@ -160,8 +160,8 @@ TEST(IncludesNormalize, LongInvalidPath) {
"012345678\\"
"012345678\\"
"0123456789";
- std::string forward_slashes(kExactlyMaxPath);
- std::replace(forward_slashes.begin(), forward_slashes.end(), '\\', '/');
+ string forward_slashes(kExactlyMaxPath);
+ replace(forward_slashes.begin(), forward_slashes.end(), '\\', '/');
// Make sure a path that's exactly _MAX_PATH long is canonicalized.
EXPECT_EQ(forward_slashes,
NormalizeAndCheckNoError(kExactlyMaxPath));
diff --git a/src/manifest_parser.cc b/src/manifest_parser.cc
index e8c0436..d0fac59 100644
--- a/src/manifest_parser.cc
+++ b/src/manifest_parser.cc
@@ -25,9 +25,9 @@
#include "version.h"
ManifestParser::ManifestParser(State* state, FileReader* file_reader,
- bool dupe_edge_should_err)
+ DupeEdgeAction dupe_edge_action)
: state_(state), file_reader_(file_reader),
- dupe_edge_should_err_(dupe_edge_should_err), quiet_(false) {
+ dupe_edge_action_(dupe_edge_action), quiet_(false) {
env_ = &state->bindings_;
}
@@ -331,7 +331,7 @@ bool ManifestParser::ParseEdge(string* err) {
if (!CanonicalizePath(&path, &slash_bits, &path_err))
return lexer_.Error(path_err, err);
if (!state_->AddOut(edge, path, slash_bits)) {
- if (dupe_edge_should_err_) {
+ if (dupe_edge_action_ == kDupeEdgeActionError) {
lexer_.Error("multiple rules generate " + path + " [-w dupbuild=err]",
err);
return false;
@@ -380,7 +380,7 @@ bool ManifestParser::ParseFileInclude(bool new_scope, string* err) {
return false;
string path = eval.Evaluate(env_);
- ManifestParser subparser(state_, file_reader_);
+ ManifestParser subparser(state_, file_reader_, dupe_edge_action_);
if (new_scope) {
subparser.env_ = new BindingEnv(env_);
} else {
diff --git a/src/manifest_parser.h b/src/manifest_parser.h
index f72cd6f..41d388c 100644
--- a/src/manifest_parser.h
+++ b/src/manifest_parser.h
@@ -25,6 +25,11 @@ struct BindingEnv;
struct EvalString;
struct State;
+enum DupeEdgeAction {
+ kDupeEdgeActionWarn,
+ kDupeEdgeActionError,
+};
+
/// Parses .ninja files.
struct ManifestParser {
struct FileReader {
@@ -33,7 +38,7 @@ struct ManifestParser {
};
ManifestParser(State* state, FileReader* file_reader,
- bool dupe_edge_should_err = false);
+ DupeEdgeAction dupe_edge_action);
/// Load and parse a file.
bool Load(const string& filename, string* err, Lexer* parent = NULL);
@@ -66,7 +71,7 @@ private:
BindingEnv* env_;
FileReader* file_reader_;
Lexer lexer_;
- bool dupe_edge_should_err_;
+ DupeEdgeAction dupe_edge_action_;
bool quiet_;
};
diff --git a/src/manifest_parser_test.cc b/src/manifest_parser_test.cc
index 8f7b575..a18433a 100644
--- a/src/manifest_parser_test.cc
+++ b/src/manifest_parser_test.cc
@@ -24,7 +24,7 @@
struct ParserTest : public testing::Test,
public ManifestParser::FileReader {
void AssertParse(const char* input) {
- ManifestParser parser(&state, this);
+ ManifestParser parser(&state, this, kDupeEdgeActionWarn);
string err;
EXPECT_TRUE(parser.ParseTest(input, &err));
ASSERT_EQ("", err);
@@ -371,12 +371,28 @@ TEST_F(ParserTest, DuplicateEdgeWithMultipleOutputsError) {
"build out1 out2: cat in1\n"
"build out1: cat in2\n"
"build final: cat out1\n";
- ManifestParser parser(&state, this, /*dupe_edges_should_err=*/true);
+ ManifestParser parser(&state, this, kDupeEdgeActionError);
string err;
EXPECT_FALSE(parser.ParseTest(kInput, &err));
EXPECT_EQ("input:5: multiple rules generate out1 [-w dupbuild=err]\n", err);
}
+TEST_F(ParserTest, DuplicateEdgeInIncludedFile) {
+ files_["sub.ninja"] =
+ "rule cat\n"
+ " command = cat $in > $out\n"
+ "build out1 out2: cat in1\n"
+ "build out1: cat in2\n"
+ "build final: cat out1\n";
+ const char kInput[] =
+ "subninja sub.ninja\n";
+ ManifestParser parser(&state, this, kDupeEdgeActionError);
+ string err;
+ EXPECT_FALSE(parser.ParseTest(kInput, &err));
+ EXPECT_EQ("sub.ninja:5: multiple rules generate out1 [-w dupbuild=err]\n",
+ err);
+}
+
TEST_F(ParserTest, ReservedWords) {
ASSERT_NO_FATAL_FAILURE(AssertParse(
"rule build\n"
@@ -388,7 +404,7 @@ TEST_F(ParserTest, ReservedWords) {
TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest(string("subn", 4), &err));
EXPECT_EQ("input:1: expected '=', got eof\n"
@@ -399,7 +415,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("foobar", &err));
EXPECT_EQ("input:1: expected '=', got eof\n"
@@ -410,7 +426,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("x 3", &err));
EXPECT_EQ("input:1: expected '=', got identifier\n"
@@ -421,7 +437,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("x = 3", &err));
EXPECT_EQ("input:1: unexpected EOF\n"
@@ -432,7 +448,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("x = 3\ny 2", &err));
EXPECT_EQ("input:2: expected '=', got identifier\n"
@@ -443,7 +459,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("x = $", &err));
EXPECT_EQ("input:1: bad $-escape (literal $ must be written as $$)\n"
@@ -454,7 +470,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("x = $\n $[\n", &err));
EXPECT_EQ("input:2: bad $-escape (literal $ must be written as $$)\n"
@@ -465,7 +481,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("x = a$\n b$\n $\n", &err));
EXPECT_EQ("input:4: unexpected EOF\n"
@@ -474,7 +490,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("build\n", &err));
EXPECT_EQ("input:1: expected path\n"
@@ -485,7 +501,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("build x: y z\n", &err));
EXPECT_EQ("input:1: unknown build rule 'y'\n"
@@ -496,7 +512,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("build x:: y z\n", &err));
EXPECT_EQ("input:1: expected build command name\n"
@@ -507,7 +523,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n command = cat ok\n"
"build x: cat $\n :\n",
@@ -520,7 +536,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n",
&err));
@@ -529,7 +545,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n"
" command = echo\n"
@@ -543,7 +559,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n"
" command = echo\n"
@@ -555,7 +571,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n"
" command = ${fafsd\n"
@@ -570,7 +586,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n"
" command = cat\n"
@@ -585,7 +601,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n"
" command = cat\n"
@@ -599,7 +615,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule %foo\n",
&err));
@@ -608,7 +624,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule cc\n"
" command = foo\n"
@@ -622,7 +638,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule cc\n command = foo\n"
"build $.: cc bar.cc\n",
@@ -635,7 +651,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule cc\n command = foo\n && bar",
&err));
@@ -644,7 +660,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule cc\n command = foo\n"
"build $: cc bar.cc\n",
@@ -657,7 +673,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("default\n",
&err));
@@ -669,7 +685,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("default nonexistent\n",
&err));
@@ -681,7 +697,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule r\n command = r\n"
"build b: r\n"
@@ -695,7 +711,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("default $a\n", &err));
EXPECT_EQ("input:1: empty path\n"
@@ -706,7 +722,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule r\n"
" command = r\n"
@@ -718,7 +734,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
// the indented blank line must terminate the rule
// this also verifies that "unexpected (token)" errors are correct
@@ -731,7 +747,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("pool\n", &err));
EXPECT_EQ("input:1: expected pool name\n", err);
@@ -739,7 +755,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("pool foo\n", &err));
EXPECT_EQ("input:2: expected 'depth =' line\n", err);
@@ -747,7 +763,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("pool foo\n"
" depth = 4\n"
@@ -760,7 +776,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("pool foo\n"
" depth = -1\n", &err));
@@ -772,7 +788,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("pool foo\n"
" bar = 1\n", &err));
@@ -784,7 +800,7 @@ TEST_F(ParserTest, Errors) {
{
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
// Pool names are dereferenced at edge parsing time.
EXPECT_FALSE(parser.ParseTest("rule run\n"
@@ -797,7 +813,7 @@ TEST_F(ParserTest, Errors) {
TEST_F(ParserTest, MissingInput) {
State state;
- ManifestParser parser(&state, this);
+ ManifestParser parser(&state, this, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.Load("build.ninja", &err));
EXPECT_EQ("loading 'build.ninja': No such file or directory", err);
@@ -805,7 +821,7 @@ TEST_F(ParserTest, MissingInput) {
TEST_F(ParserTest, MultipleOutputs) {
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_TRUE(parser.ParseTest("rule cc\n command = foo\n depfile = bar\n"
"build a.o b.o: cc c.cc\n",
@@ -815,7 +831,7 @@ TEST_F(ParserTest, MultipleOutputs) {
TEST_F(ParserTest, MultipleOutputsWithDeps) {
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("rule cc\n command = foo\n deps = gcc\n"
"build a.o b.o: cc c.cc\n",
@@ -850,7 +866,7 @@ TEST_F(ParserTest, SubNinja) {
}
TEST_F(ParserTest, MissingSubNinja) {
- ManifestParser parser(&state, this);
+ ManifestParser parser(&state, this, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("subninja foo.ninja\n", &err));
EXPECT_EQ("input:1: loading 'foo.ninja': No such file or directory\n"
@@ -863,7 +879,7 @@ TEST_F(ParserTest, DuplicateRuleInDifferentSubninjas) {
// Test that rules are scoped to subninjas.
files_["test.ninja"] = "rule cat\n"
" command = cat\n";
- ManifestParser parser(&state, this);
+ ManifestParser parser(&state, this, kDupeEdgeActionWarn);
string err;
EXPECT_TRUE(parser.ParseTest("rule cat\n"
" command = cat\n"
@@ -876,7 +892,7 @@ TEST_F(ParserTest, DuplicateRuleInDifferentSubninjasWithInclude) {
" command = cat\n";
files_["test.ninja"] = "include rules.ninja\n"
"build x : cat\n";
- ManifestParser parser(&state, this);
+ ManifestParser parser(&state, this, kDupeEdgeActionWarn);
string err;
EXPECT_TRUE(parser.ParseTest("include rules.ninja\n"
"subninja test.ninja\n"
@@ -896,7 +912,7 @@ TEST_F(ParserTest, Include) {
TEST_F(ParserTest, BrokenInclude) {
files_["include.ninja"] = "build\n";
- ManifestParser parser(&state, this);
+ ManifestParser parser(&state, this, kDupeEdgeActionWarn);
string err;
EXPECT_FALSE(parser.ParseTest("include include.ninja\n", &err));
EXPECT_EQ("include.ninja:1: expected path\n"
@@ -976,7 +992,7 @@ TEST_F(ParserTest, UTF8) {
TEST_F(ParserTest, CRLF) {
State state;
- ManifestParser parser(&state, NULL);
+ ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_TRUE(parser.ParseTest("# comment with crlf\r\n", &err));
diff --git a/src/ninja.cc b/src/ninja.cc
index 21dede6..3af10d6 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -701,7 +701,7 @@ int NinjaMain::ToolUrtle(int argc, char** argv) {
if ('0' <= *p && *p <= '9') {
count = count*10 + *p - '0';
} else {
- for (int i = 0; i < std::max(count, 1); ++i)
+ for (int i = 0; i < max(count, 1); ++i)
printf("%c", *p);
count = 0;
}
@@ -774,9 +774,10 @@ const Tool* ChooseTool(const string& tool_name) {
bool DebugEnable(const string& name) {
if (name == "list") {
printf("debugging modes:\n"
-" stats print operation counts/timing info\n"
-" explain explain what caused a command to execute\n"
-" keeprsp don't delete @response files on success\n"
+" stats print operation counts/timing info\n"
+" explain explain what caused a command to execute\n"
+" keepdepfile don't delete depfiles after they're read by ninja\n"
+" keeprsp don't delete @response files on success\n"
#ifdef _WIN32
" nostatcache don't batch stat() calls per directory and cache them\n"
#endif
@@ -788,6 +789,9 @@ bool DebugEnable(const string& name) {
} else if (name == "explain") {
g_explaining = true;
return true;
+ } else if (name == "keepdepfile") {
+ g_keep_depfile = true;
+ return true;
} else if (name == "keeprsp") {
g_keep_rsp = true;
return true;
@@ -796,8 +800,9 @@ bool DebugEnable(const string& name) {
return true;
} else {
const char* suggestion =
- SpellcheckString(name.c_str(), "stats", "explain", "keeprsp",
- "nostatcache", NULL);
+ SpellcheckString(name.c_str(),
+ "stats", "explain", "keepdepfile", "keeprsp",
+ "nostatcache", NULL);
if (suggestion) {
Error("unknown debug setting '%s', did you mean '%s'?",
name.c_str(), suggestion);
@@ -1114,7 +1119,9 @@ int real_main(int argc, char** argv) {
RealFileReader file_reader;
ManifestParser parser(&ninja.state_, &file_reader,
- options.dupe_edges_should_err);
+ options.dupe_edges_should_err
+ ? kDupeEdgeActionError
+ : kDupeEdgeActionWarn);
string err;
if (!parser.Load(options.input_file, &err)) {
Error("%s", err.c_str());
@@ -1135,6 +1142,10 @@ int real_main(int argc, char** argv) {
// Attempt to rebuild the manifest before building anything else
if (ninja.RebuildManifest(options.input_file, &err)) {
+ // In dry_run mode the regeneration will succeed without changing the
+ // manifest forever. Better to return immediately.
+ if (config.dry_run)
+ return 0;
// Start the build over with the new manifest.
continue;
} else if (!err.empty()) {
@@ -1159,7 +1170,7 @@ int main(int argc, char** argv) {
#if defined(_MSC_VER)
// Set a handler to catch crashes not caught by the __try..__except
// block (e.g. an exception in a stack-unwind-block).
- std::set_terminate(TerminateHandler);
+ set_terminate(TerminateHandler);
__try {
// Running inside __try ... __except suppresses any Windows error
// dialogs for errors such as bad_alloc.
diff --git a/src/subprocess-win32.cc b/src/subprocess-win32.cc
index fad66e8..4bab719 100644
--- a/src/subprocess-win32.cc
+++ b/src/subprocess-win32.cc
@@ -255,7 +255,7 @@ bool SubprocessSet::DoWork() {
if (subproc->Done()) {
vector<Subprocess*>::iterator end =
- std::remove(running_.begin(), running_.end(), subproc);
+ remove(running_.begin(), running_.end(), subproc);
if (running_.end() != end) {
finished_.push(subproc);
running_.resize(end - running_.begin());
diff --git a/src/subprocess_test.cc b/src/subprocess_test.cc
index 066bbb7..2fe4bce 100644
--- a/src/subprocess_test.cc
+++ b/src/subprocess_test.cc
@@ -159,8 +159,8 @@ TEST_F(SubprocessTest, Console) {
// Test that stdin, stdout and stderr are a terminal.
// Also check that the current process is connected to a terminal.
Subprocess* subproc =
- subprocs_.Add(std::string("test -t 0 -a -t 1 -a -t 2 && ") +
- std::string(kIsConnectedToTerminal),
+ subprocs_.Add(string("test -t 0 -a -t 1 -a -t 2 && ") +
+ string(kIsConnectedToTerminal),
/*use_console=*/true);
ASSERT_NE((Subprocess*)0, subproc);
diff --git a/src/test.cc b/src/test.cc
index aed8db7..841ce04 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -95,7 +95,7 @@ Node* StateTestWithBuiltinRules::GetNode(const string& path) {
}
void AssertParse(State* state, const char* input) {
- ManifestParser parser(state, NULL);
+ ManifestParser parser(state, NULL, kDupeEdgeActionWarn);
string err;
EXPECT_TRUE(parser.ParseTest(input, &err));
ASSERT_EQ("", err);
@@ -115,7 +115,7 @@ void VerifyGraph(const State& state) {
for (vector<Node*>::const_iterator in_node = (*e)->inputs_.begin();
in_node != (*e)->inputs_.end(); ++in_node) {
const vector<Edge*>& out_edges = (*in_node)->out_edges();
- EXPECT_NE(std::find(out_edges.begin(), out_edges.end(), *e),
+ EXPECT_NE(find(out_edges.begin(), out_edges.end(), *e),
out_edges.end());
}
// Check that the edge's outputs have the edge as in-edge.