Merge pull request #1674 from cameron314/bugfix/core-count

Fixed processor count detection on Windows
diff --git a/.clang-format b/.clang-format
index 1841c03..b8e9225 100644
--- a/.clang-format
+++ b/.clang-format
@@ -23,3 +23,4 @@
 ConstructorInitializerAllOnOneLineOrOnePerLine: false
 Cpp11BracedListStyle: false
 IndentCaseLabels: false
+DerivePointerBinding: false
diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644
index 0000000..e0afd47
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1,17 @@
+---
+Checks: '
+  ,readability-avoid-const-params-in-decls,
+  ,readability-inconsistent-declaration-parameter-name,
+  ,readability-non-const-parameter,
+  ,readability-redundant-string-cstr,
+  ,readability-redundant-string-init,
+  ,readability-simplify-boolean-expr,
+'
+WarningsAsErrors: '
+  ,readability-avoid-const-params-in-decls,
+  ,readability-inconsistent-declaration-parameter-name,
+  ,readability-non-const-parameter,
+  ,readability-redundant-string-cstr,
+  ,readability-redundant-string-init,
+  ,readability-simplify-boolean-expr,
+'
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..0cc68d6
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,11 @@
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+end_of_line = lf
+
+[CMakeLists.txt]
+indent_style = tab
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
new file mode 100644
index 0000000..cd55262
--- /dev/null
+++ b/.github/workflows/linux.yml
@@ -0,0 +1,146 @@
+name: Linux
+
+on:
+  pull_request:
+  push:
+  release:
+    types: published
+
+jobs:
+  build:
+    runs-on: [ubuntu-latest]
+    container:
+      image: centos:7
+    steps:
+    - uses: actions/checkout@v2
+    - name: Install dependencies
+      run: |
+        curl -L -O https://github.com/Kitware/CMake/releases/download/v3.16.4/cmake-3.16.4-Linux-x86_64.sh
+        chmod +x cmake-3.16.4-Linux-x86_64.sh
+        ./cmake-3.16.4-Linux-x86_64.sh --skip-license --prefix=/usr/local
+        curl -L -O https://www.mirrorservice.org/sites/dl.fedoraproject.org/pub/epel/7/x86_64/Packages/p/p7zip-16.02-10.el7.x86_64.rpm
+        curl -L -O https://www.mirrorservice.org/sites/dl.fedoraproject.org/pub/epel/7/x86_64/Packages/p/p7zip-plugins-16.02-10.el7.x86_64.rpm
+        rpm -U --quiet p7zip-16.02-10.el7.x86_64.rpm
+        rpm -U --quiet p7zip-plugins-16.02-10.el7.x86_64.rpm
+        yum install -y make gcc-c++ libasan clang-analyzer
+
+    - name: Build debug ninja
+      shell: bash
+      env:
+        CFLAGS: -fstack-protector-all -fsanitize=address
+        CXXFLAGS: -fstack-protector-all -fsanitize=address
+      run: |
+        scan-build -o scanlogs cmake -DCMAKE_BUILD_TYPE=Debug -B debug-build
+        scan-build -o scanlogs cmake --build debug-build --parallel --config Debug
+
+    - name: Test debug ninja
+      run: ./ninja_test
+      working-directory: debug-build
+
+    - name: Build release ninja
+      shell: bash
+      run: |
+        cmake -DCMAKE_BUILD_TYPE=Release -B release-build
+        cmake --build release-build --parallel --config Release
+        strip release-build/ninja
+
+    - name: Test release ninja
+      run: ./ninja_test
+      working-directory: release-build
+
+    - name: Create ninja archive
+      run: |
+        mkdir artifact
+        7z a artifact/ninja-linux.zip ./release-build/ninja
+
+    # Upload ninja binary archive as an artifact
+    - name: Upload artifact
+      uses: actions/upload-artifact@v1
+      with:
+        name: ninja-binary-archives
+        path: artifact
+
+    - name: Upload release asset
+      if: github.event.action == 'published'
+      uses: actions/upload-release-asset@v1.0.1
+      env:
+        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      with:
+        upload_url: ${{ github.event.release.upload_url }}
+        asset_path: ./artifact/ninja-linux.zip
+        asset_name: ninja-linux.zip
+        asset_content_type: application/zip
+
+  test:
+    runs-on: [ubuntu-latest]
+    container:
+      image: ubuntu:20.04
+    steps:
+    - uses: actions/checkout@v2
+    - name: Install dependencies
+      run: |
+        apt update
+        apt install -y python3-pytest ninja-build clang-tidy python3-pip clang
+        pip3 install cmake==3.17.*
+    - name: Configure (GCC)
+      run: cmake -Bbuild-gcc -DCMAKE_BUILD_TYPE=Debug -G'Ninja Multi-Config'
+
+    - name: Build (GCC, Debug)
+      run: cmake --build build-gcc --config Debug
+    - name: Unit tests (GCC, Debug)
+      run: ./build-gcc/Debug/ninja_test
+    - name: Python tests (GCC, Debug)
+      run: pytest-3 --color=yes ../..
+      working-directory: build-gcc/Debug
+
+    - name: Build (GCC, Release)
+      run: cmake --build build-gcc --config Release
+    - name: Unit tests (GCC, Release)
+      run: ./build-gcc/Release/ninja_test
+    - name: Python tests (GCC, Release)
+      run: pytest-3 --color=yes ../..
+      working-directory: build-gcc/Release
+
+    - name: Configure (Clang)
+      run: CC=clang CXX=clang++ cmake -Bbuild-clang -DCMAKE_BUILD_TYPE=Debug -G'Ninja Multi-Config' -DCMAKE_EXPORT_COMPILE_COMMANDS=1
+
+    - name: Build (Clang, Debug)
+      run: cmake --build build-clang --config Debug
+    - name: Unit tests (Clang, Debug)
+      run: ./build-clang/Debug/ninja_test
+    - name: Python tests (Clang, Debug)
+      run: pytest-3 --color=yes ../..
+      working-directory: build-clang/Debug
+
+    - name: Build (Clang, Release)
+      run: cmake --build build-clang --config Release
+    - name: Unit tests (Clang, Release)
+      run: ./build-clang/Release/ninja_test
+    - name: Python tests (Clang, Release)
+      run: pytest-3 --color=yes ../..
+      working-directory: build-clang/Release
+
+    - name: clang-tidy
+      run: /usr/lib/llvm-10/share/clang/run-clang-tidy.py -header-filter=src
+      working-directory: build-clang
+
+  build-with-python:
+    runs-on: [ubuntu-latest]
+    container:
+      image: ${{ matrix.image }}
+    strategy:
+      matrix:
+        image: ['ubuntu:14.04', 'ubuntu:16.04', 'ubuntu:18.04']
+    steps:
+    - uses: actions/checkout@v2
+    - name: Install dependencies
+      run: |
+        apt update
+        apt install -y g++ python3
+    - name: ${{ matrix.image }}
+      run: |
+        python3 configure.py --bootstrap
+        ./ninja all
+        ./ninja_test --gtest_filter=-SubprocessTest.SetWithLots
+        python3 misc/ninja_syntax_test.py
+        ./misc/output_test.py
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
new file mode 100644
index 0000000..af79080
--- /dev/null
+++ b/.github/workflows/macos.yml
@@ -0,0 +1,54 @@
+name: macOS
+
+on:
+  pull_request:
+  push:
+  release:
+    types: published
+
+jobs:
+  build:
+    runs-on: macos-11.0
+
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: Install dependencies
+      run: brew install re2c p7zip cmake
+
+    - name: Build ninja
+      shell: bash
+      env:
+        MACOSX_DEPLOYMENT_TARGET: 10.12
+      run: |
+        sudo xcode-select -s /Applications/Xcode_12.2.app
+        cmake -Bbuild -GXcode '-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64'
+        cmake --build build --config Release
+
+    - name: Test ninja
+      run: ctest -C Release -vv
+      working-directory: build
+
+    - name: Create ninja archive
+      shell: bash
+      run: |
+        mkdir artifact
+        7z a artifact/ninja-mac.zip ./build/Release/ninja
+
+    # Upload ninja binary archive as an artifact
+    - name: Upload artifact
+      uses: actions/upload-artifact@v1
+      with:
+        name: ninja-binary-archives
+        path: artifact
+
+    - name: Upload release asset
+      if: github.event.action == 'published'
+      uses: actions/upload-release-asset@v1.0.1
+      env:
+        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      with:
+        upload_url: ${{ github.event.release.upload_url }}
+        asset_path: ./artifact/ninja-mac.zip
+        asset_name: ninja-mac.zip
+        asset_content_type: application/zip
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
new file mode 100644
index 0000000..04fc2f6
--- /dev/null
+++ b/.github/workflows/windows.yml
@@ -0,0 +1,51 @@
+name: Windows
+
+on:
+  pull_request:
+  push:
+  release:
+    types: published
+
+jobs:
+  build:
+    runs-on: windows-latest
+
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: Install dependencies
+      run: choco install re2c
+
+    - name: Build ninja
+      shell: bash
+      run: |
+        cmake -DCMAKE_BUILD_TYPE=Release -B build
+        cmake --build build --parallel --config Release
+
+    - name: Test ninja
+      run: .\ninja_test.exe
+      working-directory: build/Release
+
+    - name: Create ninja archive
+      shell: bash
+      run: |
+        mkdir artifact
+        7z a artifact/ninja-win.zip ./build/Release/ninja.exe
+
+    # Upload ninja binary archive as an artifact
+    - name: Upload artifact
+      uses: actions/upload-artifact@v1
+      with:
+        name: ninja-binary-archives
+        path: artifact
+
+    - name: Upload release asset
+      if: github.event.action == 'published'
+      uses: actions/upload-release-asset@v1.0.1
+      env:
+        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      with:
+        upload_url: ${{ github.event.release.upload_url }}
+        asset_path: ./artifact/ninja-win.zip
+        asset_name: ninja-win.zip
+        asset_content_type: application/zip
diff --git a/.gitignore b/.gitignore
index 98fbb21..fdca015 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,6 @@
 *.exe
 *.pdb
 *.ilk
-TAGS
 /build*/
 /build.ninja
 /ninja
@@ -18,8 +17,8 @@
 /graph.png
 /doc/manual.html
 /doc/doxygen
-/gtest-1.6.0
 *.patch
+.DS_Store
 
 # Eclipse project files
 .project
@@ -36,3 +35,11 @@
 # Visual Studio Code project files
 /.vscode/
 /.ccls-cache/
+
+# Qt Creator project files
+/CMakeLists.txt.user
+
+# clangd
+/.clangd/
+/compile_commands.json
+/.cache/
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index e5d7d2b..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-matrix:
-  include:
-    - os: linux
-      dist: precise
-      compiler: gcc
-    - os: linux
-      dist: precise
-      compiler: clang
-    - os: linux
-      dist: trusty
-      compiler: gcc
-    - os: linux
-      dist: trusty
-      compiler: clang
-    - os: linux
-      dist: xenial
-      compiler: gcc
-    - os: linux
-      dist: xenial
-      compiler: clang
-    - os: osx
-      osx_image: xcode10
-    - os: osx
-      osx_image: xcode10.1
-sudo: false
-language: cpp
-before_install:
-  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install re2c             ; fi
-  - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then choco install re2c python ; fi
-script:
-  - ./misc/ci.py
-  - python3 configure.py --bootstrap
-  - ./ninja all
-  - ./ninja_test --gtest_filter=-SubprocessTest.SetWithLots
-  - ./misc/ninja_syntax_test.py
-  - ./misc/output_test.py
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2390732..39348c9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,12 +1,39 @@
-cmake_minimum_required(VERSION 3.12)
+cmake_minimum_required(VERSION 3.15)
+
+include(CheckIncludeFileCXX)
+include(CheckIPOSupported)
+
 project(ninja)
 
-if(MSVC)
-	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /GR- /Zc:__cplusplus")
+# --- optional link-time optimization
+check_ipo_supported(RESULT lto_supported OUTPUT error)
+
+if(lto_supported)
+	message(STATUS "IPO / LTO enabled")
+	set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
 else()
-	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -fdiagnostics-color")
+	message(STATUS "IPO / LTO not supported: <${error}>")
 endif()
 
+# --- compiler flags
+if(MSVC)
+	set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+	string(REPLACE "/GR" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
+	string(APPEND CMAKE_CXX_FLAGS " /W4 /wd4100 /wd4267 /wd4706 /wd4702 /wd4244 /GR- /Zc:__cplusplus")
+	add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+else()
+	include(CheckCXXCompilerFlag)
+	check_cxx_compiler_flag(-Wno-deprecated flag_no_deprecated)
+	if(flag_no_deprecated)
+		string(APPEND CMAKE_CXX_FLAGS " -Wno-deprecated")
+	endif()
+	check_cxx_compiler_flag(-fdiagnostics-color flag_color_diag)
+	if(flag_color_diag)
+		string(APPEND CMAKE_CXX_FLAGS " -fdiagnostics-color")
+	endif()
+endif()
+
+# --- optional re2c
 find_program(RE2C re2c)
 if(RE2C)
 	# the depfile parser and ninja lexers are generated using re2c.
@@ -15,15 +42,39 @@
 			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
@@ -61,42 +112,104 @@
 	endif()
 else()
 	target_sources(libninja PRIVATE src/subprocess-posix.cc)
+	if(CMAKE_SYSTEM_NAME STREQUAL "OS400" OR CMAKE_SYSTEM_NAME STREQUAL "AIX")
+		target_sources(libninja PRIVATE src/getopt.c)
+	endif()
+
+	# Needed for perfstat_cpu_total
+	if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
+		target_link_libraries(libninja PUBLIC "-lperfstat")
+	endif()
 endif()
 
 #Fixes GetActiveProcessorCount on MinGW
 if(MINGW)
-target_compile_definitions(libninja PRIVATE _WIN32_WINNT=0x0601)
+target_compile_definitions(libninja PRIVATE _WIN32_WINNT=0x0601 __USE_MINGW_ANSI_STDIO=1)
+endif()
+
+# On IBM i (identified as "OS400" for compatibility reasons) and AIX, this fixes missing
+# PRId64 (and others) at compile time in C++ sources
+if(CMAKE_SYSTEM_NAME STREQUAL "OS400" OR CMAKE_SYSTEM_NAME STREQUAL "AIX")
+	string(APPEND CMAKE_CXX_FLAGS " -D__STDC_FORMAT_MACROS")
 endif()
 
 # Main executable is library plus main() function.
 add_executable(ninja src/ninja.cc)
 target_link_libraries(ninja PRIVATE libninja libninja-re2c)
 
-# Tests all build into ninja_test executable.
-add_executable(ninja_test
-	src/build_log_test.cc
-	src/build_test.cc
-	src/clean_test.cc
-	src/clparser_test.cc
-	src/depfile_parser_test.cc
-	src/deps_log_test.cc
-	src/disk_interface_test.cc
-	src/dyndep_parser_test.cc
-	src/edit_distance_test.cc
-	src/graph_test.cc
-	src/lexer_test.cc
-	src/manifest_parser_test.cc
-	src/ninja_test.cc
-	src/state_test.cc
-	src/string_piece_util_test.cc
-	src/subprocess_test.cc
-	src/test.cc
-	src/util_test.cc
-)
-if(WIN32)
-	target_sources(ninja_test PRIVATE src/includes_normalize_test.cc src/msvc_helper_test.cc)
-endif()
-target_link_libraries(ninja_test 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_COMMAND} -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
+	)
 
