summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt59
-rwxr-xr-xconfigure.py2
-rw-r--r--doc/manual.asciidoc4
-rw-r--r--src/build.cc2
-rw-r--r--src/build_log.cc51
-rw-r--r--src/build_log.h8
-rw-r--r--src/deps_log.cc72
-rw-r--r--src/deps_log.h5
-rw-r--r--src/disk_interface.cc2
-rwxr-xr-xsrc/inline.sh13
-rw-r--r--src/ninja.cc4
-rw-r--r--src/subprocess-posix.cc7
-rw-r--r--src/version.cc2
13 files changed, 170 insertions, 61 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 007c662..b0c0911 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,7 @@
cmake_minimum_required(VERSION 3.15)
+
+include(CheckIncludeFileCXX)
+
project(ninja)
# --- optional link-time optimization
@@ -39,15 +42,39 @@ if(RE2C)
COMMAND ${RE2C} -b -i --no-generation-date -o ${OUT} ${IN}
)
endfunction()
- re2c(${CMAKE_SOURCE_DIR}/src/depfile_parser.in.cc ${CMAKE_BINARY_DIR}/depfile_parser.cc)
- re2c(${CMAKE_SOURCE_DIR}/src/lexer.in.cc ${CMAKE_BINARY_DIR}/lexer.cc)
- add_library(libninja-re2c OBJECT ${CMAKE_BINARY_DIR}/depfile_parser.cc ${CMAKE_BINARY_DIR}/lexer.cc)
+ re2c(${PROJECT_SOURCE_DIR}/src/depfile_parser.in.cc ${PROJECT_BINARY_DIR}/depfile_parser.cc)
+ re2c(${PROJECT_SOURCE_DIR}/src/lexer.in.cc ${PROJECT_BINARY_DIR}/lexer.cc)
+ add_library(libninja-re2c OBJECT ${PROJECT_BINARY_DIR}/depfile_parser.cc ${PROJECT_BINARY_DIR}/lexer.cc)
else()
message(WARNING "re2c was not found; changes to src/*.in.cc will not affect your build.")
add_library(libninja-re2c OBJECT src/depfile_parser.cc src/lexer.cc)
endif()
target_include_directories(libninja-re2c PRIVATE src)
+# --- Check for 'browse' mode support
+function(check_platform_supports_browse_mode RESULT)
+ # Make sure the inline.sh script works on this platform.
+ # It uses the shell commands such as 'od', which may not be available.
+ execute_process(
+ COMMAND sh -c "echo 'TEST' | src/inline.sh var"
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ RESULT_VARIABLE inline_result
+ OUTPUT_QUIET
+ ERROR_QUIET
+ )
+ if(NOT inline_result EQUAL "0")
+ # The inline script failed, so browse mode is not supported.
+ set(${RESULT} "0" PARENT_SCOPE)
+ return()
+ endif()
+
+ # Now check availability of the unistd header
+ check_include_file_cxx(unistd.h PLATFORM_HAS_UNISTD_HEADER)
+ set(${RESULT} "${PLATFORM_HAS_UNISTD_HEADER}" PARENT_SCOPE)
+endfunction()
+
+check_platform_supports_browse_mode(platform_supports_ninja_browse)
+
# Core source files all build into ninja library.
add_library(libninja OBJECT
src/build_log.cc
@@ -96,6 +123,32 @@ endif()
add_executable(ninja src/ninja.cc)
target_link_libraries(ninja PRIVATE libninja libninja-re2c)
+# Adds browse mode into the ninja binary if it's supported by the host platform.
+if(platform_supports_ninja_browse)
+ # Inlines src/browse.py into the browse_py.h header, so that it can be included
+ # by src/browse.cc
+ add_custom_command(
+ OUTPUT build/browse_py.h
+ MAIN_DEPENDENCY src/browse.py
+ DEPENDS src/inline.sh
+ COMMAND cmake -E make_directory ${CMAKE_BINARY_DIR}/build
+ COMMAND src/inline.sh kBrowsePy
+ < src/browse.py
+ > ${CMAKE_BINARY_DIR}/build/browse_py.h
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ VERBATIM
+ )
+
+ target_compile_definitions(ninja PRIVATE NINJA_HAVE_BROWSE)
+ target_sources(ninja PRIVATE src/browse.cc)
+ set_source_files_properties(src/browse.cc
+ PROPERTIES
+ OBJECT_DEPENDS "${CMAKE_BINARY_DIR}/build/browse_py.h"
+ INCLUDE_DIRECTORIES "${CMAKE_BINARY_DIR}"
+ COMPILE_DEFINITIONS NINJA_PYTHON="python"
+ )
+endif()
+
# Tests all build into ninja_test executable.
add_executable(ninja_test
src/build_log_test.cc
diff --git a/configure.py b/configure.py
index 8eef7e6..48c4821 100755
--- a/configure.py
+++ b/configure.py
@@ -269,7 +269,7 @@ if configure_env:
n.variable('configure_env', config_str + '$ ')
n.newline()
-CXX = configure_env.get('CXX', 'g++')
+CXX = configure_env.get('CXX', 'c++')
objext = '.o'
if platform.is_msvc():
CXX = 'cl'
diff --git a/doc/manual.asciidoc b/doc/manual.asciidoc
index 9976ce4..e1ae083 100644
--- a/doc/manual.asciidoc
+++ b/doc/manual.asciidoc
@@ -899,7 +899,7 @@ 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
+quoting rules are determined 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
@@ -935,7 +935,7 @@ There are three types of build dependencies which are subtly different.
1. _Explicit dependencies_, as listed in a build line. These are
available as the `$in` variable in the rule. Changes in these files
- cause the output to be rebuilt; if these file are missing and
+ cause the output to be rebuilt; if these files are missing and
Ninja doesn't know how to build them, the build is aborted.
+
This is the standard form of dependency to be used e.g. for the
diff --git a/src/build.cc b/src/build.cc
index a32bdda..4833887 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -180,7 +180,7 @@ void BuildStatus::BuildLoadDyndeps() {
// it considers a portion of the graph to be out of date. Normally
// this is done before the build starts, but our caller is about to
// load a dyndep file during the build. Doing so may generate more
- // exlanation lines (via fprintf directly to stderr), but in an
+ // explanation lines (via fprintf directly to stderr), but in an
// interactive console the cursor is currently at the end of a status
// line. Start a new line so that the first explanation does not
// append to the status line. After the explanations are done a
diff --git a/src/build_log.cc b/src/build_log.cc
index 98543b6..e5f179c 100644
--- a/src/build_log.cc
+++ b/src/build_log.cc
@@ -23,6 +23,7 @@
#include "build_log.h"
#include "disk_interface.h"
+#include <cassert>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@@ -132,25 +133,9 @@ bool BuildLog::OpenForWrite(const string& path, const BuildLogUser& user,
return false;
}
- log_file_ = fopen(path.c_str(), "ab");
- if (!log_file_) {
- *err = strerror(errno);
- return false;
- }
- setvbuf(log_file_, NULL, _IOLBF, BUFSIZ);
- SetCloseOnExec(fileno(log_file_));
-
- // Opening a file in append mode doesn't set the file pointer to the file's
- // end on Windows. Do that explicitly.
- fseek(log_file_, 0, SEEK_END);
-
- if (ftell(log_file_) == 0) {
- if (fprintf(log_file_, kFileSignature, kCurrentVersion) < 0) {
- *err = strerror(errno);
- return false;
- }
- }
-
+ assert(!log_file_);
+ log_file_path_ = path; // we don't actually open the file right now, but will
+ // do so on the first write attempt
return true;
}
@@ -174,6 +159,9 @@ bool BuildLog::RecordCommand(Edge* edge, int start_time, int end_time,
log_entry->end_time = end_time;
log_entry->mtime = mtime;
+ if (!OpenForWriteIfNeeded()) {
+ return false;
+ }
if (log_file_) {
if (!WriteEntry(log_file_, *log_entry))
return false;
@@ -186,11 +174,36 @@ bool BuildLog::RecordCommand(Edge* edge, int start_time, int end_time,
}
void BuildLog::Close() {
+ OpenForWriteIfNeeded(); // create the file even if nothing has been recorded
if (log_file_)
fclose(log_file_);
log_file_ = NULL;
}
+bool BuildLog::OpenForWriteIfNeeded() {
+ if (log_file_path_.empty()) {
+ return true;
+ }
+ log_file_ = fopen(log_file_path_.c_str(), "ab");
+ if (!log_file_) {
+ return false;
+ }
+ setvbuf(log_file_, NULL, _IOLBF, BUFSIZ);
+ SetCloseOnExec(fileno(log_file_));
+
+ // Opening a file in append mode doesn't set the file pointer to the file's
+ // end on Windows. Do that explicitly.
+ fseek(log_file_, 0, SEEK_END);
+
+ if (ftell(log_file_) == 0) {
+ if (fprintf(log_file_, kFileSignature, kCurrentVersion) < 0) {
+ return false;
+ }
+ }
+ log_file_path_.clear();
+ return true;
+}
+
struct LineReader {
explicit LineReader(FILE* file)
: file_(file), buf_end_(buf_), line_start_(buf_), line_end_(NULL) {
diff --git a/src/build_log.h b/src/build_log.h
index ebe0530..6d060d1 100644
--- a/src/build_log.h
+++ b/src/build_log.h
@@ -45,7 +45,10 @@ struct BuildLog {
BuildLog();
~BuildLog();
+ /// Prepares writing to the log file without actually opening it - that will
+ /// happen when/if it's needed
bool OpenForWrite(const string& path, const BuildLogUser& user, string* err);
+
bool RecordCommand(Edge* edge, int start_time, int end_time,
TimeStamp mtime = 0);
void Close();
@@ -91,8 +94,13 @@ struct BuildLog {
const Entries& entries() const { return entries_; }
private:
+ /// Should be called before using log_file_. When false is returned, errno
+ /// will be set.
+ bool OpenForWriteIfNeeded();
+
Entries entries_;
FILE* log_file_;
+ std::string log_file_path_;
bool needs_recompaction_;
};
diff --git a/src/deps_log.cc b/src/deps_log.cc
index 59a1956..1fb65ae 100644
--- a/src/deps_log.cc
+++ b/src/deps_log.cc
@@ -49,34 +49,9 @@ bool DepsLog::OpenForWrite(const string& path, string* err) {
return false;
}
- file_ = fopen(path.c_str(), "ab");
- if (!file_) {
- *err = strerror(errno);
- return false;
- }
- // Set the buffer size to this and flush the file buffer after every record
- // to make sure records aren't written partially.
- setvbuf(file_, NULL, _IOFBF, kMaxRecordSize + 1);
- SetCloseOnExec(fileno(file_));
-
- // Opening a file in append mode doesn't set the file pointer to the file's
- // end on Windows. Do that explicitly.
- fseek(file_, 0, SEEK_END);
-
- if (ftell(file_) == 0) {
- if (fwrite(kFileSignature, sizeof(kFileSignature) - 1, 1, file_) < 1) {
- *err = strerror(errno);
- return false;
- }
- if (fwrite(&kCurrentVersion, 4, 1, file_) < 1) {
- *err = strerror(errno);
- return false;
- }
- }
- if (fflush(file_) != 0) {
- *err = strerror(errno);
- return false;
- }
+ assert(!file_);
+ file_path_ = path; // we don't actually open the file right now, but will do
+ // so on the first write attempt
return true;
}
@@ -132,6 +107,10 @@ bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
errno = ERANGE;
return false;
}
+
+ if (!OpenForWriteIfNeeded()) {
+ return false;
+ }
size |= 0x80000000; // Deps record: set high bit.
if (fwrite(&size, 4, 1, file_) < 1)
return false;
@@ -162,6 +141,7 @@ bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
}
void DepsLog::Close() {
+ OpenForWriteIfNeeded(); // create the file even if nothing has been recorded
if (file_)
fclose(file_);
file_ = NULL;
@@ -396,6 +376,10 @@ bool DepsLog::RecordId(Node* node) {
errno = ERANGE;
return false;
}
+
+ if (!OpenForWriteIfNeeded()) {
+ return false;
+ }
if (fwrite(&size, 4, 1, file_) < 1)
return false;
if (fwrite(node->path().data(), path_size, 1, file_) < 1) {
@@ -416,3 +400,35 @@ bool DepsLog::RecordId(Node* node) {
return true;
}
+
+bool DepsLog::OpenForWriteIfNeeded() {
+ if (file_path_.empty()) {
+ return true;
+ }
+ file_ = fopen(file_path_.c_str(), "ab");
+ if (!file_) {
+ return false;
+ }
+ // Set the buffer size to this and flush the file buffer after every record
+ // to make sure records aren't written partially.
+ setvbuf(file_, NULL, _IOFBF, kMaxRecordSize + 1);
+ SetCloseOnExec(fileno(file_));
+
+ // Opening a file in append mode doesn't set the file pointer to the file's
+ // end on Windows. Do that explicitly.
+ fseek(file_, 0, SEEK_END);
+
+ if (ftell(file_) == 0) {
+ if (fwrite(kFileSignature, sizeof(kFileSignature) - 1, 1, file_) < 1) {
+ return false;
+ }
+ if (fwrite(&kCurrentVersion, 4, 1, file_) < 1) {
+ return false;
+ }
+ }
+ if (fflush(file_) != 0) {
+ return false;
+ }
+ file_path_.clear();
+ return true;
+}
diff --git a/src/deps_log.h b/src/deps_log.h
index e7974a1..c4ada8b 100644
--- a/src/deps_log.h
+++ b/src/deps_log.h
@@ -110,8 +110,13 @@ struct DepsLog {
// Write a node name record, assigning it an id.
bool RecordId(Node* node);
+ /// Should be called before using file_. When false is returned, errno will
+ /// be set.
+ bool OpenForWriteIfNeeded();
+
bool needs_recompaction_;
FILE* file_;
+ std::string file_path_;
/// Maps id -> Node.
vector<Node*> nodes_;
diff --git a/src/disk_interface.cc b/src/disk_interface.cc
index dc297c4..594bc51 100644
--- a/src/disk_interface.cc
+++ b/src/disk_interface.cc
@@ -26,6 +26,8 @@
#include <sstream>
#include <windows.h>
#include <direct.h> // _mkdir
+#else
+#include <unistd.h>
#endif
#include "metrics.h"
diff --git a/src/inline.sh b/src/inline.sh
index b64e8ca..5092fa2 100755
--- a/src/inline.sh
+++ b/src/inline.sh
@@ -19,7 +19,14 @@
# stdin and writes stdout.
varname="$1"
-echo "const char $varname[] ="
-od -t x1 -A n -v | sed -e 's|^[\t ]\{0,\}$||g; s|[\t ]\{1,\}| |g; s| \{1,\}$||g; s| |\\x|g; s|^|"|; s|$|"|'
-echo ";"
+# 'od' and 'sed' may not be available on all platforms, and may not support the
+# flags used here. We must ensure that the script exits with a non-zero exit
+# code in those cases.
+byte_vals=$(od -t x1 -A n -v) || exit 1
+escaped_byte_vals=$(echo "${byte_vals}" \
+ | sed -e 's|^[\t ]\{0,\}$||g; s|[\t ]\{1,\}| |g; s| \{1,\}$||g; s| |\\x|g; s|^|"|; s|$|"|') \
+ || exit 1
+
+# Only write output once we have successfully generated the required data
+printf "const char %s[] = \n%s;" "${varname}" "${escaped_byte_vals}"
diff --git a/src/ninja.cc b/src/ninja.cc
index 1429639..00e3a5c 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -91,7 +91,7 @@ struct NinjaMain : public BuildLogUser {
/// Loaded state (rules, nodes).
State state_;
- /// Functions for accesssing the disk.
+ /// Functions for accessing the disk.
RealDiskInterface disk_interface_;
/// The build directory, used for storing the build log etc.
@@ -1050,7 +1050,7 @@ bool DebugEnable(const string& name) {
}
}
-/// Set a warning flag. Returns false if Ninja should exit instead of
+/// Set a warning flag. Returns false if Ninja should exit instead of
/// continuing.
bool WarningEnable(const string& name, Options* options) {
if (name == "list") {
diff --git a/src/subprocess-posix.cc b/src/subprocess-posix.cc
index fc5543e..74785d1 100644
--- a/src/subprocess-posix.cc
+++ b/src/subprocess-posix.cc
@@ -18,13 +18,18 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
-#include <poll.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <spawn.h>
+#if defined(USE_PPOLL)
+#include <poll.h>
+#else
+#include <sys/select.h>
+#endif
+
extern char** environ;
#include "util.h"
diff --git a/src/version.cc b/src/version.cc
index 74e1213..9d27e87 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -18,7 +18,7 @@
#include "util.h"
-const char* kNinjaVersion = "1.10.0.git";
+const char* kNinjaVersion = "1.10.1.git";
void ParseVersion(const string& version, int* major, int* minor) {
size_t end = version.find('.');