Skip to content

Commit

Permalink
v1.8.0
Browse files Browse the repository at this point in the history
  • Loading branch information
nico committed Sep 4, 2017
2 parents 256bf89 + b98941a commit 0c67152
Show file tree
Hide file tree
Showing 40 changed files with 1,097 additions and 436 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ TAGS
/ninja.bootstrap
/build_log_perftest
/canon_perftest
/clparser_perftest
/depfile_parser_perftest
/hash_collision_bench
/ninja_test
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ language: cpp
compiler:
- gcc
- clang
script: ./configure.py --bootstrap && ./ninja ninja_test && ./ninja_test --gtest_filter=-SubprocessTest.SetWithLots && ./misc/ninja_syntax_test.py
script: ./configure.py --bootstrap && ./ninja all && ./ninja_test --gtest_filter=-SubprocessTest.SetWithLots && ./misc/ninja_syntax_test.py
2 changes: 1 addition & 1 deletion HACKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ Generally it's the [Google C++ coding style][], but in brief:
* Lines are 80 columns maximum.
* All source files should have the Google Inc. license header.

[Google C++ coding style]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
[Google C++ coding style]: https://google.github.io/styleguide/cppguide.html

## Documentation

Expand Down
17 changes: 9 additions & 8 deletions RELEASING
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ Notes to myself on all the steps to make for a Ninja release.

Push new release branch:
1. Consider sending a heads-up to the ninja-build mailing list first
2. update src/version.cc with new version (with ".git"), then
git commit -a -m 'mark this 1.5.0.git'
3. git checkout release; git merge master
4. fix version number in src/version.cc (it will likely conflict in the above)
5. fix version in doc/manual.asciidoc
6. commit, tag, push (don't forget to push --tags)
git commit -a -m v1.5.0; git push origin release
2. Make sure branches 'master' and 'release' are synced up locally
3. update src/version.cc with new version (with ".git"), then
git commit -am 'mark this 1.5.0.git'
4. git checkout release; git merge master
5. fix version number in src/version.cc (it will likely conflict in the above)
6. fix version in doc/manual.asciidoc (exists only on release branch)
7. commit, tag, push (don't forget to push --tags)
git commit -am v1.5.0; git push origin release
git tag v1.5.0; git push --tags
# Push the 1.5.0.git change on master too:
git checkout master; git push origin master
7. construct release notes from prior notes
8. construct release notes from prior notes
credits: git shortlog -s --no-merges REV..

Release on github:
Expand Down
40 changes: 21 additions & 19 deletions configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,14 @@ def __init__(self, platform):
self._platform = 'netbsd'
elif self._platform.startswith('aix'):
self._platform = 'aix'
elif self._platform.startswith('dragonfly'):
self._platform = 'dragonfly'

@staticmethod
def known_platforms():
return ['linux', 'darwin', 'freebsd', 'openbsd', 'solaris', 'sunos5',
'mingw', 'msvc', 'gnukfreebsd', 'bitrig', 'netbsd', 'aix']
'mingw', 'msvc', 'gnukfreebsd', 'bitrig', 'netbsd', 'aix',
'dragonfly']

def platform(self):
return self._platform
Expand Down Expand Up @@ -95,10 +98,11 @@ def is_aix(self):
return self._platform == 'aix'

def uses_usr_local(self):
return self._platform in ('freebsd', 'openbsd', 'bitrig')
return self._platform in ('freebsd', 'openbsd', 'bitrig', 'dragonfly')

def supports_ppoll(self):
return self._platform in ('freebsd', 'linux', 'openbsd', 'bitrig')
return self._platform in ('freebsd', 'linux', 'openbsd', 'bitrig',
'dragonfly')

def supports_ninja_browse(self):
return (not self.is_windows()
Expand Down Expand Up @@ -302,7 +306,7 @@ def binary(name):
'/Zi', # Create pdb with debug info.
'/W4', # Highest warning level.
'/WX', # Warnings as errors.
'/wd4530', '/wd4100', '/wd4706',
'/wd4530', '/wd4100', '/wd4706', '/wd4244',
'/wd4512', '/wd4800', '/wd4702', '/wd4819',
# Disable warnings about constant conditional expressions.
'/wd4127',
Expand Down Expand Up @@ -489,6 +493,7 @@ def has_re2c():
'manifest_parser',
'metrics',
'state',
'string_piece_util',
'util',
'version']:
objs += cxx(name)
Expand Down Expand Up @@ -551,6 +556,7 @@ def has_re2c():
'manifest_parser_test',
'ninja_test',
'state_test',
'string_piece_util_test',
'subprocess_test',
'test',
'util_test']:
Expand All @@ -566,21 +572,17 @@ def has_re2c():