-enable_testing()
-add_test(NinjaTest ninja_test)
+	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()
+
+include(CTest)
+if(BUILD_TESTING)
+  # Tests all build into ninja_test executable.
+  add_executable(ninja_test
+    src/build_log_test.cc
+    src/build_test.cc
+    src/clean_test.cc
+    src/clparser_test.cc
+    src/depfile_parser_test.cc
+    src/deps_log_test.cc
+    src/disk_interface_test.cc
+    src/dyndep_parser_test.cc
+    src/edit_distance_test.cc
+    src/graph_test.cc
+    src/lexer_test.cc
+    src/manifest_parser_test.cc
+    src/ninja_test.cc
+    src/state_test.cc
+    src/string_piece_util_test.cc
+    src/subprocess_test.cc
+    src/test.cc
+    src/util_test.cc
+  )
+  if(WIN32)
+    target_sources(ninja_test PRIVATE src/includes_normalize_test.cc src/msvc_helper_test.cc)
+  endif()
+  target_link_libraries(ninja_test PRIVATE libninja libninja-re2c)
+
+  foreach(perftest
+    build_log_perftest
+    canon_perftest
+    clparser_perftest
+    depfile_parser_perftest
+    hash_collision_bench
+    manifest_parser_perftest
+  )
+    add_executable(${perftest} src/${perftest}.cc)
+    target_link_libraries(${perftest} PRIVATE libninja libninja-re2c)
+  endforeach()
+
+  if(CMAKE_SYSTEM_NAME STREQUAL "AIX" AND CMAKE_SIZEOF_VOID_P EQUAL 4)
+    # These tests require more memory than will fit in the standard AIX shared stack/heap (256M)
+    target_link_libraries(hash_collision_bench PRIVATE "-Wl,-bmaxdata:0x80000000")
+    target_link_libraries(manifest_parser_perftest PRIVATE "-Wl,-bmaxdata:0x80000000")
+  endif()
+
+  add_test(NAME NinjaTest COMMAND ninja_test)
+endif()
+
+install(TARGETS ninja DESTINATION bin)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..be1fc02
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,34 @@
+# How to successfully make changes to Ninja
+
+We're very wary of changes that increase the complexity of Ninja (in particular,
+new build file syntax or command-line flags) or increase the maintenance burden
+of Ninja. Ninja is already successfully used by hundreds of developers for large
+projects and it already achieves (most of) the goals we set out for it to do.
+It's probably best to discuss new feature ideas on the
+[mailing list](https://groups.google.com/forum/#!forum/ninja-build) or in an
+issue before creating a PR.
+
+## Coding guidelines
+
+Generally it's the
+[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) with
+a few additions:
+
+* Any code merged into the Ninja codebase which will be part of the main
+  executable must compile as C++03. You may use C++11 features in a test or an
+  unimportant tool if you guard your code with `#if __cplusplus >= 201103L`.
+* We have used `using namespace std;` a lot in the past. For new contributions,
+  please try to avoid relying on it and instead whenever possible use `std::`.
+  However, please do not change existing code simply to add `std::` unless your
+  contribution already needs to change that line of code anyway.
+* All source files should have the Google Inc. license header.
+* Use `///` for [Doxygen](http://www.doxygen.nl/) (use `\a` to refer to
+  arguments).
+* It's not necessary to document each argument, especially when they're
+  relatively self-evident (e.g. in
+  `CanonicalizePath(string* path, string* err)`, the arguments are hopefully
+  obvious).
+
+If you're unsure about code formatting, please use
+[clang-format](https://clang.llvm.org/docs/ClangFormat.html). However, please do
+not format code that is not otherwise part of your contribution.
diff --git a/HACKING.md b/HACKING.md
deleted file mode 100644
index bd6fec7..0000000
--- a/HACKING.md
+++ /dev/null
@@ -1,252 +0,0 @@
-## Basic overview
-
-`./configure.py` generates the `build.ninja` files used to build
-ninja.  It accepts various flags to adjust build parameters.
-Run './configure.py --help' for more configuration options.
-
-The primary build target of interest is `ninja`, but when hacking on
-Ninja your changes should be testable so it's more useful to build and
-run `ninja_test` when developing.
-
-### Bootstrapping
-
-Ninja is built using itself.  To bootstrap the first binary, run the
-configure script as `./configure.py --bootstrap`.  This first compiles
-all non-test source files together, then re-builds Ninja using itself.
-You should end up with a `ninja` binary (or `ninja.exe`) in the project root.
-
-#### Windows
-
-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).
-
-For other combinations such as gcc/clang you will need the compiler
-(gcc/cl) in your PATH and you will have to set the appropriate
-platform configuration script.
-
-See below if you want to use mingw or some other compiler instead of
-Visual Studio.
-
-##### Using Visual Studio
-Assuming that you now have Python installed, then the steps for building under
-Windows using Visual Studio are:
-
-Clone and checkout the latest release (or whatever branch you want). You
-can do this in either a command prompt or by opening a git bash prompt:
-
-```
-    $ git clone git://github.com/ninja-build/ninja.git && cd ninja
-    $ git checkout release
-```
-
-Then:
-
-1. Open a Windows command prompt in the folder where you checked out ninja.
-2. Select the Microsoft build environment by running
-`vcvarsall.bat` with the appropriate environment.
-3. Build ninja and test it.
-
-The steps for a Visual Studio 2015 64-bit build are outlined here:
-
-```
-    > "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
-    > python configure.py --bootstrap
-    > ninja --help
-```
-Copy the ninja executable to another location, if desired, e.g. C:\local\Ninja.
-
-Finally add the path where ninja.exe is to the PATH variable.
-
-### Adjusting build flags
-
-Build in "debug" mode while developing (disables optimizations and builds
-way faster on Windows):
-
-    ./configure.py --debug
-
-To use clang, set `CXX`:
-
-    CXX=clang++ ./configure.py
-
-## How to successfully make changes to Ninja
-
-Github pull requests are convenient for me to merge (I can just click
-a button and it's all handled server-side), but I'm also comfortable
-accepting pre-github git patches (via `send-email` etc.).
-
-Good pull requests have all of these attributes:
-
-* Are scoped to one specific issue
-* Include a test to demonstrate their correctness
-* Update the docs where relevant
-* Match the Ninja coding style (see below)
-* Don't include a mess of "oops, fix typo" commits
-
-These are typically merged without hesitation.  If a change is lacking
-any of the above I usually will ask you to fix it, though there are
-obvious exceptions (fixing typos in comments don't need tests).
-
-I am very wary of changes that increase the complexity of Ninja (in
-particular, new build file syntax or command-line flags) or increase
-the maintenance burden of Ninja.  Ninja is already successfully used
-by hundreds of developers for large projects and it already achieves
-(most of) the goals I set out for it to do.  It's probably best to
-discuss new feature ideas on the [mailing list](https://groups.google.com/forum/#!forum/ninja-build)
-before I shoot down your patch.
-
-## Testing
-
-### Test-driven development
-
-Set your build command to
-
-    ./ninja ninja_test && ./ninja_test --gtest_filter=MyTest.Name
-
-now you can repeatedly run that while developing until the tests pass
-(I frequently set it as my compilation command in Emacs).  Remember to
-build "all" before committing to verify the other source still works!
-
-## Testing performance impact of changes
-
-If you have a Chrome build handy, it's a good test case.  There's a
-script at `misc/measure.py` that repeatedly runs a command (to address
-variance) and summarizes its runtime.  E.g.
-
-    path/to/misc/measure.py path/to/my/ninja chrome
-
-For changing the depfile parser, you can also build `parser_perftest`
-and run that directly on some representative input files.
-
-## Coding guidelines
-
-Generally it's the [Google C++ coding style][], but in brief:
-
-* Function name are camelcase.
-* Member methods are camelcase, except for trivial getters which are
-  underscore separated.
-* Local variables are underscore separated.
-* Member variables are underscore separated and suffixed by an extra
-  underscore.
-* Two spaces indentation.
-* Opening braces is at the end of line.
-* Lines are 80 columns maximum.
-* All source files should have the Google Inc. license header.
-
-[Google C++ coding style]: https://google.github.io/styleguide/cppguide.html
-
-## Documentation
-
-### Style guidelines
-
-* Use `///` for doxygen.
-* Use `\a` to refer to arguments.
-* It's not necessary to document each argument, especially when they're
-  relatively self-evident (e.g. in `CanonicalizePath(string* path, string* err)`,
-  the arguments are hopefully obvious)
-
-### Building the manual
-
-    sudo apt-get install asciidoc --no-install-recommends
-    ./ninja manual
-
-### Building the code documentation
-
-    sudo apt-get install doxygen
-    ./ninja doxygen
-
-## Building for Windows
-
-While developing, it's helpful to copy `ninja.exe` to another name like
-`n.exe`; otherwise, rebuilds will be unable to write `ninja.exe` because
-it's locked while in use.
-
-### Via Visual Studio
-
-* Install Visual Studio (Express is fine), [Python for Windows][],
-  and (if making changes) googletest (see above instructions)
-* In a Visual Studio command prompt: `python configure.py --bootstrap`
-
-[Python for Windows]: http://www.python.org/getit/windows/
-
-### Via mingw on Windows (not well supported)
-
-* Install mingw, msys, and python
-* In the mingw shell, put Python in your path, and
-  `python configure.py --bootstrap`
-* To reconfigure, run `python configure.py`
-* Remember to strip the resulting executable if size matters to you
-
-### Via mingw on Linux (not well supported)
-
-Setup on Ubuntu Lucid:
-* `sudo apt-get install gcc-mingw32 wine`
-* `export CC=i586-mingw32msvc-cc CXX=i586-mingw32msvc-c++ AR=i586-mingw32msvc-ar`
-
-Setup on Ubuntu Precise:
-* `sudo apt-get install gcc-mingw-w64-i686 g++-mingw-w64-i686 wine`
-* `export CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++ AR=i686-w64-mingw32-ar`
-
-Setup on Arch:
-* Uncomment the `[multilib]` section of `/etc/pacman.conf` and `sudo pacman -Sy`.
-* `sudo pacman -S mingw-w64-gcc wine`
-* `export CC=x86_64-w64-mingw32-cc CXX=x86_64-w64-mingw32-c++ AR=x86_64-w64-mingw32-ar`
-* `export CFLAGS=-I/usr/x86_64-w64-mingw32/include`
-
-Then run:
-* `./configure.py --platform=mingw --host=linux`
-* Build `ninja.exe` using a Linux ninja binary: `/path/to/linux/ninja`
-* Run: `./ninja.exe`  (implicitly runs through wine(!))
-
-### Using Microsoft compilers on Linux (extremely flaky)
-
-The trick is to install just the compilers, and not all of Visual Studio,
-by following [these instructions][win7sdk].
-
-[win7sdk]: http://www.kegel.com/wine/cl-howto-win7sdk.html
-
-### Using gcov
-
-Do a clean debug build with the right flags:
-
-    CFLAGS=-coverage LDFLAGS=-coverage ./configure.py --debug
-    ninja -t clean ninja_test && ninja ninja_test
-
-Run the test binary to generate `.gcda` and `.gcno` files in the build
-directory, then run gcov on the .o files to generate `.gcov` files in the
-root directory:
-
-    ./ninja_test
-    gcov build/*.o
-
-Look at the generated `.gcov` files directly, or use your favorite gcov viewer.
-
-### Using afl-fuzz
-
-Build with afl-clang++:
-
-    CXX=path/to/afl-1.20b/afl-clang++ ./configure.py
-    ninja
-
-Then run afl-fuzz like so:
-
-    afl-fuzz -i misc/afl-fuzz -o /tmp/afl-fuzz-out ./ninja -n -f @@
-
-You can pass `-x misc/afl-fuzz-tokens` to use the token dictionary. In my
-testing, that did not seem more effective though.
-
-#### Using afl-fuzz with asan
-
-If you want to use asan (the `isysroot` bit is only needed on OS X; if clang
-can't find C++ standard headers make sure your LLVM checkout includes a libc++
-checkout and has libc++ installed in the build directory):
-
-    CFLAGS="-fsanitize=address -isysroot $(xcrun -show-sdk-path)" \
-        LDFLAGS=-fsanitize=address CXX=path/to/afl-1.20b/afl-clang++ \
-        ./configure.py
-    AFL_CXX=path/to/clang++ ninja
-
-Make sure ninja can find the asan runtime:
-
-    DYLD_LIBRARY_PATH=path/to//lib/clang/3.7.0/lib/darwin/ \
-        afl-fuzz -i misc/afl-fuzz -o /tmp/afl-fuzz-out ./ninja -n -f @@
diff --git a/README b/README
deleted file mode 100644
index a1535ff..0000000
--- a/README
+++ /dev/null
@@ -1,21 +0,0 @@
-Ninja is a small build system with a focus on speed.
-https://ninja-build.org/
-
-See the manual -- https://ninja-build.org/manual.html or
-doc/manual.asciidoc included in the distribution -- for background
-and more details.
-
-Binaries for Linux, Mac, and Windows are available at
-  https://github.com/ninja-build/ninja/releases
-Run './ninja -h' for Ninja help.
-
-To build your own binary, on many platforms it should be sufficient to
-just run `./configure.py --bootstrap`; for more details see HACKING.md.
-(Also read that before making changes to Ninja, as it has advice.)
-
-Installation is not necessary because the only required file is the
-resulting ninja binary. However, to enable features like Bash
-completion and Emacs and Vim editing modes, some files in misc/ must be
-copied to appropriate locations.
-
-If you're interested in making changes to Ninja, read HACKING.md first.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d11fd33
--- /dev/null
+++ b/README.md
@@ -0,0 +1,51 @@
+# Ninja
+
+Ninja is a small build system with a focus on speed.
+https://ninja-build.org/
+
+See [the manual](https://ninja-build.org/manual.html) or
+`doc/manual.asciidoc` included in the distribution for background
+and more details.
+
+Binaries for Linux, Mac, and Windows are available at
+  [GitHub](https://github.com/ninja-build/ninja/releases).
+Run `./ninja -h` for Ninja help.
+
+Installation is not necessary because the only required file is the
+resulting ninja binary. However, to enable features like Bash
+completion and Emacs and Vim editing modes, some files in misc/ must be
+copied to appropriate locations.
+
+If you're interested in making changes to Ninja, read
+[CONTRIBUTING.md](CONTRIBUTING.md) first.
+
+## Building Ninja itself
+
+You can either build Ninja via the custom generator script written in Python or
+via CMake. For more details see
+[the wiki](https://github.com/ninja-build/ninja/wiki).
+
+### Python
+
+```
+./configure.py --bootstrap
+```
+
+This will generate the `ninja` binary and a `build.ninja` file you can now use
+to build Ninja with itself.
+
+### CMake
+
+```
+cmake -Bbuild-cmake -H.
+cmake --build build-cmake
+```
+
+The `ninja` binary will now be inside the `build-cmake` directory (you can
+choose any other name you like).
+
+To run the unit tests:
+
+```
+./build-cmake/ninja_test
+```
diff --git a/RELEASING b/RELEASING
index da4dbdd..0b03341 100644
--- a/RELEASING
+++ b/RELEASING
@@ -1,7 +1,7 @@
 Notes to myself on all the steps to make for a Ninja release.
 
 Push new release branch:
-1. Run afl-fuzz for a day or so (see HACKING.md) and run ninja_test
+1. Run afl-fuzz for a day or so and run ninja_test
 2. Consider sending a heads-up to the ninja-build mailing list first
 3. Make sure branches 'master' and 'release' are synced up locally
 4. Update src/version.cc with new version (with ".git"), then
diff --git a/bootstrap.py b/bootstrap.py
deleted file mode 100755
index 56eab64..0000000
--- a/bootstrap.py
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2011 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from __future__ import print_function
-
-import subprocess
-import sys
-
-print('DEPRECATED: this script will be deleted.')
-print('use "configure.py --bootstrap" instead.')
-subprocess.check_call([sys.executable, 'configure.py', '--bootstrap'])
diff --git a/configure.py b/configure.py
index 1d6ee7d..cded265 100755
--- a/configure.py
+++ b/configure.py
@@ -269,7 +269,7 @@
     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'
@@ -356,7 +356,7 @@
     except:
         pass
     if platform.is_mingw():
-        cflags += ['-D_WIN32_WINNT=0x0601']
+        cflags += ['-D_WIN32_WINNT=0x0601', '-D__USE_MINGW_ANSI_STDIO=1']
     ldflags = ['-L$builddir']
     if platform.uses_usr_local():
         cflags.append('-I/usr/local/include')
@@ -596,6 +596,11 @@
 
 n.comment('Ancillary executables.')
 
+if platform.is_aix() and '-maix64' not in ldflags:
+    # Both hash_collision_bench and manifest_parser_perftest require more
+    # memory than will fit in the standard 32-bit AIX shared stack/heap (256M)
+    libs.append('-Wl,-bmaxdata:0x80000000')
+
 for name in ['build_log_perftest',
              'canon_perftest',
              'depfile_parser_perftest',
@@ -649,7 +654,7 @@
        command='$doxygen_mainpage_generator $in > $out',
        description='DOXYGEN_MAINPAGE $out')
 mainpage = n.build(built('doxygen_mainpage'), 'doxygen_mainpage',
-                   ['README', 'COPYING'],
+                   ['README.md', 'COPYING'],
                    implicit=['$doxygen_mainpage_generator'])
 n.build('doxygen', 'doxygen', doc('doxygen.config'),
         implicit=mainpage)
diff --git a/doc/manual.asciidoc b/doc/manual.asciidoc
index e49d26d..e1ae083 100644
--- a/doc/manual.asciidoc
+++ b/doc/manual.asciidoc
@@ -271,6 +271,9 @@
 tool takes in account the +-v+ and the +-n+ options (note that +-n+
 implies +-v+).
 
+`cleandead`:: remove files produced by previous builds that are no longer in the
+build file. _Available since Ninja 1.10._
+
 `compdb`:: given a list of rules, each of which is expected to be a
 C family language compiler rule whose first input is the name of the
 source file, prints on standard output a compilation database in the
@@ -283,6 +286,9 @@
 
 `recompact`:: recompact the `.ninja_deps` file. _Available since Ninja 1.4._
 
+`restat`:: updates all recorded file modification timestamps in the `.ninja_log`
+file. _Available since Ninja 1.10._
+
 `rules`:: output the list of all rules (eventually with their description
 if they have one).  It can be used to know which rule name to pass to
 +ninja -t targets rule _name_+ or +ninja -t compdb+.
@@ -569,10 +575,10 @@
 ----
 rule cc
   depfile = $out.d
-  command = gcc -MMD -MF $out.d [other gcc flags here]
+  command = gcc -MD -MF $out.d [other gcc flags here]
 ----
 
-The `-MMD` flag to `gcc` tells it to output header dependencies, and
+The `-MD` flag to `gcc` tells it to output header dependencies, and
 the `-MF` flag tells it where to write them.
 
 deps
@@ -893,7 +899,7 @@
 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
@@ -929,7 +935,7 @@
 
 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/misc/manifest_fuzzer.cc b/misc/manifest_fuzzer.cc
new file mode 100644
index 0000000..0e1261a
--- /dev/null
+++ b/misc/manifest_fuzzer.cc
@@ -0,0 +1,41 @@
+// Copyright 2020 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "stdint.h"
+#include <string>
+#include "disk_interface.h"
+#include "state.h"
+#include "manifest_parser.h"
+#include <filesystem>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+	char build_file[256];
+	sprintf(build_file, "/tmp/build.ninja");
+	FILE *fp = fopen(build_file, "wb");
+	if (!fp)
+		return 0;
+	fwrite(data, size, 1, fp);
+	fclose(fp);	
+	
+	std::string err;
+	RealDiskInterface disk_interface;
+	State state;
+	ManifestParser parser(&state, &disk_interface);
+	
+	parser.Load("/tmp/build.ninja", &err);
+	
+	std::__fs::filesystem::remove_all("/tmp/build.ninja");
+	return 0;
+}
diff --git a/misc/ninja_syntax.py b/misc/ninja_syntax.py
index ebe6490..ab5c0d4 100644
--- a/misc/ninja_syntax.py
+++ b/misc/ninja_syntax.py
@@ -1,5 +1,19 @@
 #!/usr/bin/python
 
+# Copyright 2011 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 """Python module for generating .ninja files.
 
 Note that this is emphatically not a required piece of Ninja; it's
diff --git a/misc/oss-fuzz/build.sh b/misc/oss-fuzz/build.sh
new file mode 100644
index 0000000..4328feb
--- /dev/null
+++ b/misc/oss-fuzz/build.sh
@@ -0,0 +1,29 @@
+#!/bin/bash -eu
+# Copyright 2020 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+################################################################################
+
+cmake -Bbuild-cmake -H.
+cmake --build build-cmake
+
+cd $SRC/ninja/misc
+
+$CXX $CXXFLAGS -fdiagnostics-color -I/src/ninja/src -o fuzzer.o -c manifest_fuzzer.cc
+
+find .. -name "*.o" -exec ar rcs fuzz_lib.a {} \;
+
+$CXX $CXXFLAGS $LIB_FUZZING_ENGINE fuzzer.o -o $OUT/fuzzer fuzz_lib.a
+
+zip $OUT/fuzzer_seed_corpus.zip $SRC/sample_ninja_build
diff --git a/misc/oss-fuzz/sample_ninja_build b/misc/oss-fuzz/sample_ninja_build
new file mode 100644
index 0000000..7b513be
--- /dev/null
+++ b/misc/oss-fuzz/sample_ninja_build
@@ -0,0 +1,14 @@
+# build.ninja
+cc     = clang
+cflags = -Weverything
+
+rule compile
+  command = $cc $cflags -c $in -o $out
+
+rule link
+  command = $cc $in -o $out
+
+build hello.o: compile hello.c
+build hello: link hello.o
+
+default hello
diff --git a/misc/output_test.py b/misc/output_test.py
index fb73d72..b63520f 100755
--- a/misc/output_test.py
+++ b/misc/output_test.py
@@ -18,12 +18,15 @@
 if 'CLICOLOR_FORCE' in default_env:
     del default_env['CLICOLOR_FORCE']
 default_env['TERM'] = ''
+NINJA_PATH = os.path.abspath('./ninja')
 
 def run(build_ninja, flags='', pipe=False, env=default_env):
-    with tempfile.NamedTemporaryFile('w') as f:
-        f.write(build_ninja)
-        f.flush()
-        ninja_cmd = './ninja {} -f {}'.format(flags, f.name)
+    with tempfile.TemporaryDirectory() as d:
+        os.chdir(d)
+        with open('build.ninja', 'w') as f:
+            f.write(build_ninja)
+            f.flush()
+        ninja_cmd = '{} {}'.format(NINJA_PATH, flags)
         try:
             if pipe:
                 output = subprocess.check_output([ninja_cmd], shell=True, env=env)
@@ -43,6 +46,7 @@
         final_output += line.replace('\r', '')
     return final_output
 
+@unittest.skipIf(platform.system() == 'Windows', 'These test methods do not work on Windows')
 class Output(unittest.TestCase):
     def test_issue_1418(self):
         self.assertEqual(run(
@@ -99,5 +103,13 @@
 \x1b[31mred\x1b[0m
 ''')
 
+    def test_pr_1685(self):
+        # Running those tools without .ninja_deps and .ninja_log shouldn't fail.
+        self.assertEqual(run('', flags='-t recompact'), '')
+        self.assertEqual(run('', flags='-t restat'), '')
+
+    def test_status(self):
+        self.assertEqual(run(''), 'ninja: no work to do.\n')
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/misc/packaging/ninja.spec b/misc/packaging/ninja.spec
index 05f5a07..36e5181 100644
--- a/misc/packaging/ninja.spec
+++ b/misc/packaging/ninja.spec
@@ -32,7 +32,7 @@
 
 %files
 %defattr(-, root, root)
-%doc COPYING README doc/manual.html
+%doc COPYING README.md doc/manual.html
 %{_bindir}/*
 
 %clean
diff --git a/src/browse.cc b/src/browse.cc
index c08c9f4..76bee07 100644
--- a/src/browse.cc
+++ b/src/browse.cc
@@ -22,6 +22,8 @@
 
 #include "build/browse_py.h"
 
+using namespace std;
+
 void RunBrowsePython(State* state, const char* ninja_command,
                      const char* input_file, int argc, char* argv[]) {
   // Fork off a Python process and have it run our code via its stdin.
diff --git a/src/browse.py b/src/browse.py
index 1c9c39b..653cbe9 100755
--- a/src/browse.py
+++ b/src/browse.py
@@ -29,12 +29,15 @@
     import BaseHTTPServer as httpserver
     import SocketServer as socketserver
 import argparse
-import cgi
 import os
 import socket
 import subprocess
 import sys
 import webbrowser
+if sys.version_info >= (3, 2):
+    from html import escape
+else:
+    from cgi import escape
 try:
     from urllib.request import unquote
 except ImportError:
@@ -62,7 +65,7 @@
     return (True, line[len(prefix):])
 
 def html_escape(text):
-    return cgi.escape(text, quote=True)
+    return escape(text, quote=True)
 
 def parse(text):
     lines = iter(text.split('\n'))
diff --git a/src/build.cc b/src/build.cc
index 931fb95..2007d82 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -40,6 +40,8 @@
 #include "subprocess.h"
 #include "util.h"
 
+using namespace std;
+
 namespace {
 
 /// A CommandRunner that doesn't actually run the commands.
@@ -77,12 +79,9 @@
 }  // namespace
 
 BuildStatus::BuildStatus(const BuildConfig& config)
-    : config_(config),
-      start_time_millis_(GetTimeMillis()),
-      started_edges_(0), finished_edges_(0), total_edges_(0),
-      progress_status_format_(NULL),
-      overall_rate_(), current_rate_(config.parallelism) {
-
+    : config_(config), start_time_millis_(GetTimeMillis()), started_edges_(0),
+      finished_edges_(0), total_edges_(0), progress_status_format_(NULL),
+      current_rate_(config.parallelism) {
   // Don't do anything fancy in verbose mode.
   if (config_.verbosity != BuildConfig::NORMAL)
     printer_.set_smart_terminal(false);
@@ -96,7 +95,7 @@
   total_edges_ = total;
 }
 
-void BuildStatus::BuildEdgeStarted(Edge* edge) {
+void BuildStatus::BuildEdgeStarted(const Edge* edge) {
   assert(running_edges_.find(edge) == running_edges_.end());
   int start_time = (int)(GetTimeMillis() - start_time_millis_);
   running_edges_.insert(make_pair(edge, start_time));
@@ -183,7 +182,7 @@
   // 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
@@ -290,7 +289,7 @@
   return out;
 }
 
-void BuildStatus::PrintStatus(Edge* edge, EdgeStatus status) {
+void BuildStatus::PrintStatus(const Edge* edge, EdgeStatus status) {
   if (config_.verbosity == BuildConfig::QUIET)
     return;
 
@@ -319,11 +318,11 @@
   want_.clear();
 }
 
-bool Plan::AddTarget(Node* node, string* err) {
-  return AddSubTarget(node, NULL, err, NULL);
+bool Plan::AddTarget(const Node* target, string* err) {
+  return AddSubTarget(target, NULL, err, NULL);
 }
 
-bool Plan::AddSubTarget(Node* node, Node* dependent, string* err,
+bool Plan::AddSubTarget(const Node* node, const Node* dependent, string* err,
                         set<Edge*>* dyndep_walk) {
   Edge* edge = node->in_edge();
   if (!edge) {  // Leaf node.
@@ -382,7 +381,7 @@
 Edge* Plan::FindWork() {
   if (ready_.empty())
     return NULL;
-  set<Edge*>::iterator e = ready_.begin();
+  EdgeSet::iterator e = ready_.begin();
   Edge* edge = *e;
   ready_.erase(e);
   return edge;
@@ -533,7 +532,7 @@
   return true;
 }
 
-bool Plan::DyndepsLoaded(DependencyScan* scan, Node* node,
+bool Plan::DyndepsLoaded(DependencyScan* scan, const Node* node,
                          const DyndepFile& ddf, string* err) {
   // Recompute the dirty state of all our direct and indirect dependents now
   // that our dyndep information has been loaded.
@@ -601,7 +600,7 @@
   return true;
 }
 
-bool Plan::RefreshDyndepDependents(DependencyScan* scan, Node* node,
+bool Plan::RefreshDyndepDependents(DependencyScan* scan, const Node* node,
                                    string* err) {
   // Collect the transitive closure of dependents and mark their edges
   // as not yet visited by RecomputeDirty.
@@ -635,7 +634,7 @@
   return true;
 }
 
-void Plan::UnmarkDependents(Node* node, set<Node*>* dependents) {
+void Plan::UnmarkDependents(const Node* node, set<Node*>* dependents) {
   for (vector<Edge*>::const_iterator oe = node->out_edges().begin();
        oe != node->out_edges().end(); ++oe) {
     Edge* edge = *oe;
@@ -655,9 +654,9 @@
   }
 }
 
-void Plan::Dump() {
+void Plan::Dump() const {
   printf("pending: %d\n", (int)want_.size());
-  for (map<Edge*, Want>::iterator e = want_.begin(); e != want_.end(); ++e) {
+  for (map<Edge*, Want>::const_iterator e = want_.begin(); e != want_.end(); ++e) {
     if (e->second != kWantNothing)
       printf("want ");
     e->first->Dump();
@@ -676,12 +675,12 @@
 
   const BuildConfig& config_;
   SubprocessSet subprocs_;
-  map<Subprocess*, Edge*> subproc_to_edge_;
+  map<const Subprocess*, Edge*> subproc_to_edge_;
 };
 
 vector<Edge*> RealCommandRunner::GetActiveEdges() {
   vector<Edge*> edges;
-  for (map<Subprocess*, Edge*>::iterator e = subproc_to_edge_.begin();
+  for (map<const Subprocess*, Edge*>::iterator e = subproc_to_edge_.begin();
        e != subproc_to_edge_.end(); ++e)
     edges.push_back(e->second);
   return edges;
@@ -720,7 +719,7 @@
   result->status = subproc->Finish();
   result->output = subproc->GetOutput();
 
-  map<Subprocess*, Edge*>::iterator e = subproc_to_edge_.find(subproc);
+  map<const Subprocess*, Edge*>::iterator e = subproc_to_edge_.find(subproc);
   result->edge = e->second;
   subproc_to_edge_.erase(e);
 
@@ -783,16 +782,16 @@
   return node;
 }
 
-bool Builder::AddTarget(Node* node, string* err) {
-  if (!scan_.RecomputeDirty(node, err))
+bool Builder::AddTarget(Node* target, string* err) {
+  if (!scan_.RecomputeDirty(target, err))
     return false;
 
-  if (Edge* in_edge = node->in_edge()) {
+  if (Edge* in_edge = target->in_edge()) {
     if (in_edge->outputs_ready())
       return true;  // Nothing to do.
   }
 
-  if (!plan_.AddTarget(node, err))
+  if (!plan_.AddTarget(target, err))
     return false;
 
   return true;
@@ -829,6 +828,10 @@
     // See if we can start any more commands.
     if (failures_allowed && command_runner_->CanRunMore()) {
       if (Edge* edge = plan_.FindWork()) {
+        if (edge->GetBindingBool("generator")) {
+          scan_.build_log()->Close();
+        }
+
         if (!StartEdge(edge, err)) {
           Cleanup();
           status_->BuildFinished();
@@ -1033,14 +1036,16 @@
   }
 
   if (!deps_type.empty() && !config_.dry_run) {
-    assert(edge->outputs_.size() == 1 && "should have been rejected by parser");
-    Node* out = edge->outputs_[0];
-    TimeStamp deps_mtime = disk_interface_->Stat(out->path(), err);
-    if (deps_mtime == -1)
-      return false;
-    if (!scan_.deps_log()->RecordDeps(out, deps_mtime, deps_nodes)) {
-      *err = string("Error writing to deps log: ") + strerror(errno);
-      return false;
+    assert(!edge->outputs_.empty() && "should have been rejected by parser");
+    for (std::vector<Node*>::const_iterator o = edge->outputs_.begin();
+         o != edge->outputs_.end(); ++o) {
+      TimeStamp deps_mtime = disk_interface_->Stat((*o)->path(), err);
+      if (deps_mtime == -1)
+        return false;
+      if (!scan_.deps_log()->RecordDeps(*o, deps_mtime, deps_nodes)) {
+        *err = std::string("Error writing to deps log: ") + strerror(errno);
+        return false;
+      }
     }
   }
   return true;
@@ -1065,8 +1070,7 @@
       // complexity in IncludesNormalize::Relativize.
       deps_nodes->push_back(state_->GetNode(*i, ~0u));
     }
-  } else
-  if (deps_type == "gcc") {
+  } else if (deps_type == "gcc") {
     string depfile = result->edge->GetUnescapedDepfile();
     if (depfile.empty()) {
       *err = string("edge with deps=gcc but no depfile makes no sense");
diff --git a/src/build.h b/src/build.h
index 410d4a5..0a68478 100644
--- a/src/build.h
+++ b/src/build.h
@@ -19,7 +19,6 @@
 #include <map>
 #include <memory>
 #include <queue>
-#include <set>
 #include <string>
 #include <vector>
 
@@ -46,7 +45,7 @@
   /// Add a target to our plan (including all its dependencies).
   /// Returns false if we don't need to build this target; may
   /// fill in |err| with an error message if there's a problem.
-  bool AddTarget(Node* node, string* err);
+  bool AddTarget(const Node* target, std::string* err);
 
   // Pop a ready edge off the queue of edges to build.
   // Returns NULL if there's no work to do.
@@ -56,7 +55,7 @@
   bool more_to_do() const { return wanted_edges_ > 0 && command_edges_ > 0; }
 
   /// Dumps the current state of the plan.
-  void Dump();
+  void Dump() const;
 
   enum EdgeResult {
     kEdgeFailed,
@@ -67,11 +66,11 @@
   /// If any of the edge's outputs are dyndep bindings of their dependents,
   /// this loads dynamic dependencies from the nodes' paths.
   /// Returns 'false' if loading dyndep info fails and 'true' otherwise.
-  bool EdgeFinished(Edge* edge, EdgeResult result, string* err);
+  bool EdgeFinished(Edge* edge, EdgeResult result, std::string* err);
 
   /// Clean the given node during the build.
   /// Return false on error.
-  bool CleanNode(DependencyScan* scan, Node* node, string* err);
+  bool CleanNode(DependencyScan* scan, Node* node, std::string* err);
 
   /// Number of edges with commands to run.
   int command_edge_count() const { return command_edges_; }
@@ -81,19 +80,19 @@
 
   /// Update the build plan to account for modifications made to the graph
   /// by information loaded from a dyndep file.
-  bool DyndepsLoaded(DependencyScan* scan, Node* node,
-                     const DyndepFile& ddf, string* err);
+  bool DyndepsLoaded(DependencyScan* scan, const Node* node,
+                     const DyndepFile& ddf, std::string* err);
 private:
-  bool RefreshDyndepDependents(DependencyScan* scan, Node* node, string* err);
-  void UnmarkDependents(Node* node, set<Node*>* dependents);
-  bool AddSubTarget(Node* node, Node* dependent, string* err,
-                    set<Edge*>* dyndep_walk);
+  bool RefreshDyndepDependents(DependencyScan* scan, const Node* node, std::string* err);
+  void UnmarkDependents(const Node* node, std::set<Node*>* dependents);
+  bool AddSubTarget(const Node* node, const Node* dependent, std::string* err,
+                    std::set<Edge*>* dyndep_walk);
 
   /// Update plan with knowledge that the given node is up to date.
   /// If the node is a dyndep binding on any of its dependents, this
   /// loads dynamic dependencies from the node's path.
   /// Returns 'false' if loading dyndep info fails and 'true' otherwise.
-  bool NodeFinished(Node* node, string* err);
+  bool NodeFinished(Node* node, std::string* err);
 
   /// Enumerate possible steps we want for an edge.
   enum Want
@@ -109,20 +108,20 @@
   };
 
   void EdgeWanted(const Edge* edge);
-  bool EdgeMaybeReady(map<Edge*, Want>::iterator want_e, string* err);
+  bool EdgeMaybeReady(std::map<Edge*, Want>::iterator want_e, std::string* err);
 
   /// Submits a ready edge as a candidate for execution.
   /// The edge may be delayed from running, for example if it's a member of a
   /// currently-full pool.
-  void ScheduleWork(map<Edge*, Want>::iterator want_e);
+  void ScheduleWork(std::map<Edge*, Want>::iterator want_e);
 
   /// Keep track of which edges we want to build in this plan.  If this map does
   /// not contain an entry for an edge, we do not want to build the entry or its
   /// dependents.  If it does contain an entry, the enumeration indicates what
   /// we want for the edge.
-  map<Edge*, Want> want_;
+  std::map<Edge*, Want> want_;
 
-  set<Edge*> ready_;
+  EdgeSet ready_;
 
   Builder* builder_;
 
@@ -146,13 +145,13 @@
     Result() : edge(NULL) {}
     Edge* edge;
     ExitStatus status;
-    string output;
+    std::string output;
     bool success() const { return status == ExitSuccess; }
   };
   /// Wait for a command to complete, or return false if interrupted.
   virtual bool WaitForCommand(Result* result) = 0;
 
-  virtual vector<Edge*> GetActiveEdges() { return vector<Edge*>(); }
+  virtual std::vector<Edge*> GetActiveEdges() { return std::vector<Edge*>(); }
   virtual void Abort() {}
 };
 
@@ -186,24 +185,24 @@
   /// Clean up after interrupted commands by deleting output files.
   void Cleanup();
 
-  Node* AddTarget(const string& name, string* err);
+  Node* AddTarget(const std::string& name, std::string* err);
 
   /// Add a target to the build, scanning dependencies.
   /// @return false on error.
-  bool AddTarget(Node* target, string* err);
+  bool AddTarget(Node* target, std::string* err);
 
   /// Returns true if the build targets are already up to date.
   bool AlreadyUpToDate() const;
 
   /// Run the build.  Returns false on error.
   /// It is an error to call this function when AlreadyUpToDate() is true.
-  bool Build(string* err);
+  bool Build(std::string* err);
 
-  bool StartEdge(Edge* edge, string* err);
+  bool StartEdge(Edge* edge, std::string* err);
 
   /// Update status ninja logs following a command termination.
   /// @return false if the build can not proceed further due to a fatal error.
-  bool FinishCommand(CommandRunner::Result* result, string* err);
+  bool FinishCommand(CommandRunner::Result* result, std::string* err);
 
   /// Used for tests.
   void SetBuildLog(BuildLog* log) {
@@ -211,22 +210,22 @@
   }
 
   /// Load the dyndep information provided by the given node.
-  bool LoadDyndeps(Node* node, string* err);
+  bool LoadDyndeps(Node* node, std::string* err);
 
   State* state_;
   const BuildConfig& config_;
   Plan plan_;
 #if __cplusplus < 201703L
-  auto_ptr<CommandRunner> command_runner_;
+  std::auto_ptr<CommandRunner> command_runner_;
 #else
-  unique_ptr<CommandRunner> command_runner_;  // auto_ptr was removed in C++17.
+  std::unique_ptr<CommandRunner> command_runner_;  // auto_ptr was removed in C++17.
 #endif
   BuildStatus* status_;
 
  private:
-   bool ExtractDeps(CommandRunner::Result* result, const string& deps_type,
-                    const string& deps_prefix, vector<Node*>* deps_nodes,
-                    string* err);
+  bool ExtractDeps(CommandRunner::Result* result, const std::string& deps_type,
+                   const std::string& deps_prefix,
+                   std::vector<Node*>* deps_nodes, std::string* err);
 
   DiskInterface* disk_interface_;
   DependencyScan scan_;
@@ -240,8 +239,8 @@
 struct BuildStatus {
   explicit BuildStatus(const BuildConfig& config);
   void PlanHasTotalEdges(int total);
-  void BuildEdgeStarted(Edge* edge);
-  void BuildEdgeFinished(Edge* edge, bool success, const string& output,
+  void BuildEdgeStarted(const Edge* edge);
+  void BuildEdgeFinished(Edge* edge, bool success, const std::string& output,
                          int* start_time, int* end_time);
   void BuildLoadDyndeps();
   void BuildStarted();
@@ -257,11 +256,11 @@
   /// placeholders.
   /// @param progress_status_format The format of the progress status.
   /// @param status The status of the edge.
-  string FormatProgressStatus(const char* progress_status_format,
-                              EdgeStatus status) const;
+  std::string FormatProgressStatus(const char* progress_status_format,
+                                   EdgeStatus status) const;
 
  private:
-  void PrintStatus(Edge* edge, EdgeStatus status);
+  void PrintStatus(const Edge* edge, EdgeStatus status);
 
   const BuildConfig& config_;
 
@@ -271,7 +270,7 @@
   int started_edges_, finished_edges_, total_edges_;
 
   /// Map of running edge to time the edge started running.
-  typedef map<Edge*, int> RunningEdgeMap;
+  typedef std::map<const Edge*, int> RunningEdgeMap;
   RunningEdgeMap running_edges_;
 
   /// Prints progress output.
@@ -327,7 +326,7 @@
     double rate_;
     Stopwatch stopwatch_;
     const size_t N;
-    queue<double> times_;
+    std::queue<double> times_;
     int last_update_;
   };
 
diff --git a/src/build_log.cc b/src/build_log.cc
index c4a08a0..4dcd6ce 100644
--- a/src/build_log.cc
+++ b/src/build_log.cc
@@ -21,7 +21,9 @@
 #endif
 
 #include "build_log.h"
+#include "disk_interface.h"
 
+#include <cassert>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
@@ -39,6 +41,8 @@
 #define strtoll _strtoi64
 #endif
 
+using namespace std;
+
 // Implementation details:
 // Each run's log appends to the log file.
 // To load, we run through all log entries in series, throwing away
@@ -131,25 +135,9 @@
       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;
 }
 
@@ -173,6 +161,9 @@
     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;
@@ -185,11 +176,37 @@
 }
 
 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_ || log_file_path_.empty()) {
+    return true;
+  }
+  log_file_ = fopen(log_file_path_.c_str(), "ab");
+  if (!log_file_) {
+    return false;
+  }
+  if (setvbuf(log_file_, NULL, _IOLBF, BUFSIZ) != 0) {
+    return false;
+  }
+  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;
+    }
+  }
+  return true;
+}
+
 struct LineReader {
   explicit LineReader(FILE* file)
     : file_(file), buf_end_(buf_), line_start_(buf_), line_end_(NULL) {
@@ -241,14 +258,14 @@
   char* line_end_;
 };
 
-bool BuildLog::Load(const string& path, string* err) {
+LoadStatus BuildLog::Load(const string& path, string* err) {
   METRIC_RECORD(".ninja_log load");
   FILE* file = fopen(path.c_str(), "r");
   if (!file) {
     if (errno == ENOENT)
-      return true;
+      return LOAD_NOT_FOUND;
     *err = strerror(errno);
-    return false;
+    return LOAD_ERROR;
   }
 
   int log_version = 0;
@@ -269,7 +286,7 @@
         unlink(path.c_str());
         // Don't report this as a failure.  An empty build log will cause
         // us to rebuild the outputs anyway.
-        return true;
+        return LOAD_SUCCESS;
       }
     }
 
@@ -339,7 +356,7 @@
   fclose(file);
 
   if (!line_start) {
-    return true; // file was empty
+    return LOAD_SUCCESS; // file was empty
   }
 
   // Decide whether it's time to rebuild the log:
@@ -354,7 +371,7 @@
     needs_recompaction_ = true;
   }
 
-  return true;
+  return LOAD_SUCCESS;
 }
 
 BuildLog::LogEntry* BuildLog::LookupByOutput(const string& path) {
@@ -418,3 +435,60 @@
 
   return true;
 }
+
+bool BuildLog::Restat(const StringPiece path,
+                      const DiskInterface& disk_interface,
+                      const int output_count, char** outputs,
+                      std::string* const err) {
+  METRIC_RECORD(".ninja_log restat");
+
+  Close();
+  std::string temp_path = path.AsString() + ".restat";
+  FILE* f = fopen(temp_path.c_str(), "wb");
+  if (!f) {
+    *err = strerror(errno);
+    return false;
+  }
+
+  if (fprintf(f, kFileSignature, kCurrentVersion) < 0) {
+    *err = strerror(errno);
+    fclose(f);
+    return false;
+  }
+  for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) {
+    bool skip = output_count > 0;
+    for (int j = 0; j < output_count; ++j) {
+      if (i->second->output == outputs[j]) {
+        skip = false;
+        break;
+      }
+    }
+    if (!skip) {
+      const TimeStamp mtime = disk_interface.Stat(i->second->output, err);
+      if (mtime == -1) {
+        fclose(f);
+        return false;
+      }
+      i->second->mtime = mtime;
+    }
+
+    if (!WriteEntry(f, *i->second)) {
+      *err = strerror(errno);
+      fclose(f);
+      return false;
+    }
+  }
+
+  fclose(f);
+  if (unlink(path.str_) < 0) {
+    *err = strerror(errno);
+    return false;
+  }
+
+  if (rename(temp_path.c_str(), path.str_) < 0) {
+    *err = strerror(errno);
+    return false;
+  }
+
+  return true;
+}
diff --git a/src/build_log.h b/src/build_log.h
index 5268fab..88551e3 100644
--- a/src/build_log.h
+++ b/src/build_log.h
@@ -17,12 +17,13 @@
 
 #include <string>
 #include <stdio.h>
-using namespace std;
 
 #include "hash_map.h"
+#include "load_status.h"
 #include "timestamp.h"
 #include "util.h"  // uint64_t
 
+struct DiskInterface;
 struct Edge;
 
 /// Can answer questions about the manifest for the BuildLog.
@@ -43,16 +44,19 @@
   BuildLog();
   ~BuildLog();
 
-  bool OpenForWrite(const string& path, const BuildLogUser& user, string* err);
+  /// Prepares writing to the log file without actually opening it - that will
+  /// happen when/if it's needed
+  bool OpenForWrite(const std::string& path, const BuildLogUser& user,
+                    std::string* err);
   bool RecordCommand(Edge* edge, int start_time, int end_time,
                      TimeStamp mtime = 0);
   void Close();
 
   /// Load the on-disk log.
-  bool Load(const string& path, string* err);
+  LoadStatus Load(const std::string& path, std::string* err);
 
   struct LogEntry {
-    string output;
+    std::string output;
     uint64_t command_hash;
     int start_time;
     int end_time;
@@ -67,26 +71,36 @@
           mtime == o.mtime;
     }
 
-    explicit LogEntry(const string& output);
-    LogEntry(const string& output, uint64_t command_hash,
+    explicit LogEntry(const std::string& output);
+    LogEntry(const std::string& output, uint64_t command_hash,
              int start_time, int end_time, TimeStamp restat_mtime);
   };
 
   /// Lookup a previously-run command by its output path.
-  LogEntry* LookupByOutput(const string& path);
+  LogEntry* LookupByOutput(const std::string& path);
 
   /// Serialize an entry into a log file.
   bool WriteEntry(FILE* f, const LogEntry& entry);
 
   /// Rewrite the known log entries, throwing away old data.
-  bool Recompact(const string& path, const BuildLogUser& user, string* err);
+  bool Recompact(const std::string& path, const BuildLogUser& user,
+                 std::string* err);
+
+  /// Restat all outputs in the log
+  bool Restat(StringPiece path, const DiskInterface& disk_interface,
+              int output_count, char** outputs, std::string* err);
 
   typedef ExternalStringHashMap<LogEntry*>::Type Entries;
   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/build_log_perftest.cc b/src/build_log_perftest.cc
index e471d13..ced0df9 100644
--- a/src/build_log_perftest.cc
+++ b/src/build_log_perftest.cc
@@ -26,6 +26,8 @@
 #include <unistd.h>
 #endif
 
+using namespace std;
+
 const char kTestFilename[] = "BuildLogPerfTest-tempfile";
 
 struct NoDeadPaths : public BuildLogUser {
diff --git a/src/build_log_test.cc b/src/build_log_test.cc
index ad30380..3718299 100644
--- a/src/build_log_test.cc
+++ b/src/build_log_test.cc
@@ -25,6 +25,9 @@
 #include <sys/types.h>
 #include <unistd.h>
 #endif
+#include <cassert>
+
+using namespace std;
 
 namespace {
 
@@ -150,7 +153,7 @@
 
     BuildLog log3;
     err.clear();
-    ASSERT_TRUE(log3.Load(kTestFilename, &err) || !err.empty());
+    ASSERT_TRUE(log3.Load(kTestFilename, &err) == LOAD_SUCCESS || !err.empty());
   }
 }
 
@@ -216,6 +219,54 @@
   ASSERT_NO_FATAL_FAILURE(AssertHash("command2", e->command_hash));
 }
 
+struct TestDiskInterface : public DiskInterface {
+  virtual TimeStamp Stat(const string& path, string* err) const {
+    return 4;
+  }
+  virtual bool WriteFile(const string& path, const string& contents) {
+    assert(false);
+    return true;
+  }
+  virtual bool MakeDir(const string& path) {
+    assert(false);
+    return false;
+  }
+  virtual Status ReadFile(const string& path, string* contents, string* err) {
+    assert(false);
+    return NotFound;
+  }
+  virtual int RemoveFile(const string& path) {
+    assert(false);
+    return 0;
+  }
+};
+
+TEST_F(BuildLogTest, Restat) {
+  FILE* f = fopen(kTestFilename, "wb");
+  fprintf(f, "# ninja log v4\n"
+             "1\t2\t3\tout\tcommand\n");
+  fclose(f);
+  std::string err;
+  BuildLog log;
+  EXPECT_TRUE(log.Load(kTestFilename, &err));
+  ASSERT_EQ("", err);
+  BuildLog::LogEntry* e = log.LookupByOutput("out");
+  ASSERT_EQ(3, e->mtime);
+
+  TestDiskInterface testDiskInterface;
+  char out2[] = { 'o', 'u', 't', '2', 0 };
+  char* filter2[] = { out2 };
+  EXPECT_TRUE(log.Restat(kTestFilename, testDiskInterface, 1, filter2, &err));
+  ASSERT_EQ("", err);
+  e = log.LookupByOutput("out");
+  ASSERT_EQ(3, e->mtime); // unchanged, since the filter doesn't match
+
+  EXPECT_TRUE(log.Restat(kTestFilename, testDiskInterface, 0, NULL, &err));
+  ASSERT_EQ("", err);
+  e = log.LookupByOutput("out");
+  ASSERT_EQ(4, e->mtime);
+}
+
 TEST_F(BuildLogTest, VeryLongInputLine) {
   // Ninja's build log buffer is currently 256kB. Lines longer than that are
   // silently ignored, but don't affect parsing of other lines.
diff --git a/src/build_test.cc b/src/build_test.cc
index ddf8574..0baabc4 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -21,6 +21,8 @@
 #include "graph.h"
 #include "test.h"
 
+using namespace std;
+
 struct CompareEdgesByOutput {
   static bool cmp(const Edge* a, const Edge* b) {
     return a->outputs_[0]->path() < b->outputs_[0]->path();
@@ -488,6 +490,10 @@
                 status_(config_) {
   }
 
+  explicit BuildTest(DepsLog* log)
+      : config_(MakeConfig()), command_runner_(&fs_),
+        builder_(&state_, config_, NULL, log, &fs_), status_(config_) {}
+
   virtual void SetUp() {
     StateTestWithBuiltinRules::SetUp();
 
@@ -582,6 +588,8 @@
       edge->rule().name() == "cat_rsp" ||
       edge->rule().name() == "cat_rsp_out" ||
       edge->rule().name() == "cc" ||
+      edge->rule().name() == "cp_multi_msvc" ||
+      edge->rule().name() == "cp_multi_gcc" ||
       edge->rule().name() == "touch" ||
       edge->rule().name() == "touch-interrupt" ||
       edge->rule().name() == "touch-fail-tick2") {
@@ -643,6 +651,14 @@
     return true;
   }
 
+  if (edge->rule().name() == "cp_multi_msvc") {
+    const std::string prefix = edge->GetBinding("msvc_deps_prefix");
+    for (std::vector<Node*>::iterator in = edge->inputs_.begin();
+         in != edge->inputs_.end(); ++in) {
+      result->output += prefix + (*in)->path() + '\n';
+    }
+  }
+
   if (edge->rule().name() == "fail" ||
       (edge->rule().name() == "touch-fail-tick2" && fs_->now_ == 2))
     result->status = ExitFailure;
@@ -657,7 +673,7 @@
     bool verify_active_edge_found = false;
     for (vector<Edge*>::iterator i = active_edges_.begin();
          i != active_edges_.end(); ++i) {
-      if ((*i)->outputs_.size() >= 1 &&
+      if (!(*i)->outputs_.empty() &&
           (*i)->outputs_[0]->path() == verify_active_edge) {
         verify_active_edge_found = true;
       }
@@ -1855,6 +1871,214 @@
   EXPECT_EQ("subcommand failed", err);
 }
 
+struct BuildWithQueryDepsLogTest : public BuildTest {
+  BuildWithQueryDepsLogTest() : BuildTest(&log_) {
+  }
+
+  ~BuildWithQueryDepsLogTest() {
+    log_.Close();
+  }
+
+  virtual void SetUp() {
+    BuildTest::SetUp();
+
+    temp_dir_.CreateAndEnter("BuildWithQueryDepsLogTest");
+
+    std::string err;
+    ASSERT_TRUE(log_.OpenForWrite("ninja_deps", &err));
+    ASSERT_EQ("", err);
+  }
+
+  ScopedTempDir temp_dir_;
+
+  DepsLog log_;
+};
+
+/// Test a MSVC-style deps log with multiple outputs.
+TEST_F(BuildWithQueryDepsLogTest, TwoOutputsDepFileMSVC) {
+  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule cp_multi_msvc\n"
+"    command = echo 'using $in' && for file in $out; do cp $in $$file; done\n"
+"    deps = msvc\n"
+"    msvc_deps_prefix = using \n"
+"build out1 out2: cp_multi_msvc in1\n"));
+
+  std::string err;
+  EXPECT_TRUE(builder_.AddTarget("out1", &err));
+  ASSERT_EQ("", err);
+  EXPECT_TRUE(builder_.Build(&err));
+  EXPECT_EQ("", err);
+  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
+  EXPECT_EQ("echo 'using in1' && for file in out1 out2; do cp in1 $file; done", command_runner_.commands_ran_[0]);
+
+  Node* out1_node = state_.LookupNode("out1");
+  DepsLog::Deps* out1_deps = log_.GetDeps(out1_node);
+  EXPECT_EQ(1, out1_deps->node_count);
+  EXPECT_EQ("in1", out1_deps->nodes[0]->path());
+
+  Node* out2_node = state_.LookupNode("out2");
+  DepsLog::Deps* out2_deps = log_.GetDeps(out2_node);
+  EXPECT_EQ(1, out2_deps->node_count);
+  EXPECT_EQ("in1", out2_deps->nodes[0]->path());
+}
+
+/// Test a GCC-style deps log with multiple outputs.
+TEST_F(BuildWithQueryDepsLogTest, TwoOutputsDepFileGCCOneLine) {
+  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule cp_multi_gcc\n"
+"    command = echo '$out: $in' > in.d && for file in $out; do cp in1 $$file; done\n"
+"    deps = gcc\n"
+"    depfile = in.d\n"
+"build out1 out2: cp_multi_gcc in1 in2\n"));
+
+  std::string err;
+  EXPECT_TRUE(builder_.AddTarget("out1", &err));
+  ASSERT_EQ("", err);
+  fs_.Create("in.d", "out1 out2: in1 in2");
+  EXPECT_TRUE(builder_.Build(&err));
+  EXPECT_EQ("", err);
+  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
+  EXPECT_EQ("echo 'out1 out2: in1 in2' > in.d && for file in out1 out2; do cp in1 $file; done", command_runner_.commands_ran_[0]);
+
+  Node* out1_node = state_.LookupNode("out1");
+  DepsLog::Deps* out1_deps = log_.GetDeps(out1_node);
+  EXPECT_EQ(2, out1_deps->node_count);
+  EXPECT_EQ("in1", out1_deps->nodes[0]->path());
+  EXPECT_EQ("in2", out1_deps->nodes[1]->path());
+
+  Node* out2_node = state_.LookupNode("out2");
+  DepsLog::Deps* out2_deps = log_.GetDeps(out2_node);
+  EXPECT_EQ(2, out2_deps->node_count);
+  EXPECT_EQ("in1", out2_deps->nodes[0]->path());
+  EXPECT_EQ("in2", out2_deps->nodes[1]->path());
+}
+
+/// Test a GCC-style deps log with multiple outputs using a line per input.
+TEST_F(BuildWithQueryDepsLogTest, TwoOutputsDepFileGCCMultiLineInput) {
+  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule cp_multi_gcc\n"
+"    command = echo '$out: in1\\n$out: in2' > in.d && for file in $out; do cp in1 $$file; done\n"
+"    deps = gcc\n"
+"    depfile = in.d\n"
+"build out1 out2: cp_multi_gcc in1 in2\n"));
+
+  std::string err;
+  EXPECT_TRUE(builder_.AddTarget("out1", &err));
+  ASSERT_EQ("", err);
+  fs_.Create("in.d", "out1 out2: in1\nout1 out2: in2");
+  EXPECT_TRUE(builder_.Build(&err));
+  EXPECT_EQ("", err);
+  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
+  EXPECT_EQ("echo 'out1 out2: in1\\nout1 out2: in2' > in.d && for file in out1 out2; do cp in1 $file; done", command_runner_.commands_ran_[0]);
+
+  Node* out1_node = state_.LookupNode("out1");
+  DepsLog::Deps* out1_deps = log_.GetDeps(out1_node);
+  EXPECT_EQ(2, out1_deps->node_count);
+  EXPECT_EQ("in1", out1_deps->nodes[0]->path());
+  EXPECT_EQ("in2", out1_deps->nodes[1]->path());
+
+  Node* out2_node = state_.LookupNode("out2");
+  DepsLog::Deps* out2_deps = log_.GetDeps(out2_node);
+  EXPECT_EQ(2, out2_deps->node_count);
+  EXPECT_EQ("in1", out2_deps->nodes[0]->path());
+  EXPECT_EQ("in2", out2_deps->nodes[1]->path());
+}
+
+/// Test a GCC-style deps log with multiple outputs using a line per output.
+TEST_F(BuildWithQueryDepsLogTest, TwoOutputsDepFileGCCMultiLineOutput) {
+  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule cp_multi_gcc\n"
+"    command = echo 'out1: $in\\nout2: $in' > in.d && for file in $out; do cp in1 $$file; done\n"
+"    deps = gcc\n"
+"    depfile = in.d\n"
+"build out1 out2: cp_multi_gcc in1 in2\n"));
+
+  std::string err;
+  EXPECT_TRUE(builder_.AddTarget("out1", &err));
+  ASSERT_EQ("", err);
+  fs_.Create("in.d", "out1: in1 in2\nout2: in1 in2");
+  EXPECT_TRUE(builder_.Build(&err));
+  EXPECT_EQ("", err);
+  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
+  EXPECT_EQ("echo 'out1: in1 in2\\nout2: in1 in2' > in.d && for file in out1 out2; do cp in1 $file; done", command_runner_.commands_ran_[0]);
+
+  Node* out1_node = state_.LookupNode("out1");
+  DepsLog::Deps* out1_deps = log_.GetDeps(out1_node);
+  EXPECT_EQ(2, out1_deps->node_count);
+  EXPECT_EQ("in1", out1_deps->nodes[0]->path());
+  EXPECT_EQ("in2", out1_deps->nodes[1]->path());
+
+  Node* out2_node = state_.LookupNode("out2");
+  DepsLog::Deps* out2_deps = log_.GetDeps(out2_node);
+  EXPECT_EQ(2, out2_deps->node_count);
+  EXPECT_EQ("in1", out2_deps->nodes[0]->path());
+  EXPECT_EQ("in2", out2_deps->nodes[1]->path());
+}
+
+/// Test a GCC-style deps log with multiple outputs mentioning only the main output.
+TEST_F(BuildWithQueryDepsLogTest, TwoOutputsDepFileGCCOnlyMainOutput) {
+  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule cp_multi_gcc\n"
+"    command = echo 'out1: $in' > in.d && for file in $out; do cp in1 $$file; done\n"
+"    deps = gcc\n"
+"    depfile = in.d\n"
+"build out1 out2: cp_multi_gcc in1 in2\n"));
+
+  std::string err;
+  EXPECT_TRUE(builder_.AddTarget("out1", &err));
+  ASSERT_EQ("", err);
+  fs_.Create("in.d", "out1: in1 in2");
+  EXPECT_TRUE(builder_.Build(&err));
+  EXPECT_EQ("", err);
+  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
+  EXPECT_EQ("echo 'out1: in1 in2' > in.d && for file in out1 out2; do cp in1 $file; done", command_runner_.commands_ran_[0]);
+
+  Node* out1_node = state_.LookupNode("out1");
+  DepsLog::Deps* out1_deps = log_.GetDeps(out1_node);
+  EXPECT_EQ(2, out1_deps->node_count);
+  EXPECT_EQ("in1", out1_deps->nodes[0]->path());
+  EXPECT_EQ("in2", out1_deps->nodes[1]->path());
+
+  Node* out2_node = state_.LookupNode("out2");
+  DepsLog::Deps* out2_deps = log_.GetDeps(out2_node);
+  EXPECT_EQ(2, out2_deps->node_count);
+  EXPECT_EQ("in1", out2_deps->nodes[0]->path());
+  EXPECT_EQ("in2", out2_deps->nodes[1]->path());
+}
+
+/// Test a GCC-style deps log with multiple outputs mentioning only the secondary output.
+TEST_F(BuildWithQueryDepsLogTest, TwoOutputsDepFileGCCOnlySecondaryOutput) {
+  // Note: This ends up short-circuiting the node creation due to the primary
+  // output not being present, but it should still work.
+  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule cp_multi_gcc\n"
+"    command = echo 'out2: $in' > in.d && for file in $out; do cp in1 $$file; done\n"
+"    deps = gcc\n"
+"    depfile = in.d\n"
+"build out1 out2: cp_multi_gcc in1 in2\n"));
+
+  std::string err;
+  EXPECT_TRUE(builder_.AddTarget("out1", &err));
+  ASSERT_EQ("", err);
+  fs_.Create("in.d", "out2: in1 in2");
+  EXPECT_TRUE(builder_.Build(&err));
+  EXPECT_EQ("", err);
+  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
+  EXPECT_EQ("echo 'out2: in1 in2' > in.d && for file in out1 out2; do cp in1 $file; done", command_runner_.commands_ran_[0]);
+
+  Node* out1_node = state_.LookupNode("out1");
+  DepsLog::Deps* out1_deps = log_.GetDeps(out1_node);
+  EXPECT_EQ(2, out1_deps->node_count);
+  EXPECT_EQ("in1", out1_deps->nodes[0]->path());
+  EXPECT_EQ("in2", out1_deps->nodes[1]->path());
+
+  Node* out2_node = state_.LookupNode("out2");
+  DepsLog::Deps* out2_deps = log_.GetDeps(out2_node);
+  EXPECT_EQ(2, out2_deps->node_count);
+  EXPECT_EQ("in1", out2_deps->nodes[0]->path());
+  EXPECT_EQ("in2", out2_deps->nodes[1]->path());
+}
+
 /// Tests of builds involving deps logs necessarily must span
 /// multiple builds.  We reuse methods on BuildTest but not the
 /// builder_ it sets up, because we want pristine objects for
diff --git a/src/canon_perftest.cc b/src/canon_perftest.cc
index 03f4a2f..088bd45 100644
--- a/src/canon_perftest.cc
+++ b/src/canon_perftest.cc
@@ -18,6 +18,8 @@
 #include "util.h"
 #include "metrics.h"
 
+using namespace std;
+
 const char kPath[] =
     "../../third_party/WebKit/Source/WebCore/"
     "platform/leveldb/LevelDBWriteBatch.cpp";
diff --git a/src/clean.cc b/src/clean.cc
index d1f221d..3e57437 100644
--- a/src/clean.cc
+++ b/src/clean.cc
@@ -22,14 +22,14 @@
 #include "state.h"
 #include "util.h"
 
+using namespace std;
+
 Cleaner::Cleaner(State* state,
                  const BuildConfig& config,
                  DiskInterface* disk_interface)
   : state_(state),
     config_(config),
     dyndep_loader_(state, disk_interface),
-    removed_(),
-    cleaned_(),
     cleaned_files_count_(0),
     disk_interface_(disk_interface),
     status_(0) {
@@ -124,6 +124,19 @@
   return status_;
 }
 
+int Cleaner::CleanDead(const BuildLog::Entries& entries) {
+  Reset();
+  PrintHeader();
+  for (BuildLog::Entries::const_iterator i = entries.begin(); i != entries.end(); ++i) {
+    Node* n = state_->LookupNode(i->first);
+    if (!n || !n->in_edge()) {
+      Remove(i->first.AsString());
+    }
+  }
+  PrintFooter();
+  return status_;
+}
+
 void Cleaner::DoCleanTarget(Node* target) {
   if (Edge* e = target->in_edge()) {
     // Do not try to remove phony targets
diff --git a/src/clean.h b/src/clean.h
index d044fb1..cf3f1c3 100644
--- a/src/clean.h
+++ b/src/clean.h
@@ -20,8 +20,7 @@
 
 #include "build.h"
 #include "dyndep.h"
-
-using namespace std;
+#include "build_log.h"
 
 struct State;
 struct Node;
@@ -58,6 +57,10 @@
   /// Clean the file produced by the given @a rules.
   /// @return non-zero if an error occurs.
   int CleanRules(int rule_count, char* rules[]);
+  /// Clean the files produced by previous builds that are no longer in the
+  /// manifest.
+  /// @return non-zero if an error occurs.
+  int CleanDead(const BuildLog::Entries& entries);
 
   /// @return the number of file cleaned.
   int cleaned_files_count() const {
@@ -73,15 +76,15 @@
  private:
   /// Remove the file @a path.
   /// @return whether the file has been removed.
-  int RemoveFile(const string& path);
+  int RemoveFile(const std::string& path);
   /// @returns whether the file @a path exists.
-  bool FileExists(const string& path);
-  void Report(const string& path);
+  bool FileExists(const std::string& path);
+  void Report(const std::string& path);
 
   /// Remove the given @a path file only if it has not been already removed.
-  void Remove(const string& path);
+  void Remove(const std::string& path);
   /// @return whether the given @a path has already been removed.
-  bool IsAlreadyRemoved(const string& path);
+  bool IsAlreadyRemoved(const std::string& path);
   /// Remove the depfile and rspfile for an Edge.
   void RemoveEdgeFiles(Edge* edge);
 
@@ -98,8 +101,8 @@
   State* state_;
   const BuildConfig& config_;
   DyndepLoader dyndep_loader_;
-  set<string> removed_;
-  set<Node*> cleaned_;
+  std::set<std::string> removed_;
+  std::set<Node*> cleaned_;
   int cleaned_files_count_;
   DiskInterface* disk_interface_;
   int status_;
diff --git a/src/clean_test.cc b/src/clean_test.cc
index 45187f4..1b843a2 100644
--- a/src/clean_test.cc
+++ b/src/clean_test.cc
@@ -15,8 +15,19 @@
 #include "clean.h"
 #include "build.h"
 
+#include "util.h"
 #include "test.h"
 
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+using namespace std;
+
+namespace {
+
+const char kTestFilename[] = "CleanTest-tempfile";
+
 struct CleanTest : public StateTestWithBuiltinRules {
   VirtualFileSystem fs_;
   BuildConfig config_;
@@ -454,3 +465,76 @@
   EXPECT_EQ(0, fs_.Stat("out 1.d", &err));
   EXPECT_EQ(0, fs_.Stat("out 2.rsp", &err));
 }
+
+struct CleanDeadTest : public CleanTest, public BuildLogUser{
+  virtual void SetUp() {
+    // In case a crashing test left a stale file behind.
+    unlink(kTestFilename);
+    CleanTest::SetUp();
+  }
+  virtual void TearDown() {
+    unlink(kTestFilename);
+  }
+  virtual bool IsPathDead(StringPiece) const { return false; }
+};
+
+TEST_F(CleanDeadTest, CleanDead) {
+  State state;
+  ASSERT_NO_FATAL_FAILURE(AssertParse(&state,
+"rule cat\n"
+"  command = cat $in > $out\n"
+"build out1: cat in\n"
+"build out2: cat in\n"
+));
+  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"build out2: cat in\n"
+));
+  fs_.Create("in", "");
+  fs_.Create("out1", "");
+  fs_.Create("out2", "");
+
+  BuildLog log1;
+  string err;
+  EXPECT_TRUE(log1.OpenForWrite(kTestFilename, *this, &err));
+  ASSERT_EQ("", err);
+  log1.RecordCommand(state.edges_[0], 15, 18);
+  log1.RecordCommand(state.edges_[1], 20, 25);
+  log1.Close();
+
+  BuildLog log2;
+  EXPECT_TRUE(log2.Load(kTestFilename, &err));
+  ASSERT_EQ("", err);
+  ASSERT_EQ(2u, log2.entries().size());
+  ASSERT_TRUE(log2.LookupByOutput("out1"));
+  ASSERT_TRUE(log2.LookupByOutput("out2"));
+
+  // First use the manifest that describe how to build out1.
+  Cleaner cleaner1(&state, config_, &fs_);
+  EXPECT_EQ(0, cleaner1.CleanDead(log2.entries()));
+  EXPECT_EQ(0, cleaner1.cleaned_files_count());
+  EXPECT_EQ(0u, fs_.files_removed_.size());
+  EXPECT_NE(0, fs_.Stat("in", &err));
+  EXPECT_NE(0, fs_.Stat("out1", &err));
+  EXPECT_NE(0, fs_.Stat("out2", &err));
+
+  // Then use the manifest that does not build out1 anymore.
+  Cleaner cleaner2(&state_, config_, &fs_);
+  EXPECT_EQ(0, cleaner2.CleanDead(log2.entries()));
+  EXPECT_EQ(1, cleaner2.cleaned_files_count());
+  EXPECT_EQ(1u, fs_.files_removed_.size());
+  EXPECT_EQ("out1", *(fs_.files_removed_.begin()));
+  EXPECT_NE(0, fs_.Stat("in", &err));
+  EXPECT_EQ(0, fs_.Stat("out1", &err));
+  EXPECT_NE(0, fs_.Stat("out2", &err));
+
+  // Nothing to do now.
+  EXPECT_EQ(0, cleaner2.CleanDead(log2.entries()));
+  EXPECT_EQ(0, cleaner2.cleaned_files_count());
+  EXPECT_EQ(1u, fs_.files_removed_.size());
+  EXPECT_EQ("out1", *(fs_.files_removed_.begin()));
+  EXPECT_NE(0, fs_.Stat("in", &err));
+  EXPECT_EQ(0, fs_.Stat("out1", &err));
+  EXPECT_NE(0, fs_.Stat("out2", &err));
+  log2.Close();
+}
+}  // anonymous namespace
diff --git a/src/clparser.cc b/src/clparser.cc
index 7994c06..275641e 100644
--- a/src/clparser.cc
+++ b/src/clparser.cc
@@ -28,6 +28,8 @@
 #include "util.h"
 #endif
 
+using namespace std;
+
 namespace {
 
 /// Return true if \a input ends with \a needle.
diff --git a/src/clparser.h b/src/clparser.h
index e597e7e..2a33628 100644
--- a/src/clparser.h
+++ b/src/clparser.h
@@ -17,7 +17,6 @@
 
 #include <set>
 #include <string>
-using namespace std;
 
 /// Visual Studio's cl.exe requires some massaging to work with Ninja;
 /// for example, it emits include information on stderr in a funny
@@ -27,26 +26,26 @@
   /// Parse a line of cl.exe output and extract /showIncludes info.
   /// If a dependency is extracted, returns a nonempty string.
   /// Exposed for testing.
-  static string FilterShowIncludes(const string& line,
-                                   const string& deps_prefix);
+  static std::string FilterShowIncludes(const std::string& line,
+                                        const std::string& deps_prefix);
 
   /// Return true if a mentioned include file is a system path.
   /// Filtering these out reduces dependency information considerably.
-  static bool IsSystemInclude(string path);
+  static bool IsSystemInclude(std::string path);
 
   /// Parse a line of cl.exe output and return true if it looks like
   /// it's printing an input filename.  This is a heuristic but it appears
   /// to be the best we can do.
   /// Exposed for testing.
-  static bool FilterInputFilename(string line);
+  static bool FilterInputFilename(std::string line);
 
   /// Parse the full output of cl, filling filtered_output with the text that
   /// should be printed (if any). Returns true on success, or false with err
   /// filled. output must not be the same object as filtered_object.
-  bool Parse(const string& output, const string& deps_prefix,
-             string* filtered_output, string* err);
+  bool Parse(const std::string& output, const std::string& deps_prefix,
+             std::string* filtered_output, std::string* err);
 
-  set<string> includes_;
+  std::set<std::string> includes_;
 };
 
 #endif  // NINJA_CLPARSER_H_
diff --git a/src/clparser_perftest.cc b/src/clparser_perftest.cc
index 7ac5230..008ac46 100644
--- a/src/clparser_perftest.cc
+++ b/src/clparser_perftest.cc
@@ -18,6 +18,8 @@
 #include "clparser.h"
 #include "metrics.h"
 
+using namespace std;
+
 int main(int argc, char* argv[]) {
   // Output of /showIncludes from #include <iostream>
   string perf_testdata =
diff --git a/src/clparser_test.cc b/src/clparser_test.cc
index 1549ab1..0b829c1 100644
--- a/src/clparser_test.cc
+++ b/src/clparser_test.cc
@@ -17,6 +17,8 @@
 #include "test.h"
 #include "util.h"
 
+using namespace std;
+
 TEST(CLParserTest, ShowIncludes) {
   ASSERT_EQ("", CLParser::FilterShowIncludes("", ""));
 
diff --git a/src/depfile_parser.cc b/src/depfile_parser.cc
index 6faeac6..bffeb76 100644
--- a/src/depfile_parser.cc
+++ b/src/depfile_parser.cc
@@ -1,4 +1,4 @@
-/* Generated by re2c 1.1.1 */
+/* Generated by re2c 1.3 */
 // Copyright 2011 Google Inc. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,10 @@
 #include "depfile_parser.h"
 #include "util.h"
 
+#include <algorithm>
+
+using namespace std;
+
 DepfileParser::DepfileParser(DepfileParserOptions options)
   : options_(options)
 {
@@ -48,10 +52,8 @@
   char* in = &(*content)[0];
   char* end = in + content->size();
   bool have_target = false;
-  bool have_secondary_target_on_this_rule = false;
-  bool have_newline_since_primary_target = false;
-  bool warned_distinct_target_lines = false;
   bool parsing_targets = true;
+  bool poisoned_input = false;
   while (in < end) {
     bool have_newline = false;
     // out: current output point (typically same as in, but can fall behind
@@ -166,22 +168,23 @@
       goto yy5;
 yy13:
       yych = *(yymarker = ++in);
-      if (yych <= 0x1F) {
+      if (yych <= ' ') {
         if (yych <= '\n') {
           if (yych <= 0x00) goto yy5;
           if (yych <= '\t') goto yy16;
           goto yy17;
         } else {
           if (yych == '\r') goto yy19;
-          goto yy16;
+          if (yych <= 0x1F) goto yy16;
+          goto yy21;
         }
       } else {
-        if (yych <= '#') {
-          if (yych <= ' ') goto yy21;
-          if (yych <= '"') goto yy16;
-          goto yy23;
+        if (yych <= '9') {
+          if (yych == '#') goto yy23;
+          goto yy16;
         } else {
-          if (yych == '\\') goto yy25;
+          if (yych <= ':') goto yy25;
+          if (yych == '\\') goto yy27;
           goto yy16;
         }
       }
@@ -231,26 +234,63 @@
       }
 yy25:
       yych = *++in;
-      if (yych <= 0x1F) {
+      if (yych <= '\f') {
+        if (yych <= 0x00) goto yy28;
+        if (yych <= 0x08) goto yy26;
+        if (yych <= '\n') goto yy28;
+      } else {
+        if (yych <= '\r') goto yy28;
+        if (yych == ' ') goto yy28;
+      }
+yy26:
+      {
+        // De-escape colon sign, but preserve other leading backslashes.
+        // Regular expression uses lookahead to make sure that no whitespace
+        // nor EOF follows. In that case it'd be the : at the end of a target
+        int len = (int)(in - start);
+        if (len > 2 && out < start)
+          memset(out, '\\', len - 2);
+        out += len - 2;
+        *out++ = ':';
+        continue;
+      }
+yy27:
+      yych = *++in;
+      if (yych <= ' ') {
         if (yych <= '\n') {
           if (yych <= 0x00) goto yy11;
           if (yych <= '\t') goto yy16;
           goto yy11;
         } else {
           if (yych == '\r') goto yy11;
-          goto yy16;
+          if (yych <= 0x1F) goto yy16;
+          goto yy30;
         }
       } else {
-        if (yych <= '#') {
-          if (yych <= ' ') goto yy26;
-          if (yych <= '"') goto yy16;
-          goto yy23;
+        if (yych <= '9') {
+          if (yych == '#') goto yy23;
+          goto yy16;
         } else {
-          if (yych == '\\') goto yy28;
+          if (yych <= ':') goto yy25;
+          if (yych == '\\') goto yy32;
           goto yy16;
         }
       }
-yy26:
+yy28:
+      ++in;
+      {
+        // Backslash followed by : and whitespace.
+        // It is therefore normal text and not an escaped colon
+        int len = (int)(in - start - 1);
+        // Need to shift it over if we're overwriting backslashes.
+        if (out < start)
+          memmove(out, start, len);
+        out += len;
+        if (*(in - 1) == '\n')
+          have_newline = true;
+        break;
+      }
+yy30:
       ++in;
       {
         // 2N backslashes plus space -> 2N backslashes, end of filename.
@@ -260,24 +300,25 @@
         out += len - 1;
         break;
       }
-yy28:
+yy32:
       yych = *++in;
-      if (yych <= 0x1F) {
+      if (yych <= ' ') {
         if (yych <= '\n') {
           if (yych <= 0x00) goto yy11;
           if (yych <= '\t') goto yy16;
           goto yy11;
         } else {
           if (yych == '\r') goto yy11;
-          goto yy16;
+          if (yych <= 0x1F) goto yy16;
+          goto yy21;
         }
       } else {
-        if (yych <= '#') {
-          if (yych <= ' ') goto yy21;
-          if (yych <= '"') goto yy16;
-          goto yy23;
+        if (yych <= '9') {
+          if (yych == '#') goto yy23;
+          goto yy16;
         } else {
-          if (yych == '\\') goto yy25;
+          if (yych <= ':') goto yy25;
+          if (yych == '\\') goto yy27;
           goto yy16;
         }
       }
@@ -294,41 +335,32 @@
     }
 
     if (len > 0) {
-      if (is_dependency) {
-        if (have_secondary_target_on_this_rule) {
-          if (!have_newline_since_primary_target) {
-            *err = "depfile has multiple output paths";
+      StringPiece piece = StringPiece(filename, len);
+      // If we've seen this as an input before, skip it.
+      std::vector<StringPiece>::iterator pos = std::find(ins_.begin(), ins_.end(), piece);
+      if (pos == ins_.end()) {
+        if (is_dependency) {
+          if (poisoned_input) {
+            *err = "inputs may not also have inputs";
             return false;
-          } else if (options_.depfile_distinct_target_lines_action_ ==
-                     kDepfileDistinctTargetLinesActionError) {
-            *err =
-                "depfile has multiple output paths (on separate lines)"
-                " [-w depfilemulti=err]";
-            return false;
-          } else {
-            if (!warned_distinct_target_lines) {
-              warned_distinct_target_lines = true;
-              Warning("depfile has multiple output paths (on separate lines); "
-                      "continuing anyway [-w depfilemulti=warn]");
-            }
-            continue;
           }
+          // New input.
+          ins_.push_back(piece);
+        } else {
+          // Check for a new output.
+          if (std::find(outs_.begin(), outs_.end(), piece) == outs_.end())
+            outs_.push_back(piece);
         }
-        ins_.push_back(StringPiece(filename, len));
-      } else if (!out_.str_) {
-        out_ = StringPiece(filename, len);
-      } else if (out_ != StringPiece(filename, len)) {
-        have_secondary_target_on_this_rule = true;
+      } else if (!is_dependency) {
+        // We've passed an input on the left side; reject new inputs.
+        poisoned_input = true;
       }
     }
 
     if (have_newline) {
       // A newline ends a rule so the next filename will be a new target.
       parsing_targets = true;
-      have_secondary_target_on_this_rule = false;
-      if (have_target) {
-        have_newline_since_primary_target = true;
-      }
+      poisoned_input = false;
     }
   }
   if (!have_target) {
diff --git a/src/depfile_parser.h b/src/depfile_parser.h
index be20374..0e8db81 100644
--- a/src/depfile_parser.h
+++ b/src/depfile_parser.h
@@ -17,21 +17,11 @@
 
 #include <string>
 #include <vector>
-using namespace std;
 
 #include "string_piece.h"
 
-enum DepfileDistinctTargetLinesAction {
-  kDepfileDistinctTargetLinesActionWarn,
-  kDepfileDistinctTargetLinesActionError,
-};
-
 struct DepfileParserOptions {
-  DepfileParserOptions()
-      : depfile_distinct_target_lines_action_(
-          kDepfileDistinctTargetLinesActionWarn) {}
-  DepfileDistinctTargetLinesAction
-    depfile_distinct_target_lines_action_;
+  DepfileParserOptions() {}
 };
 
 /// Parser for the dependency information emitted by gcc's -M flags.
@@ -42,10 +32,10 @@
   /// Parse an input file.  Input must be NUL-terminated.
   /// Warning: may mutate the content in-place and parsed StringPieces are
   /// pointers within it.
-  bool Parse(string* content, string* err);
+  bool Parse(std::string* content, std::string* err);
 
-  StringPiece out_;
-  vector<StringPiece> ins_;
+  std::vector<StringPiece> outs_;
+  std::vector<StringPiece> ins_;
   DepfileParserOptions options_;
 };
 
diff --git a/src/depfile_parser.in.cc b/src/depfile_parser.in.cc
index 735a0c3..75ba982 100644
--- a/src/depfile_parser.in.cc
+++ b/src/depfile_parser.in.cc
@@ -15,6 +15,10 @@
 #include "depfile_parser.h"
 #include "util.h"
 
+#include <algorithm>
+
+using namespace std;
+
 DepfileParser::DepfileParser(DepfileParserOptions options)
   : options_(options)
 {
@@ -47,10 +51,8 @@
   char* in = &(*content)[0];
   char* end = in + content->size();
   bool have_target = false;
-  bool have_secondary_target_on_this_rule = false;
-  bool have_newline_since_primary_target = false;
-  bool warned_distinct_target_lines = false;
   bool parsing_targets = true;
+  bool poisoned_input = false;
   while (in < end) {
     bool have_newline = false;
     // out: current output point (typically same as in, but can fall behind
@@ -103,6 +105,29 @@
         *out++ = '#';
         continue;
       }
+      '\\'+ ':' [\x00\x20\r\n\t] {
+        // Backslash followed by : and whitespace.
+        // It is therefore normal text and not an escaped colon
+        int len = (int)(in - start - 1);
+        // Need to shift it over if we're overwriting backslashes.
+        if (out < start)
+          memmove(out, start, len);
+        out += len;
+        if (*(in - 1) == '\n')
+          have_newline = true;
+        break;
+      }
+      '\\'+ ':' {
+        // De-escape colon sign, but preserve other leading backslashes.
+        // Regular expression uses lookahead to make sure that no whitespace
+        // nor EOF follows. In that case it'd be the : at the end of a target
+        int len = (int)(in - start);
+        if (len > 2 && out < start)
+          memset(out, '\\', len - 2);
+        out += len - 2;
+        *out++ = ':';
+        continue;
+      }
       '$$' {
         // De-escape dollar character.
         *out++ = '$';
@@ -146,41 +171,32 @@
     }
 
     if (len > 0) {
-      if (is_dependency) {
-        if (have_secondary_target_on_this_rule) {
-          if (!have_newline_since_primary_target) {
-            *err = "depfile has multiple output paths";
+      StringPiece piece = StringPiece(filename, len);
+      // If we've seen this as an input before, skip it.
+      std::vector<StringPiece>::iterator pos = std::find(ins_.begin(), ins_.end(), piece);
+      if (pos == ins_.end()) {
+        if (is_dependency) {
+          if (poisoned_input) {
+            *err = "inputs may not also have inputs";
             return false;
-          } else if (options_.depfile_distinct_target_lines_action_ ==
-                     kDepfileDistinctTargetLinesActionError) {
-            *err =
-                "depfile has multiple output paths (on separate lines)"
-                " [-w depfilemulti=err]";
-            return false;
-          } else {
-            if (!warned_distinct_target_lines) {
-              warned_distinct_target_lines = true;
-              Warning("depfile has multiple output paths (on separate lines); "
-                      "continuing anyway [-w depfilemulti=warn]");
-            }
-            continue;
           }
+          // New input.
+          ins_.push_back(piece);
+        } else {
+          // Check for a new output.
+          if (std::find(outs_.begin(), outs_.end(), piece) == outs_.end())
+            outs_.push_back(piece);
         }
-        ins_.push_back(StringPiece(filename, len));
-      } else if (!out_.str_) {
-        out_ = StringPiece(filename, len);
-      } else if (out_ != StringPiece(filename, len)) {
-        have_secondary_target_on_this_rule = true;
+      } else if (!is_dependency) {
+        // We've passed an input on the left side; reject new inputs.
+        poisoned_input = true;
       }
     }
 
     if (have_newline) {
       // A newline ends a rule so the next filename will be a new target.
       parsing_targets = true;
-      have_secondary_target_on_this_rule = false;
-      if (have_target) {
-        have_newline_since_primary_target = true;
-      }
+      poisoned_input = false;
     }
   }
   if (!have_target) {
diff --git a/src/depfile_parser_perftest.cc b/src/depfile_parser_perftest.cc
index b215221..52555e6 100644
--- a/src/depfile_parser_perftest.cc
+++ b/src/depfile_parser_perftest.cc
@@ -19,6 +19,8 @@
 #include "util.h"
 #include "metrics.h"
 
+using namespace std;
+
 int main(int argc, char* argv[]) {
   if (argc < 2) {
     printf("usage: %s <file1> <file2...>\n", argv[0]);
diff --git a/src/depfile_parser_test.cc b/src/depfile_parser_test.cc
index 19224f3..8886258 100644
--- a/src/depfile_parser_test.cc
+++ b/src/depfile_parser_test.cc
@@ -16,6 +16,8 @@
 
 #include "test.h"
 
+using namespace std;
+
 struct DepfileParserTest : public testing::Test {
   bool Parse(const char* input, string* err);
 
@@ -34,7 +36,8 @@
 "build/ninja.o: ninja.cc ninja.h eval_env.h manifest_parser.h\n",
       &err));
   ASSERT_EQ("", err);
-  EXPECT_EQ("build/ninja.o", parser_.out_.AsString());
+  ASSERT_EQ(1u, parser_.outs_.size());
+  EXPECT_EQ("build/ninja.o", parser_.outs_[0].AsString());
   EXPECT_EQ(4u, parser_.ins_.size());
 }
 
@@ -54,7 +57,8 @@
 "  bar.h baz.h\n",
       &err));
   ASSERT_EQ("", err);
-  EXPECT_EQ("foo.o", parser_.out_.AsString());
+  ASSERT_EQ(1u, parser_.outs_.size());
+  EXPECT_EQ("foo.o", parser_.outs_[0].AsString());
   EXPECT_EQ(2u, parser_.ins_.size());
 }
 
@@ -65,7 +69,8 @@
 "  bar.h baz.h\r\n",
       &err));
   ASSERT_EQ("", err);
-  EXPECT_EQ("foo.o", parser_.out_.AsString());
+  ASSERT_EQ(1u, parser_.outs_.size());
+  EXPECT_EQ("foo.o", parser_.outs_[0].AsString());
   EXPECT_EQ(2u, parser_.ins_.size());
 }
 
@@ -79,8 +84,9 @@
 "  Project\\Thing\\Bar.tlb \\\n",
       &err));
   ASSERT_EQ("", err);
+  ASSERT_EQ(1u, parser_.outs_.size());
   EXPECT_EQ("Project\\Dir\\Build\\Release8\\Foo\\Foo.res",
-            parser_.out_.AsString());
+            parser_.outs_[0].AsString());
   EXPECT_EQ(4u, parser_.ins_.size());
 }
 
@@ -90,8 +96,9 @@
 "a\\ bc\\ def:   a\\ b c d",
       &err));
   ASSERT_EQ("", err);
+  ASSERT_EQ(1u, parser_.outs_.size());
   EXPECT_EQ("a bc def",
-            parser_.out_.AsString());
+            parser_.outs_[0].AsString());
   ASSERT_EQ(3u, parser_.ins_.size());
   EXPECT_EQ("a b",
             parser_.ins_[0].AsString());
@@ -111,8 +118,9 @@
 "a\\ b\\#c.h: \\\\\\\\\\  \\\\\\\\ \\\\share\\info\\\\#1",
       &err));
   ASSERT_EQ("", err);
+  ASSERT_EQ(1u, parser_.outs_.size());
   EXPECT_EQ("a b#c.h",
-            parser_.out_.AsString());
+            parser_.outs_[0].AsString());
   ASSERT_EQ(3u, parser_.ins_.size());
   EXPECT_EQ("\\\\ ",
             parser_.ins_[0].AsString());
