From f1b5d2bf37ba6cd10bf7ab4b51877d68eae97cbc Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 28 Apr 2016 12:32:31 -0700 Subject: Fix NINJA_STATUS %e on dumb terminals PR #999 made dumb terminals only output when edges finish. BuildStatus::overall_rate_ stopwatch is only initialized to the current time when PrintStatus is called with finished_edges_ == 0, but on a dumb terminal it will be called for the first time when finished_edge_ = 1, which results in very long elapsed times: NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es ] " [0 processes, 2/2 @ 0.0/s : 1461869902.367s ] Reset the stopwatches in BuildEdgeFinished before finshed_edges_ is incremented instead. --- src/build.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/build.cc b/src/build.cc index 8c0fbf8..2c39636 100644 --- a/src/build.cc +++ b/src/build.cc @@ -109,6 +109,12 @@ void BuildStatus::BuildEdgeFinished(Edge* edge, int* start_time, int* end_time) { int64_t now = GetTimeMillis(); + + if (finished_edges_ == 0) { + overall_rate_.Restart(); + current_rate_.Restart(); + } + ++finished_edges_; RunningEdgeMap::iterator i = running_edges_.find(edge); @@ -256,10 +262,6 @@ void BuildStatus::PrintStatus(Edge* edge) { if (to_print.empty() || force_full_command) to_print = edge->GetBinding("command"); - if (finished_edges_ == 0) { - overall_rate_.Restart(); - current_rate_.Restart(); - } to_print = FormatProgressStatus(progress_status_format_) + to_print; printer_.Print(to_print, -- cgit v0.12 From af4973d2251bf9bc616ceb5f9d9d64dd948ed569 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 28 Apr 2016 12:36:49 -0700 Subject: Fix NINJA_STATUS %r on dumb terminals PR #999 made dumb terminals only output when edges finish. PrintStatus is called after finished_edges_ is incremented, which means the calculation for running edges will always return 1 less than the real number of running processes. This happens on smart terminals too, but ninja will immediately print the status for the next edge with starting_edges_ incremented, so the incorrect value is never visible. Pass a boolean specifying whether the status is being printed on an edge finishing, and if so count the edge that just finished as being running. --- src/build.cc | 19 ++++++++++++------- src/build.h | 11 +++++++++-- src/build_test.cc | 6 ++++-- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/build.cc b/src/build.cc index 2c39636..7792016 100644 --- a/src/build.cc +++ b/src/build.cc @@ -97,7 +97,7 @@ void BuildStatus::BuildEdgeStarted(Edge* edge) { ++started_edges_; if (edge->use_console() || printer_.is_smart_terminal()) - PrintStatus(edge); + PrintStatus(edge, kEdgeStarted); if (edge->use_console()) printer_.SetConsoleLocked(true); @@ -129,7 +129,7 @@ void BuildStatus::BuildEdgeFinished(Edge* edge, return; if (!edge->use_console()) - PrintStatus(edge); + PrintStatus(edge, kEdgeFinished); // Print the command that is spewing before printing its output. if (!success) { @@ -170,7 +170,7 @@ void BuildStatus::BuildFinished() { } string BuildStatus::FormatProgressStatus( - const char* progress_status_format) const { + const char* progress_status_format, EdgeStatus status) const { string out; char buf[32]; int percent; @@ -195,10 +195,15 @@ string BuildStatus::FormatProgressStatus( break; // Running edges. - case 'r': - snprintf(buf, sizeof(buf), "%d", started_edges_ - finished_edges_); + case 'r': { + int running_edges = started_edges_ - finished_edges_; + // count the edge that just finished as a running edge + if (status == kEdgeFinished) + running_edges++; + snprintf(buf, sizeof(buf), "%d", running_edges); out += buf; break; + } // Unstarted edges. case 'u': @@ -252,7 +257,7 @@ string BuildStatus::FormatProgressStatus( return out; } -void BuildStatus::PrintStatus(Edge* edge) { +void BuildStatus::PrintStatus(Edge* edge, EdgeStatus status) { if (config_.verbosity == BuildConfig::QUIET) return; @@ -262,7 +267,7 @@ void BuildStatus::PrintStatus(Edge* edge) { if (to_print.empty() || force_full_command) to_print = edge->GetBinding("command"); - to_print = FormatProgressStatus(progress_status_format_) + to_print; + to_print = FormatProgressStatus(progress_status_format_, status) + to_print; printer_.Print(to_print, force_full_command ? LinePrinter::FULL : LinePrinter::ELIDE); diff --git a/src/build.h b/src/build.h index 51589ef..819d832 100644 --- a/src/build.h +++ b/src/build.h @@ -202,14 +202,21 @@ struct BuildStatus { int* start_time, int* end_time); void BuildFinished(); + enum EdgeStatus { + kEdgeStarted, + kEdgeFinished, + }; + /// Format the progress status string by replacing the placeholders. /// See the user manual for more information about the available /// placeholders. /// @param progress_status_format The format of the progress status. - string FormatProgressStatus(const char* progress_status_format) const; + /// @param finished True if the edge being printed just finished + string FormatProgressStatus(const char* progress_status_format, + EdgeStatus kEdgeFinished) const; private: - void PrintStatus(Edge* edge); + void PrintStatus(Edge* edge, EdgeStatus status); const BuildConfig& config_; diff --git a/src/build_test.cc b/src/build_test.cc index 55d093e..06871d2 100644 --- a/src/build_test.cc +++ b/src/build_test.cc @@ -1286,7 +1286,8 @@ TEST_F(BuildWithLogTest, RestatTest) { ASSERT_EQ("", err); EXPECT_TRUE(builder_.Build(&err)); ASSERT_EQ("", err); - EXPECT_EQ("[3/3]", builder_.status_->FormatProgressStatus("[%s/%t]")); + EXPECT_EQ("[3/3]", builder_.status_->FormatProgressStatus("[%s/%t]", + BuildStatus::kEdgeStarted)); command_runner_.commands_ran_.clear(); state_.Reset(); @@ -1726,7 +1727,8 @@ TEST_F(BuildTest, DepsGccWithEmptyDepfileErrorsOut) { TEST_F(BuildTest, StatusFormatReplacePlaceholder) { EXPECT_EQ("[%/s0/t0/r0/u0/f0]", - status_.FormatProgressStatus("[%%/s%s/t%t/r%r/u%u/f%f]")); + status_.FormatProgressStatus("[%%/s%s/t%t/r%r/u%u/f%f]", + BuildStatus::kEdgeStarted)); } TEST_F(BuildTest, FailedDepsParse) { -- cgit v0.12 From 28cedf169580f0b9847f2330a00dec9dd6041ab5 Mon Sep 17 00:00:00 2001 From: KiYugadgeter Date: Tue, 3 May 2016 13:32:47 +0900 Subject: Make misc/measure.py compatible with python3 --- misc/measure.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/misc/measure.py b/misc/measure.py index 1323fc6..8ce95e6 100755 --- a/misc/measure.py +++ b/misc/measure.py @@ -17,6 +17,8 @@ """measure the runtime of a command by repeatedly running it. """ +from __future__ import print_function + import time import subprocess import sys @@ -24,7 +26,7 @@ import sys devnull = open('/dev/null', 'w') def run(cmd, repeat=10): - print 'sampling:', + print('sampling:', end=' ') sys.stdout.flush() samples = [] @@ -33,10 +35,10 @@ def run(cmd, repeat=10): subprocess.call(cmd, stdout=devnull, stderr=devnull) end = time.time() dt = (end - start) * 1000 - print '%dms' % int(dt), + print('%dms' % int(dt), end=' ') sys.stdout.flush() samples.append(dt) - print + print() # We're interested in the 'pure' runtime of the code, which is # conceptually the smallest time we'd see if we ran it enough times @@ -45,10 +47,10 @@ def run(cmd, repeat=10): # Also print how varied the outputs were in an attempt to make it # more obvious if something has gone terribly wrong. err = sum(s - best for s in samples) / float(len(samples)) - print 'estimate: %dms (mean err %.1fms)' % (best, err) + print('estimate: %dms (mean err %.1fms)' % (best, err)) if __name__ == '__main__': if len(sys.argv) < 2: - print 'usage: measure.py command args...' + print('usage: measure.py command args...') sys.exit(1) run(cmd=sys.argv[1:]) -- cgit v0.12 From ccaa3d1c9c8a581ce0cd696a3b0d6ab713908e40 Mon Sep 17 00:00:00 2001 From: Nicolas Despres Date: Tue, 24 May 2016 12:12:28 +0200 Subject: Parser accepts no explicit outputs. There is a class of commands that take an output directory where they create their output files. Among them are cp(1), tar(1) to name a few. These commands have one or more implicit outputs but no explicit output. With this patch, Ninja's parser accepts build edge with an empty list of explicit outputs. --- src/graph_test.cc | 39 +++++++++++++++++++++++++++++++++++++++ src/manifest_parser.cc | 10 +++++----- src/manifest_parser_test.cc | 5 +---- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/graph_test.cc b/src/graph_test.cc index 723e8ea..be08b19 100644 --- a/src/graph_test.cc +++ b/src/graph_test.cc @@ -149,6 +149,45 @@ TEST_F(GraphTest, ImplicitOutputOutOfDate) { EXPECT_TRUE(GetNode("out.imp")->dirty()); } +TEST_F(GraphTest, ImplicitOutputOnlyParse) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"build | out.imp: cat in\n")); + + Edge* edge = GetNode("out.imp")->in_edge(); + EXPECT_EQ(1, edge->outputs_.size()); + EXPECT_EQ("out.imp", edge->outputs_[0]->path()); + EXPECT_EQ(1, edge->implicit_outs_); + EXPECT_EQ(edge, GetNode("out.imp")->in_edge()); +} + +TEST_F(GraphTest, ImplicitOutputOnlyMissing) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"build | out.imp: cat in\n")); + fs_.Create("in", ""); + + Edge* edge = GetNode("out.imp")->in_edge(); + string err; + EXPECT_TRUE(scan_.RecomputeDirty(edge, &err)); + ASSERT_EQ("", err); + + EXPECT_TRUE(GetNode("out.imp")->dirty()); +} + +TEST_F(GraphTest, ImplicitOutputOnlyOutOfDate) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"build | out.imp: cat in\n")); + fs_.Create("out.imp", ""); + fs_.Tick(); + fs_.Create("in", ""); + + Edge* edge = GetNode("out.imp")->in_edge(); + string err; + EXPECT_TRUE(scan_.RecomputeDirty(edge, &err)); + ASSERT_EQ("", err); + + EXPECT_TRUE(GetNode("out.imp")->dirty()); +} + TEST_F(GraphTest, PathWithCurrentDirectory) { ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, "rule catdep\n" diff --git a/src/manifest_parser.cc b/src/manifest_parser.cc index a4f489e..d6dcf22 100644 --- a/src/manifest_parser.cc +++ b/src/manifest_parser.cc @@ -236,16 +236,13 @@ bool ManifestParser::ParseEdge(string* err) { EvalString out; if (!lexer_.ReadPath(&out, err)) return false; - if (out.empty()) - return lexer_.Error("expected path", err); - - do { + while (!out.empty()) { outs.push_back(out); out.Clear(); if (!lexer_.ReadPath(&out, err)) return false; - } while (!out.empty()); + } } // Add all implicit outs, counting how many as we go. @@ -262,6 +259,9 @@ bool ManifestParser::ParseEdge(string* err) { } } + if (outs.empty()) + return lexer_.Error("expected path", err); + if (!ExpectToken(Lexer::COLON, err)) return false; diff --git a/src/manifest_parser_test.cc b/src/manifest_parser_test.cc index 1312d26..3c82dc5 100644 --- a/src/manifest_parser_test.cc +++ b/src/manifest_parser_test.cc @@ -976,13 +976,10 @@ TEST_F(ParserTest, ImplicitOutputDupes) { TEST_F(ParserTest, NoExplicitOutput) { ManifestParser parser(&state, NULL, kDupeEdgeActionWarn); string err; - EXPECT_FALSE(parser.ParseTest( + EXPECT_TRUE(parser.ParseTest( "rule cat\n" " command = cat $in > $out\n" "build | imp : cat bar\n", &err)); - ASSERT_EQ("input:3: expected path\n" - "build | imp : cat bar\n" - " ^ near here", err); } TEST_F(ParserTest, DefaultDefault) { -- cgit v0.12 From 8aeb91ebb12057b34b60084311ef4c790311559f Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 20 May 2016 15:24:56 -0700 Subject: Escape ninja output inserted into HTML Ninja query or error output may contain characters that need to be escaped when being inserted into HTML. Replace &, ", <, and > with their & equivalent. --- src/browse.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/browse.py b/src/browse.py index 32792f3..4b4faa8 100755 --- a/src/browse.py +++ b/src/browse.py @@ -27,6 +27,7 @@ try: except ImportError: import BaseHTTPServer as httpserver import argparse +import cgi import os import socket import subprocess @@ -58,6 +59,9 @@ def match_strip(line, prefix): return (False, line) return (True, line[len(prefix):]) +def html_escape(text): + return cgi.escape(text, quote=True) + def parse(text): lines = iter(text.split('\n')) @@ -124,19 +128,19 @@ tt { ''' + body def generate_html(node): - document = ['