n.comment('Ancillary executables.')
objs = cxx('build_log_perftest')
all_targets += n.build(binary('build_log_perftest'), 'link', objs,
implicit=ninja_lib, variables=[('libs', libs)])
objs = cxx('canon_perftest')
all_targets += n.build(binary('canon_perftest'), 'link', objs,
implicit=ninja_lib, variables=[('libs', libs)])
objs = cxx('depfile_parser_perftest')
all_targets += n.build(binary('depfile_parser_perftest'), 'link', objs,
implicit=ninja_lib, variables=[('libs', libs)])
objs = cxx('hash_collision_bench')
all_targets += n.build(binary('hash_collision_bench'), 'link', objs,
implicit=ninja_lib, variables=[('libs', libs)])
objs = cxx('manifest_parser_perftest')
all_targets += n.build(binary('manifest_parser_perftest'), 'link', objs,
implicit=ninja_lib, variables=[('libs', libs)])

for name in ['build_log_perftest',
'canon_perftest',
'depfile_parser_perftest',
'hash_collision_bench',
'manifest_parser_perftest',
'clparser_perftest']:
objs = cxx(name)
all_targets += n.build(binary(name), 'link', objs,
implicit=ninja_lib, variables=[('libs', libs)])

n.newline()

n.comment('Generate a graph using the "graph" tool.')
Expand Down
7 changes: 6 additions & 1 deletion doc/manual.asciidoc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The Ninja build system
======================
v1.7.2, Nov 2016
v1.8.0, Sep 2017


Introduction
Expand Down Expand Up @@ -280,6 +280,11 @@ http://clang.llvm.org/docs/JSONCompilationDatabase.html[JSON format] expected
by the Clang tooling interface.
_Available since Ninja 1.2._
`deps`:: show all dependencies stored in the `.ninja_deps` file. When given a
target, show just the target's dependencies. _Available since Ninja 1.4._
`recompact`:: recompact the `.ninja_deps` file. _Available since Ninja 1.4._
Writing your own Ninja files
----------------------------
Expand Down
7 changes: 6 additions & 1 deletion misc/zsh-completion
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ __get_targets() {
then
eval dir="${opt_args[-C]}"
fi
targets_command="ninja -C \"${dir}\" -t targets all"
file="build.ninja"
if [ -n "${opt_args[-f]}" ];
then
eval file="${opt_args[-f]}"
fi
targets_command="ninja -f \"${file}\" -C \"${dir}\" -t targets all"
eval ${targets_command} 2>/dev/null | cut -d: -f1
}

Expand Down
8 changes: 6 additions & 2 deletions src/browse.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ def log_message(self, format, *args):
parser = argparse.ArgumentParser(prog='ninja -t browse')
parser.add_argument('--port', '-p', default=8000, type=int,
help='Port number to use (default %(default)d)')
parser.add_argument('--hostname', '-a', default='localhost', type=str,
help='Hostname to bind to (default %(default)s)')
parser.add_argument('--no-browser', action='store_true',
help='Do not open a webbrowser on startup.')

Expand All @@ -205,9 +207,11 @@ def log_message(self, format, *args):

args = parser.parse_args()
port = args.port
httpd = httpserver.HTTPServer(('',port), RequestHandler)
hostname = args.hostname
httpd = httpserver.HTTPServer((hostname,port), RequestHandler)
try:
hostname = socket.gethostname()
if hostname == "":
hostname = socket.gethostname()
print('Web server running on %s:%d, ctl-C to abort...' % (hostname,port) )
print('Web server pid %d' % os.getpid(), file=sys.stderr )
if not args.no_browser:
Expand Down
94 changes: 42 additions & 52 deletions src/build.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
#include <stdlib.h>
#include <functional>

#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#endif

#if defined(__SVR4) && defined(__sun)
#include <sys/termios.h>
#endif
Expand Down Expand Up @@ -155,7 +160,17 @@ void BuildStatus::BuildEdgeFinished(Edge* edge,
final_output = StripAnsiEscapeCodes(output);
else
final_output = output;

#ifdef _WIN32
// Fix extra CR being added on Windows, writing out CR CR LF (#773)
_setmode(_fileno(stdout), _O_BINARY); // Begin Windows extra CR fix
#endif

printer_.PrintOnNewLine(final_output);

#ifdef _WIN32
_setmode(_fileno(stdout), _O_TEXT); // End Windows extra CR fix
#endif
}
}