@@ -130,11 +138,47 @@
 "\\!\\@\\#$$\\%\\^\\&\\[\\]\\\\:",
       &err));
   ASSERT_EQ("", err);
+  ASSERT_EQ(1u, parser_.outs_.size());
   EXPECT_EQ("\\!\\@#$\\%\\^\\&\\[\\]\\\\",
-            parser_.out_.AsString());
+            parser_.outs_[0].AsString());
   ASSERT_EQ(0u, parser_.ins_.size());
 }
 
+TEST_F(DepfileParserTest, EscapedColons)
+{
+  std::string err;
+  // Tests for correct parsing of depfiles produced on Windows
+  // by both Clang, GCC pre 10 and GCC 10
+  EXPECT_TRUE(Parse(
+"c\\:\\gcc\\x86_64-w64-mingw32\\include\\stddef.o: \\\n"
+" c:\\gcc\\x86_64-w64-mingw32\\include\\stddef.h \n",
+      &err));
+  ASSERT_EQ("", err);
+  ASSERT_EQ(1u, parser_.outs_.size());
+  EXPECT_EQ("c:\\gcc\\x86_64-w64-mingw32\\include\\stddef.o",
+            parser_.outs_[0].AsString());
+  ASSERT_EQ(1u, parser_.ins_.size());
+  EXPECT_EQ("c:\\gcc\\x86_64-w64-mingw32\\include\\stddef.h",
+            parser_.ins_[0].AsString());
+}
+
+TEST_F(DepfileParserTest, EscapedTargetColon)
+{
+  std::string err;
+  EXPECT_TRUE(Parse(
+"foo1\\: x\n"
+"foo1\\:\n"
+"foo1\\:\r\n"
+"foo1\\:\t\n"
+"foo1\\:",
+      &err));
+  ASSERT_EQ("", err);
+  ASSERT_EQ(1u, parser_.outs_.size());
+  EXPECT_EQ("foo1\\", parser_.outs_[0].AsString());
+  ASSERT_EQ(1u, parser_.ins_.size());
+  EXPECT_EQ("x", parser_.ins_[0].AsString());
+}
+
 TEST_F(DepfileParserTest, SpecialChars) {
   // See filenames like istreambuf.iterator_op!= in
   // https://github.com/google/libcxx/tree/master/test/iterators/stream.iterators/istreambuf.iterator/
@@ -147,8 +191,9 @@
 " a[1]b@2%c",
       &err));
   ASSERT_EQ("", err);
