summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build.cc64
-rw-r--r--src/build.h37
-rw-r--r--src/build_log.cc5
-rw-r--r--src/build_log_perftest.cc3
-rw-r--r--src/build_log_test.cc6
-rw-r--r--src/build_test.cc54
-rw-r--r--src/canon_perftest.cc1
-rw-r--r--src/clean.h1
-rw-r--r--src/depfile_parser.cc36
-rw-r--r--src/depfile_parser.in.cc2
-rw-r--r--src/depfile_parser_test.cc9
-rw-r--r--src/getopt.c8
-rw-r--r--src/graph.cc7
-rw-r--r--src/lexer.cc110
-rw-r--r--src/lexer.in.cc4
-rw-r--r--src/manifest_parser.cc (renamed from src/parsers.cc)2
-rw-r--r--src/manifest_parser.h (renamed from src/parsers.h)6
-rw-r--r--src/manifest_parser_test.cc (renamed from src/parsers_test.cc)22
-rw-r--r--src/metrics.cc10
-rw-r--r--src/metrics.h25
-rw-r--r--src/ninja.cc7
-rw-r--r--src/parser_perftest.cc1
-rw-r--r--src/state.h1
-rw-r--r--src/subprocess-win32.cc9
-rw-r--r--src/subprocess.cc7
-rw-r--r--src/subprocess_test.cc11
-rw-r--r--src/test.cc2
-rw-r--r--src/util.cc16
-rw-r--r--src/util.h6
-rw-r--r--src/win32port.h3
30 files changed, 341 insertions, 134 deletions
diff --git a/src/build.cc b/src/build.cc
index 65aa6a9..90a84c2 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -37,7 +37,9 @@ BuildStatus::BuildStatus(const BuildConfig& config)
: config_(config),
start_time_millis_(GetTimeMillis()),
started_edges_(0), finished_edges_(0), total_edges_(0),
- have_blank_line_(true), progress_status_format_(NULL) {
+ have_blank_line_(true), progress_status_format_(NULL),
+ overall_rate_(), current_rate_(),
+ current_rate_average_count_(config.parallelism) {
#ifndef _WIN32
const char* term = getenv("TERM");
smart_terminal_ = isatty(1) && term && string(term) != "dumb";
@@ -171,6 +173,25 @@ string BuildStatus::FormatProgressStatus(const char* progress_status_format) con
out += buf;
break;
+ // Overall finished edges per second.
+ case 'o':
+ overall_rate_.UpdateRate(finished_edges_, finished_edges_);
+ overall_rate_.snprinfRate(buf, "%.1f");
+ out += buf;
+ break;
+
+ // Current rate, average over the last '-j' jobs.
+ case 'c':
+ // TODO use sliding window?
+ if (finished_edges_ > current_rate_.last_update() &&
+ finished_edges_ - current_rate_.last_update() == current_rate_average_count_) {
+ current_rate_.UpdateRate(current_rate_average_count_, finished_edges_);
+ current_rate_.Restart();
+ }
+ current_rate_.snprinfRate(buf, "%.0f");
+ out += buf;
+ break;
+
default: {
Fatal("unknown placeholder '%%%c' in $NINJA_STATUS", *s);
return "";
@@ -208,6 +229,10 @@ void BuildStatus::PrintStatus(Edge* edge) {
#endif
}
+ if (finished_edges_ == 0) {
+ overall_rate_.Restart();
+ current_rate_.Restart();
+ }
to_print = FormatProgressStatus(progress_status_format_) + to_print;
if (smart_terminal_ && !force_full_command) {
@@ -236,22 +261,36 @@ void BuildStatus::PrintStatus(Edge* edge) {
#endif
}
- printf("%s", to_print.c_str());
-
if (smart_terminal_ && !force_full_command) {
#ifndef _WIN32
+ printf("%s", to_print.c_str());
printf("\x1B[K"); // Clear to end of line.
fflush(stdout);
have_blank_line_ = false;
#else
- // Clear to end of line.
+ // We don't want to have the cursor spamming back and forth, so
+ // use WriteConsoleOutput instead which updates the contents of
+ // the buffer, but doesn't move the cursor position.
GetConsoleScreenBufferInfo(console_, &csbi);
- int num_spaces = csbi.dwSize.X - 1 - csbi.dwCursorPosition.X;
- printf("%*s", num_spaces, "");
+ COORD buf_size = { csbi.dwSize.X, 1 };
+ COORD zero_zero = { 0, 0 };
+ SMALL_RECT target = { csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y,
+ csbi.dwCursorPosition.X + csbi.dwSize.X - 1,
+ csbi.dwCursorPosition.Y };
+ CHAR_INFO* char_data = new CHAR_INFO[csbi.dwSize.X];
+ memset(char_data, 0, sizeof(CHAR_INFO) * csbi.dwSize.X);
+ for (int i = 0; i < csbi.dwSize.X; ++i) {
+ char_data[i].Char.AsciiChar = ' ';
+ char_data[i].Attributes = csbi.wAttributes;
+
+ }
+ for (size_t i = 0; i < to_print.size(); ++i)
+ char_data[i].Char.AsciiChar = to_print[i];
+ WriteConsoleOutput(console_, char_data, buf_size, zero_zero, &target);
have_blank_line_ = false;
#endif
} else {
- printf("\n");
+ printf("%s\n", to_print.c_str());
}
}
@@ -465,7 +504,7 @@ void RealCommandRunner::Abort() {
bool RealCommandRunner::CanRunMore() {
return ((int)subprocs_.running_.size()) < config_.parallelism
- && ((subprocs_.running_.size() == 0 || config_.max_load_average <= 0.0f)
+ && ((subprocs_.running_.empty() || config_.max_load_average <= 0.0f)
|| GetLoadAverage() < config_.max_load_average);
}
@@ -739,19 +778,13 @@ void Builder::FinishEdge(Edge* edge, bool success, const string& output) {
for (vector<Node*>::iterator i = edge->inputs_.begin();
i != edge->inputs_.end() - edge->order_only_deps_; ++i) {
TimeStamp input_mtime = disk_interface_->Stat((*i)->path());
- if (input_mtime == 0) {
- restat_mtime = 0;
- break;
- }
if (input_mtime > restat_mtime)
restat_mtime = input_mtime;
}
if (restat_mtime != 0 && !edge->rule().depfile().empty()) {
TimeStamp depfile_mtime = disk_interface_->Stat(edge->EvaluateDepFile());
- if (depfile_mtime == 0)
- restat_mtime = 0;
- else if (depfile_mtime > restat_mtime)
+ if (depfile_mtime > restat_mtime)
restat_mtime = depfile_mtime;
}
@@ -776,3 +809,4 @@ void Builder::FinishEdge(Edge* edge, bool success, const string& output) {
if (success && log_)
log_->RecordCommand(edge, start_time, end_time, restat_mtime);
}
+
diff --git a/src/build.h b/src/build.h
index c9ee4ac..5e26bbb 100644
--- a/src/build.h
+++ b/src/build.h
@@ -21,9 +21,10 @@
#include <queue>
#include <vector>
#include <memory>
-using namespace std;
+#include <cstdio>
#include "exit_status.h"
+#include "metrics.h"
#include "util.h" // int64_t
struct BuildLog;
@@ -191,9 +192,43 @@ struct BuildStatus {
/// The custom progress status format to use.
const char* progress_status_format_;
+ struct RateInfo {
+ RateInfo() : last_update_(0), rate_(-1) {}
+
+ double rate() const { return rate_; }
+ int last_update() const { return last_update_; }
+ void Restart() { return stopwatch_.Restart(); }
+
+ double UpdateRate(int edges, int update_hint) {
+ if (update_hint != last_update_) {
+ rate_ = edges / stopwatch_.Elapsed() + 0.5;
+ last_update_ = update_hint;
+ }
+ return rate_;
+ }
+
+ template<class T>
+ void snprinfRate(T buf, const char* format) {
+ if (rate_ == -1)
+ snprintf(buf, sizeof(buf), "?");
+ else
+ snprintf(buf, sizeof(buf), format, rate_);
+ }
+
+ private:
+ Stopwatch stopwatch_;
+ int last_update_;
+ double rate_;
+ };
+
+ mutable RateInfo overall_rate_;
+ mutable RateInfo current_rate_;
+ const int current_rate_average_count_;
+
#ifdef _WIN32
void* console_;
#endif
};
#endif // NINJA_BUILD_H_
+
diff --git a/src/build_log.cc b/src/build_log.cc
index 0a44817..c35b0e4 100644
--- a/src/build_log.cc
+++ b/src/build_log.cc
@@ -164,7 +164,9 @@ void BuildLog::Close() {
class LineReader {
public:
explicit LineReader(FILE* file)
- : file_(file), buf_end_(buf_), line_start_(buf_), line_end_(NULL) {}
+ : file_(file), buf_end_(buf_), line_start_(buf_), line_end_(NULL) {
+ memset(buf_, 0, sizeof(buf_));
+ }
// Reads a \n-terminated line from the file passed to the constructor.
// On return, *line_start points to the beginning of the next line, and
@@ -235,6 +237,7 @@ bool BuildLog::Load(const string& path, string* err) {
if (log_version < kOldestSupportedVersion) {
*err = "unable to extract version from build log, perhaps due to "
"being too old; you must clobber your build output and rebuild";
+ fclose(file);
return false;
}
}
diff --git a/src/build_log_perftest.cc b/src/build_log_perftest.cc
index 51bb51b..5755079 100644
--- a/src/build_log_perftest.cc
+++ b/src/build_log_perftest.cc
@@ -17,9 +17,10 @@
#include "build_log.h"
#include "graph.h"
-#include "parsers.h"
+#include "manifest_parser.h"
#include "state.h"
#include "util.h"
+#include "metrics.h"
const char kTestFilename[] = "BuildLogPerfTest-tempfile";
diff --git a/src/build_log_test.cc b/src/build_log_test.cc
index 9fb42c9..0225684 100644
--- a/src/build_log_test.cc
+++ b/src/build_log_test.cc
@@ -131,7 +131,7 @@ TEST_F(BuildLogTest, Truncate) {
ASSERT_GT(statbuf.st_size, 0);
// For all possible truncations of the input file, assert that we don't
- // crash or report an error when parsing.
+ // crash when parsing.
for (off_t size = statbuf.st_size; size > 0; --size) {
#ifndef _WIN32
ASSERT_EQ(0, truncate(kTestFilename, size));
@@ -143,8 +143,8 @@ TEST_F(BuildLogTest, Truncate) {
#endif
BuildLog log2;
- EXPECT_TRUE(log2.Load(kTestFilename, &err));
- ASSERT_EQ("", err);
+ err.clear();
+ ASSERT_TRUE(log2.Load(kTestFilename, &err) || !err.empty());
}
}
diff --git a/src/build_test.cc b/src/build_test.cc
index 23f1909..a3f345b 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -802,6 +802,60 @@ TEST_F(BuildWithLogTest, RestatMissingFile) {
ASSERT_EQ(1u, commands_ran_.size());
}
+// Test scenario, in which an input file is removed, but output isn't changed
+// https://github.com/martine/ninja/issues/295
+TEST_F(BuildWithLogTest, RestatMissingInput) {
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+ "rule true\n"
+ " command = true\n"
+ " depfile = $out.d\n"
+ " restat = 1\n"
+ "rule cc\n"
+ " command = cc\n"
+ "build out1: true in\n"
+ "build out2: cc out1\n"));
+
+ // Create all necessary files
+ fs_.Create("in", now_, "");
+
+ // The implicit dependencies and the depfile itself
+ // are newer than the output
+ TimeStamp restat_mtime = ++now_;
+ fs_.Create("out1.d", now_, "out1: will.be.deleted restat.file\n");
+ fs_.Create("will.be.deleted", now_, "");
+ fs_.Create("restat.file", now_, "");
+
+ // Run the build, out1 and out2 get built
+ string err;
+ EXPECT_TRUE(builder_.AddTarget("out2", &err));
+ ASSERT_EQ("", err);
+ EXPECT_TRUE(builder_.Build(&err));
+ ASSERT_EQ(2u, commands_ran_.size());
+
+ // See that an entry in the logfile is created, capturing
+ // the right mtime
+ BuildLog::LogEntry * log_entry = build_log_.LookupByOutput("out1");
+ ASSERT_TRUE(NULL != log_entry);
+ ASSERT_EQ(restat_mtime, log_entry->restat_mtime);
+
+ // Now remove a file, referenced from depfile, so that target becomes
+ // dirty, but the output does not change
+ fs_.RemoveFile("will.be.deleted");
+
+ // Trigger the build again - only out1 gets built
+ commands_ran_.clear();
+ state_.Reset();
+ EXPECT_TRUE(builder_.AddTarget("out2", &err));
+ ASSERT_EQ("", err);
+ EXPECT_TRUE(builder_.Build(&err));
+ ASSERT_EQ(1u, commands_ran_.size());
+
+ // Check that the logfile entry remains correctly set
+ log_entry = build_log_.LookupByOutput("out1");
+ ASSERT_TRUE(NULL != log_entry);
+ ASSERT_EQ(restat_mtime, log_entry->restat_mtime);
+}
+
struct BuildDryRun : public BuildWithLogTest {
BuildDryRun() {
config_.dry_run = true;
diff --git a/src/canon_perftest.cc b/src/canon_perftest.cc
index 6248937..d0ed397 100644
--- a/src/canon_perftest.cc
+++ b/src/canon_perftest.cc
@@ -16,6 +16,7 @@
#include <string.h>
#include "util.h"
+#include "metrics.h"
const char kPath[] =
"../../third_party/WebKit/Source/WebCore/"
diff --git a/src/clean.h b/src/clean.h
index 4d9b4e6..5938dff 100644
--- a/src/clean.h
+++ b/src/clean.h
@@ -14,7 +14,6 @@
#ifndef NINJA_CLEAN_H_
#define NINJA_CLEAN_H_
-#pragma once
#include <set>
#include <string>
diff --git a/src/depfile_parser.cc b/src/depfile_parser.cc
index b6ea1ce..47b64d1 100644
--- a/src/depfile_parser.cc
+++ b/src/depfile_parser.cc
@@ -56,8 +56,8 @@ bool DepfileParser::Parse(string* content, string* err) {
0, 0, 0, 0, 0, 0, 0, 0,
128, 128, 0, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 0, 0, 0, 0, 0,
- 0, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 0, 0, 128, 0, 0,
+ 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 0, 0, 0, 0, 128,
@@ -84,27 +84,35 @@ bool DepfileParser::Parse(string* content, string* err) {
};
yych = *in;
- if (yych <= '[') {
+ if (yych <= 'Z') {
if (yych <= '*') {
if (yych <= 0x00) goto yy6;
if (yych <= '\'') goto yy8;
if (yych <= ')') goto yy4;
goto yy8;
} else {
- if (yych <= ':') goto yy4;
- if (yych <= '@') goto yy8;
- if (yych <= 'Z') goto yy4;
- goto yy8;
+ if (yych <= '<') {
+ if (yych <= ':') goto yy4;
+ goto yy8;
+ } else {
+ if (yych <= '=') goto yy4;
+ if (yych <= '?') goto yy8;
+ goto yy4;
+ }
}
} else {
- if (yych <= '`') {
- if (yych <= '\\') goto yy2;
- if (yych == '_') goto yy4;
- goto yy8;
+ if (yych <= '_') {
+ if (yych == '\\') goto yy2;
+ if (yych <= '^') goto yy8;
+ goto yy4;
} else {
- if (yych <= 'z') goto yy4;
- if (yych == '~') goto yy4;
- goto yy8;
+ if (yych <= 'z') {
+ if (yych <= '`') goto yy8;
+ goto yy4;
+ } else {
+ if (yych == '~') goto yy4;
+ goto yy8;
+ }
}
}
yy2:
diff --git a/src/depfile_parser.in.cc b/src/depfile_parser.in.cc
index 8c415b9..68b6a95 100644
--- a/src/depfile_parser.in.cc
+++ b/src/depfile_parser.in.cc
@@ -68,7 +68,7 @@ bool DepfileParser::Parse(string* content, string* err) {
*out++ = yych;
continue;
}
- [a-zA-Z0-9+,/_:.~()-]+ {
+ [a-zA-Z0-9+,/_:.~()@=-]+ {
// Got a span of plain text.
int len = in - start;
// Need to shift it over if we're overwriting backslashes.
diff --git a/src/depfile_parser_test.cc b/src/depfile_parser_test.cc
index fd76ae7..2bb9105 100644
--- a/src/depfile_parser_test.cc
+++ b/src/depfile_parser_test.cc
@@ -106,12 +106,17 @@ TEST_F(DepfileParserTest, Escapes) {
TEST_F(DepfileParserTest, SpecialChars) {
string err;
EXPECT_TRUE(Parse(
-"C:/Program\\ Files\\ (x86)/Microsoft\\ crtdefs.h:",
+"C:/Program\\ Files\\ (x86)/Microsoft\\ crtdefs.h: \n"
+" en@quot.header~ t+t-x=1",
&err));
ASSERT_EQ("", err);
EXPECT_EQ("C:/Program Files (x86)/Microsoft crtdefs.h",
parser_.out_.AsString());
- ASSERT_EQ(0u, parser_.ins_.size());
+ ASSERT_EQ(2u, parser_.ins_.size());
+ EXPECT_EQ("en@quot.header~",
+ parser_.ins_[0].AsString());
+ EXPECT_EQ("t+t-x=1",
+ parser_.ins_[1].AsString());
}
TEST_F(DepfileParserTest, UnifyMultipleOutputs) {
diff --git a/src/getopt.c b/src/getopt.c
index 1e3c09d..75ef99c 100644
--- a/src/getopt.c
+++ b/src/getopt.c
@@ -91,10 +91,6 @@ gpietsch@comcast.net
#include "getopt.h"
#endif
-#ifdef _WIN32
-#pragma warning(disable: 4701)
-#endif
-
/* macros */
/* types */
@@ -159,7 +155,7 @@ getopt_internal (int argc, char **argv, char *shortopts,
char *possible_arg = NULL;
int longopt_match = -1;
int has_arg = -1;
- char *cp;
+ char *cp = NULL;
int arg_next = 0;
/* first, deal with silly parameters and easy stuff */
@@ -255,7 +251,7 @@ getopt_internal (int argc, char **argv, char *shortopts,
longopts[optindex].name, match_chars) == 0)
{
/* do we have an exact match? */
- if (match_chars == (int) (strlen (longopts[optindex].name)))
+ if (match_chars == strlen (longopts[optindex].name))
{
longopt_match = optindex;
break;
diff --git a/src/graph.cc b/src/graph.cc
index 4bf558a..caf2aca 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -21,8 +21,8 @@
#include "depfile_parser.h"
#include "disk_interface.h"
#include "explain.h"
+#include "manifest_parser.h"
#include "metrics.h"
-#include "parsers.h"
#include "state.h"
#include "util.h"
@@ -140,7 +140,10 @@ bool Edge::RecomputeOutputDirty(BuildLog* build_log,
if (rule_->restat() && build_log &&
(entry = build_log->LookupByOutput(output->path()))) {
if (entry->restat_mtime < most_recent_input) {
- EXPLAIN("restat of output %s older than inputs", output->path().c_str());
+ EXPLAIN("restat of output %s older than most recent input %s (%d vs %d)",
+ output->path().c_str(),
+ most_recent_node ? most_recent_node->path().c_str() : "",
+ entry->restat_mtime, most_recent_input);
return true;
}
} else {
diff --git a/src/lexer.cc b/src/lexer.cc
index 48a46b0..45bf4ef 100644
--- a/src/lexer.cc
+++ b/src/lexer.cc
@@ -127,7 +127,7 @@ Lexer::Token Lexer::ReadToken() {
unsigned int yyaccept = 0;
static const unsigned char yybm[] = {
0, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 0, 64, 64, 64, 64, 64,
+ 64, 64, 0, 64, 64, 0, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
192, 64, 64, 64, 64, 64, 64, 64,
@@ -216,7 +216,8 @@ yy3:
yy4:
yyaccept = 1;
yych = *(q = ++p);
- if (yych >= 0x01) goto yy60;
+ if (yych <= 0x00) goto yy5;
+ if (yych != '\r') goto yy60;
yy5:
{ token = ERROR; break; }
yy6:
@@ -354,7 +355,9 @@ yy60:
if (yybm[0+yych] & 64) {
goto yy59;
}
- if (yych >= 0x01) goto yy62;
+ if (yych <= 0x00) goto yy61;
+ if (yych <= '\f') goto yy62;
+yy61:
p = q;
if (yyaccept <= 0) {
goto yy3;
@@ -576,7 +579,7 @@ bool Lexer::ReadEvalString(EvalString* eval, bool path, string* err) {
unsigned char yych;
static const unsigned char yybm[] = {
0, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 0, 128, 128, 128, 128, 128,
+ 128, 128, 0, 128, 128, 0, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
16, 128, 128, 128, 0, 128, 128, 128,
@@ -609,24 +612,25 @@ bool Lexer::ReadEvalString(EvalString* eval, bool path, string* err) {
128, 128, 128, 128, 128, 128, 128, 128,
};
yych = *p;
- if (yych <= '#') {
+ if (yych <= ' ') {
if (yych <= '\n') {
if (yych <= 0x00) goto yy96;
if (yych >= '\n') goto yy92;
} else {
- if (yych == ' ') goto yy92;
+ if (yych == '\r') goto yy98;
+ if (yych >= ' ') goto yy92;
}
} else {
- if (yych <= ':') {
- if (yych <= '$') goto yy94;
- if (yych >= ':') goto yy92;
+ if (yych <= '9') {
+ if (yych == '$') goto yy94;
} else {
+ if (yych <= ':') goto yy92;
if (yych == '|') goto yy92;
}
}
++p;
yych = *p;
- goto yy120;
+ goto yy121;
yy91:
{
eval->AddText(StringPiece(start, p - start));
@@ -649,39 +653,40 @@ yy94:
++p;
if ((yych = *p) <= '/') {
if (yych <= ' ') {
- if (yych == '\n') goto yy109;
- if (yych <= 0x1F) goto yy98;
- goto yy100;
+ if (yych == '\n') goto yy110;
+ if (yych <= 0x1F) goto yy99;
+ goto yy101;
} else {
if (yych <= '$') {
- if (yych <= '#') goto yy98;
- goto yy102;
+ if (yych <= '#') goto yy99;
+ goto yy103;
} else {
- if (yych == '-') goto yy104;
- goto yy98;
+ if (yych == '-') goto yy105;
+ goto yy99;
}
}
} else {
if (yych <= '^') {
if (yych <= ':') {
- if (yych <= '9') goto yy104;
- goto yy106;
+ if (yych <= '9') goto yy105;
+ goto yy107;
} else {
- if (yych <= '@') goto yy98;
- if (yych <= 'Z') goto yy104;
- goto yy98;
+ if (yych <= '@') goto yy99;
+ if (yych <= 'Z') goto yy105;
+ goto yy99;
}
} else {
if (yych <= '`') {
- if (yych <= '_') goto yy104;
- goto yy98;
+ if (yych <= '_') goto yy105;
+ goto yy99;
} else {
- if (yych <= 'z') goto yy104;
- if (yych <= '{') goto yy108;
- goto yy98;
+ if (yych <= 'z') goto yy105;
+ if (yych <= '{') goto yy109;
+ goto yy99;
}
}
}
+yy95:
{
last_token_ = start;
return Error("lexing error", err);
@@ -693,83 +698,86 @@ yy96:
return Error("unexpected EOF", err);
}
yy98:
- ++p;
+ yych = *++p;
+ goto yy95;
yy99:
+ ++p;
+yy100:
{
last_token_ = start;
return Error("bad $-escape (literal $ must be written as $$)", err);
}
-yy100:
+yy101:
++p;
{
eval->AddText(StringPiece(" ", 1));
continue;
}
-yy102:
+yy103:
++p;
{
eval->AddText(StringPiece("$", 1));
continue;
}
-yy104:
+yy105:
++p;
yych = *p;
- goto yy118;
-yy105:
+ goto yy119;
+yy106:
{
eval->AddSpecial(StringPiece(start + 1, p - start - 1));
continue;
}
-yy106:
+yy107:
++p;
{
eval->AddText(StringPiece(":", 1));
continue;
}
-yy108:
+yy109:
yych = *(q = ++p);
if (yybm[0+yych] & 32) {
- goto yy112;
+ goto yy113;
}
- goto yy99;
-yy109:
+ goto yy100;
+yy110:
++p;
yych = *p;
if (yybm[0+yych] & 16) {
- goto yy109;
+ goto yy110;
}
{
continue;
}
-yy112:
+yy113:
++p;
yych = *p;
if (yybm[0+yych] & 32) {
- goto yy112;
+ goto yy113;
}
- if (yych == '}') goto yy115;
+ if (yych == '}') goto yy116;
p = q;
- goto yy99;
-yy115:
+ goto yy100;
+yy116:
++p;
{
eval->AddSpecial(StringPiece(start + 2, p - start - 3));
continue;
}
-yy117:
+yy118:
++p;
yych = *p;
-yy118:
+yy119:
if (yybm[0+yych] & 64) {
- goto yy117;
+ goto yy118;
}
- goto yy105;
-yy119:
+ goto yy106;
+yy120:
++p;
yych = *p;
-yy120:
+yy121:
if (yybm[0+yych] & 128) {
- goto yy119;
+ goto yy120;
}
goto yy91;
}
diff --git a/src/lexer.in.cc b/src/lexer.in.cc
index e478921..852d6e9 100644
--- a/src/lexer.in.cc
+++ b/src/lexer.in.cc
@@ -130,7 +130,7 @@ Lexer::Token Lexer::ReadToken() {
simple_varname = [a-zA-Z0-9_-]+;
varname = [a-zA-Z0-9_.-]+;
- [ ]*"#"[^\000\n]*"\n" { continue; }
+ [ ]*"#"[^\000\r\n]*"\n" { continue; }
[ ]*[\n] { token = NEWLINE; break; }
[ ]+ { token = INDENT; break; }
"build" { token = BUILD; break; }
@@ -200,7 +200,7 @@ bool Lexer::ReadEvalString(EvalString* eval, bool path, string* err) {
for (;;) {
start = p;
/*!re2c
- [^$ :\n|\000]+ {
+ [^$ :\r\n|\000]+ {
eval->AddText(StringPiece(start, p - start));
continue;
}
diff --git a/src/parsers.cc b/src/manifest_parser.cc
index bc76ba1..057e12c 100644
--- a/src/parsers.cc
+++ b/src/manifest_parser.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "parsers.h"
+#include "manifest_parser.h"
#include <assert.h>
#include <errno.h>
diff --git a/src/parsers.h b/src/manifest_parser.h
index f889156..a2c6c93 100644
--- a/src/parsers.h
+++ b/src/manifest_parser.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef NINJA_PARSERS_H_
-#define NINJA_PARSERS_H_
+#ifndef NINJA_MANIFEST_PARSER_H_
+#define NINJA_MANIFEST_PARSER_H_
#include <string>
#include <vector>
@@ -68,4 +68,4 @@ private:
Lexer lexer_;
};
-#endif // NINJA_PARSERS_H_
+#endif // NINJA_MANIFEST_PARSER_H_
diff --git a/src/parsers_test.cc b/src/manifest_parser_test.cc
index fc83946..3261d39 100644
--- a/src/parsers_test.cc
+++ b/src/manifest_parser_test.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "parsers.h"
+#include "manifest_parser.h"
#include <gtest/gtest.h>
@@ -682,3 +682,23 @@ TEST_F(ParserTest, UTF8) {
" command = true\n"
" description = compilaci\xC3\xB3\n"));
}
+
+// We might want to eventually allow CRLF to be nice to Windows developers,
+// but for now just verify we error out with a nice message.
+TEST_F(ParserTest, CRLF) {
+ State state;
+ ManifestParser parser(&state, NULL);
+ string err;
+
+ EXPECT_FALSE(parser.ParseTest("# comment with crlf\r\n",
+ &err));
+ EXPECT_EQ("input:1: lexing error\n",
+ err);
+
+ EXPECT_FALSE(parser.ParseTest("foo = foo\nbar = bar\r\n",
+ &err));
+ EXPECT_EQ("input:2: lexing error\n"
+ "bar = bar\r\n"
+ " ^ near here",
+ err);
+}
diff --git a/src/metrics.cc b/src/metrics.cc
index fb44868..8407717 100644
--- a/src/metrics.cc
+++ b/src/metrics.cc
@@ -72,6 +72,7 @@ int64_t TimerToMicros(int64_t dt) {
} // anonymous namespace
+
ScopedMetric::ScopedMetric(Metric* metric) {
metric_ = metric;
if (!metric_)
@@ -113,3 +114,12 @@ void Metrics::Report() {
metric->count, avg, total);
}
}
+
+uint64_t Stopwatch::Now() const {
+ return TimerToMicros(HighResTimer());
+}
+
+int64_t GetTimeMillis() {
+ return 1000 * TimerToMicros(HighResTimer());
+}
+
diff --git a/src/metrics.h b/src/metrics.h
index af6e9a2..dae6b9f 100644
--- a/src/metrics.h
+++ b/src/metrics.h
@@ -33,6 +33,7 @@ struct Metric {
int64_t sum;
};
+
/// A scoped object for recording a metric across the body of a function.
/// Used by the METRIC_RECORD macro.
struct ScopedMetric {
@@ -57,6 +58,30 @@ private:
vector<Metric*> metrics_;
};
+/// Get the current time as relative to some epoch.
+/// Epoch varies between platforms; only useful for measuring elapsed
+/// time.
+int64_t GetTimeMillis();
+
+
+/// A simple stopwatch which retruns the time
+// in seconds since Restart() was called
+class Stopwatch
+{
+public:
+ Stopwatch() : started_(0) {}
+
+ /// Seconds since Restart() call
+ double Elapsed() const { return 1e-6 * (Now() - started_); }
+
+ void Restart() { started_ = Now(); }
+
+private:
+ uint64_t started_;
+ uint64_t Now() const;
+};
+
+
/// The primary interface to metrics. Use METRIC_RECORD("foobar") at the top
/// of a function to get timing stats recorded for each call of the function.
#define METRIC_RECORD(name) \
diff --git a/src/ninja.cc b/src/ninja.cc
index 6090bdb..619c3bf 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -42,8 +42,8 @@
#include "explain.h"
#include "graph.h"
#include "graphviz.h"
+#include "manifest_parser.h"
#include "metrics.h"
-#include "parsers.h"
#include "state.h"
#include "util.h"
@@ -707,7 +707,10 @@ int main(int argc, char** argv) {
// The formatting of this string, complete with funny quotes, is
// so Emacs can properly identify that the cwd has changed for
// subsequent commands.
- printf("ninja: Entering directory `%s'\n", working_dir);
+ // Don't print this if a tool is being used, so that tool output
+ // can be piped into a file without this string showing up.
+ if (tool == "")
+ printf("ninja: Entering directory `%s'\n", working_dir);
#ifdef _WIN32
if (_chdir(working_dir) < 0) {
#else
diff --git a/src/parser_perftest.cc b/src/parser_perftest.cc
index b1d5bf0..b215221 100644
--- a/src/parser_perftest.cc
+++ b/src/parser_perftest.cc
@@ -17,6 +17,7 @@
#include "depfile_parser.h"
#include "util.h"
+#include "metrics.h"
int main(int argc, char* argv[]) {
if (argc < 2) {
diff --git a/src/state.h b/src/state.h
index 23ca12b..9197ef8 100644
--- a/src/state.h
+++ b/src/state.h
@@ -14,7 +14,6 @@
#ifndef NINJA_STATE_H_
#define NINJA_STATE_H_
-#pragma once
#include <map>
#include <string>
diff --git a/src/subprocess-win32.cc b/src/subprocess-win32.cc
index 3484e5f..38b6957 100644
--- a/src/subprocess-win32.cc
+++ b/src/subprocess-win32.cc
@@ -44,7 +44,7 @@ Subprocess::~Subprocess() {
HANDLE Subprocess::SetupPipe(HANDLE ioport) {
char pipe_name[100];
snprintf(pipe_name, sizeof(pipe_name),
- "\\\\.\\pipe\\ninja_pid%u_sp%p", GetCurrentProcessId(), this);
+ "\\\\.\\pipe\\ninja_pid%lu_sp%p", GetCurrentProcessId(), this);
pipe_ = ::CreateNamedPipeA(pipe_name,
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
@@ -271,9 +271,12 @@ Subprocess* SubprocessSet::NextFinished() {
void SubprocessSet::Clear() {
for (vector<Subprocess*>::iterator i = running_.begin();
i != running_.end(); ++i) {
- if ((*i)->child_)
- if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, GetProcessId((*i)->child_)))
+ if ((*i)->child_) {
+ if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
+ GetProcessId((*i)->child_))) {
Win32Fatal("GenerateConsoleCtrlEvent");
+ }
+ }
}
for (vector<Subprocess*>::iterator i = running_.begin();
i != running_.end(); ++i)
diff --git a/src/subprocess.cc b/src/subprocess.cc
index 0d240b1..1c47fd1 100644
--- a/src/subprocess.cc
+++ b/src/subprocess.cc
@@ -25,6 +25,13 @@
#include <string.h>
#include <sys/wait.h>
+// Older versions of glibc (like 2.4) won't find this in <poll.h>. glibc
+// 2.4 keeps it in <asm-generic/poll.h>, though attempting to include that
+// will redefine the pollfd structure.
+#ifndef POLLRDHUP
+#define POLLRDHUP 0x2000
+#endif
+
#include "util.h"
Subprocess::Subprocess() : fd_(-1), pid_(-1) {
diff --git a/src/subprocess_test.cc b/src/subprocess_test.cc
index c155012..7dbaf97 100644
--- a/src/subprocess_test.cc
+++ b/src/subprocess_test.cc
@@ -16,6 +16,13 @@
#include "test.h"
+#ifndef _WIN32
+// SetWithLots need setrlimit.
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#endif
+
namespace {
#ifdef _WIN32
@@ -142,7 +149,7 @@ TEST_F(SubprocessTest, SetWithMulti) {
}
}
-#ifdef linux
+#ifndef _WIN32
TEST_F(SubprocessTest, SetWithLots) {
// Arbitrary big number; needs to be over 1024 to confirm we're no longer
// hostage to pselect.
@@ -169,4 +176,4 @@ TEST_F(SubprocessTest, SetWithLots) {
}
ASSERT_EQ(kNumProcs, subprocs_.finished_.size());
}
-#endif // linux
+#endif // _WIN32
diff --git a/src/test.cc b/src/test.cc
index afedd10..0138b3a 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -19,7 +19,7 @@
#include <errno.h>
#include "build_log.h"
-#include "parsers.h"
+#include "manifest_parser.h"
#include "util.h"
#ifdef _WIN32
diff --git a/src/util.cc b/src/util.cc
index d8d7fb3..ca05292 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -43,7 +43,7 @@
void Fatal(const char* msg, ...) {
va_list ap;
- fprintf(stderr, "ninja: FATAL: ");
+ fprintf(stderr, "ninja: fatal: ");
va_start(ap, msg);
vfprintf(stderr, msg, ap);
va_end(ap);
@@ -61,7 +61,7 @@ void Fatal(const char* msg, ...) {
void Warning(const char* msg, ...) {
va_list ap;
- fprintf(stderr, "ninja: WARNING: ");
+ fprintf(stderr, "ninja: warning: ");
va_start(ap, msg);
vfprintf(stderr, msg, ap);
va_end(ap);
@@ -70,7 +70,7 @@ void Warning(const char* msg, ...) {
void Error(const char* msg, ...) {
va_list ap;
- fprintf(stderr, "ninja: ERROR: ");
+ fprintf(stderr, "ninja: error: ");
va_start(ap, msg);
vfprintf(stderr, msg, ap);
va_end(ap);
@@ -204,16 +204,6 @@ void SetCloseOnExec(int fd) {
#endif // ! _WIN32
}
-int64_t GetTimeMillis() {
-#ifdef _WIN32
- // GetTickCount64 is only available on Vista or later.
- return GetTickCount();
-#else
- timeval now;
- gettimeofday(&now, NULL);
- return ((int64_t)now.tv_sec * 1000) + (now.tv_usec / 1000);
-#endif
-}
const char* SpellcheckStringV(const string& text,
const vector<const char*>& words) {
diff --git a/src/util.h b/src/util.h
index 82f4850..5caf644 100644
--- a/src/util.h
+++ b/src/util.h
@@ -14,7 +14,6 @@
#ifndef NINJA_UTIL_H_
#define NINJA_UTIL_H_
-#pragma once
#ifdef _WIN32
#include "win32port.h"
@@ -53,11 +52,6 @@ int ReadFile(const string& path, string* contents, string* err);
/// Mark a file descriptor to not be inherited on exec()s.
void SetCloseOnExec(int fd);
-/// Get the current time as relative to some epoch.
-/// Epoch varies between platforms; only useful for measuring elapsed
-/// time.
-int64_t GetTimeMillis();
-
/// Given a misspelled string and a list of correct spellings, returns
/// the closest match or NULL if there is no close enough match.
const char* SpellcheckStringV(const string& text, const vector<const char*>& words);
diff --git a/src/win32port.h b/src/win32port.h
index 8b42b38..ce3c949 100644
--- a/src/win32port.h
+++ b/src/win32port.h
@@ -14,8 +14,9 @@
#ifndef NINJA_WIN32PORT_H_
#define NINJA_WIN32PORT_H_
-#pragma once
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
/// A 64-bit integer type
typedef signed long long int64_t;
typedef unsigned long long uint64_t;