Expand Down Expand Up @@ -275,27 +290,30 @@ void BuildStatus::PrintStatus(Edge* edge, EdgeStatus status) {

Plan::Plan() : command_edges_(0), wanted_edges_(0) {}

void Plan::Reset() {
command_edges_ = 0;
wanted_edges_ = 0;
ready_.clear();
want_.clear();
}

bool Plan::AddTarget(Node* node, string* err) {
vector<Node*> stack;
return AddSubTarget(node, &stack, err);
return AddSubTarget(node, NULL, err);
}

bool Plan::AddSubTarget(Node* node, vector<Node*>* stack, string* err) {
bool Plan::AddSubTarget(Node* node, Node* dependent, string* err) {
Edge* edge = node->in_edge();
if (!edge) { // Leaf node.
if (node->dirty()) {
string referenced;
if (!stack->empty())
referenced = ", needed by '" + stack->back()->path() + "',";
if (dependent)
referenced = ", needed by '" + dependent->path() + "',";
*err = "'" + node->path() + "'" + referenced + " missing "
"and no known rule to make it";
}
return false;
}

if (CheckDependencyCycle(node, *stack, err))
return false;

if (edge->outputs_ready())
return false; // Don't need to do anything.

Expand All @@ -319,50 +337,15 @@ bool Plan::AddSubTarget(Node* node, vector<Node*>* stack, string* err) {
if (!want_ins.second)
return true; // We've already processed the inputs.

stack->push_back(node);
for (vector<Node*>::iterator i = edge->inputs_.begin();
i != edge->inputs_.end(); ++i) {
if (!AddSubTarget(*i, stack, err) && !err->empty())
if (!AddSubTarget(*i, node, err) && !err->empty())
return false;
}
assert(stack->back() == node);
stack->pop_back();

return true;
}

bool Plan::CheckDependencyCycle(Node* node, const vector<Node*>& stack,
string* err) {
vector<Node*>::const_iterator start = stack.begin();
while (start != stack.end() && (*start)->in_edge() != node->in_edge())
++start;
if (start == stack.end())
return false;

// Build error string for the cycle.
vector<Node*> cycle(start, stack.end());
cycle.push_back(node);

if (cycle.front() != cycle.back()) {
// Consider
// build a b: cat c
// build c: cat a
// stack will contain [b, c], node will be a. To not print b -> c -> a,
// shift by one to get c -> a -> c which makes the cycle clear.
cycle.erase(cycle.begin());
cycle.push_back(cycle.front());
assert(cycle.front() == cycle.back());
}

*err = "dependency cycle: ";
for (vector<Node*>::const_iterator i = cycle.begin(); i != cycle.end(); ++i) {
if (i != cycle.begin())
err->append(" -> ");
err->append((*i)->path());
}
return true;
}

Edge* Plan::FindWork() {
if (ready_.empty())
return NULL;
Expand Down Expand Up @@ -618,9 +601,10 @@ Node* Builder::AddTarget(const string& name, string* err) {
}

bool Builder::AddTarget(Node* node, string* err) {
if (!scan_.RecomputeDirty(node, err))
return false;

if (Edge* in_edge = node->in_edge()) {
if (!scan_.RecomputeDirty(in_edge, err))
return false;
if (in_edge->outputs_ready())
return true; // Nothing to do.
}
Expand Down Expand Up @@ -793,17 +777,20 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {
return true;
}

// Restat the edge outputs, if necessary.
TimeStamp restat_mtime = 0;
if (edge->GetBindingBool("restat") && !config_.dry_run) {
// Restat the edge outputs
TimeStamp output_mtime = 0;
bool restat = edge->GetBindingBool("restat");
if (!config_.dry_run) {
bool node_cleaned = false;

for (vector<Node*>::iterator o = edge->outputs_.begin();
o != edge->outputs_.end(); ++o) {
TimeStamp new_mtime = disk_interface_->Stat((*o)->path(), err);
if (new_mtime == -1)
return false;
if ((*o)->mtime() == new_mtime) {
if (new_mtime > output_mtime)
output_mtime = new_mtime;
if ((*o)->mtime() == new_mtime && restat) {
// The rule command did not change the output. Propagate the clean
// state through the build graph.
// Note that this also applies to nonexistent outputs (mtime == 0).
Expand All @@ -814,6 +801,7 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {
}

if (node_cleaned) {
TimeStamp restat_mtime = 0;
// If any output was cleaned, find the most recent mtime of any
// (existing) non-order-only input or the depfile.
for (vector<Node*>::iterator i = edge->inputs_.begin();
Expand All @@ -837,6 +825,8 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {
// The total number of edges in the plan may have changed as a result
// of a restat.
status_->PlanHasTotalEdges(plan_.command_edge_count());

output_mtime = restat_mtime;
}
}

Expand All @@ -849,7 +839,7 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {

if (scan_.build_log()) {
if (!scan_.build_log()->RecordCommand(edge, start_time, end_time,
restat_mtime)) {
output_mtime)) {
*err = string("Error writing to build log: ") + strerror(errno);
return false;
}
Expand Down Expand Up @@ -918,7 +908,7 @@ bool Builder::ExtractDeps(CommandRunner::Result* result,
deps_nodes->reserve(deps.ins_.size());
for (vector<StringPiece>::iterator i = deps.ins_.begin();
i != deps.ins_.end(); ++i) {
unsigned int slash_bits;
uint64_t slash_bits;
if (!CanonicalizePath(const_cast<char*>(i->str_), &i->len_, &slash_bits,
err))
return false;
Expand Down
Loading

0 comments on commit 0c67152

Please sign in to comment.