+  ASSERT_EQ(1u, parser_.outs_.size());
   EXPECT_EQ("C:/Program Files (x86)/Microsoft crtdefs.h",
-            parser_.out_.AsString());
+            parser_.outs_[0].AsString());
   ASSERT_EQ(5u, parser_.ins_.size());
   EXPECT_EQ("en@quot.header~",
             parser_.ins_[0].AsString());
@@ -166,18 +211,25 @@
   // check that multiple duplicate targets are properly unified
   string err;
   EXPECT_TRUE(Parse("foo foo: x y z", &err));
-  ASSERT_EQ("foo", parser_.out_.AsString());
+  ASSERT_EQ(1u, parser_.outs_.size());
+  ASSERT_EQ("foo", parser_.outs_[0].AsString());
   ASSERT_EQ(3u, parser_.ins_.size());
   EXPECT_EQ("x", parser_.ins_[0].AsString());
   EXPECT_EQ("y", parser_.ins_[1].AsString());
   EXPECT_EQ("z", parser_.ins_[2].AsString());
 }
 
-TEST_F(DepfileParserTest, RejectMultipleDifferentOutputs) {
-  // check that multiple different outputs are rejected by the parser
+TEST_F(DepfileParserTest, MultipleDifferentOutputs) {
+  // check that multiple different outputs are accepted by the parser
   string err;
-  EXPECT_FALSE(Parse("foo bar: x y z", &err));
-  ASSERT_EQ("depfile has multiple output paths", err);
+  EXPECT_TRUE(Parse("foo bar: x y z", &err));
+  ASSERT_EQ(2u, parser_.outs_.size());
+  ASSERT_EQ("foo", parser_.outs_[0].AsString());
+  ASSERT_EQ("bar", parser_.outs_[1].AsString());
+  ASSERT_EQ(3u, parser_.ins_.size());
+  EXPECT_EQ("x", parser_.ins_[0].AsString());
+  EXPECT_EQ("y", parser_.ins_[1].AsString());
+  EXPECT_EQ("z", parser_.ins_[2].AsString());
 }
 
 TEST_F(DepfileParserTest, MultipleEmptyRules) {
@@ -185,7 +237,8 @@
   EXPECT_TRUE(Parse("foo: x\n"
                     "foo: \n"
                     "foo:\n", &err));
-  ASSERT_EQ("foo", parser_.out_.AsString());
+  ASSERT_EQ(1u, parser_.outs_.size());
+  ASSERT_EQ("foo", parser_.outs_[0].AsString());
   ASSERT_EQ(1u, parser_.ins_.size());
   EXPECT_EQ("x", parser_.ins_[0].AsString());
 }
@@ -196,7 +249,8 @@
                     "foo: y\n"
                     "foo \\\n"
                     "foo: z\n", &err));