%s

' % node.target] + document = ['

%s

' % html_escape(node.target)] if node.inputs: document.append('

target is built using rule %s of

' % - node.rule) + html_escape(node.rule)) if len(node.inputs) > 0: document.append('
') for input, type in sorted(node.inputs): extra = '' if type: - extra = ' (%s)' % type + extra = ' (%s)' % html_escape(type) document.append('%s%s
' % - (input, input, extra)) + (html_escape(input), html_escape(input), extra)) document.append('
') if node.outputs: @@ -144,7 +148,7 @@ def generate_html(node): document.append('
') for output in sorted(node.outputs): document.append('%s
' % - (output, output)) + (html_escape(output), html_escape(output))) document.append('
') return '\n'.join(document) @@ -177,7 +181,7 @@ class RequestHandler(httpserver.BaseHTTPRequestHandler): page_body = generate_html(parse(ninja_output.strip())) else: # Relay ninja's error message. - page_body = '

%s

' % ninja_error + page_body = '

%s

' % html_escape(ninja_error) self.send_response(200) self.end_headers() -- cgit v0.12 From 87ae5be1895899e71103160b43b903fb8b31f132 Mon Sep 17 00:00:00 2001 From: Nicolas Despres Date: Thu, 9 Jun 2016 18:14:22 +0200 Subject: Constify State::RootNodes(). --- src/state.cc | 9 +++++---- src/state.h | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/state.cc b/src/state.cc index a70f211..d539e7b 100644 --- a/src/state.cc +++ b/src/state.cc @@ -159,11 +159,12 @@ bool State::AddDefault(StringPiece path, string* err) { return true; } -vector State::RootNodes(string* err) { +vector State::RootNodes(string* err) const { vector root_nodes; // Search for nodes with no output. - for (vector::iterator e = edges_.begin(); e != edges_.end(); ++e) { - for (vector::iterator out = (*e)->outputs_.begin(); + for (vector::const_iterator e = edges_.begin(); + e != edges_.end(); ++e) { + for (vector::const_iterator out = (*e)->outputs_.begin(); out != (*e)->outputs_.end(); ++out) { if ((*out)->out_edges().empty()) root_nodes.push_back(*out); @@ -176,7 +177,7 @@ vector State::RootNodes(string* err) { return root_nodes; } -vector State::DefaultNodes(string* err) { +vector State::DefaultNodes(string* err) const { return defaults_.empty() ? RootNodes(err) : defaults_; } diff --git a/src/state.h b/src/state.h index d7987ba..b530207 100644 --- a/src/state.h +++ b/src/state.h @@ -110,8 +110,8 @@ struct State { /// @return the root node(s) of the graph. (Root nodes have no output edges). /// @param error where to write the error message if somethings went wrong. - vector RootNodes(string* error); - vector DefaultNodes(string* error); + vector RootNodes(string* error) const; + vector DefaultNodes(string* error) const; /// Mapping of path -> Node. typedef ExternalStringHashMap::Type Paths; -- cgit v0.12 From 1992ab65adfb796e1c65a1ca0631f31d5cce5eb0 Mon Sep 17 00:00:00 2001 From: Frank Benkstein Date: Tue, 21 Jun 2016 15:04:02 +0200 Subject: enhance write_fake_manifest.py Add an option to write_fake_manifest.py to generate sources expected by the manifest. Also slightly adapt command lines to the called commands. Together these changes mean that generated manifest can actually be executed successfully on Linux and OSX. Also add command line options to to change the number of targets being generated and the seed for the random number generator. Example usage: # create build directory in fake/build, sources in fake/src $ python misc/write_fake_manifest.py -s ../src fake/build # execute build in fake/build $ ninja -C fake/build --- misc/write_fake_manifests.py | 89 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 18 deletions(-) diff --git a/misc/write_fake_manifests.py b/misc/write_fake_manifests.py index ca49535..cec28de 100644 --- a/misc/write_fake_manifests.py +++ b/misc/write_fake_manifests.py @@ -50,9 +50,10 @@ def moar(avg_options, p_suffix): class GenRandom(object): - def __init__(self): + def __init__(self, src_dir): self.seen_names = set([None]) self.seen_defines = set([None]) + self.src_dir = src_dir def _unique_string(self, seen, avg_options=1.3, p_suffix=0.1): s = None @@ -76,7 +77,7 @@ class GenRandom(object): def src_obj_pairs(self, path, name): num_sources = paretoint(55, alpha=2) + 1 - return [(os.path.join('..', '..', path, s + '.cc'), + return [(os.path.join(self.src_dir, path, s + '.cc'), os.path.join('obj', path, '%s.%s.o' % (name, s))) for s in self._n_unique_strings(num_sources)] @@ -103,12 +104,8 @@ class Target(object): self.kind = kind self.has_compile_depends = random.random() < 0.4 - @property - def includes(self): - return ['-I' + dep.dir_path for dep in self.deps] - -def write_target_ninja(ninja, target): +def write_target_ninja(ninja, target, src_dir): compile_depends = None if target.has_compile_depends: compile_depends = os.path.join( @@ -117,8 +114,7 @@ def write_target_ninja(ninja, target): ninja.newline() ninja.variable('defines', target.defines) - if target.deps: - ninja.variable('includes', target.includes) + ninja.variable('includes', '-I' + src_dir) ninja.variable('cflags', ['-Wall', '-fno-rtti', '-fno-exceptions']) ninja.newline() @@ -129,17 +125,63 @@ def write_target_ninja(ninja, target): deps = [dep.output for dep in target.deps] libs = [dep.output for dep in target.deps if dep.kind == LIB] if target.kind == EXE: - ninja.variable('ldflags', '-Wl,pie') ninja.variable('libs', libs) + if sys.platform == "darwin": + ninja.variable('ldflags', '-Wl,-pie') link = { LIB: 'alink', EXE: 'link'}[target.kind] ninja.build(target.output, link, [obj for _, obj in target.src_obj_pairs], implicit=deps) +def write_sources(target, root_dir): + need_main = target.kind == EXE + + includes = [] + + # Include siblings. + for cc_filename, _ in target.src_obj_pairs: + h_filename = os.path.basename(os.path.splitext(cc_filename)[0] + '.h') + includes.append(h_filename) + + # Include deps. + for dep in target.deps: + for cc_filename, _ in dep.src_obj_pairs: + h_filename = os.path.basename( + os.path.splitext(cc_filename)[0] + '.h') + includes.append("%s/%s" % (dep.dir_path, h_filename)) + + for cc_filename, _ in target.src_obj_pairs: + cc_path = os.path.join(root_dir, cc_filename) + h_path = os.path.splitext(cc_path)[0] + '.h' + namespace = os.path.basename(target.dir_path) + class_ = os.path.splitext(os.path.basename(cc_filename))[0] + try: + os.makedirs(os.path.dirname(cc_path)) + except OSError: + pass + + with open(h_path, 'w') as f: + f.write('namespace %s { struct %s { %s(); }; }' % (namespace, + class_, class_)) + with open(cc_path, 'w') as f: + for include in includes: + f.write('#include "%s"\n' % include) + f.write('\n') + f.write('namespace %s { %s::%s() {} }' % (namespace, + class_, class_)) + + if need_main: + f.write('int main(int argc, char **argv) {}\n') + need_main = False + def write_master_ninja(master_ninja, targets): """Writes master build.ninja file, referencing all given subninjas.""" master_ninja.variable('cxx', 'c++') master_ninja.variable('ld', '$cxx') + if sys.platform == 'darwin': + master_ninja.variable('alink', 'libtool -static') + else: + master_ninja.variable('alink', 'ar rcs') master_ninja.newline() master_ninja.pool('link_pool', depth=4) @@ -148,8 +190,8 @@ def write_master_ninja(master_ninja, targets): master_ninja.rule('cxx', description='CXX $out', command='$cxx -MMD -MF $out.d $defines $includes $cflags -c $in -o $out', depfile='$out.d', deps='gcc') - master_ninja.rule('alink', description='LIBTOOL-STATIC $out', - command='rm -f $out && libtool -static -o $out $in') + master_ninja.rule('alink', description='ARCHIVE $out', + command='rm -f $out && $alink -o $out $in') master_ninja.rule('link', description='LINK $out', pool='link_pool', command='$ld $ldflags -o $out $in $libs') master_ninja.rule('stamp', description='STAMP $out', command='touch $out') @@ -181,9 +223,8 @@ def FileWriter(path): f.close() -def random_targets(): - num_targets = 1500 - gen = GenRandom() +def random_targets(num_targets, src_dir): + gen = GenRandom(src_dir) # N-1 static libraries, and 1 executable depending on all of them. targets = [Target(gen, LIB) for i in xrange(num_targets - 1)] @@ -199,16 +240,28 @@ def random_targets(): def main(): parser = argparse.ArgumentParser() + parser.add_argument('-s', '--sources', nargs="?", const="src", + help='write sources to directory (relative to output directory)') + parser.add_argument('-t', '--targets', type=int, default=1500) + help='number of targets (default: 1500)', + parser.add_argument('-S', '--seed', type=int, help='random seed', + default=12345) parser.add_argument('outdir', help='output directory') args = parser.parse_args() root_dir = args.outdir - random.seed(12345) + random.seed(args.seed) - targets = random_targets() + do_write_sources = args.sources is not None + src_dir = args.sources if do_write_sources else "src" + + targets = random_targets(args.targets, src_dir) for target in targets: with FileWriter(os.path.join(root_dir, target.ninja_file_path)) as n: - write_target_ninja(n, target) + write_target_ninja(n, target, src_dir) + + if do_write_sources: + write_sources(target, root_dir) with FileWriter(os.path.join(root_dir, 'build.ninja')) as master_ninja: master_ninja.width = 120 -- cgit v0.12 From e074e59a3b1347ff54d1e4f5abb7808431d9b1a6 Mon Sep 17 00:00:00 2001 From: gkistanova Date: Thu, 14 Jul 2016 10:53:40 -0700 Subject: Regression test for not initialized elapsed time bug. --- src/build_test.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/build_test.cc b/src/build_test.cc index 06871d2..640e1b0 100644 --- a/src/build_test.cc +++ b/src/build_test.cc @@ -1725,6 +1725,14 @@ TEST_F(BuildTest, DepsGccWithEmptyDepfileErrorsOut) { ASSERT_EQ(1u, command_runner_.commands_ran_.size()); } +TEST_F(BuildTest, StatusFormatElapsed) { + status_.BuildStarted(); + // Before any task is done, the elapsed time must be zero. + EXPECT_EQ("[%/e0.000]", + status_.FormatProgressStatus("[%%/e%e]", + BuildStatus::kEdgeStarted)); +} + TEST_F(BuildTest, StatusFormatReplacePlaceholder) { EXPECT_EQ("[%/s0/t0/r0/u0/f0]", status_.FormatProgressStatus("[%%/s%s/t%t/r%r/u%u/f%f]", -- cgit v0.12 From 3473e08fae5ee76c86db0de079255f00251c1e2c Mon Sep 17 00:00:00 2001 From: gkistanova Date: Thu, 14 Jul 2016 10:55:54 -0700 Subject: Fixed not initialized elapsed time. --- src/build.cc | 13 ++++++++----- src/build.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/build.cc b/src/build.cc index 7792016..b806fb5 100644 --- a/src/build.cc +++ b/src/build.cc @@ -110,11 +110,6 @@ void BuildStatus::BuildEdgeFinished(Edge* edge, int* end_time) { int64_t now = GetTimeMillis(); - if (finished_edges_ == 0) { - overall_rate_.Restart(); - current_rate_.Restart(); - } - ++finished_edges_; RunningEdgeMap::iterator i = running_edges_.find(edge); @@ -164,6 +159,11 @@ void BuildStatus::BuildEdgeFinished(Edge* edge, } } +void BuildStatus::BuildStarted() { + overall_rate_.Restart(); + current_rate_.Restart(); +} + void BuildStatus::BuildFinished() { printer_.SetConsoleLocked(false); printer_.PrintOnNewLine(""); @@ -650,6 +650,9 @@ bool Builder::Build(string* err) { command_runner_.reset(new RealCommandRunner(config_)); } + // We are about to start the build process. + status_->BuildStarted(); + // This main loop runs the entire build process. // It is structured like this: // First, we attempt to start as many commands as allowed by the diff --git a/src/build.h b/src/build.h index 819d832..e633c95 100644 --- a/src/build.h +++ b/src/build.h @@ -200,6 +200,7 @@ struct BuildStatus { void BuildEdgeStarted(Edge* edge); void BuildEdgeFinished(Edge* edge, bool success, const string& output, int* start_time, int* end_time); + void BuildStarted(); void BuildFinished(); enum EdgeStatus { -- cgit v0.12 From 68cf75583ddae4b29f333f7275a690342ac8a1d0 Mon Sep 17 00:00:00 2001 From: Pietro Cerutti Date: Thu, 15 Sep 2016 12:20:35 +0000 Subject: FreeBSD supports ppoll(2) --- configure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.py b/configure.py index 84218b9..9ec368f 100755 --- a/configure.py +++ b/configure.py @@ -98,7 +98,7 @@ class Platform(object): return self._platform in ('freebsd', 'openbsd', 'bitrig') def supports_ppoll(self): - return self._platform in ('linux', 'openbsd', 'bitrig') + return self._platform in ('freebsd', 'linux', 'openbsd', 'bitrig') def supports_ninja_browse(self): return (not self.is_windows() -- cgit v0.12 From 965e549b8dc08f0692ae8f5b33cbe957118c46bd Mon Sep 17 00:00:00 2001 From: Pietro Cerutti Date: Tue, 20 Sep 2016 10:52:56 +0000 Subject: Disable ppoll(2) on FreeBSD < 10.2 --- src/subprocess-posix.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/subprocess-posix.cc b/src/subprocess-posix.cc index 5ffe85b..3c81b7f 100644 --- a/src/subprocess-posix.cc +++ b/src/subprocess-posix.cc @@ -24,6 +24,13 @@ #include #include +#ifdef __FreeBSD__ +# include +# if defined USE_PPOLL && __FreeBSD_version < 1002000 +# undef USE_PPOLL +# endif +#endif + extern char** environ; #include "util.h" -- cgit v0.12 From 05d60b58ab0f8036ea9078fb5dbf3391e180e522 Mon Sep 17 00:00:00 2001 From: Scott Graham Date: Fri, 7 Oct 2016 15:29:58 -0700 Subject: Tidy up rate snprintf'ing helper --- src/build.cc | 4 ++-- src/build.h | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/build.cc b/src/build.cc index b806fb5..64710dd 100644 --- a/src/build.cc +++ b/src/build.cc @@ -220,14 +220,14 @@ string BuildStatus::FormatProgressStatus( // Overall finished edges per second. case 'o': overall_rate_.UpdateRate(finished_edges_); - snprinfRate(overall_rate_.rate(), buf, "%.1f"); + SnprintfRate(overall_rate_.rate(), buf, "%.1f"); out += buf; break; // Current rate, average over the last '-j' jobs. case 'c': current_rate_.UpdateRate(finished_edges_); - snprinfRate(current_rate_.rate(), buf, "%.1f"); + SnprintfRate(current_rate_.rate(), buf, "%.1f"); out += buf; break; diff --git a/src/build.h b/src/build.h index e633c95..66ce607 100644 --- a/src/build.h +++ b/src/build.h @@ -212,9 +212,9 @@ struct BuildStatus { /// See the user manual for more information about the available /// placeholders. /// @param progress_status_format The format of the progress status. - /// @param finished True if the edge being printed just finished + /// @param status The status of the edge. string FormatProgressStatus(const char* progress_status_format, - EdgeStatus kEdgeFinished) const; + EdgeStatus status) const; private: void PrintStatus(Edge* edge, EdgeStatus status); @@ -237,9 +237,11 @@ struct BuildStatus { const char* progress_status_format_; template - void snprinfRate(double rate, char(&buf)[S], const char* format) const { - if (rate == -1) snprintf(buf, S, "?"); - else snprintf(buf, S, format, rate); + void SnprintfRate(double rate, char(&buf)[S], const char* format) const { + if (rate == -1) + snprintf(buf, S, "?"); + else + snprintf(buf, S, format, rate); } struct RateInfo { -- cgit v0.12 From 61c6884335438f6c02d157ea3258577da5cdbea9 Mon Sep 17 00:00:00 2001 From: James Robinson Date: Mon, 24 Oct 2016 17:12:03 -0700 Subject: Fix syntax error in misc/write_fake_manifests.py This is used by manifest_parser_perftest --- misc/write_fake_manifests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/write_fake_manifests.py b/misc/write_fake_manifests.py index cec28de..b3594de 100644 --- a/misc/write_fake_manifests.py +++ b/misc/write_fake_manifests.py @@ -242,8 +242,8 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument('-s', '--sources', nargs="?", const="src", help='write sources to directory (relative to output directory)') - parser.add_argument('-t', '--targets', type=int, default=1500) - help='number of targets (default: 1500)', + parser.add_argument('-t', '--targets', type=int, default=1500, + help='number of targets (default: 1500)') parser.add_argument('-S', '--seed', type=int, help='random seed', default=12345) parser.add_argument('outdir', help='output directory') -- cgit v0.12 From 82a68c96f4b02b68a41d8ad5d0acac86acba4e32 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 7 Nov 2016 10:17:08 -0800 Subject: Only run SubprocessTest.SetWithLots on FreeBSD when ppoll() exists. Should fix #1189 after #1185. --- src/subprocess-posix.cc | 7 ------- src/subprocess.h | 8 ++++++++ src/subprocess_test.cc | 4 +--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/subprocess-posix.cc b/src/subprocess-posix.cc index 3c81b7f..5ffe85b 100644 --- a/src/subprocess-posix.cc +++ b/src/subprocess-posix.cc @@ -24,13 +24,6 @@ #include #include -#ifdef __FreeBSD__ -# include -# if defined USE_PPOLL && __FreeBSD_version < 1002000 -# undef USE_PPOLL -# endif -#endif - extern char** environ; #include "util.h" diff --git a/src/subprocess.h b/src/subprocess.h index 51f40b2..b2d486c 100644 --- a/src/subprocess.h +++ b/src/subprocess.h @@ -26,6 +26,14 @@ using namespace std; #include #endif +// ppoll() exists on FreeBSD, but only on newer versions. +#ifdef __FreeBSD__ +# include +# if defined USE_PPOLL && __FreeBSD_version < 1002000 +# undef USE_PPOLL +# endif +#endif + #include "exit_status.h" /// Subprocess wraps a single async subprocess. It is entirely diff --git a/src/subprocess_test.cc b/src/subprocess_test.cc index ee16190..0a8c206 100644 --- a/src/subprocess_test.cc +++ b/src/subprocess_test.cc @@ -214,9 +214,7 @@ TEST_F(SubprocessTest, SetWithMulti) { } } -// OS X's process limit is less than 1025 by default -// (|sysctl kern.maxprocperuid| is 709 on 10.7 and 10.8 and less prior to that). -#if !defined(__APPLE__) && !defined(_WIN32) +#if defined(USE_PPOLL) TEST_F(SubprocessTest, SetWithLots) { // Arbitrary big number; needs to be over 1024 to confirm we're no longer // hostage to pselect. -- cgit v0.12 From b0cce09f563d0942fcf1c1256db679cebcbd6bea Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 7 Nov 2016 10:28:51 -0800 Subject: mark this 1.7.2.git --- src/version.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.cc b/src/version.cc index f64a94d..e2a83bb 100644 --- a/src/version.cc +++ b/src/version.cc @@ -18,7 +18,7 @@ #include "util.h" -const char* kNinjaVersion = "1.7.1.git"; +const char* kNinjaVersion = "1.7.2.git"; void ParseVersion(const string& version, int* major, int* minor) { size_t end = version.find('.'); -- cgit v0.12