-  ASSERT_EQ("foo", parser_.out_.AsString());
+  ASSERT_EQ(1u, parser_.outs_.size());
+  ASSERT_EQ("foo", parser_.outs_[0].AsString());
   ASSERT_EQ(3u, parser_.ins_.size());
   EXPECT_EQ("x", parser_.ins_[0].AsString());
   EXPECT_EQ("y", parser_.ins_[1].AsString());
@@ -209,7 +263,8 @@
                     "foo: y\r\n"
                     "foo \\\r\n"
                     "foo: z\r\n", &err));
-  ASSERT_EQ("foo", parser_.out_.AsString());
+  ASSERT_EQ(1u, parser_.outs_.size());
+  ASSERT_EQ("foo", parser_.outs_[0].AsString());
   ASSERT_EQ(3u, parser_.ins_.size());
   EXPECT_EQ("x", parser_.ins_[0].AsString());
   EXPECT_EQ("y", parser_.ins_[1].AsString());
@@ -222,7 +277,8 @@
                     "     y\n"
                     "foo \\\n"
                     "foo: z\n", &err));
-  ASSERT_EQ("foo", parser_.out_.AsString());
+  ASSERT_EQ(1u, parser_.outs_.size());
+  ASSERT_EQ("foo", parser_.outs_[0].AsString());
   ASSERT_EQ(3u, parser_.ins_.size());
   EXPECT_EQ("x", parser_.ins_[0].AsString());
   EXPECT_EQ("y", parser_.ins_[1].AsString());
@@ -235,7 +291,8 @@
                     "     y\r\n"
                     "foo \\\r\n"
                     "foo: z\r\n", &err));
-  ASSERT_EQ("foo", parser_.out_.AsString());
+  ASSERT_EQ(1u, parser_.outs_.size());
+  ASSERT_EQ("foo", parser_.outs_[0].AsString());
   ASSERT_EQ(3u, parser_.ins_.size());
   EXPECT_EQ("x", parser_.ins_[0].AsString());
   EXPECT_EQ("y", parser_.ins_[1].AsString());
@@ -247,7 +304,8 @@
   EXPECT_TRUE(Parse(" foo: x\n"
                     " foo: y\n"
                     " foo: z\n", &err));
-  ASSERT_EQ("foo", parser_.out_.AsString());
+  ASSERT_EQ(1u, parser_.outs_.size());
+  ASSERT_EQ("foo", parser_.outs_[0].AsString());
   ASSERT_EQ(3u, parser_.ins_.size());
   EXPECT_EQ("x", parser_.ins_[0].AsString());
   EXPECT_EQ("y", parser_.ins_[1].AsString());
@@ -259,7 +317,8 @@
   EXPECT_TRUE(Parse(" foo: x\r\n"
                     " foo: y\r\n"
                     " foo: z\r\n", &err));
-  ASSERT_EQ("foo", parser_.out_.AsString());
+  ASSERT_EQ(1u, parser_.outs_.size());
+  ASSERT_EQ("foo", parser_.outs_[0].AsString());
   ASSERT_EQ(3u, parser_.ins_.size());
   EXPECT_EQ("x", parser_.ins_[0].AsString());
   EXPECT_EQ("y", parser_.ins_[1].AsString());
@@ -272,7 +331,8 @@
                     "x:\n"
                     "y:\n"
                     "z:\n", &err));
-  ASSERT_EQ("foo", parser_.out_.AsString());
+  ASSERT_EQ(1u, parser_.outs_.size());
+  ASSERT_EQ("foo", parser_.outs_[0].AsString());
   ASSERT_EQ(3u, parser_.ins_.size());
   EXPECT_EQ("x", parser_.ins_[0].AsString());
   EXPECT_EQ("y", parser_.ins_[1].AsString());
@@ -287,25 +347,34 @@
                     "y:\n"
                     "foo: z\n"
                     "z:\n", &err));
-  ASSERT_EQ("foo", parser_.out_.AsString());
+  ASSERT_EQ(1u, parser_.outs_.size());
+  ASSERT_EQ("foo", parser_.outs_[0].AsString());
   ASSERT_EQ(3u, parser_.ins_.size());
   EXPECT_EQ("x", parser_.ins_[0].AsString());
   EXPECT_EQ("y", parser_.ins_[1].AsString());
   EXPECT_EQ("z", parser_.ins_[2].AsString());
 }
 
-TEST_F(DepfileParserTest, MultipleRulesRejectDifferentOutputs) {
-  // check that multiple different outputs are rejected by the parser
+TEST_F(DepfileParserTest, MultipleRulesDifferentOutputs) {
+  // check that multiple different outputs are accepted by the parser
   // when spread across multiple rules
-  DepfileParserOptions parser_opts;
-  parser_opts.depfile_distinct_target_lines_action_ =
-      kDepfileDistinctTargetLinesActionError;
-  DepfileParser parser(parser_opts);
   string err;
-  string input =
-      "foo: x y\n"
-      "bar: y z\n";
-  EXPECT_FALSE(parser.Parse(&input, &err));
-  ASSERT_EQ("depfile has multiple output paths (on separate lines)"
-            " [-w depfilemulti=err]", err);
+  EXPECT_TRUE(Parse("foo: x y\n"
+                    "bar: y z\n", &err));
+  ASSERT_EQ(2u, parser_.outs_.size());
+  ASSERT_EQ("foo", parser_.outs_[0].AsString());
+  ASSERT_EQ("bar", parser_.outs_[1].AsString());
+  ASSERT_EQ(3u, parser_.ins_.size());
+  EXPECT_EQ("x", parser_.ins_[0].AsString());
+  EXPECT_EQ("y", parser_.ins_[1].AsString());
+  EXPECT_EQ("z", parser_.ins_[2].AsString());
+}
+
+TEST_F(DepfileParserTest, BuggyMP) {
+  std::string err;
+  EXPECT_FALSE(Parse("foo: x y z\n"
+                     "x: alsoin\n"
+                     "y:\n"
+                     "z:\n", &err));
+  ASSERT_EQ("inputs may not also have inputs", err);
 }
diff --git a/src/deps_log.cc b/src/deps_log.cc
index 4aaffeb..191f300 100644
--- a/src/deps_log.cc
+++ b/src/deps_log.cc
@@ -30,6 +30,8 @@
 #include "state.h"
 #include "util.h"
 
+using namespace std;
+
 // The version is stored as 4 bytes after the signature and also serves as a
 // byte order mark. Signature and version combined are 16 bytes long.
 const char kFileSignature[] = "# ninjadeps\n";
@@ -49,34 +51,9 @@
       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 +109,10 @@
     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,20 +143,21 @@
 }
 
 void DepsLog::Close() {
+  OpenForWriteIfNeeded();  // create the file even if nothing has been recorded
   if (file_)
     fclose(file_);
   file_ = NULL;
 }
 
-bool DepsLog::Load(const string& path, State* state, string* err) {
+LoadStatus DepsLog::Load(const string& path, State* state, string* err) {
   METRIC_RECORD(".ninja_deps load");
   char buf[kMaxRecordSize + 1];
   FILE* f = fopen(path.c_str(), "rb");
   if (!f) {
     if (errno == ENOENT)
-      return true;
+      return LOAD_NOT_FOUND;
     *err = strerror(errno);
-    return false;
+    return LOAD_ERROR;
   }
 
   bool valid_header = true;
@@ -196,7 +178,7 @@
     unlink(path.c_str());
     // Don't report this as a failure.  An empty deps log will cause
     // us to rebuild the outputs anyway.
-    return true;
+    return LOAD_SUCCESS;
   }
 
   long offset;
@@ -284,12 +266,12 @@
     fclose(f);
 
     if (!Truncate(path, offset, err))
-      return false;
+      return LOAD_ERROR;
 
     // The truncate succeeded; we'll just report the load error as a
     // warning because the build can proceed.
     *err += "; recovering";
-    return true;
+    return LOAD_SUCCESS;
   }
 
   fclose(f);
@@ -302,7 +284,7 @@
     needs_recompaction_ = true;
   }
 
-  return true;
+  return LOAD_SUCCESS;
 }
 
 DepsLog::Deps* DepsLog::GetDeps(Node* node) {
@@ -396,10 +378,14 @@
     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) {
-    assert(node->path().size() > 0);
+    assert(!node->path().empty());
     return false;
   }
   if (padding && fwrite("\0\0", padding, 1, file_) < 1)
@@ -416,3 +402,37 @@
 
   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.
+  if (setvbuf(file_, NULL, _IOFBF, kMaxRecordSize + 1) != 0) {
+    return false;
+  }
+  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 3812a28..cc44b41 100644
--- a/src/deps_log.h
+++ b/src/deps_log.h
@@ -17,10 +17,10 @@
 
 #include <string>
 #include <vector>
-using namespace std;
 
 #include <stdio.h>
 
+#include "load_status.h"
 #include "timestamp.h"
 
 struct Node;
@@ -70,8 +70,8 @@
   ~DepsLog();
 
   // Writing (build-time) interface.
-  bool OpenForWrite(const string& path, string* err);
-  bool RecordDeps(Node* node, TimeStamp mtime, const vector<Node*>& nodes);
+  bool OpenForWrite(const std::string& path, std::string* err);
+  bool RecordDeps(Node* node, TimeStamp mtime, const std::vector<Node*>& nodes);
   bool RecordDeps(Node* node, TimeStamp mtime, int node_count, Node** nodes);
   void Close();
 
@@ -84,11 +84,11 @@
     int node_count;
     Node** nodes;
   };
-  bool Load(const string& path, State* state, string* err);
+  LoadStatus Load(const std::string& path, State* state, std::string* err);
   Deps* GetDeps(Node* node);
 
   /// Rewrite the known log entries, throwing away old data.
-  bool Recompact(const string& path, string* err);
+  bool Recompact(const std::string& path, std::string* err);
 
   /// Returns if the deps entry for a node is still reachable from the manifest.
   ///
@@ -99,8 +99,8 @@
   bool IsDepsEntryLiveFor(Node* node);
 
   /// Used for tests.
-  const vector<Node*>& nodes() const { return nodes_; }
-  const vector<Deps*>& deps() const { return deps_; }
+  const std::vector<Node*>& nodes() const { return nodes_; }
+  const std::vector<Deps*>& deps() const { return deps_; }
 
  private:
   // Updates the in-memory representation.  Takes ownership of |deps|.
@@ -109,13 +109,18 @@
   // 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_;
+  std::vector<Node*> nodes_;
   /// Maps id -> deps of that id.
-  vector<Deps*> deps_;
+  std::vector<Deps*> deps_;
 
   friend struct DepsLogTest;
 };
diff --git a/src/deps_log_test.cc b/src/deps_log_test.cc
index 0cdeb45..4055941 100644
--- a/src/deps_log_test.cc
+++ b/src/deps_log_test.cc
@@ -23,6 +23,8 @@
 #include "util.h"
 #include "test.h"
 
+using namespace std;
+
 namespace {
 
 const char kTestFilename[] = "DepsLogTest-tempfile";
diff --git a/src/disk_interface.cc b/src/disk_interface.cc
index dc297c4..49af001 100644
--- a/src/disk_interface.cc
+++ b/src/disk_interface.cc
@@ -26,11 +26,15 @@
 #include <sstream>
 #include <windows.h>
 #include <direct.h>  // _mkdir
+#else
+#include <unistd.h>
 #endif
 
 #include "metrics.h"
 #include "util.h"
 
+using namespace std;
+
 namespace {
 
 string DirName(const string& path) {
diff --git a/src/disk_interface.h b/src/disk_interface.h
index 145e089..bc29ab7 100644
--- a/src/disk_interface.h
+++ b/src/disk_interface.h
@@ -17,7 +17,6 @@
 
 #include <map>
 #include <string>
-using namespace std;
 
 #include "timestamp.h"
 
@@ -35,8 +34,8 @@
 
   /// Read and store in given string.  On success, return Okay.
   /// On error, return another Status and fill |err|.
-  virtual Status ReadFile(const string& path, string* contents,
-                          string* err) = 0;
+  virtual Status ReadFile(const std::string& path, std::string* contents,
+                          std::string* err) = 0;
 };
 
 /// Interface for accessing the disk.
@@ -46,25 +45,26 @@
 struct DiskInterface: public FileReader {
   /// stat() a file, returning the mtime, or 0 if missing and -1 on
   /// other errors.
-  virtual TimeStamp Stat(const string& path, string* err) const = 0;
+  virtual TimeStamp Stat(const std::string& path, std::string* err) const = 0;
 
   /// Create a directory, returning false on failure.
-  virtual bool MakeDir(const string& path) = 0;
+  virtual bool MakeDir(const std::string& path) = 0;
 
   /// Create a file, with the specified name and contents
   /// Returns true on success, false on failure
-  virtual bool WriteFile(const string& path, const string& contents) = 0;
+  virtual bool WriteFile(const std::string& path,
+                         const std::string& contents) = 0;
 
   /// Remove the file named @a path. It behaves like 'rm -f path' so no errors
   /// are reported if it does not exists.
   /// @returns 0 if the file has been removed,
   ///          1 if the file does not exist, and
   ///          -1 if an error occurs.
-  virtual int RemoveFile(const string& path) = 0;
+  virtual int RemoveFile(const std::string& path) = 0;
 
   /// Create all the parent directories for path; like mkdir -p
   /// `basename path`.
-  bool MakeDirs(const string& path);
+  bool MakeDirs(const std::string& path);
 };
 
 /// Implementation of DiskInterface that actually hits the disk.
@@ -75,11 +75,12 @@
 #endif
                       {}
   virtual ~RealDiskInterface() {}
-  virtual TimeStamp Stat(const string& path, string* err) const;
-  virtual bool MakeDir(const string& path);
-  virtual bool WriteFile(const string& path, const string& contents);
-  virtual Status ReadFile(const string& path, string* contents, string* err);
-  virtual int RemoveFile(const string& path);
+  virtual TimeStamp Stat(const std::string& path, std::string* err) const;
+  virtual bool MakeDir(const std::string& path);
+  virtual bool WriteFile(const std::string& path, const std::string& contents);
+  virtual Status ReadFile(const std::string& path, std::string* contents,
+                          std::string* err);
+  virtual int RemoveFile(const std::string& path);
 
   /// Whether stat information can be cached.  Only has an effect on Windows.
   void AllowStatCache(bool allow);
@@ -89,10 +90,10 @@
   /// Whether stat information can be cached.
   bool use_cache_;
 
-  typedef map<string, TimeStamp> DirCache;
+  typedef std::map<std::string, TimeStamp> DirCache;
   // TODO: Neither a map nor a hashmap seems ideal here.  If the statcache
   // works out, come up with a better data structure.
-  typedef map<string, DirCache> Cache;
+  typedef std::map<std::string, DirCache> Cache;
   mutable Cache cache_;
 #endif
 };
diff --git a/src/disk_interface_test.cc b/src/disk_interface_test.cc
index bac515d..066c770 100644
--- a/src/disk_interface_test.cc
+++ b/src/disk_interface_test.cc
@@ -23,6 +23,8 @@
 #include "graph.h"
 #include "test.h"
 
+using namespace std;
+
 namespace {
 
 struct DiskInterfaceTest : public testing::Test {
@@ -190,7 +192,7 @@
 
 TEST_F(DiskInterfaceTest, MakeDirs) {
   string path = "path/with/double//slash/";
-  EXPECT_TRUE(disk_.MakeDirs(path.c_str()));
+  EXPECT_TRUE(disk_.MakeDirs(path));
   FILE* f = fopen((path + "a_file").c_str(), "w");
   EXPECT_TRUE(f);
   EXPECT_EQ(0, fclose(f));
diff --git a/src/dyndep.cc b/src/dyndep.cc
index 2aee601..b388e9b 100644
--- a/src/dyndep.cc
+++ b/src/dyndep.cc
@@ -24,6 +24,8 @@
 #include "state.h"
 #include "util.h"
 
+using namespace std;
+
 bool DyndepLoader::LoadDyndeps(Node* node, std::string* err) const {
   DyndepFile ddf;
   return LoadDyndeps(node, &ddf, err);
diff --git a/src/dyndep_parser.cc b/src/dyndep_parser.cc
index baebbac..56da16f 100644
--- a/src/dyndep_parser.cc
+++ b/src/dyndep_parser.cc
@@ -22,6 +22,8 @@
 #include "util.h"
 #include "version.h"
 
+using namespace std;
+
 DyndepParser::DyndepParser(State* state, FileReader* file_reader,
                            DyndepFile* dyndep_file)
     : Parser(state, file_reader)
diff --git a/src/dyndep_parser.h b/src/dyndep_parser.h
index 09a3722..8f4c28d 100644
--- a/src/dyndep_parser.h
+++ b/src/dyndep_parser.h
@@ -27,17 +27,18 @@
                DyndepFile* dyndep_file);
 
   /// Parse a text string of input.  Used by tests.
-  bool ParseTest(const string& input, string* err) {
+  bool ParseTest(const std::string& input, std::string* err) {
     return Parse("input", input, err);
   }
 
 private:
   /// Parse a file, given its contents as a string.
-  bool Parse(const string& filename, const string& input, string* err);
+  bool Parse(const std::string& filename, const std::string& input,
+             std:: string* err);
 
-  bool ParseDyndepVersion(string* err);
-  bool ParseLet(string* key, EvalString* val, string* err);
-  bool ParseEdge(string* err);
+  bool ParseDyndepVersion(std::string* err);
+  bool ParseLet(std::string* key, EvalString* val, std::string* err);
+  bool ParseEdge(std::string* err);
 
   DyndepFile* dyndep_file_;
   BindingEnv env_;
diff --git a/src/dyndep_parser_test.cc b/src/dyndep_parser_test.cc
index 39ec657..1bba7ba 100644
--- a/src/dyndep_parser_test.cc
+++ b/src/dyndep_parser_test.cc
@@ -22,6 +22,8 @@
 #include "state.h"
 #include "test.h"
 
+using namespace std;
+
 struct DyndepParserTest : public testing::Test {
   void AssertParse(const char* input) {
     DyndepParser parser(&state_, &fs_, &dyndep_file_);
diff --git a/src/edit_distance.cc b/src/edit_distance.cc
index 3bb62b8..34bf0e5 100644
--- a/src/edit_distance.cc
+++ b/src/edit_distance.cc
@@ -17,6 +17,8 @@
 #include <algorithm>
 #include <vector>
 
+using namespace std;
+
 int EditDistance(const StringPiece& s1,
                  const StringPiece& s2,
                  bool allow_replacements,
diff --git a/src/eval_env.cc b/src/eval_env.cc
index e9b6c43..796a326 100644
--- a/src/eval_env.cc
+++ b/src/eval_env.cc
@@ -16,6 +16,8 @@
 
 #include "eval_env.h"
 
+using namespace std;
+
 string BindingEnv::LookupVariable(const string& var) {
   map<string, string>::iterator i = bindings_.find(var);
   if (i != bindings_.end())
diff --git a/src/eval_env.h b/src/eval_env.h
index 8fb9bf4..ca7daa4 100644
--- a/src/eval_env.h
+++ b/src/eval_env.h
@@ -18,7 +18,6 @@
 #include <map>
 #include <string>
 #include <vector>
-using namespace std;
 
 #include "string_piece.h"
 
@@ -27,7 +26,7 @@
 /// An interface for a scope for variable (e.g. "$foo") lookups.
 struct Env {
   virtual ~Env() {}
-  virtual string LookupVariable(const string& var) = 0;
+  virtual std::string LookupVariable(const std::string& var) = 0;
 };
 
 /// A tokenized string that contains variable references.
@@ -35,10 +34,10 @@
 struct EvalString {
   /// @return The evaluated string with variable expanded using value found in
   ///         environment @a env.
-  string Evaluate(Env* env) const;
+  std::string Evaluate(Env* env) const;
 
   /// @return The string with variables not expanded.
-  string Unparse() const;
+  std::string Unparse() const;
 
   void Clear() { parsed_.clear(); }
   bool empty() const { return parsed_.empty(); }
@@ -48,32 +47,32 @@
 
   /// Construct a human-readable representation of the parsed state,
   /// for use in tests.
-  string Serialize() const;
+  std::string Serialize() const;
 
 private:
   enum TokenType { RAW, SPECIAL };
-  typedef vector<pair<string, TokenType> > TokenList;
+  typedef std::vector<std::pair<std::string, TokenType> > TokenList;
   TokenList parsed_;
 };
 
 /// An invokable build command and associated metadata (description, etc.).
 struct Rule {
-  explicit Rule(const string& name) : name_(name) {}
+  explicit Rule(const std::string& name) : name_(name) {}
 
-  const string& name() const { return name_; }
+  const std::string& name() const { return name_; }
 
-  void AddBinding(const string& key, const EvalString& val);
+  void AddBinding(const std::string& key, const EvalString& val);
 
-  static bool IsReservedBinding(const string& var);
+  static bool IsReservedBinding(const std::string& var);
 
-  const EvalString* GetBinding(const string& key) const;
+  const EvalString* GetBinding(const std::string& key) const;
 
  private:
   // Allow the parsers to reach into this object and fill out its fields.
   friend struct ManifestParser;
 
-  string name_;
-  typedef map<string, EvalString> Bindings;
+  std::string name_;
+  typedef std::map<std::string, EvalString> Bindings;
   Bindings bindings_;
 };
 
@@ -84,26 +83,26 @@
   explicit BindingEnv(BindingEnv* parent) : parent_(parent) {}
 
   virtual ~BindingEnv() {}
-  virtual string LookupVariable(const string& var);
+  virtual std::string LookupVariable(const std::string& var);
 
   void AddRule(const Rule* rule);
-  const Rule* LookupRule(const string& rule_name);
-  const Rule* LookupRuleCurrentScope(const string& rule_name);
-  const map<string, const Rule*>& GetRules() const;
+  const Rule* LookupRule(const std::string& rule_name);
+  const Rule* LookupRuleCurrentScope(const std::string& rule_name);
+  const std::map<std::string, const Rule*>& GetRules() const;
 
-  void AddBinding(const string& key, const string& val);
+  void AddBinding(const std::string& key, const std::string& val);
 
   /// This is tricky.  Edges want lookup scope to go in this order:
   /// 1) value set on edge itself (edge_->env_)
   /// 2) value set on rule, with expansion in the edge's scope
   /// 3) value set on enclosing scope of edge (edge_->env_->parent_)
   /// This function takes as parameters the necessary info to do (2).
-  string LookupWithFallback(const string& var, const EvalString* eval,
-                            Env* env);
+  std::string LookupWithFallback(const std::string& var, const EvalString* eval,
+                                 Env* env);
 
 private:
-  map<string, string> bindings_;
-  map<string, const Rule*> rules_;
+  std::map<std::string, std::string> bindings_;
+  std::map<std::string, const Rule*> rules_;
   BindingEnv* parent_;
 };
 
diff --git a/src/graph.cc b/src/graph.cc
index facb76d..78d0d49 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -14,6 +14,7 @@
 
 #include "graph.h"
 
+#include <algorithm>
 #include <assert.h>
 #include <stdio.h>
 
@@ -27,6 +28,8 @@
 #include "state.h"
 #include "util.h"
 
+using namespace std;
+
 bool Node::Stat(DiskInterface* disk_interface, string* err) {
   return (mtime_ = disk_interface->Stat(path_, err)) != -1;
 }
@@ -222,8 +225,8 @@
   return true;
 }
 
-bool DependencyScan::RecomputeOutputDirty(Edge* edge,
-                                          Node* most_recent_input,
+bool DependencyScan::RecomputeOutputDirty(const Edge* edge,
+                                          const Node* most_recent_input,
                                           const string& command,
                                           Node* output) {
   if (edge->is_phony()) {
@@ -383,7 +386,7 @@
       result.push_back(sep);
     const string& path = (*i)->PathDecanonicalized();
     if (escape_in_out_ == kShellEscape) {
-#if _WIN32
+#ifdef _WIN32
       GetWin32EscapedString(path, &result);
 #else
       GetShellEscapedString(path, &result);
@@ -511,6 +514,17 @@
   return true;
 }
 
+struct matches {
+  explicit matches(std::vector<StringPiece>::iterator i) : i_(i) {}
+
+  bool operator()(const Node* node) const {
+    StringPiece opath = StringPiece(node->path());
+    return *i_ == opath;
+  }
+
+  std::vector<StringPiece>::iterator i_;
+};
+
 bool ImplicitDepLoader::LoadDepFile(Edge* edge, const string& path,
                                     string* err) {
   METRIC_RECORD("depfile load");
@@ -541,9 +555,15 @@
     return false;
   }
 
+  if (depfile.outs_.empty()) {
+    *err = path + ": no outputs declared";
+    return false;
+  }
+
   uint64_t unused;
-  if (!CanonicalizePath(const_cast<char*>(depfile.out_.str_),
-                        &depfile.out_.len_, &unused, err)) {
+  std::vector<StringPiece>::iterator primary_out = depfile.outs_.begin();
+  if (!CanonicalizePath(const_cast<char*>(primary_out->str_),
+                        &primary_out->len_, &unused, err)) {
     *err = path + ": " + *err;
     return false;
   }
@@ -552,12 +572,22 @@
   // mark the edge as dirty.
   Node* first_output = edge->outputs_[0];
   StringPiece opath = StringPiece(first_output->path());
-  if (opath != depfile.out_) {
+  if (opath != *primary_out) {
     EXPLAIN("expected depfile '%s' to mention '%s', got '%s'", path.c_str(),
-            first_output->path().c_str(), depfile.out_.AsString().c_str());
+            first_output->path().c_str(), primary_out->AsString().c_str());
     return false;
   }
 
+  // Ensure that all mentioned outputs are outputs of the edge.
+  for (std::vector<StringPiece>::iterator o = depfile.outs_.begin();
+       o != depfile.outs_.end(); ++o) {
+    matches m(o);
+    if (std::find_if(edge->outputs_.begin(), edge->outputs_.end(), m) == edge->outputs_.end()) {
+      *err = path + ": depfile mentions '" + o->AsString() + "' as an output, but no such output was declared";
+      return false;
+    }
+  }
+
   // Preallocate space in edge->inputs_ to be filled in below.
   vector<Node*>::iterator implicit_dep =
       PreallocateSpace(edge, depfile.ins_.size());
diff --git a/src/graph.h b/src/graph.h
index 19b25c4..8c51782 100644
--- a/src/graph.h
+++ b/src/graph.h
@@ -15,9 +15,9 @@
 #ifndef NINJA_GRAPH_H_
 #define NINJA_GRAPH_H_
 
+#include <set>
 #include <string>
 #include <vector>
-using namespace std;
 
 #include "dyndep.h"
 #include "eval_env.h"
@@ -36,7 +36,7 @@
 /// Information about a node in the dependency graph: the file, whether
 /// it's dirty, mtime, etc.
 struct Node {
-  Node(const string& path, uint64_t slash_bits)
+  Node(const std::string& path, uint64_t slash_bits)
       : path_(path),
         slash_bits_(slash_bits),
         mtime_(-1),
@@ -46,10 +46,10 @@
         id_(-1) {}
 
   /// Return false on error.
-  bool Stat(DiskInterface* disk_interface, string* err);
+  bool Stat(DiskInterface* disk_interface, std::string* err);
 
   /// Return false on error.
-  bool StatIfNecessary(DiskInterface* disk_interface, string* err) {
+  bool StatIfNecessary(DiskInterface* disk_interface, std::string* err) {
     if (status_known())
       return true;
     return Stat(disk_interface, err);
@@ -74,13 +74,13 @@
     return mtime_ != -1;
   }
 
-  const string& path() const { return path_; }
+  const std::string& path() const { return path_; }
   /// Get |path()| but use slash_bits to convert back to original slash styles.
-  string PathDecanonicalized() const {
+  std::string PathDecanonicalized() const {
     return PathDecanonicalized(path_, slash_bits_);
   }
-  static string PathDecanonicalized(const string& path,
-                                    uint64_t slash_bits);
+  static std::string PathDecanonicalized(const std::string& path,
+                                         uint64_t slash_bits);
   uint64_t slash_bits() const { return slash_bits_; }
 
   TimeStamp mtime() const { return mtime_; }
@@ -98,13 +98,13 @@
   int id() const { return id_; }
   void set_id(int id) { id_ = id; }
 
-  const vector<Edge*>& out_edges() const { return out_edges_; }
+  const std::vector<Edge*>& out_edges() const { return out_edges_; }
   void AddOutEdge(Edge* edge) { out_edges_.push_back(edge); }
 
   void Dump(const char* prefix="") const;
 
 private:
-  string path_;
+  std::string path_;
 
   /// Set bits starting from lowest for backslashes that were normalized to
   /// forward slashes by CanonicalizePath. See |PathDecanonicalized|.
@@ -130,7 +130,7 @@
   Edge* in_edge_;
 
   /// All Edges that use this Node as an input.
-  vector<Edge*> out_edges_;
+  std::vector<Edge*> out_edges_;
 
   /// A dense integer id for the node, assigned and used by DepsLog.
   int id_;
@@ -144,10 +144,11 @@
     VisitDone
   };
 
-  Edge() : rule_(NULL), pool_(NULL), dyndep_(NULL), env_(NULL),
-           mark_(VisitNone), outputs_ready_(false), deps_loaded_(false),
-           deps_missing_(false), implicit_deps_(0), order_only_deps_(0),
-           implicit_outs_(0) {}
+  Edge()
+      : rule_(NULL), pool_(NULL), dyndep_(NULL), env_(NULL), mark_(VisitNone),
+        id_(0), outputs_ready_(false), deps_loaded_(false),
+        deps_missing_(false), implicit_deps_(0), order_only_deps_(0),
+        implicit_outs_(0) {}
 
   /// Return true if all inputs' in-edges are ready.
   bool AllInputsReady() const;
@@ -158,13 +159,13 @@
   std::string EvaluateCommand(bool incl_rsp_file = false) const;
 
   /// Returns the shell-escaped value of |key|.
-  std::string GetBinding(const string& key) const;
-  bool GetBindingBool(const string& key) const;
+  std::string GetBinding(const std::string& key) const;
+  bool GetBindingBool(const std::string& key) const;
 
   /// Like GetBinding("depfile"), but without shell escaping.
-  string GetUnescapedDepfile() const;
+  std::string GetUnescapedDepfile() const;
   /// Like GetBinding("dyndep"), but without shell escaping.
-  string GetUnescapedDyndep() const;
+  std::string GetUnescapedDyndep() const;
   /// Like GetBinding("rspfile"), but without shell escaping.
   std::string GetUnescapedRspfile() const;
 
@@ -172,11 +173,12 @@
 
   const Rule* rule_;
   Pool* pool_;
-  vector<Node*> inputs_;
-  vector<Node*> outputs_;
+  std::vector<Node*> inputs_;
+  std::vector<Node*> outputs_;
   Node* dyndep_;
   BindingEnv* env_;
   VisitMark mark_;
+  size_t id_;
   bool outputs_ready_;
   bool deps_loaded_;
   bool deps_missing_;
@@ -219,6 +221,13 @@
   bool maybe_phonycycle_diagnostic() const;
 };
 
+struct EdgeCmp {
+  bool operator()(const Edge* a, const Edge* b) const {
+    return a->id_ < b->id_;
+  }
+};
+
+typedef std::set<Edge*, EdgeCmp> EdgeSet;
 
 /// ImplicitDepLoader loads implicit dependencies, as referenced via the
 /// "depfile" attribute in build files.
@@ -232,7 +241,7 @@
   /// Load implicit dependencies for \a edge.
   /// @return false on error (without filling \a err if info is just missing
   //                          or out of date).
-  bool LoadDeps(Edge* edge, string* err);
+  bool LoadDeps(Edge* edge, std::string* err);
 
   DepsLog* deps_log() const {
     return deps_log_;
@@ -241,15 +250,15 @@
  private:
   /// Load implicit dependencies for \a edge from a depfile attribute.
   /// @return false on error (without filling \a err if info is just missing).
-  bool LoadDepFile(Edge* edge, const string& path, string* err);
+  bool LoadDepFile(Edge* edge, const std::string& path, std::string* err);
 
   /// Load implicit dependencies for \a edge from the DepsLog.
   /// @return false on error (without filling \a err if info is just missing).
-  bool LoadDepsFromLog(Edge* edge, string* err);
+  bool LoadDepsFromLog(Edge* edge, std::string* err);
 
   /// Preallocate \a count spaces in the input array on \a edge, returning
   /// an iterator pointing at the first new space.
-  vector<Node*>::iterator PreallocateSpace(Edge* edge, int count);
+  std::vector<Node*>::iterator PreallocateSpace(Edge* edge, int count);
 
   /// If we don't have a edge that generates this input already,
   /// create one; this makes us not abort if the input is missing,
@@ -279,12 +288,12 @@
   /// needs to be re-run, and update outputs_ready_ and each outputs' |dirty_|
   /// state accordingly.
   /// Returns false on failure.
-  bool RecomputeDirty(Node* node, string* err);
+  bool RecomputeDirty(Node* node, std::string* err);
 
   /// Recompute whether any output of the edge is dirty, if so sets |*dirty|.
   /// Returns false on failure.
   bool RecomputeOutputsDirty(Edge* edge, Node* most_recent_input,
-                             bool* dirty, string* err);
+                             bool* dirty, std::string* err);
 
   BuildLog* build_log() const {
     return build_log_;
@@ -301,17 +310,17 @@
   /// build graph with the new information.  One overload accepts
   /// a caller-owned 'DyndepFile' object in which to store the
   /// information loaded from the dyndep file.
-  bool LoadDyndeps(Node* node, string* err) const;
-  bool LoadDyndeps(Node* node, DyndepFile* ddf, string* err) const;
+  bool LoadDyndeps(Node* node, std::string* err) const;
+  bool LoadDyndeps(Node* node, DyndepFile* ddf, std::string* err) const;
 
  private:
-  bool RecomputeDirty(Node* node, vector<Node*>* stack, string* err);
-  bool VerifyDAG(Node* node, vector<Node*>* stack, string* err);
+  bool RecomputeDirty(Node* node, std::vector<Node*>* stack, std::string* err);
+  bool VerifyDAG(Node* node, std::vector<Node*>* stack, std::string* err);
 
   /// Recompute whether a given single output should be marked dirty.
   /// Returns true if so.
-  bool RecomputeOutputDirty(Edge* edge, Node* most_recent_input,
-                            const string& command, Node* output);
+  bool RecomputeOutputDirty(const Edge* edge, const Node* most_recent_input,
+                            const std::string& command, Node* output);
 
   BuildLog* build_log_;
   DiskInterface* disk_interface_;
diff --git a/src/graph_test.cc b/src/graph_test.cc
index c8cca1c..14f6375 100644
--- a/src/graph_test.cc
+++ b/src/graph_test.cc
@@ -17,6 +17,8 @@
 
 #include "test.h"
 
+using namespace std;
+
 struct GraphTest : public StateTestWithBuiltinRules {
   GraphTest() : scan_(&state_, NULL, NULL, &fs_, NULL) {}
 
@@ -218,7 +220,7 @@
 "build a$ b: cat no'space with$ space$$ no\"space2\n"));
 
   Edge* edge = GetNode("a b")->in_edge();
-#if _WIN32
+#ifdef _WIN32
   EXPECT_EQ("cat no'space \"with space$\" \"no\\\"space2\" > \"a b\"",
       edge->EvaluateCommand());
 #else
diff --git a/src/graphviz.cc b/src/graphviz.cc
index 0d07251..37b7108 100644
--- a/src/graphviz.cc
+++ b/src/graphviz.cc
@@ -20,6 +20,8 @@
 #include "dyndep.h"
 #include "graph.h"
 
+using namespace std;
+
 void GraphViz::AddTarget(Node* node) {
   if (visited_nodes_.find(node) != visited_nodes_.end())
     return;
diff --git a/src/graphviz.h b/src/graphviz.h
index 601c9b2..3a3282e 100644
--- a/src/graphviz.h
+++ b/src/graphviz.h
@@ -18,6 +18,7 @@
 #include <set>
 
 #include "dyndep.h"
+#include "graph.h"
 
 struct DiskInterface;
 struct Node;
@@ -34,7 +35,7 @@
 
   DyndepLoader dyndep_loader_;
   std::set<Node*> visited_nodes_;
-  std::set<Edge*> visited_edges_;
+  EdgeSet visited_edges_;
 };
 
 #endif  // NINJA_GRAPHVIZ_H_
diff --git a/src/hash_collision_bench.cc b/src/hash_collision_bench.cc
index ff947dc..8f37ed0 100644
--- a/src/hash_collision_bench.cc
+++ b/src/hash_collision_bench.cc
@@ -15,20 +15,22 @@
 #include "build_log.h"
 
 #include <algorithm>
-using namespace std;
 
 #include <stdlib.h>
 #include <time.h>
 
+using namespace std;
+
 int random(int low, int high) {
   return int(low + (rand() / double(RAND_MAX)) * (high - low) + 0.5);
 }
 
 void RandomCommand(char** s) {
   int len = random(5, 100);
-  *s = new char[len];
+  *s = new char[len+1];
   for (int i = 0; i < len; ++i)
     (*s)[i] = (char)random(32, 127);
+  (*s)[len] = '\0';
 }
 
 int main() {
diff --git a/src/includes_normalize-win32.cc b/src/includes_normalize-win32.cc
index 79bf5b4..9f8dfc2 100644
--- a/src/includes_normalize-win32.cc
+++ b/src/includes_normalize-win32.cc
@@ -24,6 +24,8 @@
 
 #include <windows.h>
 
+using namespace std;
+
 namespace {
 
 bool InternalGetFullPathName(const StringPiece& file_name, char* buffer,
diff --git a/src/includes_normalize.h b/src/includes_normalize.h
index 0339581..7d50556 100644
--- a/src/includes_normalize.h
+++ b/src/includes_normalize.h
@@ -14,7 +14,6 @@
 
 #include <string>
 #include <vector>
-using namespace std;
 
 struct StringPiece;
 
@@ -22,18 +21,20 @@
 /// TODO: this likely duplicates functionality of CanonicalizePath; refactor.
 struct IncludesNormalize {
   /// Normalize path relative to |relative_to|.
-  IncludesNormalize(const string& relative_to);
+  IncludesNormalize(const std::string& relative_to);
 
   // Internal utilities made available for testing, maybe useful otherwise.
-  static string AbsPath(StringPiece s, string* err);
-  static string Relativize(StringPiece path,
-                           const vector<StringPiece>& start_list, string* err);
+  static std::string AbsPath(StringPiece s, std::string* err);
+  static std::string Relativize(StringPiece path,
+                                const std::vector<StringPiece>& start_list,
+                                std::string* err);
 
   /// Normalize by fixing slashes style, fixing redundant .. and . and makes the
   /// path |input| relative to |this->relative_to_| and store to |result|.
-  bool Normalize(const string& input, string* result, string* err) const;
+  bool Normalize(const std::string& input, std::string* result,
+                 std::string* err) const;
 
  private:
-  string relative_to_;
-  vector<StringPiece> split_relative_to_;
+  std::string relative_to_;
+  std::vector<StringPiece> split_relative_to_;
 };
diff --git a/src/includes_normalize_test.cc b/src/includes_normalize_test.cc
index dbcdbe0..9214f53 100644
--- a/src/includes_normalize_test.cc
+++ b/src/includes_normalize_test.cc
@@ -22,6 +22,8 @@
 #include "test.h"
 #include "util.h"
 
+using namespace std;
+
 namespace {
 
 string GetCurDir() {
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/lexer.cc b/src/lexer.cc
index 35ae97b..6e4a470 100644
--- a/src/lexer.cc
+++ b/src/lexer.cc
@@ -1,4 +1,4 @@
-/* Generated by re2c 0.16 */
+/* Generated by re2c 1.1.1 */
 // Copyright 2011 Google Inc. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,6 +20,8 @@
 #include "eval_env.h"
 #include "util.h"
 
+using namespace std;
+
 bool Lexer::Error(const string& message, string* err) {
   // Compute line/column.
   int line = 1;
@@ -233,8 +235,7 @@
 	goto yy5;
 yy9:
 	yyaccept = 0;
-	q = ++p;
-	yych = *p;
+	yych = *(q = ++p);
 	if (yybm[0+yych] & 32) {
 		goto yy9;
 	}
@@ -252,8 +253,7 @@
 	if (yych <= 0x00) goto yy5;
 	goto yy33;
 yy13:
-	++p;
-	yych = *p;
+	yych = *++p;
 yy14:
 	if (yybm[0+yych] & 64) {
 		goto yy13;
@@ -290,8 +290,8 @@
 	if (yych == 'u') goto yy41;
 	goto yy14;
 yy26:
-	++p;
-	if ((yych = *p) == '|') goto yy42;
+	yych = *++p;
+	if (yych == '|') goto yy42;
 	{ token = PIPE;     break; }
 yy28:
 	++p;
@@ -307,8 +307,7 @@
 		goto yy5;
 	}
 yy32:
-	++p;
-	yych = *p;
+	yych = *++p;
 yy33:
 	if (yybm[0+yych] & 128) {
 		goto yy32;
@@ -380,14 +379,14 @@
 	if (yych == 'u') goto yy61;
 	goto yy14;
 yy53:
-	++p;
-	if (yybm[0+(yych = *p)] & 64) {
+	yych = *++p;
+	if (yybm[0+yych] & 64) {
 		goto yy13;
 	}
 	{ token = POOL;     break; }
 yy55:
-	++p;
-	if (yybm[0+(yych = *p)] & 64) {
+	yych = *++p;
+	if (yybm[0+yych] & 64) {
 		goto yy13;
 	}
 	{ token = RULE;     break; }
@@ -396,8 +395,8 @@
 	if (yych == 'i') goto yy62;
 	goto yy14;
 yy58:
-	++p;
-	if (yybm[0+(yych = *p)] & 64) {
+	yych = *++p;
+	if (yybm[0+yych] & 64) {
 		goto yy13;
 	}
 	{ token = BUILD;    break; }
@@ -426,22 +425,22 @@
 	if (yych == 'j') goto yy70;
 	goto yy14;
 yy66:
-	++p;
-	if (yybm[0+(yych = *p)] & 64) {
+	yych = *++p;
+	if (yybm[0+yych] & 64) {
 		goto yy13;
 	}
 	{ token = DEFAULT;  break; }
 yy68:
-	++p;
-	if (yybm[0+(yych = *p)] & 64) {
+	yych = *++p;
+	if (yybm[0+yych] & 64) {
 		goto yy13;
 	}
 	{ token = INCLUDE;  break; }
 yy70:
 	yych = *++p;
 	if (yych != 'a') goto yy14;
-	++p;
-	if (yybm[0+(yych = *p)] & 64) {
+	yych = *++p;
+	if (yybm[0+yych] & 64) {
 		goto yy13;
 	}
 	{ token = SUBNINJA; break; }
@@ -521,8 +520,7 @@
 yy78:
 	{ break; }
 yy79:
-	++p;
-	yych = *p;
+	yych = *++p;
 	if (yybm[0+yych] & 128) {
 		goto yy79;
 	}
@@ -600,8 +598,7 @@
       return false;
     }
 yy93:
-	++p;
-	yych = *p;
+	yych = *++p;
 	if (yybm[0+yych] & 128) {
 		goto yy93;
 	}
@@ -681,8 +678,7 @@
       return Error("unexpected EOF", err);
     }
 yy100:
-	++p;
-	yych = *p;
+	yych = *++p;
 	if (yybm[0+yych] & 16) {
 		goto yy100;
 	}
@@ -704,8 +700,8 @@
       }
     }
 yy105:
-	++p;
-	if ((yych = *p) == '\n') goto yy108;
+	yych = *++p;
+	if (yych == '\n') goto yy108;
 	{
       last_token_ = start;
       return Error(DescribeLastError(), err);
@@ -750,8 +746,7 @@
       return Error("bad $-escape (literal $ must be written as $$)", err);
     }
 yy112:
-	++p;
-	yych = *p;
+	yych = *++p;
 	if (yybm[0+yych] & 32) {
 		goto yy112;
 	}
@@ -775,8 +770,7 @@
       continue;
     }
 yy120:
-	++p;
-	yych = *p;
+	yych = *++p;
 	if (yybm[0+yych] & 64) {
 		goto yy120;
 	}
@@ -797,15 +791,13 @@
 	}
 	goto yy111;
 yy126:
-	++p;
-	yych = *p;
+	yych = *++p;
 	if (yych == ' ') goto yy126;
 	{
       continue;
     }
 yy129:
-	++p;
-	yych = *p;
+	yych = *++p;
 	if (yybm[0+yych] & 128) {
 		goto yy129;
 	}
diff --git a/src/lexer.h b/src/lexer.h
index f366556..788d948 100644
--- a/src/lexer.h
+++ b/src/lexer.h
@@ -55,7 +55,7 @@
 
   /// If the last token read was an ERROR token, provide more info
   /// or the empty string.
-  string DescribeLastError();
+  std::string DescribeLastError();
 
   /// Start parsing some input.
   void Start(StringPiece filename, StringPiece input);
@@ -71,30 +71,30 @@
 
   /// Read a simple identifier (a rule or variable name).
   /// Returns false if a name can't be read.
-  bool ReadIdent(string* out);
+  bool ReadIdent(std::string* out);
 
   /// Read a path (complete with $escapes).
   /// Returns false only on error, returned path may be empty if a delimiter
   /// (space, newline) is hit.
-  bool ReadPath(EvalString* path, string* err) {
+  bool ReadPath(EvalString* path, std::string* err) {
     return ReadEvalString(path, true, err);
   }
 
   /// Read the value side of a var = value line (complete with $escapes).
   /// Returns false only on error.
-  bool ReadVarValue(EvalString* value, string* err) {
+  bool ReadVarValue(EvalString* value, std::string* err) {
     return ReadEvalString(value, false, err);
   }
 
   /// Construct an error message with context.
-  bool Error(const string& message, string* err);
+  bool Error(const std::string& message, std::string* err);
 
 private:
   /// Skip past whitespace (called after each read token/ident/etc.).
   void EatWhitespace();
 
   /// Read a $-escaped string.
-  bool ReadEvalString(EvalString* eval, bool path, string* err);
+  bool ReadEvalString(EvalString* eval, bool path, std::string* err);
 
   StringPiece filename_;
   StringPiece input_;
diff --git a/src/lexer.in.cc b/src/lexer.in.cc
index c1fb822..88007e7 100644
--- a/src/lexer.in.cc
+++ b/src/lexer.in.cc
@@ -19,6 +19,8 @@
 #include "eval_env.h"
 #include "util.h"
 
+using namespace std;
+
 bool Lexer::Error(const string& message, string* err) {
   // Compute line/column.
   int line = 1;
diff --git a/src/lexer_test.cc b/src/lexer_test.cc
index 331d8e1..c5c416d 100644
--- a/src/lexer_test.cc
+++ b/src/lexer_test.cc
@@ -17,6 +17,8 @@
 #include "eval_env.h"
 #include "test.h"
 
+using namespace std;
+
 TEST(Lexer, ReadVarValue) {
   Lexer lexer("plain text $var $VaR ${x}\n");
   EvalString eval;
diff --git a/src/line_printer.cc b/src/line_printer.cc
index c93173e..68c58ad 100644
--- a/src/line_printer.cc
+++ b/src/line_printer.cc
@@ -30,6 +30,8 @@
 
 #include "util.h"
 
+using namespace std;
+
 LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) {
   const char* term = getenv("TERM");
 #ifndef _WIN32
diff --git a/src/line_printer.h b/src/line_printer.h
index 92d4dc4..a8ec9ff 100644
--- a/src/line_printer.h
+++ b/src/line_printer.h
@@ -17,7 +17,6 @@
 
 #include <stddef.h>
 #include <string>
-using namespace std;
 
 /// Prints lines of text, possibly overprinting previously printed lines
 /// if the terminal supports it.
@@ -35,10 +34,10 @@
   };
   /// Overprints the current line. If type is ELIDE, elides to_print to fit on
   /// one line.
-  void Print(string to_print, LineType type);
+  void Print(std::string to_print, LineType type);
 
   /// Prints a string on a new line, not overprinting previous output.
-  void PrintOnNewLine(const string& to_print);
+  void PrintOnNewLine(const std::string& to_print);
 
   /// Lock or unlock the console.  Any output sent to the LinePrinter while the
   /// console is locked will not be printed until it is unlocked.
@@ -58,13 +57,13 @@
   bool console_locked_;
 
   /// Buffered current line while console is locked.
-  string line_buffer_;
+  std::string line_buffer_;
 
   /// Buffered line type while console is locked.
   LineType line_type_;
 
   /// Buffered console output while console is locked.
-  string output_buffer_;
+  std::string output_buffer_;
 
 #ifdef _WIN32
   void* console_;
diff --git a/src/load_status.h b/src/load_status.h
new file mode 100644
index 0000000..0b16b1a
--- /dev/null
+++ b/src/load_status.h
@@ -0,0 +1,24 @@
+// Copyright 2019 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef NINJA_LOAD_STATUS_H_
+#define NINJA_LOAD_STATUS_H_
+
+enum LoadStatus {
+  LOAD_ERROR,
+  LOAD_SUCCESS,
+  LOAD_NOT_FOUND,
+};
+
+#endif  // NINJA_LOAD_STATUS_H_
diff --git a/src/manifest_parser.cc b/src/manifest_parser.cc
index 2011368..54ad3f4 100644
--- a/src/manifest_parser.cc
+++ b/src/manifest_parser.cc
@@ -23,6 +23,8 @@
 #include "util.h"
 #include "version.h"
 
+using namespace std;
+
 ManifestParser::ManifestParser(State* state, FileReader* file_reader,
                                ManifestParserOptions options)
     : Parser(state, file_reader),
@@ -200,10 +202,7 @@
       return false;
   } while (!eval.empty());
 
-  if (!ExpectToken(Lexer::NEWLINE, err))
-    return false;
-
-  return true;
+  return ExpectToken(Lexer::NEWLINE, err);
 }
 
 bool ManifestParser::ParseEdge(string* err) {
@@ -228,7 +227,7 @@
     for (;;) {
       EvalString out;
       if (!lexer_.ReadPath(&out, err))
-        return err;
+        return false;
       if (out.empty())
         break;
       outs.push_back(out);
@@ -266,7 +265,7 @@
     for (;;) {
       EvalString in;
       if (!lexer_.ReadPath(&in, err))
-        return err;
+        return false;
       if (in.empty())
         break;
       ins.push_back(in);
@@ -379,14 +378,6 @@
     }
   }
 
-  // Multiple outputs aren't (yet?) supported with depslog.
-  string deps_type = edge->GetBinding("deps");
-  if (!deps_type.empty() && edge->outputs_.size() > 1) {
-    return lexer_.Error("multiple outputs aren't (yet?) supported by depslog; "
-                        "bring this up on the mailing list if it affects you",
-                        err);
-  }
-
   // Lookup, validate, and save any dyndep binding.  It will be used later
   // to load generated dependency information dynamically, but it must
   // be one of our manifest-specified inputs.
diff --git a/src/manifest_parser.h b/src/manifest_parser.h
index e14d069..954cf46 100644
--- a/src/manifest_parser.h
+++ b/src/manifest_parser.h
@@ -44,24 +44,25 @@
                  ManifestParserOptions options = ManifestParserOptions());
 
   /// Parse a text string of input.  Used by tests.
-  bool ParseTest(const string& input, string* err) {
+  bool ParseTest(const std::string& input, std::string* err) {
     quiet_ = true;
     return Parse("input", input, err);
   }
 
 private:
   /// Parse a file, given its contents as a string.
-  bool Parse(const string& filename, const string& input, string* err);
+  bool Parse(const std::string& filename, const std::string& input,
+             std::string* err);
 
   /// Parse various statement types.
-  bool ParsePool(string* err);
-  bool ParseRule(string* err);
-  bool ParseLet(string* key, EvalString* val, string* err);
-  bool ParseEdge(string* err);
-  bool ParseDefault(string* err);
+  bool ParsePool(std::string* err);
+  bool ParseRule(std::string* err);
+  bool ParseLet(std::string* key, EvalString* val, std::string* err);
+  bool ParseEdge(std::string* err);
+  bool ParseDefault(std::string* err);
 
   /// Parse either a 'subninja' or 'include' line.
-  bool ParseFileInclude(bool new_scope, string* err);
+  bool ParseFileInclude(bool new_scope, std::string* err);
 
   BindingEnv* env_;
   ManifestParserOptions options_;
diff --git a/src/manifest_parser_perftest.cc b/src/manifest_parser_perftest.cc
index 67d11f9..853d8e0 100644
--- a/src/manifest_parser_perftest.cc
+++ b/src/manifest_parser_perftest.cc
@@ -25,6 +25,9 @@
 #ifdef _WIN32
 #include "getopt.h"
 #include <direct.h>
+#elif defined(_AIX)
+#include "getopt.h"
+#include <unistd.h>
 #else
 #include <getopt.h>
 #include <unistd.h>
@@ -37,6 +40,8 @@
 #include "state.h"
 #include "util.h"
 
+using namespace std;
+
 bool WriteFakeManifests(const string& dir, string* err) {
   RealDiskInterface disk_interface;
   TimeStamp mtime = disk_interface.Stat(dir + "/build.ninja", err);
diff --git a/src/manifest_parser_test.cc b/src/manifest_parser_test.cc
index f2b7467..ec2eeed 100644
--- a/src/manifest_parser_test.cc
+++ b/src/manifest_parser_test.cc
@@ -21,6 +21,8 @@
 #include "state.h"
 #include "test.h"
 
+using namespace std;
+
 struct ParserTest : public testing::Test {
   void AssertParse(const char* input) {
     ManifestParser parser(&state, &fs_);
@@ -858,11 +860,10 @@
   State local_state;
   ManifestParser parser(&local_state, NULL);
   string err;
-  EXPECT_FALSE(parser.ParseTest("rule cc\n  command = foo\n  deps = gcc\n"
+  EXPECT_TRUE(parser.ParseTest("rule cc\n  command = foo\n  deps = gcc\n"
                                "build a.o b.o: cc c.cc\n",
                                &err));
-  EXPECT_EQ("input:5: multiple outputs aren't (yet?) supported by depslog; "
-            "bring this up on the mailing list if it affects you\n", err);
+  EXPECT_EQ("", err);
 }
 
 TEST_F(ParserTest, SubNinja) {
diff --git a/src/metrics.cc b/src/metrics.cc
index a7d3c7a..dbaf221 100644
--- a/src/metrics.cc
+++ b/src/metrics.cc
@@ -28,6 +28,8 @@
 
 #include "util.h"
 
+using namespace std;
+
 Metrics* g_metrics = NULL;
 
 namespace {
diff --git a/src/metrics.h b/src/metrics.h
index b6da859..11239b5 100644
--- a/src/metrics.h
+++ b/src/metrics.h
@@ -17,7 +17,6 @@
 
 #include <string>
 #include <vector>
-using namespace std;
 
 #include "util.h"  // For int64_t.
 
@@ -26,7 +25,7 @@
 
 /// A single metrics we're tracking, like "depfile load time".
 struct Metric {
-  string name;
+  std::string name;
   /// Number of times we've hit the code path.
   int count;
   /// Total time (in micros) we've spent on the code path.
@@ -49,13 +48,13 @@
 
 /// The singleton that stores metrics and prints the report.
 struct Metrics {
-  Metric* NewMetric(const string& name);
+  Metric* NewMetric(const std::string& name);
 
   /// Print a summary report to stdout.
   void Report();
 
 private:
-  vector<Metric*> metrics_;
+  std::vector<Metric*> metrics_;
 };
 
 /// Get the current time as relative to some epoch.
diff --git a/src/minidump-win32.cc b/src/minidump-win32.cc
index ca93638..9aea767 100644
--- a/src/minidump-win32.cc
+++ b/src/minidump-win32.cc
@@ -19,6 +19,8 @@
 
 #include "util.h"
 
+using namespace std;
+
 typedef BOOL (WINAPI *MiniDumpWriteDumpFunc) (
     IN HANDLE,
     IN DWORD,
diff --git a/src/msvc_helper-win32.cc b/src/msvc_helper-win32.cc
index de6147a..1148ae5 100644
--- a/src/msvc_helper-win32.cc
+++ b/src/msvc_helper-win32.cc
@@ -18,6 +18,8 @@
 
 #include "util.h"
 
+using namespace std;
+
 namespace {
 
 string Replace(const string& input, const string& find, const string& replace) {
diff --git a/src/msvc_helper.h b/src/msvc_helper.h
index 70d1fff..568b9f9 100644
--- a/src/msvc_helper.h
+++ b/src/msvc_helper.h
@@ -13,9 +13,8 @@
 // limitations under the License.
 
 #include <string>
-using namespace std;
 
-string EscapeForDepfile(const string& path);
+std::string EscapeForDepfile(const std::string& path);
 
 /// Wraps a synchronous execution of a CL subprocess.
 struct CLWrapper {
@@ -27,7 +26,7 @@
 
   /// Start a process and gather its raw output.  Returns its exit code.
   /// Crashes (calls Fatal()) on error.
-  int Run(const string& command, string* output);
+  int Run(const std::string& command, std::string* output);
 
   void* env_block_;
 };
diff --git a/src/msvc_helper_main-win32.cc b/src/msvc_helper_main-win32.cc
index 644b2a2..7d59307 100644
--- a/src/msvc_helper_main-win32.cc
+++ b/src/msvc_helper_main-win32.cc
@@ -24,6 +24,8 @@
 
 #include "getopt.h"
 
+using namespace std;
+
 namespace {
 
 void Usage() {
diff --git a/src/msvc_helper_test.cc b/src/msvc_helper_test.cc
index eaae51f..d9e2ee6 100644
--- a/src/msvc_helper_test.cc
+++ b/src/msvc_helper_test.cc
@@ -17,6 +17,8 @@
 #include "test.h"
 #include "util.h"
 
+using namespace std;
+
 TEST(EscapeForDepfileTest, SpacesInFilename) {
   ASSERT_EQ("sub\\some\\ sdk\\foo.h",
             EscapeForDepfile("sub\\some sdk\\foo.h"));
diff --git a/src/ninja.cc b/src/ninja.cc
index c24f09d..eb97320 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -17,6 +17,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <cstdlib>
 
 #ifdef _WIN32
 #include "getopt.h"
@@ -45,6 +46,8 @@
 #include "util.h"
 #include "version.h"
 
+using namespace std;
+
 #ifdef _MSC_VER
 // Defined in msvc_helper_main-win32.cc.
 int MSVCHelperMain(int argc, char** argv);
@@ -73,10 +76,6 @@
 
   /// Whether phony cycles should warn or print an error.
   bool phony_cycle_should_err;
-
-  /// Whether a depfile with multiple targets on separate lines should
-  /// warn or print an error.
-  bool depfile_distinct_target_lines_should_err;
 };
 
 /// The Ninja main() loads up a series of data structures; various tools need
@@ -94,7 +93,7 @@
   /// 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.
@@ -123,17 +122,19 @@
   int ToolTargets(const Options* options, int argc, char* argv[]);
   int ToolCommands(const Options* options, int argc, char* argv[]);
   int ToolClean(const Options* options, int argc, char* argv[]);
+  int ToolCleanDead(const Options* options, int argc, char* argv[]);
   int ToolCompilationDatabase(const Options* options, int argc, char* argv[]);
   int ToolRecompact(const Options* options, int argc, char* argv[]);
+  int ToolRestat(const Options* options, int argc, char* argv[]);
   int ToolUrtle(const Options* options, int argc, char** argv);
   int ToolRules(const Options* options, int argc, char* argv[]);
 
   /// Open the build log.
-  /// @return false on error.
+  /// @return LOAD_ERROR on error.
   bool OpenBuildLog(bool recompact_only = false);
 
   /// Open the deps log: load it, then open for writing.
-  /// @return false on error.
+  /// @return LOAD_ERROR on error.
   bool OpenDepsLog(bool recompact_only = false);
 
   /// Ensure the build directory exists, creating it if necessary.
@@ -154,7 +155,7 @@
 
   virtual bool IsPathDead(StringPiece s) const {
     Node* n = state_.LookupNode(s);
-    if (!n || !n->in_edge())
+    if (n && n->in_edge())
       return false;
     // Just checking n isn't enough: If an old output is both in the build log
     // and in the deps log, it will have a Node object in state_.  (It will also
@@ -612,7 +613,7 @@
 }
 
 enum PrintCommandMode { PCM_Single, PCM_All };
-void PrintCommands(Edge* edge, set<Edge*>* seen, PrintCommandMode mode) {
+void PrintCommands(Edge* edge, EdgeSet* seen, PrintCommandMode mode) {
   if (!edge)
     return;
   if (!seen->insert(edge).second)
@@ -663,7 +664,7 @@
     return 1;
   }
 
-  set<Edge*> seen;
+  EdgeSet seen;
   for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in)
     PrintCommands((*in)->in_edge(), &seen, mode);
 
@@ -719,6 +720,11 @@
   }
 }
 
+int NinjaMain::ToolCleanDead(const Options* options, int argc, char* argv[]) {
+  Cleaner cleaner(&state_, config_, &disk_interface_);
+  return cleaner.CleanDead(build_log_.entries());
+}
+
 void EncodeJSONString(const char *str) {
   while (*str) {
     if (*str == '"' || *str == '\\')
@@ -803,12 +809,14 @@
 
   bool first = true;
   vector<char> cwd;
+  char* success = NULL;
 
   do {
     cwd.resize(cwd.size() + 1024);
     errno = 0;
-  } while (!getcwd(&cwd[0], cwd.size()) && errno == ERANGE);
-  if (errno != 0 && errno != ERANGE) {
+    success = getcwd(&cwd[0], cwd.size());
+  } while (!success && errno == ERANGE);
+  if (!success) {
     Error("cannot determine working directory: %s", strerror(errno));
     return 1;
   }
@@ -845,13 +853,71 @@
   if (!EnsureBuildDirExists())
     return 1;
 
-  if (!OpenBuildLog(/*recompact_only=*/true) ||
-      !OpenDepsLog(/*recompact_only=*/true))
+  if (OpenBuildLog(/*recompact_only=*/true) == LOAD_ERROR ||
+      OpenDepsLog(/*recompact_only=*/true) == LOAD_ERROR)
     return 1;
 
   return 0;
 }
 
+int NinjaMain::ToolRestat(const Options* options, int argc, char* argv[]) {
+  // The restat tool uses getopt, and expects argv[0] to contain the name of the
+  // tool, i.e. "restat"
+  argc++;
+  argv--;
+
+  optind = 1;
+  int opt;
+  while ((opt = getopt(argc, argv, const_cast<char*>("h"))) != -1) {
+    switch (opt) {
+    case 'h':
+    default:
+      printf("usage: ninja -t restat [outputs]\n");
+      return 1;
+    }
+  }
+  argv += optind;
+  argc -= optind;
+
+  if (!EnsureBuildDirExists())
+    return 1;
+
+  string log_path = ".ninja_log";
+  if (!build_dir_.empty())
+    log_path = build_dir_ + "/" + log_path;
+
+  string err;
+  const LoadStatus status = build_log_.Load(log_path, &err);
+  if (status == LOAD_ERROR) {
+    Error("loading build log %s: %s", log_path.c_str(), err.c_str());
+    return EXIT_FAILURE;
+  }
+  if (status == LOAD_NOT_FOUND) {
+    // Nothing to restat, ignore this
+    return EXIT_SUCCESS;
+  }
+  if (!err.empty()) {
+    // Hack: Load() can return a warning via err by returning LOAD_SUCCESS.
+    Warning("%s", err.c_str());
+    err.clear();
+  }
+
+  bool success = build_log_.Restat(log_path, disk_interface_, argc, argv, &err);
+  if (!success) {
+    Error("failed recompaction: %s", err.c_str());
+    return EXIT_FAILURE;
+  }
+
+  if (!config_.dry_run) {
+    if (!build_log_.OpenForWrite(log_path, *this, &err)) {
+      Error("opening build log: %s", err.c_str());
+      return EXIT_FAILURE;
+    }
+  }
+
+  return EXIT_SUCCESS;
+}
+
 int NinjaMain::ToolUrtle(const Options* options, int argc, char** argv) {
   // RLE encoded.
   const char* urtle =
@@ -904,8 +970,12 @@
       Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCompilationDatabase },
     { "recompact",  "recompacts ninja-internal data structures",
       Tool::RUN_AFTER_LOAD, &NinjaMain::ToolRecompact },
+    { "restat",  "restats all outputs in the build log",
+      Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolRestat },
     { "rules",  "list all rules",
       Tool::RUN_AFTER_LOAD, &NinjaMain::ToolRules },
+    { "cleandead",  "clean built files that are no longer produced by the manifest",
+      Tool::RUN_AFTER_LOGS, &NinjaMain::ToolCleanDead },
     { "urtle", NULL,
       Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolUrtle },
     { NULL, NULL, Tool::RUN_AFTER_FLAGS, NULL }
@@ -982,14 +1052,13 @@
   }
 }
 
-/// 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") {
     printf("warning flags:\n"
 "  dupbuild={err,warn}  multiple build lines for one target\n"
 "  phonycycle={err,warn}  phony build statement references itself\n"
-"  depfilemulti={err,warn}  depfile has multiple output paths on separate lines\n"
     );
     return false;
   } else if (name == "dupbuild=err") {
@@ -1004,11 +1073,9 @@
   } else if (name == "phonycycle=warn") {
     options->phony_cycle_should_err = false;
     return true;
-  } else if (name == "depfilemulti=err") {
-    options->depfile_distinct_target_lines_should_err = true;
-    return true;
-  } else if (name == "depfilemulti=warn") {
-    options->depfile_distinct_target_lines_should_err = false;
+  } else if (name == "depfilemulti=err" ||
+             name == "depfilemulti=warn") {
+    Warning("deprecated warning 'depfilemulti'");
     return true;
   } else {
     const char* suggestion =
@@ -1030,17 +1097,21 @@
     log_path = build_dir_ + "/" + log_path;
 
   string err;
-  if (!build_log_.Load(log_path, &err)) {
+  const LoadStatus status = build_log_.Load(log_path, &err);
+  if (status == LOAD_ERROR) {
     Error("loading build log %s: %s", log_path.c_str(), err.c_str());
     return false;
   }
   if (!err.empty()) {
-    // Hack: Load() can return a warning via err by returning true.
+    // Hack: Load() can return a warning via err by returning LOAD_SUCCESS.
     Warning("%s", err.c_str());
     err.clear();
   }
 
   if (recompact_only) {
+    if (status == LOAD_NOT_FOUND) {
+      return true;
+    }
     bool success = build_log_.Recompact(log_path, *this, &err);
     if (!success)
       Error("failed recompaction: %s", err.c_str());
@@ -1065,17 +1136,21 @@
     path = build_dir_ + "/" + path;
 
   string err;
-  if (!deps_log_.Load(path, &state_, &err)) {
+  const LoadStatus status = deps_log_.Load(path, &state_, &err);
+  if (status == LOAD_ERROR) {
     Error("loading deps log %s: %s", path.c_str(), err.c_str());
     return false;
   }
   if (!err.empty()) {
-    // Hack: Load() can return a warning via err by returning true.
+    // Hack: Load() can return a warning via err by returning LOAD_SUCCESS.
     Warning("%s", err.c_str());
     err.clear();
   }
 
   if (recompact_only) {
+    if (status == LOAD_NOT_FOUND) {
+      return true;
+    }
     bool success = deps_log_.Recompact(path, &err);
     if (!success)
       Error("failed recompaction: %s", err.c_str());
@@ -1284,11 +1359,6 @@
   if (exit_code >= 0)
     exit(exit_code);
 
-  if (options.depfile_distinct_target_lines_should_err) {
-    config.depfile_parser_options.depfile_distinct_target_lines_action_ =
-        kDepfileDistinctTargetLinesActionError;
-  }
-
   if (options.working_dir) {
     // The formatting of this string, complete with funny quotes, is
     // so Emacs can properly identify that the cwd has changed for
diff --git a/src/ninja_test.cc b/src/ninja_test.cc
index d642c5c..b40e176 100644
--- a/src/ninja_test.cc
+++ b/src/ninja_test.cc
@@ -28,6 +28,8 @@
 #include "test.h"
 #include "line_printer.h"
 
+using namespace std;
+
 struct RegisteredTest {
   testing::Test* (*factory)();
   const char *name;
diff --git a/src/parser.cc b/src/parser.cc
index 745c532..756922d 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -17,6 +17,8 @@
 #include "disk_interface.h"
 #include "metrics.h"
 
+using namespace std;
+
 bool Parser::Load(const string& filename, string* err, Lexer* parent) {
   METRIC_RECORD(".ninja parse");
   string contents;
diff --git a/src/parser.h b/src/parser.h
index e2d2b97..011fad8 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -17,8 +17,6 @@
 
 #include <string>
 
-using namespace std;
-
 #include "lexer.h"
 
 struct FileReader;
@@ -30,12 +28,12 @@
       : state_(state), file_reader_(file_reader) {}
 
   /// Load and parse a file.
-  bool Load(const string& filename, string* err, Lexer* parent = NULL);
+  bool Load(const std::string& filename, std::string* err, Lexer* parent = NULL);
 
 protected:
   /// If the next token is not \a expected, produce an error string
   /// saying "expected foo, got bar".
-  bool ExpectToken(Lexer::Token expected, string* err);
+  bool ExpectToken(Lexer::Token expected, std::string* err);
 
   State* state_;
   FileReader* file_reader_;
@@ -43,8 +41,8 @@
 
 private:
   /// Parse a file, given its contents as a string.
-  virtual bool Parse(const string& filename, const string& input,
-                     string* err) = 0;
+  virtual bool Parse(const std::string& filename, const std::string& input,
+                     std::string* err) = 0;
 };
 
 #endif  // NINJA_PARSER_H_
diff --git a/src/state.cc b/src/state.cc
index 74cf4c1..a33d5a8 100644
--- a/src/state.cc
+++ b/src/state.cc
@@ -22,6 +22,7 @@
 #include "metrics.h"
 #include "util.h"
 
+using namespace std;
 
 void Pool::EdgeScheduled(const Edge& edge) {
   if (depth_ != 0)
@@ -38,7 +39,7 @@
   delayed_.insert(edge);
 }
 
-void Pool::RetrieveReadyEdges(set<Edge*>* ready_queue) {
+void Pool::RetrieveReadyEdges(EdgeSet* ready_queue) {
   DelayedEdges::iterator it = delayed_.begin();
   while (it != delayed_.end()) {
     Edge* edge = *it;
@@ -61,14 +62,6 @@
   }
 }
 
-// static
-bool Pool::WeightedEdgeCmp(const Edge* a, const Edge* b) {
-  if (!a) return b;
-  if (!b) return false;
-  int weight_diff = a->weight() - b->weight();
-  return ((weight_diff < 0) || (weight_diff == 0 && a < b));
-}
-
 Pool State::kDefaultPool("", 0);
 Pool State::kConsolePool("console", 1);
 const Rule State::kPhonyRule("phony");
@@ -96,6 +89,7 @@
   edge->rule_ = rule;
   edge->pool_ = &State::kDefaultPool;
   edge->env_ = &bindings_;
+  edge->id_ = edges_.size();
   edges_.push_back(edge);
   return edge;
 }
diff --git a/src/state.h b/src/state.h
index 6fe886c..72c5b33 100644
--- a/src/state.h
+++ b/src/state.h
@@ -19,9 +19,9 @@
 #include <set>
 #include <string>
 #include <vector>
-using namespace std;
 
 #include "eval_env.h"
+#include "graph.h"
 #include "hash_map.h"
 #include "util.h"
 
@@ -38,13 +38,13 @@
 /// the total scheduled weight diminishes enough (i.e. when a scheduled edge
 /// completes).
 struct Pool {
-  Pool(const string& name, int depth)
-    : name_(name), current_use_(0), depth_(depth), delayed_(&WeightedEdgeCmp) {}
+  Pool(const std::string& name, int depth)
+    : name_(name), current_use_(0), depth_(depth), delayed_() {}
 
   // A depth of 0 is infinite
   bool is_valid() const { return depth_ >= 0; }
   int depth() const { return depth_; }
-  const string& name() const { return name_; }
+  const std::string& name() const { return name_; }
   int current_use() const { return current_use_; }
 
   /// true if the Pool might delay this edge
@@ -62,22 +62,29 @@
   void DelayEdge(Edge* edge);
 
   /// Pool will add zero or more edges to the ready_queue
-  void RetrieveReadyEdges(set<Edge*>* ready_queue);
+  void RetrieveReadyEdges(EdgeSet* ready_queue);
 
   /// Dump the Pool and its edges (useful for debugging).
   void Dump() const;
 
  private:
-  string name_;
+  std::string name_;
 
   /// |current_use_| is the total of the weights of the edges which are
   /// currently scheduled in the Plan (i.e. the edges in Plan::ready_).
   int current_use_;
   int depth_;
 
-  static bool WeightedEdgeCmp(const Edge* a, const Edge* b);
+  struct WeightedEdgeCmp {
+    bool operator()(const Edge* a, const Edge* b) const {
+      if (!a) return b;
+      if (!b) return false;
+      int weight_diff = a->weight() - b->weight();
+      return ((weight_diff < 0) || (weight_diff == 0 && EdgeCmp()(a, b)));
+    }
+  };
 
-  typedef set<Edge*,bool(*)(const Edge*, const Edge*)> DelayedEdges;
+  typedef std::set<Edge*, WeightedEdgeCmp> DelayedEdges;
   DelayedEdges delayed_;
 };
 
@@ -90,17 +97,17 @@
   State();
 
   void AddPool(Pool* pool);
-  Pool* LookupPool(const string& pool_name);
+  Pool* LookupPool(const std::string& pool_name);
 
   Edge* AddEdge(const Rule* rule);
 
   Node* GetNode(StringPiece path, uint64_t slash_bits);
   Node* LookupNode(StringPiece path) const;
-  Node* SpellcheckNode(const string& path);
+  Node* SpellcheckNode(const std::string& path);
 
   void AddIn(Edge* edge, StringPiece path, uint64_t slash_bits);
   bool AddOut(Edge* edge, StringPiece path, uint64_t slash_bits);
-  bool AddDefault(StringPiece path, string* error);
+  bool AddDefault(StringPiece path, std::string* error);
 
   /// Reset state.  Keeps all nodes and edges, but restores them to the
   /// state where we haven't yet examined the disk for dirty state.
@@ -111,21 +118,21 @@
 
   /// @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<Node*> RootNodes(string* error) const;
-  vector<Node*> DefaultNodes(string* error) const;
+  std::vector<Node*> RootNodes(std::string* error) const;
+  std::vector<Node*> DefaultNodes(std::string* error) const;
 
   /// Mapping of path -> Node.
   typedef ExternalStringHashMap<Node*>::Type Paths;
   Paths paths_;
 
   /// All the pools used in the graph.
-  map<string, Pool*> pools_;
+  std::map<std::string, Pool*> pools_;
 
   /// All the edges of the graph.
-  vector<Edge*> edges_;
+  std::vector<Edge*> edges_;
 
   BindingEnv bindings_;
-  vector<Node*> defaults_;
+  std::vector<Node*> defaults_;
 };
 
 #endif  // NINJA_STATE_H_
diff --git a/src/state_test.cc b/src/state_test.cc
index 458b519..96469f9 100644
--- a/src/state_test.cc
+++ b/src/state_test.cc
@@ -16,6 +16,8 @@
 #include "state.h"
 #include "test.h"
 
+using namespace std;
+
 namespace {
 
 TEST(State, Basic) {
diff --git a/src/string_piece.h b/src/string_piece.h
index 031bda4..1c0bee6 100644
--- a/src/string_piece.h
+++ b/src/string_piece.h
@@ -17,8 +17,6 @@
 
 #include <string>
 
-using namespace std;
-
 #include <string.h>
 
 /// StringPiece represents a slice of a string whose memory is managed
@@ -30,7 +28,7 @@
   StringPiece() : str_(NULL), len_(0) {}
 
   /// The constructors intentionally allow for implicit conversions.
-  StringPiece(const string& str) : str_(str.data()), len_(str.size()) {}
+  StringPiece(const std::string& str) : str_(str.data()), len_(str.size()) {}
   StringPiece(const char* str) : str_(str), len_(strlen(str)) {}
 
   StringPiece(const char* str, size_t len) : str_(str), len_(len) {}
@@ -38,14 +36,15 @@
   bool operator==(const StringPiece& other) const {
     return len_ == other.len_ && memcmp(str_, other.str_, len_) == 0;
   }
+
   bool operator!=(const StringPiece& other) const {
     return !(*this == other);
   }
 
   /// Convert the slice into a full-fledged std::string, copying the
   /// data into a new string.
-  string AsString() const {
-    return len_ ? string(str_, len_) : string();
+  std::string AsString() const {
+    return len_ ? std::string(str_, len_) : std::string();
   }
 
   const_iterator begin() const {
diff --git a/src/string_piece_util.cc b/src/string_piece_util.cc
index 8e1ecfd..69513f5 100644
--- a/src/string_piece_util.cc
+++ b/src/string_piece_util.cc
@@ -39,7 +39,7 @@
 }
 
 string JoinStringPiece(const vector<StringPiece>& list, char sep) {
-  if (list.size() == 0){
+  if (list.empty()) {
     return "";
   }
 
diff --git a/src/string_piece_util.h b/src/string_piece_util.h
index 2e40b9f..28470f1 100644
--- a/src/string_piece_util.h
+++ b/src/string_piece_util.h
@@ -19,11 +19,10 @@
 #include <vector>
 
 #include "string_piece.h"
-using namespace std;
 
-vector<StringPiece> SplitStringPiece(StringPiece input, char sep);
+std::vector<StringPiece> SplitStringPiece(StringPiece input, char sep);
 
-string JoinStringPiece(const vector<StringPiece>& list, char sep);
+std::string JoinStringPiece(const std::vector<StringPiece>& list, char sep);
 
 inline char ToLowerASCII(char c) {
   return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
diff --git a/src/string_piece_util_test.cc b/src/string_piece_util_test.cc
index 648c647..61586dd 100644
--- a/src/string_piece_util_test.cc
+++ b/src/string_piece_util_test.cc
@@ -16,6 +16,8 @@
 
 #include "test.h"
 
+using namespace std;
+
 TEST(StringPieceUtilTest, SplitStringPiece) {
   {
     string input("a:b:c");
@@ -29,7 +31,7 @@
   }
 
   {
-    string empty("");
+    string empty;
     vector<StringPiece> list = SplitStringPiece(empty, ':');
 
     EXPECT_EQ(list.size(), 1);
@@ -80,7 +82,7 @@
   }
 
   {
-    string empty("");
+    string empty;
     vector<StringPiece> list = SplitStringPiece(empty, ':');
 
     EXPECT_EQ("", JoinStringPiece(list, ':'));
diff --git a/src/subprocess-posix.cc b/src/subprocess-posix.cc
index fc5543e..8e78540 100644
--- a/src/subprocess-posix.cc
+++ b/src/subprocess-posix.cc
@@ -18,17 +18,24 @@
 #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"
 
+using namespace std;
+
 Subprocess::Subprocess(bool use_console) : fd_(-1), pid_(-1),
                                            use_console_(use_console) {
 }
@@ -147,6 +154,16 @@
     Fatal("waitpid(%d): %s", pid_, strerror(errno));
   pid_ = -1;
 
+#ifdef _AIX
+  if (WIFEXITED(status) && WEXITSTATUS(status) & 0x80) {
+    // Map the shell's exit code used for signal failure (128 + signal) to the
+    // status code expected by AIX WIFSIGNALED and WTERMSIG macros which, unlike
+    // other systems, uses a different bit layout.
+    int signal = WEXITSTATUS(status) & 0x7f;
+    status = (signal << 16) | signal;
+  }
+#endif
+
   if (WIFEXITED(status)) {
     int exit = WEXITSTATUS(status);
     if (exit == 0)
diff --git a/src/subprocess-win32.cc b/src/subprocess-win32.cc
index a4a7669..ff3baac 100644
--- a/src/subprocess-win32.cc
+++ b/src/subprocess-win32.cc
@@ -21,6 +21,8 @@
 
 #include "util.h"
 
+using namespace std;
+
 Subprocess::Subprocess(bool use_console) : child_(NULL) , overlapped_(),
                                            is_reading_(false),
                                            use_console_(use_console) {
@@ -124,12 +126,20 @@
       buf_ = "CreateProcess failed: The system cannot find the file "
           "specified.\n";
       return true;
-    } else if (error == ERROR_INVALID_PARAMETER) {
-      // This generally means that the command line was too long. Give extra
-      // context for this case.
-      Win32Fatal("CreateProcess", "is the command line too long?");
     } else {
-      Win32Fatal("CreateProcess");    // pass all other errors to Win32Fatal
+      fprintf(stderr, "\nCreateProcess failed. Command attempted:\n\"%s\"\n",
+              command.c_str());
+      const char* hint = NULL;
+      // ERROR_INVALID_PARAMETER means the command line was formatted
+      // incorrectly. This can be caused by a command line being too long or
+      // leading whitespace in the command. Give extra context for this case.
+      if (error == ERROR_INVALID_PARAMETER) {
+        if (command.length() > 0 && (command[0] == ' ' || command[0] == '\t'))
+          hint = "command contains leading whitespace";
+        else
+          hint = "is the command line too long?";
+      }
+      Win32Fatal("CreateProcess", hint);
     }
   }
 
diff --git a/src/subprocess.h b/src/subprocess.h
index b2d486c..9e3d2ee 100644
--- a/src/subprocess.h
+++ b/src/subprocess.h
@@ -18,7 +18,6 @@
 #include <string>
 #include <vector>
 #include <queue>
-using namespace std;
 
 #ifdef _WIN32
 #include <windows.h>
@@ -49,14 +48,14 @@
 
   bool Done() const;
 
-  const string& GetOutput() const;
+  const std::string& GetOutput() const;
 
  private:
   Subprocess(bool use_console);
-  bool Start(struct SubprocessSet* set, const string& command);
+  bool Start(struct SubprocessSet* set, const std::string& command);
   void OnPipeReady();
 
-  string buf_;
+  std::string buf_;
 
 #ifdef _WIN32
   /// Set up pipe_ as the parent-side pipe of the subprocess; return the
@@ -84,13 +83,13 @@
   SubprocessSet();
   ~SubprocessSet();
 
-  Subprocess* Add(const string& command, bool use_console = false);
+  Subprocess* Add(const std::string& command, bool use_console = false);
   bool DoWork();
   Subprocess* NextFinished();
   void Clear();
 
-  vector<Subprocess*> running_;
-  queue<Subprocess*> finished_;
+  std::vector<Subprocess*> running_;
+  std::queue<Subprocess*> finished_;
 
 #ifdef _WIN32
   static BOOL WINAPI NotifyInterrupted(DWORD dwCtrlType);
diff --git a/src/subprocess_test.cc b/src/subprocess_test.cc
index 6e487db..073fe86 100644
--- a/src/subprocess_test.cc
+++ b/src/subprocess_test.cc
@@ -24,6 +24,8 @@
 #include <unistd.h>
 #endif
 
+using namespace std;
+
 namespace {
 
 #ifdef _WIN32
diff --git a/src/test.cc b/src/test.cc
index 8ba2297..11b1c9e 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #ifdef _WIN32
 #include <windows.h>
+#include <io.h>
 #else
 #include <unistd.h>
 #endif
@@ -42,22 +43,14 @@
 }
 #endif
 
+using namespace std;
+
 namespace {
 
 #ifdef _WIN32
-#ifndef _mktemp_s
-/// mingw has no mktemp.  Implement one with the same type as the one
-/// found in the Windows API.
-int _mktemp_s(char* templ) {
-  char* ofs = strchr(templ, 'X');
-  sprintf(ofs, "%d", rand() % 1000000);
-  return 0;
-}
-#endif
-
 /// Windows has no mkdtemp.  Implement it in terms of _mktemp_s.
 char* mkdtemp(char* name_template) {
-  int err = _mktemp_s(name_template);
+  int err = _mktemp_s(name_template, strlen(name_template) + 1);
   if (err < 0) {
     perror("_mktemp_s");
     return NULL;
diff --git a/src/test.h b/src/test.h
index 6af17b3..4552c34 100644
--- a/src/test.h
+++ b/src/test.h
@@ -118,7 +118,7 @@
   void AddCatRule(State* state);
 
   /// Short way to get a Node by its path from state_.
-  Node* GetNode(const string& path);
+  Node* GetNode(const std::string& path);
 
   State state_;
 };
@@ -135,7 +135,7 @@
   VirtualFileSystem() : now_(1) {}
 
   /// "Create" a file with contents.
-  void Create(const string& path, const string& contents);
+  void Create(const std::string& path, const std::string& contents);
 
   /// Tick "time" forwards; subsequent file operations will be newer than
   /// previous ones.
@@ -144,25 +144,26 @@
   }
 
   // DiskInterface
-  virtual TimeStamp Stat(const string& path, string* err) const;
-  virtual bool WriteFile(const string& path, const string& contents);
-  virtual bool MakeDir(const string& path);
-  virtual Status ReadFile(const string& path, string* contents, string* err);
-  virtual int RemoveFile(const string& path);
+  virtual TimeStamp Stat(const std::string& path, std::string* err) const;
+  virtual bool WriteFile(const std::string& path, const std::string& contents);
+  virtual bool MakeDir(const std::string& path);
+  virtual Status ReadFile(const std::string& path, std::string* contents,
+                          std::string* err);
+  virtual int RemoveFile(const std::string& path);
 
   /// An entry for a single in-memory file.
   struct Entry {
     int mtime;
-    string stat_error;  // If mtime is -1.
-    string contents;
+    std::string stat_error;  // If mtime is -1.
+    std::string contents;
   };
 
-  vector<string> directories_made_;
-  vector<string> files_read_;
-  typedef map<string, Entry> FileMap;
+  std::vector<std::string> directories_made_;
+  std::vector<std::string> files_read_;
+  typedef std::map<std::string, Entry> FileMap;
   FileMap files_;
-  set<string> files_removed_;
-  set<string> files_created_;
+  std::set<std::string> files_removed_;
+  std::set<std::string> files_created_;
 
   /// A simple fake timestamp for file operations.
   int now_;
@@ -170,15 +171,15 @@
 
 struct ScopedTempDir {
   /// Create a temporary directory and chdir into it.
-  void CreateAndEnter(const string& name);
+  void CreateAndEnter(const std::string& name);
 
   /// Clean up the temporary directory.
   void Cleanup();
 
   /// The temp directory containing our dir.
-  string start_dir_;
+  std::string start_dir_;
   /// The subdirectory name for our dir, or empty if it hasn't been set up.
-  string temp_dir_name_;
+  std::string temp_dir_name_;
 };
 
 #endif // NINJA_TEST_H_
diff --git a/src/util.cc b/src/util.cc
index 6ea854b..ae2e3c2 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -51,9 +51,15 @@
 #include <sys/sysinfo.h>
 #endif
 
+#if defined(__FreeBSD__)
+#include <sys/cpuset.h>
+#endif
+
 #include "edit_distance.h"
 #include "metrics.h"
 
+using namespace std;
+
 void Fatal(const char* msg, ...) {
   va_list ap;
   fprintf(stderr, "ninja: fatal: ");
@@ -512,10 +518,17 @@
 #endif
   return GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
 #else
-#ifdef CPU_COUNT
   // The number of exposed processors might not represent the actual number of
   // processors threads can run on. This happens when a CPU set limitation is
   // active, see https://github.com/ninja-build/ninja/issues/1278
+#if defined(__FreeBSD__)
+  cpuset_t mask;
+  CPU_ZERO(&mask);
+  if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask),
+    &mask) == 0) {
+    return CPU_COUNT(&mask);
+  }
+#elif defined(CPU_COUNT)
   cpu_set_t set;
   if (sched_getaffinity(getpid(), sizeof(set), &set) == 0) {
     return CPU_COUNT(&set);
diff --git a/src/util.h b/src/util.h
index 6a4a7a9..4e6ebb8 100644
--- a/src/util.h
+++ b/src/util.h
@@ -23,7 +23,6 @@
 
 #include <string>
 #include <vector>
-using namespace std;
 
 #ifdef _MSC_VER
 #define NORETURN __declspec(noreturn)
@@ -57,29 +56,30 @@
 /// Canonicalize a path like "foo/../bar.h" into just "bar.h".
 /// |slash_bits| has bits set starting from lowest for a backslash that was
 /// normalized to a forward slash. (only used on Windows)
-bool CanonicalizePath(string* path, uint64_t* slash_bits, string* err);
+bool CanonicalizePath(std::string* path, uint64_t* slash_bits,
+                      std::string* err);
 bool CanonicalizePath(char* path, size_t* len, uint64_t* slash_bits,
-                      string* err);
+                      std::string* err);
 
 /// Appends |input| to |*result|, escaping according to the whims of either
 /// Bash, or Win32's CommandLineToArgvW().
 /// Appends the string directly to |result| without modification if we can
 /// determine that it contains no problematic characters.
-void GetShellEscapedString(const string& input, string* result);
-void GetWin32EscapedString(const string& input, string* result);
+void GetShellEscapedString(const std::string& input, std::string* result);
+void GetWin32EscapedString(const std::string& input, std::string* result);
 
 /// Read a file to a string (in text mode: with CRLF conversion
 /// on Windows).
 /// Returns -errno and fills in \a err on error.
-int ReadFile(const string& path, string* contents, string* err);
+int ReadFile(const std::string& path, std::string* contents, std::string* err);
 
 /// Mark a file descriptor to not be inherited on exec()s.
 void SetCloseOnExec(int fd);
 
 /// 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);
+const char* SpellcheckStringV(const std::string& text,
+                              const std::vector<const char*>& words);
 
 /// Like SpellcheckStringV, but takes a NULL-terminated list.
 const char* SpellcheckString(const char* text, ...);
@@ -87,7 +87,7 @@
 bool islatinalpha(int c);
 
 /// Removes all Ansi escape codes (http://www.termsys.demon.co.uk/vtansi.htm).
-string StripAnsiEscapeCodes(const string& in);
+std::string StripAnsiEscapeCodes(const std::string& in);
 
 /// @return the number of processors on the machine.  Useful for an initial
 /// guess for how many jobs to run in parallel.  @return 0 on error.
@@ -99,10 +99,10 @@
 
 /// Elide the given string @a str with '...' in the middle if the length
 /// exceeds @a width.
-string ElideMiddle(const string& str, size_t width);
+std::string ElideMiddle(const std::string& str, size_t width);
 
 /// Truncates a file to the given size.
-bool Truncate(const string& path, size_t size, string* err);
+bool Truncate(const std::string& path, size_t size, std::string* err);
 
 #ifdef _MSC_VER
 #define snprintf _snprintf
@@ -116,7 +116,7 @@
 
 #ifdef _WIN32
 /// Convert the value returned by GetLastError() into a string.
-string GetLastErrorString();
+std::string GetLastErrorString();
 
 /// Calls Fatal() with a function name and GetLastErrorString.
 NORETURN void Win32Fatal(const char* function, const char* hint = NULL);
diff --git a/src/util_test.cc b/src/util_test.cc
index b43788d..1621c91 100644
--- a/src/util_test.cc
+++ b/src/util_test.cc
@@ -16,6 +16,8 @@
 
 #include "test.h"
 
+using namespace std;
+
 namespace {
 
 bool CanonicalizePath(string* path, string* err) {
diff --git a/src/version.cc b/src/version.cc
index 1c906ae..97afa7e 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -18,7 +18,9 @@
 
 #include "util.h"
 
-const char* kNinjaVersion = "1.9.0.git";
+using namespace std;
+
+const char* kNinjaVersion = "1.10.2.git";
 
 void ParseVersion(const string& version, int* major, int* minor) {
   size_t end = version.find('.');
diff --git a/src/version.h b/src/version.h
index bd6b9ff..9d84ecb 100644
--- a/src/version.h
+++ b/src/version.h
@@ -16,17 +16,16 @@
 #define NINJA_VERSION_H_
 
 #include <string>
-using namespace std;
 
 /// The version number of the current Ninja release.  This will always
 /// be "git" on trunk.
 extern const char* kNinjaVersion;
 
 /// Parse the major/minor components of a version string.
-void ParseVersion(const string& version, int* major, int* minor);
+void ParseVersion(const std::string& version, int* major, int* minor);
 
 /// Check whether \a version is compatible with the current Ninja version,
 /// aborting if not.
-void CheckNinjaVersion(const string& required_version);
+void CheckNinjaVersion(const std::string& required_version);
 
 #endif  // NINJA_VERSION_H_