Close fuchsia-rfc-0153 branch.

Since all development has been moved to the `main`
branch, remove all files from the current branch,
and add a new README.md one explaining the situation
and listing the corresponding `main` commit that
replicates the last known state of this one.

Fixed: 301120237
Change-Id: Ifd3f4ffe22d5d4c547bbcace517e088df6c76f2b
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/github.com/ninja-build/ninja/+/987832
Reviewed-by: Tyler Mandry <tmandry@google.com>
Reviewed-by: David Turner <digit@google.com>
diff --git a/.clang-format b/.clang-format
deleted file mode 100644
index b8e9225..0000000
--- a/.clang-format
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2014 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.
-
-# This isn't meant to be authoritative, but it's good enough to be useful.
-# Still use your best judgement for formatting decisions: clang-format
-# sometimes makes strange choices.
-
-BasedOnStyle: Google
-AllowShortFunctionsOnASingleLine: Inline
-AllowShortIfStatementsOnASingleLine: false
-AllowShortLoopsOnASingleLine: false
-ConstructorInitializerAllOnOneLineOrOnePerLine: false
-Cpp11BracedListStyle: false
-IndentCaseLabels: false
-DerivePointerBinding: false
diff --git a/.clang-tidy b/.clang-tidy
deleted file mode 100644
index e0afd47..0000000
--- a/.clang-tidy
+++ /dev/null
@@ -1,17 +0,0 @@
----
-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
deleted file mode 100644
index 0cc68d6..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-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
deleted file mode 100644
index 57a569e..0000000
--- a/.github/workflows/linux.yml
+++ /dev/null
@@ -1,209 +0,0 @@
-name: Linux
-
-on:
-  pull_request:
-  push:
-  release:
-    types: published
-
-jobs:
-  build:
-    runs-on: [ubuntu-latest]
-    container:
-      image: centos:7
-    steps:
-    - uses: actions/checkout@v2
-    - uses: codespell-project/actions-codespell@master
-      with:
-        ignore_words_list: fo,wee
-    - 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-20.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-20.el7.x86_64.rpm
-        rpm -U --quiet p7zip-16.02-20.el7.x86_64.rpm
-        rpm -U --quiet p7zip-plugins-16.02-20.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
-
-  build-aarch64:
-    name: Build Linux ARM64
-    runs-on: [ubuntu-latest]
-    steps:
-    - uses: actions/checkout@v3
-
-    - name: Build
-      uses: uraimo/run-on-arch-action@v2
-      with:
-        arch: aarch64
-        distro: ubuntu18.04
-        githubToken: ${{ github.token }}
-        dockerRunArgs: |
-          --volume "${PWD}:/ninja"
-        install: |
-          apt-get update -q -y
-          apt-get install -q -y make gcc g++ libasan5 clang-tools curl p7zip-full file
-        run: |
-          set -x
-          cd /ninja
-
-          # INSTALL CMAKE
-          CMAKE_VERSION=3.23.4
-          curl -L -O https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-aarch64.sh
-          chmod +x cmake-${CMAKE_VERSION}-Linux-aarch64.sh
-          ./cmake-${CMAKE_VERSION}-Linux-aarch64.sh --skip-license --prefix=/usr/local
-
-          # BUILD
-          cmake -DCMAKE_BUILD_TYPE=Release -B release-build
-          cmake --build release-build --parallel --config Release
-          strip release-build/ninja
-          file release-build/ninja
-
-          # TEST
-          pushd release-build
-          ./ninja_test
-          popd
-
-          # CREATE ARCHIVE
-          mkdir artifact
-          7z a artifact/ninja-linux-aarch64.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-aarch64.zip
-        asset_name: ninja-linux-aarch64.zip
-        asset_content_type: application/zip
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
deleted file mode 100644
index 96b7cf1..0000000
--- a/.github/workflows/macos.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-name: macOS
-
-on:
-  pull_request:
-  push:
-  release:
-    types: published
-
-jobs:
-  build:
-    runs-on: macos-12
-
-    steps:
-    - uses: actions/checkout@v2
-
-    - name: Install dependencies
-      run: brew install re2c p7zip cmake
-
-    - name: Build ninja
-      shell: bash
-      env:
-        MACOSX_DEPLOYMENT_TARGET: 10.15
-      run: |
-        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
deleted file mode 100644
index b6ec2ac..0000000
--- a/.github/workflows/windows.yml
+++ /dev/null
@@ -1,67 +0,0 @@
-name: Windows
-
-on:
-  pull_request:
-  push:
-  release:
-    types: published
-
-jobs:
-  build:
-    runs-on: windows-latest
-
-    strategy:
-      fail-fast: false
-      matrix:
-        include:
-        - arch: 'x64'
-          suffix: ''
-        - arch: 'arm64'
-          suffix: 'arm64'
-
-    steps:
-    - uses: actions/checkout@v2
-
-    - name: Install dependencies
-      run: choco install re2c
-
-    - name: Build ninja
-      shell: bash
-      run: |
-        cmake -Bbuild -A ${{ matrix.arch }}
-        cmake --build build --parallel --config Debug
-        cmake --build build --parallel --config Release
-
-    - name: Test ninja (Debug)
-      if: matrix.arch != 'arm64'
-      run: .\ninja_test.exe
-      working-directory: build/Debug
-
-    - name: Test ninja (Release)
-      if: matrix.arch != 'arm64'
-      run: .\ninja_test.exe
-      working-directory: build/Release
-
-    - name: Create ninja archive
-      shell: bash
-      run: |
-        mkdir artifact
-        7z a artifact/ninja-win${{ matrix.suffix }}.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${{ matrix.suffix }}.zip
-        asset_name: ninja-win${{ matrix.suffix }}.zip
-        asset_content_type: application/zip
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index ca36ec8..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,49 +0,0 @@
-*.pyc
-*.obj
-*.exe
-*.pdb
-*.ilk
-/build*/
-/build.ninja
-/ninja
-/ninja.bootstrap
-/build_log_perftest
-/canon_perftest
-/clparser_perftest
-/depfile_parser_perftest
-/hash_collision_bench
-/ninja_test
-/manifest_parser_perftest
-/graph.png
-/doc/manual.html
-/doc/doxygen
-*.patch
-.DS_Store
-
-# Eclipse project files
-.project
-.cproject
-
-# SublimeText project files
-*.sublime-project
-*.sublime-workspace
-
-# Ninja output
-.ninja_deps
-.ninja_log
-
-# Visual Studio Code project files
-/.vscode/
-/.ccls-cache/
-
-# Qt Creator project files
-/CMakeLists.txt.user
-
-# clangd
-/.clangd/
-/compile_commands.json
-/.cache/
-
-# Visual Studio files
-/.vs/
-/out/
diff --git a/CMakeLists.txt b/CMakeLists.txt
deleted file mode 100644
index b901d7c..0000000
--- a/CMakeLists.txt
+++ /dev/null
@@ -1,313 +0,0 @@
-cmake_minimum_required(VERSION 3.15)
-
-include(CheckSymbolExists)
-include(CheckIPOSupported)
-
-option(NINJA_BUILD_BINARY "Build ninja binary" ON)
-option(NINJA_FORCE_PSELECT "Use pselect() even on platforms that provide ppoll()" OFF)
-
-project(ninja CXX)
-
-# --- 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()
-	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})
-	# Note that these settings are separately specified in configure.py, and
-	# these lists should be kept in sync.
-	add_compile_options(/W4 /wd4100 /wd4267 /wd4706 /wd4702 /wd4244 /GR- /Zc:__cplusplus)
-	add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
-else()
-	include(CheckCXXCompilerFlag)
-	check_cxx_compiler_flag(-Wno-deprecated flag_no_deprecated)
-	if(flag_no_deprecated)
-		add_compile_options(-Wno-deprecated)
-	endif()
-	check_cxx_compiler_flag(-fdiagnostics-color flag_color_diag)
-	if(flag_color_diag)
-		add_compile_options(-fdiagnostics-color)
-	endif()
-
-	if(NOT NINJA_FORCE_PSELECT)
-		# Check whether ppoll() is usable on the target platform.
-		# Set -DUSE_PPOLL=1 if this is the case.
-		#
-		# NOTE: Use check_cxx_symbol_exists() instead of check_symbol_exists()
-		# because on Linux, <poll.h> only exposes the symbol when _GNU_SOURCE
-		# is defined.
-		#
-		# Both g++ and clang++ define the symbol by default, because the C++
-		# standard library headers require it, but *not* gcc and clang, which
-		# are used by check_symbol_exists().
-		include(CheckCXXSymbolExists)
-		check_cxx_symbol_exists(ppoll poll.h HAVE_PPOLL)
-		check_cxx_symbol_exists(kqueue sys/event.h HAVE_KQUEUE)
-		if (HAVE_KQUEUE)
-			add_compile_definitions(USE_KQUEUE=1)
-		elseif (HAVE_PPOLL)
-			add_compile_definitions(USE_PPOLL=1)
-		endif()
-	endif()
-endif()
-
-# --- optional re2c
-find_program(RE2C re2c)
-if(RE2C)
-	# the depfile parser and ninja lexers are generated using re2c.
-	function(re2c IN OUT)
-		add_custom_command(DEPENDS ${IN} OUTPUT ${OUT}
-			COMMAND ${RE2C} -b -i --no-generation-date --no-version -o ${OUT} ${IN}
-		)
-	endfunction()
-	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 ${PROJECT_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)
-		if(NOT WIN32)
-			message(WARNING "browse feature omitted due to inline script failure")
-		endif()
-		return()
-	endif()
-
-	# Now check availability of the unistd header
-	check_symbol_exists(fork "unistd.h" HAVE_FORK)
-	check_symbol_exists(pipe "unistd.h" HAVE_PIPE)
-	set(browse_supported 0)
-	if (HAVE_FORK AND HAVE_PIPE)
-		set(browse_supported 1)
-	endif ()
-	set(${RESULT} "${browse_supported}" PARENT_SCOPE)
-	if(NOT browse_supported)
-		message(WARNING "browse feature omitted due to missing `fork` and `pipe` functions")
-	endif()
-
-endfunction()
-
-set(NINJA_PYTHON "python" CACHE STRING "Python interpreter to use for the browse tool")
-
-check_platform_supports_browse_mode(platform_supports_ninja_browse)
-
-# Core source files all build into ninja library.
-add_library(libninja OBJECT
-	src/async_loop.cc
-	src/build_config.cc
-	src/build_log.cc
-	src/build.cc
-	src/clean.cc
-	src/clparser.cc
-	src/dyndep.cc
-	src/dyndep_parser.cc
-	src/debug_flags.cc
-	src/deps_log.cc
-	src/disk_interface.cc
-	src/edit_distance.cc
-	src/eval_env.cc
-	src/graph.cc
-	src/graphviz.cc
-	src/ipc_utils.cc
-	src/json.cc
-	src/line_printer.cc
-	src/manifest_parser.cc
-	src/metrics.cc
-	src/missing_deps.cc
-	src/parser.cc
-	src/persistent_mode.cc
-	src/persistent_service.cc
-	src/process_utils.cc
-	src/state.cc
-	src/status.cc
-	src/stdio_redirection.cc
-	src/string_piece_util.cc
-	src/util.cc
-	src/version.cc
-)
-if(WIN32)
-	target_sources(libninja PRIVATE
-		src/subprocess-win32.cc
-		src/includes_normalize-win32.cc
-		src/interrupt_handling-win32.cc
-		src/ipc_handle-win32.cc
-		src/msvc_helper-win32.cc
-		src/msvc_helper_main-win32.cc
-		src/getopt.c
-		src/minidump-win32.cc
-	)
-	# Build getopt.c, which can be compiled as either C or C++, as C++
-	# so that build environments which lack a C compiler, but have a C++
-	# compiler may build ninja.
-	set_source_files_properties(src/getopt.c PROPERTIES LANGUAGE CXX)
-else()
-	target_sources(libninja PRIVATE
-		src/interrupt_handling-posix.cc
-		src/ipc_handle-posix.cc
-		src/subprocess-posix.cc
-	)
-	if(CMAKE_SYSTEM_NAME STREQUAL "OS400" OR CMAKE_SYSTEM_NAME STREQUAL "AIX")
-		target_sources(libninja PRIVATE src/getopt.c)
-		# Build getopt.c, which can be compiled as either C or C++, as C++
-		# so that build environments which lack a C compiler, but have a C++
-		# compiler may build ninja.
-		set_source_files_properties(src/getopt.c PROPERTIES LANGUAGE CXX)
-	endif()
-
-	# Needed for perfstat_cpu_total
-	if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
-		target_link_libraries(libninja PUBLIC "-lperfstat")
-	endif()
-endif()
-
-if(WIN32)
-	target_sources(libninja PRIVATE
-		src/stat_cache-win32.cc
-	)
-else()
-	target_sources(libninja PRIVATE
-		src/stat_cache-posix.cc
-	)
-endif()
-
-target_compile_features(libninja PUBLIC cxx_std_11)
-
-#Fixes GetActiveProcessorCount on MinGW
-if(MINGW)
-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")
-	add_compile_definitions(__STDC_FORMAT_MACROS)
-endif()
-
-# Main executable is library plus main() function.
-if(NINJA_BUILD_BINARY)
-	add_executable(ninja src/ninja.cc)
-	target_link_libraries(ninja PRIVATE libninja libninja-re2c)
-
-	if(WIN32)
-		target_sources(ninja PRIVATE windows/ninja.manifest)
-	endif()
-endif()
-
-# 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 ${PROJECT_BINARY_DIR}/build
-		COMMAND src/inline.sh kBrowsePy
-						< src/browse.py
-						> ${PROJECT_BINARY_DIR}/build/browse_py.h
-		WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
-		VERBATIM
-	)
-
-	if(NINJA_BUILD_BINARY)
-		target_compile_definitions(ninja PRIVATE NINJA_HAVE_BROWSE)
-		target_sources(ninja PRIVATE src/browse.cc)
-	endif()
-	set_source_files_properties(src/browse.cc
-		PROPERTIES
-			OBJECT_DEPENDS "${PROJECT_BINARY_DIR}/build/browse_py.h"
-			INCLUDE_DIRECTORIES "${PROJECT_BINARY_DIR}"
-			COMPILE_DEFINITIONS NINJA_PYTHON="${NINJA_PYTHON}"
-	)
-endif()
-
-include(CTest)
-if(BUILD_TESTING)
-  # Tests all build into ninja_test executable.
-  add_executable(ninja_test
-    src/async_loop_test.cc
-    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/interrupt_handling_test.cc
-    src/ipc_handle_test.cc
-    src/ipc_utils_test.cc
-    src/json_test.cc
-    src/lexer_test.cc
-    src/manifest_parser_test.cc
-    src/missing_deps_test.cc
-    src/ninja_test.cc
-    src/persistent_mode_test.cc
-    src/persistent_service_test.cc
-    src/process_utils_test.cc
-    src/stat_cache_test.cc
-    src/state_test.cc
-    src/stdio_redirection_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
-    persistent_mode_test_helper
-    persistent_service_test_helper
-  )
-    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_options(hash_collision_bench PRIVATE "-Wl,-bmaxdata:0x80000000")
-    target_link_options(manifest_parser_perftest PRIVATE "-Wl,-bmaxdata:0x80000000")
-  endif()
-
-  add_test(NAME NinjaTest COMMAND ninja_test)
-endif()
-
-if(NINJA_BUILD_BINARY)
-	install(TARGETS ninja)
-endif()
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index 37f6ebc..0000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# 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:
-
-* 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.
-* 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/COPYING b/COPYING
deleted file mode 100644
index 131cb1d..0000000
--- a/COPYING
+++ /dev/null
@@ -1,202 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2010
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   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.
diff --git a/README.fuchsia b/README.fuchsia
deleted file mode 100644
index 6251197..0000000
--- a/README.fuchsia
+++ /dev/null
@@ -1,87 +0,0 @@
-Name: Ninja
-URL: https://ninja-build.org
-Gerrit Git: https://fuchsia.googlesource.com/third_party/github.com/ninja-build/ninja
-Upstream Git: https://github.com/ninja-build/ninja
-Fuchsia RFC: https://fuchsia.dev/fuchsia-src/contribute/governance/rfcs/0153_ninja_customization?hl=en
-License: Apache 2.0
-License File: COPYING
-Fuchsia Bug: https://fxbug.dev/91545
-Description:
-
-Ninja is a small build system with a focus on speed. As explained in the
-Fuchsia RFC-0153 document, this is a temporary custom branch of the upstream
-Ninja sources to provide various improvements for the Fuchsia build. All
-changes should be expressed as a set of small commits on top of the upstream
-main branch, periodically rebased according to the strategy described in the
-RFC document. Due to this, local modifications are not listed explictly here
-to reduce unnecessary merge conflicts in this file.
-
-Note that:
-
-- Development happens in the `fuchsia-rfc-0153` branch of
-  `https://fuchsia.googlesource.com/third_party/github.com/ninja-build/ninja`
-
-- All patches need to be uploaded to Gerrit for review approval.
-
-- Sync branches can only be created on Gerrit, and require filing
-  a ticket, see associated bug for details.
-
-Use `git log origin/upstream/master..fuchsia-rfc-0153` to see the detail log
-of changes instead.
-
-To facilite sync branch creation and management, the commit message of
-patches should following these conventions:
-
-- Patches that were cherry-picked from upstream should have a line that
-  starts with `Upstream-Cherry-Pick: <COMMIT>` added to their original
-  commit message.
-
-- Patches that were cherry-picked from the upstream GitHub pull requests
-  should have a line that starts with  `Upstream-GitHub-PR: <URL>`
-  pointing to the corresponding pull request.
-
-- Patches that should not be sent upstream should have a line that
-  starts with `Fuchsia-Only: <REASON>`. These should only matter for
-  Fuchsia specific documentation (such as this file), or development
-  scripts.
-
-- Non-trivial changes that address a specific feature should be provided
-  as a series of small patches whose commit messages all include a line
-  that starts with `Fuchsia-Topic: <name>`, where `<name>` is a small
-  identifier describing the common feature (e.g. `faster-manifest-parser`)
-  described by the list in the next section of this README.fuchsia file.
-
-  This will allow collecting the commits to send them as upstream pull
-  requests (after removing these lines from the commit message), or to
-  re-order them during sync-branch rebase operations.
-
-Fuchsia-specific scripts or data files should go under `misc/fuchsia/`.
-
-List of Fuchsia-Topic items:
-
-multi-line-status
-  Improve the status display in smart terminals to include a list of
-  the oldest pending commands that are still running. This feature is
-  controlled by setting NINJA_STATUS_MAX_COMMANDS in the
-  environment to a decimal value that is >= 1.
-
-advanced-ipc
-  Provide support for advanced inter-process communication using
-  named pipes (on Win32) or unix domain sockets (on Posix). This
-  will be used to implement both the `persistent-mode` feature
-  and the `jobserver-support` feature.
-
-persistent-mode
-  Allow the Ninja process to run in daemon mode after parsing the
-  Ninja build plan, until a .ninja file is changed or some fixed
-  expiration time, in order to start future `ninja` invocations
-  immediately (instead of spending several seconds to re-load the
-  build plan every time).
-  Requires: advanced-ipc
-
-jobserver-support
-  Allow Ninja to act as both a GNU Make jobserver client
-  (when invoking from other build systems), and a server
-  (when invoking sub-commands).
-  Requires: advanced-ipc
-
diff --git a/README.md b/README.md
index 1ca56c5..629c892 100644
--- a/README.md
+++ b/README.md
@@ -1,51 +1,10 @@
-# Ninja
+Development of the Fuchsia-specific Ninja fork
+described by Fuchsia RFC-0153 has moved from the
+`fuchsia-rfc-0153` branch to the `main` one on
+this git repository. For more details, see
 
-Ninja is a small build system with a focus on speed.
-https://ninja-build.org/
+  https://fxbug.dev/301120237
 
-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 on
-  [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
-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
-```
+The previous state of this branch is reflected
+in commit dba41a7f80dc426364ae9238746f37ff7d06febf
+belonging to the main branch.
diff --git a/RELEASING.md b/RELEASING.md
deleted file mode 100644
index 4e3a4bd..0000000
--- a/RELEASING.md
+++ /dev/null
@@ -1,41 +0,0 @@
-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 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
-   ```
-   git commit -am 'mark this 1.5.0.git'
-   ```
-5. git checkout release; git merge master
-6. Fix version number in src/version.cc (it will likely conflict in the above)
-7. Fix version in doc/manual.asciidoc (exists only on release branch)
-8. commit, tag, push (don't forget to push --tags)
-   ```
-   git commit -am v1.5.0; git push origin release
-   git tag v1.5.0; git push --tags
-   # Push the 1.5.0.git change on master too:
-   git checkout master; git push origin master
-   ```
-9. Construct release notes from prior notes
-
-   credits: `git shortlog -s --no-merges REV..`
-
-
-### Release on GitHub:
-1. Go to [Tags](https://github.com/ninja-build/ninja/tags)
-2. Open the newly created tag and select "Create release from tag"
-3. Create the release which will trigger a build which automatically attaches
-   the binaries
-
-### Make announcement on mailing list:
-1. copy old mail
-
-### Update website:
-1. Make sure your ninja checkout is on the v1.5.0 tag
-2. Clone https://github.com/ninja-build/ninja-build.github.io
-3. In that repo, `./update-docs.sh`
-4. Update index.html with newest version and link to release notes
-5. `git commit -m 'run update-docs.sh, 1.5.0 release'`
-6. `git push origin master`
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index f0b92b8..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,61 +0,0 @@
-version: 1.0.{build}
-image:
-  - Visual Studio 2017
-  - Ubuntu1804
-
-environment:
-  CLICOLOR_FORCE: 1
-  CHERE_INVOKING: 1 # Tell Bash to inherit the current working directory
-  matrix:
-    - MSYSTEM: MINGW64
-    - MSYSTEM: MSVC
-    - MSYSTEM: LINUX
-
-matrix:
-  exclude:
-    - image: Visual Studio 2017
-      MSYSTEM: LINUX
-    - image: Ubuntu1804
-      MSYSTEM: MINGW64
-    - image: Ubuntu1804
-      MSYSTEM: MSVC
-
-for:
-  -
-    matrix:
-      only:
-        - MSYSTEM: MINGW64
-    build_script:
-      ps: "C:\\msys64\\usr\\bin\\bash -lc @\"\n
-      pacman -S --quiet --noconfirm --needed re2c 2>&1\n
-      ./configure.py --bootstrap --platform mingw 2>&1\n
-      ./ninja all\n
-      ./ninja_test 2>&1\n
-      ./misc/ninja_syntax_test.py 2>&1\n\"@"
-  -
-    matrix:
-      only:
-        - MSYSTEM: MSVC
-    build_script:
-    - cmd: >-
-        call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
-
-        python configure.py --bootstrap
-
-        ninja.bootstrap.exe all
-
-        ninja_test
-
-        python misc/ninja_syntax_test.py
-
-  - matrix:
-      only:
-        - image: Ubuntu1804
-    build_script:
-      - ./configure.py --bootstrap
-      - ./ninja all
-      - ./ninja_test
-      - misc/ninja_syntax_test.py
-      - misc/output_test.py
-
-test: off
diff --git a/configure.py b/configure.py
deleted file mode 100755
index 4a3c67c..0000000
--- a/configure.py
+++ /dev/null
@@ -1,774 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2001 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.
-
-"""Script that generates the build.ninja for ninja itself.
-
-Projects that use ninja themselves should either write a similar script
-or use a meta-build system that supports Ninja output."""
-
-from optparse import OptionParser
-import os
-import pipes
-import string
-import subprocess
-import sys
-
-sourcedir = os.path.dirname(os.path.realpath(__file__))
-sys.path.insert(0, os.path.join(sourcedir, 'misc'))
-import ninja_syntax
-
-
-class Platform(object):
-    """Represents a host/target platform and its specific build attributes."""
-    def __init__(self, platform):
-        self._platform = platform
-        if self._platform is not None:
-            return
-        self._platform = sys.platform
-        if self._platform.startswith('linux'):
-            self._platform = 'linux'
-        elif self._platform.startswith('freebsd'):
-            self._platform = 'freebsd'
-        elif self._platform.startswith('gnukfreebsd'):
-            self._platform = 'freebsd'
-        elif self._platform.startswith('openbsd'):
-            self._platform = 'openbsd'
-        elif self._platform.startswith('solaris') or self._platform == 'sunos5':
-            self._platform = 'solaris'
-        elif self._platform.startswith('mingw'):
-            self._platform = 'mingw'
-        elif self._platform.startswith('win'):
-            self._platform = 'msvc'
-        elif self._platform.startswith('bitrig'):
-            self._platform = 'bitrig'
-        elif self._platform.startswith('netbsd'):
-            self._platform = 'netbsd'
-        elif self._platform.startswith('aix'):
-            self._platform = 'aix'
-        elif self._platform.startswith('os400'):
-            self._platform = 'os400'
-        elif self._platform.startswith('dragonfly'):
-            self._platform = 'dragonfly'
-
-    @staticmethod
-    def known_platforms():
-      return ['linux', 'darwin', 'freebsd', 'openbsd', 'solaris', 'sunos5',
-              'mingw', 'msvc', 'gnukfreebsd', 'bitrig', 'netbsd', 'aix',
-              'dragonfly']
-
-    def platform(self):
-        return self._platform
-
-    def is_linux(self):
-        return self._platform == 'linux'
-
-    def is_mingw(self):
-        return self._platform == 'mingw'
-
-    def is_msvc(self):
-        return self._platform == 'msvc'
-
-    def msvc_needs_fs(self):
-        popen = subprocess.Popen(['cl', '/nologo', '/help'],
-                                 stdout=subprocess.PIPE,
-                                 stderr=subprocess.PIPE)
-        out, err = popen.communicate()
-        return b'/FS' in out
-
-    def is_windows(self):
-        return self.is_mingw() or self.is_msvc()
-
-    def is_solaris(self):
-        return self._platform == 'solaris'
-
-    def is_aix(self):
-        return self._platform == 'aix'
-
-    def is_os400_pase(self):
-        return self._platform == 'os400' or os.uname().sysname.startswith('OS400')
-
-    def uses_usr_local(self):
-        return self._platform in ('freebsd', 'openbsd', 'bitrig', 'dragonfly', 'netbsd')
-
-    def supports_ppoll(self):
-        return self._platform in ('freebsd', 'linux', 'openbsd', 'bitrig',
-                                  'dragonfly')
-    def supports_kqueue(self):
-        return self._platform in ('freebsd', 'openbsd', 'dragonfly', 'darwin')
-
-    def supports_ninja_browse(self):
-        return (not self.is_windows()
-                and not self.is_solaris()
-                and not self.is_aix())
-
-    def can_rebuild_in_place(self):
-        return not (self.is_windows() or self.is_aix())
-
-class Bootstrap:
-    """API shim for ninja_syntax.Writer that instead runs the commands.
-
-    Used to bootstrap Ninja from scratch.  In --bootstrap mode this
-    class is used to execute all the commands to build an executable.
-    It also proxies all calls to an underlying ninja_syntax.Writer, to
-    behave like non-bootstrap mode.
-    """
-    def __init__(self, writer, verbose=False):
-        self.writer = writer
-        self.verbose = verbose
-        # Map of variable name => expanded variable value.
-        self.vars = {}
-        # Map of rule name => dict of rule attributes.
-        self.rules = {
-            'phony': {}
-        }
-
-    def comment(self, text):
-        return self.writer.comment(text)
-
-    def newline(self):
-        return self.writer.newline()
-
-    def variable(self, key, val):
-        # In bootstrap mode, we have no ninja process to catch /showIncludes
-        # output.
-        self.vars[key] = self._expand(val).replace('/showIncludes', '')
-        return self.writer.variable(key, val)
-
-    def rule(self, name, **kwargs):
-        self.rules[name] = kwargs
-        return self.writer.rule(name, **kwargs)
-
-    def build(self, outputs, rule, inputs=None, **kwargs):
-        ruleattr = self.rules[rule]
-        cmd = ruleattr.get('command')
-        if cmd is None:  # A phony rule, for example.
-            return
-
-        # Implement just enough of Ninja variable expansion etc. to
-        # make the bootstrap build work.
-        local_vars = {
-            'in': self._expand_paths(inputs),
-            'out': self._expand_paths(outputs)
-        }
-        for key, val in kwargs.get('variables', []):
-            local_vars[key] = ' '.join(ninja_syntax.as_list(val))
-
-        self._run_command(self._expand(cmd, local_vars))
-
-        return self.writer.build(outputs, rule, inputs, **kwargs)
-
-    def default(self, paths):
-        return self.writer.default(paths)
-
-    def _expand_paths(self, paths):
-        """Expand $vars in an array of paths, e.g. from a 'build' block."""
-        paths = ninja_syntax.as_list(paths)
-        return ' '.join(map(self._shell_escape, (map(self._expand, paths))))
-
-    def _expand(self, str, local_vars={}):
-        """Expand $vars in a string."""
-        return ninja_syntax.expand(str, self.vars, local_vars)
-
-    def _shell_escape(self, path):
-        """Quote paths containing spaces."""
-        return '"%s"' % path if ' ' in path else path
-
-    def _run_command(self, cmdline):
-        """Run a subcommand, quietly.  Prints the full command on error."""
-        try:
-            if self.verbose:
-                print(cmdline)
-            subprocess.check_call(cmdline, shell=True)
-        except subprocess.CalledProcessError:
-            print('when running: ', cmdline)
-            raise
-
-
-parser = OptionParser()
-profilers = ['gmon', 'pprof']
-parser.add_option('--bootstrap', action='store_true',
-                  help='bootstrap a ninja binary from nothing')
-parser.add_option('--verbose', action='store_true',
-                  help='enable verbose build')
-parser.add_option('--platform',
-                  help='target platform (' +
-                       '/'.join(Platform.known_platforms()) + ')',
-                  choices=Platform.known_platforms())
-parser.add_option('--host',
-                  help='host platform (' +
-                       '/'.join(Platform.known_platforms()) + ')',
-                  choices=Platform.known_platforms())
-parser.add_option('--debug', action='store_true',
-                  help='enable debugging extras',)
-parser.add_option('--profile', metavar='TYPE',
-                  choices=profilers,
-                  help='enable profiling (' + '/'.join(profilers) + ')',)
-parser.add_option('--with-gtest', metavar='PATH', help='ignored')
-parser.add_option('--with-python', metavar='EXE',
-                  help='use EXE as the Python interpreter',
-                  default=os.path.basename(sys.executable))
-parser.add_option('--force-pselect', action='store_true',
-                  help='ppoll() is used by default where available, '
-                       'but some platforms may need to use pselect instead',)
-(options, args) = parser.parse_args()
-if args:
-    print('ERROR: extra unparsed command-line arguments:', args)
-    sys.exit(1)
-
-platform = Platform(options.platform)
-if options.host:
-    host = Platform(options.host)
-else:
-    host = platform
-
-BUILD_FILENAME = 'build.ninja'
-ninja_writer = ninja_syntax.Writer(open(BUILD_FILENAME, 'w'))
-n = ninja_writer
-
-if options.bootstrap:
-    # Make the build directory.
-    try:
-        os.mkdir('build')
-    except OSError:
-        pass
-    # Wrap ninja_writer with the Bootstrapper, which also executes the
-    # commands.
-    print('bootstrapping ninja...')
-    n = Bootstrap(n, verbose=options.verbose)
-
-n.comment('This file is used to build ninja itself.')
-n.comment('It is generated by ' + os.path.basename(__file__) + '.')
-n.newline()
-
-n.variable('ninja_required_version', '1.3')
-n.newline()
-
-n.comment('The arguments passed to configure.py, for rerunning it.')
-configure_args = sys.argv[1:]
-if '--bootstrap' in configure_args:
-    configure_args.remove('--bootstrap')
-n.variable('configure_args', ' '.join(configure_args))
-env_keys = set(['CXX', 'AR', 'CFLAGS', 'CXXFLAGS', 'LDFLAGS'])
-configure_env = dict((k, os.environ[k]) for k in os.environ if k in env_keys)
-if configure_env:
-    config_str = ' '.join([k + '=' + pipes.quote(configure_env[k])
-                           for k in configure_env])
-    n.variable('configure_env', config_str + '$ ')
-n.newline()
-
-CXX = configure_env.get('CXX', 'c++')
-objext = '.o'
-if platform.is_msvc():
-    CXX = 'cl'
-    objext = '.obj'
-
-def src(filename):
-    return os.path.join('$root', 'src', filename)
-def built(filename):
-    return os.path.join('$builddir', filename)
-def doc(filename):
-    return os.path.join('$root', 'doc', filename)
-def cc(name, **kwargs):
-    return n.build(built(name + objext), 'cxx', src(name + '.c'), **kwargs)
-def cxx(name, **kwargs):
-    return n.build(built(name + objext), 'cxx', src(name + '.cc'), **kwargs)
-def binary(name):
-    if platform.is_windows():
-        exe = name + '.exe'
-        n.build(name, 'phony', exe)
-        return exe
-    return name
-
-root = sourcedir
-if root == os.getcwd():
-    # In the common case where we're building directly in the source
-    # tree, simplify all the paths to just be cwd-relative.
-    root = '.'
-n.variable('root', root)
-n.variable('builddir', 'build')
-n.variable('cxx', CXX)
-if platform.is_msvc():
-    n.variable('ar', 'link')
-else:
-    n.variable('ar', configure_env.get('AR', 'ar'))
-
-def search_system_path(file_name):
-  """Find a file in the system path."""
-  for dir in os.environ['path'].split(';'):
-    path = os.path.join(dir, file_name)
-    if os.path.exists(path):
-      return path
-
-# Note that build settings are separately specified in CMakeLists.txt and
-# these lists should be kept in sync.
-if platform.is_msvc():
-    if not search_system_path('cl.exe'):
-        raise Exception('cl.exe not found. Run again from the Developer Command Prompt for VS')
-    cflags = ['/showIncludes',
-              '/nologo',  # Don't print startup banner.
-              '/Zi',  # Create pdb with debug info.
-              '/W4',  # Highest warning level.
-              '/WX',  # Warnings as errors.
-              '/wd4530', '/wd4100', '/wd4706', '/wd4244',
-              '/wd4512', '/wd4800', '/wd4702', '/wd4819',
-              # Disable warnings about constant conditional expressions.
-              '/wd4127',
-              # Disable warnings about passing "this" during initialization.
-              '/wd4355',
-              # Disable warnings about ignored typedef in DbgHelp.h
-              '/wd4091',
-              '/GR-',  # Disable RTTI.
-              '/Zc:__cplusplus',
-              # Disable size_t -> int truncation warning.
-              # We never have strings or arrays larger than 2**31.
-              '/wd4267',
-              '/DNOMINMAX', '/D_CRT_SECURE_NO_WARNINGS',
-              '/D_HAS_EXCEPTIONS=0',
-              '/DNINJA_PYTHON="%s"' % options.with_python]
-    if platform.msvc_needs_fs():
-        cflags.append('/FS')
-    ldflags = ['/DEBUG', '/libpath:$builddir']
-    if not options.debug:
-        cflags += ['/Ox', '/DNDEBUG', '/GL']
-        ldflags += ['/LTCG', '/OPT:REF', '/OPT:ICF']
-else:
-    cflags = ['-g', '-Wall', '-Wextra',
-              '-Wno-deprecated',
-              '-Wno-missing-field-initializers',
-              '-Wno-unused-parameter',
-              '-fno-rtti',
-              '-fno-exceptions',
-              '-std=c++11',
-              '-fvisibility=hidden', '-pipe',
-              '-DNINJA_PYTHON="%s"' % options.with_python]
-    if options.debug:
-        cflags += ['-D_GLIBCXX_DEBUG', '-D_GLIBCXX_DEBUG_PEDANTIC']
-        cflags.remove('-fno-rtti')  # Needed for above pedanticness.
-    else:
-        cflags += ['-O2', '-DNDEBUG']
-    try:
-        proc = subprocess.Popen(
-            [CXX, '-fdiagnostics-color', '-c', '-x', 'c++', '/dev/null',
-             '-o', '/dev/null'],
-            stdout=open(os.devnull, 'wb'), stderr=subprocess.STDOUT)
-        if proc.wait() == 0:
-            cflags += ['-fdiagnostics-color']
-    except:
-        pass
-    if platform.is_mingw():
-        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')
-        ldflags.append('-L/usr/local/lib')
-    if platform.is_aix():
-        # printf formats for int64_t, uint64_t; large file support
-        cflags.append('-D__STDC_FORMAT_MACROS')
-        cflags.append('-D_LARGE_FILES')
-
-
-libs = []
-
-if platform.is_mingw():
-    cflags.remove('-fvisibility=hidden');
-    ldflags.append('-static')
-elif platform.is_solaris():
-    cflags.remove('-fvisibility=hidden')
-elif platform.is_aix():
-    cflags.remove('-fvisibility=hidden')
-elif platform.is_msvc():
-    pass
-else:
-    if options.profile == 'gmon':
-        cflags.append('-pg')
-        ldflags.append('-pg')
-    elif options.profile == 'pprof':
-        cflags.append('-fno-omit-frame-pointer')
-        libs.extend(['-Wl,--no-as-needed', '-lprofiler'])
-
-if platform.supports_kqueue() and not options.force_pselect:
-    cflags.append('-DUSE_KQUEUE')
-elif platform.supports_ppoll() and not options.force_pselect:
-    cflags.append('-DUSE_PPOLL')
-if platform.supports_ninja_browse():
-    cflags.append('-DNINJA_HAVE_BROWSE')
-
-# Search for generated headers relative to build dir.
-cflags.append('-I.')
-
-def shell_escape(str):
-    """Escape str such that it's interpreted as a single argument by
-    the shell."""
-
-    # This isn't complete, but it's just enough to make NINJA_PYTHON work.
-    if platform.is_windows():
-      return str
-    if '"' in str:
-        return "'%s'" % str.replace("'", "\\'")
-    return str
-
-if 'CFLAGS' in configure_env:
-    cflags.append(configure_env['CFLAGS'])
-    ldflags.append(configure_env['CFLAGS'])
-if 'CXXFLAGS' in configure_env:
-    cflags.append(configure_env['CXXFLAGS'])
-    ldflags.append(configure_env['CXXFLAGS'])
-n.variable('cflags', ' '.join(shell_escape(flag) for flag in cflags))
-if 'LDFLAGS' in configure_env:
-    ldflags.append(configure_env['LDFLAGS'])
-n.variable('ldflags', ' '.join(shell_escape(flag) for flag in ldflags))
-n.newline()
-
-if platform.is_msvc():
-    n.rule('cxx',
-        command='$cxx $cflags -c $in /Fo$out /Fd' + built('$pdb'),
-        description='CXX $out',
-        deps='msvc'  # /showIncludes is included in $cflags.
-    )
-else:
-    n.rule('cxx',
-        command='$cxx -MMD -MT $out -MF $out.d $cflags -c $in -o $out',
-        depfile='$out.d',
-        deps='gcc',
-        description='CXX $out')
-n.newline()
-
-if host.is_msvc():
-    n.rule('ar',
-           command='lib /nologo /ltcg /out:$out $in',
-           description='LIB $out')
-elif host.is_mingw():
-    n.rule('ar',
-           command='$ar crs $out $in',
-           description='AR $out')
-else:
-    n.rule('ar',
-           command='rm -f $out && $ar crs $out $in',
-           description='AR $out')
-n.newline()
-
-if platform.is_msvc():
-    n.rule('link',
-        command='$cxx $in $libs /nologo /link $ldflags /out:$out',
-        description='LINK $out')
-else:
-    n.rule('link',
-        command='$cxx $ldflags -o $out $in $libs',
-        description='LINK $out')
-n.newline()
-
-objs = []
-
-if platform.supports_ninja_browse():
-    n.comment('browse_py.h is used to inline browse.py.')
-    n.rule('inline',
-           command='"%s"' % src('inline.sh') + ' $varname < $in > $out',
-           description='INLINE $out')
-    n.build(built('browse_py.h'), 'inline', src('browse.py'),
-            implicit=src('inline.sh'),
-            variables=[('varname', 'kBrowsePy')])
-    n.newline()
-
-    objs += cxx('browse', order_only=built('browse_py.h'))
-    n.newline()
-
-n.comment('the depfile parser and ninja lexers are generated using re2c.')
-def has_re2c():
-    try:
-        proc = subprocess.Popen(['re2c', '-V'], stdout=subprocess.PIPE)
-        return int(proc.communicate()[0], 10) >= 1503
-    except OSError:
-        return False
-if has_re2c():
-    n.rule('re2c',
-           command='re2c -b -i --no-generation-date --no-version -o $out $in',
-           description='RE2C $out')
-    # Generate the .cc files in the source directory so we can check them in.
-    n.build(src('depfile_parser.cc'), 're2c', src('depfile_parser.in.cc'))
-    n.build(src('lexer.cc'), 're2c', src('lexer.in.cc'))
-else:
-    print("warning: A compatible version of re2c (>= 0.15.3) was not found; "
-           "changes to src/*.in.cc will not affect your build.")
-n.newline()
-
-cxxvariables = []
-if platform.is_msvc():
-    cxxvariables = [('pdb', 'ninja.pdb')]
-
-n.comment('Generate a library for `ninja-re2c`.')
-re2c_objs = []
-for name in ['depfile_parser', 'lexer']:
-    re2c_objs += cxx(name, variables=cxxvariables)
-if platform.is_msvc():
-    n.build(built('ninja-re2c.lib'), 'ar', re2c_objs)
-else:
-    n.build(built('libninja-re2c.a'), 'ar', re2c_objs)
-n.newline()
-
-n.comment('Core source files all build into ninja library.')
-objs.extend(re2c_objs)
-for name in ['async_loop',
-             'build',
-             'build_config',
-             'build_log',
-             'clean',
-             'clparser',
-             'debug_flags',
-             'deps_log',
-             'disk_interface',
-             'dyndep',
-             'dyndep_parser',
-             'edit_distance',
-             'eval_env',
-             'graph',
-             'graphviz',
-             'ipc_utils',
-             'json',
-             'line_printer',
-             'manifest_parser',
-             'metrics',
-             'missing_deps',
-             'parser',
-             'persistent_mode',
-             'persistent_service',
-             'process_utils',
-             'state',
-             'status',
-             'stdio_redirection',
-             'string_piece_util',
-             'util',
-             'version']:
-    objs += cxx(name, variables=cxxvariables)
-if platform.is_windows():
-    for name in ['includes_normalize-win32',
-                 'interrupt_handling-win32',
-                 'ipc_handle-win32',
-                 'msvc_helper-win32',
-                 'msvc_helper_main-win32',
-                 'subprocess-win32']:
-        objs += cxx(name, variables=cxxvariables)
-    if platform.is_msvc():
-        objs += cxx('minidump-win32', variables=cxxvariables)
-    objs += cc('getopt')
-else:
-    for name in ['interrupt_handling-posix',
-                 'ipc_handle-posix',
-                 'subprocess-posix']:
-        objs += cxx(name, variables=cxxvariables)
-
-if platform.is_windows():
-    objs += cxx('stat_cache-win32', variables=cxxvariables)
-else:
-    objs += cxx('stat_cache-posix', variables=cxxvariables)
-
-if platform.is_aix():
-    objs += cc('getopt')
-if platform.is_msvc():
-    ninja_lib = n.build(built('ninja.lib'), 'ar', objs)
-else:
-    ninja_lib = n.build(built('libninja.a'), 'ar', objs)
-n.newline()
-
-if platform.is_msvc():
-    libs.append('ninja.lib')
-else:
-    libs.append('-lninja')
-
-if platform.is_aix() and not platform.is_os400_pase():
-    libs.append('-lperfstat')
-
-all_targets = []
-
-n.comment('Main executable is library plus main() function.')
-objs = cxx('ninja', variables=cxxvariables)
-ninja = n.build(binary('ninja'), 'link', objs, implicit=ninja_lib,
-                variables=[('libs', libs)])
-n.newline()
-all_targets += ninja
-
-if options.bootstrap:
-    # We've built the ninja binary.  Don't run any more commands
-    # through the bootstrap executor, but continue writing the
-    # build.ninja file.
-    n = ninja_writer
-
-n.comment('Tests all build into ninja_test executable.')
-
-objs = []
-if platform.is_msvc():
-    cxxvariables = [('pdb', 'ninja_test.pdb')]
-
-for name in ['async_loop_test',
-             'build_log_test',
-             'build_test',
-             'clean_test',
-             'clparser_test',
-             'depfile_parser_test',
-             'deps_log_test',
-             'dyndep_parser_test',
-             'disk_interface_test',
-             'edit_distance_test',
-             'graph_test',
-             'interrupt_handling_test',
-             'ipc_handle_test',
-             'ipc_utils_test',
-             'json_test',
-             'lexer_test',
-             'manifest_parser_test',
-             'missing_deps_test',
-             'ninja_test',
-             'persistent_mode_test',
-             'persistent_service_test',
-             'process_utils_test',
-             'stat_cache_test',
-             'state_test',
-             'status_test',
-             'stdio_redirection_test',
-             'string_piece_util_test',
-             'subprocess_test',
-             'test',
-             'util_test']:
-    objs += cxx(name, variables=cxxvariables)
-if platform.is_windows():
-    for name in ['includes_normalize_test', 'msvc_helper_test']:
-        objs += cxx(name, variables=cxxvariables)
-
-ninja_test = n.build(binary('ninja_test'), 'link', objs, implicit=ninja_lib,
-                     variables=[('libs', libs)])
-n.newline()
-all_targets += ninja_test
-
-
-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',
-             'hash_collision_bench',
-             'manifest_parser_perftest',
-             'persistent_mode_test_helper',
-             'persistent_service_test_helper',
-             'clparser_perftest']:
-  if platform.is_msvc():
-    cxxvariables = [('pdb', name + '.pdb')]
-  objs = cxx(name, variables=cxxvariables)
-  all_targets += n.build(binary(name), 'link', objs,
-                         implicit=ninja_lib, variables=[('libs', libs)])
-
-n.newline()
-
-n.comment('Generate a graph using the "graph" tool.')
-n.rule('gendot',
-       command='./ninja -t graph all > $out')
-n.rule('gengraph',
-       command='dot -Tpng $in > $out')
-dot = n.build(built('graph.dot'), 'gendot', ['ninja', 'build.ninja'])
-n.build('graph.png', 'gengraph', dot)
-n.newline()
-
-n.comment('Generate the manual using asciidoc.')
-n.rule('asciidoc',
-       command='asciidoc -b docbook -d book -o $out $in',
-       description='ASCIIDOC $out')
-n.rule('xsltproc',
-       command='xsltproc --nonet doc/docbook.xsl $in > $out',
-       description='XSLTPROC $out')
-docbookxml = n.build(built('manual.xml'), 'asciidoc', doc('manual.asciidoc'))
-manual = n.build(doc('manual.html'), 'xsltproc', docbookxml,
-                 implicit=[doc('style.css'), doc('docbook.xsl')])
-n.build('manual', 'phony',
-        order_only=manual)
-n.newline()
-
-n.rule('dblatex',
-       command='dblatex -q -o $out -p doc/dblatex.xsl $in',
-       description='DBLATEX $out')
-n.build(doc('manual.pdf'), 'dblatex', docbookxml,
-        implicit=[doc('dblatex.xsl')])
-
-n.comment('Generate Doxygen.')
-n.rule('doxygen',
-       command='doxygen $in',
-       description='DOXYGEN $in')
-n.variable('doxygen_mainpage_generator',
-           src('gen_doxygen_mainpage.sh'))
-n.rule('doxygen_mainpage',
-       command='$doxygen_mainpage_generator $in > $out',
-       description='DOXYGEN_MAINPAGE $out')
-mainpage = n.build(built('doxygen_mainpage'), 'doxygen_mainpage',
-                   ['README.md', 'COPYING'],
-                   implicit=['$doxygen_mainpage_generator'])
-n.build('doxygen', 'doxygen', doc('doxygen.config'),
-        implicit=mainpage)
-n.newline()
-
-if not host.is_mingw():
-    n.comment('Regenerate build files if build script changes.')
-    n.rule('configure',
-           command='${configure_env}%s $root/configure.py $configure_args' %
-               options.with_python,
-           generator=True)
-    n.build('build.ninja', 'configure',
-            implicit=['$root/configure.py',
-                      os.path.normpath('$root/misc/ninja_syntax.py')])
-    n.newline()
-
-n.default(ninja)
-n.newline()
-
-if host.is_linux():
-    n.comment('Packaging')
-    n.rule('rpmbuild',
-           command="misc/packaging/rpmbuild.sh",
-           description='Building rpms..')
-    n.build('rpm', 'rpmbuild')
-    n.newline()
-
-n.build('all', 'phony', all_targets)
-
-n.close()
-print('wrote %s.' % BUILD_FILENAME)
-
-if options.bootstrap:
-    print('bootstrap complete.  rebuilding...')
-
-    rebuild_args = []
-
-    if platform.can_rebuild_in_place():
-        rebuild_args.append('./ninja')
-    else:
-        if platform.is_windows():
-            bootstrap_exe = 'ninja.bootstrap.exe'
-            final_exe = 'ninja.exe'
-        else:
-            bootstrap_exe = './ninja.bootstrap'
-            final_exe = './ninja'
-
-        if os.path.exists(bootstrap_exe):
-            os.unlink(bootstrap_exe)
-        os.rename(final_exe, bootstrap_exe)
-
-        rebuild_args.append(bootstrap_exe)
-
-    if options.verbose:
-        rebuild_args.append('-v')
-
-    subprocess.check_call(rebuild_args)
diff --git a/doc/README.md b/doc/README.md
deleted file mode 100644
index 6afe5d4..0000000
--- a/doc/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-This directory contains the Ninja manual and support files used in
-building it.  Here's a brief overview of how it works.
-
-The source text, `manual.asciidoc`, is written in the AsciiDoc format.
-AsciiDoc can generate HTML but it doesn't look great; instead, we use
-AsciiDoc to generate the Docbook XML format and then provide our own
-Docbook XSL tweaks to produce HTML from that.
-
-In theory using AsciiDoc and DocBook allows us to produce nice PDF
-documentation etc.  In reality it's not clear anyone wants that, but the
-build rules are in place to generate it if you install dblatex.
diff --git a/doc/dblatex.xsl b/doc/dblatex.xsl
deleted file mode 100644
index c0da212..0000000
--- a/doc/dblatex.xsl
+++ /dev/null
@@ -1,7 +0,0 @@
-<!-- This custom XSL tweaks the dblatex XML settings. -->
-<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>
-  <!-- These parameters disable the list of collaborators and revisions.
-       Together remove a useless page from the front matter. -->
-  <xsl:param name='doc.collab.show'>0</xsl:param>
-  <xsl:param name='latex.output.revhistory'>0</xsl:param>
-</xsl:stylesheet>
diff --git a/doc/docbook.xsl b/doc/docbook.xsl
deleted file mode 100644
index 2235be2..0000000
--- a/doc/docbook.xsl
+++ /dev/null
@@ -1,34 +0,0 @@
-<!-- This custom XSL tweaks the DocBook XML -> HTML settings to produce
-     an OK-looking manual.  -->
-<!DOCTYPE xsl:stylesheet [
-<!ENTITY css SYSTEM "style.css">
-]>
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
-		version='1.0'>
-  <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
-
-  <!-- Embed our stylesheet as the user-provided <head> content. -->
-  <xsl:template name="user.head.content"><style>&css;</style></xsl:template>
-
-  <!-- Remove the body.attributes block, which specifies a bunch of
-       useless bgcolor etc. attrs on the <body> tag. -->
-  <xsl:template name="body.attributes"></xsl:template>
-
-  <!-- Specify that in "book" form (which we're using), we only want a
-       single table of contents at the beginning of the document. -->
-  <xsl:param name="generate.toc">book toc</xsl:param>
-
-  <!-- Don't put the "Chapter 1." prefix on the "chapters". -->
-  <xsl:param name="chapter.autolabel">0</xsl:param>
-
-  <!-- Make builds reproducible by generating the same IDs from the same inputs -->
-  <xsl:param name="generate.consistent.ids">1</xsl:param>
-
-  <!-- Use <ul> for the table of contents.  By default DocBook uses a
-       <dl>, which makes no semantic sense.  I imagine they just did
-       it because it looks nice? -->
-  <xsl:param name="toc.list.type">ul</xsl:param>
-
-  <xsl:output method="html" encoding="utf-8" indent="no"
-              doctype-public=""/>
-</xsl:stylesheet>
diff --git a/doc/doxygen.config b/doc/doxygen.config
deleted file mode 100644
index d933021..0000000
--- a/doc/doxygen.config
+++ /dev/null
@@ -1,1250 +0,0 @@
-# Doxyfile 1.4.5
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
-#
-# All text after a hash (#) is considered a comment and will be ignored
-# The format is:
-#       TAG = value [value, ...]
-# For lists items can also be appended using:
-#       TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
-
-PROJECT_NAME           = "Ninja"
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
-
-# PROJECT_NUMBER         = "0"
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
-
-OUTPUT_DIRECTORY       = "doc/doxygen/"
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
-
-CREATE_SUBDIRS         = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
-# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
-# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
-# Swedish, and Ukrainian.
-
-OUTPUT_LANGUAGE        = English
-
-# This tag can be used to specify the encoding used in the generated output.
-# The encoding is not always determined by the language that is chosen,
-# but also whether or not the output is meant for Windows or non-Windows users.
-# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
-# forces the Windows encoding (this is the default for the Windows binary),
-# whereas setting the tag to NO uses a Unix-style encoding (the default for
-# all platforms other than Windows).
-
-# Obsolet option.
-#USE_WINDOWS_ENCODING   = YES
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
-
-BRIEF_MEMBER_DESC      = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-
-REPEAT_BRIEF           = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
-
-ABBREVIATE_BRIEF       =
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
-# description.
-
-ALWAYS_DETAILED_SEC    = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-
-INLINE_INHERITED_MEMB  = YES
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
-
-FULL_PATH_NAMES        = YES
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
-
-STRIP_FROM_PATH        = src
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
-
-STRIP_FROM_INC_PATH    = src/
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful is your file systems
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
-SHORT_NAMES            = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like the Qt-style comments (thus requiring an
-# explicit @brief command for a brief description.
-
-JAVADOC_AUTOBRIEF      = YES
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the DETAILS_AT_TOP tag is set to YES then Doxygen
-# will output the detailed description near the top, like JavaDoc.
-# If set to NO, the detailed description appears after the member
-# documentation.
-
-# Has become obsolete.
-#DETAILS_AT_TOP         = NO
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
-
-INHERIT_DOCS           = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
-
-SEPARATE_MEMBER_PAGES  = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
-TAB_SIZE               = 2
-
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
-
-ALIASES                =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
-
-OPTIMIZE_OUTPUT_FOR_C  = NO
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for Java.
-# For instance, namespaces will be presented as packages, qualified scopes
-# will look different, etc.
-
-OPTIMIZE_OUTPUT_JAVA   = NO
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
-# include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-
-# BUILTIN_STL_SUPPORT    = NO
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC   = NO
-
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
-
-SUBGROUPING            = YES
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL            = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
-
-EXTRACT_PRIVATE        = YES
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
-
-EXTRACT_STATIC         = YES
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
-
-EXTRACT_LOCAL_CLASSES  = YES
-
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
-
-EXTRACT_LOCAL_METHODS  = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_MEMBERS     = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_CLASSES     = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
-
-HIDE_FRIEND_COMPOUNDS  = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
-
-HIDE_IN_BODY_DOCS      = NO
-
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
-
-INTERNAL_DOCS          = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-
-CASE_SENSE_NAMES       = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
-
-HIDE_SCOPE_NAMES       = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
-
-SHOW_INCLUDE_FILES     = YES
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
-
-INLINE_INFO            = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
-
-SORT_MEMBER_DOCS       = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
-
-SORT_BRIEF_DOCS        = YES
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
-
-SORT_BY_SCOPE_NAME     = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
-
-GENERATE_TODOLIST      = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
-
-GENERATE_TESTLIST      = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
-
-GENERATE_BUGLIST       = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-
-ENABLED_SECTIONS       =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or define consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and defines in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
-
-MAX_INITIALIZER_LINES  = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
-
-SHOW_USED_FILES        = YES
-
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is YES.
-
-SHOW_DIRECTORIES       = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from the
-# version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
-# is used as the file version. See the manual for examples.
-
-FILE_VERSION_FILTER    =
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
-QUIET                  = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
-
-WARNINGS               = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
-
-WARN_IF_UNDOCUMENTED   = YES
-
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
-
-WARN_IF_DOC_ERROR      = YES
-
-# This WARN_NO_PARAMDOC option can be abled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
-
-WARN_NO_PARAMDOC       = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
-
-WARN_FORMAT            = "$file:$line: $text "
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
-
-WARN_LOGFILE           =
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
-
-INPUT                  = src \
-                         build/doxygen_mainpage
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
-# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
-
-FILE_PATTERNS          = *.cc \
-                         *.h
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
-
-RECURSIVE              = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-
-EXCLUDE                =
-
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
-# directories that are symbolic links (a Unix filesystem feature) are excluded
-# from the input.
-
-EXCLUDE_SYMLINKS       = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
-
-EXCLUDE_PATTERNS       =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
-
-EXAMPLE_PATH           = src
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-
-EXAMPLE_PATTERNS       = *.cpp \
-                         *.cc \
-                         *.h \
-                         *.hh \
-                         INSTALL DEPENDENCIES CHANGELOG LICENSE LGPL
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
-
-EXAMPLE_RECURSIVE      = YES
-
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
-
-IMAGE_PATH             = src
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.  If FILTER_PATTERNS is specified, this tag will be
-# ignored.
-
-INPUT_FILTER           =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis.  Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match.  The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
-# is applied to all files.
-
-FILTER_PATTERNS        =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
-FILTER_SOURCE_FILES    = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
-
-SOURCE_BROWSER         = YES
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES         = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
-
-STRIP_CODE_COMMENTS    = NO
-
-# If the REFERENCED_BY_RELATION tag is set to YES (the default)
-# then for each documented function all documented
-# functions referencing it will be listed.
-
-REFERENCED_BY_RELATION = YES
-
-# If the REFERENCES_RELATION tag is set to YES (the default)
-# then for each documented function all documented entities
-# called/used by that function will be listed.
-
-REFERENCES_RELATION    = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
-
-USE_HTAGS              = NO
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
-
-VERBATIM_HEADERS       = YES
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
-
-ALPHABETICAL_INDEX     = YES
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-
-COLS_IN_ALPHA_INDEX    = 2
-
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
-
-IGNORE_PREFIX          =
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
-
-GENERATE_HTML          = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
-
-HTML_OUTPUT            = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
-
-HTML_FILE_EXTENSION    = .html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header.
-HTML_HEADER            =
-
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
-
-HTML_FOOTER            =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# stylesheet in the HTML output directory as well, or it will be erased!
-
-HTML_STYLESHEET        =
-
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
-# of the generated HTML documentation.
-
-GENERATE_HTMLHELP      = YES
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
-# written to the html output directory.
-
-CHM_FILE               =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
-
-HHC_LOCATION           =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
-
-GENERATE_CHI           = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
-
-BINARY_TOC             = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
-
-TOC_EXPAND             = NO
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
-
-DISABLE_INDEX          = NO
-
-# This tag can be used to set the number of enum values (range [1..20])
-# that doxygen will group on one line in the generated HTML documentation.
-
-ENUM_VALUES_PER_LINE   = 4
-
-# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
-# generated containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
-# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
-# probably better off using the HTML help feature.
-
-GENERATE_TREEVIEW      = YES
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
-
-TREEVIEW_WIDTH         = 250
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
-
-GENERATE_LATEX         = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
-
-LATEX_OUTPUT           = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-
-LATEX_CMD_NAME         =
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
-
-MAKEINDEX_CMD_NAME     =
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_LATEX          = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, a4wide, letter, legal and
-# executive. If left blank a4wide will be used.
-
-PAPER_TYPE             = a4
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
-
-EXTRA_PACKAGES         =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
-
-LATEX_HEADER           =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
-
-PDF_HYPERLINKS         = YES
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
-
-USE_PDFLATEX           = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
-
-LATEX_BATCHMODE        = YES
-
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
-
-LATEX_HIDE_INDICES     = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
-
-GENERATE_RTF           = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
-
-RTF_OUTPUT             = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_RTF            = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
-
-RTF_HYPERLINKS         = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
-
-RTF_STYLESHEET_FILE    =
-
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
-
-RTF_EXTENSIONS_FILE    =
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
-
-GENERATE_MAN           = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
-
-MAN_OUTPUT             = man
-
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
-
-MAN_EXTENSION          = .3
-
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
-
-MAN_LINKS              = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
-
-GENERATE_XML           = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
-
-XML_OUTPUT             = xml
-
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_SCHEMA             =
-
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_DTD                =
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
-
-XML_PROGRAMLISTING     = YES
-
-#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
-
-GENERATE_AUTOGEN_DEF   = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
-
-GENERATE_PERLMOD       = NO
-
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
-
-PERLMOD_LATEX          = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader.  This is useful
-# if you want to understand what is going on.  On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
-
-PERLMOD_PRETTY         = YES
-
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
-
-ENABLE_PREPROCESSING   = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
-MACRO_EXPANSION        = YES
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_DEFINED tags.
-
-EXPAND_ONLY_PREDEF     = YES
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
-
-SEARCH_INCLUDES        = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
-
-INCLUDE_PATH           =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
-
-INCLUDE_FILE_PATTERNS  =
-
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
-
-PREDEFINED             =
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
-
-EXPAND_AS_DEFINED      =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all function-like macros that are alone
-# on a line, have an all uppercase name, and do not end with a semicolon. Such
-# function macros are typically used for boiler-plate code, and will confuse
-# the parser if not removed.
-
-SKIP_FUNCTION_MACROS   = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
-#   TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-#   TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
-# is run, you must also specify the path to the tagfile here.
-
-TAGFILES               =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
-
-GENERATE_TAGFILE       = doc/doxygen/html/Ninja.TAGFILE
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
-
-ALLEXTERNALS           = YES
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
-
-EXTERNAL_GROUPS        = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
-
-PERL_PATH              = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option is superseded by the HAVE_DOT option below. This is only a
-# fallback. It is recommended to install and use dot, since it yields more
-# powerful graphs.
-
-CLASS_DIAGRAMS         = YES
-
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
-
-HIDE_UNDOC_RELATIONS   = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
-
-HAVE_DOT               = YES
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
-
-CLASS_GRAPH            = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
-
-COLLABORATION_GRAPH    = NO
-
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
-
-GROUP_GRAPHS           = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-
-UML_LOOK               = NO
-# UML_LOOK               = YES
-
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
-
-TEMPLATE_RELATIONS     = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
-
-INCLUDE_GRAPH          = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
-
-INCLUDED_BY_GRAPH      = YES
-
-# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
-# generate a call dependency graph for every global function or class method.
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
-
-CALL_GRAPH             = NO
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will graphical hierarchy of all classes instead of a textual one.
-
-GRAPHICAL_HIERARCHY    = YES
-
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
-
-DIRECTORY_GRAPH        = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are png, jpg, or gif
-# If left blank png will be used.
-
-DOT_IMAGE_FORMAT       = png
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-
-DOT_PATH               =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
-
-DOTFILE_DIRS           =
-
-# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than
-# this value, doxygen will try to truncate the graph, so that it fits within
-# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
-
-# Obsolet option.
-#MAX_DOT_GRAPH_WIDTH    = 1280
-
-# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than
-# this value, doxygen will try to truncate the graph, so that it fits within
-# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
-
-# Obsolet option.
-#MAX_DOT_GRAPH_HEIGHT   = 1024
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that a graph may be further truncated if the graph's
-# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
-# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
-# the graph is not depth-constrained.
-
-MAX_DOT_GRAPH_DEPTH    = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, which results in a white background.
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-
-DOT_TRANSPARENT        = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
-# JW
-# DOT_MULTI_TARGETS      = NO
-DOT_MULTI_TARGETS      = YES
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
-
-GENERATE_LEGEND        = YES
-
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
-
-DOT_CLEANUP            = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to the search engine
-#---------------------------------------------------------------------------
-
-# The SEARCHENGINE tag specifies whether or not a search engine should be
-# used. If set to NO the values of all tags below this one will be ignored.
-
-# JW SEARCHENGINE           = NO
-SEARCHENGINE           = YES
diff --git a/doc/manual.asciidoc b/doc/manual.asciidoc
deleted file mode 100644
index 45db7e2..0000000
--- a/doc/manual.asciidoc
+++ /dev/null
@@ -1,1346 +0,0 @@
-The Ninja build system
-======================
-
-
-Introduction
-------------
-
-Ninja is yet another build system.  It takes as input the
-interdependencies of files (typically source code and output
-executables) and orchestrates building them, _quickly_.
-
-Ninja joins a sea of other build systems.  Its distinguishing goal is
-to be fast.  It is born from
-http://neugierig.org/software/chromium/notes/2011/02/ninja.html[my
-work on the Chromium browser project], which has over 30,000 source
-files and whose other build systems (including one built from custom
-non-recursive Makefiles) would take ten seconds to start building
-after changing one file.  Ninja is under a second.
-
-Philosophical overview
-~~~~~~~~~~~~~~~~~~~~~~
-
-Where other build systems are high-level languages, Ninja aims to be
-an assembler.
-
-Build systems get slow when they need to make decisions.  When you are
-in an edit-compile cycle you want it to be as fast as possible -- you
-want the build system to do the minimum work necessary to figure out
-what needs to be built immediately.
-
-Ninja contains the barest functionality necessary to describe
-arbitrary dependency graphs.  Its lack of syntax makes it impossible
-to express complex decisions.
-
-Instead, Ninja is intended to be used with a separate program
-generating its input files.  The generator program (like the
-`./configure` found in autotools projects) can analyze system
-dependencies and make as many decisions as possible up front so that
-incremental builds stay fast.  Going beyond autotools, even build-time
-decisions like "which compiler flags should I use?"  or "should I
-build a debug or release-mode binary?"  belong in the `.ninja` file
-generator.
-
-Design goals
-~~~~~~~~~~~~
-
-Here are the design goals of Ninja:
-
-* very fast (i.e., instant) incremental builds, even for very large
-  projects.
-
-* very little policy about how code is built.  Different projects and
-  higher-level build systems have different opinions about how code
-  should be built; for example, should built objects live alongside
-  the sources or should all build output go into a separate directory?
-  Is there a "package" rule that builds a distributable package of
-  the project?  Sidestep these decisions by trying to allow either to
-  be implemented, rather than choosing, even if that results in
-  more verbosity.
-
-* get dependencies correct, and in particular situations that are
-  difficult to get right with Makefiles (e.g. outputs need an implicit
-  dependency on the command line used to generate them; to build C
-  source code you need to use gcc's `-M` flags for header
-  dependencies).
-
-* when convenience and speed are in conflict, prefer speed.
-
-Some explicit _non-goals_:
-
-* convenient syntax for writing build files by hand.  _You should
-  generate your ninja files using another program_.  This is how we
-  can sidestep many policy decisions.
-
-* built-in rules. _Out of the box, Ninja has no rules for
-  e.g. compiling C code._
-
-* build-time customization of the build. _Options belong in
-  the program that generates the ninja files_.
-
-* build-time decision-making ability such as conditionals or search
-  paths. _Making decisions is slow._
-
-To restate, Ninja is faster than other build systems because it is
-painfully simple.  You must tell Ninja exactly what to do when you
-create your project's `.ninja` files.
-
-Comparison to Make
-~~~~~~~~~~~~~~~~~~
-
-Ninja is closest in spirit and functionality to Make, relying on
-simple dependencies between file timestamps.
-
-But fundamentally, make has a lot of _features_: suffix rules,
-functions, built-in rules that e.g. search for RCS files when building
-source.  Make's language was designed to be written by humans.  Many
-projects find make alone adequate for their build problems.
-
-In contrast, Ninja has almost no features; just those necessary to get
-builds correct while punting most complexity to generation of the
-ninja input files.  Ninja by itself is unlikely to be useful for most
-projects.
-
-Here are some of the features Ninja adds to Make.  (These sorts of
-features can often be implemented using more complicated Makefiles,
-but they are not part of make itself.)
-
-* Ninja has special support for discovering extra dependencies at build
-  time, making it easy to get <<ref_headers,header dependencies>>
-  correct for C/C++ code.
-
-* A build edge may have multiple outputs.
-
-* Outputs implicitly depend on the command line that was used to generate
-  them, which means that changing e.g. compilation flags will cause
-  the outputs to rebuild.
-
-* Output directories are always implicitly created before running the
-  command that relies on them.
-
-* Rules can provide shorter descriptions of the command being run, so
-  you can print e.g. `CC foo.o` instead of a long command line while
-  building.
-
-* Builds are always run in parallel, based by default on the number of
-  CPUs your system has.  Underspecified build dependencies will result
-  in incorrect builds.
-
-* Command output is always buffered.  This means commands running in
-  parallel don't interleave their output, and when a command fails we
-  can print its failure output next to the full command line that
-  produced the failure.
-
-
-Using Ninja for your project
-----------------------------
-
-Ninja currently works on Unix-like systems and Windows. It's seen the
-most testing on Linux (and has the best performance there) but it runs
-fine on Mac OS X and FreeBSD.
-
-If your project is small, Ninja's speed impact is likely unnoticeable.
-(However, even for small projects it sometimes turns out that Ninja's
-limited syntax forces simpler build rules that result in faster
-builds.)  Another way to say this is that if you're happy with the
-edit-compile cycle time of your project already then Ninja won't help.
-
-There are many other build systems that are more user-friendly or
-featureful than Ninja itself.  For some recommendations: the Ninja
-author found http://gittup.org/tup/[the tup build system] influential
-in Ninja's design, and thinks https://github.com/apenwarr/redo[redo]'s
-design is quite clever.
-
-Ninja's benefit comes from using it in conjunction with a smarter
-meta-build system.
-
-https://gn.googlesource.com/gn/[gn]:: The meta-build system used to
-generate build files for Google Chrome and related projects (v8,
-node.js), as well as Google Fuchsia.  gn can generate Ninja files for
-all platforms supported by Chrome.
-
-https://cmake.org/[CMake]:: A widely used meta-build system that
-can generate Ninja files on Linux as of CMake version 2.8.8.  Newer versions
-of CMake support generating Ninja files on Windows and Mac OS X too.
-
-https://github.com/ninja-build/ninja/wiki/List-of-generators-producing-ninja-build-files[others]:: Ninja ought to fit perfectly into other meta-build software
-like https://premake.github.io/[premake].  If you do this work,
-please let us know!
-
-Running Ninja
-~~~~~~~~~~~~~
-
-Run `ninja`.  By default, it looks for a file named `build.ninja` in
-the current directory and builds all out-of-date targets.  You can
-specify which targets (files) to build as command line arguments.
-
-There is also a special syntax `target^` for specifying a target
-as the first output of some rule containing the source you put in
-the command line, if one exists. For example, if you specify target as
-`foo.c^` then `foo.o` will get built (assuming you have those targets
-in your build files).
-
-`ninja -h` prints help output.  Many of Ninja's flags intentionally
-match those of Make; e.g `ninja -C build -j 20` changes into the
-`build` directory and runs 20 build commands in parallel.  (Note that
-Ninja defaults to running commands in parallel anyway, so typically
-you don't need to pass `-j`.)
-
-
-Environment variables
-~~~~~~~~~~~~~~~~~~~~~
-
-Ninja supports a few environment variables to control its behavior:
-
-`NINJA_STATUS`, the progress status printed before the rule being run.
-
-Several placeholders are available:
-
-`%s`:: The number of started edges.
-`%t`:: The total number of edges that must be run to complete the build.
-`%p`:: The percentage of started edges.
-`%r`:: The number of currently running edges.
-`%u`:: The number of remaining edges to start.
-`%f`:: The number of finished edges.
-`%o`:: Overall rate of finished edges per second
-`%c`:: Current rate of finished edges per second (average over builds
-specified by `-j` or its default)
-`%e`:: Elapsed time in seconds.  _(Available since Ninja 1.2.)_
-`%%`:: A plain `%` character.
-
-The default progress status is `"[%f/%t] "` (note the trailing space
-to separate from the build rule). Another example of possible progress status
-could be `"[%u/%r/%f] "`.
-
-`NINJA_STATUS_MAX_COMMANDS` can be set to a decimal integer value.
-When it is  greater than 0, then Ninja will display, below the status line,
-a list of commands that are still running, with their elapsed times, sorted
-from oldest to newest. The value determines the maximum number of pending
-commands to display.For example, with a value of 4, it can look like:
-
-
----------------------------------
-[2617/70332] STAMP obj/zircon/system/...c_sdk_verify_api.generated_file.stamp
-  1.5s | RUST obj/third_party/rust_cr...ibdata_encoding-182ebdb900ce1527.rlib
-  1.4s | RUST obj/third_party/rust_crates/liblibc-49c4578e69d66647.rlib
-  1.3s | RUST obj/third_party/rust_crates/libnum_traits-eace97eec9f18ef0.rlib
-  1.1s | RUST obj/third_party/rust_cr...libregex_syntax-49dcde6b7db9cfdf.rlib
----------------------------------
-
-The commands list is refreshed every 100ms by default, but this period can be
-changed using `NINJA_STATUS_REFRESH_MILLIS`, whose value must be a period
-in milliseconds that is >= 100 (there is no point in using lower values
-since all elapsed times are printed up to a single decimal digit, so anything
-lower will be ignored).
-
-Note that:
-
-- Pending commands are never displayed when using `-n` (i.e. dry-run)
-  or `--verbose`, or on dumb terminals, so it should not affect scripts
-  parsing Ninja output.
-
-- The commands list is cleared automatically before Ninja prints
-  any command-specific output. This includes the output of edges with
-  `pool = console`.
-
-- Finally, the status line itself prints the same thing, i.e. the last
-  completed command only.
-
-`NINJA_PERSISTENT_MODE` can be set to `1` or `on` to use Ninja's persistent
-mode, where the first invocation for a given build directory will spawn a
-background server process that will load the build graph in memory, then
-answers multiple queries in succession. For very large build graphs, this
-allows Ninja to restart much faster.
-
-Note that this feature should be transparent to the user, except on Win32
-where it currently does not work(!).
-
-Each server process will shutdown gracefully after 5 minutes of idle time,
-or if any of the input `.ninja` file changed (to ensure correctness). The
-`server` tool can be used to interact with the server (see below).
-
-For debugging, it is possible to launch a server process in the foreground
-by setting `NINJA_PERSISTENT_MODE=server` in the environment. Server logs
-will then be printed directly to the current terminal stdout/stderr.
-
-By default, the server will shutdown gracefully after waiting for client
-connections for 5 minutes. This delay can be changed by setting the
-`NINJA_PERSISTENT_MODE_TIMEOUT_SECONDS` environment variable, which
-should receive a strictly positive timeout in seconds. For example,
-use 3600 for an hour.
-
-`NINJA_PERSISTENT_LOG_FILE` can be set to specify a file where the logs of
-new background server processes are written too, which can be useful for
-debugging.
-
-All environment variables from the client process are passed to the server
-on each incremental build, then used when spawning new commands. Note that
-this does not affect the server, so the `NINJA_PERSISTENT_XXX` variables
-only take effect when a server starts.
-
-Extra tools
-~~~~~~~~~~~
-
-The `-t` flag on the Ninja command line runs some tools that we have
-found useful during Ninja's development.  The current tools are:
-
-[horizontal]
-`query`:: dump the inputs and outputs of a given target.
-
-`browse`:: browse the dependency graph in a web browser.  Clicking a
-file focuses the view on that file, showing inputs and outputs.  This
-feature requires a Python installation. By default, port 8000 is used
-and a web browser will be opened. This can be changed as follows:
-+
-----
-ninja -t browse --port=8000 --no-browser mytarget
-----
-+
-`graph`:: output a file in the syntax used by `graphviz`, an automatic
-graph layout tool.  Use it like:
-+
-----
-ninja -t graph mytarget | dot -Tpng -ograph.png
-----
-+
-In the Ninja source tree, `ninja graph.png`
-generates an image for Ninja itself.  If no target is given generate a
-graph for all root targets.
-
-`targets`:: output a list of targets either by rule or by depth.  If used
-like +ninja -t targets rule _name_+ it prints the list of targets
-using the given rule to be built.  If no rule is given, it prints the source
-files (the leaves of the graph).  If used like
-+ninja -t targets depth _digit_+ it
-prints the list of targets in a depth-first manner starting by the root
-targets (the ones with no outputs). Indentation is used to mark dependencies.
-If the depth is zero it prints all targets. If no arguments are provided
-+ninja -t targets depth 1+ is assumed. In this mode targets may be listed
-several times. If used like this +ninja -t targets all+ it
-prints all the targets available without indentation and it is faster
-than the _depth_ mode.
-
-`commands`:: given a list of targets, print a list of commands which, if
-executed in order, may be used to rebuild those targets, assuming that all
-output files are out of date.
-
-`inputs`:: given a list of targets, print a list of all inputs used to
-rebuild those targets.
-_Available since Ninja 1.11._
-
-`clean`:: remove built files. By default, it removes all built files
-except for those created by the generator.  Adding the `-g` flag also
-removes built files created by the generator (see <<ref_rule,the rule
-reference for the +generator+ attribute>>).  Additional arguments are
-targets, which removes the given targets and recursively all files
-built for them.
-+
-If used like +ninja -t clean -r _rules_+ it removes all files built using
-the given rules.
-+
-Files created but not referenced in the graph are not removed. This
-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
-http://clang.llvm.org/docs/JSONCompilationDatabase.html[JSON format] expected
-by the Clang tooling interface.
-_Available since Ninja 1.2._
-
-`deps`:: show all dependencies stored in the `.ninja_deps` file. When given a
-target, show just the target's dependencies. _Available since Ninja 1.4._
-
-`missingdeps`:: given a list of targets, look for targets that depend on
-a generated file, but do not have a properly (possibly transitive) dependency
-on the generator.  Such targets may cause build flakiness on clean builds.
-+
-The broken targets can be found assuming deps log / depfile dependency
-information is correct.  Any target that depends on a generated file (output
-of a generator-target) implicitly, but does not have an explicit or order-only
-dependency path to the generator-target, is considered broken.
-+
-The tool's findings can be verified by trying to build the listed targets in
-a clean outdir without building any other targets.  The build should fail for
-each of them with a missing include error or equivalent pointing to the
-generated file.
-_Available since Ninja 1.11._
-
-`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. It can be used to know which rule name
-to pass to +ninja -t targets rule _name_+ or +ninja -t compdb+. Adding the `-d`
-flag also prints the description of the rules.
-
-`msvc`:: Available on Windows hosts only.
-Helper tool to invoke the `cl.exe` compiler with a pre-defined set of
-environment variables, as in:
-+
-----
-ninja -t msvc -e ENVFILE -- cl.exe <arguments>
-----
-+
-Where `ENVFILE` is a binary file that contains an environment block suitable
-for CreateProcessA() on Windows (i.e. a series of zero-terminated strings that
-look like NAME=VALUE, followed by an extra zero terminator). Note that this uses
-the local codepage encoding.
-
-This tool also supports a deprecated way of parsing the compiler's output when
-the `/showIncludes` flag is used, and generating a GCC-compatible depfile from it.
-+
----
-ninja -t msvc -o DEPFILE [-p STRING] -- cl.exe /showIncludes <arguments>
----
-+
-
-When using this option, `-p STRING` can be used to pass the localized line prefix
-that `cl.exe` uses to output dependency information. For English-speaking regions
-this is `"Note: including file: "` without the double quotes, but will be different
-for other regions.
-
-Note that Ninja supports this natively now, with the use of `deps = msvc` and
-`msvc_deps_prefix` in Ninja files. Native support also avoids launching an extra
-tool process each time the compiler must be called, which can speed up builds
-noticeably on Windows.
-
-`wincodepage`:: Available on Windows hosts (_since Ninja 1.11_).
-Prints the Windows code page whose encoding is expected in the build file.
-The output has the form:
-+
-----
-Build file encoding: <codepage>
-----
-+
-Additional lines may be added in future versions of Ninja.
-+
-The `<codepage>` is one of:
-
-`UTF-8`::: Encode as UTF-8.
-
-`ANSI`::: Encode to the system-wide ANSI code page.
-
-
-`server`:: interact with a persistent server instance if there is one. Use
-+ninja -t server status+ to retrieve the status of the server, and use
-+ninja -t server stop+  to stop any existing server instance.
-
-Writing your own Ninja files
-----------------------------
-
-The remainder of this manual is only useful if you are constructing
-Ninja files yourself: for example, if you're writing a meta-build
-system or supporting a new language.
-
-Conceptual overview
-~~~~~~~~~~~~~~~~~~~
-
-Ninja evaluates a graph of dependencies between files, and runs
-whichever commands are necessary to make your build target up to date
-as determined by file modification times.  If you are familiar with
-Make, Ninja is very similar.
-
-A build file (default name: `build.ninja`) provides a list of _rules_
--- short names for longer commands, like how to run the compiler --
-along with a list of _build_ statements saying how to build files
-using the rules -- which rule to apply to which inputs to produce
-which outputs.
-
-Conceptually, `build` statements describe the dependency graph of your
-project, while `rule` statements describe how to generate the files
-along a given edge of the graph.
-
-Syntax example
-~~~~~~~~~~~~~~
-
-Here's a basic `.ninja` file that demonstrates most of the syntax.
-It will be used as an example for the following sections.
-
----------------------------------
-cflags = -Wall
-
-rule cc
-  command = gcc $cflags -c $in -o $out
-
-build foo.o: cc foo.c
----------------------------------
-
-Variables
-~~~~~~~~~
-Despite the non-goal of being convenient to write by hand, to keep
-build files readable (debuggable), Ninja supports declaring shorter
-reusable names for strings.  A declaration like the following
-
-----------------
-cflags = -g
-----------------
-
-can be used on the right side of an equals sign, dereferencing it with
-a dollar sign, like this:
-
-----------------
-rule cc
-  command = gcc $cflags -c $in -o $out
-----------------
-
-Variables can also be referenced using curly braces like `${in}`.
-
-Variables might better be called "bindings", in that a given variable
-cannot be changed, only shadowed.  There is more on how shadowing works
-later in this document.
-
-Rules
-~~~~~
-
-Rules declare a short name for a command line.  They begin with a line
-consisting of the `rule` keyword and a name for the rule.  Then
-follows an indented set of `variable = value` lines.
-
-The basic example above declares a new rule named `cc`, along with the
-command to run.  In the context of a rule, the `command` variable
-defines the command to run, `$in` expands to the list of
-input files (`foo.c`), and `$out` to the output files (`foo.o`) for the
-command.  A full list of special variables is provided in
-<<ref_rule,the reference>>.
-
-Build statements
-~~~~~~~~~~~~~~~~
-
-Build statements declare a relationship between input and output
-files.  They begin with the `build` keyword, and have the format
-+build _outputs_: _rulename_ _inputs_+.  Such a declaration says that
-all of the output files are derived from the input files.  When the
-output files are missing or when the inputs change, Ninja will run the
-rule to regenerate the outputs.
-
-The basic example above describes how to build `foo.o`, using the `cc`
-rule.
-
-In the scope of a `build` block (including in the evaluation of its
-associated `rule`), the variable `$in` is the list of inputs and the
-variable `$out` is the list of outputs.
-
-A build statement may be followed by an indented set of `key = value`
-pairs, much like a rule.  These variables will shadow any variables
-when evaluating the variables in the command.  For example:
-
-----------------
-cflags = -Wall -Werror
-rule cc
-  command = gcc $cflags -c $in -o $out
-
-# If left unspecified, builds get the outer $cflags.
-build foo.o: cc foo.c
-
-# But you can shadow variables like cflags for a particular build.
-build special.o: cc special.c
-  cflags = -Wall
-
-# The variable was only shadowed for the scope of special.o;
-# Subsequent build lines get the outer (original) cflags.
-build bar.o: cc bar.c
-
-----------------
-
-For more discussion of how scoping works, consult <<ref_scope,the
-reference>>.
-
-If you need more complicated information passed from the build
-statement to the rule (for example, if the rule needs "the file
-extension of the first input"), pass that through as an extra
-variable, like how `cflags` is passed above.
-
-If the top-level Ninja file is specified as an output of any build
-statement and it is out of date, Ninja will rebuild and reload it
-before building the targets requested by the user.
-
-Generating Ninja files from code
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-`misc/ninja_syntax.py` in the Ninja distribution is a tiny Python
-module to facilitate generating Ninja files.  It allows you to make
-Python calls like `ninja.rule(name='foo', command='bar',
-depfile='$out.d')` and it will generate the appropriate syntax.  Feel
-free to just inline it into your project's build system if it's
-useful.
-
-
-More details
-------------
-
-The `phony` rule
-~~~~~~~~~~~~~~~~
-
-The special rule name `phony` can be used to create aliases for other
-targets.  For example:
-
-----------------
-build foo: phony some/file/in/a/faraway/subdir/foo
-----------------
-
-This makes `ninja foo` build the longer path.  Semantically, the
-`phony` rule is equivalent to a plain rule where the `command` does
-nothing, but phony rules are handled specially in that they aren't
-printed when run, logged (see below), nor do they contribute to the
-command count printed as part of the build process.
-
-When a `phony` target is used as an input to another build rule, the
-other build rule will, semantically, consider the inputs of the
-`phony` rule as its own. Therefore, `phony` rules can be used to group
-inputs, e.g. header files.
-
-`phony` can also be used to create dummy targets for files which
-may not exist at build time.  If a phony build statement is written
-without any dependencies, the target will be considered out of date if
-it does not exist.  Without a phony build statement, Ninja will report
-an error if the file does not exist and is required by the build.
-
-To create a rule that never rebuilds, use a build rule without any input:
-----------------
-rule touch
-  command = touch $out
-build file_that_always_exists.dummy: touch
-build dummy_target_to_follow_a_pattern: phony file_that_always_exists.dummy
-----------------
-
-
-Default target statements
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-By default, if no targets are specified on the command line, Ninja
-will build every output that is not named as an input elsewhere.
-You can override this behavior using a default target statement.
-A default target statement causes Ninja to build only a given subset
-of output files if none are specified on the command line.
-
-Default target statements begin with the `default` keyword, and have
-the format +default _targets_+.  A default target statement must appear
-after the build statement that declares the target as an output file.
-They are cumulative, so multiple statements may be used to extend
-the list of default targets.  For example:
-
-----------------
-default foo bar
-default baz
-----------------
-
-This causes Ninja to build the `foo`, `bar` and `baz` targets by
-default.
-
-
-[[ref_log]]
-The Ninja log
-~~~~~~~~~~~~~
-
-For each built file, Ninja keeps a log of the command used to build
-it.  Using this log Ninja can know when an existing output was built
-with a different command line than the build files specify (i.e., the
-command line changed) and knows to rebuild the file.
-
-The log file is kept in the build root in a file called `.ninja_log`.
-If you provide a variable named `builddir` in the outermost scope,
-`.ninja_log` will be kept in that directory instead.
-
-
-[[ref_versioning]]
-Version compatibility
-~~~~~~~~~~~~~~~~~~~~~
-
-_Available since Ninja 1.2._
-
-Ninja version labels follow the standard major.minor.patch format,
-where the major version is increased on backwards-incompatible
-syntax/behavioral changes and the minor version is increased on new
-behaviors.  Your `build.ninja` may declare a variable named
-`ninja_required_version` that asserts the minimum Ninja version
-required to use the generated file.  For example,
-
------
-ninja_required_version = 1.1
------
-
-declares that the build file relies on some feature that was
-introduced in Ninja 1.1 (perhaps the `pool` syntax), and that
-Ninja 1.1 or greater must be used to build.  Unlike other Ninja
-variables, this version requirement is checked immediately when
-the variable is encountered in parsing, so it's best to put it
-at the top of the build file.
-
-Ninja always warns if the major versions of Ninja and the
-`ninja_required_version` don't match; a major version change hasn't
-come up yet so it's difficult to predict what behavior might be
-required.
-
-[[ref_headers]]
-C/C++ header dependencies
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To get C/C++ header dependencies (or any other build dependency that
-works in a similar way) correct Ninja has some extra functionality.
-
-The problem with headers is that the full list of files that a given
-source file depends on can only be discovered by the compiler:
-different preprocessor defines and include paths cause different files
-to be used.  Some compilers can emit this information while building,
-and Ninja can use that to get its dependencies perfect.
-
-Consider: if the file has never been compiled, it must be built anyway,
-generating the header dependencies as a side effect.  If any file is
-later modified (even in a way that changes which headers it depends
-on) the modification will cause a rebuild as well, keeping the
-dependencies up to date.
-
-When loading these special dependencies, Ninja implicitly adds extra
-build edges such that it is not an error if the listed dependency is
-missing.  This allows you to delete a header file and rebuild without
-the build aborting due to a missing input.
-
-depfile
-^^^^^^^
-
-`gcc` (and other compilers like `clang`) support emitting dependency
-information in the syntax of a Makefile.  (Any command that can write
-dependencies in this form can be used, not just `gcc`.)
-
-To bring this information into Ninja requires cooperation.  On the
-Ninja side, the `depfile` attribute on the `build` must point to a
-path where this data is written.  (Ninja only supports the limited
-subset of the Makefile syntax emitted by compilers.)  Then the command
-must know to write dependencies into the `depfile` path.
-Use it like in the following example:
-
-----
-rule cc
-  depfile = $out.d
-  command = gcc -MD -MF $out.d [other gcc flags here]
-----
-
-The `-MD` flag to `gcc` tells it to output header dependencies, and
-the `-MF` flag tells it where to write them.
-
-deps
-^^^^
-
-_(Available since Ninja 1.3.)_
-
-It turns out that for large projects (and particularly on Windows,
-where the file system is slow) loading these dependency files on
-startup is slow.
-
-Ninja 1.3 can instead process dependencies just after they're generated
-and save a compacted form of the same information in a Ninja-internal
-database.
-
-Ninja supports this processing in two forms.
-
-1. `deps = gcc` specifies that the tool outputs `gcc`-style dependencies
-   in the form of Makefiles.  Adding this to the above example will
-   cause Ninja to process the `depfile` immediately after the
-   compilation finishes, then delete the `.d` file (which is only used
-   as a temporary).
-
-2. `deps = msvc` specifies that the tool outputs header dependencies
-   in the form produced by the Visual Studio compiler's
-   http://msdn.microsoft.com/en-us/library/hdkef6tk(v=vs.90).aspx[`/showIncludes`
-   flag].  Briefly, this means the tool outputs specially-formatted lines
-   to its stdout.  Ninja then filters these lines from the displayed
-   output.  No `depfile` attribute is necessary, but the localized string
-   in front of the header file path should be globally defined. For instance,
-   `msvc_deps_prefix = Note: including file:`
-   for an English Visual Studio (the default).
-+
-----
-msvc_deps_prefix = Note: including file:
-rule cc
-  deps = msvc
-  command = cl /showIncludes -c $in /Fo$out
-----
-
-If the include directory directives are using absolute paths, your depfile
-may result in a mixture of relative and absolute paths. Paths used by other
-build rules need to match exactly. Therefore, it is recommended to use
-relative paths in these cases.
-
-[[ref_pool]]
-Pools
-~~~~~
-
-_Available since Ninja 1.1._
-
-Pools allow you to allocate one or more rules or edges a finite number
-of concurrent jobs which is more tightly restricted than the default
-parallelism.
-
-This can be useful, for example, to restrict a particular expensive rule
-(like link steps for huge executables), or to restrict particular build
-statements which you know perform poorly when run concurrently.
-
-Each pool has a `depth` variable which is specified in the build file.
-The pool is then referred to with the `pool` variable on either a rule
-or a build statement.
-
-No matter what pools you specify, ninja will never run more concurrent jobs
-than the default parallelism, or the number of jobs specified on the command
-line (with `-j`).
-
-----------------
-# No more than 4 links at a time.
-pool link_pool
-  depth = 4
-
-# No more than 1 heavy object at a time.
-pool heavy_object_pool
-  depth = 1
-
-rule link
-  ...
-  pool = link_pool
-
-rule cc
-  ...
-
-# The link_pool is used here. Only 4 links will run concurrently.
-build foo.exe: link input.obj
-
-# A build statement can be exempted from its rule's pool by setting an
-# empty pool. This effectively puts the build statement back into the default
-# pool, which has infinite depth.
-build other.exe: link input.obj
-  pool =
-
-# A build statement can specify a pool directly.
-# Only one of these builds will run at a time.
-build heavy_object1.obj: cc heavy_obj1.cc
-  pool = heavy_object_pool
-build heavy_object2.obj: cc heavy_obj2.cc
-  pool = heavy_object_pool
-
-----------------
-
-The `console` pool
-^^^^^^^^^^^^^^^^^^
-
-_Available since Ninja 1.5._
-
-There exists a pre-defined pool named `console` with a depth of 1. It has
-the special property that any task in the pool has direct access to the
-standard input, output and error streams provided to Ninja, which are
-normally connected to the user's console (hence the name) but could be
-redirected. This can be useful for interactive tasks or long-running tasks
-which produce status updates on the console (such as test suites).
-
-While a task in the `console` pool is running, Ninja's regular output (such
-as progress status and output from concurrent tasks) is buffered until
-it completes.
-
-[[ref_ninja_file]]
-Ninja file reference
---------------------
-
-A file is a series of declarations.  A declaration can be one of:
-
-1. A rule declaration, which begins with +rule _rulename_+, and
-   then has a series of indented lines defining variables.
-
-2. A build edge, which looks like +build _output1_ _output2_:
-   _rulename_ _input1_ _input2_+. +
-   Implicit dependencies may be tacked on the end with +|
-   _dependency1_ _dependency2_+. +
-   Order-only dependencies may be tacked on the end with +||
-   _dependency1_ _dependency2_+.  (See <<ref_dependencies,the reference on
-   dependency types>>.)
-   Validations may be taked on the end with +|@ _validation1_ _validation2_+.
-   (See <<validations,the reference on validations>>.)
-+
-Implicit outputs _(available since Ninja 1.7)_ may be added before
-the `:` with +| _output1_ _output2_+ and do not appear in `$out`.
-(See <<ref_outputs,the reference on output types>>.)
-
-3. Variable declarations, which look like +_variable_ = _value_+.
-
-4. Default target statements, which look like +default _target1_ _target2_+.
-
-5. References to more files, which look like +subninja _path_+ or
-   +include _path_+.  The difference between these is explained below
-   <<ref_scope,in the discussion about scoping>>.
-
-6. A pool declaration, which looks like +pool _poolname_+. Pools are explained
-   <<ref_pool, in the section on pools>>.
-
-[[ref_lexer]]
-Lexical syntax
-~~~~~~~~~~~~~~
-
-Ninja is mostly encoding agnostic, as long as the bytes Ninja cares
-about (like slashes in paths) are ASCII.  This means e.g. UTF-8 or
-ISO-8859-1 input files ought to work.
-
-Comments begin with `#` and extend to the end of the line.
-
-Newlines are significant.  Statements like `build foo bar` are a set
-of space-separated tokens that end at the newline.  Newlines and
-spaces within a token must be escaped.
-
-There is only one escape character, `$`, and it has the following
-behaviors:
-
-`$` followed by a newline:: escape the newline (continue the current line
-across a line break).
-
-`$` followed by text:: a variable reference.
-
-`${varname}`:: alternate syntax for `$varname`.
-
-`$` followed by space:: a space.  (This is only necessary in lists of
-paths, where a space would otherwise separate filenames.  See below.)
-
-`$:` :: a colon.  (This is only necessary in `build` lines, where a colon
-would otherwise terminate the list of outputs.)
-
-`$$`:: a literal `$`.
-
-A `build` or `default` statement is first parsed as a space-separated
-list of filenames and then each name is expanded.  This means that
-spaces within a variable will result in spaces in the expanded
-filename.
-
-----
-spaced = foo bar
-build $spaced/baz other$ file: ...
-# The above build line has two outputs: "foo bar/baz" and "other file".
-----
-
-In a `name = value` statement, whitespace at the beginning of a value
-is always stripped.  Whitespace at the beginning of a line after a
-line continuation is also stripped.
-
-----
-two_words_with_one_space = foo $
-    bar
-one_word_with_no_space = foo$
-    bar
-----
-
-Other whitespace is only significant if it's at the beginning of a
-line.  If a line is indented more than the previous one, it's
-considered part of its parent's scope; if it is indented less than the
-previous one, it closes the previous scope.
-
-[[ref_toplevel]]
-Top-level variables
-~~~~~~~~~~~~~~~~~~~
-
-Two variables are significant when declared in the outermost file scope.
-
-`builddir`:: a directory for some Ninja output files.  See <<ref_log,the
-  discussion of the build log>>.  (You can also store other build output
-  in this directory.)
-
-`ninja_required_version`:: the minimum version of Ninja required to process
-  the build correctly.  See <<ref_versioning,the discussion of versioning>>.
-
-
-[[ref_rule]]
-Rule variables
-~~~~~~~~~~~~~~
-
-A `rule` block contains a list of `key = value` declarations that
-affect the processing of the rule.  Here is a full list of special
-keys.
-
-`command` (_required_):: the command line to run.  Each `rule` may
-  have only one `command` declaration. See <<ref_rule_command,the next
-  section>> for more details on quoting and executing multiple commands.
-
-`depfile`:: path to an optional `Makefile` that contains extra
-  _implicit dependencies_ (see <<ref_dependencies,the reference on
-  dependency types>>).  This is explicitly to support C/C++ header
-  dependencies; see <<ref_headers,the full discussion>>.
-
-`deps`:: _(Available since Ninja 1.3.)_ if present, must be one of
-  `gcc` or `msvc` to specify special dependency processing.  See
-   <<ref_headers,the full discussion>>.  The generated database is
-   stored as `.ninja_deps` in the `builddir`, see <<ref_toplevel,the
-   discussion of `builddir`>>.
-
-`msvc_deps_prefix`:: _(Available since Ninja 1.5.)_ defines the string
-  which should be stripped from msvc's /showIncludes output. Only
-  needed when `deps = msvc` and no English Visual Studio version is used.
-
-`description`:: a short description of the command, used to pretty-print
-  the command as it's running.  The `-v` flag controls whether to print
-  the full command or its description; if a command fails, the full command
-  line will always be printed before the command's output.
-
-`dyndep`:: _(Available since Ninja 1.10.)_ Used only on build statements.
-  If present, must name one of the build statement inputs.  Dynamically
-  discovered dependency information will be loaded from the file.
-  See the <<ref_dyndep,dynamic dependencies>> section for details.
-
-`generator`:: if present, specifies that this rule is used to
-  re-invoke the generator program.  Files built using `generator`
-  rules are treated specially in two ways: firstly, they will not be
-  rebuilt if the command line changes; and secondly, they are not
-  cleaned by default.
-
-`in`:: the space-separated list of files provided as inputs to the build line
-  referencing this `rule`, shell-quoted if it appears in commands.  (`$in` is
-  provided solely for convenience; if you need some subset or variant of this
-  list of files, just construct a new variable with that list and use
-  that instead.)
-
-`in_newline`:: the same as `$in` except that multiple inputs are
-  separated by newlines rather than spaces.  (For use with
-  `$rspfile_content`; this works around a bug in the MSVC linker where
-  it uses a fixed-size buffer for processing input.)
-
-`out`:: the space-separated list of files provided as outputs to the build line
-  referencing this `rule`, shell-quoted if it appears in commands.
-
-`restat`:: if present, causes Ninja to re-stat the command's outputs
-  after execution of the command.  Each output whose modification time
-  the command did not change will be treated as though it had never
-  needed to be built.  This may cause the output's reverse
-  dependencies to be removed from the list of pending build actions.
-
-`rspfile`, `rspfile_content`:: if present (both), Ninja will use a
-  response file for the given command, i.e. write the selected string
-  (`rspfile_content`) to the given file (`rspfile`) before calling the
-  command and delete the file after successful execution of the
-  command.
-+
-This is particularly useful on Windows OS, where the maximal length of
-a command line is limited and response files must be used instead.
-+
-Use it like in the following example:
-+
-----
-rule link
-  command = link.exe /OUT$out [usual link flags here] @$out.rsp
-  rspfile = $out.rsp
-  rspfile_content = $in
-
-build myapp.exe: link a.obj b.obj [possibly many other .obj files]
-----
-
-[[ref_rule_command]]
-Interpretation of the `command` variable
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Fundamentally, command lines behave differently on Unixes and Windows.
-
-On Unixes, commands are arrays of arguments.  The Ninja `command`
-variable is passed directly to `sh -c`, which is then responsible for
-interpreting that string into an argv array.  Therefore, the quoting
-rules are those of the shell, and you can use all the normal shell
-operators, like `&&` to chain multiple commands, or `VAR=value cmd` to
-set environment variables.
-
-On Windows, commands are strings, so Ninja passes the `command` string
-directly to `CreateProcess`.  (In the common case of simply executing
-a compiler this means there is less overhead.)  Consequently, the
-quoting rules are 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
-prefixing the command with `cmd /c`. Ninja may error with "invalid parameter"
-which usually indicates that the command line length has been exceeded.
-
-[[ref_outputs]]
-Build outputs
-~~~~~~~~~~~~~
-
-There are two types of build outputs which are subtly different.
-
-1. _Explicit outputs_, as listed in a build line.  These are
-   available as the `$out` variable in the rule.
-+
-This is the standard form of output to be used for e.g. the
-object file of a compile command.
-
-2. _Implicit outputs_, as listed in a build line with the syntax +|
-   _out1_ _out2_+ + before the `:` of a build line _(available since
-   Ninja 1.7)_.  The semantics are identical to explicit outputs,
-  the only difference is that implicit outputs don't show up in the
-  `$out` variable.
-+
-This is for expressing outputs that don't show up on the
-command line of the command.
-
-[[ref_dependencies]]
-Build dependencies
-~~~~~~~~~~~~~~~~~~
-
-There are three types of build dependencies which are subtly different.
-
-1. _Explicit dependencies_, as listed in a build line.  These are
-   available as the `$in` variable in the rule.  Changes in these files
-   cause the output to be rebuilt; if these 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
-source file of a compile command.
-
-2. _Implicit dependencies_, either as picked up from
-   a `depfile` attribute on a rule or from the syntax +| _dep1_
-   _dep2_+ on the end of a build line.  The semantics are identical to
-   explicit dependencies, the only difference is that implicit dependencies
-   don't show up in the `$in` variable.
-+
-This is for expressing dependencies that don't show up on the
-command line of the command; for example, for a rule that runs a
-script that reads a hardcoded file, the hardcoded file should 
-be an implicit dependency, as changes to the file should cause 
-the output to rebuild, even though it doesn't show up in the arguments.
-+
-Note that dependencies as loaded through depfiles have slightly different
-semantics, as described in the <<ref_rule,rule reference>>.
-
-3. _Order-only dependencies_, expressed with the syntax +|| _dep1_
-   _dep2_+ on the end of a build line.  When these are out of date, the
-   output is not rebuilt until they are built, but changes in order-only
-   dependencies alone do not cause the output to be rebuilt.
-+
-Order-only dependencies can be useful for bootstrapping dependencies
-that are only discovered during build time: for example, to generate a
-header file before starting a subsequent compilation step.  (Once the
-header is used in compilation, a generated dependency file will then
-express the implicit dependency.)
-
-File paths are compared as is, which means that an absolute path and a
-relative path, pointing to the same file, are considered different by Ninja.
-
-[[validations]]
-Validations
-~~~~~~~~~~~
-
-_Available since Ninja 1.11._
-
-Validations listed on the build line cause the specified files to be
-added to the top level of the build graph (as if they were specified
-on the Ninja command line) whenever the build line is a transitive
-dependency of one of the targets specified on the command line or a
-default target.
-
-Validations are added to the build graph regardless of whether the output
-files of the build statement are dirty are not, and the dirty state of
-the build statement that outputs the file being used as a validation
-has no effect on the dirty state of the build statement that requested it.
-
-A build edge can list another build edge as a validation even if the second
-edge depends on the first.
-
-Validations are designed to handle rules that perform error checking but
-don't produce any artifacts needed by the build, for example, static
-analysis tools.  Marking the static analysis rule as an implicit input
-of the main build rule of the source files or of the rules that depend
-on the main build rule would slow down the critical path of the build,
-but using a validation would allow the build to proceed in parallel with
-the static analysis rule once the main build rule is complete.
-
-Variable expansion
-~~~~~~~~~~~~~~~~~~
-
-Variables are expanded in paths (in a `build` or `default` statement)
-and on the right side of a `name = value` statement.
-
-When a `name = value` statement is evaluated, its right-hand side is
-expanded immediately (according to the below scoping rules), and
-from then on `$name` expands to the static string as the result of the
-expansion.  It is never the case that you'll need to "double-escape" a
-value to prevent it from getting expanded twice.
-
-All variables are expanded immediately as they're encountered in parsing,
-with one important exception: variables in `rule` blocks are expanded
-when the rule is _used_, not when it is declared.  In the following
-example, the `demo` rule prints "this is a demo of bar".
-
-----
-rule demo
-  command = echo "this is a demo of $foo"
-
-build out: demo
-  foo = bar
-----
-
-[[ref_scope]]
-Evaluation and scoping
-~~~~~~~~~~~~~~~~~~~~~~
-
-Top-level variable declarations are scoped to the file they occur in.
-
-Rule declarations are also scoped to the file they occur in.
-_(Available since Ninja 1.6)_
-
-The `subninja` keyword, used to include another `.ninja` file,
-introduces a new scope.  The included `subninja` file may use the
-variables and rules from the parent file, and shadow their values for the file's
-scope, but it won't affect values of the variables in the parent.
-
-To include another `.ninja` file in the current scope, much like a C
-`#include` statement, use `include` instead of `subninja`.
-
-Variable declarations indented in a `build` block are scoped to the
-`build` block.  The full lookup order for a variable expanded in a
-`build` block (or the `rule` is uses) is:
-
-1. Special built-in variables (`$in`, `$out`).
-
-2. Build-level variables from the `build` block.
-
-3. Rule-level variables from the `rule` block (i.e. `$command`).
-   (Note from the above discussion on expansion that these are
-   expanded "late", and may make use of in-scope bindings like `$in`.)
-
-4. File-level variables from the file that the `build` line was in.
-
-5. Variables from the file that included that file using the
-   `subninja` keyword.
-
-[[ref_dyndep]]
-Dynamic Dependencies
---------------------
-
-_Available since Ninja 1.10._
-
-Some use cases require implicit dependency information to be dynamically
-discovered from source file content _during the build_ in order to build
-correctly on the first run (e.g. Fortran module dependencies).  This is
-unlike <<ref_headers,header dependencies>> which are only needed on the
-second run and later to rebuild correctly.  A build statement may have a
-`dyndep` binding naming one of its inputs to specify that dynamic
-dependency information must be loaded from the file.  For example:
-
-----
-build out: ... || foo
-  dyndep = foo
-build foo: ...
-----
-
-This specifies that file `foo` is a dyndep file.  Since it is an input,
-the build statement for `out` can never be executed before `foo` is built.
-As soon as `foo` is finished Ninja will read it to load dynamically
-discovered dependency information for `out`.  This may include additional
-implicit inputs and/or outputs.  Ninja will update the build graph
-accordingly and the build will proceed as if the information was known
-originally.
-
-Dyndep file reference
-~~~~~~~~~~~~~~~~~~~~~
-
-Files specified by `dyndep` bindings use the same <<ref_lexer,lexical syntax>>
-as <<ref_ninja_file,ninja build files>> and have the following layout.
-
-1. A version number in the form `<major>[.<minor>][<suffix>]`:
-+
-----
-ninja_dyndep_version = 1
-----
-+
-Currently the version number must always be `1` or `1.0` but may have
-an arbitrary suffix.
-
-2. One or more build statements of the form:
-+
-----
-build out | imp-outs... : dyndep | imp-ins...
-----
-+
-Every statement must specify exactly one explicit output and must use
-the rule name `dyndep`.  The `| imp-outs...` and `| imp-ins...` portions
-are optional.
-
-3. An optional `restat` <<ref_rule,variable binding>> on each build statement.
-
-The build statements in a dyndep file must have a one-to-one correspondence
-to build statements in the <<ref_ninja_file,ninja build file>> that name the
-dyndep file in a `dyndep` binding.  No dyndep build statement may be omitted
-and no extra build statements may be specified.
-
-Dyndep Examples
-~~~~~~~~~~~~~~~
-
-Fortran Modules
-^^^^^^^^^^^^^^^
-
-Consider a Fortran source file `foo.f90` that provides a module
-`foo.mod` (an implicit output of compilation) and another source file
-`bar.f90` that uses the module (an implicit input of compilation).  This
-implicit dependency must be discovered before we compile either source
-in order to ensure that `bar.f90` never compiles before `foo.f90`, and
-that `bar.f90` recompiles when `foo.mod` changes.  We can achieve this
-as follows:
-
-----
-rule f95
-  command = f95 -o $out -c $in
-rule fscan
-  command = fscan -o $out $in
-
-build foobar.dd: fscan foo.f90 bar.f90
-
-build foo.o: f95 foo.f90 || foobar.dd
-  dyndep = foobar.dd
-build bar.o: f95 bar.f90 || foobar.dd
-  dyndep = foobar.dd
-----
-
-In this example the order-only dependencies ensure that `foobar.dd` is
-generated before either source compiles.  The hypothetical `fscan` tool
-scans the source files, assumes each will be compiled to a `.o` of the
-same name, and writes `foobar.dd` with content such as:
-
-----
-ninja_dyndep_version = 1
-build foo.o | foo.mod: dyndep
-build bar.o: dyndep |  foo.mod
-----
-
-Ninja will load this file to add `foo.mod` as an implicit output of
-`foo.o` and implicit input of `bar.o`.  This ensures that the Fortran
-sources are always compiled in the proper order and recompiled when
-needed.
-
-Tarball Extraction
-^^^^^^^^^^^^^^^^^^
-
-Consider a tarball `foo.tar` that we want to extract.  The extraction time
-can be recorded with a `foo.tar.stamp` file so that extraction repeats if
-the tarball changes, but we also would like to re-extract if any of the
-outputs is missing.  However, the list of outputs depends on the content
-of the tarball and cannot be spelled out explicitly in the ninja build file.
-We can achieve this as follows:
-
-----
-rule untar
-  command = tar xf $in && touch $out
-rule scantar
-  command = scantar --stamp=$stamp --dd=$out $in
-build foo.tar.dd: scantar foo.tar
-  stamp = foo.tar.stamp
-build foo.tar.stamp: untar foo.tar || foo.tar.dd
-  dyndep = foo.tar.dd
-----
-
-In this example the order-only dependency ensures that `foo.tar.dd` is
-built before the tarball extracts.  The hypothetical `scantar` tool
-will read the tarball (e.g. via `tar tf`) and write `foo.tar.dd` with
-content such as:
-
-----
-ninja_dyndep_version = 1
-build foo.tar.stamp | file1.txt file2.txt : dyndep
-  restat = 1
-----
-
-Ninja will load this file to add `file1.txt` and `file2.txt` as implicit
-outputs of `foo.tar.stamp`, and to mark the build statement for `restat`.
-On future builds, if any implicit output is missing the tarball will be
-extracted again.  The `restat` binding tells Ninja to tolerate the fact
-that the implicit outputs may not have modification times newer than
-the tarball itself (avoiding re-extraction on every build).
diff --git a/doc/style.css b/doc/style.css
deleted file mode 100644
index 9976c03..0000000
--- a/doc/style.css
+++ /dev/null
@@ -1,29 +0,0 @@
-body {
-    margin: 5ex 10ex;
-    max-width: 80ex;
-    line-height: 1.5;
-    font-family: sans-serif;
-}
-h1, h2, h3 {
-    font-weight: normal;
-}
-pre, code {
-    font-family: x, monospace;
-}
-pre {
-    padding: 1ex;
-    background: #eee;
-    border: solid 1px #ddd;
-    min-width: 0;
-    font-size: 90%;
-}
-code {
-    color: #007;
-}
-div.chapter {
-    margin-top: 4em;
-    border-top: solid 2px black;
-}
-p {
-    margin-top: 0;
-}
diff --git a/misc/afl-fuzz-tokens/kw_build b/misc/afl-fuzz-tokens/kw_build
deleted file mode 100644
index c795b05..0000000
--- a/misc/afl-fuzz-tokens/kw_build
+++ /dev/null
@@ -1 +0,0 @@
-build
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/kw_default b/misc/afl-fuzz-tokens/kw_default
deleted file mode 100644
index 331d858..0000000
--- a/misc/afl-fuzz-tokens/kw_default
+++ /dev/null
@@ -1 +0,0 @@
-default
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/kw_include b/misc/afl-fuzz-tokens/kw_include
deleted file mode 100644
index 2996fba..0000000
--- a/misc/afl-fuzz-tokens/kw_include
+++ /dev/null
@@ -1 +0,0 @@
-include
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/kw_pool b/misc/afl-fuzz-tokens/kw_pool
deleted file mode 100644
index e783591..0000000
--- a/misc/afl-fuzz-tokens/kw_pool
+++ /dev/null
@@ -1 +0,0 @@
-pool
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/kw_rule b/misc/afl-fuzz-tokens/kw_rule
deleted file mode 100644
index 841e840..0000000
--- a/misc/afl-fuzz-tokens/kw_rule
+++ /dev/null
@@ -1 +0,0 @@
-rule
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/kw_subninja b/misc/afl-fuzz-tokens/kw_subninja
deleted file mode 100644
index c4fe0c7..0000000
--- a/misc/afl-fuzz-tokens/kw_subninja
+++ /dev/null
@@ -1 +0,0 @@
-subninja
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/misc_a b/misc/afl-fuzz-tokens/misc_a
deleted file mode 100644
index 2e65efe..0000000
--- a/misc/afl-fuzz-tokens/misc_a
+++ /dev/null
@@ -1 +0,0 @@
-a
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/misc_b b/misc/afl-fuzz-tokens/misc_b
deleted file mode 100644
index 63d8dbd..0000000
--- a/misc/afl-fuzz-tokens/misc_b
+++ /dev/null
@@ -1 +0,0 @@
-b
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/misc_colon b/misc/afl-fuzz-tokens/misc_colon
deleted file mode 100644
index 22ded55..0000000
--- a/misc/afl-fuzz-tokens/misc_colon
+++ /dev/null
@@ -1 +0,0 @@
-:
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/misc_cont b/misc/afl-fuzz-tokens/misc_cont
deleted file mode 100644
index 857f13a..0000000
--- a/misc/afl-fuzz-tokens/misc_cont
+++ /dev/null
@@ -1 +0,0 @@
-$
diff --git a/misc/afl-fuzz-tokens/misc_dollar b/misc/afl-fuzz-tokens/misc_dollar
deleted file mode 100644
index 6f4f765..0000000
--- a/misc/afl-fuzz-tokens/misc_dollar
+++ /dev/null
@@ -1 +0,0 @@
-$
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/misc_eq b/misc/afl-fuzz-tokens/misc_eq
deleted file mode 100644
index 851c75c..0000000
--- a/misc/afl-fuzz-tokens/misc_eq
+++ /dev/null
@@ -1 +0,0 @@
-=
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/misc_indent b/misc/afl-fuzz-tokens/misc_indent
deleted file mode 100644
index 136d063..0000000
--- a/misc/afl-fuzz-tokens/misc_indent
+++ /dev/null
@@ -1 +0,0 @@
-  
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/misc_pipe b/misc/afl-fuzz-tokens/misc_pipe
deleted file mode 100644
index a3871d4..0000000
--- a/misc/afl-fuzz-tokens/misc_pipe
+++ /dev/null
@@ -1 +0,0 @@
-|
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/misc_pipepipe b/misc/afl-fuzz-tokens/misc_pipepipe
deleted file mode 100644
index 27cc728..0000000
--- a/misc/afl-fuzz-tokens/misc_pipepipe
+++ /dev/null
@@ -1 +0,0 @@
-||
\ No newline at end of file
diff --git a/misc/afl-fuzz-tokens/misc_space b/misc/afl-fuzz-tokens/misc_space
deleted file mode 100644
index 0519ecb..0000000
--- a/misc/afl-fuzz-tokens/misc_space
+++ /dev/null
@@ -1 +0,0 @@
- 
\ No newline at end of file
diff --git a/misc/afl-fuzz/build.ninja b/misc/afl-fuzz/build.ninja
deleted file mode 100644
index 52cd2f1..0000000
--- a/misc/afl-fuzz/build.ninja
+++ /dev/null
@@ -1,5 +0,0 @@
-rule b
-  command = clang -MMD -MF $out.d -o $out -c $in
-  description = building $out
-
-build a.o: b a.c
diff --git a/misc/bash-completion b/misc/bash-completion
deleted file mode 100644
index e604cd4..0000000
--- a/misc/bash-completion
+++ /dev/null
@@ -1,57 +0,0 @@
-# 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.
-
-# Add the following to your .bashrc to tab-complete ninja targets
-#   . path/to/ninja/misc/bash-completion
-
-_ninja_target() {
-    local cur prev targets dir line targets_command OPTIND
-
-    # When available, use bash_completion to:
-    #   1) Complete words when the cursor is in the middle of the word
-    #   2) Complete paths with files or directories, as appropriate
-    if _get_comp_words_by_ref cur prev &>/dev/null ; then
-        case $prev in
-            -f)
-                _filedir
-                return 0
-                ;;
-            -C)
-                _filedir -d
-                return 0
-                ;;
-        esac
-    else
-        cur="${COMP_WORDS[COMP_CWORD]}"
-    fi
-
-    if [[ "$cur" == "--"* ]]; then
-        # there is currently only one argument that takes --
-	COMPREPLY=($(compgen -P '--' -W 'version' -- "${cur:2}"))
-    else
-	dir="."
-	line=$(echo ${COMP_LINE} | cut -d" " -f 2-)
-        # filter out all non relevant arguments but keep C for dirs
-	while getopts :C:f:j:l:k:nvd:t: opt $line; do
-	    case $opt in
-                # eval for tilde expansion
-		C) eval dir="$OPTARG" ;;
-	    esac
-	done;
-	targets_command="eval ninja -C \"${dir}\" -t targets all 2>/dev/null | cut -d: -f1"
-	COMPREPLY=($(compgen -W '`${targets_command}`' -- "$cur"))
-    fi
-    return
-}
-complete -F _ninja_target ninja
diff --git a/misc/ci.py b/misc/ci.py
deleted file mode 100755
index 17cbf14..0000000
--- a/misc/ci.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python3
-
-import os
-
-ignores = [
-	'.git/',
-	'misc/afl-fuzz-tokens/',
-	'ninja_deps',
-	'src/depfile_parser.cc',
-	'src/lexer.cc',
-]
-
-error_count = 0
-
-def error(path, msg):
-	global error_count
-	error_count += 1
-	print('\x1b[1;31m{}\x1b[0;31m{}\x1b[0m'.format(path, msg))
-
-for root, directory, filenames in os.walk('.'):
-	for filename in filenames:
-		path = os.path.join(root, filename)[2:]
-		if any([path.startswith(x) for x in ignores]):
-			continue
-		with open(path, 'rb') as file:
-			line_nr = 1
-			try:
-				for line in [x.decode() for x in file.readlines()]:
-					if len(line) == 0 or line[-1] != '\n':
-						error(path, ' missing newline at end of file.')
-					if len(line) > 1:
-						if line[-2] == '\r':
-							error(path, ' has Windows line endings.')
-							break
-						if line[-2] == ' ' or line[-2] == '\t':
-							error(path, ':{} has trailing whitespace.'.format(line_nr))
-					line_nr += 1
-			except UnicodeError:
-				pass # binary file
-
-exit(error_count)
diff --git a/misc/fuchsia/build-ninja.sh b/misc/fuchsia/build-ninja.sh
deleted file mode 100755
index 0f5488d..0000000
--- a/misc/fuchsia/build-ninja.sh
+++ /dev/null
@@ -1,619 +0,0 @@
-#!/bin/bash
-# Copyright 2023 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.
-
-set -e
-
-SCRIPT_DIR="$(dirname "$0")"
-
-die () {
-  echo >&2 "ERROR: $*"
-  exit 1
-}
-
-_VERBOSE=
-
-run () {
-  if [[ -n "${_VERBOSE}" ]]; then
-    echo "@COMMAND: $*"
-  fi
-  "$@"
-}
-
-# Determine Fuchsia host_tag for prebuilt binaries.
-UNAME_OS="$(uname -s)"
-UNAME_ARCH="$(uname -m)"
-
-case "${UNAME_OS}" in
-  Linux)
-    HOST_OS=linux
-    ;;
-  Darwin)
-    HOST_OS=mac
-    ;;
-  *)
-    die "Unknown host operation system: ${UNAME_OS}"
-    ;;
-esac
-
-case "${UNAME_ARCH}" in
-  amd64|x86_64)
-    HOST_ARCH=x64
-    ;;
-  arm64|aarch64)
-    HOST_ARCH=arm64
-    ;;
-  *)
-    die "Unknown host CPU architecture: ${UNAME_ARCH}"
-    ;;
-esac
-
-DEFAULT_JEMALLOC_GIT_URL=https://fuchsia.googlesource.com/third_party/github.com/jemalloc/jemalloc.git
-DEFAULT_JEMALLOC_TAG=5.3.0
-
-HOST_TAG="${HOST_OS}-${HOST_ARCH}"
-
-ALLOCATOR=
-ALLOCATOR_LINK_ONLY=
-BUILD_DIR=
-CLANG_BINPREFIX=
-CMAKE=cmake
-DEBUG=
-HELP=
-INCREMENTAL=
-INSTALL_PATH=
-LTO=
-NINJA=
-NO_LTO=
-NO_CLANG=
-NO_TESTS=
-STATIC=
-SYSROOT=
-TARGET_FLAGS=
-USE_LIBCXX=
-USE_MINGW64=
-USE_WINE=
-WINDOWS_SSH=${NINJA_WINDOWS_SSH:-}
-for OPT; do
-  case "${OPT}" in
-    --help)
-      HELP=true
-      ;;
-    --cmake=*)
-      CMAKE="${OPT#--cmake=}"
-      ;;
-    --debug)
-      DEBUG=true
-      ;;
-    --static)
-      STATIC=true
-      ;;
-    -v|--verbose)
-      _VERBOSE=1
-      ;;
-    -i|--incremental)
-      INCREMENTAL=true
-      ;;
-    --no-clang)
-      NO_CLANG=true
-      ;;
-    --build-dir=*)
-      BUILD_DIR="${OPT#--build-dir=}"
-      ;;
-    --clang-binprefix=*)
-      CLANG_BINPREFIX="${OPT#--clang-binprefix=}"
-      ;;
-    --sysroot=*)
-      SYSROOT="${OPT#--sysroot=}"
-      ;;
-    --fuchsia-dir=*)
-      FUCHSIA_DIR="${OPT#--fuchsia-dir=}"
-      CLANG_BINPREFIX="${FUCHSIA_DIR}/prebuilt/third_party/clang/${HOST_TAG}/bin"
-      if [[ "${HOST_OS}" == "linux" ]]; then
-        SYSROOT="${FUCHSIA_DIR}/prebuilt/third_party/sysroot/linux"
-      fi
-      if [[ "${HOST_OS}" == "mac" ]]; then
-        # NOTE: Required to link binaries properly, otherwise on MacOS
-        # the prebuilt toolchain will try to link the system libc++.a
-        # which is incompatible with the libc++ headers that come with
-        # the prebuilt toolchain.
-        USE_LIBCXX=true
-      fi
-      NINJA="${FUCHSIA_DIR}/prebuilt/third_party/ninja/${HOST_TAG}/ninja"
-      CMAKE="${FUCHSIA_DIR}/prebuilt/third_party/cmake/${HOST_TAG}/bin/cmake"
-      ;;
-    --target=*)
-      TARGET_FLAGS="${OPT}"
-      ;;
-    --ninja=*)
-      NINJA="${OPT##--ninja=}"
-      ;;
-    --no-tests)
-      NO_TESTS=true
-      ;;
-    --no-lto)
-      NO_LTO=true
-      ;;
-    --allocator=*)
-      ALLOCATOR="${OPT#--allocator=}"
-      ALLOCATOR_LINK_ONLY=
-      ;;
-    --allocator-link-only=*)
-      ALLOCATOR="${OPT#--allocator-link-only=}"
-      ALLOCATOR_LINK_ONLY=true
-      ;;
-    --jemalloc-git-url=*)
-      JEMALLOC_GIT_URL="${OPT#--jemalloc-git-url=}"
-      ;;
-    --jemalloc-tag=*)
-      JEMALLOC_TAG="${OPT#--jemalloc-tag=}"
-      ;;
-    --use-libc++)
-      USE_LIBCXX=true
-      ;;
-    --install-to=*)
-      INSTALL_PATH="${OPT#--install-to=}"
-      ;;
-    --mingw64)
-      USE_MINGW64=true
-      ;;
-    --wine)
-      USE_WINE=true
-      WINDOWS_SSH=
-      ;;
-    --windows-ssh=*)
-      WINDOWS_SSH=${OPT##--windows-ssh=}
-      USE_WINE=
-      ;;
-    -*)
-      die "Unknown option $OPT, see --help."
-      ;;
-    *)
-      die "This script does not take parameters [$OPT]. See --help."
-      ;;
-  esac
-done
-
-if [[ -n "$HELP" ]]; then
-  PROGNAME="$(basename "$0")"
-  cat <<EOF
-Usage: ${PROGNAME} [options]
-
-Rebuild an optimized Ninja binary locally, using settings similar to the ones
-use by the Fuchsia LUCI recipe (which generates the prebuilt used by the
-Fuchsia build). This allows better performance comparisons. This means:
-
-- Enabling link-time optimization
-  (except if '--no-lto' is used).
-
-- Linking against the rpmalloc or mimalloc library
-  (when '--allocator=<name>' or '--allocator-link-only=<name>' is used).
-
-- Use the Fuchsia prebuilt Clang toolchain for compilation
-  (when '--fuchsia-dir=FUCHSIA_DIR' is specified).
-
-The script will also rebuild the test suite and run it to validate the
-generated binary. Use '--no-tests'to disable this.
-
-Use '--install-to=PATH' to copy the generated Ninja binary to a specific
-location. It will be under 'build-cmake/ninja/build/ninja' otherwise.
-
-Use '--no-clang' to use the default C++ compiler, otherwise the script will
-use 'clang++' instead, unless '--clang-binprefix=PREFIX' is used.
-
-Use '--ninja=PATH' to use Ninja as the CMake build generator (default is Make,
-which is considerably slower).
-
-Use '--fuchsia-dir=FUCHSIA_DIR' to use the prebuilt Clang toolchain, prebuilt
-sysroot and Ninja tool.
-
-Valid options:
-
-  --help                 Print this message.
-  --cmake=PATH           Specify CMake executable path to use.
-  --ninja=PATH           Specify Ninja executable path, to use as a CMake
-                         generator. This results in faster build than the
-                         default Make generator.
-  --no-lto               Disable Link Time Optimization (LTO).
-  --no-tests             Do not run tests.
-  --incremental, -i      Perform incremental build.
-  --debug                Generate debug version.
-  --install-to=FILE      Copy the resulting binary to FILE.
-  --no-clang             Do not use Clang, only the system 'c++' and 'ar'.
-  --clang-binprefix=DIR  Specify directory with Clang toolchain binaries.
-  --sysroot=DIR          Specify sysroot directory.
-  --fuchsia-dir=DIR      Specify Fuchsia directory where to find Clang and sysroot prebuilts.
-  --target=ARCH          Specify clang target triple for cross-compilation..
-
-  --build-dir=DIR        Specify directory (default is ${BUILD_DIR}).
-
-  --static               Generate static executable. Note that this can be
-                         slower due to lack of SIMD-optimized memchr() and
-                         related functions.
-
-  --mingw64              Use mingw64 on Linux to cross-compile Windows binaries,
-
-  --wine                 Use Wine on Linux to run the tests. Requires
-                         --mingw64.
-
-  --windows-ssh=<hostname>
-  --windows-ssh=<hostname>:<port>
-                         Run Windows binaries on a remote Windows machine
-                         with ssh. Requires --mingw64. Note: setting the
-                         value in the NINJA_WINDOWS_SSH environment variable
-                         works too.
-  --allocator=rpmalloc
-  --allocator=mimalloc
-  --allocator=jemalloc
-                         Build and link an alternative malloc library, which
-                         in many cases results in a 10% faster binary. Note
-                         that the allocator static library is cached in
-                         a user-specific directory to be reused later
-                         with --allocator-link-only (see below).
-
-  --allocator-link-only=<name>
-                         Same as --allocator=<name> but do not rebuild the
-                         allocator, and instead reuse a cached version from
-                         a previous --allocator=<name> call.
-
-  --jemalloc-git-url=URL
-                         jemalloc source git URL
-                         [$DEFAULT_JEMALLOC_GIT_URL]
-  --jemalloc-tag=TAG
-                         jemalloc git tag [$DEFAULT_JEMALLOC_TAG]
-
-
-  --use-libc++           Use libc++ (incompatible with --no-clang).
-EOF
-  exit 0
-fi
-
-# Directory where to store cached elements (e.g. allocator libraries, gtest, etc)
-if [[ -z "${XDG_CACHE_HOME}" ]]; then
-  XDG_CACHE_HOME=${HOME}/.cache
-fi
-CACHE_DIR="${XDG_CACHE_HOME}/build-ninja-cache"
-# Location of binaries specific to a given build type.
-# For now use a single directory, later, separate based on build options to
-# speed up incremental builds when switching between build types.
-BUILD_CACHE_DIR="${CACHE_DIR}/build"
-
-# Validate --allocator value is any,
-case "${ALLOCATOR}" in
-  jemalloc|rpmalloc|mimalloc|"")  # Note: "" selects for ALLOCATOR not being set.
-    ;;
-  *)
-    die "Invalid --allocator value ${ALLOCATOR}, must be one of: jemalloc, rpmalloc, mimalloc"
-    ;;
-esac
-
-CMAKE_ARGS=()
-if [[ -n "${NINJA}" ]]; then
-  CMAKE_ARGS+=(-GNinja -DCMAKE_MAKE_PROGRAM="${NINJA}")
-fi
-
-if [[ -n "${DEBUG}" ]]; then
-  CMAKE_ARGS+=("-DCMAKE_BUILD_TYPE=Debug")
-else
-  CMAKE_ARGS+=("-DCMAKE_BUILD_TYPE=Release")
-fi
-
-if [[ -n "${USE_MINGW64}" ]]; then
-  if [[ -n "${ALLOCATOR}" ]]; then
-    die "The --mingw64  option is not compatible with the --allocator option"
-  fi
-  MINGW64_TOOLCHAIN="${SCRIPT_DIR}/mingw64-toolchain.cmake"
-  CMAKE_ARGS+=("-DCMAKE_TOOLCHAIN_FILE=${MINGW64_TOOLCHAIN}")
-  if [[ -z "${BUILD_DIR}" ]]; then
-    BUILD_DIR=build-mingw64
-  fi
-  if [[ -z "${USE_WINE}" && -z "${WINDOWS_SSH}" ]]; then
-    echo >&2 "WARNING: Disabling tests due to lack of --wine or --windows-ssh option."
-    NO_TESTS=true
-  fi
-else
-  if [[ -n "${USE_WINE}" ]]; then
-    echo >&2 "ERROR: --wine requires --mingw64"
-    exit 1
-  fi
-  if [[ -n "${WINDOWS_SSH}" ]]; then
-    echo >&2 "ERROR: --windows-ssh requires --mingw64"
-    exit 1
-  fi
-fi
-
-if [[ -z "${BUILD_DIR}" ]]; then
-  BUILD_DIR=build-cmake
-fi
-
-if [[ -n "${CLANG_BINPREFIX}" ]]; then
-  # Ensure CLANG_BINPREFIX has a trailing separator to make
-  # expressions like "${CLANG_BINPREFIX}clang" work properly.
-  CLANG_BINPREFIX="${CLANG_BINPREFIX%/}/"
-fi
-
-if [[ -n "${NO_CLANG}" ]]; then
-  CC=$(which cc)
-  CXX=$(which c++)
-  AR=$(which ar)
-else
-  CC="${CLANG_BINPREFIX}clang"
-  CXX="${CLANG_BINPREFIX}clang++"
-  AR="${CLANG_BINPREFIX}llvm-ar"
-fi
-if [[ ! -f "${AR}" ]]; then
-  unset AR
-fi
-CFLAGS="$TARGET_FLAGS"
-CXXFLAGS="$TARGET_FLAGS"
-LDFLAGS="$TARGET_FLAGS"
-
-CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-rtti"
-
-if [[ -n "${STATIC}" ]]; then
-  CXXFLAGS="$CXXFLAGS -static"
-  LDFLAGS="$LDFLAGS -static"
-fi
-
-LIBCXX_FLAGS="-static-libstdc++"
-if [[ -z "$USE_MINGW64" ]]; then
-  LIBCXX_FLAGS="$LIBCXX_FLAGS -pthread"
-fi
-
-if [[ -n "${USE_MINGW64}" && -z "${NO_LTO}" ]]; then
-  echo >&2 "WARNING: Disabling LTO for mingw64 toolchain since it produces broken binaries!"
-  NO_LTO=true
-fi
-
-if [[ -n "${NO_LTO}" ]]; then
-  CFLAGS="$CFLAGS -fno-lto"
-  CXXFLAGS="$CXXFLAGS -fno-lto"
-  LDFLAGS="$LDFLAGS -fno-lto"
-fi
-
-if [[ -n "${USE_LIBCXX}" ]]; then
-  LIBCXX_A="$("${CLANG_BINPREFIX}clang++" --print-file-name=libc++.a)"
-  if [[ "${LIBCXX_A}" == "libc++.a" ]]; then
-    # NOTE: --print-file-name=libc++.a does not work on MacOS for some reason.
-    LIBCXX_A="${CLANG_BINPREFIX}../lib/libc++.a"
-    if [[ ! -f "${LIBCXX_A}" ]]; then
-      die "Could not find libc++.a with your Clang toolchain!"
-    fi
-  fi
-  CXXFLAGS="$CXXFLAGS -stdlib=libc++"
-  LIBCXX_FLAGS="-stdlib=libc++ $LIBCXX_A"
-  if [[ -z "$USE_MINGW64" ]]; then
-    LIBCXX_FLAGS="$LIBCXX_FLAGS -lpthread -ldl"
-  fi
-fi
-
-# Ensure we generate smaller executables on Linux
-if [[ "$OSTYPE" =~ linux* ]]; then
-  CFLAGS="$CFLAGS -fPIE"
-fi
-
-export CC CXX CFLAGS CXXFLAGS LDFLAGS
-
-if [[ -n "${SYSROOT}" ]]; then
-  CMAKE_ARGS+=("-DCMAKE_SYSROOT=$SYSROOT")
-fi
-
-if [[ "${ALLOCATOR}" == "rpmalloc" ]]; then
-  RPMALLOC_LIB="${BUILD_CACHE_DIR}/librpmallocwrap.a"
-
-  if [[ -z "${ALLOCATOR_LINK_ONLY}" ]]; then
-    if [[ -z "${NINJA}" ]]; then
-      die "Ninja is required to build rpmalloc, please use --ninja or --fuchsia-dir!"
-    fi
-    echo "Rebuilding rpmalloc library from scratch"
-    RPMALLOC_GIT_URL="https://fuchsia.googlesource.com/third_party/github.com/mjansson/rpmalloc"
-    RPMALLOC_BRANCH='+upstream/develop'
-    RPMALLOC_REVISION='b097fd0916500439721a114bb9cd8d14bd998683'
-    RPMALLOC_ARCH=x86-64
-    RPMALLOC_OS=linux
-    if [[ "$RPMALLOC_OS" == "macos" ]]; then
-      RPMALLOC_LIBPATH=lib/$RPMALLOC_OS/release/librpmallocwrap.a
-    else
-      RPMALLOC_LIBPATH=lib/$RPMALLOC_OS/release/$RPMALLOC_ARCH/librpmallocwrap.a
-    fi
-
-    TMPDIR="$(mktemp -d /tmp/build-rpmalloc.XXXXX)"
-    (
-      run cd "$TMPDIR"
-      run git init
-      run git fetch --tags --quiet "$RPMALLOC_GIT_URL" "$RPMALLOC_BRANCH"
-      run git checkout "$RPMALLOC_REVISION"
-
-      # Clang will now complain when `-funit-at-a-time` is being used.
-      run sed -i -e "s|-Wno-disabled-macro-expansion'|-Wno-disabled-macro-expansion', '-Wno-ignored-optimization-argument'|g" build/ninja/clang.py
-
-      # Remove -Weverything
-      run sed -i -e "s|-Weverything|-Wno-pedantic|g" build/ninja/clang.py
-
-      export CC CXX AR CFLAGS CXXFLAGS LDFLAGS
-      run ./configure.py -c release -a $RPMALLOC_ARCH --lto
-      run ${NINJA} $RPMALLOC_LIBPATH
-    )
-
-    run mkdir -p "$(dirname "$RPMALLOC_LIB")"
-    run cp -f "${TMPDIR}/${RPMALLOC_LIBPATH}" "${RPMALLOC_LIB}"
-  else
-    if [[ ! -f "$RPMALLOC_LIB" ]]; then
-      die "rpmalloc library is missing, use --allocator=rpmalloc instead: $RPMALLOC_LIB"
-    fi
-  fi
-
-  echo "Using rpmalloc library: $RPMALLOC_LIB"
-fi
-
-if [[ "${ALLOCATOR}" == "mimalloc" ]]; then
-  MIMALLOC_OBJ="${BUILD_CACHE_DIR}/mimalloc.o"
-
-  if [[ -z "${ALLOCATOR_LINK_ONLY}" ]]; then
-    echo "Rebuilding mimalloc library from scratch"
-    MIMALLOC_GIT_URL="https://github.com/microsoft/mimalloc.git"
-    MIMALLOC_BRANCH='master'
-    MIMALLOC_REVISION='5ac9e36'
-    MIALLOC_CMAKE_OPTIONS=(\
-      -DCMAKE_BUILD_TYPE=Release \
-      -DMI_OVERRIDE=ON \
-      -DMI_BUILD_SHARED=OFF \
-      -DMI_BUILD_STATIC=OFF \
-      -DMI_BUILD_OBJECT=ON \
-      -DMI_BUILD_TESTS=OFF \
-    )
-    if [[ -n "${NINJA}" ]]; then
-      MIALLOC_CMAKE_OPTIONS+=(-GNinja -DCMAKE_MAKE_PROGRAM="${NINJA}")
-    fi
-
-    TMPDIR=$(mktemp -d /tmp/build-mimalloc.XXXXX)
-    (
-      run cd "$TMPDIR"
-      run git init
-      run git fetch --tags --quiet "$MIMALLOC_GIT_URL" "$MIMALLOC_BRANCH"
-      run git checkout "$MIMALLOC_REVISION"
-
-      run export CC CXX AR CFLAGS CXXFLAGS LDFLAGS
-      run cmake -B build-cmake "${MIALLOC_CMAKE_OPTIONS[@]}" .
-      run cmake --build build-cmake --parallel
-    )
-
-    run mkdir -p "$(dirname "$MIMALLOC_OBJ")"
-    run cp -f "$TMPDIR/build-cmake/mimalloc.o" "$MIMALLOC_OBJ"
-  else
-    if [[ ! -f "$MIMALLOC_OBJ" ]]; then
-      die "mimalloc library is missing, use --allocator=mimalloc: $MIMALLOC_OBJ"
-    fi
-  fi
-
-  echo "Using mimalloc library: $MIMALLOC_OBJ"
-  LDFLAGS="$MIMALLOC_OBJ $LDFLAGS"
-fi
-
-if [[ "${ALLOCATOR}" == "jemalloc" ]]; then
-  JEMALLOC_LIB="${BUILD_CACHE_DIR}/libjemalloc.a"
-
-  if [[ -z "${ALLOCATOR_LINK_ONLY}" ]]; then
-    echo "Rebuilding jemalloc from scratch (this may take a minute or more)."
-    JEMALLOC_SRC="$(mktemp -d /tmp/build-jemalloc.XXXXXX)"
-    JEMALLOC_LOG="${TMPDIR:-/tmp}/jemalloc-build-$$.log"
-    echo "Log file at: ${JEMALLOC_LOG}"
-    if [[ -z "${JEMALLOC_TAG}" ]]; then
-      JEMALLOC_TAG="${DEFAULT_JEMALLOC_TAG}"
-    fi
-    if [[ -z "$JEMALLOC_GIT_URL" ]]; then
-      JEMALLOC_GIT_URL="${DEFAULT_JEMALLOC_GIT_URL}"
-    fi
-    JEMALLOC_CFLAGS="$CFLAGS -Wno-error"
-    JEMALLOC_LDFLAGS="$LDFLAGS"
-    if [[ -n "$LTO" ]]; then
-      JEMALLOC_CFLAGS="$JEMALLOC_CFLAGS -flto"
-      JEMALLOC_LDFLAGS="$JEMALLOC_LDFLAGS -flto"
-    fi
-    (
-      run cd "${JEMALLOC_SRC}"
-      run git init
-      run git fetch "${JEMALLOC_GIT_URL}" refs/tags/"${JEMALLOC_TAG}" --depth=1
-      run git checkout FETCH_HEAD
-      CFLAGS="$JEMALLOC_CFLAGS" \
-      CXXFLAGS="$JEMALLOC_CFLAGS" \
-      LDFLAGS="$JEMALLOC_LDFLAGS" \
-      run ./autogen.sh \
-        --disable-shared \
-        --enable-static \
-        --disable-libdl \
-        --disable-syscall \
-        --disable-stats
-      run make -j"$(nproc)" "lib/libjemalloc.a"
-    ) > "${JEMALLOC_LOG}" 2>&1
-    if [[ "$?" != 0 ]]; then
-      die "jemalloc compilation failed, please look at: $JEMALLOC_LOG"
-    fi
-    run cp "${JEMALLOC_SRC}/lib/libjemalloc.a" "${JEMALLOC_LIB}"
-  else
-    if [[ ! -f "$JEMALLOC_LIB" ]]; then
-      die "jemalloc library is missing, use --allocator=jemalloc: $JEMALLOC_LIB"
-    fi
-  fi
-  echo "Using jemalloc library: $JEMALLOC_LIB"
-  LDFLAGS="$JEMALLOC_LIB $LDFLAGS"
-fi
-
-LIBCXX_LDFLAGS="${LIBCXX_FLAGS}"
-LDFLAGS="$LDFLAGS $LIBCXX_LDFLAGS"
-
-# To link Ninja with rpmalloc, a top-level CMakeLists.txt, that includes the
-# Ninja one and adds a few directives, is needed.
-SRC_DIR=$(pwd 2>/dev/null)
-TEST_DIR="${BUILD_DIR}"
-run mkdir -p "${BUILD_DIR}"
-if [[ -z "${INCREMENTAL}" ]]; then
-  run rm -rf "${BUILD_DIR}"/*
-fi
-BUILD_BUILD_DIR="${BUILD_DIR}"
-BUILD_SRC_DIR="${SRC_DIR}"
-if [[ -n "${RPMALLOC_LIB}" ]]; then
-  BUILD_BUILD_DIR="${BUILD_DIR}/build"
-  BUILD_SRC_DIR="${BUILD_DIR}"
-  TEST_DIR="${BUILD_BUILD_DIR}/ninja"
-  if [[ -z "${INCREMENTAL}" ]]; then
-    cat > "${BUILD_DIR}"/CMakeLists.txt <<EOF
-cmake_minimum_required(VERSION 3.15)
-project(ninja-rpmalloc)
-include(CTest)
-add_subdirectory("${SRC_DIR}" ninja)
-target_link_libraries(ninja PRIVATE "${RPMALLOC_LIB}" -lpthread -ldl)
-EOF
-  fi
-fi
-if [[ -z "$INCREMENTAL" ]]; then
-  run "${CMAKE}" -S"${BUILD_SRC_DIR}" -B"${BUILD_BUILD_DIR}" "${CMAKE_ARGS[@]}"
-fi
-run "${CMAKE}" --build "${BUILD_BUILD_DIR}" --parallel
-if [[ -z "${NO_TESTS}" ]]; then
-  if [[ -n "${USE_WINE}" ]]; then
-    run "${SCRIPT_DIR}/mingw64-wine.sh" "${TEST_DIR}"/ninja_test.exe
-  elif [[ -n "${WINDOWS_SSH}" ]]; then
-    # Copy program binaries to Windows host with scp, then run them
-    # with ssh. Print the corresponding command for verification.
-    IFS=: read -ra _WINDOWS_ARGS <<< "${WINDOWS_SSH}"
-    _WINDOWS_HOST="${_WINDOWS_ARGS[0]}"
-    _WINDOWS_PORT="${_WINDOWS_ARGS[1]}"
-    _WINDOWS_SSH_ARGS=(-t)
-    _WINDOWS_SCP_ARGS=()
-    if [[ -n "${_WINDOWS_PORT}" ]]; then
-      _WINDOWS_SSH_ARGS+=(-p "${_WINDOWS_PORT}")
-      _WINDOWS_SCP_ARGS+=(-P "${_WINDOWS_PORT}")
-    fi
-    # NOTE: Pass all executables because their names change all the time
-    _SRC_FILES=("${BUILD_BUILD_DIR}"/*.exe)
-    run scp "${_WINDOWS_SCP_ARGS[@]}" "${_SRC_FILES[@]}" "${_WINDOWS_HOST}":
-    run ssh "${_WINDOWS_SSH_ARGS[@]}" "${_WINDOWS_HOST}" .\\ninja_test.exe
-  else
-    # Run the Ninja tests locally.
-    # They are run in the test directory, but Python tests are collected from
-    # the source tree, omitting those from CMake dependencies such
-    # as ./<build_dir>/_deps/googletest-src/.
-    #
-    # The main problem with them occurs when there are several build directories
-    # in the same top-level dir (e.g. `build-cmake/` and `build-mingw64/`
-    # because pytest wouldi, by default, collect tests from both directories on
-    # the next build, resulting in a very weird Python module import failure!
-    mapfile -t PYTHON_TESTS <<< "$(find "${SRC_DIR}" -name '*_test.py' | grep -v _deps/)"
-    (run cd "${TEST_DIR}" && run ./ninja_test && run pytest "${PYTHON_TESTS[@]}")
-  fi
-fi
-if [[ -n "${INSTALL_PATH}" ]]; then
-  run cp "${TEST_DIR}"/ninja "${INSTALL_PATH}"
-fi
diff --git a/misc/fuchsia/mingw64-toolchain.cmake b/misc/fuchsia/mingw64-toolchain.cmake
deleted file mode 100644
index 43ae329..0000000
--- a/misc/fuchsia/mingw64-toolchain.cmake
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2023 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-#
-# Sample toolchain file for building for Windows from an Ubuntu Linux system.
-#
-# Typical usage:
-#    *) install cross compiler: `sudo apt-get install mingw-w64`
-#    *) cd build
-#    *) cmake -DCMAKE_TOOLCHAIN_FILE=~/mingw-w64-x86_64.cmake ..
-
-set(CMAKE_SYSTEM_NAME Windows)
-set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
-
-# cross compilers to use for C, C++ and Fortran
-set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc-win32)
-set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++-win32)
-set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran)
-set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
-
-# target environment on the build host system
-set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
-
-# modify default behavior of FIND_XXX() commands
-set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
-set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
-set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/misc/fuchsia/mingw64-wine.sh b/misc/fuchsia/mingw64-wine.sh
deleted file mode 100755
index 26de6b9..0000000
--- a/misc/fuchsia/mingw64-wine.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-# Copyright 2023 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.
-
-set -e
-
-# Ensure WINEPATH is set to a value that allows the mingw64-generated
-# binaries to find runtime libraries for libstdc++ and others properly.
-if [[ -z "${WINEPATH}" ]]; then
-    export WINEPATH="/usr/x86_64-w64-mingw32/lib/;/usr/lib/gcc/x86_64-w64-mingw32/12-posix"
-    echo "Setting WINEPATH=\"${WINEPATH}\""
-fi
-wine "$@"
diff --git a/misc/fuchsia/sync-branch.py b/misc/fuchsia/sync-branch.py
deleted file mode 100755
index f8685bf..0000000
--- a/misc/fuchsia/sync-branch.py
+++ /dev/null
@@ -1,554 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2023 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""General tool to manage sync-branches as described in Fuchsia RFC-0153.
-
-This tool provides several commands that simplify creation and management
-of sync branches. A typical use case would be:
-
-  1) Use the `create` command to create a new local sync-branch, with
-     the right cherry-picked commits in it.
-
-  2) Optional: resolve any conflicts that happen during the cherry-pick
-     operation launched by the `create` command. Alternatively, it is possible
-     to rebase the sync branch, for example to re-order commits or update
-     documentation.
-
-  3) Use the `rebase` command to rebase the current sync-branch on top of
-     the current upstream reference.
-
-  4) Optional: resolve any conflicts that happen during the rebase operation.
-
-  5) Use the `merge` command to merge the sync branch into the
-     main development branch.
-
-Use `<command> --help` for command-specific details.
-
-"""
-
-import argparse
-import json
-import shlex
-import shutil
-import subprocess
-import sys
-import time
-from pathlib import Path
-from typing import Any, Iterable, List, Sequence
-
-_DEFAULT_UPSTREAM_REF = "origin/upstream/master"
-_DEFAULT_DEV_BRANCH = "fuchsia-rfc-0153"
-_DEFAULT_SYNC_BRANCH_NAME = "sync-branch-" + time.strftime("%Y-%m-%d", time.gmtime())
-
-
-_VERBOSE = False
-
-
-def log(msg: str):
-    if _VERBOSE:
-        print("LOG: " + msg, file=sys.stderr)
-
-
-def cmd_args_to_list(cmd_args: Iterable[Any]) -> Sequence[str]:
-    return [str(c) for c in cmd_args]
-
-
-def cmd_quote(cmd_args: Iterable[Any]) -> str:
-    return " ".join(shlex.quote(str(c)) for c in cmd_args)
-
-
-def run_command(cmd_args: Iterable[Any], **kwargs) -> subprocess.CompletedProcess:
-    log("CMD: " + cmd_quote(cmd_args))
-    return subprocess.run(cmd_args_to_list(cmd_args), **kwargs)
-
-
-def get_command_output(cmd_args: Iterable[Any], **kwargs) -> str:
-    assert "capture_output" not in kwargs
-    assert "text" not in kwargs
-    kwargs["capture_output"] = True
-    kwargs["text"] = True
-    ret = run_command(cmd_args, **kwargs)
-    ret.check_returncode()
-    return ret.stdout.strip()
-
-
-def read_file(path: Path) -> str:
-    with open(path) as f:
-        return f.read()
-
-
-def write_file(path: Path, content: str):
-    path.parent.mkdir(exist_ok=True, parents=True)
-    with open(path, "w") as f:
-        f.write(content)
-
-
-class CommandError(Exception):
-    pass
-
-
-class GitDirectory(object):
-    """A Git directory."""
-
-    def __init__(self, git_dir: Path):
-        assert git_dir.is_dir(), "Not a directory: %s" % git_dir
-        assert (git_dir / ".git").is_dir(), (
-            "Not a git directory (missing .git/): %s" % git_dir
-        )
-        self._git_dir = git_dir
-        self._cfg_dir = git_dir / ".git" / "sync_branch"
-
-    @property
-    def git_dir(self) -> Path:
-        return self._git_dir
-
-    @property
-    def cfg_dir(self) -> Path:
-        return self._cfg_dir
-
-    @property
-    def cfg_file_path(self) -> Path:
-        return self._cfg_dir / "config.json"
-
-    def cmd(self, args: List[Any]):
-        ret = run_command(["git", "-C", self._git_dir] + args)
-        ret.check_returncode()
-
-    def cmd_output(self, args: List) -> str:
-        return get_command_output(["git", "-C", self._git_dir] + args)
-
-
-class PrintingGitDirectory(GitDirectory):
-    """A GitDirectory subclass that prints commands instead of running them."""
-
-    def __init__(self, parent: GitDirectory):
-        self._parent = parent
-
-    def cmd(self, args: Iterable[Any]) -> None:
-        print(
-            "git -C %s %s"
-            % (self._parent.git_dir, " ".join(shlex.quote(a) for a in args))
-        )
-
-
-class SyncBranchConfig(object):
-    def __init__(self, git_dir: GitDirectory):
-        self.git_dir = git_dir
-        self.upstream_ref: str = _DEFAULT_UPSTREAM_REF
-        self.dev_branch_name: str = _DEFAULT_DEV_BRANCH
-        self.sync_branch_name: str = _DEFAULT_SYNC_BRANCH_NAME
-        self.stem_commit: str = ""
-        self.upstream_commit: str = ""
-        self.src_commits: List[str] = []
-
-    def init_from_create_args(self, args: argparse.Namespace) -> None:
-        if args.name:
-            self.sync_branch_name = args.name
-        if args.upstream_ref:
-            self.upstream_ref = args.upstream_ref
-        if args.dev_branch:
-            self.dev_branch_name = args.dev_branch
-
-        # Verify that the branch does not exist yet.
-        g = self.git_dir
-        has_sync_branch = False
-        on_sync_branch = False
-        current_branch = g.cmd_output(["branch", "--show-current"])
-        if current_branch and current_branch == self.sync_branch_name:
-            has_sync_branch = True
-            on_sync_branch = True
-        else:
-            has_sync_branch = bool(
-                g.cmd_output(["branch", "--list", self.sync_branch_name])
-            )
-
-        if has_sync_branch:
-            if not args.force:
-                raise CommandError(
-                    "Cannot create new sync-branch over current one, use --force to override!"
-                )
-            if on_sync_branch:
-                g.cmd(["checkout", "--force", self.dev_branch_name])
-            g.cmd(["branch", "-D", self.sync_branch_name])
-
-        self.upstream_commit = self.git_dir.cmd_output(["rev-parse", self.upstream_ref])
-
-        # Compute stem commit, this the first common ancestor of
-        # the upstream and development branch. For example in:
-        #
-        # upstream --A1-------A2---A3
-        #             \         \
-        #              \         +--B1"--B2"--C2"
-        #               \         \             \
-        #                \         B1'--B2'      \
-        #                 \               \       \
-        # dev -------------B1---B2---------C1--C2--D1--D2
-        #
-        # The stem commit is A2
-        #
-        self.stem_commit = g.cmd_output(
-            ["merge-base", self.upstream_ref, self.dev_branch_name]
-        ).strip()
-
-        if self.stem_commit == self.upstream_commit and not args.force:
-            raise CommandError(
-                "All upstream commits in current branch, no sync branch needed!"
-            )
-
-        # Compute source commits
-        #
-        # To do that, use --ancestry-path to limit the result to
-        # commits that belong only to the most recent sync branch
-        # is required.
-        #
-        # For example, without --ancestry-path, a command like
-        # `git rev-list STEM..dev` would return the following commits
-        # from the previous example history, which contains multiple
-        # sync branches originating from the same stem:
-        #
-        # upstream            A2
-        #                       \
-        #                        +--B1"--B2"--C2"
-        #                         \             \
-        #                          B1'--B2'      \
-        #                                 \       \
-        # dev                              C1--C2--D1--D2
-        #
-        # By using --ancestry-path=C2", the result is
-        # limited to only the commits from the most recent sync branch, i.e.:
-        #
-        # upstream            A2
-        #                       \
-        #                        +--B1"--B2"--C2"
-        #                                       \
-        #                                        \
-        #                                         \
-        # dev                                      D1--D2
-        #
-        # The commit to pass to --ancestry-path is the _second_
-        # parent of the most recent merge in the dev branch.
-        #
-        # To find it, the command below uses `rev-list --merges --format=%P`
-        # to print two lines per merge commit that is in the common ancestry
-        # of the stem and the dev HEAD.
-        #
-        # In the example above, the stem is A2, the HEAD is D2, and
-        # they share two merge commits C1 and D1, and the commands
-        # prints the following:
-        #
-        #   commit <D1>
-        #   <C2> <C2">
-        #   commit <C1>
-        #   <B2> <B2'>
-        #
-        # Taking the last hash of the second line of output gives us
-        # the commit value for --ancestry-path.
-        merge_commits_lines = g.cmd_output(
-            [
-                "rev-list",
-                "%s..%s" % (self.upstream_ref, self.dev_branch_name),
-                "--merges",
-                "--format=%P",
-            ]
-        ).splitlines()
-
-        if len(merge_commits_lines) == 0:
-            # No merge commit means we never created a sync branch
-            # in the past. In that case, do not use --ancestry-path
-            ancestry_path_args = []
-        else:
-            if len(merge_commits_lines) < 2:
-                raise CommandError(
-                    "Invalid git rev-list output!\n%  %s\n"
-                    % "  \n".join(merge_commits_lines)
-                )
-
-            parents = merge_commits_lines[1].split(" ")
-            if len(parents) != 2:
-                # We really don't know how to handle merges with more
-                # than 2 parents. These were not created by the sync-branch tool.
-                raise CommandError(
-                    "Most recent merge has more than 2 parents!\n  %s\n"
-                    % "  \n".join(merge_commits_lines)
-                )
-
-            ancestry_path_args = ["--ancestry-path=" + parents[1]]
-
-        # Now list all the source commits.
-        self.src_commits = g.cmd_output(
-            [
-                "rev-list",
-                "--reverse",
-                "--no-merges",
-                "--pretty=oneline",
-                "%s..%s" % (self.stem_commit, self.dev_branch_name),
-            ]
-            + ancestry_path_args
-        ).splitlines()
-
-    def has_config_file(self) -> bool:
-        return self.git_dir.cfg_file_path.exists()
-
-    def read_config_file(self):
-        c = json.loads(read_file(self.git_dir.cfg_file_path))
-        self.upstream_ref = c["upstream_ref"]
-        self.dev_branch_name = c["dev_branch_name"]
-        self.sync_branch_name = c["sync_branch_name"]
-        self.stem_commit = c["stem_commit"]
-        self.src_commits = c["src_commits"]
-
-    def write_config_file(self) -> None:
-        c = {
-            "upstream_ref": self.upstream_ref,
-            "dev_branch_name": self.dev_branch_name,
-            "sync_branch_name": self.sync_branch_name,
-            "stem_commit": self.stem_commit,
-            "src_commits": self.src_commits,
-        }
-        write_file(self.git_dir.cfg_file_path, json.dumps(c, sort_keys=True, indent=2))
-
-    def clear_config_file(self) -> None:
-        cfg_dir = self.git_dir.cfg_dir
-        if cfg_dir.exists():
-            shutil.rmtree(cfg_dir)
-
-
-def get_git_directory(args: argparse.Namespace) -> GitDirectory:
-    # Compute git directory.
-    if args.git_dir:
-        git_dir = Path(args.git_dir)
-    else:
-        git_dir = Path.cwd()
-
-    if not git_dir.is_dir():
-        raise CommandError("Not a directory: %s" % git_dir)
-    if not (git_dir / ".git").is_dir():
-        raise CommandError("Not a git directory (missing .git): %s" % git_dir)
-
-    return GitDirectory(git_dir)
-
-
-def command_create(args: argparse.Namespace) -> None:
-    git_dir = get_git_directory(args)
-    sbc = SyncBranchConfig(git_dir)
-    sbc.init_from_create_args(args)
-    sbc.write_config_file()
-
-    if args.print_only:
-        git_dir = PrintingGitDirectory(git_dir)
-
-    # Create a tag pointing to the stem commit, for debugging.
-    git_dir.cmd(["tag", "-f", "SYNC_BRANCH_STEM", sbc.stem_commit])
-    git_dir.cmd(["checkout", "-b", sbc.sync_branch_name, sbc.stem_commit])
-    git_dir.cmd(["cherry-pick"] + [c.split(" ")[0] for c in sbc.src_commits])
-
-
-def command_rebase(args: argparse.Namespace) -> None:
-    git_dir = get_git_directory(args)
-    sbc = SyncBranchConfig(git_dir)
-    if not sbc.has_config_file():
-        raise CommandError("No current sync branch, please use `create` command first!")
-
-    sbc.read_config_file()
-    if args.print_only:
-        git_dir = PrintingGitDirectory(git_dir)
-
-    cmd_args = [
-        "rebase",
-        "--onto",
-        sbc.upstream_ref,
-        sbc.stem_commit,
-        sbc.sync_branch_name,
-    ]
-    git_dir.cmd(cmd_args)
-
-
-def command_merge(args: argparse.Namespace) -> None:
-    git_dir = get_git_directory(args)
-    sbc = SyncBranchConfig(git_dir)
-    if not sbc.has_config_file():
-        raise CommandError("No current sync branch, please use `create` command first!")
-
-    sbc.read_config_file()
-    if args.print_only:
-        git_dir = PrintingGitDirectory(git_dir)
-
-    git_dir.cmd(["checkout", sbc.dev_branch_name])
-
-    merge_cmd = ["merge", "--no-ff", "-X", "theirs", sbc.sync_branch_name]
-    if args.no_commit:
-        merge_cmd += ["--no-commit"]
-
-    git_dir.cmd(merge_cmd)
-
-
-def main():
-    parser = argparse.ArgumentParser(
-        description=__doc__, formatter_class=argparse.RawTextHelpFormatter
-    )
-
-    parser.add_argument("--verbose", action="store_true", help="Enable verbose mode")
-    parser.add_argument("--git-dir", help="Specify git directory.")
-    parser.add_argument(
-        "--print-only",
-        action="store_true",
-        help="Only print the git commands, do not run them.",
-    )
-
-    subparsers = parser.add_subparsers(required=True, help="Available commands")
-
-    parser_create = subparsers.add_parser(
-        "create",
-        help="Create new local sync-branch",
-        formatter_class=argparse.RawTextHelpFormatter,
-        description=r"""
-Create a new local sync branch, which will start at the 'stem' commit that
-is common to both the upstream and development branches, and will include
-all commits between them (as cherry picks).
-
-For example, consider the following initial state:
-
-  upstream ---A1--A2--A3
-                    \
-  dev      - - - - - B1--B2--B3
-
-The command will create a new branch starting from A2 that contains
-cherry picks of B1..B3, as in:
-
-  sync-branch        B1'--B2'--B3'
-                    /
-  upstream ---A1--A2--A3
-                    \
-  dev      - - - - - B1--B2--B3
-
-Note that the cherry-pick command launched by `create` may fail in case of
-rare conflicts. If this happens, just fix the issue manually then use
-`git cherry-pick --continue` to complete the operation,
-
-After the cherry pick has completed, the user is free to rebase the branch,
-for example to reorder commits, or update documentation, before invoking
-the `rebase` command.
-
-Note that `create` will not work if a local sync branch already exists, or
-when upstream commits are already reachable in the developement branch.
-These conditions can be overriden by using the `--force` option.
-
-""",
-    )
-
-    parser_create.add_argument(
-        "--force", action="store_true", help="Discard any existing sync branch."
-    )
-    parser_create.add_argument(
-        "--name",
-        default=_DEFAULT_SYNC_BRANCH_NAME,
-        help=f"Specify sync branch name (default {_DEFAULT_SYNC_BRANCH_NAME})",
-    )
-    parser_create.add_argument(
-        "--upstream-ref",
-        default=_DEFAULT_UPSTREAM_REF,
-        help=f"Specify upstream branch reference (default {_DEFAULT_UPSTREAM_REF})",
-    )
-    parser_create.add_argument(
-        "--dev-branch",
-        default=_DEFAULT_DEV_BRANCH,
-        help=f"Specify development branch (default {_DEFAULT_DEV_BRANCH})",
-    )
-    parser_create.set_defaults(func=command_create)
-
-    parser_rebase = subparsers.add_parser(
-        "rebase",
-        help="Rebase current sync-branch on top of upstream.",
-        formatter_class=argparse.RawTextHelpFormatter,
-        description=r"""
-Rebase the current sync branch on top of the current upstream commit.
-This must be called after the completion of a `create` operation.
-
-For example consider the following state resulting from a previous
-`create` operation:
-
-  sync-branch        B1'--B2'--B3'
-                    /
-  upstream ---A1--A2--A3
-                    \
-  dev      - - - - - B1--B2--B3
-
-After the rebase, the sync branch should be something like:
-
-  sync-branch            B1''--B2''--B3''
-                        /
-  upstream ---A1--A2--A3
-                    \
-  dev      - - - - - B1--B2--B3
-
-Where both B3 and B3'' correspond to the new desired sources.
-
-After the rebase, the user is free to inspect the branch, rebase it or do
-any necessary cleanups, and verify that everything still works as expected.
-
-The user will then launch the `merge` command to merge the result into the
-main development branch.
-
-""",
-    )
-    parser_rebase.set_defaults(func=command_rebase)
-
-    parser_merge = subparsers.add_parser(
-        "merge",
-        help="Merge sync-branch to main development branch.",
-        formatter_class=argparse.RawTextHelpFormatter,
-        description=r"""
-Merge the current sync branch into the main development branch. This should
-only happen after a successful `rebase` command invocation.
-
-For example consider the following state resulting from a previous
-`rebase` operation:
-
-  sync-branch            B1''--B2''--B3''
-                        /
-  upstream ---A1--A2--A3
-                    \
-  dev      - - - - - B1--B2--B3
-
-The end result will be:
-
-  upstream ---A1--A2--A3
-                        \
-  sync-branch            B1''--B2''--B3''
-                                         \
-  dev      - - - - - B1--B2--B3-----------C1
-
-Where C1 is the new merge commit on the main development branch.
-
-Note that A3 will become the stem commit for future 'create'
-operations.
-
-""",
-    )
-    parser_merge.add_argument(
-        "--no-commit", action="store_true", help="Do not commit the merge."
-    )
-    parser_merge.set_defaults(func=command_merge)
-
-    args = parser.parse_args()
-
-    if args.verbose:
-        global _VERBOSE
-        _VERBOSE = True
-
-    try:
-        args.func(args)
-    except CommandError as e:
-        print(str(e), file=sys.stderr)
-        return 1
-    except subprocess.CalledProcessError as e:
-        print("%s:\n%s\n" % (e, e.stderr), file=sys.stderr)
-        return e.returncode
-
-    return 0
-
-
-if __name__ == "__main__":
-    sys.exit(main())
diff --git a/misc/inherited-fds.ninja b/misc/inherited-fds.ninja
deleted file mode 100644
index 671155e..0000000
--- a/misc/inherited-fds.ninja
+++ /dev/null
@@ -1,23 +0,0 @@
-# This build file prints out a list of open file descriptors in
-# Ninja subprocesses, to help verify we don't accidentally leak
-# any.
-
-# Because one fd leak was in the code managing multiple subprocesses,
-# this test brings up multiple subprocesses and then dumps the fd
-# table of the last one.
-
-# Use like: ./ninja -f misc/inherited-fds.ninja
-
-rule sleep
-  command = sleep 10000
-
-rule dump
-  command = sleep 1; ls -l /proc/self/fd; exit 1
-
-build all: phony a b c d e
-
-build a: sleep
-build b: sleep
-build c: sleep
-build d: sleep
-build e: dump
diff --git a/misc/long-slow-build.ninja b/misc/long-slow-build.ninja
deleted file mode 100644
index 46af6ba..0000000
--- a/misc/long-slow-build.ninja
+++ /dev/null
@@ -1,38 +0,0 @@
-# An input file for running a "slow" build.
-# Use like: ninja -f misc/long-slow-build.ninja all
-
-rule sleep
-  command = sleep 1
-  description = SLEEP $out
-
-build 0: sleep README
-build 1: sleep README
-build 2: sleep README
-build 3: sleep README
-build 4: sleep README
-build 5: sleep README
-build 6: sleep README
-build 7: sleep README
-build 8: sleep README
-build 9: sleep README
-build 10: sleep 0
-build 11: sleep 1
-build 12: sleep 2
-build 13: sleep 3
-build 14: sleep 4
-build 15: sleep 5
-build 16: sleep 6
-build 17: sleep 7
-build 18: sleep 8
-build 19: sleep 9
-build 20: sleep 10
-build 21: sleep 11
-build 22: sleep 12
-build 23: sleep 13
-build 24: sleep 14
-build 25: sleep 15
-build 26: sleep 16
-build 27: sleep 17
-build 28: sleep 18
-build 29: sleep 19
-build all: phony 20 21 22 23 24 25 26 27 28 29
diff --git a/misc/manifest_fuzzer.cc b/misc/manifest_fuzzer.cc
deleted file mode 100644
index 0e1261a..0000000
--- a/misc/manifest_fuzzer.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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/measure.py b/misc/measure.py
deleted file mode 100755
index f3825ef..0000000
--- a/misc/measure.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/env python3
-
-# 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.
-
-"""measure the runtime of a command by repeatedly running it.
-"""
-
-import time
-import subprocess
-import sys
-
-devnull = open('/dev/null', 'w')
-
-def run(cmd, repeat=10):
-    print('sampling:', end=' ')
-    sys.stdout.flush()
-
-    samples = []
-    for _ in range(repeat):
-        start = time.time()
-        subprocess.call(cmd, stdout=devnull, stderr=devnull)
-        end = time.time()
-        dt = (end - start) * 1000
-        print('%dms' % int(dt), end=' ')
-        sys.stdout.flush()
-        samples.append(dt)
-    print()
-
-    # We're interested in the 'pure' runtime of the code, which is
-    # conceptually the smallest time we'd see if we ran it enough times
-    # such that it got the perfect time slices / disk cache hits.
-    best = min(samples)
-    # Also print how varied the outputs were in an attempt to make it
-    # more obvious if something has gone terribly wrong.
-    err = sum(s - best for s in samples) / float(len(samples))
-    print('estimate: %dms (mean err %.1fms)' % (best, err))
-
-if __name__ == '__main__':
-    if len(sys.argv) < 2:
-        print('usage: measure.py command args...')
-        sys.exit(1)
-    run(cmd=sys.argv[1:])
diff --git a/misc/ninja-mode.el b/misc/ninja-mode.el
deleted file mode 100644
index 8b975d5..0000000
--- a/misc/ninja-mode.el
+++ /dev/null
@@ -1,85 +0,0 @@
-;;; ninja-mode.el --- Major mode for editing .ninja files -*- lexical-binding: t -*-
-
-;; Package-Requires: ((emacs "24"))
-
-;; 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.
-
-;;; Commentary:
-
-;; Simple emacs mode for editing .ninja files.
-;; Just some syntax highlighting for now.
-
-;;; Code:
-
-(defvar ninja-keywords
-  `((,(concat "^" (regexp-opt '("rule" "build" "subninja" "include"
-                                "pool" "default")
-                              'words))
-     . font-lock-keyword-face)
-    ("\\([[:alnum:]_]+\\) =" 1 font-lock-variable-name-face)
-    ;; Variable expansion.
-    ("$[[:alnum:]_]+" . font-lock-variable-name-face)
-    ("${[[:alnum:]._]+}" . font-lock-variable-name-face)
-    ;; Rule names
-    ("rule +\\([[:alnum:]_.-]+\\)" 1 font-lock-function-name-face)
-    ;; Build Statement - highlight the rule used,
-    ;; allow for escaped $,: in outputs.
-    ("build +\\(?:[^:$\n]\\|$[:$]\\)+ *: *\\([[:alnum:]_.-]+\\)"
-     1 font-lock-function-name-face)))
-
-(defvar ninja-mode-syntax-table
-  (let ((table (make-syntax-table)))
-    (modify-syntax-entry ?\" "." table)
-    table)
-  "Syntax table used in `ninja-mode'.")
-
-(defun ninja-syntax-propertize (start end)
-  (save-match-data
-    (goto-char start)
-    (while (search-forward "#" end t)
-      (let ((match-pos (match-beginning 0)))
-        (when (and
-               ;; Is it the first non-white character on the line?
-               (eq match-pos (save-excursion (back-to-indentation) (point)))
-               (save-excursion
-                 (goto-char (line-end-position 0))
-                 (or
-                  ;; If we're continuing the previous line, it's not a
-                  ;; comment.
-                  (not (eq ?$ (char-before)))
-                  ;; Except if the previous line is a comment as well, as the
-                  ;; continuation dollar is ignored then.
-                  (nth 4 (syntax-ppss)))))
-          (put-text-property match-pos (1+ match-pos) 'syntax-table '(11))
-          (let ((line-end (line-end-position)))
-            ;; Avoid putting properties past the end of the buffer.
-            ;; Otherwise we get an `args-out-of-range' error.
-            (unless (= line-end (1+ (buffer-size)))
-              (put-text-property line-end (1+ line-end) 'syntax-table '(12)))))))))
-
-;;;###autoload
-(define-derived-mode ninja-mode prog-mode "ninja"
-  (set (make-local-variable 'comment-start) "#")
-  (set (make-local-variable 'parse-sexp-lookup-properties) t)
-  (set (make-local-variable 'syntax-propertize-function) #'ninja-syntax-propertize)
-  (setq font-lock-defaults '(ninja-keywords)))
-
-;; Run ninja-mode for files ending in .ninja.
-;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.ninja$" . ninja-mode))
-
-(provide 'ninja-mode)
-
-;;; ninja-mode.el ends here
diff --git a/misc/ninja.vim b/misc/ninja.vim
deleted file mode 100644
index c1ffd50..0000000
--- a/misc/ninja.vim
+++ /dev/null
@@ -1,87 +0,0 @@
-" ninja build file syntax.
-" Language: ninja build file as described at
-"           http://ninja-build.org/manual.html
-" Version: 1.5
-" Last Change: 2018/04/05
-" Maintainer: Nicolas Weber <nicolasweber@gmx.de>
-" Version 1.4 of this script is in the upstream vim repository and will be
-" included in the next vim release. If you change this, please send your change
-" upstream.
-
-" ninja lexer and parser are at
-" https://github.com/ninja-build/ninja/blob/master/src/lexer.in.cc
-" https://github.com/ninja-build/ninja/blob/master/src/manifest_parser.cc
-
-if exists("b:current_syntax")
-  finish
-endif
-
-let s:cpo_save = &cpo
-set cpo&vim
-
-syn case match
-
-" Comments are only matched when the # is at the beginning of the line (with
-" optional whitespace), as long as the prior line didn't end with a $
-" continuation.
-syn match ninjaComment /\(\$\n\)\@<!\_^\s*#.*$/  contains=@Spell
-
-" Toplevel statements are the ones listed here and
-" toplevel variable assignments (ident '=' value).
-" lexer.in.cc, ReadToken() and manifest_parser.cc, Parse()
-syn match ninjaKeyword "^build\>"
-syn match ninjaKeyword "^rule\>"
-syn match ninjaKeyword "^pool\>"
-syn match ninjaKeyword "^default\>"
-syn match ninjaKeyword "^include\>"
-syn match ninjaKeyword "^subninja\>"
-
-" Both 'build' and 'rule' begin a variable scope that ends
-" on the first line without indent. 'rule' allows only a
-" limited set of magic variables, 'build' allows general
-" let assignments.
-" manifest_parser.cc, ParseRule()
-syn region ninjaRule start="^rule" end="^\ze\S" contains=TOP transparent
-syn keyword ninjaRuleCommand contained containedin=ninjaRule command
-                                     \ deps depfile description generator
-                                     \ pool restat rspfile rspfile_content
-
-syn region ninjaPool start="^pool" end="^\ze\S" contains=TOP transparent
-syn keyword ninjaPoolCommand contained containedin=ninjaPool  depth
-
-" Strings are parsed as follows:
-" lexer.in.cc, ReadEvalString()
-" simple_varname = [a-zA-Z0-9_-]+;
-" varname = [a-zA-Z0-9_.-]+;
-" $$ -> $
-" $\n -> line continuation
-" '$ ' -> escaped space
-" $simple_varname -> variable
-" ${varname} -> variable
-
-syn match   ninjaDollar "\$\$"
-syn match   ninjaWrapLineOperator "\$$"
-syn match   ninjaSimpleVar "\$[a-zA-Z0-9_-]\+"
-syn match   ninjaVar       "\${[a-zA-Z0-9_.-]\+}"
-
-" operators are:
-" variable assignment =
-" rule definition :
-" implicit dependency |
-" order-only dependency ||
-syn match ninjaOperator "\(=\|:\||\|||\)\ze\s"
-
-hi def link ninjaComment Comment
-hi def link ninjaKeyword Keyword
-hi def link ninjaRuleCommand Statement
-hi def link ninjaPoolCommand Statement
-hi def link ninjaDollar ninjaOperator
-hi def link ninjaWrapLineOperator ninjaOperator
-hi def link ninjaOperator Operator
-hi def link ninjaSimpleVar ninjaVar
-hi def link ninjaVar Identifier
-
-let b:current_syntax = "ninja"
-
-let &cpo = s:cpo_save
-unlet s:cpo_save
diff --git a/misc/ninja_syntax.py b/misc/ninja_syntax.py
deleted file mode 100644
index ca73b5b..0000000
--- a/misc/ninja_syntax.py
+++ /dev/null
@@ -1,199 +0,0 @@
-#!/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
-just a helpful utility for build-file-generation systems that already
-use Python.
-"""
-
-import re
-import textwrap
-
-def escape_path(word):
-    return word.replace('$ ', '$$ ').replace(' ', '$ ').replace(':', '$:')
-
-class Writer(object):
-    def __init__(self, output, width=78):
-        self.output = output
-        self.width = width
-
-    def newline(self):
-        self.output.write('\n')
-
-    def comment(self, text):
-        for line in textwrap.wrap(text, self.width - 2, break_long_words=False,
-                                  break_on_hyphens=False):
-            self.output.write('# ' + line + '\n')
-
-    def variable(self, key, value, indent=0):
-        if value is None:
-            return
-        if isinstance(value, list):
-            value = ' '.join(filter(None, value))  # Filter out empty strings.
-        self._line('%s = %s' % (key, value), indent)
-
-    def pool(self, name, depth):
-        self._line('pool %s' % name)
-        self.variable('depth', depth, indent=1)
-
-    def rule(self, name, command, description=None, depfile=None,
-             generator=False, pool=None, restat=False, rspfile=None,
-             rspfile_content=None, deps=None):
-        self._line('rule %s' % name)
-        self.variable('command', command, indent=1)
-        if description:
-            self.variable('description', description, indent=1)
-        if depfile:
-            self.variable('depfile', depfile, indent=1)
-        if generator:
-            self.variable('generator', '1', indent=1)
-        if pool:
-            self.variable('pool', pool, indent=1)
-        if restat:
-            self.variable('restat', '1', indent=1)
-        if rspfile:
-            self.variable('rspfile', rspfile, indent=1)
-        if rspfile_content:
-            self.variable('rspfile_content', rspfile_content, indent=1)
-        if deps:
-            self.variable('deps', deps, indent=1)
-
-    def build(self, outputs, rule, inputs=None, implicit=None, order_only=None,
-              variables=None, implicit_outputs=None, pool=None, dyndep=None):
-        outputs = as_list(outputs)
-        out_outputs = [escape_path(x) for x in outputs]
-        all_inputs = [escape_path(x) for x in as_list(inputs)]
-
-        if implicit:
-            implicit = [escape_path(x) for x in as_list(implicit)]
-            all_inputs.append('|')
-            all_inputs.extend(implicit)
-        if order_only:
-            order_only = [escape_path(x) for x in as_list(order_only)]
-            all_inputs.append('||')
-            all_inputs.extend(order_only)
-        if implicit_outputs:
-            implicit_outputs = [escape_path(x)
-                                for x in as_list(implicit_outputs)]
-            out_outputs.append('|')
-            out_outputs.extend(implicit_outputs)
-
-        self._line('build %s: %s' % (' '.join(out_outputs),
-                                     ' '.join([rule] + all_inputs)))
-        if pool is not None:
-            self._line('  pool = %s' % pool)
-        if dyndep is not None:
-            self._line('  dyndep = %s' % dyndep)
-
-        if variables:
-            if isinstance(variables, dict):
-                iterator = iter(variables.items())
-            else:
-                iterator = iter(variables)
-
-            for key, val in iterator:
-                self.variable(key, val, indent=1)
-
-        return outputs
-
-    def include(self, path):
-        self._line('include %s' % path)
-
-    def subninja(self, path):
-        self._line('subninja %s' % path)
-
-    def default(self, paths):
-        self._line('default %s' % ' '.join(as_list(paths)))
-
-    def _count_dollars_before_index(self, s, i):
-        """Returns the number of '$' characters right in front of s[i]."""
-        dollar_count = 0
-        dollar_index = i - 1
-        while dollar_index > 0 and s[dollar_index] == '$':
-            dollar_count += 1
-            dollar_index -= 1
-        return dollar_count
-
-    def _line(self, text, indent=0):
-        """Write 'text' word-wrapped at self.width characters."""
-        leading_space = '  ' * indent
-        while len(leading_space) + len(text) > self.width:
-            # The text is too wide; wrap if possible.
-
-            # Find the rightmost space that would obey our width constraint and
-            # that's not an escaped space.
-            available_space = self.width - len(leading_space) - len(' $')
-            space = available_space
-            while True:
-                space = text.rfind(' ', 0, space)
-                if (space < 0 or
-                    self._count_dollars_before_index(text, space) % 2 == 0):
-                    break
-
-            if space < 0:
-                # No such space; just use the first unescaped space we can find.
-                space = available_space - 1
-                while True:
-                    space = text.find(' ', space + 1)
-                    if (space < 0 or
-                        self._count_dollars_before_index(text, space) % 2 == 0):
-                        break
-            if space < 0:
-                # Give up on breaking.
-                break
-
-            self.output.write(leading_space + text[0:space] + ' $\n')
-            text = text[space+1:]
-
-            # Subsequent lines are continuations, so indent them.
-            leading_space = '  ' * (indent+2)
-
-        self.output.write(leading_space + text + '\n')
-
-    def close(self):
-        self.output.close()
-
-
-def as_list(input):
-    if input is None:
-        return []
-    if isinstance(input, list):
-        return input
-    return [input]
-
-
-def escape(string):
-    """Escape a string such that it can be embedded into a Ninja file without
-    further interpretation."""
-    assert '\n' not in string, 'Ninja syntax does not allow newlines'
-    # We only have one special metacharacter: '$'.
-    return string.replace('$', '$$')
-
-
-def expand(string, vars, local_vars={}):
-    """Expand a string containing $vars as Ninja would.
-
-    Note: doesn't handle the full Ninja variable syntax, but it's enough
-    to make configure.py's use of it work.
-    """
-    def exp(m):
-        var = m.group(1)
-        if var == '$':
-            return '$'
-        return local_vars.get(var, vars.get(var, ''))
-    return re.sub(r'\$(\$|\w*)', exp, string)
diff --git a/misc/ninja_syntax_test.py b/misc/ninja_syntax_test.py
deleted file mode 100755
index 61fb177..0000000
--- a/misc/ninja_syntax_test.py
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/usr/bin/env python3
-
-# 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.
-
-import unittest
-
-try:
-    from StringIO import StringIO
-except ImportError:
-    from io import StringIO
-
-import ninja_syntax
-
-LONGWORD = 'a' * 10
-LONGWORDWITHSPACES = 'a'*5 + '$ ' + 'a'*5
-INDENT = '    '
-
-class TestLineWordWrap(unittest.TestCase):
-    def setUp(self):
-        self.out = StringIO()
-        self.n = ninja_syntax.Writer(self.out, width=8)
-
-    def test_single_long_word(self):
-        # We shouldn't wrap a single long word.
-        self.n._line(LONGWORD)
-        self.assertEqual(LONGWORD + '\n', self.out.getvalue())
-
-    def test_few_long_words(self):
-        # We should wrap a line where the second word is overlong.
-        self.n._line(' '.join(['x', LONGWORD, 'y']))
-        self.assertEqual(' $\n'.join(['x',
-                                      INDENT + LONGWORD,
-                                      INDENT + 'y']) + '\n',
-                         self.out.getvalue())
-
-    def test_comment_wrap(self):
-        # Filenames should not be wrapped
-        self.n.comment('Hello /usr/local/build-tools/bin')
-        self.assertEqual('# Hello\n# /usr/local/build-tools/bin\n',
-                         self.out.getvalue())
-
-    def test_short_words_indented(self):
-        # Test that indent is taking into account when breaking subsequent lines.
-        # The second line should not be '    to tree', as that's longer than the
-        # test layout width of 8.
-        self.n._line('line_one to tree')
-        self.assertEqual('''\
-line_one $
-    to $
-    tree
-''',
-                         self.out.getvalue())
-
-    def test_few_long_words_indented(self):
-        # Check wrapping in the presence of indenting.
-        self.n._line(' '.join(['x', LONGWORD, 'y']), indent=1)
-        self.assertEqual(' $\n'.join(['  ' + 'x',
-                                      '  ' + INDENT + LONGWORD,
-                                      '  ' + INDENT + 'y']) + '\n',
-                         self.out.getvalue())
-
-    def test_escaped_spaces(self):
-        self.n._line(' '.join(['x', LONGWORDWITHSPACES, 'y']))
-        self.assertEqual(' $\n'.join(['x',
-                                      INDENT + LONGWORDWITHSPACES,
-                                      INDENT + 'y']) + '\n',
-                         self.out.getvalue())
-
-    def test_fit_many_words(self):
-        self.n = ninja_syntax.Writer(self.out, width=78)
-        self.n._line('command = cd ../../chrome; python ../tools/grit/grit/format/repack.py ../out/Debug/obj/chrome/chrome_dll.gen/repack/theme_resources_large.pak ../out/Debug/gen/chrome/theme_resources_large.pak', 1)
-        self.assertEqual('''\
-  command = cd ../../chrome; python ../tools/grit/grit/format/repack.py $
-      ../out/Debug/obj/chrome/chrome_dll.gen/repack/theme_resources_large.pak $
-      ../out/Debug/gen/chrome/theme_resources_large.pak
-''',
-                         self.out.getvalue())
-
-    def test_leading_space(self):
-        self.n = ninja_syntax.Writer(self.out, width=14)  # force wrapping
-        self.n.variable('foo', ['', '-bar', '-somethinglong'], 0)
-        self.assertEqual('''\
-foo = -bar $
-    -somethinglong
-''',
-                         self.out.getvalue())
-
-    def test_embedded_dollar_dollar(self):
-        self.n = ninja_syntax.Writer(self.out, width=15)  # force wrapping
-        self.n.variable('foo', ['a$$b', '-somethinglong'], 0)
-        self.assertEqual('''\
-foo = a$$b $
-    -somethinglong
-''',
-                         self.out.getvalue())
-
-    def test_two_embedded_dollar_dollars(self):
-        self.n = ninja_syntax.Writer(self.out, width=17)  # force wrapping
-        self.n.variable('foo', ['a$$b', '-somethinglong'], 0)
-        self.assertEqual('''\
-foo = a$$b $
-    -somethinglong
-''',
-                         self.out.getvalue())
-
-    def test_leading_dollar_dollar(self):
-        self.n = ninja_syntax.Writer(self.out, width=14)  # force wrapping
-        self.n.variable('foo', ['$$b', '-somethinglong'], 0)
-        self.assertEqual('''\
-foo = $$b $
-    -somethinglong
-''',
-                         self.out.getvalue())
-
-    def test_trailing_dollar_dollar(self):
-        self.n = ninja_syntax.Writer(self.out, width=14)  # force wrapping
-        self.n.variable('foo', ['a$$', '-somethinglong'], 0)
-        self.assertEqual('''\
-foo = a$$ $
-    -somethinglong
-''',
-                         self.out.getvalue())
-
-class TestBuild(unittest.TestCase):
-    def setUp(self):
-        self.out = StringIO()
-        self.n = ninja_syntax.Writer(self.out)
-
-    def test_variables_dict(self):
-        self.n.build('out', 'cc', 'in', variables={'name': 'value'})
-        self.assertEqual('''\
-build out: cc in
-  name = value
-''',
-                         self.out.getvalue())
-
-    def test_variables_list(self):
-        self.n.build('out', 'cc', 'in', variables=[('name', 'value')])
-        self.assertEqual('''\
-build out: cc in
-  name = value
-''',
-                         self.out.getvalue())
-
-    def test_implicit_outputs(self):
-        self.n.build('o', 'cc', 'i', implicit_outputs='io')
-        self.assertEqual('''\
-build o | io: cc i
-''',
-                         self.out.getvalue())
-
-class TestExpand(unittest.TestCase):
-    def test_basic(self):
-        vars = {'x': 'X'}
-        self.assertEqual('foo', ninja_syntax.expand('foo', vars))
-
-    def test_var(self):
-        vars = {'xyz': 'XYZ'}
-        self.assertEqual('fooXYZ', ninja_syntax.expand('foo$xyz', vars))
-
-    def test_vars(self):
-        vars = {'x': 'X', 'y': 'YYY'}
-        self.assertEqual('XYYY', ninja_syntax.expand('$x$y', vars))
-
-    def test_space(self):
-        vars = {}
-        self.assertEqual('x y z', ninja_syntax.expand('x$ y$ z', vars))
-
-    def test_locals(self):
-        vars = {'x': 'a'}
-        local_vars = {'x': 'b'}
-        self.assertEqual('a', ninja_syntax.expand('$x', vars))
-        self.assertEqual('b', ninja_syntax.expand('$x', vars, local_vars))
-
-    def test_double(self):
-        self.assertEqual('a b$c', ninja_syntax.expand('a$ b$$c', {}))
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/misc/oss-fuzz/build.sh b/misc/oss-fuzz/build.sh
deleted file mode 100644
index 4328feb..0000000
--- a/misc/oss-fuzz/build.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/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
deleted file mode 100644
index 7b513be..0000000
--- a/misc/oss-fuzz/sample_ninja_build
+++ /dev/null
@@ -1,14 +0,0 @@
-# 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
deleted file mode 100755
index 18c84d9..0000000
--- a/misc/output_test.py
+++ /dev/null
@@ -1,168 +0,0 @@
-#!/usr/bin/env python3
-
-"""Runs ./ninja and checks if the output is correct.
-
-In order to simulate a smart terminal it uses the 'script' command.
-"""
-
-import os
-import platform
-import subprocess
-import sys
-import tempfile
-import unittest
-
-default_env = dict(os.environ)
-for varname in ('NINJA_STATUS', 'NINJA_STATUS_MAX_COMMANDS', 'NINJA_PERSISTENT_MODE', 'CLICOLOR_FORCE'):
-    if varname in default_env:
-        del default_env[varname]
-
-default_env['TERM'] = ''
-NINJA_PATH = os.path.abspath('./ninja')
-
-def run(build_ninja, flags='', pipe=False, env=default_env):
-    with tempfile.TemporaryDirectory() as d:
-        with open(os.path.join(d, '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, cwd=d, env=env)
-            elif platform.system() == 'Darwin':
-                output = subprocess.check_output(['script', '-q', '/dev/null', 'bash', '-c', ninja_cmd],
-                                                 cwd=d, env=env)
-            else:
-                output = subprocess.check_output(['script', '-qfec', ninja_cmd, '/dev/null'],
-                                                 cwd=d, env=env)
-        except subprocess.CalledProcessError as err:
-            sys.stdout.buffer.write(err.output)
-            raise err
-    final_output = ''
-    for line in output.decode('utf-8').splitlines(True):
-        if len(line) > 0 and line[-1] == '\r':
-            continue
-        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):
-    BUILD_SIMPLE_ECHO = '\n'.join((
-        'rule echo',
-        '  command = printf "do thing"',
-        '  description = echo $out',
-        '',
-        'build a: echo',
-        '',
-    ))
-
-    def test_issue_1418(self):
-        self.assertEqual(run(
-'''rule echo
-  command = sleep $delay && echo $out
-  description = echo $out
-
-build a: echo
-  delay = 3
-build b: echo
-  delay = 2
-build c: echo
-  delay = 1
-''', '-j3'),
-'''[1/3] echo c\x1b[K
-c
-[2/3] echo b\x1b[K
-b
-[3/3] echo a\x1b[K
-a
-''')
-
-    def test_issue_1214(self):
-        print_red = '''rule echo
-  command = printf '\x1b[31mred\x1b[0m'
-  description = echo $out
-
-build a: echo
-'''
-        # Only strip color when ninja's output is piped.
-        self.assertEqual(run(print_red),
-'''[1/1] echo a\x1b[K
-\x1b[31mred\x1b[0m
-''')
-        self.assertEqual(run(print_red, pipe=True),
-'''[1/1] echo a
-red
-''')
-        # Even in verbose mode, colors should still only be stripped when piped.
-        self.assertEqual(run(print_red, flags='-v'),
-'''[1/1] printf '\x1b[31mred\x1b[0m'
-\x1b[31mred\x1b[0m
-''')
-        self.assertEqual(run(print_red, flags='-v', pipe=True),
-'''[1/1] printf '\x1b[31mred\x1b[0m'
-red
-''')
-
-        # CLICOLOR_FORCE=1 can be used to disable escape code stripping.
-        env = default_env.copy()
-        env['CLICOLOR_FORCE'] = '1'
-        self.assertEqual(run(print_red, pipe=True, env=env),
-'''[1/1] echo a
-\x1b[31mred\x1b[0m
-''')
-
-    def test_issue_1966(self):
-        self.assertEqual(run(
-'''rule cat
-  command = cat $rspfile $rspfile > $out
-  rspfile = cat.rsp
-  rspfile_content = a b c
-
-build a: cat
-''', '-j3'),
-'''[1/1] cat cat.rsp cat.rsp > a\x1b[K
-''')
-
-
-    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')
-        self.assertEqual(run('', pipe=True), 'ninja: no work to do.\n')
-
-    def test_ninja_status_default(self):
-        'Do we show the default status by default?'
-        self.assertEqual(run(Output.BUILD_SIMPLE_ECHO), '[1/1] echo a\x1b[K\ndo thing\n')
-
-    def test_ninja_status_quiet(self):
-        'Do we suppress the status information when --quiet is specified?'
-        output = run(Output.BUILD_SIMPLE_ECHO, flags='--quiet')
-        self.assertEqual(output, 'do thing\n')
-
-    def test_entering_directory_on_stdout(self):
-        output = run(Output.BUILD_SIMPLE_ECHO, flags='-C$PWD', pipe=True)
-        self.assertEqual(output.splitlines()[0][:25], "ninja: Entering directory")
-
-    def test_tool_inputs(self):
-        plan = '''
-rule cat
-  command = cat $in $out
-build out1 : cat in1
-build out2 : cat in2 out1
-build out3 : cat out2 out1 | implicit || order_only
-'''
-        self.assertEqual(run(plan, flags='-t inputs out3'),
-'''implicit
-in1
-in2
-order_only
-out1
-out2
-''')
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/misc/packaging/ninja.spec b/misc/packaging/ninja.spec
deleted file mode 100644
index 36e5181..0000000
--- a/misc/packaging/ninja.spec
+++ /dev/null
@@ -1,42 +0,0 @@
-Summary: Ninja is a small build system with a focus on speed.
-Name: ninja
-Version: %{ver}
-Release: %{rel}%{?dist}
-Group: Development/Tools
-License: Apache 2.0
-URL: https://github.com/ninja-build/ninja
-Source0: %{name}-%{version}-%{rel}.tar.gz
-BuildRoot: %{_tmppath}/%{name}-%{version}-%{rel}
-
-BuildRequires: asciidoc
-
-%description
-Ninja is yet another build system. It takes as input the interdependencies of files (typically source code and output executables) and
-orchestrates building them, quickly.
-
-Ninja joins a sea of other build systems. Its distinguishing goal is to be fast. It is born from my work on the Chromium browser project,
-which has over 30,000 source files and whose other build systems (including one built from custom non-recursive Makefiles) can take ten
-seconds to start building after changing one file. Ninja is under a second.
-
-%prep
-%setup -q -n %{name}-%{version}-%{rel}
-
-%build
-echo Building..
-./configure.py --bootstrap
-./ninja manual
-
-%install
-mkdir -p %{buildroot}%{_bindir} %{buildroot}%{_docdir}
-cp -p ninja %{buildroot}%{_bindir}/
-
-%files
-%defattr(-, root, root)
-%doc COPYING README.md doc/manual.html
-%{_bindir}/*
-
-%clean
-rm -rf %{buildroot}
-
-#The changelog is built automatically from Git history
-%changelog
diff --git a/misc/packaging/rpmbuild.sh b/misc/packaging/rpmbuild.sh
deleted file mode 100755
index 9b74c65..0000000
--- a/misc/packaging/rpmbuild.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash
-
-echo Building ninja RPMs..
-GITROOT=$(git rev-parse --show-toplevel)
-cd $GITROOT
-
-VER=1.0
-REL=$(git rev-parse --short HEAD)git
-RPMTOPDIR=$GITROOT/rpm-build
-echo "Ver: $VER, Release: $REL"
-
-# Create tarball
-mkdir -p $RPMTOPDIR/{SOURCES,SPECS}
-git archive --format=tar --prefix=ninja-${VER}-${REL}/ HEAD | gzip -c > $RPMTOPDIR/SOURCES/ninja-${VER}-${REL}.tar.gz
-
-# Convert git log to RPM's ChangeLog format (shown with rpm -qp --changelog <rpm file>)
-sed -e "s/%{ver}/$VER/" -e "s/%{rel}/$REL/" misc/packaging/ninja.spec > $RPMTOPDIR/SPECS/ninja.spec
-git log --format="* %cd %aN%n- (%h) %s%d%n" --date=local | sed -r 's/[0-9]+:[0-9]+:[0-9]+ //' >> $RPMTOPDIR/SPECS/ninja.spec
-
-# Build SRC and binary RPMs
-rpmbuild    --quiet                       \
-            --define "_topdir $RPMTOPDIR" \
-            --define "_rpmdir $PWD"       \
-            --define "_srcrpmdir $PWD"    \
-            --define '_rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm' \
-            -ba $RPMTOPDIR/SPECS/ninja.spec &&
-
-rm -rf $RPMTOPDIR &&
-echo Done
diff --git a/misc/persistent_mode_test.py b/misc/persistent_mode_test.py
deleted file mode 100755
index f526d99..0000000
--- a/misc/persistent_mode_test.py
+++ /dev/null
@@ -1,254 +0,0 @@
-#!/usr/bin/env python3
-
-"""Runs ./ninja in persistent mode and checks if the output is correct.
-
-In order to simulate a smart terminal it uses the 'script' command.
-"""
-import os
-import platform
-import subprocess
-import sys
-import tempfile
-import unittest
-
-default_env = dict(os.environ)
-for varname in ("NINJA_STATUS", "NINJA_STATUS_MAX_COMMANDS", "CLICOLOR_FORCE"):
-    if varname in default_env:
-        del default_env[varname]
-
-default_env["TERM"] = ""
-default_env["NINJA_PERSISTENT_MODE"] = "1"
-default_env["DEBUG_PERSISTENT_SERVICE_LOG_FILE"] = "/tmp/DLOG"
-default_env["NINJA_PERSISTENT_LOG_FILE"] = "/tmp/ELOG"
-NINJA_PATH = os.path.abspath("./ninja")
-
-
-class NinjaPersistentInstance(object):
-    def __init__(self, build_ninja: str):
-        """Initialize instance.
-
-        This creates a temporary directory, cd to it, then writes a build.ninja
-        plan in it that will be used by future run() calls.
-
-        Args:
-           build_ninja: The content of a "build.ninja" file
-        """
-        self._server_running = False
-        self._tempdir = tempfile.TemporaryDirectory(ignore_cleanup_errors=True)
-        self._dir = self._tempdir.name
-        self.write_build_ninja(build_ninja)
-
-    def write_build_ninja(self, build_ninja):
-        """Rewrite the build.ninja file with new content."""
-        self.write_file("build.ninja", build_ninja)
-
-    def write_file(self, path, content):
-        with open(os.path.join(self._dir, path), "w") as f:
-            f.write(content)
-            f.flush()
-
-    def close(self):
-        """Close the instance, ensuring the persistent server is stopped."""
-        if self._server_running:
-            self.run(flags="-t server stop")
-            self._server_running = False
-
-        if self._tempdir:
-            self._tempdir.cleanup()
-            self._tempdir = None
-
-    def server_status(self):
-        return self.run(flags="-t server status")
-
-    def has_server(self):
-        status = self.server_status()
-        return status == f"server is running for {self._dir}\n"
-
-    def server_pid(self):
-        """Return PID of server process, or -1 if there is none."""
-        return int(self.run(flags="-t server pid").strip())
-
-    def run(self, flags="", pipe=False, env=default_env):
-        """Run a Ninja command."""
-        self._server_running = True
-        ninja_cmd = "{} {}".format(NINJA_PATH, flags).strip()
-        try:
-            if pipe:
-                output = subprocess.check_output(
-                    ninja_cmd, shell=True, cwd=self._dir, env=env
-                )
-            elif platform.system() == "Darwin":
-                output = subprocess.check_output(
-                    ["script", "-q", "/dev/null", "bash", "-c", ninja_cmd],
-                    cwd=self._dir,
-                    env=env,
-                )
-            else:
-                output = subprocess.check_output(
-                    ["script", "-qfec", ninja_cmd, "/dev/null"], cwd=self._dir, env=env
-                )
-        except subprocess.CalledProcessError as err:
-            sys.stdout.buffer.write(err.output)
-            raise err
-
-        final_output = ""
-        for line in output.decode("utf-8").splitlines(True):
-            if len(line) > 0 and line[-1] == "\r":
-                continue
-            final_output += line.replace("\r", "")
-        return final_output
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, exc_type, exc_val, exc_tb):
-        self.close()
-        return False
-
-
-@unittest.skipIf(
-    platform.system() == "Windows", "These test methods do not work on Windows"
-)
-class Output(unittest.TestCase):
-    BUILD_SIMPLE_ECHO = "\n".join(
-        (
-            "rule echo",
-            '  command = printf "do thing"',
-            "  description = echo $out",
-            "",
-            "build a: echo",
-            "",
-        )
-    )
-
-    def test_start_persistent_server(self):
-        with NinjaPersistentInstance(Output.BUILD_SIMPLE_ECHO) as ninja:
-            self.assertFalse(ninja.has_server())
-            self.assertEqual(ninja.run(), "[1/1] echo a\x1b[K\ndo thing\n")
-            self.assertTrue(ninja.has_server())
-            server_pid = ninja.server_pid()
-            self.assertNotEqual(server_pid, -1)
-            self.assertEqual(ninja.run(), "[1/1] echo a\x1b[K\ndo thing\n")
-            self.assertTrue(ninja.has_server())
-            self.assertEqual(server_pid, ninja.server_pid())
-            self.assertEqual(ninja.run(), "[1/1] echo a\x1b[K\ndo thing\n")
-            self.assertTrue(ninja.has_server())
-            self.assertEqual(server_pid, ninja.server_pid())
-
-    def test_stop_persistent_server(self):
-        with NinjaPersistentInstance(Output.BUILD_SIMPLE_ECHO) as ninja:
-            self.assertFalse(ninja.has_server())
-            self.assertEqual(ninja.run(), "[1/1] echo a\x1b[K\ndo thing\n")
-            self.assertTrue(ninja.has_server())
-
-            server_pid = ninja.server_pid()
-            self.assertNotEqual(server_pid, -1)
-
-            ninja.run(flags="-t server stop")
-            self.assertFalse(ninja.has_server())
-            self.assertEqual(ninja.server_pid(), -1)
-
-            self.assertEqual(ninja.run(), "[1/1] echo a\x1b[K\ndo thing\n")
-            self.assertTrue(ninja.has_server())
-            new_server_pid = ninja.server_pid()
-            self.assertNotEqual(new_server_pid, -1)
-            self.assertNotEqual(new_server_pid, server_pid)
-
-            self.assertEqual(ninja.run(), "[1/1] echo a\x1b[K\ndo thing\n")
-            self.assertTrue(ninja.has_server())
-            self.assertEqual(new_server_pid, ninja.server_pid())
-
-    def test_ninja_status(self):
-        env = default_env.copy()
-        env["NINJA_STATUS"] = "STATUS [%f/%t] "
-        with NinjaPersistentInstance(Output.BUILD_SIMPLE_ECHO) as ninja:
-            self.assertFalse(ninja.has_server())
-            non_persistent_env = env.copy()
-            non_persistent_env["NINJA_PERSISTENT_MODE"] = "0"
-            self.assertEqual(
-                ninja.run(env=non_persistent_env),
-                "STATUS [1/1] echo a\x1b[K\ndo thing\n",
-            )
-            self.assertFalse(ninja.has_server())
-
-            env["NINJA_PERSISTENT_STATUS"] = "1"
-            self.assertEqual(
-                ninja.run(env=env), "STATUS [1/1] echo a\x1b[K\ndo thing\n"
-            )
-            self.assertTrue(ninja.has_server())
-
-            env["NINJA_STATUS"] = "NOPE"
-            self.assertEqual(ninja.run(env=env), "NOPEecho a\x1b[K\ndo thing\n")
-            self.assertTrue(ninja.has_server())
-
-    def test_environment_variables(self):
-        build_ninja = """
-rule print_var
-  command = printf "%s=[%s]" $varname $$$varname
-  description = print $varname
-
-build foo: print_var
-  varname = foo
-"""
-        env = default_env.copy()
-        if "foo" in env:
-            del env["foo"]
-
-        with NinjaPersistentInstance(build_ninja) as ninja:
-            self.assertFalse(ninja.has_server())
-            self.assertEqual(ninja.run(env=env), "[1/1] print foo\x1b[K\nfoo=[]\n")
-            self.assertTrue(ninja.has_server())
-            self.assertEqual(ninja.run(env=env), "[1/1] print foo\x1b[K\nfoo=[]\n")
-            self.assertTrue(ninja.has_server())
-            env["foo"] = "FOO"
-            self.assertEqual(ninja.run(env=env), "[1/1] print foo\x1b[K\nfoo=[FOO]\n")
-            self.assertTrue(ninja.has_server())
-            del env["foo"]
-            self.assertEqual(ninja.run(env=env), "[1/1] print foo\x1b[K\nfoo=[]\n")
-            self.assertTrue(ninja.has_server())
-
-    def test_server_restart_on_input_file_change(self):
-        with NinjaPersistentInstance(Output.BUILD_SIMPLE_ECHO) as ninja:
-            self.assertFalse(ninja.has_server())
-            self.assertEqual(ninja.run(), "[1/1] echo a\x1b[K\ndo thing\n")
-            self.assertTrue(ninja.has_server())
-
-            ninja.write_build_ninja(Output.BUILD_SIMPLE_ECHO)
-            server_pid = ninja.server_pid()
-
-            self.assertEqual(ninja.run(), "[1/1] echo a\x1b[K\ndo thing\n")
-            self.assertTrue(ninja.has_server())
-            self.assertNotEqual(server_pid, ninja.server_pid())
-
-    def test_server_restart_on_generator_run(self):
-        build_ninja = """
-rule echo
-  command = printf "do thing"
-  description = echo $out
-
-build a: echo
-
-rule regen
-  command = cp input.depfile $out.d && touch build.ninja
-  depfile = $out.d
-  generator = 1
-
-build build.ninja: regen
-"""
-        with NinjaPersistentInstance(build_ninja) as ninja:
-            # Launch the server.
-            ninja.write_file("CMakeLists.txt", "# Fake original config file")
-            ninja.write_file("input.depfile", "build.ninja: CMakeLists.txt")
-            self.assertFalse(ninja.has_server())
-            ninja.run(flags="a")
-            self.assertTrue(ninja.has_server())
-            server_pid = ninja.server_pid()
-
-            ninja.write_file("CMakeLists.txt", "# Fake update to config file")
-            ninja.run(flags="a")
-            self.assertTrue(ninja.has_server())
-            self.assertNotEqual(ninja.server_pid(), server_pid)
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/misc/write_fake_manifests.py b/misc/write_fake_manifests.py
deleted file mode 100755
index bf9cf7d..0000000
--- a/misc/write_fake_manifests.py
+++ /dev/null
@@ -1,272 +0,0 @@
-#!/usr/bin/env python3
-
-"""Writes large manifest files, for manifest parser performance testing.
-
-The generated manifest files are (eerily) similar in appearance and size to the
-ones used in the Chromium project.
-
-Usage:
-  python misc/write_fake_manifests.py outdir  # Will run for about 5s.
-
-The program contains a hardcoded random seed, so it will generate the same
-output every time it runs.  By changing the seed, it's easy to generate many
-different sets of manifest files.
-"""
-
-import argparse
-import contextlib
-import os
-import random
-import sys
-
-import ninja_syntax
-
-
-def paretoint(avg, alpha):
-    """Returns a random integer that's avg on average, following a power law.
-    alpha determines the shape of the power curve. alpha has to be larger
-    than 1. The closer alpha is to 1, the higher the variation of the returned
-    numbers."""
-    return int(random.paretovariate(alpha) * avg / (alpha / (alpha - 1)))
-
-
-# Based on http://neugierig.org/software/chromium/class-name-generator.html
-def moar(avg_options, p_suffix):
-    kStart = ['render', 'web', 'browser', 'tab', 'content', 'extension', 'url',
-              'file', 'sync', 'content', 'http', 'profile']
-    kOption = ['view', 'host', 'holder', 'container', 'impl', 'ref',
-               'delegate', 'widget', 'proxy', 'stub', 'context',
-               'manager', 'master', 'watcher', 'service', 'file', 'data',
-               'resource', 'device', 'info', 'provider', 'internals', 'tracker',
-               'api', 'layer']
-    kOS = ['win', 'mac', 'aura', 'linux', 'android', 'unittest', 'browsertest']
-    num_options = min(paretoint(avg_options, alpha=4), 5)
-    # The original allows kOption to repeat as long as no consecutive options
-    # repeat.  This version doesn't allow any option repetition.
-    name = [random.choice(kStart)] + random.sample(kOption, num_options)
-    if random.random() < p_suffix:
-        name.append(random.choice(kOS))
-    return '_'.join(name)
-
-
-class GenRandom(object):
-    def __init__(self, src_dir):
-        self.seen_names = set([None])
-        self.seen_defines = set([None])
-        self.src_dir = src_dir
-
-    def _unique_string(self, seen, avg_options=1.3, p_suffix=0.1):
-        s = None
-        while s in seen:
-            s = moar(avg_options, p_suffix)
-        seen.add(s)
-        return s
-
-    def _n_unique_strings(self, n):
-        seen = set([None])
-        return [self._unique_string(seen, avg_options=3, p_suffix=0.4)
-                for _ in range(n)]
-
-    def target_name(self):
-        return self._unique_string(p_suffix=0, seen=self.seen_names)
-
-    def path(self):
-        return os.path.sep.join([
-            self._unique_string(self.seen_names, avg_options=1, p_suffix=0)
-            for _ in range(1 + paretoint(0.6, alpha=4))])
-
-    def src_obj_pairs(self, path, name):
-        num_sources = paretoint(55, alpha=2) + 1
-        return [(os.path.join(self.src_dir, path, s + '.cc'),
-                 os.path.join('obj', path, '%s.%s.o' % (name, s)))
-                for s in self._n_unique_strings(num_sources)]
-
-    def defines(self):
-        return [
-            '-DENABLE_' + self._unique_string(self.seen_defines).upper()
-            for _ in range(paretoint(20, alpha=3))]
-
-
-LIB, EXE = 0, 1
-class Target(object):
-    def __init__(self, gen, kind):
-        self.name = gen.target_name()
-        self.dir_path = gen.path()
-        self.ninja_file_path = os.path.join(
-            'obj', self.dir_path, self.name + '.ninja')
-        self.src_obj_pairs = gen.src_obj_pairs(self.dir_path, self.name)
-        if kind == LIB:
-            self.output = os.path.join('lib' + self.name + '.a')
-        elif kind == EXE:
-            self.output = os.path.join(self.name)
-        self.defines = gen.defines()
-        self.deps = []
-        self.kind = kind
-        self.has_compile_depends = random.random() < 0.4
-
-
-def write_target_ninja(ninja, target, src_dir):
-    compile_depends = None
-    if target.has_compile_depends:
-      compile_depends = os.path.join(
-          'obj', target.dir_path, target.name + '.stamp')
-      ninja.build(compile_depends, 'stamp', target.src_obj_pairs[0][0])
-      ninja.newline()
-
-    ninja.variable('defines', target.defines)
-    ninja.variable('includes', '-I' + src_dir)
-    ninja.variable('cflags', ['-Wall', '-fno-rtti', '-fno-exceptions'])
-    ninja.newline()
-
-    for src, obj in target.src_obj_pairs:
-        ninja.build(obj, 'cxx', src, implicit=compile_depends)
-    ninja.newline()
-
-    deps = [dep.output for dep in target.deps]
-    libs = [dep.output for dep in target.deps if dep.kind == LIB]
-    if target.kind == EXE:
-        ninja.variable('libs', libs)
-        if sys.platform == "darwin":
-            ninja.variable('ldflags', '-Wl,-pie')
-    link = { LIB: 'alink', EXE: 'link'}[target.kind]
-    ninja.build(target.output, link, [obj for _, obj in target.src_obj_pairs],
-                implicit=deps)
-
-
-def write_sources(target, root_dir):
-    need_main = target.kind == EXE
-
-    includes = []
-
-    # Include siblings.
-    for cc_filename, _ in target.src_obj_pairs:
-        h_filename = os.path.basename(os.path.splitext(cc_filename)[0] + '.h')
-        includes.append(h_filename)
-
-    # Include deps.
-    for dep in target.deps:
-        for cc_filename, _ in dep.src_obj_pairs:
-            h_filename = os.path.basename(
-                os.path.splitext(cc_filename)[0] + '.h')
-            includes.append("%s/%s" % (dep.dir_path, h_filename))
-
-    for cc_filename, _ in target.src_obj_pairs:
-        cc_path = os.path.join(root_dir, cc_filename)
-        h_path = os.path.splitext(cc_path)[0] + '.h'
-        namespace = os.path.basename(target.dir_path)
-        class_ = os.path.splitext(os.path.basename(cc_filename))[0]
-        try:
-            os.makedirs(os.path.dirname(cc_path))
-        except OSError:
-            pass
-
-        with open(h_path, 'w') as f:
-            f.write('namespace %s { struct %s { %s(); }; }' % (namespace,
-                                                               class_, class_))
-        with open(cc_path, 'w') as f:
-            for include in includes:
-                f.write('#include "%s"\n' % include)
-            f.write('\n')
-            f.write('namespace %s { %s::%s() {} }' % (namespace,
-                                                      class_, class_))
-
-            if need_main:
-                f.write('int main(int argc, char **argv) {}\n')
-                need_main = False
-
-def write_master_ninja(master_ninja, targets):
-    """Writes master build.ninja file, referencing all given subninjas."""
-    master_ninja.variable('cxx', 'c++')
-    master_ninja.variable('ld', '$cxx')
-    if sys.platform == 'darwin':
-        master_ninja.variable('alink', 'libtool -static')
-    else:
-        master_ninja.variable('alink', 'ar rcs')
-    master_ninja.newline()
-
-    master_ninja.pool('link_pool', depth=4)
-    master_ninja.newline()
-
-    master_ninja.rule('cxx', description='CXX $out',
-      command='$cxx -MMD -MF $out.d $defines $includes $cflags -c $in -o $out',
-      depfile='$out.d', deps='gcc')
-    master_ninja.rule('alink', description='ARCHIVE $out',
-      command='rm -f $out && $alink -o $out $in')
-    master_ninja.rule('link', description='LINK $out', pool='link_pool',
-      command='$ld $ldflags -o $out $in $libs')
-    master_ninja.rule('stamp', description='STAMP $out', command='touch $out')
-    master_ninja.newline()
-
-    for target in targets:
-        master_ninja.subninja(target.ninja_file_path)
-    master_ninja.newline()
-
-    master_ninja.comment('Short names for targets.')
-    for target in targets:
-        if target.name != target.output:
-            master_ninja.build(target.name, 'phony', target.output)
-    master_ninja.newline()
-
-    master_ninja.build('all', 'phony', [target.output for target in targets])
-    master_ninja.default('all')
-
-
-@contextlib.contextmanager
-def FileWriter(path):
-    """Context manager for a ninja_syntax object writing to a file."""
-    try:
-        os.makedirs(os.path.dirname(path))
-    except OSError:
-        pass
-    f = open(path, 'w')
-    yield ninja_syntax.Writer(f)
-    f.close()
-
-
-def random_targets(num_targets, src_dir):
-    gen = GenRandom(src_dir)
-
-    # N-1 static libraries, and 1 executable depending on all of them.
-    targets = [Target(gen, LIB) for i in range(num_targets - 1)]
-    for i in range(len(targets)):
-        targets[i].deps = [t for t in targets[0:i] if random.random() < 0.05]
-
-    last_target = Target(gen, EXE)
-    last_target.deps = targets[:]
-    last_target.src_obj_pairs = last_target.src_obj_pairs[0:10]  # Trim.
-    targets.append(last_target)
-    return targets
-
-
-def main():
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-s', '--sources', nargs="?", const="src",
-        help='write sources to directory (relative to output directory)')
-    parser.add_argument('-t', '--targets', type=int, default=1500,
-                        help='number of targets (default: 1500)')
-    parser.add_argument('-S', '--seed', type=int, help='random seed',
-                        default=12345)
-    parser.add_argument('outdir', help='output directory')
-    args = parser.parse_args()
-    root_dir = args.outdir
-
-    random.seed(args.seed)
-
-    do_write_sources = args.sources is not None
-    src_dir = args.sources if do_write_sources else "src"
-
-    targets = random_targets(args.targets, src_dir)
-    for target in targets:
-        with FileWriter(os.path.join(root_dir, target.ninja_file_path)) as n:
-            write_target_ninja(n, target, src_dir)
-
-        if do_write_sources:
-            write_sources(target, root_dir)
-
-    with FileWriter(os.path.join(root_dir, 'build.ninja')) as master_ninja:
-        master_ninja.width = 120
-        write_master_ninja(master_ninja, targets)
-
-
-if __name__ == '__main__':
-    sys.exit(main())
diff --git a/misc/zsh-completion b/misc/zsh-completion
deleted file mode 100644
index d439df3..0000000
--- a/misc/zsh-completion
+++ /dev/null
@@ -1,75 +0,0 @@
-#compdef ninja
-# 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.
-
-# Add the following to your .zshrc to tab-complete ninja targets
-#   fpath=(path/to/ninja/misc/zsh-completion $fpath)
-
-(( $+functions[_ninja-get-targets] )) || _ninja-get-targets() {
-  dir="."
-  if [ -n "${opt_args[-C]}" ];
-  then
-    eval dir="${opt_args[-C]}"
-  fi
-  file="build.ninja"
-  if [ -n "${opt_args[-f]}" ];
-  then
-    eval file="${opt_args[-f]}"
-  fi
-  targets_command="ninja -f \"${file}\" -C \"${dir}\" -t targets all"
-  eval ${targets_command} 2>/dev/null | cut -d: -f1
-}
-
-(( $+functions[_ninja-get-tools] )) || _ninja-get-tools() {
-  # remove the first line; remove the leading spaces; replace spaces with colon
-  ninja -t list 2> /dev/null | sed -e '1d;s/^ *//;s/ \+/:/'
-}
-
-(( $+functions[_ninja-get-modes] )) || _ninja-get-modes() {
-  # remove the first line; remove the last line; remove the leading spaces; replace spaces with colon
-  ninja -d list 2> /dev/null | sed -e '1d;$d;s/^ *//;s/ \+/:/'
-}
-
-(( $+functions[_ninja-modes] )) || _ninja-modes() {
-  local -a modes
-  modes=(${(fo)"$(_ninja-get-modes)"})
-  _describe 'modes' modes
-}
-
-(( $+functions[_ninja-tools] )) || _ninja-tools() {
-  local -a tools
-  tools=(${(fo)"$(_ninja-get-tools)"})
-  _describe 'tools' tools
-}
-
-(( $+functions[_ninja-targets] )) || _ninja-targets() {
-  local -a targets
-  targets=(${(fo)"$(_ninja-get-targets)"})
-  _describe 'targets' targets
-}
-
-_arguments \
-  '(- *)'{-h,--help}'[Show help]' \
-  '(- *)--version[Print ninja version]' \
-  '-C+[Change to directory before doing anything else]:directories:_directories' \
-  '-f+[Specify input build file (default=build.ninja)]:files:_files' \
-  '-j+[Run N jobs in parallel (default=number of CPUs available)]:number of jobs' \
-  '-l+[Do not start new jobs if the load average is greater than N]:number of jobs' \
-  '-k+[Keep going until N jobs fail (default=1)]:number of jobs' \
-  '-n[Dry run (do not run commands but act like they succeeded)]' \
-  '(-v --verbose --quiet)'{-v,--verbose}'[Show all command lines while building]' \
-  "(-v --verbose --quiet)--quiet[Don't show progress status, just command output]" \
-  '-d+[Enable debugging (use -d list to list modes)]:modes:_ninja-modes' \
-  '-t+[Run a subtool (use -t list to list subtools)]:tools:_ninja-tools' \
-  '*::targets:_ninja-targets'
diff --git a/src/async_loop-posix.h b/src/async_loop-posix.h
deleted file mode 100644
index 0bc517e..0000000
--- a/src/async_loop-posix.h
+++ /dev/null
@@ -1,840 +0,0 @@
-// Copyright 2023 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_ASYNC_LOOP_POSIX_H
-#define NINJA_ASYNC_LOOP_POSIX_H
-
-// Posix implementation of the AsyncLoop class.
-// This contains specialized code paths for Linux ppoll() and MacOS kqueue()
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <signal.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#ifdef USE_KQUEUE
-#include <sys/event.h>
-#endif
-
-#include <algorithm>
-#include <unordered_map>
-
-#include "async_loop.h"
-#include "async_loop_timers.h"
-#include "interrupt_handling.h"
-#include "metrics.h"  // For GetTimeMillis()
-#include "util.h"     // For Fatal() and Win32Fatal().
-
-#ifdef USE_KQUEUE
-// The know state of a kqueue read or write filter for a given file descriptor.
-// Unknown means that the kernel queue does not know about this filter yet.
-enum class KqueueFilterState {
-  Unknown = 0,
-  Disabled,
-  Enabled,
-};
-#endif  // USE_KQUEUE
-
-class AsyncHandle::State {
- public:
-  enum class Kind {
-    None = 0,
-    Read,
-    Write,
-    Connect,
-    Accept,
-  };
-
-  // Constructors.
-  explicit State(AsyncLoop& async_loop) : async_loop_(async_loop) {}
-
-  State(IpcHandle handle, AsyncLoop& async_loop,
-        AsyncHandle::Callback&& callback)
-      : fd_(std::move(handle)), callback_(std::move(callback)),
-        async_loop_(async_loop) {
-    if (fd_)
-      async_loop_.AttachHandle(this);
-  }
-
-  // Destructor. Note that this type is unmoveable due to Win32
-  // requirements.
-  ~State() {
-    if (fd_)
-      async_loop_.DetachHandle(this);
-  }
-
-  // Disallow copy operations. Even though this is implied by
-  // the use of moveable-only fields like |fd_|.
-  State(const State&) = delete;
-  State& operator=(const State&) = delete;
-
-  // Disallow move operations. The address of these instances are recorded
-  // in the |AsyncLoop::Impl::watches_| data structure.
-  State(State&&) noexcept = delete;
-  State& operator=(State&&) noexcept = delete;
-
-  // Return AsyncLoop instance this instance belongs to.
-  AsyncLoop& async_loop() const { return async_loop_; }
-
-  // Return AsyncLoop implementation instance.
-  AsyncLoop::Impl& loop() const { return *async_loop_.impl_; }
-
-  // Return file descriptor.
-  int fd() const { return fd_.native_handle(); }
-  int native_handle() const { return fd(); }
-
-  // Return true if the handle for this instnace is valid.
-  bool is_valid() const { return !!fd_; }
-
-  // Release the native handle for this instance, making it invalid.
-  int ReleaseHandle() {
-    Reset(Kind::None);
-    if (fd_)
-      async_loop_.DetachHandle(this);
-    return fd_.ReleaseNativeHandle();
-  }
-
-  // Is an asynchronous operation running?
-  bool IsRunning() const { return kind_ != Kind::None && !completed_; }
-
-  // Cancel current asynchronous operation, if any.
-  void Cancel() {
-    if (kind_ != Kind::None) {
-      async_loop_.CancelHandle(this);
-      Reset(Kind::None);
-    }
-  }
-
-  // Reset the callback.
-  void ResetCallback(AsyncHandle::Callback&& cb) { callback_ = std::move(cb); }
-
-  void ResetHandle(IpcHandle handle) {
-    Reset(Kind::None);
-    if (fd_)
-      async_loop_.DetachHandle(this);
-    fd_ = std::move(handle);
-    if (fd_)
-      async_loop_.AttachHandle(this);
-  }
-
-  bool NeedsEvent() const { return !completed_ && kind_ != Kind::None; }
-
-  bool NeedsWriteEvent() const {
-    return !completed_ && (kind_ == Kind::Write || kind_ == Kind::Connect);
-  }
-
-  bool NeedsReadEvent() const {
-    return !completed_ && (kind_ == Kind::Read || kind_ == Kind::Accept);
-  }
-
-  short poll_events() const {
-    if (completed_)
-      return 0;
-    if (kind_ == Kind::Write || kind_ == Kind::Connect)
-      return POLLOUT;
-    if (kind_ == Kind::Read || kind_ == Kind::Accept)
-      return POLLIN | POLLPRI;
-    return 0;
-  }
-
-  short poll_revents() const { return poll_events() | POLLERR | POLLHUP; }
-
-  // Reset state to start a new asynchronous operation. Cancels current one
-  // if any.
-  void Reset(Kind kind = Kind::None) {
-    kind_ = kind;
-    completed_ = false;
-    error_ = 0;
-    buffer_ = nullptr;
-    wanted_size_ = 0;
-    actual_size_ = 0;
-    accept_handle_.Close();
-  }
-
-  void StartRead(void* buffer, size_t size) {
-    Reset(Kind::Read);
-    buffer_ = buffer;
-    wanted_size_ = size;
-    if (!size)
-      completed_ = true;
-    else
-      async_loop().UpdateHandle(this);
-  }
-
-  void StartWrite(const void* buffer, size_t size) {
-    Reset(Kind::Write);
-    buffer_ = const_cast<void*>(buffer);
-    wanted_size_ = size;
-    if (!size)
-      completed_ = true;
-    else
-      async_loop().UpdateHandle(this);
-  }
-
-  void StartConnect() {
-    Reset(Kind::Connect);
-    async_loop().UpdateHandle(this);
-  }
-
-  void StartAccept() {
-    Reset(Kind::Accept);
-    async_loop().UpdateHandle(this);
-  }
-
-  bool OnEvent() {
-    error_ = 0;
-    actual_size_ = 0;
-
-    assert(!completed_);
-    completed_ = true;
-
-    switch (kind_) {
-    case Kind::Read: {
-      int ret;
-      do {
-        ret = ::read(fd_.native_handle(), buffer_, wanted_size_);
-      } while (ret < 0 && errno == EINTR);
-      if (ret < 0) {
-        error_ = errno;
-        if (error_ == EAGAIN || error_ == EWOULDBLOCK) {
-          // A spurious wakeup happened.
-          return false;
-        }
-      } else {
-        actual_size_ = static_cast<size_t>(ret);
-      }
-      break;
-    }
-
-    case Kind::Write: {
-      int ret;
-      do {
-        ret = ::write(fd_.native_handle(), buffer_, wanted_size_);
-      } while (ret < 0 && errno == EINTR);
-      if (ret < 0) {
-        error_ = errno;
-        if (error_ == EAGAIN || error_ == EWOULDBLOCK) {
-          // A spurious wakeup happened.
-          return false;
-        }
-      } else {
-        actual_size_ = static_cast<size_t>(ret);
-      }
-      break;
-    }
-
-    case Kind::Connect: {
-      int so_error =
-          IpcHandle::GetNativeAsyncConnectStatus(fd_.native_handle());
-      if (so_error != 0) {
-        if (so_error == EAGAIN || so_error == EINPROGRESS)
-          return false;
-
-        error_ = so_error;
-      }
-      break;
-    }
-
-    case Kind::Accept: {
-      int ret;
-      do {
-        ret = ::accept(fd_.native_handle(), nullptr, 0);
-      } while (ret < 0 && errno == EINTR);
-      if (ret < 0) {
-        error_ = errno;
-        if (error_ == EAGAIN || error_ == EWOULDBLOCK)
-          return false;
-      } else {
-        accept_handle_ = IpcHandle(ret);
-        // NOTE: On Linux, client handle does not inherit O_NONBLOCK
-        // but it will on BSDs, so portable programs should set the
-        // flag explicitly. TODO(digit).
-      }
-      break;
-    }
-
-    default:
-      assert(false && "Invalid runtime async op type!");
-      return false;
-    }
-    async_loop_.UpdateHandle(this);
-    callback_(error_, actual_size_);
-    return true;
-  }
-
-  IpcHandle TakeAcceptedHandle() { return std::move(accept_handle_); }
-
-  IpcHandle fd_;
-  Kind kind_ = Kind::None;
-  bool completed_ = false;
-#ifdef USE_KQUEUE
-  // These values are used exclusively by AsyncLoop::Impl::Watches
-  KqueueFilterState kqueue_read_filter_ = KqueueFilterState::Unknown;
-  KqueueFilterState kqueue_write_filter_ = KqueueFilterState::Unknown;
-#endif  // USE_KQUEUE
-  int error_ = 0;
-  void* buffer_ = nullptr;
-  size_t wanted_size_ = 0;
-  size_t actual_size_ = 0;
-  AsyncHandle::Callback callback_;
-  IpcHandle accept_handle_;
-  AsyncLoop& async_loop_;
-};
-
-class AsyncLoop::Impl {
-  /// The list of pending AsyncHandle::States that have completed but whose
-  /// Invoke() method wasn't called yet. Identified by their address.
-  struct PendingList : public std::vector<AsyncHandle::State*> {
-    // Remove one async state from the list.
-    bool Remove(AsyncHandle::State* astate) {
-      for (auto it = begin(); it != end(); ++it) {
-        if (*it == astate) {
-          // Order does not matter for this list, so just move last item
-          // to current location to avoid O(n) removal cost.
-          auto it_last = end() - 1;
-          if (it != it_last)
-            *it = *it_last;
-          pop_back();
-          return true;
-        }
-      }
-      return false;
-    }
-  };
-
-  PendingList pending_ops_;
-
-#ifdef USE_KQUEUE
-  class Watches {
-    IpcHandle queue_ = -1;
-    std::vector<AsyncHandle::State*> states_;
-    std::vector<struct kevent> events_;
-
-    static constexpr size_t npos = ~size_t(0);
-
-    size_t FindState(AsyncHandle::State* state) const {
-      size_t result = 0;
-      for (auto it = states_.begin(); it != states_.end(); ++it, ++result) {
-        if (*it == state)
-          return result;
-      }
-      return npos;
-    }
-
-    void InsertIntoQueue(AsyncHandle::State* state) {
-      // Do not create any filter yet, these will be added on demand
-      // during WaitForEvents().
-      state->kqueue_read_filter_ = KqueueFilterState::Unknown;
-      state->kqueue_write_filter_ = KqueueFilterState::Unknown;
-    }
-
-    void RemoveFromQueue(AsyncHandle::State* state) {
-      // Remove the filters directly, instead of delaying the operation
-      // to WaitForEvents().
-      struct kevent events[2];
-      int count = 0;
-      if (state->kqueue_read_filter_ != KqueueFilterState::Unknown) {
-        events[count++] = {
-          static_cast<uintptr_t>(state->fd()),
-          EVFILT_READ,
-          EV_DELETE,
-          0,
-          0,
-          state,
-        };
-      }
-      if (state->kqueue_write_filter_ != KqueueFilterState::Unknown) {
-        events[count++] = {
-          static_cast<uintptr_t>(state->fd()),
-          EVFILT_WRITE,
-          EV_DELETE,
-          0,
-          0,
-          state,
-        };
-      }
-      if (count > 0) {
-        int ret = kevent(queue_.native_handle(), events, count, NULL, 0, NULL);
-        if (ret < 0)
-          ErrnoFatal("kevent.Remove");
-      }
-    }
-
-   public:
-    Watches() : queue_(kqueue()) {
-      if (!queue_)
-        ErrnoFatal("kqueue()");
-    }
-
-    ~Watches() {
-      assert(states_.empty() &&
-             "Destroying AsyncLoop before child AsyncHandle instances!");
-    }
-
-    bool HasWaiters() const {
-      for (const auto* state : states_) {
-        if (state->IsRunning())
-          return true;
-      }
-      return false;
-    }
-
-    void Insert(AsyncHandle::State* state) {
-      assert(FindState(state) == npos && "Async state already in the set!");
-      states_.push_back(state);
-      InsertIntoQueue(state);
-    }
-
-    void Remove(AsyncHandle::State* state) {
-      size_t state_pos = FindState(state);
-      assert(state_pos != npos && "Async state not in the set!");
-      RemoveFromQueue(state);
-      // Order is not important
-      states_[state_pos] = states_.back();
-      states_.pop_back();
-    }
-
-    void Update(AsyncHandle::State* state) {
-      assert(FindState(state) != npos && "Updating unknown async state!");
-      // Do not do anything, changes will be computed on
-      // demand in the next WaitForEvents() call.
-    }
-
-    int WaitForEvents(const struct timespec* ts, PendingList& pending_ops) {
-      events_.resize(2 * states_.size());
-
-      // Compute the changes to send to the kernel.
-      int num_changes = 0;
-      int num_events = 0;
-
-      // Helper function to compute the set of flags to apply to
-      // a given Kqueue filter. Return 0 if there is no change to apply.
-      // Also updates num_events.
-      auto check_filter = [&num_events](KqueueFilterState& filter,
-                                        bool event_needed) -> uint16_t {
-        uint16_t flags = 0;
-        if (event_needed) {
-          num_events++;
-          if (filter != KqueueFilterState::Enabled) {
-            flags = EV_ENABLE | EV_CLEAR |
-                    ((filter == KqueueFilterState::Unknown) ? EV_ADD : 0);
-            filter = KqueueFilterState::Enabled;
-          }
-        } else if (filter == KqueueFilterState::Enabled) {
-          flags = EV_DELETE;
-          filter = KqueueFilterState::Disabled;
-        }
-        return flags;
-      };
-
-      for (auto* state : states_) {
-        uint16_t flags =
-            check_filter(state->kqueue_read_filter_, state->NeedsReadEvent());
-        if (flags) {
-          events_[num_changes++] = {
-            static_cast<uintptr_t>(state->fd()),
-            EVFILT_READ,
-            flags,
-            0,
-            0,
-            state,
-          };
-        }
-
-        flags =
-            check_filter(state->kqueue_write_filter_, state->NeedsWriteEvent());
-        if (flags) {
-          events_[num_changes++] = {
-            static_cast<uintptr_t>(state->fd()),
-            EVFILT_WRITE,
-            flags,
-            0,
-            0,
-            state,
-          };
-        }
-      }
-
-      struct kevent* events = &events_.front();
-      int ret = kevent(queue_.native_handle(), events, num_changes, events,
-                       events_.size(), ts);
-      if (ret < 0) {
-        if (errno != EINTR)
-          ErrnoFatal("kevent.Wait");
-        return -1;
-      }
-
-      // kevent() always returns immediately if the size of the events array
-      // is 0, even if there is a timeout so use pselect() instead.
-      if (ret == 0 && num_events == 0) {
-        int ret = pselect(0, NULL, NULL, NULL, ts, NULL);
-        if (ret < 0 && errno != EINTR)
-          ErrnoFatal("pselect");
-        return ret;
-      }
-
-      struct kevent* event = &events_.front();
-      for (int n = 0; n < ret; ++n, ++event) {
-        auto* state = static_cast<AsyncHandle::State*>(event->udata);
-        assert(state);
-        assert(static_cast<uintptr_t>(state->fd()) == event->ident);
-
-        // Do not try to interpret EV_ERROR here, assume that the OnError()
-        // method will retry the syscall and get the error from it.
-
-        if (event->filter == EVFILT_READ) {
-          assert(state->NeedsReadEvent());
-          assert(state->kqueue_read_filter_ == KqueueFilterState::Enabled);
-          state->kqueue_read_filter_ = KqueueFilterState::Disabled;
-          pending_ops.push_back(state);
-        } else if (event->filter == EVFILT_WRITE) {
-          assert(state->NeedsWriteEvent());
-          assert(state->kqueue_write_filter_ == KqueueFilterState::Enabled);
-          state->kqueue_write_filter_ = KqueueFilterState::Disabled;
-          pending_ops.push_back(state);
-        }
-      }
-      return ret;
-    }
-  };
-#elif defined(USE_PPOLL)
-  class Watches {
-    // Use two parallel vectors, where polls_[n] is an entry matching
-    // states_[n], since only one async operation can exist for each file
-    // descriptor. They must be separate because the address of polls_.front()
-    // will be passed to the kernel for ppoll(), which expects a contiguous
-    // array of pollfd items in memory.
-    std::vector<AsyncHandle::State*> states_;
-    std::vector<pollfd> polls_;
-
-    size_t FindState(AsyncHandle::State* state) {
-      size_t result = 0;
-      for (auto* s : states_) {
-        if (s == state)
-          return result;
-        ++result;
-      }
-      return npos;
-    }
-
-   public:
-    static constexpr size_t npos = ~size_t(0);
-
-    ~Watches() {
-      assert(states_.empty() &&
-             "Destroying AsyncLoop before child AsyncHandle instances!");
-    }
-
-    bool HasWaiters() const {
-      for (const auto& poll : polls_) {
-        if (poll.events != 0)
-          return true;
-      }
-      return false;
-    }
-
-    void Insert(AsyncHandle::State* state) {
-      assert(FindState(state) == npos && "Async state already in the set!");
-      states_.push_back(state);
-      polls_.push_back({ state->fd(), state->poll_events(), 0 });
-    }
-
-    void Remove(AsyncHandle::State* state) {
-      size_t state_pos = FindState(state);
-      assert(state_pos != npos && "Async state not in the set!");
-      // Order is not important
-      size_t last_pos = states_.size() - 1;
-      if (state_pos != last_pos) {
-        states_[state_pos] = states_[last_pos];
-        polls_[state_pos] = polls_[last_pos];
-      }
-      states_.pop_back();
-      polls_.pop_back();
-    }
-
-    void Update(AsyncHandle::State* state) {
-      size_t state_pos = FindState(state);
-      assert(state_pos != npos && "Updating unknown async state!");
-      polls_[state_pos].events = state->poll_events();
-    }
-
-    int WaitForEvents(const struct timespec* ts, PendingList& pending_ops) {
-      int ret = ppoll(&polls_.front(), static_cast<nfds_t>(polls_.size()), ts,
-                      nullptr);
-      if (ret < 0) {
-        if (errno != EINTR)
-          ErrnoFatal("ppoll");
-      } else if (ret > 0) {
-        auto cur_poll = polls_.begin();
-        auto cur_state = states_.begin();
-        for (; cur_poll != polls_.end(); ++cur_poll, ++cur_state) {
-          AsyncHandle::State* state = *cur_state;
-          assert(state->fd() == cur_poll->fd);
-          if (cur_poll->revents & state->poll_revents())
-            pending_ops.push_back(state);
-        }
-      }
-      return ret;
-    }
-  };
-
-#else   // !USE_KQUEUE && !USE_PPOLL
-  class Watches {
-    static constexpr int kInvalid = -2;
-    mutable int max_fds_ = kInvalid;
-
-    using ListType = std::vector<AsyncHandle::State*>;
-    ListType states_;
-    fd_set read_fds_;
-    fd_set write_fds_;
-    fd_set event_read_fds_;
-    fd_set event_write_fds_;
-
-    void Invalidate() { max_fds_ = kInvalid; }
-
-    int num_fds() const {
-      // Recompute max file descriptor if needed.
-      if (max_fds_ == kInvalid) {
-        max_fds_ = -1;
-        for (AsyncHandle::State* state : states_) {
-          if (state->NeedsReadEvent() || state->NeedsWriteEvent()) {
-            if (state->fd() > max_fds_)
-              max_fds_ = state->fd();
-          }
-        }
-      }
-      return max_fds_ + 1;
-    }
-
-    ListType::iterator FindState(AsyncHandle::State* state) {
-      return std::find(states_.begin(), states_.end(), state);
-    }
-
-   public:
-    Watches() {
-      FD_ZERO(&read_fds_);
-      FD_ZERO(&write_fds_);
-    }
-
-    void Insert(AsyncHandle::State* state) {
-      if (state->fd() >= static_cast<int>(FD_SETSIZE))
-        Fatal("File descriptor too large for pselect(): %d\n", state->fd());
-
-      auto it = FindState(state);
-      assert(it == states_.end() && "Async state already in the set!");
-      if (it != states_.end())
-        return;
-      states_.push_back(state);
-      if (state->NeedsReadEvent())
-        FD_SET(state->fd(), &read_fds_);
-      if (state->NeedsWriteEvent())
-        FD_SET(state->fd(), &write_fds_);
-      Invalidate();
-    }
-
-    void Remove(AsyncHandle::State* state) {
-      auto it = FindState(state);
-      assert(it != states_.end() && "Removing unknown Async state!");
-      if (it == states_.end())
-        return;
-      FD_CLR(state->fd(), &read_fds_);
-      FD_CLR(state->fd(), &write_fds_);
-      Invalidate();
-    }
-
-    void Update(AsyncHandle::State* state) {
-      int fd = state->fd();
-      if (state->NeedsReadEvent()) {
-        FD_SET(fd, &read_fds_);
-      } else {
-        FD_CLR(fd, &read_fds_);
-      }
-      if (state->NeedsWriteEvent()) {
-        FD_SET(fd, &write_fds_);
-      } else {
-        FD_CLR(fd, &write_fds_);
-      }
-    }
-
-    bool HasWaiters() const {
-      for (const auto* state : states_) {
-        if (state->IsRunning())
-          return true;
-      }
-      return false;
-    }
-
-    int WaitForEvents(const struct timespec* ts, PendingList& pending_ops) {
-      event_read_fds_ = read_fds_;
-      event_write_fds_ = write_fds_;
-
-      int count = num_fds();
-      int ret = pselect(count, &event_read_fds_, &event_write_fds_, nullptr, ts,
-                        nullptr);
-      if (ret < 0) {
-        if (errno != EINTR)
-          ErrnoFatal("pselect");
-      } else if (ret > 0) {
-        for (auto* state : states_) {
-          int fd = state->fd();
-          bool has_event = false;
-          has_event |=
-              state->NeedsWriteEvent() && FD_ISSET(fd, &event_write_fds_);
-          has_event |=
-              state->NeedsReadEvent() && FD_ISSET(fd, &event_read_fds_);
-          if (has_event)
-            pending_ops.emplace_back(state);
-        }
-      }
-      return ret;
-    }
-  };
-#endif  // !USE_KQUEUE && !USE_PPOLL
-
- public:
-  ~Impl() {
-    assert(!watches_.HasWaiters() &&
-           "Destroying AsyncLoop before children AsyncHandle instances!");
-    assert(timers_.empty() &&
-           "Destroying AsyncLoop before children AsyncTimer instances!");
-  }
-
-  AsyncLoopTimers& timers() { return timers_; }
-
-  void AttachHandle(AsyncHandle::State* state) {
-    assert(state->fd_ && "Trying to attach invalid handle");
-    watches_.Insert(state);
-  }
-
-  void DetachHandle(AsyncHandle::State* state) {
-    assert(state->fd_ && "Trying to detach invalid handle");
-    watches_.Remove(state);
-  }
-
-  void UpdateHandle(AsyncHandle::State* state) { watches_.Update(state); }
-
-  void CancelHandle(AsyncHandle::State* state) {
-    pending_ops_.Remove(state);
-    watches_.Update(state);
-  }
-
-  AsyncLoop::ExitStatus RunOnce(int64_t timeout_ms, AsyncLoop& loop) {
-    assert(pending_ops_.empty());
-
-    /// An interrupt occured outside of this loop, return immediately.
-    if (interrupt_catcher_.get() && interrupt_catcher_->interrupted()) {
-      return ExitInterrupted;
-    }
-
-    /// Handle timeout.
-    bool has_timers = false;
-    int64_t timer_expiration_ms = timers_.ComputeNextExpiration();
-    if (timer_expiration_ms >= 0) {
-      has_timers = true;
-      int64_t now_ms = NowMs();
-      int64_t timer_timeout_ms = timer_expiration_ms - now_ms;
-      if (timer_timeout_ms < 0) {
-        timer_timeout_ms = 0;
-      }
-
-      if (timeout_ms < 0)
-        timeout_ms = timer_timeout_ms;
-      else if (timeout_ms > timer_timeout_ms)
-        timeout_ms = timer_timeout_ms;
-    }
-
-    const struct timespec* ts = NULL;
-    struct timespec timeout_ts = {};
-    if (timeout_ms >= 0) {
-      timeout_ts.tv_sec = static_cast<time_t>(timeout_ms / 1000);
-      timeout_ts.tv_nsec = static_cast<long>((timeout_ms % 1000) * 1000000LL);
-      ts = &timeout_ts;
-    }
-
-    /// Exit immediately if there is nothing to do and no timeout.
-    if (!watches_.HasWaiters() && pending_ops_.empty() && timeout_ms < 0)
-      return ExitIdle;
-
-    int ret = watches_.WaitForEvents(ts, pending_ops_);
-    if (ret == -1) {
-      return ExitInterrupted;
-    }
-
-    if (interrupt_catcher_.get()) {
-      interrupt_catcher_->HandlePendingInterrupt();
-      if (interrupt_catcher_->interrupted())
-        return ExitInterrupted;
-    }
-
-    ExitStatus result = ExitTimeout;
-
-    // Handle all pending operations.
-    // Note that OnEvent() may invoke a callback that changes the
-    // state of pending_ops_.
-    while (!pending_ops_.empty()) {
-      AsyncHandle::State* state = pending_ops_.back();
-      pending_ops_.pop_back();
-      if (state->OnEvent())
-        result = ExitSuccess;
-    }
-
-    if (has_timers && timers_.ProcessExpiration(NowMs()))
-      result = ExitSuccess;
-
-    return result;
-  }
-
-  void ClearInterrupt() {
-    if (interrupt_catcher_)
-      interrupt_catcher_->Clear();
-  }
-
-  int GetInterruptSignal() const {
-    if (!interrupt_catcher_)
-      return 0;
-    return interrupt_catcher_->interrupted();
-  }
-
-  sigset_t GetOldSignalMask() const {
-    if (!interrupt_catcher_) {
-      sigset_t old_mask;
-      sigset_t empty;
-      sigemptyset(&empty);
-      sigprocmask(SIG_BLOCK, &empty, &old_mask);
-      return old_mask;
-    }
-    return interrupt_catcher_->old_mask();
-  }
-
-  void EnableInterruptCatcher() {
-    interrupt_catcher_.reset(new InterruptCatcher());
-  }
-
-  void DisableInterruptCatcher() { interrupt_catcher_.reset(); }
-
- private:
-  std::unique_ptr<InterruptCatcher> interrupt_catcher_;
-  AsyncLoopTimers timers_;
-  Watches watches_;
-};
-
-#endif  // NINJA_ASYNC_LOOP_POSIX_H
diff --git a/src/async_loop-win32.h b/src/async_loop-win32.h
deleted file mode 100644
index fe6f702..0000000
--- a/src/async_loop-win32.h
+++ /dev/null
@@ -1,460 +0,0 @@
-// Copyright 2023 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_ASYNC_LOOP_WIN32_H
-#define NINJA_ASYNC_LOOP_WIN32_H
-
-/// Win32 implementation of the AsyncLoop class.
-
-#include <assert.h>
-
-#include <list>
-#include <unordered_map>
-
-#include "async_loop.h"
-#include "async_loop_timers.h"
-#include "interrupt_handling.h"
-#include "metrics.h"  // GetTimeMillis()
-#include "util.h"     // Win32Fatal()
-#include "win32port.h"  // PRId64
-
-// Set to 1 to add special code paths to add extra debugging checks.
-#define DEBUG 0
-
-#if DEBUG
-#define DEBUG_OVERLAPPED_POINTERS  1
-#else
-#define DEBUG_OVERLAPPED_POINTERS  0
-#endif
-
-// Technical note on Win32 overlapped i/o:
-//
-// - Calling CreateIoCompletionPort() on a handle that
-//   was already associated with the same port returns
-//   ERROR_INVALID_PARAMETER.
-//
-//   This means it is impossible to change the completion_key
-//   value for a handle once it has been set.
-//
-// - If a handle is associated with a completion port,
-//   calling DuplicateHandle() will create a new handle
-//   that is _already_ associated with the same completion port.
-//
-//   This means that calling CreateIoCompletionPort(new_handle, ...)
-//   will fail with ERROR_INVALID_PARAMETER.
-//
-//   But it also means the completion_key for both handles will
-//   always be the same. Thus this value becomes useless to
-//   distinguish handles in general. The only reliable way is to
-//   use the OVERLAPPED* pointer.
-//
-// - Even if an overlapped ReadFile() call succeeds immediately,
-//   a completion event will still be sent to the port for it.
-//   Same with WriteFile(), ConnectNamedPipe() and other Win32 I/O functions.
-//
-
-// The Win32-specific state of an AsyncHandle instance, without any
-// AsyncLoop reference. Wraps an OVERLAPPED struct
-struct AsyncHandle::State {
-  enum class Kind {
-    None = 0,
-    Read,
-    Write,
-    Connect,
-    Accept,
-  };
-
-  // Constructors.
-  explicit State(AsyncLoop& async_loop) : async_loop_(async_loop) {}
-
-  State(IpcHandle handle, AsyncLoop& async_loop, AsyncHandle::Callback&& callback)
-      : handle_(std::move(handle)), async_loop_(async_loop), callback_(std::move(callback)) {
-    if (handle_)
-      async_loop_.AttachHandle(this);
-  }
-
-  // Destructor.
-  ~State() {
-    if (!completed_)
-      Cancel();
-    if (handle_) {
-      async_loop_.DetachHandle(this);
-    }
-  }
-
-  // Disallow copy operations. Even though this is implied by
-  // the use of moveable-only fields like |handle_|.
-  State(const State&) = delete;
-  State& operator=(const State&) = delete;
-
-  // Disable move operations, since the address of this instance's
-  // |overlapped_| field (which should equal the instance's address) is
-  // passed to the Windows kernel, and thus cannot change.
-  State(State&&) noexcept = delete;
-  State& operator=(State&&) noexcept = delete;
-
-  // Return AsyncLoop this instance belongs to.
-  AsyncLoop& async_loop() const { return async_loop_; }
-  AsyncLoop::Impl& loop() const { return *async_loop_.impl_; }
-
-  bool is_valid() const { return !!handle_; }
-
-  // Is an asynchronous operation running?
-  bool IsRunning() const { return !completed_; }
-
-  HANDLE native_handle() const { return handle_.native_handle(); }
-
-  // Cancel current asynchronous operation, if any.
-  void Cancel() {
-    if (!completed_ && kind_ != Kind::None) {
-      async_loop_.CancelHandle(this);
-      ::CancelIoEx(handle_.native_handle(), &overlapped_);
-      completed_ = true;
-    }
-  }
-
-  // Reset the callback.
-  void ResetCallback(AsyncHandle::Callback&& cb) { callback_ = std::move(cb); }
-
-  void ResetHandle(IpcHandle handle) {
-    if (handle_) {
-      Cancel();
-      async_loop_.DetachHandle(this);
-    }
-    handle_ = std::move(handle);
-    if (handle_)
-      async_loop_.AttachHandle(this);
-  }
-
-  HANDLE ReleaseHandle() {
-    if (!handle_)
-      return INVALID_HANDLE_VALUE;
-
-    Cancel();
-    async_loop_.DetachHandle(this);
-    return handle_.ReleaseNativeHandle();
-  }
-
-  // Reset state to start a new asynchronous operation. Cancels current one
-  // if any.
-  void Reset(Kind kind = Kind::None) {
-    kind_ = kind;
-    if (!completed_) {
-      ::CancelIoEx(handle_.native_handle(), &overlapped_);
-      completed_ = true;
-    }
-    error_ = 0;
-    actual_bytes_ = 0;
-    accept_handle_.Close();
-  }
-
-  // Start async read operation.
-  void StartRead(void* buffer, size_t size) {
-    Reset(Kind::Read);
-    completed_ = false;
-    if (!ReadFile(handle_.native_handle(), buffer, size, &actual_bytes_,
-                  &overlapped_)) {
-      error_ = GetLastError();
-      completed_ = (error_ != ERROR_IO_PENDING);
-    }
-    async_loop_.UpdateHandle(this);
-  }
-
-  // Start async write operation.
-  void StartWrite(const void* buffer, size_t size) {
-    Reset(Kind::Write);
-    completed_ = false;
-    if (!::WriteFile(handle_.native_handle(), buffer, size, &actual_bytes_,
-                     &overlapped_)) {
-      error_ = GetLastError();
-      completed_ = (error_ != ERROR_IO_PENDING);
-    }
-    async_loop_.UpdateHandle(this);
-  }
-
-  // Start async connect operation.
-  void StartConnect() {
-    Reset(Kind::Connect);
-    // Connection to named pipes is immediate on Win32.
-    completed_ = true;
-    async_loop_.UpdateHandle(this);
-  }
-
-  // Start async accept operation.
-  void StartAccept() {
-    // Note: duplicate the server handle here to be able to pass
-    // the result to the final AsyncHandle::TakeAcceptedHandle()
-    // call as a separate client connection handle.
-    //
-    // The duplicate is already associated with the i/o completion port
-    // and does not need to be attached to the AsyncLoop instance.
-    Reset(Kind::Accept);
-    completed_ = false;
-    accept_handle_ = handle_.Clone();
-
-    if (!ConnectNamedPipe(accept_handle_.native_handle(), &overlapped_)) {
-      error_ = GetLastError();
-      completed_ = (error_ != ERROR_IO_PENDING);
-    }
-    async_loop_.UpdateHandle(this);
-  }
-
-  // Called when a completion event is received. Do not invoke the callback
-  // yet though.
-  void OnCompletion(AsyncError error, size_t transfer_size) {
-    completed_ = true;
-    error_ = error;
-    actual_bytes_ = transfer_size;
-  }
-
-  // Invoke the callback.
-  void InvokeCallback() { callback_(error_, actual_bytes_); }
-
-  // Return accepted handle, if any.
-  IpcHandle TakeAcceptedHandle() { return std::move(accept_handle_); }
-
-  OVERLAPPED overlapped_ = {};  // Must be first!
-  IpcHandle handle_;
-  Kind kind_ = Kind::None;
-  bool completed_ = false;
-  DWORD error_ = 0;
-  DWORD actual_bytes_ = 0;
-  IpcHandle accept_handle_;
-  AsyncLoop& async_loop_;
-  AsyncHandle::Callback callback_;
-};
-
-// Win32-specific implementation of the AsyncLoop internal interface.
-class AsyncLoop::Impl {
-  /// The list of pending AsyncHandle::States that have completed but whose
-  /// Invoke() method wasn't called yet. Identified by their address.
-  struct PendingList : public std::vector<AsyncHandle::State*> {
-    // Remove one async_id from the list.
-    bool Remove(AsyncHandle::State* async_op) {
-      for (auto it = begin(); it != end(); ++it) {
-        if (*it == async_op) {
-          // Order does not matter for this list, so just move last item
-          // to current location to avoid O(n) removal cost.
-          auto it_last = end() - 1;
-          if (it != it_last)
-            *it = *it_last;
-          pop_back();
-          return true;
-        }
-      }
-      return false;
-    }
-  };
-
-  PendingList pending_ops_;
-
-  // The number of AsyncHandle instances attached to this loop.
-  size_t attached_count_ = 0;
-
-  // The number of AsyncHandle instances waiting for an event.
-  size_t waiting_count_ = 0;
-
-#if DEBUG_OVERLAPPED_POINTERS
-  // A map used to convert OVERLAPPED* pointer values to the address
-  // of a known AsyncHandle::State. Used for safety.
-  using OverlappedMap = std::unordered_map<OVERLAPPED*, AsyncHandle::State*>;
-  OverlappedMap overlapped_map_;
-#endif
-
- public:
-  ~Impl() {
-#if DEBUG_OVERLAPPED_POINTERS
-    assert(overlapped_map_.empty() &&
-           "Destroying AsyncLop before AsyncHandle!");
-#endif
-    assert(timers_.empty() &&
-           "Destroying AsyncLoop before children AsyncTimer instances!");
-  }
-
-  AsyncLoopTimers& timers() { return timers_; }
-
-  void AttachHandle(AsyncHandle::State* async_op) {
-    assert(async_op && "Attaching null async op!");
-    assert(async_op->handle_ && "Attaching invalid handle!");
-
-    HANDLE handle = async_op->handle_.native_handle();
-    if (handle == INVALID_HANDLE_VALUE)
-      return;
-
-    auto key = reinterpret_cast<ULONG_PTR>(handle);
-    if (!CreateIoCompletionPort(handle, ioport_.get(), key, 0)) {
-      DWORD error = GetLastError();
-      // CreateIoCompletionPort() will return invalid parameter
-      // when trying to call it with the duplicate of a handle that
-      // was already associated with the port. Ignore it.
-      if (error != ERROR_INVALID_PARAMETER)
-        Win32Fatal("CreateIoCompletionPortRead");
-    }
-
-#if DEBUG_OVERLAPPED_POINTERS
-    auto ret = overlapped_map_.emplace(&async_op->overlapped_, async_op);
-    assert(ret.second &&
-           "Adding AsyncHandle::State for known OVERLAPPED pointer!");
-#endif  // DEBUG_OVERLAPPED_POINTERS
-
-    attached_count_ += 1;
-  }
-
-  void DetachHandle(AsyncHandle::State* async_op) {
-    assert(async_op->handle_ && "Detaching invalid handle!");
-    if (!async_op->handle_)
-      return;
-
-    assert(attached_count_ > 0 &&
-           "Detaching AsyncHandle::State from empty AsyncLoop!");
-    attached_count_--;
-
-#if DEBUG_OVERLAPPED_POINTERS
-    auto overlapped_it = overlapped_map_.find(&async_op->overlapped_);
-    assert(overlapped_it != overlapped_map_.end() &&
-           "Releasing AsyncHandle::State for unknown OVERLAPPED pointer!");
-    overlapped_map_.erase(overlapped_it);
-#endif  // DEBUG_OVERLAPPED_POINTERS
-  }
-
-  void UpdateHandle(AsyncHandle::State* state) {
-    if (state->completed_)
-      pending_ops_.push_back(state);
-    else
-      waiting_count_++;
-  }
-
-  void CancelHandle(AsyncHandle::State* astate) {
-    pending_ops_.Remove(astate);
-    assert(waiting_count_ > 0);
-    waiting_count_--;
-  }
-
-  ExitStatus RunOnce(int64_t timeout_ms, AsyncLoop& loop) {
-    // Any pending operations (e.g. from StartAsyncConnect()) means
-    // no timeout is needed.
-    if (!pending_ops_.empty())
-      timeout_ms = 0;
-
-    // Handle timeout.
-    bool has_timers = false;
-    int64_t timer_expiration_ms = timers_.ComputeNextExpiration();
-    if (timer_expiration_ms >= 0) {
-      has_timers = true;
-      int64_t timer_timeout_ms = timer_expiration_ms - NowMs();
-      if (timer_timeout_ms < 0)
-        timer_timeout_ms = 0;
-
-      if (timeout_ms < 0)
-        timeout_ms = timer_timeout_ms;
-      else if (timeout_ms > timer_timeout_ms)
-        timeout_ms = timer_timeout_ms;
-    }
-
-    // Do we have any async operation here?
-    if (timeout_ms < 0 && !waiting_count_)
-      return ExitIdle;
-
-    DWORD error = 0;
-    DWORD transfer_size = 0;
-    ULONG_PTR completion_key = 0;
-    bool received_key = true;
-    OVERLAPPED* overlapped_ptr = nullptr;
-    DWORD timeout = timeout_ms < 0 ? INFINITE : static_cast<DWORD>(timeout_ms);
-    if (!GetQueuedCompletionStatus(ioport_.get(), &transfer_size,
-                                   &completion_key, &overlapped_ptr, timeout)) {
-      error = GetLastError();
-      if (error == ERROR_BROKEN_PIPE) {
-        // Pass the error to the callback.
-      } else if (error == WAIT_TIMEOUT) {
-        received_key = false;
-        if (pending_ops_.empty() && !has_timers)
-          return ExitTimeout;
-      } else {
-        Win32Fatal("GetQueuedCompletionStatus");
-      }
-    }
-
-    if (received_key) {
-      // NotifyInterrupted is the only thing that posts a NULL completion key.
-      if (!completion_key)
-        return ExitInterrupted;
-
-#if DEBUG_OVERLAPPED_POINTERS
-      auto overlapped_it = overlapped_map_.find(overlapped_ptr);
-      assert(overlapped_it != overlapped_map_.end() &&
-             "Received completion for unknown OVERLAPPED pointer!");
-      AsyncHandle::State* async_op = overlapped_it->second;
-      assert(async_op ==
-                 reinterpret_cast<AsyncHandle::State*>(overlapped_ptr) &&
-             "Inconsistent OVERLAPPED pointer value!");
-#else  // !DEBUG_OVERLAPPED_POINTERS
-      AsyncHandle::State* async_op =
-          reinterpret_cast<AsyncHandle::State*>(overlapped_ptr);
-#endif
-      async_op->OnCompletion(error, transfer_size);
-      assert(waiting_count_ > 0);
-      waiting_count_ -= 1;
-      pending_ops_.push_back(async_op);
-    }
-
-    // Handle all pending operations.
-    // Note that InvokeCallback() may invoke a callback that changes the
-    // state of pending_ops_.
-    while (!pending_ops_.empty()) {
-      AsyncHandle::State* async_op = pending_ops_.back();
-      pending_ops_.pop_back();
-      async_op->InvokeCallback();
-    }
-
-    if (has_timers && !timers_.ProcessExpiration(NowMs()))
-      return ExitTimeout;
-
-    return ExitSuccess;
-  }
-
-  void ClearInterrupt() {
-    // Nothing to do here.
-  }
-
-  void EnableInterruptCatcher() {
-    interrupt_handler_.reset(new InterruptCompletionPortHandler(ioport_.get()));
-  }
-
-  void DisableInterruptCatcher() { interrupt_handler_.reset(); }
-
- private:
-  /// Helper class to create and close an I/O completion port handle
-  /// in the right order.
-  struct ScopedIoPort {
-    ScopedIoPort()
-        : handle_(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1)) {
-      if (!handle_)
-        Win32Fatal("CreateIoCompletionPort");
-    }
-
-    ~ScopedIoPort() { ::CloseHandle(handle_); }
-
-    HANDLE get() const { return handle_; }
-
-   private:
-    HANDLE handle_;
-  };
-
-  ScopedIoPort ioport_;
-  std::unique_ptr<InterruptCompletionPortHandler> interrupt_handler_;
-  AsyncLoopTimers timers_;
-};
-
-#endif  // NINJA_ASYNC_LOOP_WIN32_H
diff --git a/src/async_loop.cc b/src/async_loop.cc
deleted file mode 100644
index 978a972..0000000
--- a/src/async_loop.cc
+++ /dev/null
@@ -1,340 +0,0 @@
-// Copyright 2023 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 "async_loop.h"
-
-#include "util.h"
-
-#ifdef _WIN32
-#include "async_loop-win32.h"
-#else
-#include "async_loop-posix.h"
-#endif
-
-// static
-std::string AsyncErrorToString(AsyncError error) {
-  return std::string(strerror(error));
-}
-
-// Global instance.
-static std::unique_ptr<AsyncLoop> s_loop;
-
-// static
-AsyncLoop& AsyncLoop::Get() {
-  AsyncLoop* loop = s_loop.get();
-  if (!loop) {
-    loop = new AsyncLoop();
-    s_loop.reset(loop);
-  }
-  return *loop;
-}
-
-// static
-std::unique_ptr<AsyncLoop> AsyncLoop::CreateLocal() {
-  return std::unique_ptr<AsyncLoop>(new AsyncLoop());
-}
-
-void AsyncLoop::Reset() {
-  impl_.reset(new AsyncLoop::Impl());
-  if (interrupt_catcher_count_ > 0)
-    impl_->EnableInterruptCatcher();
-}
-
-// static
-void AsyncLoop::ResetForTesting() {
-  AsyncLoop* loop = s_loop.get();
-  if (loop)
-    loop->Reset();
-}
-
-AsyncLoop::AsyncLoop() : impl_(new AsyncLoop::Impl()) {}
-
-AsyncLoop::~AsyncLoop() = default;
-
-// static
-int64_t AsyncLoop::NowMs() {
-  static bool init = false;
-  static int64_t start_ms = 0;
-  int64_t result = GetTimeMillis();
-  if (!init) {
-    start_ms = result;
-    init = true;
-  }
-  return result - start_ms;
-}
-
-AsyncLoop::ExitStatus AsyncLoop::RunOnce(int64_t timeout_ms) {
-  return impl_->RunOnce(timeout_ms, *this);
-}
-
-void AsyncLoop::ClearInterrupt() {
-  impl_->ClearInterrupt();
-}
-
-#ifndef _WIN32
-int AsyncLoop::GetInterruptSignal() const {
-  return impl_->GetInterruptSignal();
-}
-
-sigset_t AsyncLoop::GetOldSignalMask() const {
-  return impl_->GetOldSignalMask();
-}
-#endif  // !_WIN32
-
-void AsyncLoop::UpdateHandle(AsyncHandle::State* state) {
-  impl_->UpdateHandle(state);
-}
-
-void AsyncLoop::CancelHandle(AsyncHandle::State* state) {
-  impl_->CancelHandle(state);
-}
-
-void AsyncLoop::AttachTimer(AsyncTimer::State* state) {
-  impl_->timers().AttachTimer(state);
-}
-
-void AsyncLoop::DetachTimer(AsyncTimer::State* state) {
-  impl_->timers().DetachTimer(state);
-}
-
-void AsyncLoop::UpdateTimer(AsyncTimer::State* state) {
-  impl_->timers().UpdateTimer(state);
-}
-
-AsyncLoop::RunUntilState::RunUntilState(int64_t timeout_ms)
-    : timeout_ms_(timeout_ms) {}
-
-bool AsyncLoop::RunUntilState::LoopAgain(AsyncLoop& async_loop) {
-  // Initialize expiration_ms_ the first time this method is called.
-  int64_t expiration_ms = -1;
-  if (timeout_ms_ >= 0)
-    expiration_ms = async_loop.NowMs() + timeout_ms_;
-
-  status_ = async_loop.RunOnce(timeout_ms_);
-  if (status_ != ExitSuccess) {
-    // Either an interrupt, timeout or idle exit.
-    // This is the end of the loop.
-    return false;
-  }
-
-  if (timeout_ms_ < 0) {
-    // Since no timeout was specified, just loop again
-    // after an async event.
-    return true;
-  }
-
-  // Adjust the timeout for the next invocation.
-  timeout_ms_ = expiration_ms - async_loop.NowMs();
-  if (timeout_ms_ >= 0) {
-    // There is still time left, so loop again.
-    return true;
-  }
-
-  // There is no time left, stop the loop reporting
-  // a real timeout.
-  timeout_ms_ = 0;
-  status_ = ExitTimeout;
-  return false;
-}
-
-void AsyncLoop::ChangeInterruptCatcher(bool increment) {
-  if (increment) {
-    if (++interrupt_catcher_count_ == 1)
-      impl_->EnableInterruptCatcher();
-  } else {
-    if (interrupt_catcher_count_ <= 0)
-      Fatal("Unbalanced ChangeInterruptCatcher() calls");
-    if (--interrupt_catcher_count_ == 0)
-      impl_->DisableInterruptCatcher();
-  }
-}
-
-void AsyncLoop::AttachHandle(AsyncHandle::State* state) {
-  impl_->AttachHandle(state);
-}
-
-void AsyncLoop::DetachHandle(AsyncHandle::State* state) {
-  impl_->DetachHandle(state);
-}
-
-///////////////////////////////////////////////////////////////////////////
-///
-///   AsyncHandle
-///
-
-AsyncHandle::AsyncHandle() = default;
-AsyncHandle::AsyncHandle(std::unique_ptr<AsyncHandle::State> state)
-    : state_(std::move(state)) {}
-
-// static
-AsyncHandle AsyncHandle::Create(IpcHandle handle, AsyncLoop& async_loop,
-                                AsyncHandle::Callback&& callback) {
-  auto state = std::unique_ptr<AsyncHandle::State>(new AsyncHandle::State(
-      std::move(handle), async_loop, std::move(callback)));
-  return AsyncHandle(std::move(state));
-}
-
-// static
-AsyncHandle AsyncHandle::Create(IpcHandle::HandleType native_handle,
-                                AsyncLoop& async_loop,
-                                AsyncHandle::Callback&& callback) {
-  return Create(IpcHandle(native_handle), async_loop, std::move(callback));
-}
-
-// static
-AsyncHandle AsyncHandle::CreateClone(IpcHandle::HandleType native_handle,
-                                     AsyncLoop& async_loop,
-                                     AsyncHandle::Callback&& callback) {
-  return Create(IpcHandle::CloneNativeHandle(native_handle), async_loop,
-                std::move(callback));
-}
-
-AsyncHandle::~AsyncHandle() = default;
-
-AsyncHandle::AsyncHandle(AsyncHandle&&) noexcept = default;
-AsyncHandle& AsyncHandle::operator=(AsyncHandle&&) noexcept = default;
-
-void AsyncHandle::Close() {
-  if (is_valid()) {
-    state_->Cancel();
-    state_.reset();
-  }
-}
-
-void AsyncHandle::ResetHandle(IpcHandle handle) {
-  assert(state_ && "Reset() on invalid AsyncHandle value");
-#ifndef _WIN32
-  handle.SetNonBlocking(true);
-#endif
-  state_->ResetHandle(std::move(handle));
-}
-
-IpcHandle::HandleType AsyncHandle::Release() {
-  return state_->ReleaseHandle();
-}
-
-bool AsyncHandle::is_valid() const {
-  return state_ && state_->is_valid();
-}
-
-IpcHandle::HandleType AsyncHandle::native_handle() const {
-  return state_ ? state_->native_handle() : IpcHandle::kInvalid;
-}
-
-bool AsyncHandle::IsRunning() const {
-  return state_ && state_->IsRunning();
-}
-
-void AsyncHandle::Cancel() {
-  if (state_)
-    state_->Cancel();
-}
-
-AsyncHandle& AsyncHandle::ResetCallback(AsyncHandle::Callback&& callback) {
-  assert(state_ && "ResetCallback() on invalid AsyncHandle value");
-  state_->ResetCallback(std::move(callback));
-  return *this;
-}
-
-void AsyncHandle::StartRead(void* buffer, size_t size) {
-  assert(state_ && "StartRead() on invalid AsyncHandle value");
-  state_->StartRead(buffer, size);
-}
-
-void AsyncHandle::StartWrite(const void* buffer, size_t size) {
-  assert(state_ && "StartWrite() on invalid AsyncHandle value");
-  state_->StartWrite(buffer, size);
-}
-
-void AsyncHandle::StartConnect() {
-  assert(state_ && "StartConnect() on invalid AsyncHandle value");
-  state_->StartConnect();
-}
-
-void AsyncHandle::StartAccept() {
-  assert(state_ && "StartAccept() on invalid AsyncHandle value");
-  state_->StartAccept();
-}
-
-IpcHandle AsyncHandle::TakeAcceptedHandle() {
-  assert(state_ && "TakeAcceptedHandle() on invalid AsyncHandle value");
-  return state_->TakeAcceptedHandle();
-}
-
-AsyncLoop& AsyncHandle::async_loop() const {
-  assert(state_ && "async_loop() on invalid AsyncHandle value");
-  return state_->async_loop();
-}
-
-///////////////////////////////////////////////////////////////////////////
-///
-///   AsyncTimer
-///
-
-AsyncTimer::AsyncTimer() = default;
-
-AsyncTimer::AsyncTimer(AsyncLoop& async_loop, AsyncTimer::Callback&& callback)
-    : state_(new State(async_loop, std::move(callback))) {}
-
-AsyncTimer::~AsyncTimer() = default;
-
-AsyncTimer::AsyncTimer(AsyncTimer&&) noexcept = default;
-AsyncTimer& AsyncTimer::operator=(AsyncTimer&&) noexcept = default;
-
-void AsyncTimer::ResetCallback(AsyncTimer::Callback&& callback) {
-  assert(state_ && "Calling AsyncTimer::ResetCallback() on invalid instance!");
-  state_->ResetCallback(std::move(callback));
-}
-void AsyncTimer::SetExpirationMs(int64_t expiration_ms) {
-  assert(state_ &&
-         "Calling AsyncTimer::SetExpirationMs() on invalid instance!");
-  state_->SetExpirationMs(expiration_ms);
-}
-
-void AsyncTimer::SetDurationMs(int64_t duration_ms) {
-  assert(state_ && "Calling AsyncTimer::SetDurationMs() on invalid instance!");
-  state_->SetDurationMs(duration_ms);
-}
-
-void AsyncTimer::Cancel() {
-  assert(state_ && "Calling AsyncTimer::Cancel() on invalid instance!");
-  state_->Cancel();
-}
-
-void AsyncTimer::Close() {
-  state_.reset();
-}
-
-AsyncLoop& AsyncTimer::async_loop() const {
-  assert(state_ && "Calling AsyncTimer::async_loop() on invalid instance!");
-  return state_->async_loop();
-}
-
-// static
-AsyncTimer AsyncTimer::CreateWithExpiration(int64_t expiration_ms,
-                                            AsyncLoop& async_loop,
-                                            AsyncTimer::Callback&& callback) {
-  AsyncTimer timer(async_loop, std::move(callback));
-  timer.SetExpirationMs(expiration_ms);
-  return timer;
-}
-
-// static
-AsyncTimer AsyncTimer::CreateWithDuration(int64_t duration_ms,
-                                          AsyncLoop& async_loop,
-                                          AsyncTimer::Callback&& callback) {
-  AsyncTimer timer(async_loop, std::move(callback));
-  timer.SetDurationMs(duration_ms);
-  return timer;
-}
diff --git a/src/async_loop.h b/src/async_loop.h
deleted file mode 100644
index fd83729..0000000
--- a/src/async_loop.h
+++ /dev/null
@@ -1,471 +0,0 @@
-// Copyright 2023 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_ASYNC_LOOP_H
-#define NINJA_ASYNC_LOOP_H
-
-#include "ipc_handle.h"
-
-#ifndef _WIN32
-#include <signal.h>
-#endif
-
-#include <functional>
-#include <memory>
-
-/// AsyncLoop provides an abstraction to perform asynchronous i/o
-/// operations on Posix and Win32. Its API is inspired by Win32
-/// overlapped operations, since this model can be implemented
-/// efficiently on Posix.
-///
-/// AsyncHandle wraps an i/o handle, and a user-provided callback.
-/// It provides methods like StartRead() to initiate an asynchronous operation.
-///
-/// AsyncTimer wraps an expiration date and a user-provided callback.
-/// It provides SetExpirationMs() and SetDurationMs() methods to indicate
-/// when the timer's next expiration should occur.
-///
-/// Each AsyncHandle or AsyncTimer instance is scoped to a parent AsyncLoop
-/// instance.
-///
-/// Example usage:
-///
-///  1) Obtain a reference to an AsyncLoop instance, e.g. by
-///     calling AsyncLoop::Get() or AsyncLoop::CreateLocal().
-///
-///  2) Create as many AsyncHandle and AsyncTimer instances from
-///     the parent loop as needed. passing a user-provided callback
-///     when constructing each one of them.
-///
-///  4) Use AsyncHandle::StartXXX() methods to start an i/o asynchronous
-///     operation, or AsyncTimer::Set{Expiration,Duration}Ms() to set a
-///     timer's expiration time.
-///
-///  5) Call AsyncLoop::RunOnce() or AsyncLoop::RunUntil() to run the
-///     the loop. This waits for the completion of async i/o events or
-///     expiration of timers, and invokes their callbacks automatically.
-///
-///     Using AsyncLoop::RunOnce(-1) will wait until one of the following
-///     happens:
-///
-///       - There are no more active handles or timers, in which case
-///         the function returns immediately with AsyncLoop::ExitIdle.
-///
-///       - At least one AsyncHandle's i/o operation completes, in which
-///         case their callbacks are invoked before the function returns
-///         AsyncLoop::ExitSuccess.
-///
-///       - At least one AsyncTimer expires, in which case their callbacks
-///         are invoked before the function returns AsyncLoop::ExitSuccess.
-///
-///       - If the AsyncLoop's interrupt catching feature is enabled (see
-///         below), return immediately with AsyncLoop::ExitInterrupted.
-///
-///     It is also possible to pass a timeout in milliseconds, e.g.
-///     calling AsyncLoop::RunOnce(1000) to wait for one second. If the
-///     timeout expires without an i/o completion or timer expiration,
-///     the function returns with AsyncLoop::ExitTimeout.
-///
-///     Calling AsyncLoop::RunUntil() is more convenient as it allows to
-///     wait for specific conditions instead.
-///
-/// Some important points:
-///
-/// - There is a global AsyncLoop instance which can be
-///   retrieved with AsyncLoop::Get(), this is meant to be
-///   used from the main thread only.
-///
-/// - Use AsyncLoop::CreateLocal() to create additionnal
-///   AsyncLoop instances. This can be useful to run them in
-///   background threads.
-///
-/// - It is a runtime error to destroy an AsyncLoop before any of its
-///   children AsyncHandle or AsyncTimer instances (assertion failure on
-///   debug build).
-///
-/// - An AsyncLoop instance can catch interrupts (i.e. Ctrl-C
-///   on Windows, and SIGINT/SIGUP/SIGTERM on Posix) automatically
-///   and report them in AsyncLoop::ExitStatus.
-///
-///   IMPORTANT: At the moment, the global AsyncLoop always catches
-///   interrupts by default. This may change in the future.
-///   TODO(digit): Change this and make all uses explicit.
-///
-///   Only one AsyncLoop instance can catch interrupts at any
-///   given time. Use AsyncLoop::ScopedInterruptCatcher if you
-///   want to force a given AsyncLoop instance to catch
-///   interrupts (see its documentation below for details).
-///
-/// - Once a timer expires, it must be re-armed explicitly, which can
-///   be done by calling its Set{Expiration,Duration}Ms() method directly
-///   from its callback.
-///
-/// - Similarly, it is possible (and actually the most efficient path)
-///   to start another i/o operation right from the completion callback
-///   of an AsyncHandle instance.
-///
-/// - AsyncLoop::RunOnce() and AsyncLoop::RunUntil() are not re-entrant,
-///   meaning one should not call them from completion / expiration callbacks.
-///
-///   On the other hand, creating / deleting AsyncHandle / AsyncTimer instances
-///   within callbacks is supported.
-///
-/// - There is no method to cancel all asynchronous operations
-///   associated with a handle, or to detach all handles. This
-///   is intentional.
-
-/// AsyncError is an error code returned by a failed asynchronous operation.
-/// On Win32, this is a GetLastError() value, while on Posix this is an errno
-/// value. Always 0 to indicate that there is no error.
-#ifdef _WIN32
-using AsyncError = DWORD;
-#else
-using AsyncError = int;
-#endif
-
-/// Forward declaration.
-class AsyncLoop;
-
-/// Convert AsyncError to string.
-std::string AsyncErrorToString(AsyncError error);
-
-/// Scoped AsyncHandle type that only supports one async operation
-/// at a time.
-class AsyncHandle {
- public:
-  /// The type of a callable object that will be invoked when an
-  /// asynchronous operation completes. The first argument is an error
-  /// code and will be 0 in case of success. The second argument is
-  /// the transfer size, and will be 0 to connect and accept operations.
-  using Callback = std::function<void(AsyncError, size_t)>;
-
-  /// Default constructor creates an empty instance.
-  AsyncHandle();
-
-  /// Destructor, closes the handle automatically.
-  ~AsyncHandle();
-
-  /// Move operations.
-  AsyncHandle(AsyncHandle&&) noexcept;
-  AsyncHandle& operator=(AsyncHandle&&) noexcept;
-
-  /// Create new instance that takes ownership of |native_handle|.
-  static AsyncHandle Create(IpcHandle::HandleType native_handle,
-                            AsyncLoop& async_loop, Callback&& callback);
-
-  /// Create a new instance that duplicates |native_handle| and takes
-  /// ownership of the resulting handle. Note that the duplicate is
-  /// not inheritable and will be in non-blocking mode on Posix.
-  static AsyncHandle CreateClone(IpcHandle::HandleType native_handle,
-                                 AsyncLoop& async_loop, Callback&& callback);
-
-  /// Create new instance that takes ownership of the native handle
-  /// from |handle|. Note that when |handle| is an IpcServiceHandle instance,
-  /// then it should only be destroyed _after_ this instance, in order to
-  /// perform proper cleanups on MacOS (i.e. remove a Unix domain socket and
-  /// pid file), even though ownership of the native handle itself was passed
-  /// to this AsyncHandle instance.
-  static AsyncHandle Create(IpcHandle handle, AsyncLoop& async_loop,
-                            Callback&& callback);
-
-  /// Close handle
-  void Close();
-
-  /// Release native handle ownership to caller.
-  /// Note that this cancels any async operation for the handle.
-  IpcHandle::HandleType Release();
-
-  /// Return true if the native handle is valid, and was not released.
-  bool is_valid() const;
-
-  /// Return value of native handle, but does not transfer ownership.
-  IpcHandle::HandleType native_handle() const;
-
-  /// Conversion to bool, equivalent to is_valid().
-  operator bool() const { return is_valid(); }
-
-  /// Return true if an asynchronous operation was started and
-  /// Did not complete yet.
-  bool IsRunning() const;
-
-  /// Cancel current asynchronous operation, if any.
-  void Cancel();
-
-  /// Change the callback for this instance.
-  AsyncHandle& ResetCallback(Callback&& cb);
-
-  /// Reset instance with a new native handle, keeping the same AsyncLoop
-  /// reference, and same callback. Calls Cancel() implicitly.
-  void ResetHandle(IpcHandle handle);
-
-  /// Start an asynchronous read operation. Cancels any previous operation.
-  void StartRead(void* buffer, size_t size);
-
-  /// Start an asynchronous write operation. Cancels any previous operation.
-  void StartWrite(const void* buffer, size_t size);
-
-  /// Start an asynchronous connect operation. Cancels any previous operation.
-  /// Note that this instance's handle should be the result of an
-  /// IpcServiceHandle::AsyncConnectTo() operation.
-  void StartConnect();
-
-  /// Start an asynchronous accept operation. Note that in case of success,
-  /// the client handle should be retrieved with TakeAcceptedHandle();
-  /// Cancels any previous operation.
-  /// Note that this instance's handle must be the result of an
-  /// IpcServiceHandle::BindTo() call.
-  void StartAccept();
-
-  /// Return the client handle corresponding to the last successful
-  /// asynchronous accept operation.
-  IpcHandle TakeAcceptedHandle();
-
-  /// Return AsyncLoop pointer from this handle. Will be nullptr if
-  /// handle is invalid (i.e. after an explicit Close()).
-  AsyncLoop& async_loop() const;
-
-  /// Opaque type for platform-dependent asynchronous operation.
-  class State;
-
- protected:
-  /// Private constructor, use AsyncLoop::CreateHandle() to
-  /// create a new non-default instance.
-  explicit AsyncHandle(std::unique_ptr<State> state);
-
-  std::unique_ptr<State> state_;
-};
-
-class AsyncTimer {
- public:
-  using Callback = std::function<void(void)>;
-
-  // Default constructor.
-  AsyncTimer();
-
-  // Constructor.
-  AsyncTimer(AsyncLoop& async_loop, Callback&& callback);
-
-  /// Destructor. Cancels the timer automatically.
-  ~AsyncTimer();
-
-  /// Move operations are allowed.
-  AsyncTimer(AsyncTimer&&) noexcept;
-  AsyncTimer& operator=(AsyncTimer&&) noexcept;
-
-  /// Return true if this instance is valid (i.e. not default constructed).
-  bool is_valid() const { return !!state_; }
-  operator bool() const { return is_valid(); }
-
-  /// Set the expiration time for this timer. After this the callback
-  /// will be invoked once.
-  void SetExpirationMs(int64_t expiration_ms);
-
-  /// Set a duration after which the timer will expire.
-  void SetDurationMs(int64_t duration_ms);
-
-  /// Cancel this timer (remove any expiration).
-  void Cancel();
-
-  /// Close the timer before destruction (makes it invalid).
-  void Close();
-
-  /// Reset the callback for this instance.
-  void ResetCallback(Callback&& callback);
-
-  /// Construct a new timer and set its expiration time directly.
-  static AsyncTimer CreateWithExpiration(int64_t expiration_ms,
-                                         AsyncLoop& async_loop,
-                                         Callback&& callback);
-
-  /// Construct a new timer and set its duration period directly.
-  static AsyncTimer CreateWithDuration(int64_t duration_ms,
-                                       AsyncLoop& async_loop,
-                                       Callback&& callback);
-
-  /// Retrieve reference to AsyncLoop this timer belongs to.
-  /// NOTE: It is a runtime error to call this on an invalid instance.
-  AsyncLoop& async_loop() const;
-
-  class State;
-
- private:
-  std::unique_ptr<State> state_;
-};
-
-/// A class used to create asynchronous operations and wait for their
-/// completion with a possible timeout. This also detect user interruptions
-/// through Ctrl-C / SIGINT / SIGTERM / SIGHUP.
-///
-class AsyncLoop {
- public:
-  /// Destructor
-  ~AsyncLoop();
-
-  /// Retrieve reference to global instance. Created on demand.
-  /// This instance always catches interrupts by default.
-  static AsyncLoop& Get();
-
-  /// Create a new instance independent from the global one. It does _not_
-  /// catches interrupts by default. This instance will have its own set of
-  /// timer and async IDs.
-  static std::unique_ptr<AsyncLoop> CreateLocal();
-
-  /// Destroy current global instance. Only use this for testing.
-  static void ResetForTesting();
-
-#ifdef _WIN32
-  using NativeHandle = HANDLE;
-#else
-  using NativeHandle = int;
-#endif
-
-  /// Each asynchonous operation is identified by a unique, non-zero, ID.
-  using AsyncId = uint32_t;
-
-  /// Return current time in milliseconds. Epoch is undetermined
-  /// but all values are guaranteed to be non-negative.
-  static int64_t NowMs();
-
-  /// Possible return values for RunOnce() method.
-  enum ExitStatus {
-    ExitIdle = 0,     // no more async ops or timers to wait for.
-    ExitSuccess,      // at least one async op completed or timer expired.
-    ExitTimeout,      // timeout expired.
-    ExitInterrupted,  // user interruption detected.
-  };
-
-  /// Run the loop once with a timeout. This function only returns after
-  /// a least one async operation / timer has completed, or on expiration,
-  /// or a user interrupt. A negative |timeout_ms| value corresponds to no
-  /// timeout at all, but the function may return with ExitIdle if there
-  /// are no more async operations registered. Note that ExitIdle
-  /// _cannot_ be returned if the value of |timeout_ms| is not negative.
-  /// Also the function cannot return ExitInterrupted if interrupt catching
-  /// is not enabled for this AsyncLoop instance.
-  ExitStatus RunOnce(int64_t timeout_ms);
-
-  /// Run the loop until a given condition is met, or an interrupt is
-  /// detected, or a timeout expires. This will return ExitSuccess,
-  /// ExitInterrupted and ExitTimeout respectively.
-  ///
-  /// Also, if no timeout is specified (i.e. the value of |timeout_ms|
-  /// is negative), this will return ExitIdle if there are no more
-  /// registered async operations or active timers.
-  ///
-  /// |condition| is a predicate to check for the condition, whose
-  /// value only depends on variables modified by async handlers or
-  /// timers.
-  ///
-  template <typename PREDICATE>
-  ExitStatus RunUntil(PREDICATE condition, int64_t timeout_ms = -1) {
-    RunUntilState state(timeout_ms);
-    do {
-      if (condition())
-        return ExitSuccess;
-    } while (state.LoopAgain(*this));
-    return state.status();
-  }
-
-  /// Clear the interrupt flag after it has been acknowledged by the caller.
-  void ClearInterrupt();
-
-#ifndef _WIN32
-  /// Return the signal number after RunOnce() returns with ExitInterrupted.
-  int GetInterruptSignal() const;
-
-  /// Return the process signal mask that was set before this instance was
-  /// created (since the constructor blocks all signals).
-  sigset_t GetOldSignalMask() const;
-#endif
-
-  /// Completely reset the instance, forgetting about all registered
-  /// async operations and timers, only the interrupt catcher count is
-  /// preserved.
-  void Reset();
-
-  /// Convenience struct that allows to temporarily redirect interrupts
-  /// (i.e. Ctrl-C on Windows, and SIGINT/SIGHUP/SIGTERM on Posix) to
-  /// a given AsyncLoop instance. Note that only one AsyncLoop instance can
-  /// catch them at any given point in the process.
-  ///
-  /// Usage is simply:
-  ///
-  ///   {
-  ///     AsyncLoop::ScopedInterruptCatcher catcher(async_loop);
-  ///
-  ///     ... all interrupts redirect to |async_loop| until the
-  ///     ... destructor is called.
-  ///   }
-  ///
-  /// It is safe to nest multiple catchers, which can even refer to the
-  /// same async_loop. Only the most-nested instance will get the interrupts.
-  ///
-  struct ScopedInterruptCatcher {
-    explicit ScopedInterruptCatcher(AsyncLoop& async_loop)
-        : async_loop_(async_loop) {
-      async_loop_.ChangeInterruptCatcher(true);
-    }
-
-    ~ScopedInterruptCatcher() { async_loop_.ChangeInterruptCatcher(false); }
-
-    AsyncLoop& async_loop_;
-  };
-
- private:
-  friend class AsyncHandle::State;
-  friend class AsyncTimer::State;
-  friend class AsyncLoopTimers;
-
-  AsyncLoop();
-
-  // Used internally to implement AsyncHandles.
-  void AttachHandle(AsyncHandle::State* state);
-  void DetachHandle(AsyncHandle::State* state);
-  void UpdateHandle(AsyncHandle::State* state);
-  void CancelHandle(AsyncHandle::State* state);
-
-  void AttachTimer(AsyncTimer::State* state);
-  void DetachTimer(AsyncTimer::State* state);
-  void UpdateTimer(AsyncTimer::State* state);
-
-  /// Internal struct used by RunUntil() template instantiations.
-  struct RunUntilState {
-    /// Constructor sets up the state.
-    RunUntilState(int64_t timeout_ms);
-
-    /// Call this method to call RunOnce() to drain events or
-    /// timers. Returns true to indicate that the function
-    /// must be called again, and false in case of exit
-    /// condition (reported by status()).
-    bool LoopAgain(AsyncLoop& async_loop);
-
-    /// Return final status, only valid after LoopAgain()
-    /// returns false. Cannot be ExitSuccess.
-    ExitStatus status() const { return status_; }
-
-    int64_t timeout_ms_;
-    int64_t expiration_ms_ = -1;
-    ExitStatus status_ = ExitIdle;
-  };
-
-  /// Used internally by ScopedInterruptCatcher class.
-  void ChangeInterruptCatcher(bool increment);
-
-  /// Implementation details hidden from this header intentionally.
-  class Impl;
-  std::unique_ptr<Impl> impl_;
-  int interrupt_catcher_count_ = 0;
-};
-
-#endif  // NINJA_ASYNC_LOOP_H
diff --git a/src/async_loop_test.cc b/src/async_loop_test.cc
deleted file mode 100644
index c14c08d..0000000
--- a/src/async_loop_test.cc
+++ /dev/null
@@ -1,271 +0,0 @@
-// Copyright 2023 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 "async_loop.h"
-
-// This file also includes tests for the AsyncLoopTimers class.
-#include "async_loop_timers.h"
-#include "ipc_handle.h"
-#include "test.h"
-
-static AsyncLoop& GetNewLoop() {
-  AsyncLoop::ResetForTesting();
-  return AsyncLoop::Get();
-}
-
-TEST(AsyncLoop, NowMs) {
-  AsyncLoop& loop = GetNewLoop();
-  // Ensure the result of NowMs() is always positive, otherwise many
-  // things will not work correctly since a negative expiration date is
-  // interpreted as infinite.
-  EXPECT_GE(loop.NowMs(), 0LL);
-}
-
-// Helper type to store async operation results.
-struct AsyncResult {
-  bool completed = false;
-  AsyncError error = 0;
-  size_t size = 0;
-
-  AsyncHandle::Callback callback() {
-    return [this](AsyncError error, size_t size) {
-      this->completed = true;
-      this->error = error;
-      this->size = size;
-    };
-  }
-};
-
-TEST(AsyncLoop, AsyncHandleStartRead) {
-  std::string err_msg;
-  IpcHandle read_handle, write_handle;
-  bool ret = IpcHandle::CreateAsyncPipe(&read_handle, &write_handle, &err_msg);
-  if (!ret)
-    fprintf(stderr, "CreatePipe() error: %s\n", err_msg.c_str());
-  ASSERT_TRUE(ret);
-
-  AsyncLoop& loop = GetNewLoop();
-  char read_buffer[10] = {};
-
-  AsyncResult result;
-  auto async_handle =
-      AsyncHandle::Create(std::move(read_handle), loop, result.callback());
-  async_handle.StartRead(read_buffer, sizeof(read_buffer));
-
-  // Nothing should be accepted in the next 50ms
-  auto status = loop.RunOnce(50);
-  EXPECT_EQ(AsyncLoop::ExitTimeout, status);
-  EXPECT_FALSE(result.completed);
-
-  // Write to the pipe.
-  char buf[1] = { 'x' };
-  EXPECT_EQ(1, write_handle.Write(buf, sizeof(buf), &err_msg));
-
-  status = loop.RunOnce(50);
-  EXPECT_EQ(AsyncLoop::ExitSuccess, status);
-  EXPECT_TRUE(result.completed);
-  EXPECT_EQ(0u, result.error);
-  EXPECT_EQ(1u, result.size);
-  EXPECT_EQ('x', read_buffer[0]);
-}
-
-TEST(AsyncLoop, AsyncHandleStartWrite) {
-  std::string err_msg;
-  IpcHandle read_handle, write_handle;
-  bool ret = IpcHandle::CreateAsyncPipe(&read_handle, &write_handle, &err_msg);
-  if (!ret)
-    fprintf(stderr, "CreatePipe() error: %s\n", err_msg.c_str());
-  ASSERT_TRUE(ret);
-
-  AsyncLoop& loop = GetNewLoop();
-  const char buffer[] = "foo bar";
-
-  AsyncResult result;
-  auto async_handle =
-      AsyncHandle::Create(std::move(write_handle), loop, result.callback());
-  async_handle.StartWrite(buffer, sizeof(buffer));
-
-  // Writing should work directly.
-  auto status = loop.RunOnce(50);
-  EXPECT_EQ(AsyncLoop::ExitSuccess, status);
-
-  EXPECT_TRUE(result.completed);
-  EXPECT_EQ(0u, result.error);
-  EXPECT_EQ(sizeof(buffer), result.size);
-
-  // Read from pipe synchronously.
-  char read_buffer[sizeof(buffer)];
-  ssize_t actual_bytes =
-      read_handle.Read(read_buffer, sizeof(buffer), &err_msg);
-  EXPECT_EQ(sizeof(buffer), static_cast<size_t>(actual_bytes));
-}
-
-TEST(AsyncLoop, AsyncHandleStartAccept) {
-  std::string err_msg;
-  auto server_handle = IpcServiceHandle::BindTo("test_service", &err_msg);
-  if (!server_handle)
-    fprintf(stderr, "BindTo() error: %s\n", err_msg.c_str());
-  ASSERT_TRUE(server_handle);
-
-  AsyncLoop& loop = GetNewLoop();
-
-  AsyncResult result;
-  auto async_handle =
-      AsyncHandle::Create(std::move(server_handle), loop, result.callback());
-  async_handle.StartAccept();
-
-  // Nothing should be accepted in the next 50ms
-  auto status = loop.RunOnce(50);
-  EXPECT_EQ(AsyncLoop::ExitTimeout, status);
-  EXPECT_FALSE(result.completed);
-
-  // Synchronous connect.
-  IpcHandle client = IpcServiceHandle::ConnectTo("test_service", &err_msg);
-  if (!client)
-    fprintf(stderr, "ConnectTo() error: %s\n", err_msg.c_str());
-  ASSERT_TRUE(client);
-
-  status = loop.RunOnce(50);
-  EXPECT_EQ(AsyncLoop::ExitSuccess, status);
-  EXPECT_TRUE(result.completed);
-  EXPECT_EQ(0, result.error);
-
-  IpcHandle accept_handle = async_handle.TakeAcceptedHandle();
-  EXPECT_TRUE(accept_handle);
-  EXPECT_NE(accept_handle.native_handle(), client.native_handle());
-}
-
-TEST(AsyncLoop, AsyncHandleStartConnect) {
-  std::string err_msg;
-  auto server_handle = IpcServiceHandle::BindTo("test_service", &err_msg);
-  if (!server_handle)
-    fprintf(stderr, "BindTo() error: %s\n", err_msg.c_str());
-  ASSERT_TRUE(server_handle);
-
-  bool did_connect = false;
-  IpcHandle client_handle =
-      IpcServiceHandle::AsyncConnectTo("test_service", &did_connect, &err_msg);
-  if (!client_handle)
-    fprintf(stderr, "AsyncClientTo() error: %s\n", err_msg.c_str());
-  ASSERT_TRUE(client_handle);
-
-  (void)did_connect;  // ignored intentionally.
-
-  AsyncLoop& loop = GetNewLoop();
-
-  AsyncResult result;
-  auto async_handle =
-      AsyncHandle::Create(std::move(client_handle), loop, result.callback());
-  async_handle.StartConnect();
-
-  auto status = loop.RunOnce(50);
-  EXPECT_EQ(AsyncLoop::ExitSuccess, status);
-  EXPECT_TRUE(result.completed);
-  EXPECT_EQ(0, result.error);
-  EXPECT_EQ(0, result.size);
-}
-
-TEST(AsyncLoop, RunUntil) {
-  AsyncLoop& loop = GetNewLoop();
-
-  auto always_false = []() { return false; };
-
-  auto status = loop.RunUntil(always_false, -1);
-  EXPECT_EQ(AsyncLoop::ExitIdle, status);
-
-  status = loop.RunUntil(always_false, 10);
-  EXPECT_EQ(AsyncLoop::ExitTimeout, status);
-
-  bool flag = false;
-  auto flag_is_set = [&flag]() { return flag; };
-  AsyncTimer timer(loop, [&flag]() { flag = true; });
-
-  timer.SetDurationMs(100LL);
-  status = loop.RunUntil(flag_is_set, -1);
-  EXPECT_EQ(AsyncLoop::ExitSuccess, status);
-
-  flag = false;
-  timer.SetDurationMs(1000LL);
-  status = loop.RunUntil(flag_is_set, 10LL);
-  EXPECT_EQ(AsyncLoop::ExitTimeout, status);
-
-  status = loop.RunUntil(flag_is_set, -1);
-  EXPECT_EQ(AsyncLoop::ExitSuccess, status);
-}
-
-TEST(AsyncLoop, TimerTest) {
-  AsyncLoop& loop = GetNewLoop();
-  int counter = 0;
-  AsyncTimer timer_1(loop, [&counter]() { counter += 1; });
-  timer_1.SetDurationMs(100LL);
-  EXPECT_EQ(AsyncLoop::ExitTimeout, loop.RunOnce(0));
-  EXPECT_EQ(0, counter);
-
-  EXPECT_EQ(AsyncLoop::ExitSuccess, loop.RunOnce(200));
-  EXPECT_EQ(1, counter);
-}
-
-TEST(AsyncLoopTimers, Test) {
-  AsyncLoopTimers timers;
-
-  EXPECT_EQ(-1LL, timers.ComputeNextExpiration());
-
-  int counter = 0;
-
-  // Create local loop, required by AsyncTimer::State construtor
-  // but not used by the test though because its RunOnce() method is never
-  // called.
-  auto loop = AsyncLoop::CreateLocal();
-
-  auto timer_1 = std::unique_ptr<AsyncTimer::State>(
-      new AsyncTimer::State(*loop, [&counter]() { counter += 1; }));
-
-  auto timer_2 = std::unique_ptr<AsyncTimer::State>(
-      new AsyncTimer::State(*loop, [&counter]() { counter += 100; }));
-
-  timers.AttachTimer(timer_1.get());
-  timers.AttachTimer(timer_2.get());
-
-  EXPECT_EQ(-1LL, timers.ComputeNextExpiration());
-
-  timer_1->SetExpirationMs(100LL);
-
-  EXPECT_EQ(100LL, timers.ComputeNextExpiration());
-  EXPECT_EQ(0, counter);
-
-  timer_2->SetExpirationMs(200LL);
-  EXPECT_EQ(100LL, timers.ComputeNextExpiration());
-  EXPECT_EQ(0, counter);
-
-  EXPECT_FALSE(timers.ProcessExpiration(99LL));
-  EXPECT_EQ(100LL, timers.ComputeNextExpiration());
-  EXPECT_EQ(0, counter);
-
-  EXPECT_TRUE(timers.ProcessExpiration(100LL));
-  EXPECT_EQ(1, counter);
-  EXPECT_EQ(200LL, timers.ComputeNextExpiration());
-
-  EXPECT_TRUE(timers.ProcessExpiration(200LL));
-  EXPECT_EQ(101, counter);
-  EXPECT_EQ(-1LL, timers.ComputeNextExpiration());
-
-  timer_1->SetExpirationMs(200LL);
-  timers.DetachTimer(timer_1.get());
-  timers.DetachTimer(timer_2.get());
-
-  EXPECT_EQ(-1LL, timers.ComputeNextExpiration());
-
-  EXPECT_FALSE(timers.ProcessExpiration(300LL));
-  EXPECT_EQ(101, counter);
-}
diff --git a/src/async_loop_timers.h b/src/async_loop_timers.h
deleted file mode 100644
index 0b93020..0000000
--- a/src/async_loop_timers.h
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2023 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_ASYNC_LOOP_TIMERS_H
-#define NINJA_ASYNC_LOOP_TIMERS_H
-
-#include <algorithm>
-#include <vector>
-
-#include "async_loop.h"
-
-class AsyncTimer::State {
- public:
-  State(AsyncLoop& async_loop, AsyncTimer::Callback&& callback)
-      : async_loop_(async_loop), callback_(std::move(callback)) {
-    async_loop_.AttachTimer(this);
-  }
-
-  ~State() { async_loop_.DetachTimer(this); }
-
-  AsyncLoop& async_loop() const { return async_loop_; }
-
-  // Return true if this instance is active.
-  bool active() const { return expiration_ms_ >= 0; }
-
-  int64_t expiration_ms() const { return expiration_ms_; }
-
-  void ResetCallback(AsyncTimer::Callback&& callback) {
-    callback_ = std::move(callback);
-  }
-
-  void SetExpirationMs(int64_t expiration_ms) {
-    expiration_ms_ = expiration_ms;
-    async_loop_.UpdateTimer(this);
-  }
-
-  void SetDurationMs(int64_t duration_ms) {
-    SetExpirationMs(async_loop_.NowMs() + duration_ms);
-  }
-
-  void Cancel() { SetExpirationMs(-1); }
-
-  void Invoke() {
-    expiration_ms_ = -1;
-    callback_();
-  }
-
- private:
-  AsyncLoop& async_loop_;
-  int64_t expiration_ms_ = -1;
-  AsyncTimer::Callback callback_;
-};
-
-/// Common class used by all AsyncLoop implementation to manage timers.
-class AsyncLoopTimers {
- public:
-  void AttachTimer(AsyncTimer::State* timer) { timers_.push_back(timer); }
-
-  void DetachTimer(AsyncTimer::State* timer) {
-    pending_.erase(timer);
-    timers_.erase(timer);
-  }
-
-  void UpdateTimer(AsyncTimer::State* timer) { pending_.erase(timer); }
-
-  /// Compute the next expiration time in milliseconds, or return -1 if
-  /// not timer is active.
-  int64_t ComputeNextExpiration() const {
-    int64_t result = -1;
-    for (const auto* timer : timers_) {
-      if (!timer->active())
-        continue;
-      if (result < 0)
-        result = timer->expiration_ms();
-      else if (result > timer->expiration_ms())
-        result = timer->expiration_ms();
-    }
-    return result;
-  }
-
-  /// Compute the set of pending timers at a given time.
-  /// Return true if any timer expired, false otherwise.
-  bool ProcessExpiration(int64_t now_ms) {
-    // First compute the list of pending timers.
-    pending_.clear();
-    for (auto* timer : timers_) {
-      if (timer->active() && timer->expiration_ms() <= now_ms)
-        pending_.push_back(timer);
-    }
-
-    if (pending_.empty())
-      return false;
-
-    // Then process it. Each callback can end up calling ResetExpiration()
-    // or Destroy() which will remove or deactivate pending timers so do
-    // not assume that each id in the list is valid on each iteration.
-    do {
-      AsyncTimer::State* state = pending_.back();
-      pending_.pop_back();
-      state->Invoke();
-    } while (!pending_.empty());
-
-    return true;
-  }
-
-  // Return true if there are no timers in this set.
-  bool empty() const { return timers_.empty(); }
-
- private:
-  struct TimerList : public std::vector<AsyncTimer::State*> {
-    void erase(AsyncTimer::State* state) {
-      auto it = std::find(begin(), end(), state);
-      if (it != end()) {
-        *it = back();
-        pop_back();
-      }
-    }
-  };
-
-  TimerList timers_;
-  TimerList pending_;
-};
-
-#endif  // NINJA_ASYNC_LOOP_TIMERS_H
diff --git a/src/browse.cc b/src/browse.cc
deleted file mode 100644
index 76bee07..0000000
--- a/src/browse.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// 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.
-
-#include "browse.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <vector>
-
-#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.
-  // (Actually the Python process becomes the parent.)
-  int pipefd[2];
-  if (pipe(pipefd) < 0) {
-    perror("ninja: pipe");
-    return;
-  }
-
-  pid_t pid = fork();
-  if (pid < 0) {
-    perror("ninja: fork");
-    return;
-  }
-
-  if (pid > 0) {  // Parent.
-    close(pipefd[1]);
-    do {
-      if (dup2(pipefd[0], 0) < 0) {
-        perror("ninja: dup2");
-        break;
-      }
-
-      std::vector<const char *> command;
-      command.push_back(NINJA_PYTHON);
-      command.push_back("-");
-      command.push_back("--ninja-command");
-      command.push_back(ninja_command);
-      command.push_back("-f");
-      command.push_back(input_file);
-      for (int i = 0; i < argc; i++) {
-          command.push_back(argv[i]);
-      }
-      command.push_back(NULL);
-      execvp(command[0], (char**)&command[0]);
-      if (errno == ENOENT) {
-        printf("ninja: %s is required for the browse tool\n", NINJA_PYTHON);
-      } else {
-        perror("ninja: execvp");
-      }
-    } while (false);
-    _exit(1);
-  } else {  // Child.
-    close(pipefd[0]);
-
-    // Write the script file into the stdin of the Python process.
-    ssize_t len = write(pipefd[1], kBrowsePy, sizeof(kBrowsePy));
-    if (len < (ssize_t)sizeof(kBrowsePy))
-      perror("ninja: write");
-    close(pipefd[1]);
-    exit(0);
-  }
-}
diff --git a/src/browse.h b/src/browse.h
deleted file mode 100644
index 8d6d285..0000000
--- a/src/browse.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.
-
-#ifndef NINJA_BROWSE_H_
-#define NINJA_BROWSE_H_
-
-struct State;
-
-/// Run in "browse" mode, which execs a Python webserver.
-/// \a ninja_command is the command used to invoke ninja.
-/// \a args are the number of arguments to be passed to the Python script.
-/// \a argv are arguments to be passed to the Python script.
-/// This function does not return if it runs successfully.
-void RunBrowsePython(State* state, const char* ninja_command,
-                     const char* input_file, int argc, char* argv[]);
-
-#endif  // NINJA_BROWSE_H_
diff --git a/src/browse.py b/src/browse.py
deleted file mode 100755
index b125e80..0000000
--- a/src/browse.py
+++ /dev/null
@@ -1,231 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2001 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.
-
-"""Simple web server for browsing dependency graph data.
-
-This script is inlined into the final executable and spawned by
-it when needed.
-"""
-
-try:
-    import http.server as httpserver
-    import socketserver
-except ImportError:
-    import BaseHTTPServer as httpserver
-    import SocketServer as socketserver
-import argparse
-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:
-    from urllib2 import unquote
-from collections import namedtuple
-
-Node = namedtuple('Node', ['inputs', 'rule', 'target', 'outputs'])
-
-# Ideally we'd allow you to navigate to a build edge or a build node,
-# with appropriate views for each.  But there's no way to *name* a build
-# edge so we can only display nodes.
-#
-# For a given node, it has at most one input edge, which has n
-# different inputs.  This becomes node.inputs.  (We leave out the
-# outputs of the input edge due to what follows.)  The node can have
-# multiple dependent output edges.  Rather than attempting to display
-# those, they are summarized by taking the union of all their outputs.
-#
-# This means there's no single view that shows you all inputs and outputs
-# of an edge.  But I think it's less confusing than alternatives.
-
-def match_strip(line, prefix):
-    if not line.startswith(prefix):
-        return (False, line)
-    return (True, line[len(prefix):])
-
-def html_escape(text):
-    return escape(text, quote=True)
-
-def parse(text):
-    lines = iter(text.split('\n'))
-
-    target = None
-    rule = None
-    inputs = []
-    outputs = []
-
-    try:
-        target = next(lines)[:-1]  # strip trailing colon
-
-        line = next(lines)
-        (match, rule) = match_strip(line, '  input: ')
-        if match:
-            (match, line) = match_strip(next(lines), '    ')
-            while match:
-                type = None
-                (match, line) = match_strip(line, '| ')
-                if match:
-                    type = 'implicit'
-                (match, line) = match_strip(line, '|| ')
-                if match:
-                    type = 'order-only'
-                inputs.append((line, type))
-                (match, line) = match_strip(next(lines), '    ')
-
-        match, _ = match_strip(line, '  outputs:')
-        if match:
-            (match, line) = match_strip(next(lines), '    ')
-            while match:
-                outputs.append(line)
-                (match, line) = match_strip(next(lines), '    ')
-    except StopIteration:
-        pass
-
-    return Node(inputs, rule, target, outputs)
-
-def create_page(body):
-    return '''<!DOCTYPE html>
-<style>
-body {
-    font-family: sans;
-    font-size: 0.8em;
-    margin: 4ex;
-}
-h1 {
-    font-weight: normal;
-    font-size: 140%;
-    text-align: center;
-    margin: 0;
-}
-h2 {
-    font-weight: normal;
-    font-size: 120%;
-}
-tt {
-    font-family: WebKitHack, monospace;
-    white-space: nowrap;
-}
-.filelist {
-  -webkit-columns: auto 2;
-}
-</style>
-''' + body
-
-def generate_html(node):
-    document = ['<h1><tt>%s</tt></h1>' % html_escape(node.target)]
-
-    if node.inputs:
-        document.append('<h2>target is built using rule <tt>%s</tt> of</h2>' %
-                        html_escape(node.rule))
-        if len(node.inputs) > 0:
-            document.append('<div class=filelist>')
-            for input, type in sorted(node.inputs):
-                extra = ''
-                if type:
-                    extra = ' (%s)' % html_escape(type)
-                document.append('<tt><a href="?%s">%s</a>%s</tt><br>' %
-                                (html_escape(input), html_escape(input), extra))
-            document.append('</div>')
-
-    if node.outputs:
-        document.append('<h2>dependent edges build:</h2>')
-        document.append('<div class=filelist>')
-        for output in sorted(node.outputs):
-            document.append('<tt><a href="?%s">%s</a></tt><br>' %
-                            (html_escape(output), html_escape(output)))
-        document.append('</div>')
-
-    return '\n'.join(document)
-
-def ninja_dump(target):
-    cmd = [args.ninja_command, '-f', args.f, '-t', 'query', target]
-    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
-                            universal_newlines=True)
-    return proc.communicate() + (proc.returncode,)
-
-class RequestHandler(httpserver.BaseHTTPRequestHandler):
-    def do_GET(self):
-        assert self.path[0] == '/'
-        target = unquote(self.path[1:])
-
-        if target == '':
-            self.send_response(302)
-            self.send_header('Location', '?' + args.initial_target)
-            self.end_headers()
-            return
-
-        if not target.startswith('?'):
-            self.send_response(404)
-            self.end_headers()
-            return
-        target = target[1:]
-
-        ninja_output, ninja_error, exit_code = ninja_dump(target)
-        if exit_code == 0:
-            page_body = generate_html(parse(ninja_output.strip()))
-        else:
-            # Relay ninja's error message.
-            page_body = '<h1><tt>%s</tt></h1>' % html_escape(ninja_error)
-
-        self.send_response(200)
-        self.end_headers()
-        self.wfile.write(create_page(page_body).encode('utf-8'))
-
-    def log_message(self, format, *args):
-        pass  # Swallow console spam.
-
-parser = argparse.ArgumentParser(prog='ninja -t browse')
-parser.add_argument('--port', '-p', default=8000, type=int,
-    help='Port number to use (default %(default)d)')
-parser.add_argument('--hostname', '-a', default='localhost', type=str,
-    help='Hostname to bind to (default %(default)s)')
-parser.add_argument('--no-browser', action='store_true',
-    help='Do not open a webbrowser on startup.')
-
-parser.add_argument('--ninja-command', default='ninja',
-    help='Path to ninja binary (default %(default)s)')
-parser.add_argument('-f', default='build.ninja',
-    help='Path to build.ninja file (default %(default)s)')
-parser.add_argument('initial_target', default='all', nargs='?',
-    help='Initial target to show (default %(default)s)')
-
-class HTTPServer(socketserver.ThreadingMixIn, httpserver.HTTPServer):
-    # terminate server immediately when Python exits.
-    daemon_threads = True
-
-args = parser.parse_args()
-port = args.port
-hostname = args.hostname
-httpd = HTTPServer((hostname,port), RequestHandler)
-try:
-    if hostname == "":
-        hostname = socket.gethostname()
-    print('Web server running on %s:%d, ctl-C to abort...' % (hostname,port) )
-    print('Web server pid %d' % os.getpid(), file=sys.stderr )
-    if not args.no_browser:
-        webbrowser.open_new('http://%s:%s' % (hostname, port) )
-    httpd.serve_forever()
-except KeyboardInterrupt:
-    print()
-    pass  # Swallow console spam.
-
-
diff --git a/src/build.cc b/src/build.cc
deleted file mode 100644
index bca3e8d..0000000
--- a/src/build.cc
+++ /dev/null
@@ -1,964 +0,0 @@
-// 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.
-
-#include "build.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <functional>
-
-#if defined(__SVR4) && defined(__sun)
-#include <sys/termios.h>
-#endif
-
-#include "async_loop.h"
-#include "build_config.h"
-#include "build_log.h"
-#include "clparser.h"
-#include "debug_flags.h"
-#include "depfile_parser.h"
-#include "deps_log.h"
-#include "disk_interface.h"
-#include "graph.h"
-#include "metrics.h"
-#include "state.h"
-#include "status.h"
-#include "subprocess.h"
-#include "util.h"
-
-using namespace std;
-
-namespace {
-
-/// A CommandRunner that doesn't actually run the commands.
-struct DryRunCommandRunner : public CommandRunner {
-  virtual ~DryRunCommandRunner() {}
-
-  // Overridden from CommandRunner:
-  bool CanRunMore() const override;
-  bool StartCommand(Edge* edge) override;
-  bool WaitForCommand(Result* result) override;
-
- private:
-  queue<Edge*> finished_;
-};
-
-bool DryRunCommandRunner::CanRunMore() const {
-  return true;
-}
-
-bool DryRunCommandRunner::StartCommand(Edge* edge) {
-  finished_.push(edge);
-  return true;
-}
-
-bool DryRunCommandRunner::WaitForCommand(Result* result) {
-  if (finished_.empty())
-    return false;
-
-  result->status = ExitSuccess;
-  result->edge = finished_.front();
-  finished_.pop();
-  return true;
-}
-
-}  // namespace
-
-Plan::Plan(Builder* builder)
-  : builder_(builder)
-  , command_edges_(0)
-  , wanted_edges_(0)
-{}
-
-void Plan::Reset() {
-  command_edges_ = 0;
-  wanted_edges_ = 0;
-  ready_.clear();
-  want_.clear();
-}
-
-bool Plan::AddTarget(const Node* target, string* err) {
-  return AddSubTarget(target, NULL, err, NULL);
-}
-
-bool Plan::AddSubTarget(const Node* node, const Node* dependent, string* err,
-                        set<Edge*>* dyndep_walk) {
-  Edge* edge = node->in_edge();
-  if (!edge) {
-    // Leaf node, this can be either a regular input from the manifest
-    // (e.g. a source file), or an implicit input from a depfile or dyndep
-    // file. In the first case, a dirty flag means the file is missing,
-    // and the build should stop. In the second, do not do anything here
-    // since there is no producing edge to add to the plan.
-    if (node->dirty() && !node->generated_by_dep_loader()) {
-      string referenced;
-      if (dependent)
-        referenced = ", needed by '" + dependent->path() + "',";
-      *err = "'" + node->path() + "'" + referenced + " missing "
-             "and no known rule to make it";
-    }
-    return false;
-  }
-
-  if (edge->outputs_ready())
-    return false;  // Don't need to do anything.
-
-  // If an entry in want_ does not already exist for edge, create an entry which
-  // maps to kWantNothing, indicating that we do not want to build this entry itself.
-  pair<map<Edge*, Want>::iterator, bool> want_ins =
-    want_.insert(make_pair(edge, kWantNothing));
-  Want& want = want_ins.first->second;
-
-  if (dyndep_walk && want == kWantToFinish)
-    return false;  // Don't need to do anything with already-scheduled edge.
-
-  // If we do need to build edge and we haven't already marked it as wanted,
-  // mark it now.
-  if (node->dirty() && want == kWantNothing) {
-    want = kWantToStart;
-    EdgeWanted(edge);
-    if (!dyndep_walk && edge->AllInputsReady())
-      ScheduleWork(want_ins.first);
-  }
-
-  if (dyndep_walk)
-    dyndep_walk->insert(edge);
-
-  if (!want_ins.second)
-    return true;  // We've already processed the inputs.
-
-  for (vector<Node*>::iterator i = edge->inputs_.begin();
-       i != edge->inputs_.end(); ++i) {
-    if (!AddSubTarget(*i, node, err, dyndep_walk) && !err->empty())
-      return false;
-  }
-
-  return true;
-}
-
-void Plan::EdgeWanted(const Edge* edge) {
-  ++wanted_edges_;
-  if (!edge->is_phony())
-    ++command_edges_;
-}
-
-Edge* Plan::FindWork() {
-  if (ready_.empty())
-    return NULL;
-  EdgeSet::iterator e = ready_.begin();
-  Edge* edge = *e;
-  ready_.erase(e);
-  return edge;
-}
-
-void Plan::ScheduleWork(map<Edge*, Want>::iterator want_e) {
-  if (want_e->second == kWantToFinish) {
-    // This edge has already been scheduled.  We can get here again if an edge
-    // and one of its dependencies share an order-only input, or if a node
-    // duplicates an out edge (see https://github.com/ninja-build/ninja/pull/519).
-    // Avoid scheduling the work again.
-    return;
-  }
-  assert(want_e->second == kWantToStart);
-  want_e->second = kWantToFinish;
-
-  Edge* edge = want_e->first;
-  Pool* pool = edge->pool();
-  if (pool->ShouldDelayEdge()) {
-    pool->DelayEdge(edge);
-    pool->RetrieveReadyEdges(&ready_);
-  } else {
-    pool->EdgeScheduled(*edge);
-    ready_.insert(edge);
-  }
-}
-
-bool Plan::EdgeFinished(Edge* edge, EdgeResult result, string* err) {
-  map<Edge*, Want>::iterator e = want_.find(edge);
-  assert(e != want_.end());
-  bool directly_wanted = e->second != kWantNothing;
-
-  // See if this job frees up any delayed jobs.
-  if (directly_wanted)
-    edge->pool()->EdgeFinished(*edge);
-  edge->pool()->RetrieveReadyEdges(&ready_);
-
-  // The rest of this function only applies to successful commands.
-  if (result != kEdgeSucceeded)
-    return true;
-
-  if (directly_wanted)
-    --wanted_edges_;
-  want_.erase(e);
-  edge->outputs_ready_ = true;
-
-  // Check off any nodes we were waiting for with this edge.
-  for (vector<Node*>::iterator o = edge->outputs_.begin();
-       o != edge->outputs_.end(); ++o) {
-    if (!NodeFinished(*o, err))
-      return false;
-  }
-  return true;
-}
-
-bool Plan::NodeFinished(Node* node, string* err) {
-  // If this node provides dyndep info, load it now.
-  if (node->dyndep_pending()) {
-    assert(builder_ && "dyndep requires Plan to have a Builder");
-    // Load the now-clean dyndep file.  This will also update the
-    // build plan and schedule any new work that is ready.
-    return builder_->LoadDyndeps(node, err);
-  }
-
-  // See if we we want any edges from this node.
-  for (vector<Edge*>::const_iterator oe = node->out_edges().begin();
-       oe != node->out_edges().end(); ++oe) {
-    map<Edge*, Want>::iterator want_e = want_.find(*oe);
-    if (want_e == want_.end())
-      continue;
-
-    // See if the edge is now ready.
-    if (!EdgeMaybeReady(want_e, err))
-      return false;
-  }
-  return true;
-}
-
-bool Plan::EdgeMaybeReady(map<Edge*, Want>::iterator want_e, string* err) {
-  Edge* edge = want_e->first;
-  if (edge->AllInputsReady()) {
-    if (want_e->second != kWantNothing) {
-      ScheduleWork(want_e);
-    } else {
-      // We do not need to build this edge, but we might need to build one of
-      // its dependents.
-      if (!EdgeFinished(edge, kEdgeSucceeded, err))
-        return false;
-    }
-  }
-  return true;
-}
-
-bool Plan::CleanNode(DependencyScan* scan, Node* node, string* err) {
-  node->set_dirty(false);
-
-  for (vector<Edge*>::const_iterator oe = node->out_edges().begin();
-       oe != node->out_edges().end(); ++oe) {
-    // Don't process edges that we don't actually want.
-    map<Edge*, Want>::iterator want_e = want_.find(*oe);
-    if (want_e == want_.end() || want_e->second == kWantNothing)
-      continue;
-
-    // Don't attempt to clean an edge if it failed to load deps.
-    if ((*oe)->deps_missing_)
-      continue;
-
-    // If all non-order-only inputs for this edge are now clean,
-    // we might have changed the dirty state of the outputs.
-    vector<Node*>::iterator
-        begin = (*oe)->inputs_.begin(),
-        end = (*oe)->inputs_.end() - (*oe)->order_only_deps_;
-#if __cplusplus < 201703L
-#define MEM_FN mem_fun
-#else
-#define MEM_FN mem_fn  // mem_fun was removed in C++17.
-#endif
-    if (find_if(begin, end, MEM_FN(&Node::dirty)) == end) {
-      // Recompute most_recent_input.
-      Node* most_recent_input = NULL;
-      for (vector<Node*>::iterator i = begin; i != end; ++i) {
-        if (!most_recent_input || (*i)->mtime() > most_recent_input->mtime())
-          most_recent_input = *i;
-      }
-
-      // Now, this edge is dirty if any of the outputs are dirty.
-      // If the edge isn't dirty, clean the outputs and mark the edge as not
-      // wanted.
-      bool outputs_dirty = false;
-      if (!scan->RecomputeOutputsDirty(*oe, most_recent_input,
-                                       &outputs_dirty, err)) {
-        return false;
-      }
-      if (!outputs_dirty) {
-        for (vector<Node*>::iterator o = (*oe)->outputs_.begin();
-             o != (*oe)->outputs_.end(); ++o) {
-          if (!CleanNode(scan, *o, err))
-            return false;
-        }
-
-        want_e->second = kWantNothing;
-        --wanted_edges_;
-        if (!(*oe)->is_phony())
-          --command_edges_;
-      }
-    }
-  }
-  return true;
-}
-
-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.
-  if (!RefreshDyndepDependents(scan, node, err))
-    return false;
-
-  // We loaded dyndep information for those out_edges of the dyndep node that
-  // specify the node in a dyndep binding, but they may not be in the plan.
-  // Starting with those already in the plan, walk newly-reachable portion
-  // of the graph through the dyndep-discovered dependencies.
-
-  // Find edges in the the build plan for which we have new dyndep info.
-  std::vector<DyndepFile::const_iterator> dyndep_roots;
-  for (DyndepFile::const_iterator oe = ddf.begin(); oe != ddf.end(); ++oe) {
-    Edge* edge = oe->first;
-
-    // If the edge outputs are ready we do not need to consider it here.
-    if (edge->outputs_ready())
-      continue;
-
-    map<Edge*, Want>::iterator want_e = want_.find(edge);
-
-    // If the edge has not been encountered before then nothing already in the
-    // plan depends on it so we do not need to consider the edge yet either.
-    if (want_e == want_.end())
-      continue;
-
-    // This edge is already in the plan so queue it for the walk.
-    dyndep_roots.push_back(oe);
-  }
-
-  // Walk dyndep-discovered portion of the graph to add it to the build plan.
-  std::set<Edge*> dyndep_walk;
-  for (std::vector<DyndepFile::const_iterator>::iterator
-       oei = dyndep_roots.begin(); oei != dyndep_roots.end(); ++oei) {
-    DyndepFile::const_iterator oe = *oei;
-    for (vector<Node*>::const_iterator i = oe->second.implicit_inputs_.begin();
-         i != oe->second.implicit_inputs_.end(); ++i) {
-      if (!AddSubTarget(*i, oe->first->outputs_[0], err, &dyndep_walk) &&
-          !err->empty())
-        return false;
-    }
-  }
-
-  // Add out edges from this node that are in the plan (just as
-  // Plan::NodeFinished would have without taking the dyndep code path).
-  for (vector<Edge*>::const_iterator oe = node->out_edges().begin();
-       oe != node->out_edges().end(); ++oe) {
-    map<Edge*, Want>::iterator want_e = want_.find(*oe);
-    if (want_e == want_.end())
-      continue;
-    dyndep_walk.insert(want_e->first);
-  }
-
-  // See if any encountered edges are now ready.
-  for (set<Edge*>::iterator wi = dyndep_walk.begin();
-       wi != dyndep_walk.end(); ++wi) {
-    map<Edge*, Want>::iterator want_e = want_.find(*wi);
-    if (want_e == want_.end())
-      continue;
-    if (!EdgeMaybeReady(want_e, err))
-      return false;
-  }
-
-  return true;
-}
-
-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.
-  set<Node*> dependents;
-  UnmarkDependents(node, &dependents);
-
-  // Update the dirty state of all dependents and check if their edges
-  // have become wanted.
-  for (set<Node*>::iterator i = dependents.begin();
-       i != dependents.end(); ++i) {
-    Node* n = *i;
-
-    // Check if this dependent node is now dirty.  Also checks for new cycles.
-    std::vector<Node*> validation_nodes;
-    if (!scan->RecomputeDirty(n, &validation_nodes, err))
-      return false;
-
-    // Add any validation nodes found during RecomputeDirty as new top level
-    // targets.
-    for (std::vector<Node*>::iterator v = validation_nodes.begin();
-         v != validation_nodes.end(); ++v) {
-      if (Edge* in_edge = (*v)->in_edge()) {
-        if (!in_edge->outputs_ready() &&
-            !AddTarget(*v, err)) {
-          return false;
-        }
-      }
-    }
-    if (!n->dirty())
-      continue;
-
-    // This edge was encountered before.  However, we may not have wanted to
-    // build it if the outputs were not known to be dirty.  With dyndep
-    // information an output is now known to be dirty, so we want the edge.
-    Edge* edge = n->in_edge();
-    assert(edge && !edge->outputs_ready());
-    map<Edge*, Want>::iterator want_e = want_.find(edge);
-    assert(want_e != want_.end());
-    if (want_e->second == kWantNothing) {
-      want_e->second = kWantToStart;
-      EdgeWanted(edge);
-    }
-  }
-  return true;
-}
-
-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;
-
-    map<Edge*, Want>::iterator want_e = want_.find(edge);
-    if (want_e == want_.end())
-      continue;
-
-    if (edge->mark_ != Edge::VisitNone) {
-      edge->mark_ = Edge::VisitNone;
-      for (vector<Node*>::iterator o = edge->outputs_.begin();
-           o != edge->outputs_.end(); ++o) {
-        if (dependents->insert(*o).second)
-          UnmarkDependents(*o, dependents);
-      }
-    }
-  }
-}
-
-void Plan::Dump() const {
-  printf("pending: %d\n", (int)want_.size());
-  for (map<Edge*, Want>::const_iterator e = want_.begin(); e != want_.end(); ++e) {
-    if (e->second != kWantNothing)
-      printf("want ");
-    e->first->Dump();
-  }
-  printf("ready: %d\n", (int)ready_.size());
-}
-
-struct RealCommandRunner : public CommandRunner {
-  RealCommandRunner(const BuildConfig& config, DiskInterface& disk_interface)
-      : config_(config), subprocs_(config_.environment),
-        disk_interface_(disk_interface) {}
-  virtual ~RealCommandRunner() {}
-  bool CanRunMore() const override;
-  bool StartCommand(Edge* edge) override;
-  bool WaitForCommand(Result* result) override;
-  vector<Edge*> GetActiveEdges() override;
-  void Abort() override;
-
-  const BuildConfig& config_;
-  DiskInterface& disk_interface_;
-  SubprocessSet subprocs_;
-  map<const Subprocess*, Edge*> subproc_to_edge_;
-};
-
-vector<Edge*> RealCommandRunner::GetActiveEdges() {
-  std::vector<Edge*> edges;
-  edges.reserve(subproc_to_edge_.size());
-  for (const auto& pair : subproc_to_edge_)
-    edges.push_back(pair.second);
-  return edges;
-}
-
-void RealCommandRunner::Abort() {
-  subprocs_.Clear();
-}
-
-bool RealCommandRunner::CanRunMore() const {
-  size_t subproc_number =
-      subprocs_.running_.size() + subprocs_.finished_.size();
-  return (int)subproc_number < config_.parallelism
-    && ((subprocs_.running_.empty() || config_.max_load_average <= 0.0f)
-        || GetLoadAverage() < config_.max_load_average);
-}
-
-bool RealCommandRunner::StartCommand(Edge* edge) {
-  string command = edge->EvaluateCommand();
-  const Subprocess* subproc = subprocs_.Add(command, edge->use_console());
-  if (!subproc)
-    return false;
-
-  subproc_to_edge_.insert(std::make_pair(subproc, edge));
-  return true;
-}
-
-bool RealCommandRunner::WaitForCommand(Result* result) {
-  std::unique_ptr<Subprocess> subproc;
-  while (!(subproc = subprocs_.NextFinished())) {
-    bool interrupted = subprocs_.DoWork();
-
-    // Launched sub-commands may have modified file timestamps.
-    disk_interface_.Sync();
-
-    if (interrupted) {
-      result->status = ExitInterrupted;
-      return false;
-    }
-  }
-
-  result->status = subproc->Finish();
-  result->output = subproc->GetOutput();
-
-  auto e = subproc_to_edge_.find(subproc.get());
-  result->edge = e->second;
-  subproc_to_edge_.erase(e);
-
-  return true;
-}
-
-Builder::Builder(State* state, const BuildConfig& config,
-                 BuildLog* build_log, DepsLog* deps_log,
-                 DiskInterface* disk_interface, Status *status,
-                 int64_t start_time_millis)
-    : state_(state), config_(config), plan_(this), status_(status),
-      start_time_millis_(start_time_millis), disk_interface_(disk_interface),
-      scan_(state, build_log, deps_log, disk_interface,
-            &config_.depfile_parser_options) {
-  lock_file_path_ = ".ninja_lock";
-  string build_dir = state_->bindings().LookupVariable("builddir");
-  if (!build_dir.empty())
-    lock_file_path_ = build_dir + "/" + lock_file_path_;
-}
-
-Builder::~Builder() {
-  Cleanup();
-
-  // Remove lock file now.
-  string err;
-  if (disk_interface_->Stat(lock_file_path_, &err) > 0) {
-    disk_interface_->RemoveFile(lock_file_path_);
-  }
-}
-
-void Builder::Cleanup() {
-  if (command_runner_.get()) {
-    vector<Edge*> active_edges = command_runner_->GetActiveEdges();
-    command_runner_->Abort();
-
-    for (vector<Edge*>::iterator e = active_edges.begin();
-         e != active_edges.end(); ++e) {
-      string depfile = (*e)->GetUnescapedDepfile();
-      for (vector<Node*>::iterator o = (*e)->outputs_.begin();
-           o != (*e)->outputs_.end(); ++o) {
-        // Only delete this output if it was actually modified.  This is
-        // important for things like the generator where we don't want to
-        // delete the manifest file if we can avoid it.  But if the rule
-        // uses a depfile, always delete.  (Consider the case where we
-        // need to rebuild an output because of a modified header file
-        // mentioned in a depfile, and the command touches its depfile
-        // but is interrupted before it touches its output file.)
-        string err;
-        TimeStamp new_mtime = disk_interface_->Stat((*o)->path(), &err);
-        if (new_mtime == -1)  // Log and ignore Stat() errors.
-          status_->Error("%s", err.c_str());
-        if (!depfile.empty() || (*o)->mtime() != new_mtime)
-          disk_interface_->RemoveFile((*o)->path());
-      }
-      if (!depfile.empty())
-        disk_interface_->RemoveFile(depfile);
-    }
-  }
-}
-
-Node* Builder::AddTarget(const string& name, string* err) {
-  Node* node = state_->LookupNode(name);
-  if (!node) {
-    *err = "unknown target: '" + name + "'";
-    return NULL;
-  }
-  if (!AddTarget(node, err))
-    return NULL;
-  return node;
-}
-
-bool Builder::AddTarget(Node* target, string* err) {
-  std::vector<Node*> validation_nodes;
-  if (!scan_.RecomputeDirty(target, &validation_nodes, err))
-    return false;
-
-  Edge* in_edge = target->in_edge();
-  if (!in_edge || !in_edge->outputs_ready()) {
-    if (!plan_.AddTarget(target, err)) {
-      return false;
-    }
-  }
-
-  // Also add any validation nodes found during RecomputeDirty as top level
-  // targets.
-  for (std::vector<Node*>::iterator n = validation_nodes.begin();
-       n != validation_nodes.end(); ++n) {
-    if (Edge* validation_in_edge = (*n)->in_edge()) {
-      if (!validation_in_edge->outputs_ready() &&
-          !plan_.AddTarget(*n, err)) {
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
-
-bool Builder::AlreadyUpToDate() const {
-  return !plan_.more_to_do();
-}
-
-bool Builder::Build(string* err) {
-  assert(!AlreadyUpToDate());
-
-  status_->PlanHasTotalEdges(plan_.command_edge_count());
-  int pending_commands = 0;
-  int failures_allowed = config_.failures_allowed;
-
-  // Set up the command runner if we haven't done so already.
-  if (!command_runner_.get()) {
-    if (config_.dry_run)
-      command_runner_.reset(new DryRunCommandRunner);
-    else
-      command_runner_.reset(new RealCommandRunner(config_, *disk_interface_));
-  }
-
-  // We are about to start the build process.
-  status_->BuildStarted();
-
-  // This main loop runs the entire build process.
-  // It is structured like this:
-  // First, we attempt to start as many commands as allowed by the
-  // command runner.
-  // Second, we attempt to wait for / reap the next finished command.
-  while (plan_.more_to_do()) {
-    // See if we can start any more commands.
-    if (failures_allowed && command_runner_->CanRunMore()) {
-      if (Edge* edge = plan_.FindWork()) {
-        if (edge->is_generator()) {
-          scan_.build_log()->Close();
-        }
-
-        if (!StartEdge(edge, err)) {
-          Cleanup();
-          status_->BuildFinished();
-          return false;
-        }
-
-        if (edge->is_phony()) {
-          if (!plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, err)) {
-            Cleanup();
-            status_->BuildFinished();
-            return false;
-          }
-        } else {
-          ++pending_commands;
-        }
-
-        // We made some progress; go back to the main loop.
-        continue;
-      }
-    }
-
-    // See if we can reap any finished commands.
-    if (pending_commands) {
-      CommandRunner::Result result;
-      if (!command_runner_->WaitForCommand(&result) ||
-          result.status == ExitInterrupted) {
-        Cleanup();
-        status_->BuildFinished();
-        *err = "interrupted by user";
-        return false;
-      }
-
-      --pending_commands;
-      if (!FinishCommand(&result, err)) {
-        Cleanup();
-        status_->BuildFinished();
-        return false;
-      }
-
-      if (!result.success()) {
-        if (failures_allowed)
-          failures_allowed--;
-      }
-
-      // We made some progress; start the main loop over.
-      continue;
-    }
-
-    // If we get here, we cannot make any more progress.
-    status_->BuildFinished();
-    if (failures_allowed == 0) {
-      if (config_.failures_allowed > 1)
-        *err = "subcommands failed";
-      else
-        *err = "subcommand failed";
-    } else if (failures_allowed < config_.failures_allowed)
-      *err = "cannot make progress due to previous errors";
-    else
-      *err = "stuck [this is a bug]";
-
-    return false;
-  }
-
-  status_->BuildFinished();
-  return true;
-}
-
-bool Builder::StartEdge(Edge* edge, string* err) {
-  METRIC_RECORD("StartEdge");
-  if (edge->is_phony())
-    return true;
-
-  int64_t start_time_millis = GetTimeMillis() - start_time_millis_;
-  running_edges_.insert(make_pair(edge, start_time_millis));
-  status_->BuildEdgeStarted(edge);
-
-  TimeStamp build_start = -1;
-
-  // Create directories necessary for outputs and remember the current
-  // filesystem mtime to record later
-  // XXX: this will block; do we care?
-  for (vector<Node*>::iterator o = edge->outputs_.begin();
-       o != edge->outputs_.end(); ++o) {
-    if (!disk_interface_->MakeDirs((*o)->path()))
-      return false;
-    if (build_start == -1) {
-      disk_interface_->WriteFile(lock_file_path_, "");
-      build_start = disk_interface_->Stat(lock_file_path_, err);
-      if (build_start == -1)
-        build_start = 0;
-    }
-  }
-
-  edge->command_start_time_ = build_start;
-
-  // Create response file, if needed
-  // XXX: this may also block; do we care?
-  string rspfile = edge->GetUnescapedRspfile();
-  if (!rspfile.empty()) {
-    string content = edge->GetBinding("rspfile_content");
-    if (!disk_interface_->WriteFile(rspfile, content))
-      return false;
-  }
-
-  // start command computing and run it
-  if (!command_runner_->StartCommand(edge)) {
-    err->assign("command '" + edge->EvaluateCommand() + "' failed.");
-    return false;
-  }
-
-  return true;
-}
-
-bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {
-  METRIC_RECORD("FinishCommand");
-
-  Edge* edge = result->edge;
-
-  // First try to extract dependencies from the result, if any.
-  // This must happen first as it filters the command output (we want
-  // to filter /showIncludes output, even on compile failure) and
-  // extraction itself can fail, which makes the command fail from a
-  // build perspective.
-  vector<Node*> deps_nodes;
-  string deps_type = edge->GetBinding("deps");
-  const string deps_prefix = edge->GetBinding("msvc_deps_prefix");
-  if (!deps_type.empty()) {
-    string extract_err;
-    if (!ExtractDeps(result, deps_type, deps_prefix, &deps_nodes,
-                     &extract_err) &&
-        result->success()) {
-      if (!result->output.empty())
-        result->output.append("\n");
-      result->output.append(extract_err);
-      result->status = ExitFailure;
-    }
-  }
-
-  int64_t start_time_millis, end_time_millis;
-  RunningEdgeMap::iterator it = running_edges_.find(edge);
-  start_time_millis = it->second;
-  end_time_millis = GetTimeMillis() - start_time_millis_;
-  running_edges_.erase(it);
-
-  status_->BuildEdgeFinished(edge, result->success(), result->output);
-
-  // The rest of this function only applies to successful commands.
-  if (!result->success()) {
-    return plan_.EdgeFinished(edge, Plan::kEdgeFailed, err);
-  }
-
-  // Restat the edge outputs
-  TimeStamp record_mtime = 0;
-  if (!config_.dry_run) {
-    const bool restat = edge->has_restat();
-    const bool generator = edge->is_generator();
-    bool node_cleaned = false;
-    record_mtime = edge->command_start_time_;
-
-    // restat and generator rules must restat the outputs after the build
-    // has finished. if record_mtime == 0, then there was an error while
-    // attempting to touch/stat the temp file when the edge started and
-    // we should fall back to recording the outputs' current mtime in the
-    // log.
-    if (record_mtime == 0 || restat || generator) {
-      for (vector<Node*>::iterator o = edge->outputs_.begin();
-           o != edge->outputs_.end(); ++o) {
-        TimeStamp new_mtime = disk_interface_->Stat((*o)->path(), err);
-        if (new_mtime == -1)
-          return false;
-        if (new_mtime > record_mtime)
-          record_mtime = new_mtime;
-        if ((*o)->mtime() == new_mtime && restat) {
-          // The rule command did not change the output.  Propagate the clean
-          // state through the build graph.
-          // Note that this also applies to nonexistent outputs (mtime == 0).
-          if (!plan_.CleanNode(&scan_, *o, err))
-            return false;
-          node_cleaned = true;
-        }
-      }
-    }
-    if (node_cleaned) {
-      record_mtime = edge->command_start_time_;
-
-      // The total number of edges in the plan may have changed as a result
-      // of a restat.
-      status_->PlanHasTotalEdges(plan_.command_edge_count());
-    }
-  }
-
-  if (!plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, err))
-    return false;
-
-  // Delete any left over response file.
-  string rspfile = edge->GetUnescapedRspfile();
-  if (!rspfile.empty() && !g_keep_rsp)
-    disk_interface_->RemoveFile(rspfile);
-
-  if (scan_.build_log()) {
-    if (!scan_.build_log()->RecordCommand(edge, start_time_millis,
-                                          end_time_millis, record_mtime)) {
-      *err = string("Error writing to build log: ") + strerror(errno);
-      return false;
-    }
-  }
-
-  if (!deps_type.empty() && !config_.dry_run) {
-    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;
-      }
-    }
-  }
-
-  // Ensure that the next dependency scan that touches this edge removes
-  // any recorded deps in it since they are now stale.
-  edge->deps_loaded_ = false;
-  return true;
-}
-
-bool Builder::ExtractDeps(CommandRunner::Result* result,
-                          const string& deps_type,
-                          const string& deps_prefix,
-                          vector<Node*>* deps_nodes,
-                          string* err) {
-  if (deps_type == "msvc") {
-    CLParser parser;
-    string output;
-    if (!parser.Parse(result->output, deps_prefix, &output, err))
-      return false;
-    result->output = output;
-    for (set<string>::iterator i = parser.includes_.begin();
-         i != parser.includes_.end(); ++i) {
-      // ~0 is assuming that with MSVC-parsed headers, it's ok to always make
-      // all backslashes (as some of the slashes will certainly be backslashes
-      // anyway). This could be fixed if necessary with some additional
-      // complexity in IncludesNormalize::Relativize.
-      deps_nodes->push_back(state_->GetNode(*i, ~0u));
-    }
-  } 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");
-      return false;
-    }
-
-    // Read depfile content.  Treat a missing depfile as empty.
-    string content;
-    switch (disk_interface_->ReadFile(depfile, &content, err)) {
-    case DiskInterface::Okay:
-      break;
-    case DiskInterface::NotFound:
-      err->clear();
-      break;
-    case DiskInterface::OtherError:
-      return false;
-    }
-    if (content.empty())
-      return true;
-
-    DepfileParser deps(config_.depfile_parser_options);
-    if (!deps.Parse(&content, err))
-      return false;
-
-    // XXX check depfile matches expected output.
-    deps_nodes->reserve(deps.ins_.size());
-    for (vector<StringPiece>::iterator i = deps.ins_.begin();
-         i != deps.ins_.end(); ++i) {
-      uint64_t slash_bits;
-      CanonicalizePath(const_cast<char*>(i->str_), &i->len_, &slash_bits);
-      deps_nodes->push_back(state_->GetNode(*i, slash_bits));
-    }
-
-    if (!g_keep_depfile) {
-      if (disk_interface_->RemoveFile(depfile) < 0) {
-        *err = string("deleting depfile: ") + strerror(errno) + string("\n");
-        return false;
-      }
-    }
-  } else {
-    Fatal("unknown deps type '%s'", deps_type.c_str());
-  }
-
-  return true;
-}
-
-bool Builder::LoadDyndeps(Node* node, string* err) {
-  status_->BuildLoadDyndeps();
-
-  // Load the dyndep information provided by this node.
-  DyndepFile ddf;
-  if (!scan_.LoadDyndeps(node, &ddf, err))
-    return false;
-
-  // Update the build plan to account for dyndep modifications to the graph.
-  if (!plan_.DyndepsLoaded(&scan_, node, ddf, err))
-    return false;
-
-  // New command edges may have been added to the plan.
-  status_->PlanHasTotalEdges(plan_.command_edge_count());
-
-  return true;
-}
diff --git a/src/build.h b/src/build.h
deleted file mode 100644
index e2b7eeb..0000000
--- a/src/build.h
+++ /dev/null
@@ -1,223 +0,0 @@
-// 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.
-
-#ifndef NINJA_BUILD_H_
-#define NINJA_BUILD_H_
-
-#include <cstdio>
-#include <map>
-#include <memory>
-#include <queue>
-#include <string>
-#include <vector>
-
-#include "exit_status.h"
-#include "graph.h"  // XXX needed for DependencyScan; should rearrange.
-#include "util.h"   // int64_t
-
-class AsyncLoop;
-
-struct BuildConfig;
-struct BuildLog;
-struct Builder;
-struct DiskInterface;
-struct Edge;
-struct Node;
-struct State;
-struct Status;
-
-/// Plan stores the state of a build plan: what we intend to build,
-/// which steps we're ready to execute.
-struct Plan {
-  Plan(Builder* builder = NULL);
-
-  /// 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(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.
-  Edge* FindWork();
-
-  /// Returns true if there's more work to be done.
-  bool more_to_do() const { return wanted_edges_ > 0 && command_edges_ > 0; }
-
-  /// Dumps the current state of the plan.
-  void Dump() const;
-
-  enum EdgeResult {
-    kEdgeFailed,
-    kEdgeSucceeded
-  };
-
-  /// Mark an edge as done building (whether it succeeded or failed).
-  /// 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, std::string* err);
-
-  /// Clean the given node during the build.
-  /// Return false on error.
-  bool CleanNode(DependencyScan* scan, Node* node, std::string* err);
-
-  /// Number of edges with commands to run.
-  int command_edge_count() const { return command_edges_; }
-
-  /// Reset state.  Clears want and ready sets.
-  void Reset();
-
-  /// Update the build plan to account for modifications made to the graph
-  /// by information loaded from a dyndep file.
-  bool DyndepsLoaded(DependencyScan* scan, const Node* node,
-                     const DyndepFile& ddf, std::string* err);
-private:
-  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, std::string* err);
-
-  /// Enumerate possible steps we want for an edge.
-  enum Want
-  {
-    /// We do not want to build the edge, but we might want to build one of
-    /// its dependents.
-    kWantNothing,
-    /// We want to build the edge, but have not yet scheduled it.
-    kWantToStart,
-    /// We want to build the edge, have scheduled it, and are waiting
-    /// for it to complete.
-    kWantToFinish
-  };
-
-  void EdgeWanted(const Edge* edge);
-  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(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.
-  std::map<Edge*, Want> want_;
-
-  EdgeSet ready_;
-
-  Builder* builder_;
-
-  /// Total number of edges that have commands (not phony).
-  int command_edges_;
-
-  /// Total remaining number of wanted edges.
-  int wanted_edges_;
-};
-
-/// CommandRunner is an interface that wraps running the build
-/// subcommands.  This allows tests to abstract out running commands.
-/// RealCommandRunner is an implementation that actually runs commands.
-struct CommandRunner {
-  virtual ~CommandRunner() {}
-  virtual bool CanRunMore() const = 0;
-  virtual bool StartCommand(Edge* edge) = 0;
-
-  /// The result of waiting for a command.
-  struct Result {
-    Result() : edge(NULL) {}
-    Edge* edge;
-    ExitStatus status;
-    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 std::vector<Edge*> GetActiveEdges() { return std::vector<Edge*>(); }
-  virtual void Abort() {}
-};
-
-/// Builder wraps the build process: starting commands, updating status.
-struct Builder {
-  Builder(State* state, const BuildConfig& config,
-          BuildLog* build_log, DepsLog* deps_log,
-          DiskInterface* disk_interface, Status* status,
-          int64_t start_time_millis);
-  ~Builder();
-
-  /// Clean up after interrupted commands by deleting output files.
-  void Cleanup();
-
-  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, 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(std::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, std::string* err);
-
-  /// Used for tests.
-  void SetBuildLog(BuildLog* log) {
-    scan_.set_build_log(log);
-  }
-
-  /// Load the dyndep information provided by the given node.
-  bool LoadDyndeps(Node* node, std::string* err);
-
-  State* state_;
-  const BuildConfig& config_;
-  Plan plan_;
-  std::unique_ptr<CommandRunner> command_runner_;
-  Status* status_;
-
- private:
-  bool ExtractDeps(CommandRunner::Result* result, const std::string& deps_type,
-                   const std::string& deps_prefix,
-                   std::vector<Node*>* deps_nodes, std::string* err);
-
-  /// Map of running edge to time the edge started running.
-  typedef std::map<const Edge*, int> RunningEdgeMap;
-  RunningEdgeMap running_edges_;
-
-  /// Time the build started.
-  int64_t start_time_millis_;
-
-  std::string lock_file_path_;
-  DiskInterface* disk_interface_;
-  DependencyScan scan_;
-
-  // Unimplemented copy ctor and operator= ensure we don't copy the auto_ptr.
-  Builder(const Builder &other);        // DO NOT IMPLEMENT
-  void operator=(const Builder &other); // DO NOT IMPLEMENT
-};
-
-#endif  // NINJA_BUILD_H_
diff --git a/src/build_config.cc b/src/build_config.cc
deleted file mode 100644
index 121a9db..0000000
--- a/src/build_config.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2023 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 "build_config.h"
-
-#include <inttypes.h>
-
-#include "ipc_utils.h"
-#include "process_utils.h"
-#include "util.h"
-
-std::string BuildConfig::status_format() const {
-  std::string result = "[%f/%t] ";
-  const char* env = environment.Get("NINJA_STATUS");
-  if (env)
-    result = env;
-  return result;
-}
-
-int BuildConfig::status_max_commands() const {
-  int result = 0;
-  const char* env = environment.Get("NINJA_STATUS_MAX_COMMANDS");
-  if (env) {
-    int count = atoi(env);
-    if (count < 0)
-      count = 0;
-    result = count;
-  }
-  return result;
-}
-
-int64_t BuildConfig::status_refresh_millis() const {
-  int64_t result = 100;
-  const char* env = environment.Get("NINJA_STATUS_REFRESH_MILLIS");
-  if (env) {
-    long long val = strtoll(env, NULL, 10);
-    result = static_cast<int64_t>(val);
-  }
-  return result;
-}
-
-bool BuildConfig::operator==(const BuildConfig& o) const {
-  return verbosity == o.verbosity && dry_run == o.dry_run &&
-         parallelism == o.parallelism &&
-         failures_allowed == o.failures_allowed &&
-         max_load_average == o.max_load_average &&
-         depfile_parser_options == o.depfile_parser_options &&
-         input_file == o.input_file && environment == o.environment;
-}
-
-std::string BuildConfig::ToEncodedString() const {
-  WireEncoder encoder;
-  encoder.Write(verbosity);
-  encoder.Write(dry_run);
-  encoder.Write(parallelism);
-  encoder.Write(failures_allowed);
-  encoder.Write(max_load_average);
-  // depfile_parser_options is empty!
-  encoder.Write(input_file);
-  encoder.Write(environment.ToEncodedString());
-  return encoder.TakeResult();
-}
-
-// static
-BuildConfig BuildConfig::FromEncodedString(const std::string& str,
-                                           std::string* error) {
-  BuildConfig result;
-
-  WireDecoder decoder(str);
-  error->clear();
-  decoder.Read(result.verbosity);
-  decoder.Read(result.dry_run);
-  decoder.Read(result.parallelism);
-  decoder.Read(result.failures_allowed);
-  decoder.Read(result.max_load_average);
-  // depfile_parser_options is empty!
-  decoder.Read(result.input_file);
-
-  std::string encoded;
-  decoder.Read(encoded);
-  if (decoder.has_error()) {
-    *error = "Truncated BuildCOnfig encoded string";
-    return {};
-  }
-
-  result.environment = EnvironmentBlock::FromEncodedString(encoded, error);
-  if (!error->empty())
-    return {};
-
-  return result;
-}
-
-std::string BuildConfig::ToString() const {
-  std::string result = "verbosity=";
-  switch (verbosity) {
-  case QUIET:
-    result += "quiet";
-    break;
-  case NO_STATUS_UPDATE:
-    result += "no-status-upadte";
-    break;
-  case NORMAL:
-    result += "normal";
-    break;
-  case VERBOSE:
-    result += "verbose";
-    break;
-  default:
-    StringAppendFormat(result, "unknown(%d)", static_cast<int>(verbosity));
-  }
-
-  StringAppendFormat(
-      result,
-      " dry_run=%s parallelism=%d failures_allowed=%d max_load_average=%.2f",
-      dry_run ? "true" : "false", parallelism, failures_allowed,
-      max_load_average);
-
-  StringAppendFormat(result, "input_file=%s", input_file.c_str());
-
-  StringAppendFormat(
-      result,
-      " environment=%s", environment.AsString().c_str());
-
-  StringAppendFormat(
-      result,
-      " status_format=%s status_max_commands=%d status_refresh_millis=" PRId64,
-      status_format().c_str(), status_max_commands(), status_refresh_millis());
-
-  return result;
-}
diff --git a/src/build_config.h b/src/build_config.h
deleted file mode 100644
index b0f0709..0000000
--- a/src/build_config.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2023 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_BUILD_CONFIG_H_
-#define NINJA_BUILD_CONFIG_H_
-
-#include <string>
-
-#include "depfile_parser.h"
-#include "process_utils.h"
-
-/// Options (e.g. verbosity, parallelism) passed to a build.
-/// NOTE: This does not include debug flags, stored in global variables :-/
-struct BuildConfig {
-  enum Verbosity {
-    QUIET,             // No output -- used when testing.
-    NO_STATUS_UPDATE,  // just regular output but suppress status update
-    NORMAL,            // regular output and status update
-    VERBOSE
-  };
-  Verbosity verbosity = NORMAL;
-  bool dry_run = false;
-  int parallelism = 1;
-  int failures_allowed = 1;
-  /// The maximum load average we must not exceed. A negative value
-  /// means that we do not have any limit.
-  double max_load_average = -0.0f;
-  /// Name of the main manifest input file.
-  std::string input_file = "build.ninja";
-
-  DepfileParserOptions depfile_parser_options;
-
-  /// The set of environment variables to use when spawning commands.
-  EnvironmentBlock environment;
-
-  /// Retrieve some values from environment variables.
-  std::string status_format() const;
-  int status_max_commands() const;
-  int64_t status_refresh_millis() const;
-
-  /// Compare two instances.
-  bool operator==(const BuildConfig& o) const;
-  bool operator!=(const BuildConfig& o) const { return !(*this == o); }
-
-  /// Encoding/decoding support for IPC.
-  static BuildConfig FromEncodedString(const std::string& str,
-                                       std::string* error);
-
-  std::string ToEncodedString() const;
-
-  /// Convert to string for debugging.
-  std::string ToString() const;
-};
-
-#endif  // NINJA_BUILD_CONFIG_H_
diff --git a/src/build_log.cc b/src/build_log.cc
deleted file mode 100644
index b415025..0000000
--- a/src/build_log.cc
+++ /dev/null
@@ -1,502 +0,0 @@
-// 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.
-
-// On AIX, inttypes.h gets indirectly included by build_log.h.
-// It's easiest just to ask for the printf format macros right away.
-#ifndef _WIN32
-#ifndef __STDC_FORMAT_MACROS
-#define __STDC_FORMAT_MACROS
-#endif
-#endif
-
-#include "build_log.h"
-#include "disk_interface.h"
-
-#include <cassert>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef _WIN32
-#include <inttypes.h>
-#include <unistd.h>
-#endif
-
-#include "build.h"
-#include "graph.h"
-#include "metrics.h"
-#include "util.h"
-#if defined(_MSC_VER) && (_MSC_VER < 1800)
-#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
-// older runs.
-// Once the number of redundant entries exceeds a threshold, we write
-// out a new file and replace the existing one with it.
-
-namespace {
-
-const char kFileSignature[] = "# ninja log v%d\n";
-const int kOldestSupportedVersion = 4;
-const int kCurrentVersion = 5;
-
-// 64bit MurmurHash2, by Austin Appleby
-#if defined(_MSC_VER)
-#define BIG_CONSTANT(x) (x)
-#else   // defined(_MSC_VER)
-#define BIG_CONSTANT(x) (x##LLU)
-#endif // !defined(_MSC_VER)
-inline
-uint64_t MurmurHash64A(const void* key, size_t len) {
-  static const uint64_t seed = 0xDECAFBADDECAFBADull;
-  const uint64_t m = BIG_CONSTANT(0xc6a4a7935bd1e995);
-  const int r = 47;
-  uint64_t h = seed ^ (len * m);
-  const unsigned char* data = (const unsigned char*)key;
-  while (len >= 8) {
-    uint64_t k;
-    memcpy(&k, data, sizeof k);
-    k *= m;
-    k ^= k >> r;
-    k *= m;
-    h ^= k;
-    h *= m;
-    data += 8;
-    len -= 8;
-  }
-  switch (len & 7)
-  {
-  case 7: h ^= uint64_t(data[6]) << 48;
-          NINJA_FALLTHROUGH;
-  case 6: h ^= uint64_t(data[5]) << 40;
-          NINJA_FALLTHROUGH;
-  case 5: h ^= uint64_t(data[4]) << 32;
-          NINJA_FALLTHROUGH;
-  case 4: h ^= uint64_t(data[3]) << 24;
-          NINJA_FALLTHROUGH;
-  case 3: h ^= uint64_t(data[2]) << 16;
-          NINJA_FALLTHROUGH;
-  case 2: h ^= uint64_t(data[1]) << 8;
-          NINJA_FALLTHROUGH;
-  case 1: h ^= uint64_t(data[0]);
-          h *= m;
-  };
-  h ^= h >> r;
-  h *= m;
-  h ^= h >> r;
-  return h;
-}
-#undef BIG_CONSTANT
-
-
-}  // namespace
-
-// static
-uint64_t BuildLog::LogEntry::HashCommand(StringPiece command) {
-  return MurmurHash64A(command.str_, command.len_);
-}
-
-BuildLog::LogEntry::LogEntry(const string& output)
-  : output(output) {}
-
-BuildLog::LogEntry::LogEntry(const string& output, uint64_t command_hash,
-  int start_time, int end_time, TimeStamp mtime)
-  : output(output), command_hash(command_hash),
-    start_time(start_time), end_time(end_time), mtime(mtime)
-{}
-
-BuildLog::BuildLog()
-  : log_file_(NULL), needs_recompaction_(false) {}
-
-BuildLog::~BuildLog() {
-  Close();
-
-  for (auto& pair : entries_) {
-          delete pair.second;
-  }
-  entries_.clear();
-}
-
-bool BuildLog::OpenForWrite(const string& path, const BuildLogUser& user,
-                            string* err) {
-  if (needs_recompaction_) {
-    if (!Recompact(path, user, err))
-      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;
-}
-
-bool BuildLog::RecordCommand(Edge* edge, int start_time, int end_time,
-                             TimeStamp mtime) {
-  string command = edge->EvaluateCommand(true);
-  uint64_t command_hash = LogEntry::HashCommand(command);
-  for (vector<Node*>::iterator out = edge->outputs_.begin();
-       out != edge->outputs_.end(); ++out) {
-    const string& path = (*out)->path();
-    Entries::iterator i = entries_.find(path);
-    LogEntry* log_entry;
-    if (i != entries_.end()) {
-      log_entry = i->second;
-    } else {
-      log_entry = new LogEntry(path);
-      entries_.insert(Entries::value_type(log_entry->output, log_entry));
-    }
-    log_entry->command_hash = command_hash;
-    log_entry->start_time = start_time;
-    log_entry->end_time = end_time;
-    log_entry->mtime = mtime;
-
-    if (!OpenForWriteIfNeeded()) {
-      return false;
-    }
-    if (log_file_) {
-      if (!WriteEntry(log_file_, *log_entry))
-        return false;
-      if (fflush(log_file_) != 0) {
-          return false;
-      }
-    }
-  }
-  return true;
-}
-
-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) {
-      memset(buf_, 0, sizeof(buf_));
-  }
-
-  // Reads a \n-terminated line from the file passed to the constructor.
-  // On return, *line_start points to the beginning of the next line, and
-  // *line_end points to the \n at the end of the line. If no newline is seen
-  // in a fixed buffer size, *line_end is set to NULL. Returns false on EOF.
-  bool ReadLine(char** line_start, char** line_end) {
-    if (line_start_ >= buf_end_ || !line_end_) {
-      // Buffer empty, refill.
-      size_t size_read = fread(buf_, 1, sizeof(buf_), file_);
-      if (!size_read)
-        return false;
-      line_start_ = buf_;
-      buf_end_ = buf_ + size_read;
-    } else {
-      // Advance to next line in buffer.
-      line_start_ = line_end_ + 1;
-    }
-
-    line_end_ = (char*)memchr(line_start_, '\n', buf_end_ - line_start_);
-    if (!line_end_) {
-      // No newline. Move rest of data to start of buffer, fill rest.
-      size_t already_consumed = line_start_ - buf_;
-      size_t size_rest = (buf_end_ - buf_) - already_consumed;
-      memmove(buf_, line_start_, size_rest);
-
-      size_t read = fread(buf_ + size_rest, 1, sizeof(buf_) - size_rest, file_);
-      buf_end_ = buf_ + size_rest + read;
-      line_start_ = buf_;
-      line_end_ = (char*)memchr(line_start_, '\n', buf_end_ - line_start_);
-    }
-
-    *line_start = line_start_;
-    *line_end = line_end_;
-    return true;
-  }
-
- private:
-  FILE* file_;
-  char buf_[256 << 10];
-  char* buf_end_;  // Points one past the last valid byte in |buf_|.
-
-  char* line_start_;
-  // Points at the next \n in buf_ after line_start, or NULL.
-  char* line_end_;
-};
-
-LoadStatus BuildLog::Load(const string& path, string* err) {
-  METRIC_RECORD_LOAD(".ninja_log load");
-  FILE* file = fopen(path.c_str(), "r");
-  if (!file) {
-    if (errno == ENOENT)
-      return LOAD_NOT_FOUND;
-    *err = strerror(errno);
-    return LOAD_ERROR;
-  }
-
-  int log_version = 0;
-  int unique_entry_count = 0;
-  int total_entry_count = 0;
-
-  LineReader reader(file);
-  char* line_start = 0;
-  char* line_end = 0;
-  while (reader.ReadLine(&line_start, &line_end)) {
-    if (!log_version) {
-      sscanf(line_start, kFileSignature, &log_version);
-
-      if (log_version < kOldestSupportedVersion) {
-        *err = ("build log version invalid, perhaps due to being too old; "
-                "starting over");
-        fclose(file);
-        unlink(path.c_str());
-        // Don't report this as a failure.  An empty build log will cause
-        // us to rebuild the outputs anyway.
-        return LOAD_SUCCESS;
-      }
-    }
-
-    // If no newline was found in this chunk, read the next.
-    if (!line_end)
-      continue;
-
-    const char kFieldSeparator = '\t';
-
-    char* start = line_start;
-    char* end = (char*)memchr(start, kFieldSeparator, line_end - start);
-    if (!end)
-      continue;
-    *end = 0;
-
-    int start_time = 0, end_time = 0;
-    TimeStamp mtime = 0;
-
-    start_time = atoi(start);
-    start = end + 1;
-
-    end = (char*)memchr(start, kFieldSeparator, line_end - start);
-    if (!end)
-      continue;
-    *end = 0;
-    end_time = atoi(start);
-    start = end + 1;
-
-    end = (char*)memchr(start, kFieldSeparator, line_end - start);
-    if (!end)
-      continue;
-    *end = 0;
-    mtime = strtoll(start, NULL, 10);
-    start = end + 1;
-
-    end = (char*)memchr(start, kFieldSeparator, line_end - start);
-    if (!end)
-      continue;
-    string output = string(start, end - start);
-
-    start = end + 1;
-    end = line_end;
-
-    LogEntry* entry;
-    Entries::iterator i = entries_.find(output);
-    if (i != entries_.end()) {
-      entry = i->second;
-    } else {
-      entry = new LogEntry(output);
-      entries_.insert(Entries::value_type(entry->output, entry));
-      ++unique_entry_count;
-    }
-    ++total_entry_count;
-
-    entry->start_time = start_time;
-    entry->end_time = end_time;
-    entry->mtime = mtime;
-    if (log_version >= 5) {
-      char c = *end; *end = '\0';
-      entry->command_hash = (uint64_t)strtoull(start, NULL, 16);
-      *end = c;
-    } else {
-      entry->command_hash = LogEntry::HashCommand(StringPiece(start,
-                                                              end - start));
-    }
-  }
-  fclose(file);
-
-  if (!line_start) {
-    return LOAD_SUCCESS; // file was empty
-  }
-
-  // Decide whether it's time to rebuild the log:
-  // - if we're upgrading versions
-  // - if it's getting large
-  int kMinCompactionEntryCount = 100;
-  int kCompactionRatio = 3;
-  if (log_version < kCurrentVersion) {
-    needs_recompaction_ = true;
-  } else if (total_entry_count > kMinCompactionEntryCount &&
-             total_entry_count > unique_entry_count * kCompactionRatio) {
-    needs_recompaction_ = true;
-  }
-
-  return LOAD_SUCCESS;
-}
-
-BuildLog::LogEntry* BuildLog::LookupByOutput(const string& path) {
-  Entries::iterator i = entries_.find(path);
-  if (i != entries_.end())
-    return i->second;
-  return NULL;
-}
-
-bool BuildLog::WriteEntry(FILE* f, const LogEntry& entry) {
-  return fprintf(f, "%d\t%d\t%" PRId64 "\t%s\t%" PRIx64 "\n",
-          entry.start_time, entry.end_time, entry.mtime,
-          entry.output.c_str(), entry.command_hash) > 0;
-}
-
-bool BuildLog::Recompact(const string& path, const BuildLogUser& user,
-                         string* err) {
-  METRIC_RECORD(".ninja_log recompact");
-
-  Close();
-  string temp_path = path + ".recompact";
-  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;
-  }
-
-  vector<StringPiece> dead_outputs;
-  for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) {
-    if (user.IsPathDead(i->first)) {
-      dead_outputs.push_back(i->first);
-      continue;
-    }
-
-    if (!WriteEntry(f, *i->second)) {
-      *err = strerror(errno);
-      fclose(f);
-      return false;
-    }
-  }
-
-  for (size_t i = 0; i < dead_outputs.size(); ++i) {
-    auto it = entries_.find(dead_outputs[i]);
-    delete it->second;
-    entries_.erase(it);
-  }
-
-  fclose(f);
-  if (unlink(path.c_str()) < 0) {
-    *err = strerror(errno);
-    return false;
-  }
-
-  if (rename(temp_path.c_str(), path.c_str()) < 0) {
-    *err = strerror(errno);
-    return false;
-  }
-
-  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
deleted file mode 100644
index c51303c..0000000
--- a/src/build_log.h
+++ /dev/null
@@ -1,110 +0,0 @@
-// 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.
-
-#ifndef NINJA_BUILD_LOG_H_
-#define NINJA_BUILD_LOG_H_
-
-#include <string>
-#include <stdio.h>
-
-#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.
-struct BuildLogUser {
-  /// Return if a given output is no longer part of the build manifest.
-  /// This is only called during recompaction and doesn't have to be fast.
-  virtual bool IsPathDead(StringPiece s) const = 0;
-};
-
-/// Store a log of every command ran for every build.
-/// It has a few uses:
-///
-/// 1) (hashes of) command lines for existing output files, so we know
-///    when we need to rebuild due to the command changing
-/// 2) timing information, perhaps for generating reports
-/// 3) restat information
-struct BuildLog {
-  BuildLog();
-  ~BuildLog();
-
-  /// Prepares writing to the log file without actually opening it - that will
-  /// happen when/if it's needed
-  bool OpenForWrite(const 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.
-  LoadStatus Load(const std::string& path, std::string* err);
-
-  struct LogEntry {
-    std::string output;
-    uint64_t command_hash;
-    int start_time;
-    int end_time;
-    TimeStamp mtime;
-
-    static uint64_t HashCommand(StringPiece command);
-
-    // Used by tests.
-    bool operator==(const LogEntry& o) {
-      return output == o.output && command_hash == o.command_hash &&
-          start_time == o.start_time && end_time == o.end_time &&
-          mtime == o.mtime;
-    }
-
-    explicit LogEntry(const std::string& output);
-    LogEntry(const std::string& output, uint64_t command_hash,
-             int start_time, int end_time, TimeStamp mtime);
-  };
-
-  /// Return the number of entries in the log.
-  size_t size() const { return entries_.size(); }
-
-  /// Lookup a previously-run command by its output 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 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_;
-};
-
-#endif // NINJA_BUILD_LOG_H_
diff --git a/src/build_log_perftest.cc b/src/build_log_perftest.cc
deleted file mode 100644
index 5a93619..0000000
--- a/src/build_log_perftest.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2012 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 <stdio.h>
-#include <stdlib.h>
-
-#include "build_log.h"
-#include "graph.h"
-#include "manifest_parser.h"
-#include "state.h"
-#include "util.h"
-#include "metrics.h"
-
-#ifndef _WIN32
-#include <unistd.h>
-#endif
-
-using namespace std;
-
-const char kTestFilename[] = "BuildLogPerfTest-tempfile";
-
-struct NoDeadPaths : public BuildLogUser {
-  virtual bool IsPathDead(StringPiece) const { return false; }
-};
-
-bool WriteTestData(string* err) {
-  BuildLog log;
-
-  NoDeadPaths no_dead_paths;
-  if (!log.OpenForWrite(kTestFilename, no_dead_paths, err))
-    return false;
-
-  /*
-  A histogram of command lengths in chromium. For example, 407 builds,
-  1.4% of all builds, had commands longer than 32 bytes but shorter than 64.
-       32    407   1.4%
-       64    183   0.6%
-      128   1461   5.1%
-      256    791   2.8%
-      512   1314   4.6%
-     1024   6114  21.3%
-     2048  11759  41.0%
-     4096   2056   7.2%
-     8192   4567  15.9%
-    16384     13   0.0%
-    32768      4   0.0%
-    65536      5   0.0%
-  The average command length is 4.1 kB and there were 28674 commands in total,
-  which makes for a total log size of ~120 MB (also counting output filenames).
-
-  Based on this, write 30000 many 4 kB long command lines.
-  */
-
-  // ManifestParser is the only object allowed to create Rules.
-  const size_t kRuleSize = 4000;
-  string long_rule_command = "gcc ";
-  for (int i = 0; long_rule_command.size() < kRuleSize; ++i) {
-    char buf[80];
-    sprintf(buf, "-I../../and/arbitrary/but/fairly/long/path/suffixed/%d ", i);
-    long_rule_command += buf;
-  }
-  long_rule_command += "$in -o $out\n";
-
-  State state;
-  ManifestParser parser(&state, NULL);
-  if (!parser.ParseTest("rule cxx\n  command = " + long_rule_command, err))
-    return false;
-
-  // Create build edges. Using ManifestParser is as fast as using the State api
-  // for edge creation, so just use that.
-  const int kNumCommands = 30000;
-  string build_rules;
-  for (int i = 0; i < kNumCommands; ++i) {
-    char buf[80];
-    sprintf(buf, "build input%d.o: cxx input%d.cc\n", i, i);
-    build_rules += buf;
-  }
-
-  if (!parser.ParseTest(build_rules, err))
-    return false;
-
-  for (int i = 0; i < kNumCommands; ++i) {
-    log.RecordCommand(state.edges_[i],
-                      /*start_time=*/100 * i,
-                      /*end_time=*/100 * i + 1,
-                      /*mtime=*/0);
-  }
-
-  return true;
-}
-
-int main() {
-  vector<int> times;
-  string err;
-
-  if (!WriteTestData(&err)) {
-    fprintf(stderr, "Failed to write test data: %s\n", err.c_str());
-    return 1;
-  }
-
-  {
-    // Read once to warm up disk cache.
-    BuildLog log;
-    if (log.Load(kTestFilename, &err) == LOAD_ERROR) {
-      fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
-      return 1;
-    }
-  }
-  const int kNumRepetitions = 5;
-  for (int i = 0; i < kNumRepetitions; ++i) {
-    int64_t start = GetTimeMillis();
-    BuildLog log;
-    if (log.Load(kTestFilename, &err) == LOAD_ERROR) {
-      fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
-      return 1;
-    }
-    int delta = (int)(GetTimeMillis() - start);
-    printf("%dms\n", delta);
-    times.push_back(delta);
-  }
-
-  int min = times[0];
-  int max = times[0];
-  float total = 0;
-  for (size_t i = 0; i < times.size(); ++i) {
-    total += times[i];
-    if (times[i] < min)
-      min = times[i];
-    else if (times[i] > max)
-      max = times[i];
-  }
-
-  printf("min %dms  max %dms  avg %.1fms\n",
-         min, max, total / times.size());
-
-  unlink(kTestFilename);
-
-  return 0;
-}
diff --git a/src/build_log_test.cc b/src/build_log_test.cc
deleted file mode 100644
index 4725377..0000000
--- a/src/build_log_test.cc
+++ /dev/null
@@ -1,362 +0,0 @@
-// 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.
-
-#include "build_log.h"
-
-#include "util.h"
-#include "test.h"
-
-#include <sys/stat.h>
-#ifdef _WIN32
-#include <fcntl.h>
-#include <share.h>
-#else
-#include <sys/types.h>
-#include <unistd.h>
-#endif
-#include <cassert>
-
-using namespace std;
-
-namespace {
-
-const char kTestFilename[] = "BuildLogTest-tempfile";
-
-struct BuildLogTest : public StateTestWithBuiltinRules, public BuildLogUser {
-  virtual void SetUp() {
-    // In case a crashing test left a stale file behind.
-    unlink(kTestFilename);
-  }
-  virtual void TearDown() {
-    unlink(kTestFilename);
-  }
-  virtual bool IsPathDead(StringPiece s) const { return false; }
-};
-
-TEST_F(BuildLogTest, WriteRead) {
-  AssertParse(&state_,
-"build out: cat mid\n"
-"build mid: cat in\n");
-
-  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, log1.entries().size());
-  ASSERT_EQ(2u, log2.entries().size());
-  BuildLog::LogEntry* e1 = log1.LookupByOutput("out");
-  ASSERT_TRUE(e1);
-  BuildLog::LogEntry* e2 = log2.LookupByOutput("out");
-  ASSERT_TRUE(e2);
-  ASSERT_TRUE(*e1 == *e2);
-  ASSERT_EQ(15, e1->start_time);
-  ASSERT_EQ("out", e1->output);
-}
-
-TEST_F(BuildLogTest, FirstWriteAddsSignature) {
-  const char kExpectedVersion[] = "# ninja log vX\n";
-  const size_t kVersionPos = strlen(kExpectedVersion) - 2;  // Points at 'X'.
-
-  BuildLog log;
-  string contents, err;
-
-  EXPECT_TRUE(log.OpenForWrite(kTestFilename, *this, &err));
-  ASSERT_EQ("", err);
-  log.Close();
-
-  ASSERT_EQ(0, ReadFile(kTestFilename, &contents, &err));
-  ASSERT_EQ("", err);
-  if (contents.size() >= kVersionPos)
-    contents[kVersionPos] = 'X';
-  EXPECT_EQ(kExpectedVersion, contents);
-
-  // Opening the file anew shouldn't add a second version string.
-  EXPECT_TRUE(log.OpenForWrite(kTestFilename, *this, &err));
-  ASSERT_EQ("", err);
-  log.Close();
-
-  contents.clear();
-  ASSERT_EQ(0, ReadFile(kTestFilename, &contents, &err));
-  ASSERT_EQ("", err);
-  if (contents.size() >= kVersionPos)
-    contents[kVersionPos] = 'X';
-  EXPECT_EQ(kExpectedVersion, contents);
-}
-
-TEST_F(BuildLogTest, DoubleEntry) {
-  FILE* f = fopen(kTestFilename, "wb");
-  fprintf(f, "# ninja log v4\n");
-  fprintf(f, "0\t1\t2\tout\tcommand abc\n");
-  fprintf(f, "3\t4\t5\tout\tcommand def\n");
-  fclose(f);
-
-  string err;
-  BuildLog log;
-  EXPECT_TRUE(log.Load(kTestFilename, &err));
-  ASSERT_EQ("", err);
-
-  BuildLog::LogEntry* e = log.LookupByOutput("out");
-  ASSERT_TRUE(e);
-  ASSERT_NO_FATAL_FAILURE(AssertHash("command def", e->command_hash));
-}
-
-TEST_F(BuildLogTest, Truncate) {
-  AssertParse(&state_,
-"build out: cat mid\n"
-"build mid: cat in\n");
-
-  {
-    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();
-  }
-#ifdef __USE_LARGEFILE64
-  struct stat64 statbuf;
-  ASSERT_EQ(0, stat64(kTestFilename, &statbuf));
-#else
-  struct stat statbuf;
-  ASSERT_EQ(0, stat(kTestFilename, &statbuf));
-#endif
-  ASSERT_GT(statbuf.st_size, 0);
-
-  // For all possible truncations of the input file, assert that we don't
-  // crash when parsing.
-  for (off_t size = statbuf.st_size; size > 0; --size) {
-    BuildLog log2;
-    string err;
-    EXPECT_TRUE(log2.OpenForWrite(kTestFilename, *this, &err));
-    ASSERT_EQ("", err);
-    log2.RecordCommand(state_.edges_[0], 15, 18);
-    log2.RecordCommand(state_.edges_[1], 20, 25);
-    log2.Close();
-
-    ASSERT_TRUE(Truncate(kTestFilename, size, &err));
-
-    BuildLog log3;
-    err.clear();
-    ASSERT_TRUE(log3.Load(kTestFilename, &err) == LOAD_SUCCESS || !err.empty());
-  }
-}
-
-TEST_F(BuildLogTest, ObsoleteOldVersion) {
-  FILE* f = fopen(kTestFilename, "wb");
-  fprintf(f, "# ninja log v3\n");
-  fprintf(f, "123 456 0 out command\n");
-  fclose(f);
-
-  string err;
-  BuildLog log;
-  EXPECT_TRUE(log.Load(kTestFilename, &err));
-  ASSERT_NE(err.find("version"), string::npos);
-}
-
-TEST_F(BuildLogTest, SpacesInOutputV4) {
-  FILE* f = fopen(kTestFilename, "wb");
-  fprintf(f, "# ninja log v4\n");
-  fprintf(f, "123\t456\t456\tout with space\tcommand\n");
-  fclose(f);
-
-  string err;
-  BuildLog log;
-  EXPECT_TRUE(log.Load(kTestFilename, &err));
-  ASSERT_EQ("", err);
-
-  BuildLog::LogEntry* e = log.LookupByOutput("out with space");
-  ASSERT_TRUE(e);
-  ASSERT_EQ(123, e->start_time);
-  ASSERT_EQ(456, e->end_time);
-  ASSERT_EQ(456, e->mtime);
-  ASSERT_NO_FATAL_FAILURE(AssertHash("command", e->command_hash));
-}
-
-TEST_F(BuildLogTest, DuplicateVersionHeader) {
-  // Old versions of ninja accidentally wrote multiple version headers to the
-  // build log on Windows. This shouldn't crash, and the second version header
-  // should be ignored.
-  FILE* f = fopen(kTestFilename, "wb");
-  fprintf(f, "# ninja log v4\n");
-  fprintf(f, "123\t456\t456\tout\tcommand\n");
-  fprintf(f, "# ninja log v4\n");
-  fprintf(f, "456\t789\t789\tout2\tcommand2\n");
-  fclose(f);
-
-  string err;
-  BuildLog log;
-  EXPECT_TRUE(log.Load(kTestFilename, &err));
-  ASSERT_EQ("", err);
-
-  BuildLog::LogEntry* e = log.LookupByOutput("out");
-  ASSERT_TRUE(e);
-  ASSERT_EQ(123, e->start_time);
-  ASSERT_EQ(456, e->end_time);
-  ASSERT_EQ(456, e->mtime);
-  ASSERT_NO_FATAL_FAILURE(AssertHash("command", e->command_hash));
-
-  e = log.LookupByOutput("out2");
-  ASSERT_TRUE(e);
-  ASSERT_EQ(456, e->start_time);
-  ASSERT_EQ(789, e->end_time);
-  ASSERT_EQ(789, e->mtime);
-  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.
-  FILE* f = fopen(kTestFilename, "wb");
-  fprintf(f, "# ninja log v4\n");
-  fprintf(f, "123\t456\t456\tout\tcommand start");
-  for (size_t i = 0; i < (512 << 10) / strlen(" more_command"); ++i)
-    fputs(" more_command", f);
-  fprintf(f, "\n");
-  fprintf(f, "456\t789\t789\tout2\tcommand2\n");
-  fclose(f);
-
-  string err;
-  BuildLog log;
-  EXPECT_TRUE(log.Load(kTestFilename, &err));
-  ASSERT_EQ("", err);
-
-  BuildLog::LogEntry* e = log.LookupByOutput("out");
-  ASSERT_NULL(e);
-
-  e = log.LookupByOutput("out2");
-  ASSERT_TRUE(e);
-  ASSERT_EQ(456, e->start_time);
-  ASSERT_EQ(789, e->end_time);
-  ASSERT_EQ(789, e->mtime);
-  ASSERT_NO_FATAL_FAILURE(AssertHash("command2", e->command_hash));
-}
-
-TEST_F(BuildLogTest, MultiTargetEdge) {
-  AssertParse(&state_,
-"build out out.d: cat\n");
-
-  BuildLog log;
-  log.RecordCommand(state_.edges_[0], 21, 22);
-
-  ASSERT_EQ(2u, log.entries().size());
-  BuildLog::LogEntry* e1 = log.LookupByOutput("out");
-  ASSERT_TRUE(e1);
-  BuildLog::LogEntry* e2 = log.LookupByOutput("out.d");
-  ASSERT_TRUE(e2);
-  ASSERT_EQ("out", e1->output);
-  ASSERT_EQ("out.d", e2->output);
-  ASSERT_EQ(21, e1->start_time);
-  ASSERT_EQ(21, e2->start_time);
-  ASSERT_EQ(22, e2->end_time);
-  ASSERT_EQ(22, e2->end_time);
-}
-
-struct BuildLogRecompactTest : public BuildLogTest {
-  virtual bool IsPathDead(StringPiece s) const { return s == "out2"; }
-};
-
-TEST_F(BuildLogRecompactTest, Recompact) {
-  AssertParse(&state_,
-"build out: cat in\n"
-"build out2: cat in\n");
-
-  BuildLog log1;
-  string err;
-  EXPECT_TRUE(log1.OpenForWrite(kTestFilename, *this, &err));
-  ASSERT_EQ("", err);
-  // Record the same edge several times, to trigger recompaction
-  // the next time the log is opened.
-  for (int i = 0; i < 200; ++i)
-    log1.RecordCommand(state_.edges_[0], 15, 18 + i);
-  log1.RecordCommand(state_.edges_[1], 21, 22);
-  log1.Close();
-
-  // Load...
-  BuildLog log2;
-  EXPECT_TRUE(log2.Load(kTestFilename, &err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(2u, log2.entries().size());
-  ASSERT_TRUE(log2.LookupByOutput("out"));
-  ASSERT_TRUE(log2.LookupByOutput("out2"));
-  // ...and force a recompaction.
-  EXPECT_TRUE(log2.OpenForWrite(kTestFilename, *this, &err));
-  log2.Close();
-
-  // "out2" is dead, it should've been removed.
-  BuildLog log3;
-  EXPECT_TRUE(log2.Load(kTestFilename, &err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, log2.entries().size());
-  ASSERT_TRUE(log2.LookupByOutput("out"));
-  ASSERT_FALSE(log2.LookupByOutput("out2"));
-}
-
-}  // anonymous namespace
diff --git a/src/build_test.cc b/src/build_test.cc
deleted file mode 100644
index 47daa09..0000000
--- a/src/build_test.cc
+++ /dev/null
@@ -1,4303 +0,0 @@
-// 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.
-
-#include "build.h"
-
-#include <assert.h>
-
-#include "build_config.h"
-#include "build_log.h"
-#include "deps_log.h"
-#include "graph.h"
-#include "status.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();
-  }
-};
-
-/// Fixture for tests involving Plan.
-// Though Plan doesn't use State, it's useful to have one around
-// to create Nodes and Edges.
-struct PlanTest : public StateTestWithBuiltinRules {
-  Plan plan_;
-
-  /// Because FindWork does not return Edges in any sort of predictable order,
-  // provide a means to get available Edges in order and in a format which is
-  // easy to write tests around.
-  void FindWorkSorted(deque<Edge*>* ret, int count) {
-    for (int i = 0; i < count; ++i) {
-      ASSERT_TRUE(plan_.more_to_do());
-      Edge* edge = plan_.FindWork();
-      ASSERT_TRUE(edge);
-      ret->push_back(edge);
-    }
-    ASSERT_FALSE(plan_.FindWork());
-    sort(ret->begin(), ret->end(), CompareEdgesByOutput::cmp);
-  }
-
-  void TestPoolWithDepthOne(const char *test_case);
-};
-
-TEST_F(PlanTest, Basic) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat mid\n"
-"build mid: cat in\n"));
-  GetNode("mid")->MarkDirty();
-  GetNode("out")->MarkDirty();
-  string err;
-  EXPECT_TRUE(plan_.AddTarget(GetNode("out"), &err));
-  ASSERT_EQ("", err);
-  ASSERT_TRUE(plan_.more_to_do());
-
-  Edge* edge = plan_.FindWork();
-  ASSERT_TRUE(edge);
-  ASSERT_EQ("in",  edge->inputs_[0]->path());
-  ASSERT_EQ("mid", edge->outputs_[0]->path());
-
-  ASSERT_FALSE(plan_.FindWork());
-
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);
-  ASSERT_EQ("mid", edge->inputs_[0]->path());
-  ASSERT_EQ("out", edge->outputs_[0]->path());
-
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  ASSERT_FALSE(plan_.more_to_do());
-  edge = plan_.FindWork();
-  ASSERT_NULL(edge);
-}
-
-// Test that two outputs from one rule can be handled as inputs to the next.
-TEST_F(PlanTest, DoubleOutputDirect) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat mid1 mid2\n"
-"build mid1 mid2: cat in\n"));
-  GetNode("mid1")->MarkDirty();
-  GetNode("mid2")->MarkDirty();
-  GetNode("out")->MarkDirty();
-
-  string err;
-  EXPECT_TRUE(plan_.AddTarget(GetNode("out"), &err));
-  ASSERT_EQ("", err);
-  ASSERT_TRUE(plan_.more_to_do());
-
-  Edge* edge;
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);  // cat in
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);  // cat mid1 mid2
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_FALSE(edge);  // done
-}
-
-// Test that two outputs from one rule can eventually be routed to another.
-TEST_F(PlanTest, DoubleOutputIndirect) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat b1 b2\n"
-"build b1: cat a1\n"
-"build b2: cat a2\n"
-"build a1 a2: cat in\n"));
-  GetNode("a1")->MarkDirty();
-  GetNode("a2")->MarkDirty();
-  GetNode("b1")->MarkDirty();
-  GetNode("b2")->MarkDirty();
-  GetNode("out")->MarkDirty();
-  string err;
-  EXPECT_TRUE(plan_.AddTarget(GetNode("out"), &err));
-  ASSERT_EQ("", err);
-  ASSERT_TRUE(plan_.more_to_do());
-
-  Edge* edge;
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);  // cat in
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);  // cat a1
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);  // cat a2
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);  // cat b1 b2
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_FALSE(edge);  // done
-}
-
-// Test that two edges from one output can both execute.
-TEST_F(PlanTest, DoubleDependent) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat a1 a2\n"
-"build a1: cat mid\n"
-"build a2: cat mid\n"
-"build mid: cat in\n"));
-  GetNode("mid")->MarkDirty();
-  GetNode("a1")->MarkDirty();
-  GetNode("a2")->MarkDirty();
-  GetNode("out")->MarkDirty();
-
-  string err;
-  EXPECT_TRUE(plan_.AddTarget(GetNode("out"), &err));
-  ASSERT_EQ("", err);
-  ASSERT_TRUE(plan_.more_to_do());
-
-  Edge* edge;
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);  // cat in
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);  // cat mid
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);  // cat mid
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);  // cat a1 a2
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_FALSE(edge);  // done
-}
-
-void PlanTest::TestPoolWithDepthOne(const char* test_case) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, test_case));
-  GetNode("out1")->MarkDirty();
-  GetNode("out2")->MarkDirty();
-  string err;
-  EXPECT_TRUE(plan_.AddTarget(GetNode("out1"), &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(plan_.AddTarget(GetNode("out2"), &err));
-  ASSERT_EQ("", err);
-  ASSERT_TRUE(plan_.more_to_do());
-
-  Edge* edge = plan_.FindWork();
-  ASSERT_TRUE(edge);
-  ASSERT_EQ("in",  edge->inputs_[0]->path());
-  ASSERT_EQ("out1", edge->outputs_[0]->path());
-
-  // This will be false since poolcat is serialized
-  ASSERT_FALSE(plan_.FindWork());
-
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);
-  ASSERT_EQ("in", edge->inputs_[0]->path());
-  ASSERT_EQ("out2", edge->outputs_[0]->path());
-
-  ASSERT_FALSE(plan_.FindWork());
-
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  ASSERT_FALSE(plan_.more_to_do());
-  edge = plan_.FindWork();
-  ASSERT_NULL(edge);
-}
-
-TEST_F(PlanTest, PoolWithDepthOne) {
-  TestPoolWithDepthOne(
-"pool foobar\n"
-"  depth = 1\n"
-"rule poolcat\n"
-"  command = cat $in > $out\n"
-"  pool = foobar\n"
-"build out1: poolcat in\n"
-"build out2: poolcat in\n");
-}
-
-TEST_F(PlanTest, ConsolePool) {
-  TestPoolWithDepthOne(
-"rule poolcat\n"
-"  command = cat $in > $out\n"
-"  pool = console\n"
-"build out1: poolcat in\n"
-"build out2: poolcat in\n");
-}
-
-TEST_F(PlanTest, PoolsWithDepthTwo) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"pool foobar\n"
-"  depth = 2\n"
-"pool bazbin\n"
-"  depth = 2\n"
-"rule foocat\n"
-"  command = cat $in > $out\n"
-"  pool = foobar\n"
-"rule bazcat\n"
-"  command = cat $in > $out\n"
-"  pool = bazbin\n"
-"build out1: foocat in\n"
-"build out2: foocat in\n"
-"build out3: foocat in\n"
-"build outb1: bazcat in\n"
-"build outb2: bazcat in\n"
-"build outb3: bazcat in\n"
-"  pool =\n"
-"build allTheThings: cat out1 out2 out3 outb1 outb2 outb3\n"
-));
-  // Mark all the out* nodes dirty
-  for (int i = 0; i < 3; ++i) {
-    GetNode("out" + string(1, '1' + static_cast<char>(i)))->MarkDirty();
-    GetNode("outb" + string(1, '1' + static_cast<char>(i)))->MarkDirty();
-  }
-  GetNode("allTheThings")->MarkDirty();
-
-  string err;
-  EXPECT_TRUE(plan_.AddTarget(GetNode("allTheThings"), &err));
-  ASSERT_EQ("", err);
-
-  deque<Edge*> edges;
-  FindWorkSorted(&edges, 5);
-
-  for (int i = 0; i < 4; ++i) {
-    Edge *edge = edges[i];
-    ASSERT_EQ("in",  edge->inputs_[0]->path());
-    string base_name(i < 2 ? "out" : "outb");
-    ASSERT_EQ(base_name + string(1, '1' + (i % 2)), edge->outputs_[0]->path());
-  }
-
-  // outb3 is exempt because it has an empty pool
-  Edge* edge = edges[4];
-  ASSERT_TRUE(edge);
-  ASSERT_EQ("in",  edge->inputs_[0]->path());
-  ASSERT_EQ("outb3", edge->outputs_[0]->path());
-
-  // finish out1
-  plan_.EdgeFinished(edges.front(), Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-  edges.pop_front();
-
-  // out3 should be available
-  Edge* out3 = plan_.FindWork();
-  ASSERT_TRUE(out3);
-  ASSERT_EQ("in",  out3->inputs_[0]->path());
-  ASSERT_EQ("out3", out3->outputs_[0]->path());
-
-  ASSERT_FALSE(plan_.FindWork());
-
-  plan_.EdgeFinished(out3, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  ASSERT_FALSE(plan_.FindWork());
-
-  for (deque<Edge*>::iterator it = edges.begin(); it != edges.end(); ++it) {
-    plan_.EdgeFinished(*it, Plan::kEdgeSucceeded, &err);
-    ASSERT_EQ("", err);
-  }
-
-  Edge* last = plan_.FindWork();
-  ASSERT_TRUE(last);
-  ASSERT_EQ("allTheThings", last->outputs_[0]->path());
-
-  plan_.EdgeFinished(last, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  ASSERT_FALSE(plan_.more_to_do());
-  ASSERT_FALSE(plan_.FindWork());
-}
-
-TEST_F(PlanTest, PoolWithRedundantEdges) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-    "pool compile\n"
-    "  depth = 1\n"
-    "rule gen_foo\n"
-    "  command = touch foo.cpp\n"
-    "rule gen_bar\n"
-    "  command = touch bar.cpp\n"
-    "rule echo\n"
-    "  command = echo $out > $out\n"
-    "build foo.cpp.obj: echo foo.cpp || foo.cpp\n"
-    "  pool = compile\n"
-    "build bar.cpp.obj: echo bar.cpp || bar.cpp\n"
-    "  pool = compile\n"
-    "build libfoo.a: echo foo.cpp.obj bar.cpp.obj\n"
-    "build foo.cpp: gen_foo\n"
-    "build bar.cpp: gen_bar\n"
-    "build all: phony libfoo.a\n"));
-  GetNode("foo.cpp")->MarkDirty();
-  GetNode("foo.cpp.obj")->MarkDirty();
-  GetNode("bar.cpp")->MarkDirty();
-  GetNode("bar.cpp.obj")->MarkDirty();
-  GetNode("libfoo.a")->MarkDirty();
-  GetNode("all")->MarkDirty();
-  string err;
-  EXPECT_TRUE(plan_.AddTarget(GetNode("all"), &err));
-  ASSERT_EQ("", err);
-  ASSERT_TRUE(plan_.more_to_do());
-
-  Edge* edge = NULL;
-
-  deque<Edge*> initial_edges;
-  FindWorkSorted(&initial_edges, 2);
-
-  edge = initial_edges[1];  // Foo first
-  ASSERT_EQ("foo.cpp", edge->outputs_[0]->path());
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);
-  ASSERT_FALSE(plan_.FindWork());
-  ASSERT_EQ("foo.cpp", edge->inputs_[0]->path());
-  ASSERT_EQ("foo.cpp", edge->inputs_[1]->path());
-  ASSERT_EQ("foo.cpp.obj", edge->outputs_[0]->path());
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = initial_edges[0];  // Now for bar
-  ASSERT_EQ("bar.cpp", edge->outputs_[0]->path());
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);
-  ASSERT_FALSE(plan_.FindWork());
-  ASSERT_EQ("bar.cpp", edge->inputs_[0]->path());
-  ASSERT_EQ("bar.cpp", edge->inputs_[1]->path());
-  ASSERT_EQ("bar.cpp.obj", edge->outputs_[0]->path());
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);
-  ASSERT_FALSE(plan_.FindWork());
-  ASSERT_EQ("foo.cpp.obj", edge->inputs_[0]->path());
-  ASSERT_EQ("bar.cpp.obj", edge->inputs_[1]->path());
-  ASSERT_EQ("libfoo.a", edge->outputs_[0]->path());
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);
-  ASSERT_FALSE(plan_.FindWork());
-  ASSERT_EQ("libfoo.a", edge->inputs_[0]->path());
-  ASSERT_EQ("all", edge->outputs_[0]->path());
-  plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_FALSE(edge);
-  ASSERT_FALSE(plan_.more_to_do());
-}
-
-TEST_F(PlanTest, PoolWithFailingEdge) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-    "pool foobar\n"
-    "  depth = 1\n"
-    "rule poolcat\n"
-    "  command = cat $in > $out\n"
-    "  pool = foobar\n"
-    "build out1: poolcat in\n"
-    "build out2: poolcat in\n"));
-  GetNode("out1")->MarkDirty();
-  GetNode("out2")->MarkDirty();
-  string err;
-  EXPECT_TRUE(plan_.AddTarget(GetNode("out1"), &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(plan_.AddTarget(GetNode("out2"), &err));
-  ASSERT_EQ("", err);
-  ASSERT_TRUE(plan_.more_to_do());
-
-  Edge* edge = plan_.FindWork();
-  ASSERT_TRUE(edge);
-  ASSERT_EQ("in",  edge->inputs_[0]->path());
-  ASSERT_EQ("out1", edge->outputs_[0]->path());
-
-  // This will be false since poolcat is serialized
-  ASSERT_FALSE(plan_.FindWork());
-
-  plan_.EdgeFinished(edge, Plan::kEdgeFailed, &err);
-  ASSERT_EQ("", err);
-
-  edge = plan_.FindWork();
-  ASSERT_TRUE(edge);
-  ASSERT_EQ("in", edge->inputs_[0]->path());
-  ASSERT_EQ("out2", edge->outputs_[0]->path());
-
-  ASSERT_FALSE(plan_.FindWork());
-
-  plan_.EdgeFinished(edge, Plan::kEdgeFailed, &err);
-  ASSERT_EQ("", err);
-
-  ASSERT_TRUE(plan_.more_to_do()); // Jobs have failed
-  edge = plan_.FindWork();
-  ASSERT_NULL(edge);
-}
-
-/// Fake implementation of CommandRunner, useful for tests.
-struct FakeCommandRunner : public CommandRunner {
-  explicit FakeCommandRunner(VirtualFileSystem* fs) :
-      max_active_edges_(1), fs_(fs) {}
-
-  // CommandRunner impl
-  bool CanRunMore() const override;
-  bool StartCommand(Edge* edge) override;
-  bool WaitForCommand(Result* result) override;
-  vector<Edge*> GetActiveEdges() override;
-  void Abort() override;
-
-  vector<string> commands_ran_;
-  vector<Edge*> active_edges_;
-  size_t max_active_edges_;
-  VirtualFileSystem* fs_;
-};
-
-struct BuildTest : public StateTestWithBuiltinRules, public BuildLogUser {
-  BuildTest() : config_(MakeConfig()), command_runner_(&fs_), status_(config_),
-                builder_(&state_, config_, NULL, NULL, &fs_, &status_, 0) {
-  }
-
-  explicit BuildTest(DepsLog* log)
-      : config_(MakeConfig()), command_runner_(&fs_), status_(config_),
-        builder_(&state_, config_, NULL, log, &fs_, &status_, 0) {}
-
-  virtual void SetUp() {
-    StateTestWithBuiltinRules::SetUp();
-
-    builder_.command_runner_.reset(&command_runner_);
-    AssertParse(&state_,
-"build cat1: cat in1\n"
-"build cat2: cat in1 in2\n"
-"build cat12: cat cat1 cat2\n");
-
-    fs_.Create("in1", "");
-    fs_.Create("in2", "");
-  }
-
-  ~BuildTest() {
-    builder_.command_runner_.release();
-  }
-
-  virtual bool IsPathDead(StringPiece s) const { return false; }
-
-  /// Rebuild target in the 'working tree' (fs_).
-  /// State of command_runner_ and logs contents (if specified) ARE MODIFIED.
-  /// Handy to check for NOOP builds, and higher-level rebuild tests.
-  void RebuildTarget(const string& target, const char* manifest,
-                     const char* log_path = NULL, const char* deps_path = NULL,
-                     State* state = NULL);
-
-  // Mark a path dirty.
-  void Dirty(const string& path);
-
-  BuildConfig MakeConfig() {
-    BuildConfig config;
-    config.verbosity = BuildConfig::QUIET;
-    return config;
-  }
-
-  BuildConfig config_;
-  FakeCommandRunner command_runner_;
-  VirtualFileSystem fs_;
-  StatusPrinter status_;
-  Builder builder_;
-};
-
-void BuildTest::RebuildTarget(const string& target, const char* manifest,
-                              const char* log_path, const char* deps_path,
-                              State* state) {
-  State local_state, *pstate = &local_state;
-  if (state)
-    pstate = state;
-  ASSERT_NO_FATAL_FAILURE(AddCatRule(pstate));
-  AssertParse(pstate, manifest);
-
-  string err;
-  BuildLog build_log, *pbuild_log = NULL;
-  if (log_path) {
-    ASSERT_TRUE(build_log.Load(log_path, &err));
-    ASSERT_TRUE(build_log.OpenForWrite(log_path, *this, &err));
-    ASSERT_EQ("", err);
-    pbuild_log = &build_log;
-  }
-
-  DepsLog deps_log, *pdeps_log = NULL;
-  if (deps_path) {
-    ASSERT_TRUE(deps_log.Load(deps_path, pstate, &err));
-    ASSERT_TRUE(deps_log.OpenForWrite(deps_path, &err));
-    ASSERT_EQ("", err);
-    pdeps_log = &deps_log;
-  }
-
-  Builder builder(pstate, config_, pbuild_log, pdeps_log, &fs_, &status_, 0);
-  EXPECT_TRUE(builder.AddTarget(target, &err));
-
-  command_runner_.commands_ran_.clear();
-  builder.command_runner_.reset(&command_runner_);
-  if (!builder.AlreadyUpToDate()) {
-    bool build_res = builder.Build(&err);
-    EXPECT_TRUE(build_res);
-  }
-  builder.command_runner_.release();
-}
-
-bool FakeCommandRunner::CanRunMore() const {
-  return active_edges_.size() < max_active_edges_;
-}
-
-bool FakeCommandRunner::StartCommand(Edge* edge) {
-  assert(active_edges_.size() < max_active_edges_);
-  assert(find(active_edges_.begin(), active_edges_.end(), edge)
-         == active_edges_.end());
-  commands_ran_.push_back(edge->EvaluateCommand());
-  if (edge->rule().name() == "cat"  ||
-      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") {
-    for (vector<Node*>::iterator out = edge->outputs_.begin();
-         out != edge->outputs_.end(); ++out) {
-      fs_->Create((*out)->path(), "");
-    }
-  } else if (edge->rule().name() == "true" ||
-             edge->rule().name() == "fail" ||
-             edge->rule().name() == "interrupt" ||
-             edge->rule().name() == "console") {
-    // Don't do anything.
-  } else if (edge->rule().name() == "cp") {
-    assert(!edge->inputs_.empty());
-    assert(edge->outputs_.size() == 1);
-    string content;
-    string err;
-    if (fs_->ReadFile(edge->inputs_[0]->path(), &content, &err) ==
-        DiskInterface::Okay)
-      fs_->WriteFile(edge->outputs_[0]->path(), content);
-  } else if (edge->rule().name() == "touch-implicit-dep-out") {
-    string dep = edge->GetBinding("test_dependency");
-    fs_->Tick();
-    fs_->Create(dep, "");
-    fs_->Tick();
-    for (vector<Node*>::iterator out = edge->outputs_.begin();
-         out != edge->outputs_.end(); ++out) {
-      fs_->Create((*out)->path(), "");
-    }
-  } else if (edge->rule().name() == "touch-out-implicit-dep") {
-    string dep = edge->GetBinding("test_dependency");
-    for (vector<Node*>::iterator out = edge->outputs_.begin();
-         out != edge->outputs_.end(); ++out) {
-      fs_->Create((*out)->path(), "");
-    }
-    fs_->Tick();
-    fs_->Create(dep, "");
-  } else if (edge->rule().name() == "generate-depfile") {
-    string dep = edge->GetBinding("test_dependency");
-    bool touch_dep = edge->GetBindingBool("touch_dependency");
-    string depfile = edge->GetUnescapedDepfile();
-    if (touch_dep) {
-      fs_->Tick();
-      fs_->Create(dep, "");
-    }
-    string contents;
-    for (vector<Node*>::iterator out = edge->outputs_.begin();
-         out != edge->outputs_.end(); ++out) {
-      contents += (*out)->path() + ": " + dep + "\n";
-      fs_->Create((*out)->path(), "");
-    }
-    fs_->Create(depfile, contents);
-  } else if (edge->rule().name() == "long-cc") {
-    string dep = edge->GetBinding("test_dependency");
-    string depfile = edge->GetUnescapedDepfile();
-    string contents;
-    for (vector<Node*>::iterator out = edge->outputs_.begin();
-        out != edge->outputs_.end(); ++out) {
-      fs_->Tick();
-      fs_->Tick();
-      fs_->Tick();
-      fs_->Create((*out)->path(), "");
-      contents += (*out)->path() + ": " + dep + "\n";
-    }
-    if (!dep.empty() && !depfile.empty())
-      fs_->Create(depfile, contents);
-  } else {
-    printf("unknown command\n");
-    return false;
-  }
-
-  active_edges_.push_back(edge);
-
-  // Allow tests to control the order by the name of the first output.
-  sort(active_edges_.begin(), active_edges_.end(),
-       CompareEdgesByOutput::cmp);
-
-  return true;
-}
-
-bool FakeCommandRunner::WaitForCommand(Result* result) {
-  if (active_edges_.empty())
-    return false;
-
-  // All active edges were already completed immediately when started,
-  // so we can pick any edge here.  Pick the last edge.  Tests can
-  // control the order of edges by the name of the first output.
-  vector<Edge*>::iterator edge_iter = active_edges_.end() - 1;
-
-  Edge* edge = *edge_iter;
-  result->edge = edge;
-
-  if (edge->rule().name() == "interrupt" ||
-      edge->rule().name() == "touch-interrupt") {
-    result->status = ExitInterrupted;
-    return true;
-  }
-
-  if (edge->rule().name() == "console") {
-    if (edge->use_console())
-      result->status = ExitSuccess;
-    else
-      result->status = ExitFailure;
-    active_edges_.erase(edge_iter);
-    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;
-  else
-    result->status = ExitSuccess;
-
-  // This rule simulates an external process modifying files while the build command runs.
-  // See TestInputMtimeRaceCondition and TestInputMtimeRaceConditionWithDepFile.
-  // Note: only the first and third time the rule is run per test is the file modified, so
-  // the test can verify that subsequent runs without the race have no work to do.
-  if (edge->rule().name() == "long-cc") {
-    string dep = edge->GetBinding("test_dependency");
-    if (fs_->now_ == 4)
-      fs_->files_[dep].mtime = 3;
-    if (fs_->now_ == 10)
-      fs_->files_[dep].mtime = 9;
-  }
-
-  // Provide a way for test cases to verify when an edge finishes that
-  // some other edge is still active.  This is useful for test cases
-  // covering behavior involving multiple active edges.
-  const string& verify_active_edge = edge->GetBinding("verify_active_edge");
-  if (!verify_active_edge.empty()) {
-    bool verify_active_edge_found = false;
-    for (vector<Edge*>::iterator i = active_edges_.begin();
-         i != active_edges_.end(); ++i) {
-      if (!(*i)->outputs_.empty() &&
-          (*i)->outputs_[0]->path() == verify_active_edge) {
-        verify_active_edge_found = true;
-      }
-    }
-    EXPECT_TRUE(verify_active_edge_found);
-  }
-
-  active_edges_.erase(edge_iter);
-  return true;
-}
-
-vector<Edge*> FakeCommandRunner::GetActiveEdges() {
-  return active_edges_;
-}
-
-void FakeCommandRunner::Abort() {
-  active_edges_.clear();
-}
-
-void BuildTest::Dirty(const string& path) {
-  Node* node = GetNode(path);
-  node->MarkDirty();
-
-  // If it's an input file, mark that we've already stat()ed it and
-  // it's missing.
-  if (!node->in_edge())
-    node->MarkMissing();
-}
-
-TEST_F(BuildTest, NoWork) {
-  string err;
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-}
-
-TEST_F(BuildTest, OneStep) {
-  // Given a dirty target with one ready input,
-  // we should rebuild the target.
-  Dirty("cat1");
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("cat1", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cat in1 > cat1", command_runner_.commands_ran_[0]);
-}
-
-TEST_F(BuildTest, OneStep2) {
-  // Given a target with one dirty input,
-  // we should rebuild the target.
-  Dirty("cat1");
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("cat1", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cat in1 > cat1", command_runner_.commands_ran_[0]);
-}
-
-TEST_F(BuildTest, TwoStep) {
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("cat12", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  // Depending on how the pointers work out, we could've ran
-  // the first two commands in either order.
-  EXPECT_TRUE((command_runner_.commands_ran_[0] == "cat in1 > cat1" &&
-               command_runner_.commands_ran_[1] == "cat in1 in2 > cat2") ||
-              (command_runner_.commands_ran_[1] == "cat in1 > cat1" &&
-               command_runner_.commands_ran_[0] == "cat in1 in2 > cat2"));
-
-  EXPECT_EQ("cat cat1 cat2 > cat12", command_runner_.commands_ran_[2]);
-
-  fs_.Tick();
-
-  // Modifying in2 requires rebuilding one intermediate file
-  // and the final file.
-  fs_.Create("in2", "");
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("cat12", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(5u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cat in1 in2 > cat2", command_runner_.commands_ran_[3]);
-  EXPECT_EQ("cat cat1 cat2 > cat12", command_runner_.commands_ran_[4]);
-}
-
-TEST_F(BuildTest, TwoOutputs) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"build out1 out2: touch in.txt\n"));
-
-  fs_.Create("in.txt", "");
-
-  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("touch out1 out2", command_runner_.commands_ran_[0]);
-}
-
-TEST_F(BuildTest, ImplicitOutput) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out $out.imp\n"
-"build out | out.imp: touch in.txt\n"));
-  fs_.Create("in.txt", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out.imp", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("touch out out.imp", command_runner_.commands_ran_[0]);
-}
-
-// Test case from
-//   https://github.com/ninja-build/ninja/issues/148
-TEST_F(BuildTest, MultiOutIn) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"build in1 otherfile: touch in\n"
-"build out: touch in | in1\n"));
-
-  fs_.Create("in", "");
-  fs_.Tick();
-  fs_.Create("in1", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-}
-
-TEST_F(BuildTest, Chain) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build c2: cat c1\n"
-"build c3: cat c2\n"
-"build c4: cat c3\n"
-"build c5: cat c4\n"));
-
-  fs_.Create("c1", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("c5", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(4u, command_runner_.commands_ran_.size());
-
-  err.clear();
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("c5", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-
-  fs_.Tick();
-
-  fs_.Create("c3", "");
-  err.clear();
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("c5", &err));
-  ASSERT_EQ("", err);
-  EXPECT_FALSE(builder_.AlreadyUpToDate());
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ(2u, command_runner_.commands_ran_.size());  // 3->4, 4->5
-}
-
-TEST_F(BuildTest, MissingInput) {
-  // Input is referenced by build file, but no rule for it.
-  string err;
-  Dirty("in1");
-  EXPECT_FALSE(builder_.AddTarget("cat1", &err));
-  EXPECT_EQ("'in1', needed by 'cat1', missing and no known rule to make it",
-            err);
-}
-
-TEST_F(BuildTest, MissingTarget) {
-  // Target is not referenced by build file.
-  string err;
-  EXPECT_FALSE(builder_.AddTarget("meow", &err));
-  EXPECT_EQ("unknown target: 'meow'", err);
-}
-
-TEST_F(BuildTest, MissingInputTarget) {
-  // Target is a missing input file
-  string err;
-  Dirty("in1");
-  EXPECT_FALSE(builder_.AddTarget("in1", &err));
-  EXPECT_EQ("'in1' missing and no known rule to make it", err);
-}
-
-TEST_F(BuildTest, MakeDirs) {
-  string err;
-
-#ifdef _WIN32
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-                                      "build subdir\\dir2\\file: cat in1\n"));
-#else
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-                                      "build subdir/dir2/file: cat in1\n"));
-#endif
-  EXPECT_TRUE(builder_.AddTarget("subdir/dir2/file", &err));
-
-  EXPECT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(2u, fs_.directories_made_.size());
-  EXPECT_EQ("subdir", fs_.directories_made_[0]);
-  EXPECT_EQ("subdir/dir2", fs_.directories_made_[1]);
-}
-
-TEST_F(BuildTest, DepFileMissing) {
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cc\n  command = cc $in\n  depfile = $out.d\n"
-"build fo$ o.o: cc foo.c\n"));
-  fs_.Create("foo.c", "");
-
-  EXPECT_TRUE(builder_.AddTarget("fo o.o", &err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, fs_.files_read_.size());
-  EXPECT_EQ("fo o.o.d", fs_.files_read_[0]);
-}
-
-TEST_F(BuildTest, DepFileOK) {
-  string err;
-  int orig_edges = state_.edges_.size();
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cc\n  command = cc $in\n  depfile = $out.d\n"
-"build foo.o: cc foo.c\n"));
-  Edge* edge = state_.edges_.back();
-
-  fs_.Create("foo.c", "");
-  GetNode("bar.h")->MarkDirty();  // Mark bar.h as missing.
-  fs_.Create("foo.o.d", "foo.o: blah.h bar.h\n");
-  EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, fs_.files_read_.size());
-  EXPECT_EQ("foo.o.d", fs_.files_read_[0]);
-
-  // Expect one new edge generating foo.o. Loading the depfile should have
-  // added nodes, but not phony edges to the graph.
-  ASSERT_EQ(orig_edges + 1, (int)state_.edges_.size());
-
-  // Verify that nodes for blah.h and bar.h were added and that they
-  // are marked as generated by a dep loader.
-  ASSERT_FALSE(state_.LookupNode("foo.o")->generated_by_dep_loader());
-  ASSERT_FALSE(state_.LookupNode("foo.c")->generated_by_dep_loader());
-  ASSERT_TRUE(state_.LookupNode("blah.h"));
-  ASSERT_TRUE(state_.LookupNode("blah.h")->generated_by_dep_loader());
-  ASSERT_TRUE(state_.LookupNode("bar.h"));
-  ASSERT_TRUE(state_.LookupNode("bar.h")->generated_by_dep_loader());
-
-  // Expect our edge to now have three inputs: foo.c and two headers.
-  ASSERT_EQ(3u, edge->inputs_.size());
-
-  // Expect the command line we generate to only use the original input.
-  ASSERT_EQ("cc foo.c", edge->EvaluateCommand());
-}
-
-TEST_F(BuildTest, DepFileParseError) {
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cc\n  command = cc $in\n  depfile = $out.d\n"
-"build foo.o: cc foo.c\n"));
-  fs_.Create("foo.c", "");
-  fs_.Create("foo.o.d", "randomtext\n");
-  EXPECT_FALSE(builder_.AddTarget("foo.o", &err));
-  EXPECT_EQ("foo.o.d: expected ':' in depfile", err);
-}
-
-TEST_F(BuildTest, EncounterReadyTwice) {
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"build c: touch\n"
-"build b: touch || c\n"
-"build a: touch | b || c\n"));
-
-  vector<Edge*> c_out = GetNode("c")->out_edges();
-  ASSERT_EQ(2u, c_out.size());
-  EXPECT_EQ("b", c_out[0]->outputs_[0]->path());
-  EXPECT_EQ("a", c_out[1]->outputs_[0]->path());
-
-  fs_.Create("b", "");
-  EXPECT_TRUE(builder_.AddTarget("a", &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(2u, command_runner_.commands_ran_.size());
-}
-
-TEST_F(BuildTest, OrderOnlyDeps) {
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cc\n  command = cc $in\n  depfile = $out.d\n"
-"build foo.o: cc foo.c || otherfile\n"));
-  Edge* edge = state_.edges_.back();
-
-  fs_.Create("foo.c", "");
-  fs_.Create("otherfile", "");
-  fs_.Create("foo.o.d", "foo.o: blah.h bar.h\n");
-  EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
-  ASSERT_EQ("", err);
-
-  // One explicit, two implicit, one order only.
-  ASSERT_EQ(4u, edge->inputs_.size());
-  EXPECT_EQ(2, edge->implicit_deps_);
-  EXPECT_EQ(1, edge->order_only_deps_);
-  // Verify the inputs are in the order we expect
-  // (explicit then implicit then orderonly).
-  EXPECT_EQ("foo.c", edge->inputs_[0]->path());
-  EXPECT_EQ("blah.h", edge->inputs_[1]->path());
-  EXPECT_EQ("bar.h", edge->inputs_[2]->path());
-  EXPECT_EQ("otherfile", edge->inputs_[3]->path());
-
-  // Expect the command line we generate to only use the original input.
-  ASSERT_EQ("cc foo.c", edge->EvaluateCommand());
-
-  // explicit dep dirty, expect a rebuild.
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-
-  fs_.Tick();
-
-  // Recreate the depfile, as it should have been deleted by the build.
-  fs_.Create("foo.o.d", "foo.o: blah.h bar.h\n");
-
-  // implicit dep dirty, expect a rebuild.
-  fs_.Create("blah.h", "");
-  fs_.Create("bar.h", "");
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-
-  fs_.Tick();
-
-  // Recreate the depfile, as it should have been deleted by the build.
-  fs_.Create("foo.o.d", "foo.o: blah.h bar.h\n");
-
-  // order only dep dirty, no rebuild.
-  fs_.Create("otherfile", "");
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
-  EXPECT_EQ("", err);
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-
-  // implicit dep missing, expect rebuild.
-  fs_.RemoveFile("bar.h");
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-}
-
-TEST_F(BuildTest, RebuildOrderOnlyDeps) {
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cc\n  command = cc $in\n"
-"rule true\n  command = true\n"
-"build oo.h: cc oo.h.in\n"
-"build foo.o: cc foo.c || oo.h\n"));
-
-  fs_.Create("foo.c", "");
-  fs_.Create("oo.h.in", "");
-
-  // foo.o and order-only dep dirty, build both.
-  EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(2u, command_runner_.commands_ran_.size());
-
-  // all clean, no rebuild.
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
-  EXPECT_EQ("", err);
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-
-  // order-only dep missing, build it only.
-  fs_.RemoveFile("oo.h");
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-  ASSERT_EQ("cc oo.h.in", command_runner_.commands_ran_[0]);
-
-  fs_.Tick();
-
-  // order-only dep dirty, build it only.
-  fs_.Create("oo.h.in", "");
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-  ASSERT_EQ("cc oo.h.in", command_runner_.commands_ran_[0]);
-}
-
-#ifdef _WIN32
-TEST_F(BuildTest, DepFileCanonicalize) {
-  string err;
-  int orig_edges = state_.edges_.size();
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cc\n  command = cc $in\n  depfile = $out.d\n"
-"build gen/stuff\\things/foo.o: cc x\\y/z\\foo.c\n"));
-  Edge* edge = state_.edges_.back();
-
-  fs_.Create("x/y/z/foo.c", "");
-  GetNode("bar.h")->MarkDirty();  // Mark bar.h as missing.
-  // Note, different slashes from manifest.
-  fs_.Create("gen/stuff\\things/foo.o.d",
-             "gen\\stuff\\things\\foo.o: blah.h bar.h\n");
-  EXPECT_TRUE(builder_.AddTarget("gen/stuff/things/foo.o", &err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, fs_.files_read_.size());
-  // The depfile path does not get Canonicalize as it seems unnecessary.
-  EXPECT_EQ("gen/stuff\\things/foo.o.d", fs_.files_read_[0]);
-
-  // Expect one new edge generating foo.o
-  ASSERT_EQ(orig_edges + 1, (int)state_.edges_.size());
-  // Expect our edge to now have three inputs: foo.c and two headers.
-  ASSERT_EQ(3u, edge->inputs_.size());
-
-  // Expect the command line we generate to only use the original input, and
-  // using the slashes from the manifest.
-  ASSERT_EQ("cc x\\y/z\\foo.c", edge->EvaluateCommand());
-}
-#endif
-
-TEST_F(BuildTest, Phony) {
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat bar.cc\n"
-"build all: phony out\n"));
-  fs_.Create("bar.cc", "");
-
-  EXPECT_TRUE(builder_.AddTarget("all", &err));
-  ASSERT_EQ("", err);
-
-  // Only one command to run, because phony runs no command.
-  EXPECT_FALSE(builder_.AlreadyUpToDate());
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-}
-
-TEST_F(BuildTest, PhonyNoWork) {
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat bar.cc\n"
-"build all: phony out\n"));
-  fs_.Create("bar.cc", "");
-  fs_.Create("out", "");
-
-  EXPECT_TRUE(builder_.AddTarget("all", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-}
-
-// Test a self-referencing phony.  Ideally this should not work, but
-// ninja 1.7 and below tolerated and CMake 2.8.12.x and 3.0.x both
-// incorrectly produce it.  We tolerate it for compatibility.
-TEST_F(BuildTest, PhonySelfReference) {
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build a: phony a\n"));
-
-  EXPECT_TRUE(builder_.AddTarget("a", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-}
-
-// There are 6 different cases for phony rules:
-//
-// 1. output edge does not exist, inputs are not real
-// 2. output edge does not exist, no inputs
-// 3. output edge does not exist, inputs are real, newest mtime is M
-// 4. output edge is real, inputs are not real
-// 5. output edge is real, no inputs
-// 6. output edge is real, inputs are real, newest mtime is M
-//
-// Expected results :
-// 1. Edge is marked as clean, mtime is newest mtime of dependents.
-//     Touching inputs will cause dependents to rebuild.
-// 2. Edge is marked as dirty, causing dependent edges to always rebuild
-// 3. Edge is marked as clean, mtime is newest mtime of dependents.
-//     Touching inputs will cause dependents to rebuild.
-// 4. Edge is marked as clean, mtime is newest mtime of dependents.
-//     Touching inputs will cause dependents to rebuild.
-// 5. Edge is marked as dirty, causing dependent edges to always rebuild
-// 6. Edge is marked as clean, mtime is newest mtime of dependents.
-//     Touching inputs will cause dependents to rebuild.
-void TestPhonyUseCase(BuildTest* t, int i) {
-  State& state_ = t->state_;
-  Builder& builder_ = t->builder_;
-  FakeCommandRunner& command_runner_ = t->command_runner_;
-  VirtualFileSystem& fs_ = t->fs_;
-
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-" command = touch $out\n"
-"build notreal: phony blank\n"
-"build phony1: phony notreal\n"
-"build phony2: phony\n"
-"build phony3: phony blank\n"
-"build phony4: phony notreal\n"
-"build phony5: phony\n"
-"build phony6: phony blank\n"
-"\n"
-"build test1: touch phony1\n"
-"build test2: touch phony2\n"
-"build test3: touch phony3\n"
-"build test4: touch phony4\n"
-"build test5: touch phony5\n"
-"build test6: touch phony6\n"
-));
-
-  // Set up test.
-  builder_.command_runner_.release(); // BuildTest owns the CommandRunner
-  builder_.command_runner_.reset(&command_runner_);
-
-  fs_.Create("blank", "");  // a "real" file
-  EXPECT_TRUE(builder_.AddTarget("test1", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.AddTarget("test2", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.AddTarget("test3", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.AddTarget("test4", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.AddTarget("test5", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.AddTarget("test6", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-
-  string ci;
-  ci += static_cast<char>('0' + i);
-
-  // Tests 1, 3, 4, and 6 should rebuild when the input is updated.
-  if (i != 2 && i != 5) {
-    Node* testNode  = t->GetNode("test" + ci);
-    Node* phonyNode = t->GetNode("phony" + ci);
-    Node* inputNode = t->GetNode("blank");
-
-    state_.Reset();
-    TimeStamp startTime = fs_.now_;
-
-    // Build number 1
-    EXPECT_TRUE(builder_.AddTarget("test" + ci, &err));
-    ASSERT_EQ("", err);
-    if (!builder_.AlreadyUpToDate())
-      EXPECT_TRUE(builder_.Build(&err));
-    ASSERT_EQ("", err);
-
-    // Touch the input file
-    state_.Reset();
-    command_runner_.commands_ran_.clear();
-    fs_.Tick();
-    fs_.Create("blank", "");  // a "real" file
-    EXPECT_TRUE(builder_.AddTarget("test" + ci, &err));
-    ASSERT_EQ("", err);
-
-    // Second build, expect testN edge to be rebuilt
-    // and phonyN node's mtime to be updated.
-    EXPECT_FALSE(builder_.AlreadyUpToDate());
-    EXPECT_TRUE(builder_.Build(&err));
-    ASSERT_EQ("", err);
-    ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-    EXPECT_EQ(string("touch test") + ci, command_runner_.commands_ran_[0]);
-    EXPECT_TRUE(builder_.AlreadyUpToDate());
-
-    TimeStamp inputTime = inputNode->mtime();
-
-    EXPECT_FALSE(phonyNode->exists());
-    EXPECT_FALSE(phonyNode->dirty());
-
-    EXPECT_GT(phonyNode->mtime(), startTime);
-    EXPECT_EQ(phonyNode->mtime(), inputTime);
-    ASSERT_TRUE(testNode->Stat(&fs_, &err));
-    EXPECT_TRUE(testNode->exists());
-    EXPECT_GT(testNode->mtime(), startTime);
-  } else {
-    // Tests 2 and 5: Expect dependents to always rebuild.
-
-    state_.Reset();
-    command_runner_.commands_ran_.clear();
-    fs_.Tick();
-    command_runner_.commands_ran_.clear();
-    EXPECT_TRUE(builder_.AddTarget("test" + ci, &err));
-    ASSERT_EQ("", err);
-    EXPECT_FALSE(builder_.AlreadyUpToDate());
-    EXPECT_TRUE(builder_.Build(&err));
-    ASSERT_EQ("", err);
-    ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-    EXPECT_EQ("touch test" + ci, command_runner_.commands_ran_[0]);
-
-    state_.Reset();
-    command_runner_.commands_ran_.clear();
-    EXPECT_TRUE(builder_.AddTarget("test" + ci, &err));
-    ASSERT_EQ("", err);
-    EXPECT_FALSE(builder_.AlreadyUpToDate());
-    EXPECT_TRUE(builder_.Build(&err));
-    ASSERT_EQ("", err);
-    ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-    EXPECT_EQ("touch test" + ci, command_runner_.commands_ran_[0]);
-  }
-}
-
-TEST_F(BuildTest, PhonyUseCase1) { TestPhonyUseCase(this, 1); }
-TEST_F(BuildTest, PhonyUseCase2) { TestPhonyUseCase(this, 2); }
-TEST_F(BuildTest, PhonyUseCase3) { TestPhonyUseCase(this, 3); }
-TEST_F(BuildTest, PhonyUseCase4) { TestPhonyUseCase(this, 4); }
-TEST_F(BuildTest, PhonyUseCase5) { TestPhonyUseCase(this, 5); }
-TEST_F(BuildTest, PhonyUseCase6) { TestPhonyUseCase(this, 6); }
-
-TEST_F(BuildTest, Fail) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule fail\n"
-"  command = fail\n"
-"build out1: fail\n"));
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_FALSE(builder_.Build(&err));
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-  ASSERT_EQ("subcommand failed", err);
-}
-
-TEST_F(BuildTest, SwallowFailures) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule fail\n"
-"  command = fail\n"
-"build out1: fail\n"
-"build out2: fail\n"
-"build out3: fail\n"
-"build all: phony out1 out2 out3\n"));
-
-  // Swallow two failures, die on the third.
-  config_.failures_allowed = 3;
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("all", &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_FALSE(builder_.Build(&err));
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  ASSERT_EQ("subcommands failed", err);
-}
-
-TEST_F(BuildTest, SwallowFailuresLimit) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule fail\n"
-"  command = fail\n"
-"build out1: fail\n"
-"build out2: fail\n"
-"build out3: fail\n"
-"build final: cat out1 out2 out3\n"));
-
-  // Swallow ten failures; we should stop before building final.
-  config_.failures_allowed = 11;
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("final", &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_FALSE(builder_.Build(&err));
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  ASSERT_EQ("cannot make progress due to previous errors", err);
-}
-
-TEST_F(BuildTest, SwallowFailuresPool) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"pool failpool\n"
-"  depth = 1\n"
-"rule fail\n"
-"  command = fail\n"
-"  pool = failpool\n"
-"build out1: fail\n"
-"build out2: fail\n"
-"build out3: fail\n"
-"build final: cat out1 out2 out3\n"));
-
-  // Swallow ten failures; we should stop before building final.
-  config_.failures_allowed = 11;
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("final", &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_FALSE(builder_.Build(&err));
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  ASSERT_EQ("cannot make progress due to previous errors", err);
-}
-
-TEST_F(BuildTest, PoolEdgesReadyButNotWanted) {
-  fs_.Create("x", "");
-
-  const char* manifest =
-    "pool some_pool\n"
-    "  depth = 4\n"
-    "rule touch\n"
-    "  command = touch $out\n"
-    "  pool = some_pool\n"
-    "rule cc\n"
-    "  command = touch grit\n"
-    "\n"
-    "build B.d.stamp: cc | x\n"
-    "build C.stamp: touch B.d.stamp\n"
-    "build final.stamp: touch || C.stamp\n";
-
-  RebuildTarget("final.stamp", manifest);
-
-  fs_.RemoveFile("B.d.stamp");
-
-  State save_state;
-  RebuildTarget("final.stamp", manifest, NULL, NULL, &save_state);
-  EXPECT_GE(save_state.LookupPool("some_pool")->current_use(), 0);
-}
-
-struct BuildWithLogTest : public BuildTest {
-  BuildWithLogTest() {
-    builder_.SetBuildLog(&build_log_);
-  }
-
-  BuildLog build_log_;
-};
-
-TEST_F(BuildWithLogTest, ImplicitGeneratedOutOfDate) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"  generator = 1\n"
-"build out.imp: touch | in\n"));
-  fs_.Create("out.imp", "");
-  fs_.Tick();
-  fs_.Create("in", "");
-
-  string err;
-
-  EXPECT_TRUE(builder_.AddTarget("out.imp", &err));
-  EXPECT_FALSE(builder_.AlreadyUpToDate());
-
-  EXPECT_TRUE(GetNode("out.imp")->dirty());
-}
-
-TEST_F(BuildWithLogTest, ImplicitGeneratedOutOfDate2) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch-implicit-dep-out\n"
-"  command = sleep 1 ; touch $test_dependency ; sleep 1 ; touch $out\n"
-"  generator = 1\n"
-"build out.imp: touch-implicit-dep-out | inimp inimp2\n"
-"  test_dependency = inimp\n"));
-  fs_.Create("inimp", "");
-  fs_.Create("out.imp", "");
-  fs_.Tick();
-  fs_.Create("inimp2", "");
-  fs_.Tick();
-
-  string err;
-
-  EXPECT_TRUE(builder_.AddTarget("out.imp", &err));
-  EXPECT_FALSE(builder_.AlreadyUpToDate());
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  builder_.Cleanup();
-  builder_.plan_.Reset();
-
-  EXPECT_TRUE(builder_.AddTarget("out.imp", &err));
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-  EXPECT_FALSE(GetNode("out.imp")->dirty());
-
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  builder_.Cleanup();
-  builder_.plan_.Reset();
-
-  fs_.Tick();
-  fs_.Create("inimp", "");
-
-  EXPECT_TRUE(builder_.AddTarget("out.imp", &err));
-  EXPECT_FALSE(builder_.AlreadyUpToDate());
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  builder_.Cleanup();
-  builder_.plan_.Reset();
-
-  EXPECT_TRUE(builder_.AddTarget("out.imp", &err));
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-  EXPECT_FALSE(GetNode("out.imp")->dirty());
-}
-
-TEST_F(BuildWithLogTest, NotInLogButOnDisk) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cc\n"
-"  command = cc\n"
-"build out1: cc in\n"));
-
-  // Create input/output that would be considered up to date when
-  // not considering the command line hash.
-  fs_.Create("in", "");
-  fs_.Create("out1", "");
-  string err;
-
-  // Because it's not in the log, it should not be up-to-date until
-  // we build again.
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  EXPECT_FALSE(builder_.AlreadyUpToDate());
-
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-}
-
-TEST_F(BuildWithLogTest, RebuildAfterFailure) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch-fail-tick2\n"
-"  command = touch-fail-tick2\n"
-"build out1: touch-fail-tick2 in\n"));
-
-  string err;
-
-  fs_.Create("in", "");
-
-  // Run once successfully to get out1 in the log
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  EXPECT_EQ(1u, command_runner_.commands_ran_.size());
-
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  builder_.Cleanup();
-  builder_.plan_.Reset();
-
-  fs_.Tick();
-  fs_.Create("in", "");
-
-  // Run again with a failure that updates the output file timestamp
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  EXPECT_FALSE(builder_.Build(&err));
-  EXPECT_EQ("subcommand failed", err);
-  EXPECT_EQ(1u, command_runner_.commands_ran_.size());
-
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  builder_.Cleanup();
-  builder_.plan_.Reset();
-
-  fs_.Tick();
-
-  // Run again, should rerun even though the output file is up to date on disk
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  EXPECT_FALSE(builder_.AlreadyUpToDate());
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ(1u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("", err);
-}
-
-TEST_F(BuildWithLogTest, RebuildWithNoInputs) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch\n"
-"build out1: touch\n"
-"build out2: touch in\n"));
-
-  string err;
-
-  fs_.Create("in", "");
-
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  EXPECT_EQ(2u, command_runner_.commands_ran_.size());
-
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-
-  fs_.Tick();
-
-  fs_.Create("in", "");
-
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  EXPECT_EQ(1u, command_runner_.commands_ran_.size());
-}
-
-TEST_F(BuildWithLogTest, RestatTest) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule true\n"
-"  command = true\n"
-"  restat = 1\n"
-"rule cc\n"
-"  command = cc\n"
-"  restat = 1\n"
-"build out1: cc in\n"
-"build out2: true out1\n"
-"build out3: cat out2\n"));
-
-  fs_.Create("out1", "");
-  fs_.Create("out2", "");
-  fs_.Create("out3", "");
-
-  fs_.Tick();
-
-  fs_.Create("in", "");
-
-  // Do a pre-build so that there's commands in the log for the outputs,
-  // otherwise, the lack of an entry in the build log will cause out3 to rebuild
-  // regardless of restat.
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out3", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  EXPECT_EQ(3u, command_runner_.commands_ran_.size());
-  EXPECT_EQ(3u, builder_.plan_.command_edge_count());
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-
-  fs_.Tick();
-
-  fs_.Create("in", "");
-  // "cc" touches out1, so we should build out2.  But because "true" does not
-  // touch out2, we should cancel the build of out3.
-  EXPECT_TRUE(builder_.AddTarget("out3", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ(2u, command_runner_.commands_ran_.size());
-
-  // If we run again, it should be a no-op, because the build log has recorded
-  // that we've already built out2 with an input timestamp of 2 (from out1).
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("out3", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-
-  fs_.Tick();
-
-  fs_.Create("in", "");
-
-  // The build log entry should not, however, prevent us from rebuilding out2
-  // if out1 changes.
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("out3", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ(2u, command_runner_.commands_ran_.size());
-}
-
-TEST_F(BuildWithLogTest, RestatMissingFile) {
-  // If a restat rule doesn't create its output, and the output didn't
-  // exist before the rule was run, consider that behavior equivalent
-  // to a rule that doesn't modify its existent output file.
-
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule true\n"
-"  command = true\n"
-"  restat = 1\n"
-"rule cc\n"
-"  command = cc\n"
-"build out1: true in\n"
-"build out2: cc out1\n"));
-
-  fs_.Create("in", "");
-  fs_.Create("out2", "");
-
-  // Do a pre-build so that there's commands in the log for the outputs,
-  // otherwise, the lack of an entry in the build log will cause out2 to rebuild
-  // regardless of restat.
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-
-  fs_.Tick();
-  fs_.Create("in", "");
-  fs_.Create("out2", "");
-
-  // Run a build, expect only the first command to run.
-  // It doesn't touch its output (due to being the "true" command), so
-  // we shouldn't run the dependent build.
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-}
-
-TEST_F(BuildWithLogTest, RestatSingleDependentOutputDirty) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-    "rule true\n"
-    "  command = true\n"
-    "  restat = 1\n"
-    "rule touch\n"
-    "  command = touch\n"
-    "build out1: true in\n"
-    "build out2 out3: touch out1\n"
-    "build out4: touch out2\n"
-    ));
-
-  // Create the necessary files
-  fs_.Create("in", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out4", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-
-  fs_.Tick();
-  fs_.Create("in", "");
-  fs_.RemoveFile("out3");
-
-  // Since "in" is missing, out1 will be built. Since "out3" is missing,
-  // out2 and out3 will be built even though "in" is not touched when built.
-  // Then, since out2 is rebuilt, out4 should be rebuilt -- the restat on the
-  // "true" rule should not lead to the "touch" edge writing out2 and out3 being
-  // cleard.
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("out4", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-}
-
-// Test scenario, in which an input file is removed, but output isn't changed
-// https://github.com/ninja-build/ninja/issues/295
-TEST_F(BuildWithLogTest, RestatMissingInput) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-    "rule true\n"
-    "  command = true\n"
-    "  depfile = $out.d\n"
-    "  restat = 1\n"
-    "rule cc\n"
-    "  command = cc\n"
-    "build out1: true in\n"
-    "build out2: cc out1\n"));
-
-  // Create all necessary files
-  fs_.Create("in", "");
-
-  // The implicit dependencies and the depfile itself
-  // are newer than the output
-  TimeStamp restat_mtime = fs_.Tick();
-  fs_.Create("out1.d", "out1: will.be.deleted restat.file\n");
-  fs_.Create("will.be.deleted", "");
-  fs_.Create("restat.file", "");
-
-  // Run the build, out1 and out2 get built
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ(2u, command_runner_.commands_ran_.size());
-
-  // See that an entry in the logfile is created, capturing
-  // the right mtime
-  BuildLog::LogEntry* log_entry = build_log_.LookupByOutput("out1");
-  ASSERT_TRUE(NULL != log_entry);
-  ASSERT_EQ(restat_mtime, log_entry->mtime);
-
-  // Now remove a file, referenced from depfile, so that target becomes
-  // dirty, but the output does not change
-  fs_.RemoveFile("will.be.deleted");
-
-  // Trigger the build again - only out1 gets built
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-
-  // Check that the logfile entry remains correctly set
-  log_entry = build_log_.LookupByOutput("out1");
-  ASSERT_TRUE(NULL != log_entry);
-  ASSERT_EQ(restat_mtime, log_entry->mtime);
-}
-
-TEST_F(BuildWithLogTest, RestatInputChangesDueToRule) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule generate-depfile\n"
-"  command = sleep 1 ; touch $touch_dependency; touch $out ; echo \"$out: $test_dependency\" > $depfile\n"
-"build out1: generate-depfile || cat1\n"
-"  test_dependency = in2\n"
-"  touch_dependency = 1\n"
-"  restat = 1\n"
-"  depfile = out.d\n"));
-
-  // Perform the first build. out1 is a restat rule, so its recorded mtime in the build
-  // log should be the time the command completes, not the time the command started. One
-  // of out1's discovered dependencies will have a newer mtime than when out1 started
-  // running, due to its command touching the dependency itself.
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  EXPECT_EQ(2u, command_runner_.commands_ran_.size());
-  EXPECT_EQ(2u, builder_.plan_.command_edge_count());
-  BuildLog::LogEntry* log_entry = build_log_.LookupByOutput("out1");
-  ASSERT_TRUE(NULL != log_entry);
-  ASSERT_EQ(2u, log_entry->mtime);
-
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  builder_.Cleanup();
-  builder_.plan_.Reset();
-
-  fs_.Tick();
-  fs_.Create("in1", "");
-
-  // Touching a dependency of an order-only dependency of out1 should not cause out1 to
-  // rebuild. If out1 were not a restat rule, then it would rebuild here because its
-  // recorded mtime would have been an earlier mtime than its most recent input's (in2)
-  // mtime
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(!state_.GetNode("out1", 0)->dirty());
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  EXPECT_EQ(1u, command_runner_.commands_ran_.size());
-  EXPECT_EQ(1u, builder_.plan_.command_edge_count());
-}
-
-TEST_F(BuildWithLogTest, GeneratedPlainDepfileMtime) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule generate-depfile\n"
-"  command = touch $out ; echo \"$out: $test_dependency\" > $depfile\n"
-"build out: generate-depfile\n"
-"  test_dependency = inimp\n"
-"  depfile = out.d\n"));
-  fs_.Create("inimp", "");
-  fs_.Tick();
-
-  string err;
-
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_FALSE(builder_.AlreadyUpToDate());
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  builder_.Cleanup();
-  builder_.plan_.Reset();
-
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-}
-
-struct BuildDryRun : public BuildWithLogTest {
-  BuildDryRun() {
-    config_.dry_run = true;
-  }
-};
-
-TEST_F(BuildDryRun, AllCommandsShown) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule true\n"
-"  command = true\n"
-"  restat = 1\n"
-"rule cc\n"
-"  command = cc\n"
-"  restat = 1\n"
-"build out1: cc in\n"
-"build out2: true out1\n"
-"build out3: cat out2\n"));
-
-  fs_.Create("out1", "");
-  fs_.Create("out2", "");
-  fs_.Create("out3", "");
-
-  fs_.Tick();
-
-  fs_.Create("in", "");
-
-  // "cc" touches out1, so we should build out2.  But because "true" does not
-  // touch out2, we should cancel the build of out3.
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out3", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-}
-
-// Test that RSP files are created when & where appropriate and deleted after
-// successful execution.
-TEST_F(BuildTest, RspFileSuccess)
-{
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-    "rule cat_rsp\n"
-    "  command = cat $rspfile > $out\n"
-    "  rspfile = $rspfile\n"
-    "  rspfile_content = $long_command\n"
-    "rule cat_rsp_out\n"
-    "  command = cat $rspfile > $out\n"
-    "  rspfile = $out.rsp\n"
-    "  rspfile_content = $long_command\n"
-    "build out1: cat in\n"
-    "build out2: cat_rsp in\n"
-    "  rspfile = out 2.rsp\n"
-    "  long_command = Some very long command\n"
-    "build out$ 3: cat_rsp_out in\n"
-    "  long_command = Some very long command\n"));
-
-  fs_.Create("out1", "");
-  fs_.Create("out2", "");
-  fs_.Create("out 3", "");
-
-  fs_.Tick();
-
-  fs_.Create("in", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.AddTarget("out 3", &err));
-  ASSERT_EQ("", err);
-
-  size_t files_created = fs_.files_created_.size();
-  size_t files_removed = fs_.files_removed_.size();
-
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-
-  // The RSP files and temp file to acquire output mtimes were created
-  ASSERT_EQ(files_created + 3, fs_.files_created_.size());
-  ASSERT_EQ(1u, fs_.files_created_.count("out 2.rsp"));
-  ASSERT_EQ(1u, fs_.files_created_.count("out 3.rsp"));
-  ASSERT_EQ(1u, fs_.files_created_.count(".ninja_lock"));
-
-  // The RSP files were removed
-  ASSERT_EQ(files_removed + 2, fs_.files_removed_.size());
-  ASSERT_EQ(1u, fs_.files_removed_.count("out 2.rsp"));
-  ASSERT_EQ(1u, fs_.files_removed_.count("out 3.rsp"));
-}
-
-// Test that RSP file is created but not removed for commands, which fail
-TEST_F(BuildTest, RspFileFailure) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-    "rule fail\n"
-    "  command = fail\n"
-    "  rspfile = $rspfile\n"
-    "  rspfile_content = $long_command\n"
-    "build out: fail in\n"
-    "  rspfile = out.rsp\n"
-    "  long_command = Another very long command\n"));
-
-  fs_.Create("out", "");
-  fs_.Tick();
-  fs_.Create("in", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-
-  size_t files_created = fs_.files_created_.size();
-  size_t files_removed = fs_.files_removed_.size();
-
-  EXPECT_FALSE(builder_.Build(&err));
-  ASSERT_EQ("subcommand failed", err);
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-
-  // The RSP file and temp file to acquire output mtimes were created
-  ASSERT_EQ(files_created + 2, fs_.files_created_.size());
-  ASSERT_EQ(1u, fs_.files_created_.count("out.rsp"));
-  ASSERT_EQ(1u, fs_.files_created_.count(".ninja_lock"));
-
-  // The RSP file was NOT removed
-  ASSERT_EQ(files_removed, fs_.files_removed_.size());
-  ASSERT_EQ(0u, fs_.files_removed_.count("out.rsp"));
-
-  // The RSP file contains what it should
-  ASSERT_EQ("Another very long command", fs_.files_["out.rsp"].contents);
-}
-
-// Test that contents of the RSP file behaves like a regular part of
-// command line, i.e. triggers a rebuild if changed
-TEST_F(BuildWithLogTest, RspFileCmdLineChange) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-    "rule cat_rsp\n"
-    "  command = cat $rspfile > $out\n"
-    "  rspfile = $rspfile\n"
-    "  rspfile_content = $long_command\n"
-    "build out: cat_rsp in\n"
-    "  rspfile = out.rsp\n"
-    "  long_command = Original very long command\n"));
-
-  fs_.Create("out", "");
-  fs_.Tick();
-  fs_.Create("in", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-
-  // 1. Build for the 1st time (-> populate log)
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-
-  // 2. Build again (no change)
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-  ASSERT_TRUE(builder_.AlreadyUpToDate());
-
-  // 3. Alter the entry in the logfile
-  // (to simulate a change in the command line between 2 builds)
-  BuildLog::LogEntry* log_entry = build_log_.LookupByOutput("out");
-  ASSERT_TRUE(NULL != log_entry);
-  ASSERT_NO_FATAL_FAILURE(AssertHash(
-        "cat out.rsp > out;rspfile=Original very long command",
-        log_entry->command_hash));
-  log_entry->command_hash++;  // Change the command hash to something else.
-  // Now expect the target to be rebuilt
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ(1u, command_runner_.commands_ran_.size());
-}
-
-TEST_F(BuildTest, InterruptCleanup) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule interrupt\n"
-"  command = interrupt\n"
-"rule touch-interrupt\n"
-"  command = touch-interrupt\n"
-"build out1: interrupt in1\n"
-"build out2: touch-interrupt in2\n"));
-
-  fs_.Create("out1", "");
-  fs_.Create("out2", "");
-  fs_.Tick();
-  fs_.Create("in1", "");
-  fs_.Create("in2", "");
-
-  // An untouched output of an interrupted command should be retained.
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  EXPECT_EQ("", err);
-  EXPECT_FALSE(builder_.Build(&err));
-  EXPECT_EQ("interrupted by user", err);
-  builder_.Cleanup();
-  EXPECT_GT(fs_.Stat("out1", &err), 0);
-  err = "";
-
-  // A touched output of an interrupted command should be deleted.
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  EXPECT_EQ("", err);
-  EXPECT_FALSE(builder_.Build(&err));
-  EXPECT_EQ("interrupted by user", err);
-  builder_.Cleanup();
-  EXPECT_EQ(0, fs_.Stat("out2", &err));
-}
-
-TEST_F(BuildTest, StatFailureAbortsBuild) {
-  const string kTooLongToStat(400, 'i');
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-("build " + kTooLongToStat + ": cat in\n").c_str()));
-  fs_.Create("in", "");
-
-  // This simulates a stat failure:
-  fs_.files_[kTooLongToStat].mtime = -1;
-  fs_.files_[kTooLongToStat].stat_error = "stat failed";
-
-  string err;
-  EXPECT_FALSE(builder_.AddTarget(kTooLongToStat, &err));
-  EXPECT_EQ("stat failed", err);
-}
-
-TEST_F(BuildTest, PhonyWithNoInputs) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build nonexistent: phony\n"
-"build out1: cat || nonexistent\n"
-"build out2: cat nonexistent\n"));
-  fs_.Create("out1", "");
-  fs_.Create("out2", "");
-
-  // out1 should be up to date even though its input is dirty, because its
-  // order-only dependency has nothing to do.
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-
-  // out2 should still be out of date though, because its input is dirty.
-  err.clear();
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-}
-
-TEST_F(BuildTest, DepsGccWithEmptyDepfileErrorsOut) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cc\n"
-"  command = cc\n"
-"  deps = gcc\n"
-"build out: cc\n"));
-  Dirty("out");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-  EXPECT_FALSE(builder_.AlreadyUpToDate());
-
-  EXPECT_FALSE(builder_.Build(&err));
-  ASSERT_EQ("subcommand failed", err);
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-}
-
-TEST_F(BuildTest, StatusFormatElapsed) {
-  status_.BuildStarted();
-  // Before any task is done, the elapsed time must be zero.
-  EXPECT_EQ("[%/e0.000]",
-            status_.FormatProgressStatus("[%%/e%e]", 0));
-}
-
-TEST_F(BuildTest, StatusFormatReplacePlaceholder) {
-  EXPECT_EQ("[%/s0/t0/r0/u0/f0]",
-            status_.FormatProgressStatus("[%%/s%s/t%t/r%r/u%u/f%f]", 0));
-}
-
-TEST_F(BuildTest, FailedDepsParse) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build bad_deps.o: cat in1\n"
-"  deps = gcc\n"
-"  depfile = in1.d\n"));
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("bad_deps.o", &err));
-  ASSERT_EQ("", err);
-
-  // These deps will fail to parse, as they should only have one
-  // path to the left of the colon.
-  fs_.Create("in1.d", "AAA BBB");
-
-  EXPECT_FALSE(builder_.Build(&err));
-  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
-/// each build.
-struct BuildWithDepsLogTest : public BuildTest {
-  BuildWithDepsLogTest() {}
-
-  virtual void SetUp() {
-    BuildTest::SetUp();
-
-    temp_dir_.CreateAndEnter("BuildWithDepsLogTest");
-  }
-
-  virtual void TearDown() {
-    temp_dir_.Cleanup();
-  }
-
-  ScopedTempDir temp_dir_;
-
-  /// Shadow parent class builder_ so we don't accidentally use it.
-  void* builder_;
-};
-
-/// Run a straightforward build where the deps log is used.
-TEST_F(BuildWithDepsLogTest, Straightforward) {
-  string err;
-  // Note: in1 was created by the superclass SetUp().
-  const char* manifest =
-      "build out: cat in1\n"
-      "  deps = gcc\n"
-      "  depfile = in1.d\n";
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    // Run the build once, everything should be ok.
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-    ASSERT_EQ("", err);
-
-    Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    fs_.Create("in1.d", "out: in2");
-    EXPECT_TRUE(builder.Build(&err));
-    EXPECT_EQ("", err);
-
-    // The deps file should have been removed.
-    EXPECT_EQ(0, fs_.Stat("in1.d", &err));
-    // Recreate it for the next step.
-    fs_.Create("in1.d", "out: in2");
-    deps_log.Close();
-    builder.command_runner_.release();
-  }
-
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    // Touch the file only mentioned in the deps.
-    fs_.Tick();
-    fs_.Create("in2", "");
-
-    // Run the build again.
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-
-    Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    command_runner_.commands_ran_.clear();
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    EXPECT_TRUE(builder.Build(&err));
-    EXPECT_EQ("", err);
-
-    // We should have rebuilt the output due to in2 being
-    // out of date.
-    EXPECT_EQ(1u, command_runner_.commands_ran_.size());
-
-    builder.command_runner_.release();
-  }
-}
-
-/// Verify that obsolete dependency info causes a rebuild.
-/// 1) Run a successful build where everything has time t, record deps.
-/// 2) Move input/output to time t+1 -- despite files in alignment,
-///    should still need to rebuild due to deps at older time.
-TEST_F(BuildWithDepsLogTest, ObsoleteDeps) {
-  string err;
-  // Note: in1 was created by the superclass SetUp().
-  const char* manifest =
-      "build out: cat in1\n"
-      "  deps = gcc\n"
-      "  depfile = in1.d\n";
-  {
-    // Run an ordinary build that gathers dependencies.
-    fs_.Create("in1", "");
-    fs_.Create("in1.d", "out: ");
-
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    // Run the build once, everything should be ok.
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-    ASSERT_EQ("", err);
-
-    Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    EXPECT_TRUE(builder.Build(&err));
-    EXPECT_EQ("", err);
-
-    deps_log.Close();
-    builder.command_runner_.release();
-  }
-
-  // Push all files one tick forward so that only the deps are out
-  // of date.
-  fs_.Tick();
-  fs_.Create("in1", "");
-  fs_.Create("out", "");
-
-  // The deps file should have been removed, so no need to timestamp it.
-  EXPECT_EQ(0, fs_.Stat("in1.d", &err));
-
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-
-    Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    command_runner_.commands_ran_.clear();
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-
-    // Recreate the deps file here because the build expects them to exist.
-    fs_.Create("in1.d", "out: ");
-
-    EXPECT_TRUE(builder.Build(&err));
-    EXPECT_EQ("", err);
-
-    // We should have rebuilt the output due to the deps being
-    // out of date.
-    EXPECT_EQ(1u, command_runner_.commands_ran_.size());
-
-    builder.command_runner_.release();
-  }
-}
-
-TEST_F(BuildWithDepsLogTest, DepsIgnoredInDryRun) {
-  const char* manifest =
-      "build out: cat in1\n"
-      "  deps = gcc\n"
-      "  depfile = in1.d\n";
-
-  fs_.Create("out", "");
-  fs_.Tick();
-  fs_.Create("in1", "");
-
-  State state;
-  ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-  // The deps log is NULL in dry runs.
-  config_.dry_run = true;
-  Builder builder(&state, config_, NULL, NULL, &fs_, &status_, 0);
-  builder.command_runner_.reset(&command_runner_);
-  command_runner_.commands_ran_.clear();
-
-  string err;
-  EXPECT_TRUE(builder.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder.Build(&err));
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-
-  builder.command_runner_.release();
-}
-
-TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceCondition) {
-  string err;
-  const char* manifest =
-      "rule long-cc\n"
-      "  command = long-cc\n"
-      "build out: long-cc in1\n"
-      "  test_dependency = in1\n";
-
-  State state;
-  ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-  BuildLog build_log;
-  ASSERT_TRUE(build_log.Load("build_log", &err));
-  ASSERT_TRUE(build_log.OpenForWrite("build_log", *this, &err));
-
-  DepsLog deps_log;
-  ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
-  ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-
-  BuildLog::LogEntry* log_entry = NULL;
-  {
-    Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    command_runner_.commands_ran_.clear();
-
-    // Run the build, out gets built, dep file is created
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    EXPECT_TRUE(builder.Build(&err));
-    ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-
-    // See that an entry in the logfile is created. the input_mtime is 1 since that was
-    // the mtime of in1 when the command was started
-    log_entry = build_log.LookupByOutput("out");
-    ASSERT_TRUE(NULL != log_entry);
-    ASSERT_EQ(1u, log_entry->mtime);
-
-    builder.command_runner_.release();
-  }
-
-  {
-    Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    command_runner_.commands_ran_.clear();
-
-    // Trigger the build again - "out" should rebuild despite having a newer mtime than
-    // "in1", since "in1" was touched during the build of out (simulated by changing its
-    // mtime in the the test builder's WaitForCommand() which runs before FinishCommand()
-    command_runner_.commands_ran_.clear();
-    state.Reset();
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    EXPECT_TRUE(builder.Build(&err));
-    ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-
-    // Check that the logfile entry is still correct
-    log_entry = build_log.LookupByOutput("out");
-    ASSERT_TRUE(NULL != log_entry);
-    ASSERT_TRUE(fs_.files_["in1"].mtime < log_entry->mtime);
-    builder.command_runner_.release();
-  }
-
-  {
-    Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    command_runner_.commands_ran_.clear();
-
-    // And a subsequent run should not have any work to do
-    command_runner_.commands_ran_.clear();
-    state.Reset();
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    EXPECT_TRUE(builder.AlreadyUpToDate());
-
-    builder.command_runner_.release();
-  }
-}
-
-TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceConditionWithDepFile) {
-  string err;
-  const char* manifest =
-      "rule long-cc\n"
-      "  command = long-cc\n"
-      "build out: long-cc\n"
-      "  deps = gcc\n"
-      "  depfile = out.d\n"
-      "  test_dependency = header.h\n";
-
-  fs_.Create("header.h", "");
-
-  State state;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-  BuildLog build_log;
-  ASSERT_TRUE(build_log.Load("build_log", &err));
-  ASSERT_TRUE(build_log.OpenForWrite("build_log", *this, &err));
-
-  DepsLog deps_log;
-  ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
-  ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-
-  {
-    Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-
-    // Run the build, out gets built, dep file is created
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    EXPECT_TRUE(builder.Build(&err));
-    ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-
-    // See that an entry in the logfile is created. the mtime is 1 due to the command
-    // starting when the file system's mtime was 1.
-    BuildLog::LogEntry* log_entry = build_log.LookupByOutput("out");
-    ASSERT_TRUE(NULL != log_entry);
-    ASSERT_EQ(1u, log_entry->mtime);
-
-    builder.command_runner_.release();
-  }
-
-  {
-    // Trigger the build again - "out" will rebuild since its newest input mtime (header.h)
-    // is newer than the recorded mtime of out in the build log
-    Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    command_runner_.commands_ran_.clear();
-
-    state.Reset();
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    EXPECT_TRUE(builder.Build(&err));
-    ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-
-    builder.command_runner_.release();
-  }
-
-  {
-    // Trigger the build again - "out" won't rebuild since the file wasn't updated during
-    // the previous build
-    Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    command_runner_.commands_ran_.clear();
-
-    state.Reset();
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    ASSERT_TRUE(builder.AlreadyUpToDate());
-
-    builder.command_runner_.release();
-  }
-
-  // touch the header to trigger a rebuild
-  fs_.Create("header.h", "");
-  ASSERT_EQ(fs_.now_, 7);
-
-  {
-    // Rebuild. This time, long-cc will cause header.h to be updated while the build is
-    // in progress
-    Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    command_runner_.commands_ran_.clear();
-
-    state.Reset();
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    EXPECT_TRUE(builder.Build(&err));
-    ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-
-    builder.command_runner_.release();
-  }
-
-  {
-    // Rebuild. Because header.h is now in the deplog for out, it should be detectable as
-    // a change-while-in-progress and should cause a rebuild of out.
-    Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    command_runner_.commands_ran_.clear();
-
-    state.Reset();
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    EXPECT_TRUE(builder.Build(&err));
-    ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-
-    builder.command_runner_.release();
-  }
-
-  {
-    // This time, the header.h file was not updated during the build, so the target should
-    // not be considered dirty.
-    Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    command_runner_.commands_ran_.clear();
-
-    state.Reset();
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    EXPECT_TRUE(builder.AlreadyUpToDate());
-
-    builder.command_runner_.release();
-  }
-}
-
-/// Check that a restat rule generating a header cancels compilations correctly.
-TEST_F(BuildTest, RestatDepfileDependency) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule true\n"
-"  command = true\n"  // Would be "write if out-of-date" in reality.
-"  restat = 1\n"
-"build header.h: true header.in\n"
-"build out: cat in1\n"
-"  depfile = in1.d\n"));
-
-  fs_.Create("header.h", "");
-  fs_.Create("in1.d", "out: header.h");
-  fs_.Tick();
-  fs_.Create("header.in", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-}
-
-/// Check that a restat rule generating a header cancels compilations correctly,
-/// depslog case.
-TEST_F(BuildWithDepsLogTest, RestatDepfileDependencyDepsLog) {
-  string err;
-  // Note: in1 was created by the superclass SetUp().
-  const char* manifest =
-      "rule true\n"
-      "  command = true\n"  // Would be "write if out-of-date" in reality.
-      "  restat = 1\n"
-      "build header.h: true header.in\n"
-      "build out: cat in1\n"
-      "  deps = gcc\n"
-      "  depfile = in1.d\n";
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    // Run the build once, everything should be ok.
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-    ASSERT_EQ("", err);
-
-    Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    fs_.Create("in1.d", "out: header.h");
-    EXPECT_TRUE(builder.Build(&err));
-    EXPECT_EQ("", err);
-
-    deps_log.Close();
-    builder.command_runner_.release();
-  }
-
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    // Touch the input of the restat rule.
-    fs_.Tick();
-    fs_.Create("header.in", "");
-
-    // Run the build again.
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-
-    Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    command_runner_.commands_ran_.clear();
-    EXPECT_TRUE(builder.AddTarget("out", &err));
-    ASSERT_EQ("", err);
-    EXPECT_TRUE(builder.Build(&err));
-    EXPECT_EQ("", err);
-
-    // Rule "true" should have run again, but the build of "out" should have
-    // been cancelled due to restat propagating through the depfile header.
-    EXPECT_EQ(1u, command_runner_.commands_ran_.size());
-
-    builder.command_runner_.release();
-  }
-}
-
-TEST_F(BuildWithDepsLogTest, DepFileOKDepsLog) {
-  string err;
-  const char* manifest =
-      "rule cc\n  command = cc $in\n  depfile = $out.d\n  deps = gcc\n"
-      "build fo$ o.o: cc foo.c\n";
-
-  fs_.Create("foo.c", "");
-
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    // Run the build once, everything should be ok.
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-    ASSERT_EQ("", err);
-
-    Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    EXPECT_TRUE(builder.AddTarget("fo o.o", &err));
-    ASSERT_EQ("", err);
-    fs_.Create("fo o.o.d", "fo\\ o.o: blah.h bar.h\n");
-    EXPECT_TRUE(builder.Build(&err));
-    EXPECT_EQ("", err);
-
-    deps_log.Close();
-    builder.command_runner_.release();
-  }
-
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-    ASSERT_EQ("", err);
-
-    Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-
-    Edge* edge = state.edges_.back();
-
-    state.GetNode("bar.h", 0)->MarkDirty();  // Mark bar.h as missing.
-    EXPECT_TRUE(builder.AddTarget("fo o.o", &err));
-    ASSERT_EQ("", err);
-
-    // Expect one new edge generating fo o.o, loading the depfile should
-    // note generate new edges.
-    ASSERT_EQ(1u, state.edges_.size());
-    // Expect our edge to now have three inputs: foo.c and two headers.
-    ASSERT_EQ(3u, edge->inputs_.size());
-
-    // Expect the command line we generate to only use the original input.
-    ASSERT_EQ("cc foo.c", edge->EvaluateCommand());
-
-    deps_log.Close();
-    builder.command_runner_.release();
-  }
-}
-
-TEST_F(BuildWithDepsLogTest, DiscoveredDepDuringBuildChanged) {
-  string err;
-  const char* manifest =
-    "rule touch-out-implicit-dep\n"
-    "  command = touch $out ; sleep 1 ; touch $test_dependency\n"
-    "rule generate-depfile\n"
-    "  command = touch $out ; echo \"$out: $test_dependency\" > $depfile\n"
-    "build out1: touch-out-implicit-dep in1\n"
-    "  test_dependency = inimp\n"
-    "build out2: generate-depfile in1 || out1\n"
-    "  test_dependency = inimp\n"
-    "  depfile = out2.d\n"
-    "  deps = gcc\n";
-
-  fs_.Create("in1", "");
-  fs_.Tick();
-
-  BuildLog build_log;
-
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-    ASSERT_EQ("", err);
-
-    Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    EXPECT_TRUE(builder.AddTarget("out2", &err));
-    EXPECT_FALSE(builder.AlreadyUpToDate());
-
-    EXPECT_TRUE(builder.Build(&err));
-    EXPECT_TRUE(builder.AlreadyUpToDate());
-
-    deps_log.Close();
-    builder.command_runner_.release();
-  }
-
-  fs_.Tick();
-  fs_.Create("in1", "");
-
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-    ASSERT_EQ("", err);
-
-    Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    EXPECT_TRUE(builder.AddTarget("out2", &err));
-    EXPECT_FALSE(builder.AlreadyUpToDate());
-
-    EXPECT_TRUE(builder.Build(&err));
-    EXPECT_TRUE(builder.AlreadyUpToDate());
-
-    deps_log.Close();
-    builder.command_runner_.release();
-  }
-
-  fs_.Tick();
-
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-    ASSERT_EQ("", err);
-
-    Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    EXPECT_TRUE(builder.AddTarget("out2", &err));
-    EXPECT_TRUE(builder.AlreadyUpToDate());
-
-    deps_log.Close();
-    builder.command_runner_.release();
-  }
-}
-
-#ifdef _WIN32
-TEST_F(BuildWithDepsLogTest, DepFileDepsLogCanonicalize) {
-  string err;
-  const char* manifest =
-      "rule cc\n  command = cc $in\n  depfile = $out.d\n  deps = gcc\n"
-      "build a/b\\c\\d/e/fo$ o.o: cc x\\y/z\\foo.c\n";
-
-  fs_.Create("x/y/z/foo.c", "");
-
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    // Run the build once, everything should be ok.
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-    ASSERT_EQ("", err);
-
-    Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-    EXPECT_TRUE(builder.AddTarget("a/b/c/d/e/fo o.o", &err));
-    ASSERT_EQ("", err);
-    // Note, different slashes from manifest.
-    fs_.Create("a/b\\c\\d/e/fo o.o.d",
-               "a\\b\\c\\d\\e\\fo\\ o.o: blah.h bar.h\n");
-    EXPECT_TRUE(builder.Build(&err));
-    EXPECT_EQ("", err);
-
-    deps_log.Close();
-    builder.command_runner_.release();
-  }
-
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-    ASSERT_EQ("", err);
-
-    Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-
-    state.GetNode("bar.h", 0)->MarkDirty();  // Mark bar.h as missing.
-    EXPECT_TRUE(builder.AddTarget("a/b/c/d/e/fo o.o", &err));
-    ASSERT_EQ("", err);
-
-    // Expect one new edge generating fo o.o.
-    ASSERT_EQ(1u, state.edges_.size());
-    // Expect our edge to now have three inputs: foo.c and two headers.
-    Edge* edge = state.edges_.back();
-    ASSERT_EQ(3u, edge->inputs_.size());
-
-    // Expect the command line we generate to only use the original input.
-    // Note, slashes from manifest, not .d.
-    ASSERT_EQ("cc x\\y/z\\foo.c", edge->EvaluateCommand());
-
-    deps_log.Close();
-    builder.command_runner_.release();
-  }
-}
-#endif
-
-/// Check that a restat rule doesn't clear an edge if the depfile is missing.
-/// Follows from: https://github.com/ninja-build/ninja/issues/603
-TEST_F(BuildTest, RestatMissingDepfile) {
-const char* manifest =
-"rule true\n"
-"  command = true\n"  // Would be "write if out-of-date" in reality.
-"  restat = 1\n"
-"build header.h: true header.in\n"
-"build out: cat header.h\n"
-"  depfile = out.d\n";
-
-  fs_.Create("header.h", "");
-  fs_.Tick();
-  fs_.Create("out", "");
-  fs_.Create("header.in", "");
-
-  // Normally, only 'header.h' would be rebuilt, as
-  // its rule doesn't touch the output and has 'restat=1' set.
-  // But we are also missing the depfile for 'out',
-  // which should force its command to run anyway!
-  RebuildTarget("out", manifest);
-  ASSERT_EQ(2u, command_runner_.commands_ran_.size());
-}
-
-/// Check that a restat rule doesn't clear an edge if the deps are missing.
-/// https://github.com/ninja-build/ninja/issues/603
-TEST_F(BuildWithDepsLogTest, RestatMissingDepfileDepslog) {
-  string err;
-  const char* manifest =
-"rule true\n"
-"  command = true\n"  // Would be "write if out-of-date" in reality.
-"  restat = 1\n"
-"build header.h: true header.in\n"
-"build out: cat header.h\n"
-"  deps = gcc\n"
-"  depfile = out.d\n";
-
-  // Build once to populate ninja deps logs from out.d
-  fs_.Create("header.in", "");
-  fs_.Create("out.d", "out: header.h");
-  fs_.Create("header.h", "");
-
-  RebuildTarget("out", manifest, "build_log", "ninja_deps");
-  ASSERT_EQ(2u, command_runner_.commands_ran_.size());
-
-  // Sanity: this rebuild should be NOOP
-  RebuildTarget("out", manifest, "build_log", "ninja_deps");
-  ASSERT_EQ(0u, command_runner_.commands_ran_.size());
-
-  // Touch 'header.in', blank dependencies log (create a different one).
-  // Building header.h triggers 'restat' outputs cleanup.
-  // Validate that out is rebuilt netherless, as deps are missing.
-  fs_.Tick();
-  fs_.Create("header.in", "");
-
-  // (switch to a new blank deps_log "ninja_deps2")
-  RebuildTarget("out", manifest, "build_log", "ninja_deps2");
-  ASSERT_EQ(2u, command_runner_.commands_ran_.size());
-
-  // Sanity: this build should be NOOP
-  RebuildTarget("out", manifest, "build_log", "ninja_deps2");
-  ASSERT_EQ(0u, command_runner_.commands_ran_.size());
-
-  // Check that invalidating deps by target timestamp also works here
-  // Repeat the test but touch target instead of blanking the log.
-  fs_.Tick();
-  fs_.Create("header.in", "");
-  fs_.Create("out", "");
-  RebuildTarget("out", manifest, "build_log", "ninja_deps2");
-  ASSERT_EQ(2u, command_runner_.commands_ran_.size());
-
-  // And this build should be NOOP again
-  RebuildTarget("out", manifest, "build_log", "ninja_deps2");
-  ASSERT_EQ(0u, command_runner_.commands_ran_.size());
-}
-
-TEST_F(BuildTest, WrongOutputInDepfileCausesRebuild) {
-  string err;
-  const char* manifest =
-"rule cc\n"
-"  command = cc $in\n"
-"  depfile = $out.d\n"
-"build foo.o: cc foo.c\n";
-
-  fs_.Create("foo.c", "");
-  fs_.Create("foo.o", "");
-  fs_.Create("header.h", "");
-  fs_.Create("foo.o.d", "bar.o.d: header.h\n");
-
-  RebuildTarget("foo.o", manifest, "build_log", "ninja_deps");
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-}
-
-TEST_F(BuildTest, Console) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule console\n"
-"  command = console\n"
-"  pool = console\n"
-"build cons: console in.txt\n"));
-
-  fs_.Create("in.txt", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("cons", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-}
-
-TEST_F(BuildTest, DyndepMissingAndNoRule) {
-  // Verify that we can diagnose when a dyndep file is missing and
-  // has no rule to build it.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"build out: touch || dd\n"
-"  dyndep = dd\n"
-));
-
-  string err;
-  EXPECT_FALSE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("loading 'dd': No such file or directory", err);
-}
-
-TEST_F(BuildTest, DyndepReadyImplicitConnection) {
-  // Verify that a dyndep file can be loaded immediately to discover
-  // that one edge has an implicit output that is also an implicit
-  // input of another edge.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out $out.imp\n"
-"build tmp: touch || dd\n"
-"  dyndep = dd\n"
-"build out: touch || dd\n"
-"  dyndep = dd\n"
-));
-  fs_.Create("dd",
-"ninja_dyndep_version = 1\n"
-"build out | out.imp: dyndep | tmp.imp\n"
-"build tmp | tmp.imp: dyndep\n"
-);
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(2u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("touch tmp tmp.imp", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("touch out out.imp", command_runner_.commands_ran_[1]);
-}
-
-TEST_F(BuildTest, DyndepReadySyntaxError) {
-  // Verify that a dyndep file can be loaded immediately to discover
-  // and reject a syntax error in it.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"build out: touch || dd\n"
-"  dyndep = dd\n"
-));
-  fs_.Create("dd",
-"build out: dyndep\n"
-);
-
-  string err;
-  EXPECT_FALSE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("dd:1: expected 'ninja_dyndep_version = ...'\n", err);
-}
-
-TEST_F(BuildTest, DyndepReadyCircular) {
-  // Verify that a dyndep file can be loaded immediately to discover
-  // and reject a circular dependency.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build out: r in || dd\n"
-"  dyndep = dd\n"
-"build in: r circ\n"
-  ));
-  fs_.Create("dd",
-"ninja_dyndep_version = 1\n"
-"build out | circ: dyndep\n"
-  );
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_FALSE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("dependency cycle: circ -> in -> circ", err);
-}
-
-TEST_F(BuildTest, DyndepBuild) {
-  // Verify that a dyndep file can be built and loaded to discover nothing.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build out: touch || dd\n"
-"  dyndep = dd\n"
-));
-  fs_.Create("dd-in",
-"ninja_dyndep_version = 1\n"
-"build out: dyndep\n"
-);
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-
-  size_t files_created = fs_.files_created_.size();
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-
-  ASSERT_EQ(2u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd-in dd", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("touch out", command_runner_.commands_ran_[1]);
-  ASSERT_EQ(2u, fs_.files_read_.size());
-  EXPECT_EQ("dd-in", fs_.files_read_[0]);
-  EXPECT_EQ("dd", fs_.files_read_[1]);
-  ASSERT_EQ(3u + files_created, fs_.files_created_.size());
-  EXPECT_EQ(1u, fs_.files_created_.count("dd"));
-  EXPECT_EQ(1u, fs_.files_created_.count("out"));
-  EXPECT_EQ(1u, fs_.files_created_.count(".ninja_lock"));
-}
-
-TEST_F(BuildTest, DyndepBuildSyntaxError) {
-  // Verify that a dyndep file can be built and loaded to discover
-  // and reject a syntax error in it.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build out: touch || dd\n"
-"  dyndep = dd\n"
-));
-  fs_.Create("dd-in",
-"build out: dyndep\n"
-);
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_FALSE(builder_.Build(&err));
-  EXPECT_EQ("dd:1: expected 'ninja_dyndep_version = ...'\n", err);
-}
-
-TEST_F(BuildTest, DyndepBuildUnrelatedOutput) {
-  // Verify that a dyndep file can have dependents that do not specify
-  // it as their dyndep binding.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build unrelated: touch || dd\n"
-"build out: touch unrelated || dd\n"
-"  dyndep = dd\n"
-  ));
-  fs_.Create("dd-in",
-"ninja_dyndep_version = 1\n"
-"build out: dyndep\n"
-);
-  fs_.Tick();
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd-in dd", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("touch unrelated", command_runner_.commands_ran_[1]);
-  EXPECT_EQ("touch out", command_runner_.commands_ran_[2]);
-}
-
-TEST_F(BuildTest, DyndepBuildDiscoverNewOutput) {
-  // Verify that a dyndep file can be built and loaded to discover
-  // a new output of an edge.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out $out.imp\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build out: touch in || dd\n"
-"  dyndep = dd\n"
-  ));
-  fs_.Create("in", "");
-  fs_.Create("dd-in",
-"ninja_dyndep_version = 1\n"
-"build out | out.imp: dyndep\n"
-);
-  fs_.Tick();
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(2u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd-in dd", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("touch out out.imp", command_runner_.commands_ran_[1]);
-}
-
-TEST_F(BuildTest, DyndepBuildDiscoverNewOutputWithMultipleRules1) {
-  // Verify that a dyndep file can be built and loaded to discover
-  // a new output of an edge that is already the output of another edge.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out $out.imp\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build out1 | out-twice.imp: touch in\n"
-"build out2: touch in || dd\n"
-"  dyndep = dd\n"
-  ));
-  fs_.Create("in", "");
-  fs_.Create("dd-in",
-"ninja_dyndep_version = 1\n"
-"build out2 | out-twice.imp: dyndep\n"
-);
-  fs_.Tick();
-  fs_.Create("out1", "");
-  fs_.Create("out2", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_FALSE(builder_.Build(&err));
-  EXPECT_EQ("multiple rules generate out-twice.imp", err);
-}
-
-TEST_F(BuildTest, DyndepBuildDiscoverNewOutputWithMultipleRules2) {
-  // Verify that a dyndep file can be built and loaded to discover
-  // a new output of an edge that is already the output of another
-  // edge also discovered by dyndep.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out $out.imp\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd1: cp dd1-in\n"
-"build out1: touch || dd1\n"
-"  dyndep = dd1\n"
-"build dd2: cp dd2-in || dd1\n" // make order predictable for test
-"build out2: touch || dd2\n"
-"  dyndep = dd2\n"
-));
-  fs_.Create("out1", "");
-  fs_.Create("out2", "");
-  fs_.Create("dd1-in",
-"ninja_dyndep_version = 1\n"
-"build out1 | out-twice.imp: dyndep\n"
-);
-  fs_.Create("dd2-in", "");
-  fs_.Create("dd2",
-"ninja_dyndep_version = 1\n"
-"build out2 | out-twice.imp: dyndep\n"
-);
-  fs_.Tick();
-  fs_.Create("out1", "");
-  fs_.Create("out2", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_FALSE(builder_.Build(&err));
-  EXPECT_EQ("multiple rules generate out-twice.imp", err);
-}
-
-TEST_F(BuildTest, DyndepBuildDiscoverNewInput) {
-  // Verify that a dyndep file can be built and loaded to discover
-  // a new input to an edge.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build in: touch\n"
-"build out: touch || dd\n"
-"  dyndep = dd\n"
-  ));
-  fs_.Create("dd-in",
-"ninja_dyndep_version = 1\n"
-"build out: dyndep | in\n"
-);
-  fs_.Tick();
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd-in dd", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("touch in", command_runner_.commands_ran_[1]);
-  EXPECT_EQ("touch out", command_runner_.commands_ran_[2]);
-}
-
-TEST_F(BuildTest, DyndepBuildDiscoverNewInputWithValidation) {
-  // Verify that a dyndep file cannot contain the |@ validation
-  // syntax.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build out: touch || dd\n"
-"  dyndep = dd\n"
-));
-  fs_.Create("dd-in",
-"ninja_dyndep_version = 1\n"
-"build out: dyndep |@ validation\n"
-);
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_FALSE(builder_.Build(&err));
-
-  string err_first_line = err.substr(0, err.find("\n"));
-  EXPECT_EQ("dd:2: expected newline, got '|@'", err_first_line);
-}
-
-TEST_F(BuildTest, DyndepBuildDiscoverNewInputWithTransitiveValidation) {
-  // Verify that a dyndep file can be built and loaded to discover
-  // a new input to an edge that has a validation edge.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build in: touch |@ validation\n"
-"build validation: touch in out\n"
-"build out: touch || dd\n"
-"  dyndep = dd\n"
-  ));
-  fs_.Create("dd-in",
-"ninja_dyndep_version = 1\n"
-"build out: dyndep | in\n"
-);
-  fs_.Tick();
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(4u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd-in dd", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("touch in", command_runner_.commands_ran_[1]);
-  EXPECT_EQ("touch out", command_runner_.commands_ran_[2]);
-  EXPECT_EQ("touch validation", command_runner_.commands_ran_[3]);
-}
-
-TEST_F(BuildTest, DyndepBuildDiscoverImplicitConnection) {
-  // Verify that a dyndep file can be built and loaded to discover
-  // that one edge has an implicit output that is also an implicit
-  // input of another edge.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out $out.imp\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build tmp: touch || dd\n"
-"  dyndep = dd\n"
-"build out: touch || dd\n"
-"  dyndep = dd\n"
-));
-  fs_.Create("dd-in",
-"ninja_dyndep_version = 1\n"
-"build out | out.imp: dyndep | tmp.imp\n"
-"build tmp | tmp.imp: dyndep\n"
-);
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd-in dd", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("touch tmp tmp.imp", command_runner_.commands_ran_[1]);
-  EXPECT_EQ("touch out out.imp", command_runner_.commands_ran_[2]);
-}
-
-TEST_F(BuildTest, DyndepBuildDiscoverOutputAndDepfileInput) {
-  // Verify that a dyndep file can be built and loaded to discover
-  // that one edge has an implicit output that is also reported by
-  // a depfile as an input of another edge.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out $out.imp\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build tmp: touch || dd\n"
-"  dyndep = dd\n"
-"build out: cp tmp\n"
-"  depfile = out.d\n"
-));
-  fs_.Create("out.d", "out: tmp.imp\n");
-  fs_.Create("dd-in",
-"ninja_dyndep_version = 1\n"
-"build tmp | tmp.imp: dyndep\n"
-);
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-
-  // Loading the depfile did not give tmp.imp a phony input edge.
-  ASSERT_FALSE(GetNode("tmp.imp")->in_edge());
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-
-  // Loading the dyndep file gave tmp.imp a real input edge.
-  ASSERT_FALSE(GetNode("tmp.imp")->in_edge()->is_phony());
-
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd-in dd", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("touch tmp tmp.imp", command_runner_.commands_ran_[1]);
-  EXPECT_EQ("cp tmp out", command_runner_.commands_ran_[2]);
-  EXPECT_EQ(1u, fs_.files_created_.count("tmp.imp"));
-  EXPECT_TRUE(builder_.AlreadyUpToDate());
-}
-
-TEST_F(BuildTest, DyndepBuildDiscoverNowWantEdge) {
-  // Verify that a dyndep file can be built and loaded to discover
-  // that an edge is actually wanted due to a missing implicit output.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out $out.imp\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build tmp: touch || dd\n"
-"  dyndep = dd\n"
-"build out: touch tmp || dd\n"
-"  dyndep = dd\n"
-));
-  fs_.Create("tmp", "");
-  fs_.Create("out", "");
-  fs_.Create("dd-in",
-"ninja_dyndep_version = 1\n"
-"build out: dyndep\n"
-"build tmp | tmp.imp: dyndep\n"
-);
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd-in dd", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("touch tmp tmp.imp", command_runner_.commands_ran_[1]);
-  EXPECT_EQ("touch out out.imp", command_runner_.commands_ran_[2]);
-}
-
-TEST_F(BuildTest, DyndepBuildDiscoverNowWantEdgeAndDependent) {
-  // Verify that a dyndep file can be built and loaded to discover
-  // that an edge and a dependent are actually wanted.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out $out.imp\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build tmp: touch || dd\n"
-"  dyndep = dd\n"
-"build out: touch tmp\n"
-));
-  fs_.Create("tmp", "");
-  fs_.Create("out", "");
-  fs_.Create("dd-in",
-"ninja_dyndep_version = 1\n"
-"build tmp | tmp.imp: dyndep\n"
-);
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd-in dd", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("touch tmp tmp.imp", command_runner_.commands_ran_[1]);
-  EXPECT_EQ("touch out out.imp", command_runner_.commands_ran_[2]);
-}
-
-TEST_F(BuildTest, DyndepBuildDiscoverCircular) {
-  // Verify that a dyndep file can be built and loaded to discover
-  // and reject a circular dependency.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build out: r in || dd\n"
-"  depfile = out.d\n"
-"  dyndep = dd\n"
-"build in: r || dd\n"
-"  dyndep = dd\n"
-  ));
-  fs_.Create("out.d", "out: inimp\n");
-  fs_.Create("dd-in",
-"ninja_dyndep_version = 1\n"
-"build out | circ: dyndep\n"
-"build in: dyndep | circ\n"
-  );
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_FALSE(builder_.Build(&err));
-  // Depending on how the pointers in Plan::ready_ work out, we could have
-  // discovered the cycle from either starting point.
-  EXPECT_TRUE(err == "dependency cycle: circ -> in -> circ" ||
-              err == "dependency cycle: in -> circ -> in");
-}
-
-TEST_F(BuildWithLogTest, DyndepBuildDiscoverRestat) {
-  // Verify that a dyndep file can be built and loaded to discover
-  // that an edge has a restat binding.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule true\n"
-"  command = true\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd: cp dd-in\n"
-"build out1: true in || dd\n"
-"  dyndep = dd\n"
-"build out2: cat out1\n"));
-
-  fs_.Create("out1", "");
-  fs_.Create("out2", "");
-  fs_.Create("dd-in",
-"ninja_dyndep_version = 1\n"
-"build out1: dyndep\n"
-"  restat = 1\n"
-);
-  fs_.Tick();
-  fs_.Create("in", "");
-
-  // Do a pre-build so that there's commands in the log for the outputs,
-  // otherwise, the lack of an entry in the build log will cause "out2" to
-  // rebuild regardless of restat.
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd-in dd", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("true", command_runner_.commands_ran_[1]);
-  EXPECT_EQ("cat out1 > out2", command_runner_.commands_ran_[2]);
-
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  fs_.Tick();
-  fs_.Create("in", "");
-
-  // We touched "in", so we should build "out1".  But because "true" does not
-  // touch "out1", we should cancel the build of "out2".
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("true", command_runner_.commands_ran_[0]);
-}
-
-TEST_F(BuildTest, DyndepBuildDiscoverScheduledEdge) {
-  // Verify that a dyndep file can be built and loaded to discover a
-  // new input that itself is an output from an edge that has already
-  // been scheduled but not finished.  We should not re-schedule it.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out $out.imp\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build out1 | out1.imp: touch\n"
-"build zdd: cp zdd-in\n"
-"  verify_active_edge = out1\n" // verify out1 is active when zdd is finished
-"build out2: cp out1 || zdd\n"
-"  dyndep = zdd\n"
-));
-  fs_.Create("zdd-in",
-"ninja_dyndep_version = 1\n"
-"build out2: dyndep | out1.imp\n"
-);
-
-  // Enable concurrent builds so that we can load the dyndep file
-  // while another edge is still active.
-  command_runner_.max_active_edges_ = 2;
-
-  // During the build "out1" and "zdd" should be built concurrently.
-  // The fake command runner will finish these in reverse order
-  // of the names of the first outputs, so "zdd" will finish first
-  // and we will load the dyndep file while the edge for "out1" is
-  // still active.  This will add a new dependency on "out1.imp",
-  // also produced by the active edge.  The builder should not
-  // re-schedule the already-active edge.
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out1", &err));
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  // Depending on how the pointers in Plan::ready_ work out, the first
-  // two commands may have run in either order.
-  EXPECT_TRUE((command_runner_.commands_ran_[0] == "touch out1 out1.imp" &&
-               command_runner_.commands_ran_[1] == "cp zdd-in zdd") ||
-              (command_runner_.commands_ran_[1] == "touch out1 out1.imp" &&
-               command_runner_.commands_ran_[0] == "cp zdd-in zdd"));
-  EXPECT_EQ("cp out1 out2", command_runner_.commands_ran_[2]);
-}
-
-TEST_F(BuildTest, DyndepTwoLevelDirect) {
-  // Verify that a clean dyndep file can depend on a dirty dyndep file
-  // and be loaded properly after the dirty one is built and loaded.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out $out.imp\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd1: cp dd1-in\n"
-"build out1 | out1.imp: touch || dd1\n"
-"  dyndep = dd1\n"
-"build dd2: cp dd2-in || dd1\n" // direct order-only dep on dd1
-"build out2: touch || dd2\n"
-"  dyndep = dd2\n"
-));
-  fs_.Create("out1.imp", "");
-  fs_.Create("out2", "");
-  fs_.Create("out2.imp", "");
-  fs_.Create("dd1-in",
-"ninja_dyndep_version = 1\n"
-"build out1: dyndep\n"
-);
-  fs_.Create("dd2-in", "");
-  fs_.Create("dd2",
-"ninja_dyndep_version = 1\n"
-"build out2 | out2.imp: dyndep | out1.imp\n"
-);
-
-  // During the build dd1 should be built and loaded.  The RecomputeDirty
-  // called as a result of loading dd1 should not cause dd2 to be loaded
-  // because the builder will never get a chance to update the build plan
-  // to account for dd2.  Instead dd2 should only be later loaded once the
-  // builder recognizes that it is now ready (as its order-only dependency
-  // on dd1 has been satisfied).  This test case verifies that each dyndep
-  // file is loaded to update the build graph independently.
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd1-in dd1", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("touch out1 out1.imp", command_runner_.commands_ran_[1]);
-  EXPECT_EQ("touch out2 out2.imp", command_runner_.commands_ran_[2]);
-}
-
-TEST_F(BuildTest, DyndepTwoLevelIndirect) {
-  // Verify that dyndep files can add to an edge new implicit inputs that
-  // correspond to implicit outputs added to other edges by other dyndep
-  // files on which they (order-only) depend.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out $out.imp\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd1: cp dd1-in\n"
-"build out1: touch || dd1\n"
-"  dyndep = dd1\n"
-"build dd2: cp dd2-in || out1\n" // indirect order-only dep on dd1
-"build out2: touch || dd2\n"
-"  dyndep = dd2\n"
-));
-  fs_.Create("out1.imp", "");
-  fs_.Create("out2", "");
-  fs_.Create("out2.imp", "");
-  fs_.Create("dd1-in",
-"ninja_dyndep_version = 1\n"
-"build out1 | out1.imp: dyndep\n"
-);
-  fs_.Create("dd2-in", "");
-  fs_.Create("dd2",
-"ninja_dyndep_version = 1\n"
-"build out2 | out2.imp: dyndep | out1.imp\n"
-);
-
-  // During the build dd1 should be built and loaded.  Then dd2 should
-  // be built and loaded.  Loading dd2 should cause the builder to
-  // recognize that out2 needs to be built even though it was originally
-  // clean without dyndep info.
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out2", &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(3u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd1-in dd1", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("touch out1 out1.imp", command_runner_.commands_ran_[1]);
-  EXPECT_EQ("touch out2 out2.imp", command_runner_.commands_ran_[2]);
-}
-
-TEST_F(BuildTest, DyndepTwoLevelDiscoveredReady) {
-  // Verify that a dyndep file can discover a new input whose
-  // edge also has a dyndep file that is ready to load immediately.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd0: cp dd0-in\n"
-"build dd1: cp dd1-in\n"
-"build in: touch\n"
-"build tmp: touch || dd0\n"
-"  dyndep = dd0\n"
-"build out: touch || dd1\n"
-"  dyndep = dd1\n"
-  ));
-  fs_.Create("dd1-in",
-"ninja_dyndep_version = 1\n"
-"build out: dyndep | tmp\n"
-);
-  fs_.Create("dd0-in", "");
-  fs_.Create("dd0",
-"ninja_dyndep_version = 1\n"
-"build tmp: dyndep | in\n"
-);
-  fs_.Tick();
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(4u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd1-in dd1", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("touch in", command_runner_.commands_ran_[1]);
-  EXPECT_EQ("touch tmp", command_runner_.commands_ran_[2]);
-  EXPECT_EQ("touch out", command_runner_.commands_ran_[3]);
-}
-
-TEST_F(BuildTest, DyndepTwoLevelDiscoveredDirty) {
-  // Verify that a dyndep file can discover a new input whose
-  // edge also has a dyndep file that needs to be built.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"rule cp\n"
-"  command = cp $in $out\n"
-"build dd0: cp dd0-in\n"
-"build dd1: cp dd1-in\n"
-"build in: touch\n"
-"build tmp: touch || dd0\n"
-"  dyndep = dd0\n"
-"build out: touch || dd1\n"
-"  dyndep = dd1\n"
-  ));
-  fs_.Create("dd1-in",
-"ninja_dyndep_version = 1\n"
-"build out: dyndep | tmp\n"
-);
-  fs_.Create("dd0-in",
-"ninja_dyndep_version = 1\n"
-"build tmp: dyndep | in\n"
-);
-  fs_.Tick();
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(5u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cp dd1-in dd1", command_runner_.commands_ran_[0]);
-  EXPECT_EQ("cp dd0-in dd0", command_runner_.commands_ran_[1]);
-  EXPECT_EQ("touch in", command_runner_.commands_ran_[2]);
-  EXPECT_EQ("touch tmp", command_runner_.commands_ran_[3]);
-  EXPECT_EQ("touch out", command_runner_.commands_ran_[4]);
-}
-
-TEST_F(BuildTest, Validation) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-    "build out: cat in |@ validate\n"
-    "build validate: cat in2\n"));
-
-  fs_.Create("in", "");
-  fs_.Create("in2", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-
-  EXPECT_EQ(2u, command_runner_.commands_ran_.size());
-
-  // Test touching "in" only rebuilds "out" ("validate" doesn't depend on
-  // "out").
-  fs_.Tick();
-  fs_.Create("in", "");
-
-  err.clear();
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cat in > out", command_runner_.commands_ran_[0]);
-
-  // Test touching "in2" only rebuilds "validate" ("out" doesn't depend on
-  // "validate").
-  fs_.Tick();
-  fs_.Create("in2", "");
-
-  err.clear();
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cat in2 > validate", command_runner_.commands_ran_[0]);
-}
-
-TEST_F(BuildTest, ValidationDependsOnOutput) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-    "build out: cat in |@ validate\n"
-    "build validate: cat in2 | out\n"));
-
-  fs_.Create("in", "");
-  fs_.Create("in2", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-
-  EXPECT_EQ(2u, command_runner_.commands_ran_.size());
-
-  // Test touching "in" rebuilds "out" and "validate".
-  fs_.Tick();
-  fs_.Create("in", "");
-
-  err.clear();
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-
-  EXPECT_EQ(2u, command_runner_.commands_ran_.size());
-
-  // Test touching "in2" only rebuilds "validate" ("out" doesn't depend on
-  // "validate").
-  fs_.Tick();
-  fs_.Create("in2", "");
-
-  err.clear();
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cat in2 > validate", command_runner_.commands_ran_[0]);
-}
-
-TEST_F(BuildWithDepsLogTest, ValidationThroughDepfile) {
-  const char* manifest =
-      "build out: cat in |@ validate\n"
-      "build validate: cat in2 | out\n"
-      "build out2: cat in3\n"
-      "  deps = gcc\n"
-      "  depfile = out2.d\n";
-
-  string err;
-
-  {
-    fs_.Create("in", "");
-    fs_.Create("in2", "");
-    fs_.Create("in3", "");
-    fs_.Create("out2.d", "out: out");
-
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-    ASSERT_EQ("", err);
-
-    Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-
-    EXPECT_TRUE(builder.AddTarget("out2", &err));
-    ASSERT_EQ("", err);
-
-    EXPECT_TRUE(builder.Build(&err));
-    EXPECT_EQ("", err);
-
-    // On the first build, only the out2 command is run.
-    ASSERT_EQ(command_runner_.commands_ran_.size(), 1);
-    EXPECT_EQ("cat in3 > out2", command_runner_.commands_ran_[0]);
-
-    // The deps file should have been removed.
-    EXPECT_EQ(0, fs_.Stat("out2.d", &err));
-
-    deps_log.Close();
-    builder.command_runner_.release();
-  }
-
-  fs_.Tick();
-  command_runner_.commands_ran_.clear();
-
-  {
-    fs_.Create("in2", "");
-    fs_.Create("in3", "");
-
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
-
-    DepsLog deps_log;
-    ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
-    ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
-    ASSERT_EQ("", err);
-
-    Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
-    builder.command_runner_.reset(&command_runner_);
-
-    EXPECT_TRUE(builder.AddTarget("out2", &err));
-    ASSERT_EQ("", err);
-
-    EXPECT_TRUE(builder.Build(&err));
-    EXPECT_EQ("", err);
-
-    // The out and validate actions should have been run as well as out2.
-    ASSERT_EQ(command_runner_.commands_ran_.size(), 3);
-    // out has to run first, as both out2 and validate depend on it.
-    EXPECT_EQ("cat in > out", command_runner_.commands_ran_[0]);
-
-    deps_log.Close();
-    builder.command_runner_.release();
-  }
-}
-
-TEST_F(BuildTest, ValidationCircular) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-    "build out: cat in |@ out2\n"
-    "build out2: cat in2 |@ out\n"));
-
-  fs_.Create("in", "");
-  fs_.Create("in2", "");
-
-  string err;
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-
-  EXPECT_EQ(2u, command_runner_.commands_ran_.size());
-
-  // Test touching "in" rebuilds "out".
-  fs_.Tick();
-  fs_.Create("in", "");
-
-  err.clear();
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cat in > out", command_runner_.commands_ran_[0]);
-
-  // Test touching "in2" rebuilds "out2".
-  fs_.Tick();
-  fs_.Create("in2", "");
-
-  err.clear();
-  command_runner_.commands_ran_.clear();
-  state_.Reset();
-  EXPECT_TRUE(builder_.AddTarget("out", &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_TRUE(builder_.Build(&err));
-  EXPECT_EQ("", err);
-
-  ASSERT_EQ(1u, command_runner_.commands_ran_.size());
-  EXPECT_EQ("cat in2 > out2", command_runner_.commands_ran_[0]);
-}
-
-TEST_F(BuildTest, ValidationWithCircularDependency) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-    "build out: cat in |@ validate\n"
-    "build validate: cat validate_in | out\n"
-    "build validate_in: cat validate\n"));
-
-  fs_.Create("in", "");
-
-  string err;
-  EXPECT_FALSE(builder_.AddTarget("out", &err));
-  EXPECT_EQ("dependency cycle: validate -> validate_in -> validate", err);
-}
diff --git a/src/canon_perftest.cc b/src/canon_perftest.cc
deleted file mode 100644
index 6b5e382..0000000
--- a/src/canon_perftest.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2012 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 <stdio.h>
-#include <string.h>
-
-#include "util.h"
-#include "metrics.h"
-
-using namespace std;
-
-const char kPath[] =
-    "../../third_party/WebKit/Source/WebCore/"
-    "platform/leveldb/LevelDBWriteBatch.cpp";
-
-int main() {
-  vector<int> times;
-
-  char buf[200];
-  size_t len = strlen(kPath);
-  strcpy(buf, kPath);
-
-  for (int j = 0; j < 5; ++j) {
-    const int kNumRepetitions = 2000000;
-    int64_t start = GetTimeMillis();
-    uint64_t slash_bits;
-    for (int i = 0; i < kNumRepetitions; ++i) {
-      CanonicalizePath(buf, &len, &slash_bits);
-    }
-    int delta = (int)(GetTimeMillis() - start);
-    times.push_back(delta);
-  }
-
-  int min = times[0];
-  int max = times[0];
-  float total = 0;
-  for (size_t i = 0; i < times.size(); ++i) {
-    total += times[i];
-    if (times[i] < min)
-      min = times[i];
-    else if (times[i] > max)
-      max = times[i];
-  }
-
-  printf("min %dms  max %dms  avg %.1fms\n",
-         min, max, total / times.size());
-}
diff --git a/src/clean.cc b/src/clean.cc
deleted file mode 100644
index e48eb8e..0000000
--- a/src/clean.cc
+++ /dev/null
@@ -1,302 +0,0 @@
-// 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.
-
-#include "clean.h"
-
-#include <assert.h>
-#include <stdio.h>
-
-#include "disk_interface.h"
-#include "graph.h"
-#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),
-    cleaned_files_count_(0),
-    disk_interface_(disk_interface),
-    status_(0) {
-}
-
-int Cleaner::RemoveFile(const string& path) {
-  return disk_interface_->RemoveFile(path);
-}
-
-bool Cleaner::FileExists(const string& path) {
-  string err;
-  TimeStamp mtime = disk_interface_->Stat(path, &err);
-  if (mtime == -1)
-    Error("%s", err.c_str());
-  return mtime > 0;  // Treat Stat() errors as "file does not exist".
-}
-
-void Cleaner::Report(const string& path) {
-  ++cleaned_files_count_;
-  if (IsVerbose())
-    printf("Remove %s\n", path.c_str());
-}
-
-void Cleaner::Remove(const string& path) {
-  if (!IsAlreadyRemoved(path)) {
-    removed_.insert(path);
-    if (config_.dry_run) {
-      if (FileExists(path))
-        Report(path);
-    } else {
-      int ret = RemoveFile(path);
-      if (ret == 0)
-        Report(path);
-      else if (ret == -1)
-        status_ = 1;
-    }
-  }
-}
-
-bool Cleaner::IsAlreadyRemoved(const string& path) {
-  set<string>::iterator i = removed_.find(path);
-  return (i != removed_.end());
-}
-
-void Cleaner::RemoveEdgeFiles(Edge* edge) {
-  string depfile = edge->GetUnescapedDepfile();
-  if (!depfile.empty())
-    Remove(depfile);
-
-  string rspfile = edge->GetUnescapedRspfile();
-  if (!rspfile.empty())
-    Remove(rspfile);
-}
-
-void Cleaner::PrintHeader() {
-  if (config_.verbosity == BuildConfig::QUIET)
-    return;
-  printf("Cleaning...");
-  if (IsVerbose())
-    printf("\n");
-  else
-    printf(" ");
-  fflush(stdout);
-}
-
-void Cleaner::PrintFooter() {
-  if (config_.verbosity == BuildConfig::QUIET)
-    return;
-  printf("%d files.\n", cleaned_files_count_);
-}
-
-int Cleaner::CleanAll(bool generator) {
-  Reset();
-  PrintHeader();
-  LoadDyndeps();
-  for (vector<Edge*>::iterator e = state_->edges_.begin();
-       e != state_->edges_.end(); ++e) {
-    // Do not try to remove phony targets
-    if ((*e)->is_phony())
-      continue;
-    // Do not remove generator's files unless generator specified.
-    if (!generator && (*e)->is_generator())
-      continue;
-    for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
-         out_node != (*e)->outputs_.end(); ++out_node) {
-      Remove((*out_node)->path());
-    }
-
-    RemoveEdgeFiles(*e);
-  }
-  PrintFooter();
-  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);
-    // Detecting stale outputs works as follows:
-    //
-    // - If it has no Node, it is not in the build graph, or the deps log
-    //   anymore, hence is stale.
-    //
-    // - If it isn't an output or input for any edge, it comes from a stale
-    //   entry in the deps log, but no longer referenced from the build
-    //   graph.
-    //
-    if (!n || (!n->in_edge() && n->out_edges().empty())) {
-      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
-    if (!e->is_phony()) {
-      Remove(target->path());
-      RemoveEdgeFiles(e);
-    }
-    for (vector<Node*>::iterator n = e->inputs_.begin(); n != e->inputs_.end();
-         ++n) {
-      Node* next = *n;
-      // call DoCleanTarget recursively if this node has not been visited
-      if (cleaned_.count(next) == 0) {
-        DoCleanTarget(next);
-      }
-    }
-  }
-
-  // mark this target to be cleaned already
-  cleaned_.insert(target);
-}
-
-int Cleaner::CleanTarget(Node* target) {
-  assert(target);
-
-  Reset();
-  PrintHeader();
-  LoadDyndeps();
-  DoCleanTarget(target);
-  PrintFooter();
-  return status_;
-}
-
-int Cleaner::CleanTarget(const char* target) {
-  assert(target);
-
-  Reset();
-  Node* node = state_->LookupNode(target);
-  if (node) {
-    CleanTarget(node);
-  } else {
-    Error("unknown target '%s'", target);
-    status_ = 1;
-  }
-  return status_;
-}
-
-int Cleaner::CleanTargets(int target_count, char* targets[]) {
-  Reset();
-  PrintHeader();
-  LoadDyndeps();
-  for (int i = 0; i < target_count; ++i) {
-    string target_name = targets[i];
-    if (target_name.empty()) {
-      Error("failed to canonicalize '': empty path");
-      status_ = 1;
-      continue;
-    }
-    uint64_t slash_bits;
-    CanonicalizePath(&target_name, &slash_bits);
-    Node* target = state_->LookupNode(target_name);
-    if (target) {
-      if (IsVerbose())
-        printf("Target %s\n", target_name.c_str());
-      DoCleanTarget(target);
-    } else {
-      Error("unknown target '%s'", target_name.c_str());
-      status_ = 1;
-    }
-  }
-  PrintFooter();
-  return status_;
-}
-
-void Cleaner::DoCleanRule(const Rule* rule) {
-  assert(rule);
-
-  for (vector<Edge*>::iterator e = state_->edges_.begin();
-       e != state_->edges_.end(); ++e) {
-    if ((*e)->rule().name() == rule->name()) {
-      for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
-           out_node != (*e)->outputs_.end(); ++out_node) {
-        Remove((*out_node)->path());
-        RemoveEdgeFiles(*e);
-      }
-    }
-  }
-}
-
-int Cleaner::CleanRule(const Rule* rule) {
-  assert(rule);
-
-  Reset();
-  PrintHeader();
-  LoadDyndeps();
-  DoCleanRule(rule);
-  PrintFooter();
-  return status_;
-}
-
-int Cleaner::CleanRule(const char* rule) {
-  assert(rule);
-
-  Reset();
-  const Rule* r = state_->bindings().LookupRule(rule);
-  if (r) {
-    CleanRule(r);
-  } else {
-    Error("unknown rule '%s'", rule);
-    status_ = 1;
-  }
-  return status_;
-}
-
-int Cleaner::CleanRules(int rule_count, char* rules[]) {
-  assert(rules);
-
-  Reset();
-  PrintHeader();
-  LoadDyndeps();
-  for (int i = 0; i < rule_count; ++i) {
-    const char* rule_name = rules[i];
-    const Rule* rule = state_->bindings().LookupRule(rule_name);
-    if (rule) {
-      if (IsVerbose())
-        printf("Rule %s\n", rule_name);
-      DoCleanRule(rule);
-    } else {
-      Error("unknown rule '%s'", rule_name);
-      status_ = 1;
-    }
-  }
-  PrintFooter();
-  return status_;
-}
-
-void Cleaner::Reset() {
-  status_ = 0;
-  cleaned_files_count_ = 0;
-  removed_.clear();
-  cleaned_.clear();
-}
-
-void Cleaner::LoadDyndeps() {
-  // Load dyndep files that exist, before they are cleaned.
-  for (vector<Edge*>::iterator e = state_->edges_.begin();
-       e != state_->edges_.end(); ++e) {
-    if (Node* dyndep = (*e)->dyndep_) {
-      // Capture and ignore errors loading the dyndep file.
-      // We clean as much of the graph as we know.
-      std::string err;
-      dyndep_loader_.LoadDyndeps(dyndep, &err);
-    }
-  }
-}
diff --git a/src/clean.h b/src/clean.h
deleted file mode 100644
index 0ff1221..0000000
--- a/src/clean.h
+++ /dev/null
@@ -1,111 +0,0 @@
-// 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.
-
-#ifndef NINJA_CLEAN_H_
-#define NINJA_CLEAN_H_
-
-#include <set>
-#include <string>
-
-#include "build_config.h"
-#include "build_log.h"
-#include "dyndep.h"
-
-struct State;
-struct Node;
-struct Rule;
-struct DiskInterface;
-
-struct Cleaner {
-  /// Build a cleaner object with the given @a disk_interface
-  Cleaner(State* state,
-          const BuildConfig& config,
-          DiskInterface* disk_interface);
-
-  /// Clean the given @a target and all the file built for it.
-  /// @return non-zero if an error occurs.
-  int CleanTarget(Node* target);
-  /// Clean the given target @a target.
-  /// @return non-zero if an error occurs.
-  int CleanTarget(const char* target);
-  /// Clean the given target @a targets.
-  /// @return non-zero if an error occurs.
-  int CleanTargets(int target_count, char* targets[]);
-
-  /// Clean all built files, except for files created by generator rules.
-  /// @param generator If set, also clean files created by generator rules.
-  /// @return non-zero if an error occurs.
-  int CleanAll(bool generator = false);
-
-  /// Clean all the file built with the given rule @a rule.
-  /// @return non-zero if an error occurs.
-  int CleanRule(const Rule* rule);
-  /// Clean the file produced by the given @a rule.
-  /// @return non-zero if an error occurs.
-  int CleanRule(const char* rule);
-  /// 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 {
-    return cleaned_files_count_;
-  }
-
-  /// @return whether the cleaner is in verbose mode.
-  bool IsVerbose() const {
-    return (config_.verbosity != BuildConfig::QUIET
-            && (config_.verbosity == BuildConfig::VERBOSE || config_.dry_run));
-  }
-
- private:
-  /// Remove the file @a path.
-  /// @return whether the file has been removed.
-  int RemoveFile(const std::string& path);
-  /// @returns whether the file @a path exists.
-  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 std::string& path);
-  /// @return whether the given @a path has already been removed.
-  bool IsAlreadyRemoved(const std::string& path);
-  /// Remove the depfile and rspfile for an Edge.
-  void RemoveEdgeFiles(Edge* edge);
-
-  /// Helper recursive method for CleanTarget().
-  void DoCleanTarget(Node* target);
-  void PrintHeader();
-  void PrintFooter();
-  void DoCleanRule(const Rule* rule);
-  void Reset();
-
-  /// Load dependencies from dyndep bindings.
-  void LoadDyndeps();
-
-  State* state_;
-  const BuildConfig& config_;
-  DyndepLoader dyndep_loader_;
-  std::set<std::string> removed_;
-  std::set<Node*> cleaned_;
-  int cleaned_files_count_;
-  DiskInterface* disk_interface_;
-  int status_;
-};
-
-#endif  // NINJA_CLEAN_H_
diff --git a/src/clean_test.cc b/src/clean_test.cc
deleted file mode 100644
index e99909c..0000000
--- a/src/clean_test.cc
+++ /dev/null
@@ -1,601 +0,0 @@
-// 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.
-
-#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_;
-  virtual void SetUp() {
-    config_.verbosity = BuildConfig::QUIET;
-  }
-};
-
-TEST_F(CleanTest, CleanAll) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build in1: cat src1\n"
-"build out1: cat in1\n"
-"build in2: cat src2\n"
-"build out2: cat in2\n"));
-  fs_.Create("in1", "");
-  fs_.Create("out1", "");
-  fs_.Create("in2", "");
-  fs_.Create("out2", "");
-
-  Cleaner cleaner(&state_, config_, &fs_);
-
-  ASSERT_EQ(0, cleaner.cleaned_files_count());
-  EXPECT_EQ(0, cleaner.CleanAll());
-  EXPECT_EQ(4, cleaner.cleaned_files_count());
-  EXPECT_EQ(4u, fs_.files_removed_.size());
-
-  // Check they are removed.
-  string err;
-  EXPECT_EQ(0, fs_.Stat("in1", &err));
-  EXPECT_EQ(0, fs_.Stat("out1", &err));
-  EXPECT_EQ(0, fs_.Stat("in2", &err));
-  EXPECT_EQ(0, fs_.Stat("out2", &err));
-  fs_.files_removed_.clear();
-
-  EXPECT_EQ(0, cleaner.CleanAll());
-  EXPECT_EQ(0, cleaner.cleaned_files_count());
-  EXPECT_EQ(0u, fs_.files_removed_.size());
-}
-
-TEST_F(CleanTest, CleanAllDryRun) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build in1: cat src1\n"
-"build out1: cat in1\n"
-"build in2: cat src2\n"
-"build out2: cat in2\n"));
-  fs_.Create("in1", "");
-  fs_.Create("out1", "");
-  fs_.Create("in2", "");
-  fs_.Create("out2", "");
-
-  config_.dry_run = true;
-  Cleaner cleaner(&state_, config_, &fs_);
-
-  ASSERT_EQ(0, cleaner.cleaned_files_count());
-  EXPECT_EQ(0, cleaner.CleanAll());
-  EXPECT_EQ(4, cleaner.cleaned_files_count());
-  EXPECT_EQ(0u, fs_.files_removed_.size());
-
-  // Check they are not removed.
-  string err;
-  EXPECT_LT(0, fs_.Stat("in1", &err));
-  EXPECT_LT(0, fs_.Stat("out1", &err));
-  EXPECT_LT(0, fs_.Stat("in2", &err));
-  EXPECT_LT(0, fs_.Stat("out2", &err));
-  fs_.files_removed_.clear();
-
-  EXPECT_EQ(0, cleaner.CleanAll());
-  EXPECT_EQ(4, cleaner.cleaned_files_count());
-  EXPECT_EQ(0u, fs_.files_removed_.size());
-}
-
-TEST_F(CleanTest, CleanTarget) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build in1: cat src1\n"
-"build out1: cat in1\n"
-"build in2: cat src2\n"
-"build out2: cat in2\n"));
-  fs_.Create("in1", "");
-  fs_.Create("out1", "");
-  fs_.Create("in2", "");
-  fs_.Create("out2", "");
-
-  Cleaner cleaner(&state_, config_, &fs_);
-
-  ASSERT_EQ(0, cleaner.cleaned_files_count());
-  ASSERT_EQ(0, cleaner.CleanTarget("out1"));
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_EQ(2u, fs_.files_removed_.size());
-
-  // Check they are removed.
-  string err;
-  EXPECT_EQ(0, fs_.Stat("in1", &err));
-  EXPECT_EQ(0, fs_.Stat("out1", &err));
-  EXPECT_LT(0, fs_.Stat("in2", &err));
-  EXPECT_LT(0, fs_.Stat("out2", &err));
-  fs_.files_removed_.clear();
-
-  ASSERT_EQ(0, cleaner.CleanTarget("out1"));
-  EXPECT_EQ(0, cleaner.cleaned_files_count());
-  EXPECT_EQ(0u, fs_.files_removed_.size());
-}
-
-TEST_F(CleanTest, CleanTargetDryRun) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build in1: cat src1\n"
-"build out1: cat in1\n"
-"build in2: cat src2\n"
-"build out2: cat in2\n"));
-  fs_.Create("in1", "");
-  fs_.Create("out1", "");
-  fs_.Create("in2", "");
-  fs_.Create("out2", "");
-
-  config_.dry_run = true;
-  Cleaner cleaner(&state_, config_, &fs_);
-
-  ASSERT_EQ(0, cleaner.cleaned_files_count());
-  ASSERT_EQ(0, cleaner.CleanTarget("out1"));
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_EQ(0u, fs_.files_removed_.size());
-
-  // Check they are not removed.
-  string err;
-  EXPECT_LT(0, fs_.Stat("in1", &err));
-  EXPECT_LT(0, fs_.Stat("out1", &err));
-  EXPECT_LT(0, fs_.Stat("in2", &err));
-  EXPECT_LT(0, fs_.Stat("out2", &err));
-  fs_.files_removed_.clear();
-
-  ASSERT_EQ(0, cleaner.CleanTarget("out1"));
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_EQ(0u, fs_.files_removed_.size());
-}
-
-TEST_F(CleanTest, CleanRule) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cat_e\n"
-"  command = cat -e $in > $out\n"
-"build in1: cat_e src1\n"
-"build out1: cat in1\n"
-"build in2: cat_e src2\n"
-"build out2: cat in2\n"));
-  fs_.Create("in1", "");
-  fs_.Create("out1", "");
-  fs_.Create("in2", "");
-  fs_.Create("out2", "");
-
-  Cleaner cleaner(&state_, config_, &fs_);
-
-  ASSERT_EQ(0, cleaner.cleaned_files_count());
-  ASSERT_EQ(0, cleaner.CleanRule("cat_e"));
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_EQ(2u, fs_.files_removed_.size());
-
-  // Check they are removed.
-  string err;
-  EXPECT_EQ(0, fs_.Stat("in1", &err));
-  EXPECT_LT(0, fs_.Stat("out1", &err));
-  EXPECT_EQ(0, fs_.Stat("in2", &err));
-  EXPECT_LT(0, fs_.Stat("out2", &err));
-  fs_.files_removed_.clear();
-
-  ASSERT_EQ(0, cleaner.CleanRule("cat_e"));
-  EXPECT_EQ(0, cleaner.cleaned_files_count());
-  EXPECT_EQ(0u, fs_.files_removed_.size());
-}
-
-TEST_F(CleanTest, CleanRuleDryRun) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cat_e\n"
-"  command = cat -e $in > $out\n"
-"build in1: cat_e src1\n"
-"build out1: cat in1\n"
-"build in2: cat_e src2\n"
-"build out2: cat in2\n"));
-  fs_.Create("in1", "");
-  fs_.Create("out1", "");
-  fs_.Create("in2", "");
-  fs_.Create("out2", "");
-
-  config_.dry_run = true;
-  Cleaner cleaner(&state_, config_, &fs_);
-
-  ASSERT_EQ(0, cleaner.cleaned_files_count());
-  ASSERT_EQ(0, cleaner.CleanRule("cat_e"));
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_EQ(0u, fs_.files_removed_.size());
-
-  // Check they are not removed.
-  string err;
-  EXPECT_LT(0, fs_.Stat("in1", &err));
-  EXPECT_LT(0, fs_.Stat("out1", &err));
-  EXPECT_LT(0, fs_.Stat("in2", &err));
-  EXPECT_LT(0, fs_.Stat("out2", &err));
-  fs_.files_removed_.clear();
-
-  ASSERT_EQ(0, cleaner.CleanRule("cat_e"));
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_EQ(0u, fs_.files_removed_.size());
-}
-
-TEST_F(CleanTest, CleanRuleGenerator) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule regen\n"
-"  command = cat $in > $out\n"
-"  generator = 1\n"
-"build out1: cat in1\n"
-"build out2: regen in2\n"));
-  fs_.Create("out1", "");
-  fs_.Create("out2", "");
-
-  Cleaner cleaner(&state_, config_, &fs_);
-  EXPECT_EQ(0, cleaner.CleanAll());
-  EXPECT_EQ(1, cleaner.cleaned_files_count());
-  EXPECT_EQ(1u, fs_.files_removed_.size());
-
-  fs_.Create("out1", "");
-
-  EXPECT_EQ(0, cleaner.CleanAll(/*generator=*/true));
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_EQ(2u, fs_.files_removed_.size());
-}
-
-TEST_F(CleanTest, CleanDepFile) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cc\n"
-"  command = cc $in > $out\n"
-"  depfile = $out.d\n"
-"build out1: cc in1\n"));
-  fs_.Create("out1", "");
-  fs_.Create("out1.d", "");
-
-  Cleaner cleaner(&state_, config_, &fs_);
-  EXPECT_EQ(0, cleaner.CleanAll());
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_EQ(2u, fs_.files_removed_.size());
-}
-
-TEST_F(CleanTest, CleanDepFileOnCleanTarget) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cc\n"
-"  command = cc $in > $out\n"
-"  depfile = $out.d\n"
-"build out1: cc in1\n"));
-  fs_.Create("out1", "");
-  fs_.Create("out1.d", "");
-
-  Cleaner cleaner(&state_, config_, &fs_);
-  EXPECT_EQ(0, cleaner.CleanTarget("out1"));
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_EQ(2u, fs_.files_removed_.size());
-}
-
-TEST_F(CleanTest, CleanDepFileOnCleanRule) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cc\n"
-"  command = cc $in > $out\n"
-"  depfile = $out.d\n"
-"build out1: cc in1\n"));
-  fs_.Create("out1", "");
-  fs_.Create("out1.d", "");
-
-  Cleaner cleaner(&state_, config_, &fs_);
-  EXPECT_EQ(0, cleaner.CleanRule("cc"));
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_EQ(2u, fs_.files_removed_.size());
-}
-
-TEST_F(CleanTest, CleanDyndep) {
-  // Verify that a dyndep file can be loaded to discover a new output
-  // to be cleaned.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat in || dd\n"
-"  dyndep = dd\n"
-  ));
-  fs_.Create("in", "");
-  fs_.Create("dd",
-"ninja_dyndep_version = 1\n"
-"build out | out.imp: dyndep\n"
-);
-  fs_.Create("out", "");
-  fs_.Create("out.imp", "");
-
-  Cleaner cleaner(&state_, config_, &fs_);
-
-  ASSERT_EQ(0, cleaner.cleaned_files_count());
-  EXPECT_EQ(0, cleaner.CleanAll());
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_EQ(2u, fs_.files_removed_.size());
-
-  string err;
-  EXPECT_EQ(0, fs_.Stat("out", &err));
-  EXPECT_EQ(0, fs_.Stat("out.imp", &err));
-}
-
-TEST_F(CleanTest, CleanDyndepMissing) {
-  // Verify that a missing dyndep file is tolerated.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat in || dd\n"
-"  dyndep = dd\n"
-  ));
-  fs_.Create("in", "");
-  fs_.Create("out", "");
-  fs_.Create("out.imp", "");
-
-  Cleaner cleaner(&state_, config_, &fs_);
-
-  ASSERT_EQ(0, cleaner.cleaned_files_count());
-  EXPECT_EQ(0, cleaner.CleanAll());
-  EXPECT_EQ(1, cleaner.cleaned_files_count());
-  EXPECT_EQ(1u, fs_.files_removed_.size());
-
-  string err;
-  EXPECT_EQ(0, fs_.Stat("out", &err));
-  EXPECT_EQ(1, fs_.Stat("out.imp", &err));
-}
-
-TEST_F(CleanTest, CleanRspFile) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cc\n"
-"  command = cc $in > $out\n"
-"  rspfile = $rspfile\n"
-"  rspfile_content=$in\n"
-"build out1: cc in1\n"
-"  rspfile = cc1.rsp\n"));
-  fs_.Create("out1", "");
-  fs_.Create("cc1.rsp", "");
-
-  Cleaner cleaner(&state_, config_, &fs_);
-  EXPECT_EQ(0, cleaner.CleanAll());
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_EQ(2u, fs_.files_removed_.size());
-}
-
-TEST_F(CleanTest, CleanRsp) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cat_rsp \n"
-"  command = cat $rspfile > $out\n"
-"  rspfile = $rspfile\n"
-"  rspfile_content = $in\n"
-"build in1: cat src1\n"
-"build out1: cat in1\n"
-"build in2: cat_rsp src2\n"
-"  rspfile=in2.rsp\n"
-"build out2: cat_rsp in2\n"
-"  rspfile=out2.rsp\n"
-));
-  fs_.Create("in1", "");
-  fs_.Create("out1", "");
-  fs_.Create("in2.rsp", "");
-  fs_.Create("out2.rsp", "");
-  fs_.Create("in2", "");
-  fs_.Create("out2", "");
-
-  Cleaner cleaner(&state_, config_, &fs_);
-  ASSERT_EQ(0, cleaner.cleaned_files_count());
-  ASSERT_EQ(0, cleaner.CleanTarget("out1"));
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  ASSERT_EQ(0, cleaner.CleanTarget("in2"));
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  ASSERT_EQ(0, cleaner.CleanRule("cat_rsp"));
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-
-  EXPECT_EQ(6u, fs_.files_removed_.size());
-
-  // Check they are removed.
-  string err;
-  EXPECT_EQ(0, fs_.Stat("in1", &err));
-  EXPECT_EQ(0, fs_.Stat("out1", &err));
-  EXPECT_EQ(0, fs_.Stat("in2", &err));
-  EXPECT_EQ(0, fs_.Stat("out2", &err));
-  EXPECT_EQ(0, fs_.Stat("in2.rsp", &err));
-  EXPECT_EQ(0, fs_.Stat("out2.rsp", &err));
-}
-
-TEST_F(CleanTest, CleanFailure) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-                                      "build dir: cat src1\n"));
-  fs_.MakeDir("dir");
-  Cleaner cleaner(&state_, config_, &fs_);
-  EXPECT_NE(0, cleaner.CleanAll());
-}
-
-TEST_F(CleanTest, CleanPhony) {
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build phony: phony t1 t2\n"
-"build t1: cat\n"
-"build t2: cat\n"));
-
-  fs_.Create("phony", "");
-  fs_.Create("t1", "");
-  fs_.Create("t2", "");
-
-  // Check that CleanAll does not remove "phony".
-  Cleaner cleaner(&state_, config_, &fs_);
-  EXPECT_EQ(0, cleaner.CleanAll());
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_LT(0, fs_.Stat("phony", &err));
-
-  fs_.Create("t1", "");
-  fs_.Create("t2", "");
-
-  // Check that CleanTarget does not remove "phony".
-  EXPECT_EQ(0, cleaner.CleanTarget("phony"));
-  EXPECT_EQ(2, cleaner.cleaned_files_count());
-  EXPECT_LT(0, fs_.Stat("phony", &err));
-}
-
-TEST_F(CleanTest, CleanDepFileAndRspFileWithSpaces) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule cc_dep\n"
-"  command = cc $in > $out\n"
-"  depfile = $out.d\n"
-"rule cc_rsp\n"
-"  command = cc $in > $out\n"
-"  rspfile = $out.rsp\n"
-"  rspfile_content = $in\n"
-"build out$ 1: cc_dep in$ 1\n"
-"build out$ 2: cc_rsp in$ 1\n"
-));
-  fs_.Create("out 1", "");
-  fs_.Create("out 2", "");
-  fs_.Create("out 1.d", "");
-  fs_.Create("out 2.rsp", "");
-
-  Cleaner cleaner(&state_, config_, &fs_);
-  EXPECT_EQ(0, cleaner.CleanAll());
-  EXPECT_EQ(4, cleaner.cleaned_files_count());
-  EXPECT_EQ(4u, fs_.files_removed_.size());
-
-  string err;
-  EXPECT_EQ(0, fs_.Stat("out 1", &err));
-  EXPECT_EQ(0, fs_.Stat("out 2", &err));
-  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();
-}
-
-TEST_F(CleanDeadTest, CleanDeadPreservesInputs) {
-  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"
-));
-  // This manifest does not build out1 anymore, but makes
-  // it an implicit input. CleanDead should detect this
-  // and preserve it.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out2: cat in | out1\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(0, cleaner2.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));
-
-  // Nothing to do now.
-  EXPECT_EQ(0, cleaner2.CleanDead(log2.entries()));
-  EXPECT_EQ(0, cleaner2.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));
-  log2.Close();
-}
-}  // anonymous namespace
diff --git a/src/clparser.cc b/src/clparser.cc
deleted file mode 100644
index 3d3e7de..0000000
--- a/src/clparser.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2015 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 "clparser.h"
-
-#include <algorithm>
-#include <assert.h>
-#include <string.h>
-
-#include "metrics.h"
-#include "string_piece_util.h"
-
-#ifdef _WIN32
-#include "includes_normalize.h"
-#include "string_piece.h"
-#else
-#include "util.h"
-#endif
-
-using namespace std;
-
-namespace {
-
-/// Return true if \a input ends with \a needle.
-bool EndsWith(const string& input, const string& needle) {
-  return (input.size() >= needle.size() &&
-          input.substr(input.size() - needle.size()) == needle);
-}
-
-}  // anonymous namespace
-
-// static
-string CLParser::FilterShowIncludes(const string& line,
-                                    const string& deps_prefix) {
-  const string kDepsPrefixEnglish = "Note: including file: ";
-  const char* in = line.c_str();
-  const char* end = in + line.size();
-  const string& prefix = deps_prefix.empty() ? kDepsPrefixEnglish : deps_prefix;
-  if (end - in > (int)prefix.size() &&
-      memcmp(in, prefix.c_str(), (int)prefix.size()) == 0) {
-    in += prefix.size();
-    while (*in == ' ')
-      ++in;
-    return line.substr(in - line.c_str());
-  }
-  return "";
-}
-
-// static
-bool CLParser::IsSystemInclude(string path) {
-  transform(path.begin(), path.end(), path.begin(), ToLowerASCII);
-  // TODO: this is a heuristic, perhaps there's a better way?
-  return (path.find("program files") != string::npos ||
-          path.find("microsoft visual studio") != string::npos);
-}
-
-// static
-bool CLParser::FilterInputFilename(string line) {
-  transform(line.begin(), line.end(), line.begin(), ToLowerASCII);
-  // TODO: other extensions, like .asm?
-  return EndsWith(line, ".c") ||
-      EndsWith(line, ".cc") ||
-      EndsWith(line, ".cxx") ||
-      EndsWith(line, ".cpp") ||
-      EndsWith(line, ".c++");
-}
-
-// static
-bool CLParser::Parse(const string& output, const string& deps_prefix,
-                     string* filtered_output, string* err) {
-  METRIC_RECORD("CLParser::Parse");
-
-  // Loop over all lines in the output to process them.
-  assert(&output != filtered_output);
-  size_t start = 0;
-  bool seen_show_includes = false;
-#ifdef _WIN32
-  IncludesNormalize normalizer(".");
-#endif
-
-  while (start < output.size()) {
-    size_t end = output.find_first_of("\r\n", start);
-    if (end == string::npos)
-      end = output.size();
-    string line = output.substr(start, end - start);
-
-    string include = FilterShowIncludes(line, deps_prefix);
-    if (!include.empty()) {
-      seen_show_includes = true;
-      string normalized;
-#ifdef _WIN32
-      if (!normalizer.Normalize(include, &normalized, err))
-        return false;
-#else
-      // TODO: should this make the path relative to cwd?
-      normalized = include;
-      uint64_t slash_bits;
-      CanonicalizePath(&normalized, &slash_bits);
-#endif
-      if (!IsSystemInclude(normalized))
-        includes_.insert(normalized);
-    } else if (!seen_show_includes && FilterInputFilename(line)) {
-      // Drop it.
-      // TODO: if we support compiling multiple output files in a single
-      // cl.exe invocation, we should stash the filename.
-    } else {
-      filtered_output->append(line);
-      filtered_output->append("\n");
-    }
-
-    if (end < output.size() && output[end] == '\r')
-      ++end;
-    if (end < output.size() && output[end] == '\n')
-      ++end;
-    start = end;
-  }
-
-  return true;
-}
diff --git a/src/clparser.h b/src/clparser.h
deleted file mode 100644
index 2a33628..0000000
--- a/src/clparser.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2015 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_CLPARSER_H_
-#define NINJA_CLPARSER_H_
-
-#include <set>
-#include <string>
-
-/// Visual Studio's cl.exe requires some massaging to work with Ninja;
-/// for example, it emits include information on stderr in a funny
-/// format when building with /showIncludes.  This class parses this
-/// output.
-struct CLParser {
-  /// Parse a line of cl.exe output and extract /showIncludes info.
-  /// If a dependency is extracted, returns a nonempty string.
-  /// Exposed for testing.
-  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(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(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 std::string& output, const std::string& deps_prefix,
-             std::string* filtered_output, std::string* err);
-
-  std::set<std::string> includes_;
-};
-
-#endif  // NINJA_CLPARSER_H_
diff --git a/src/clparser_perftest.cc b/src/clparser_perftest.cc
deleted file mode 100644
index 008ac46..0000000
--- a/src/clparser_perftest.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2017 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 <stdio.h>
-#include <stdlib.h>
-
-#include "clparser.h"
-#include "metrics.h"
-
-using namespace std;
-
-int main(int argc, char* argv[]) {
-  // Output of /showIncludes from #include <iostream>
-  string perf_testdata =
-      "Note: including file: C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\iostream\r\n"
-      "Note: including file:  C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\istream\r\n"
-      "Note: including file:   C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\ostream\r\n"
-      "Note: including file:    C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\ios\r\n"
-      "Note: including file:     C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xlocnum\r\n"
-      "Note: including file:      C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\climits\r\n"
-      "Note: including file:       C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\yvals.h\r\n"
-      "Note: including file:        C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xkeycheck.h\r\n"
-      "Note: including file:        C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\crtdefs.h\r\n"
-      "Note: including file:         C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime.h\r\n"
-      "Note: including file:          C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\sal.h\r\n"
-      "Note: including file:           C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\ConcurrencySal.h\r\n"
-      "Note: including file:          C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vadefs.h\r\n"
-      "Note: including file:         C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt.h\r\n"
-      "Note: including file:          C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime.h\r\n"
-      "Note: including file:        C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\use_ansi.h\r\n"
-      "Note: including file:       C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\limits.h\r\n"
-      "Note: including file:        C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime.h\r\n"
-      "Note: including file:      C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\cmath\r\n"
-      "Note: including file:       C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\math.h\r\n"
-      "Note: including file:       C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xtgmath.h\r\n"
-      "Note: including file:        C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xtr1common\r\n"
-      "Note: including file:         C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\cstdlib\r\n"
-      "Note: including file:          C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\stdlib.h\r\n"
-      "Note: including file:           C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_malloc.h\r\n"
-      "Note: including file:           C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_search.h\r\n"
-      "Note: including file:            C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\stddef.h\r\n"
-      "Note: including file:           C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_wstdlib.h\r\n"
-      "Note: including file:      C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\cstdio\r\n"
-      "Note: including file:       C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\stdio.h\r\n"
-      "Note: including file:        C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_wstdio.h\r\n"
-      "Note: including file:         C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_stdio_config.h\r\n"
-      "Note: including file:      C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\streambuf\r\n"
-      "Note: including file:       C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xiosbase\r\n"
-      "Note: including file:        C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xlocale\r\n"
-      "Note: including file:         C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\cstring\r\n"
-      "Note: including file:          C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\string.h\r\n"
-      "Note: including file:           C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_memory.h\r\n"
-      "Note: including file:            C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_memcpy_s.h\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\errno.h\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime_string.h\r\n"
-      "Note: including file:              C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime.h\r\n"
-      "Note: including file:           C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_wstring.h\r\n"
-      "Note: including file:         C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\stdexcept\r\n"
-      "Note: including file:          C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\exception\r\n"
-      "Note: including file:           C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\type_traits\r\n"
-      "Note: including file:            C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xstddef\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\cstddef\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\initializer_list\r\n"
-      "Note: including file:           C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\malloc.h\r\n"
-      "Note: including file:           C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime_exception.h\r\n"
-      "Note: including file:            C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\eh.h\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_terminate.h\r\n"
-      "Note: including file:          C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xstring\r\n"
-      "Note: including file:           C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xmemory0\r\n"
-      "Note: including file:            C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\cstdint\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\stdint.h\r\n"
-      "Note: including file:              C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime.h\r\n"
-      "Note: including file:            C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\limits\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\ymath.h\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\cfloat\r\n"
-      "Note: including file:              C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\float.h\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\cwchar\r\n"
-      "Note: including file:              C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\wchar.h\r\n"
-      "Note: including file:               C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_wconio.h\r\n"
-      "Note: including file:               C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_wctype.h\r\n"
-      "Note: including file:               C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_wdirect.h\r\n"
-      "Note: including file:               C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_wio.h\r\n"
-      "Note: including file:                C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_share.h\r\n"
-      "Note: including file:               C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_wprocess.h\r\n"
-      "Note: including file:               C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\corecrt_wtime.h\r\n"
-      "Note: including file:               C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\sys/stat.h\r\n"
-      "Note: including file:                C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\sys/types.h\r\n"
-      "Note: including file:            C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\new\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime_new.h\r\n"
-      "Note: including file:              C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime.h\r\n"
-      "Note: including file:            C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xutility\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\utility\r\n"
-      "Note: including file:              C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\iosfwd\r\n"
-      "Note: including file:               C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\crtdbg.h\r\n"
-      "Note: including file:                C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime_new_debug.h\r\n"
-      "Note: including file:            C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xatomic0.h\r\n"
-      "Note: including file:            C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\intrin.h\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime.h\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\setjmp.h\r\n"
-      "Note: including file:              C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime.h\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\immintrin.h\r\n"
-      "Note: including file:              C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\wmmintrin.h\r\n"
-      "Note: including file:               C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\nmmintrin.h\r\n"
-      "Note: including file:                C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\smmintrin.h\r\n"
-      "Note: including file:                 C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\tmmintrin.h\r\n"
-      "Note: including file:                  C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\pmmintrin.h\r\n"
-      "Note: including file:                   C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\emmintrin.h\r\n"
-      "Note: including file:                    C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xmmintrin.h\r\n"
-      "Note: including file:                     C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\mmintrin.h\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\ammintrin.h\r\n"
-      "Note: including file:             C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\mm3dnow.h\r\n"
-      "Note: including file:              C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime.h\r\n"
-      "Note: including file:         C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\typeinfo\r\n"
-      "Note: including file:          C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime_typeinfo.h\r\n"
-      "Note: including file:           C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\vcruntime.h\r\n"
-      "Note: including file:         C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xlocinfo\r\n"
-      "Note: including file:          C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xlocinfo.h\r\n"
-      "Note: including file:           C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\ctype.h\r\n"
-      "Note: including file:           C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\locale.h\r\n"
-      "Note: including file:         C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\xfacet\r\n"
-      "Note: including file:        C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\system_error\r\n"
-      "Note: including file:         C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE\\cerrno\r\n"
-      "Note: including file:        C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt\\share.h\r\n";
-
-  for (int limit = 1 << 10; limit < (1<<20); limit *= 2) {
-    int64_t start = GetTimeMillis();
-    for (int rep = 0; rep < limit; ++rep) {
-      string output;
-      string err;
-
-      CLParser parser;
-      if (!parser.Parse(perf_testdata, "", &output, &err)) {
-        printf("%s\n", err.c_str());
-        return 1;
-      }
-    }
-    int64_t end = GetTimeMillis();
-
-    if (end - start > 2000) {
-      int delta_ms = (int)(end - start);
-      printf("Parse %d times in %dms avg %.1fus\n",
-             limit, delta_ms, float(delta_ms * 1000) / limit);
-      break;
-    }
-  }
-
-  return 0;
-}
diff --git a/src/clparser_test.cc b/src/clparser_test.cc
deleted file mode 100644
index f141680..0000000
--- a/src/clparser_test.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-// 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.
-
-#include "clparser.h"
-
-#include "test.h"
-#include "util.h"
-
-using namespace std;
-
-TEST(CLParserTest, ShowIncludes) {
-  ASSERT_EQ("", CLParser::FilterShowIncludes("", ""));
-
-  ASSERT_EQ("", CLParser::FilterShowIncludes("Sample compiler output", ""));
-  ASSERT_EQ("c:\\Some Files\\foobar.h",
-            CLParser::FilterShowIncludes("Note: including file: "
-                                         "c:\\Some Files\\foobar.h", ""));
-  ASSERT_EQ("c:\\initspaces.h",
-            CLParser::FilterShowIncludes("Note: including file:    "
-                                         "c:\\initspaces.h", ""));
-  ASSERT_EQ("c:\\initspaces.h",
-            CLParser::FilterShowIncludes("Non-default prefix: inc file:    "
-                                         "c:\\initspaces.h",
-                    "Non-default prefix: inc file:"));
-}
-
-TEST(CLParserTest, FilterInputFilename) {
-  ASSERT_TRUE(CLParser::FilterInputFilename("foobar.cc"));
-  ASSERT_TRUE(CLParser::FilterInputFilename("foo bar.cc"));
-  ASSERT_TRUE(CLParser::FilterInputFilename("baz.c"));
-  ASSERT_TRUE(CLParser::FilterInputFilename("FOOBAR.CC"));
-
-  ASSERT_FALSE(CLParser::FilterInputFilename(
-                   "src\\cl_helper.cc(166) : fatal error C1075: end "
-                   "of file found ..."));
-}
-
-TEST(CLParserTest, ParseSimple) {
-  CLParser parser;
-  string output, err;
-  ASSERT_TRUE(parser.Parse(
-      "foo\r\n"
-      "Note: inc file prefix:  foo.h\r\n"
-      "bar\r\n",
-      "Note: inc file prefix:", &output, &err));
-
-  ASSERT_EQ("foo\nbar\n", output);
-  ASSERT_EQ(1u, parser.includes_.size());
-  ASSERT_EQ("foo.h", *parser.includes_.begin());
-}
-
-TEST(CLParserTest, ParseFilenameFilter) {
-  CLParser parser;
-  string output, err;
-  ASSERT_TRUE(parser.Parse(
-      "foo.cc\r\n"
-      "cl: warning\r\n",
-      "", &output, &err));
-  ASSERT_EQ("cl: warning\n", output);
-}
-
-TEST(CLParserTest, NoFilenameFilterAfterShowIncludes) {
-  CLParser parser;
-  string output, err;
-  ASSERT_TRUE(parser.Parse(
-      "foo.cc\r\n"
-      "Note: including file: foo.h\r\n"
-      "something something foo.cc\r\n",
-      "", &output, &err));
-  ASSERT_EQ("something something foo.cc\n", output);
-}
-
-TEST(CLParserTest, ParseSystemInclude) {
-  CLParser parser;
-  string output, err;
-  ASSERT_TRUE(parser.Parse(
-      "Note: including file: c:\\Program Files\\foo.h\r\n"
-      "Note: including file: d:\\Microsoft Visual Studio\\bar.h\r\n"
-      "Note: including file: path.h\r\n",
-      "", &output, &err));
-  // We should have dropped the first two includes because they look like
-  // system headers.
-  ASSERT_EQ("", output);
-  ASSERT_EQ(1u, parser.includes_.size());
-  ASSERT_EQ("path.h", *parser.includes_.begin());
-}
-
-TEST(CLParserTest, DuplicatedHeader) {
-  CLParser parser;
-  string output, err;
-  ASSERT_TRUE(parser.Parse(
-      "Note: including file: foo.h\r\n"
-      "Note: including file: bar.h\r\n"
-      "Note: including file: foo.h\r\n",
-      "", &output, &err));
-  // We should have dropped one copy of foo.h.
-  ASSERT_EQ("", output);
-  ASSERT_EQ(2u, parser.includes_.size());
-}
-
-TEST(CLParserTest, DuplicatedHeaderPathConverted) {
-  CLParser parser;
-  string output, err;
-
-  // This isn't inline in the Parse() call below because the #ifdef in
-  // a macro expansion would confuse MSVC2013's preprocessor.
-  const char kInput[] =
-      "Note: including file: sub/./foo.h\r\n"
-      "Note: including file: bar.h\r\n"
-#ifdef _WIN32
-      "Note: including file: sub\\foo.h\r\n";
-#else
-      "Note: including file: sub/foo.h\r\n";
-#endif
-  ASSERT_TRUE(parser.Parse(kInput, "", &output, &err));
-  // We should have dropped one copy of foo.h.
-  ASSERT_EQ("", output);
-  ASSERT_EQ(2u, parser.includes_.size());
-}
diff --git a/src/debug_flags.cc b/src/debug_flags.cc
deleted file mode 100644
index 44b14c4..0000000
--- a/src/debug_flags.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2012 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.
-
-bool g_explaining = false;
-
-bool g_keep_depfile = false;
-
-bool g_keep_rsp = false;
-
-bool g_experimental_statcache = true;
diff --git a/src/debug_flags.h b/src/debug_flags.h
deleted file mode 100644
index e08a43b..0000000
--- a/src/debug_flags.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2012 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_EXPLAIN_H_
-#define NINJA_EXPLAIN_H_
-
-#include <stdio.h>
-
-#define EXPLAIN(fmt, ...) {                                             \
-  if (g_explaining)                                                     \
-    fprintf(stderr, "ninja explain: " fmt "\n", __VA_ARGS__);           \
-}
-
-extern bool g_explaining;
-
-extern bool g_keep_depfile;
-
-extern bool g_keep_rsp;
-
-extern bool g_experimental_statcache;
-
-#endif // NINJA_EXPLAIN_H_
diff --git a/src/depfile_parser.cc b/src/depfile_parser.cc
deleted file mode 100644
index 98fba2e..0000000
--- a/src/depfile_parser.cc
+++ /dev/null
@@ -1,371 +0,0 @@
-/* Generated by re2c */
-// 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.
-
-#include "depfile_parser.h"
-#include "util.h"
-
-#include <algorithm>
-
-using namespace std;
-
-DepfileParser::DepfileParser(DepfileParserOptions options)
-  : options_(options)
-{
-}
-
-// A note on backslashes in Makefiles, from reading the docs:
-// Backslash-newline is the line continuation character.
-// Backslash-# escapes a # (otherwise meaningful as a comment start).
-// Backslash-% escapes a % (otherwise meaningful as a special).
-// Finally, quoting the GNU manual, "Backslashes that are not in danger
-// of quoting ‘%’ characters go unmolested."
-// How do you end a line with a backslash?  The netbsd Make docs suggest
-// reading the result of a shell command echoing a backslash!
-//
-// Rather than implement all of above, we follow what GCC/Clang produces:
-// Backslashes escape a space or hash sign.
-// When a space is preceded by 2N+1 backslashes, it is represents N backslashes
-// followed by space.
-// When a space is preceded by 2N backslashes, it represents 2N backslashes at
-// the end of a filename.
-// A hash sign is escaped by a single backslash. All other backslashes remain
-// unchanged.
-//
-// If anyone actually has depfiles that rely on the more complicated
-// behavior we can adjust this.
-bool DepfileParser::Parse(string* content, string* err) {
-  // in: current parser input point.
-  // end: end of input.
-  // parsing_targets: whether we are parsing targets or dependencies.
-  char* in = &(*content)[0];
-  char* end = in + content->size();
-  bool have_target = 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
-    // as we de-escape backslashes).
-    char* out = in;
-    // filename: start of the current parsed filename.
-    char* filename = out;
-    for (;;) {
-      // start: beginning of the current parsed span.
-      const char* start = in;
-      char* yymarker = NULL;
-      
-    {
-      unsigned char yych;
-      static const unsigned char yybm[] = {
-          0,   0,   0,   0,   0,   0,   0,   0, 
-          0,   0,   0,   0,   0,   0,   0,   0, 
-          0,   0,   0,   0,   0,   0,   0,   0, 
-          0,   0,   0,   0,   0,   0,   0,   0, 
-          0, 128,   0,   0,   0, 128,   0,   0, 
-        128, 128,   0, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128,   0,   0, 128,   0,   0, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128,   0, 128,   0, 128, 
-          0, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128,   0, 128, 128,   0, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-        128, 128, 128, 128, 128, 128, 128, 128, 
-      };
-      yych = *in;
-      if (yybm[0+yych] & 128) {
-        goto yy9;
-      }
-      if (yych <= '\r') {
-        if (yych <= '\t') {
-          if (yych >= 0x01) goto yy4;
-        } else {
-          if (yych <= '\n') goto yy6;
-          if (yych <= '\f') goto yy4;
-          goto yy8;
-        }
-      } else {
-        if (yych <= '$') {
-          if (yych <= '#') goto yy4;
-          goto yy12;
-        } else {
-          if (yych <= '?') goto yy4;
-          if (yych <= '\\') goto yy13;
-          goto yy4;
-        }
-      }
-      ++in;
-      {
-        break;
-      }
-yy4:
-      ++in;
-yy5:
-      {
-        // For any other character (e.g. whitespace), swallow it here,
-        // allowing the outer logic to loop around again.
-        break;
-      }
-yy6:
-      ++in;
-      {
-        // A newline ends the current file name and the current rule.
-        have_newline = true;
-        break;
-      }
-yy8:
-      yych = *++in;
-      if (yych == '\n') goto yy6;
-      goto yy5;
-yy9:
-      yych = *++in;
-      if (yybm[0+yych] & 128) {
-        goto yy9;
-      }
-yy11:
-      {
-        // Got a span of plain text.
-        int len = (int)(in - start);
-        // Need to shift it over if we're overwriting backslashes.
-        if (out < start)
-          memmove(out, start, len);
-        out += len;
-        continue;
-      }
-yy12:
-      yych = *++in;
-      if (yych == '$') goto yy14;
-      goto yy5;
-yy13:
-      yych = *(yymarker = ++in);
-      if (yych <= ' ') {
-        if (yych <= '\n') {
-          if (yych <= 0x00) goto yy5;
-          if (yych <= '\t') goto yy16;
-          goto yy17;
-        } else {
-          if (yych == '\r') goto yy19;
-          if (yych <= 0x1F) goto yy16;
-          goto yy21;
-        }
-      } else {
-        if (yych <= '9') {
-          if (yych == '#') goto yy23;
-          goto yy16;
-        } else {
-          if (yych <= ':') goto yy25;
-          if (yych == '\\') goto yy27;
-          goto yy16;
-        }
-      }
-yy14:
-      ++in;
-      {
-        // De-escape dollar character.
-        *out++ = '$';
-        continue;
-      }
-yy16:
-      ++in;
-      goto yy11;
-yy17:
-      ++in;
-      {
-        // A line continuation ends the current file name.
-        break;
-      }
-yy19:
-      yych = *++in;
-      if (yych == '\n') goto yy17;
-      in = yymarker;
-      goto yy5;
-yy21:
-      ++in;
-      {
-        // 2N+1 backslashes plus space -> N backslashes plus space.
-        int len = (int)(in - start);
-        int n = len / 2 - 1;
-        if (out < start)
-          memset(out, '\\', n);
-        out += n;
-        *out++ = ' ';
-        continue;
-      }
-yy23:
-      ++in;
-      {
-        // De-escape hash sign, but preserve other leading backslashes.
-        int len = (int)(in - start);
-        if (len > 2 && out < start)
-          memset(out, '\\', len - 2);
-        out += len - 2;
-        *out++ = '#';
-        continue;
-      }
-yy25:
-      yych = *++in;
-      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;
-          if (yych <= 0x1F) goto yy16;
-          goto yy30;
-        }
-      } else {
-        if (yych <= '9') {
-          if (yych == '#') goto yy23;
-          goto yy16;
-        } else {
-          if (yych <= ':') goto yy25;
-          if (yych == '\\') goto yy32;
-          goto yy16;
-        }
-      }
-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.
-        int len = (int)(in - start);
-        if (out < start)
-          memset(out, '\\', len - 1);
-        out += len - 1;
-        break;
-      }
-yy32:
-      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;
-          if (yych <= 0x1F) goto yy16;
-          goto yy21;
-        }
-      } else {
-        if (yych <= '9') {
-          if (yych == '#') goto yy23;
-          goto yy16;
-        } else {
-          if (yych <= ':') goto yy25;
-          if (yych == '\\') goto yy27;
-          goto yy16;
-        }
-      }
-    }
-
-    }
-
-    int len = (int)(out - filename);
-    const bool is_dependency = !parsing_targets;
-    if (len > 0 && filename[len - 1] == ':') {
-      len--;  // Strip off trailing colon, if any.
-      parsing_targets = false;
-      have_target = true;
-    }
-
-    if (len > 0) {
-      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;
-          }
-          // 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);
-        }
-      } 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;
-      poisoned_input = false;
-    }
-  }
-  if (!have_target) {
-    *err = "expected ':' in depfile";
-    return false;
-  }
-  return true;
-}
diff --git a/src/depfile_parser.h b/src/depfile_parser.h
deleted file mode 100644
index 88210dc..0000000
--- a/src/depfile_parser.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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.
-
-#ifndef NINJA_DEPFILE_PARSER_H_
-#define NINJA_DEPFILE_PARSER_H_
-
-#include <string>
-#include <vector>
-
-#include "string_piece.h"
-
-struct DepfileParserOptions {
-  DepfileParserOptions() {}
-
-  bool operator==(const DepfileParserOptions&) const {
-    // struct is empty so always return true for now.
-    return true;
-  }
-};
-
-/// Parser for the dependency information emitted by gcc's -M flags.
-struct DepfileParser {
-  explicit DepfileParser(DepfileParserOptions options =
-                         DepfileParserOptions());
-
-  /// 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(std::string* content, std::string* err);
-
-  std::vector<StringPiece> outs_;
-  std::vector<StringPiece> ins_;
-  DepfileParserOptions options_;
-};
-
-#endif // NINJA_DEPFILE_PARSER_H_
diff --git a/src/depfile_parser.in.cc b/src/depfile_parser.in.cc
deleted file mode 100644
index 75ba982..0000000
--- a/src/depfile_parser.in.cc
+++ /dev/null
@@ -1,207 +0,0 @@
-// 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.
-
-#include "depfile_parser.h"
-#include "util.h"
-
-#include <algorithm>
-
-using namespace std;
-
-DepfileParser::DepfileParser(DepfileParserOptions options)
-  : options_(options)
-{
-}
-
-// A note on backslashes in Makefiles, from reading the docs:
-// Backslash-newline is the line continuation character.
-// Backslash-# escapes a # (otherwise meaningful as a comment start).
-// Backslash-% escapes a % (otherwise meaningful as a special).
-// Finally, quoting the GNU manual, "Backslashes that are not in danger
-// of quoting ‘%’ characters go unmolested."
-// How do you end a line with a backslash?  The netbsd Make docs suggest
-// reading the result of a shell command echoing a backslash!
-//
-// Rather than implement all of above, we follow what GCC/Clang produces:
-// Backslashes escape a space or hash sign.
-// When a space is preceded by 2N+1 backslashes, it is represents N backslashes
-// followed by space.
-// When a space is preceded by 2N backslashes, it represents 2N backslashes at
-// the end of a filename.
-// A hash sign is escaped by a single backslash. All other backslashes remain
-// unchanged.
-//
-// If anyone actually has depfiles that rely on the more complicated
-// behavior we can adjust this.
-bool DepfileParser::Parse(string* content, string* err) {
-  // in: current parser input point.
-  // end: end of input.
-  // parsing_targets: whether we are parsing targets or dependencies.
-  char* in = &(*content)[0];
-  char* end = in + content->size();
-  bool have_target = 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
-    // as we de-escape backslashes).
-    char* out = in;
-    // filename: start of the current parsed filename.
-    char* filename = out;
-    for (;;) {
-      // start: beginning of the current parsed span.
-      const char* start = in;
-      char* yymarker = NULL;
-      /*!re2c
-      re2c:define:YYCTYPE = "unsigned char";
-      re2c:define:YYCURSOR = in;
-      re2c:define:YYLIMIT = end;
-      re2c:define:YYMARKER = yymarker;
-
-      re2c:yyfill:enable = 0;
-
-      re2c:indent:top = 2;
-      re2c:indent:string = "  ";
-
-      nul = "\000";
-      newline = '\r'?'\n';
-
-      '\\\\'* '\\ ' {
-        // 2N+1 backslashes plus space -> N backslashes plus space.
-        int len = (int)(in - start);
-        int n = len / 2 - 1;
-        if (out < start)
-          memset(out, '\\', n);
-        out += n;
-        *out++ = ' ';
-        continue;
-      }
-      '\\\\'+ ' ' {
-        // 2N backslashes plus space -> 2N backslashes, end of filename.
-        int len = (int)(in - start);
-        if (out < start)
-          memset(out, '\\', len - 1);
-        out += len - 1;
-        break;
-      }
-      '\\'+ '#' {
-        // De-escape hash sign, but preserve other leading backslashes.
-        int len = (int)(in - start);
-        if (len > 2 && out < start)
-          memset(out, '\\', len - 2);
-        out += len - 2;
-        *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++ = '$';
-        continue;
-      }
-      '\\'+ [^\000\r\n] | [a-zA-Z0-9+,/_:.~()}{%=@\x5B\x5D!\x80-\xFF-]+ {
-        // Got a span of plain text.
-        int len = (int)(in - start);
-        // Need to shift it over if we're overwriting backslashes.
-        if (out < start)
-          memmove(out, start, len);
-        out += len;
-        continue;
-      }
-      nul {
-        break;
-      }
-      '\\' newline {
-        // A line continuation ends the current file name.
-        break;
-      }
-      newline {
-        // A newline ends the current file name and the current rule.
-        have_newline = true;
-        break;
-      }
-      [^] {
-        // For any other character (e.g. whitespace), swallow it here,
-        // allowing the outer logic to loop around again.
-        break;
-      }
-      */
-    }
-
-    int len = (int)(out - filename);
-    const bool is_dependency = !parsing_targets;
-    if (len > 0 && filename[len - 1] == ':') {
-      len--;  // Strip off trailing colon, if any.
-      parsing_targets = false;
-      have_target = true;
-    }
-
-    if (len > 0) {
-      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;
-          }
-          // 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);
-        }
-      } 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;
-      poisoned_input = false;
-    }
-  }
-  if (!have_target) {
-    *err = "expected ':' in depfile";
-    return false;
-  }
-  return true;
-}
diff --git a/src/depfile_parser_perftest.cc b/src/depfile_parser_perftest.cc
deleted file mode 100644
index 52555e6..0000000
--- a/src/depfile_parser_perftest.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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.
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "depfile_parser.h"
-#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]);
-    return 1;
-  }
-
-  vector<float> times;
-  for (int i = 1; i < argc; ++i) {
-    const char* filename = argv[i];
-
-    for (int limit = 1 << 10; limit < (1<<20); limit *= 2) {
-      int64_t start = GetTimeMillis();
-      for (int rep = 0; rep < limit; ++rep) {
-        string buf;
-        string err;
-        if (ReadFile(filename, &buf, &err) < 0) {
-          printf("%s: %s\n", filename, err.c_str());
-          return 1;
-        }
-
-        DepfileParser parser;
-        if (!parser.Parse(&buf, &err)) {
-          printf("%s: %s\n", filename, err.c_str());
-          return 1;
-        }
-      }
-      int64_t end = GetTimeMillis();
-
-      if (end - start > 100) {
-        int delta = (int)(end - start);
-        float time = delta*1000 / (float)limit;
-        printf("%s: %.1fus\n", filename, time);
-        times.push_back(time);
-        break;
-      }
-    }
-  }
-
-  if (!times.empty()) {
-    float min = times[0];
-    float max = times[0];
-    float total = 0;
-    for (size_t i = 0; i < times.size(); ++i) {
-      total += times[i];
-      if (times[i] < min)
-        min = times[i];
-      else if (times[i] > max)
-        max = times[i];
-    }
-
-    printf("min %.1fus  max %.1fus  avg %.1fus\n",
-           min, max, total / times.size());
-  }
-
-  return 0;
-}
diff --git a/src/depfile_parser_test.cc b/src/depfile_parser_test.cc
deleted file mode 100644
index 8886258..0000000
--- a/src/depfile_parser_test.cc
+++ /dev/null
@@ -1,380 +0,0 @@
-// 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.
-
-#include "depfile_parser.h"
-
-#include "test.h"
-
-using namespace std;
-
-struct DepfileParserTest : public testing::Test {
-  bool Parse(const char* input, string* err);
-
-  DepfileParser parser_;
-  string input_;
-};
-
-bool DepfileParserTest::Parse(const char* input, string* err) {
-  input_ = input;
-  return parser_.Parse(&input_, err);
-}
-
-TEST_F(DepfileParserTest, Basic) {
-  string err;
-  EXPECT_TRUE(Parse(
-"build/ninja.o: ninja.cc ninja.h eval_env.h manifest_parser.h\n",
-      &err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, parser_.outs_.size());
-  EXPECT_EQ("build/ninja.o", parser_.outs_[0].AsString());
-  EXPECT_EQ(4u, parser_.ins_.size());
-}
-
-TEST_F(DepfileParserTest, EarlyNewlineAndWhitespace) {
-  string err;
-  EXPECT_TRUE(Parse(
-" \\\n"
-"  out: in\n",
-      &err));
-  ASSERT_EQ("", err);
-}
-
-TEST_F(DepfileParserTest, Continuation) {
-  string err;
-  EXPECT_TRUE(Parse(
-"foo.o: \\\n"
-"  bar.h baz.h\n",
-      &err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, parser_.outs_.size());
-  EXPECT_EQ("foo.o", parser_.outs_[0].AsString());
-  EXPECT_EQ(2u, parser_.ins_.size());
-}
-
-TEST_F(DepfileParserTest, CarriageReturnContinuation) {
-  string err;
-  EXPECT_TRUE(Parse(
-"foo.o: \\\r\n"
-"  bar.h baz.h\r\n",
-      &err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, parser_.outs_.size());
-  EXPECT_EQ("foo.o", parser_.outs_[0].AsString());
-  EXPECT_EQ(2u, parser_.ins_.size());
-}
-
-TEST_F(DepfileParserTest, BackSlashes) {
-  string err;
-  EXPECT_TRUE(Parse(
-"Project\\Dir\\Build\\Release8\\Foo\\Foo.res : \\\n"
-"  Dir\\Library\\Foo.rc \\\n"
-"  Dir\\Library\\Version\\Bar.h \\\n"
-"  Dir\\Library\\Foo.ico \\\n"
-"  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_.outs_[0].AsString());
-  EXPECT_EQ(4u, parser_.ins_.size());
-}
-
-TEST_F(DepfileParserTest, Spaces) {
-  string err;
-  EXPECT_TRUE(Parse(
-"a\\ bc\\ def:   a\\ b c d",
-      &err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, parser_.outs_.size());
-  EXPECT_EQ("a bc def",
-            parser_.outs_[0].AsString());
-  ASSERT_EQ(3u, parser_.ins_.size());
-  EXPECT_EQ("a b",
-            parser_.ins_[0].AsString());
-  EXPECT_EQ("c",
-            parser_.ins_[1].AsString());
-  EXPECT_EQ("d",
-            parser_.ins_[2].AsString());
-}
-
-TEST_F(DepfileParserTest, MultipleBackslashes) {
-  // Successive 2N+1 backslashes followed by space (' ') are replaced by N >= 0
-  // backslashes and the space. A single backslash before hash sign is removed.
-  // Other backslashes remain untouched (including 2N backslashes followed by
-  // space).
-  string err;
-  EXPECT_TRUE(Parse(
-"a\\ b\\#c.h: \\\\\\\\\\  \\\\\\\\ \\\\share\\info\\\\#1",
-      &err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, parser_.outs_.size());
-  EXPECT_EQ("a b#c.h",
-            parser_.outs_[0].AsString());
-  ASSERT_EQ(3u, parser_.ins_.size());
-  EXPECT_EQ("\\\\ ",
-            parser_.ins_[0].AsString());
-  EXPECT_EQ("\\\\\\\\",
-            parser_.ins_[1].AsString());
-  EXPECT_EQ("\\\\share\\info\\#1",
-            parser_.ins_[2].AsString());
-}
-
-TEST_F(DepfileParserTest, Escapes) {
-  // Put backslashes before a variety of characters, see which ones make
-  // it through.
-  string err;
-  EXPECT_TRUE(Parse(
-"\\!\\@\\#$$\\%\\^\\&\\[\\]\\\\:",
-      &err));
-  ASSERT_EQ("", err);
-  ASSERT_EQ(1u, parser_.outs_.size());
-  EXPECT_EQ("\\!\\@#$\\%\\^\\&\\[\\]\\\\",
-            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/
-  string err;
-  EXPECT_TRUE(Parse(
-"C:/Program\\ Files\\ (x86)/Microsoft\\ crtdefs.h: \\\n"
-" en@quot.header~ t+t-x!=1 \\\n"
-" openldap/slapd.d/cn=config/cn=schema/cn={0}core.ldif\\\n"
-" Fu\303\244ball\\\n"
-" 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_.outs_[0].AsString());
-  ASSERT_EQ(5u, parser_.ins_.size());
-  EXPECT_EQ("en@quot.header~",
-            parser_.ins_[0].AsString());
-  EXPECT_EQ("t+t-x!=1",
-            parser_.ins_[1].AsString());
-  EXPECT_EQ("openldap/slapd.d/cn=config/cn=schema/cn={0}core.ldif",
-            parser_.ins_[2].AsString());
-  EXPECT_EQ("Fu\303\244ball",
-            parser_.ins_[3].AsString());
-  EXPECT_EQ("a[1]b@2%c",
-            parser_.ins_[4].AsString());
-}
-
-TEST_F(DepfileParserTest, UnifyMultipleOutputs) {
-  // check that multiple duplicate targets are properly unified
-  string err;
-  EXPECT_TRUE(Parse("foo foo: x y z", &err));
-  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, MultipleDifferentOutputs) {
-  // check that multiple different outputs are accepted by the parser
-  string 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) {
-  string err;
-  EXPECT_TRUE(Parse("foo: x\n"
-                    "foo: \n"
-                    "foo:\n", &err));
-  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());
-}
-
-TEST_F(DepfileParserTest, UnifyMultipleRulesLF) {
-  string err;
-  EXPECT_TRUE(Parse("foo: x\n"
-                    "foo: y\n"
-                    "foo \\\n"
-                    "foo: z\n", &err));
-  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, UnifyMultipleRulesCRLF) {
-  string err;
-  EXPECT_TRUE(Parse("foo: x\r\n"
-                    "foo: y\r\n"
-                    "foo \\\r\n"
-                    "foo: z\r\n", &err));
-  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, UnifyMixedRulesLF) {
-  string err;
-  EXPECT_TRUE(Parse("foo: x\\\n"
-                    "     y\n"
-                    "foo \\\n"
-                    "foo: z\n", &err));
-  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, UnifyMixedRulesCRLF) {
-  string err;
-  EXPECT_TRUE(Parse("foo: x\\\r\n"
-                    "     y\r\n"
-                    "foo \\\r\n"
-                    "foo: z\r\n", &err));
-  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, IndentedRulesLF) {
-  string err;
-  EXPECT_TRUE(Parse(" foo: x\n"
-                    " foo: y\n"
-                    " foo: z\n", &err));
-  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, IndentedRulesCRLF) {
-  string err;
-  EXPECT_TRUE(Parse(" foo: x\r\n"
-                    " foo: y\r\n"
-                    " foo: z\r\n", &err));
-  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, TolerateMP) {
-  string err;
-  EXPECT_TRUE(Parse("foo: x y z\n"
-                    "x:\n"
-                    "y:\n"
-                    "z:\n", &err));
-  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, MultipleRulesTolerateMP) {
-  string err;
-  EXPECT_TRUE(Parse("foo: x\n"
-                    "x:\n"
-                    "foo: y\n"
-                    "y:\n"
-                    "foo: z\n"
-                    "z:\n", &err));
-  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, MultipleRulesDifferentOutputs) {
-  // check that multiple different outputs are accepted by the parser
-  // when spread across multiple rules
-  string 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
deleted file mode 100644
index b728379..0000000
--- a/src/deps_log.cc
+++ /dev/null
@@ -1,454 +0,0 @@
-// Copyright 2012 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 "deps_log.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#ifndef _WIN32
-#include <unistd.h>
-#elif defined(_MSC_VER) && (_MSC_VER < 1900)
-typedef __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-#endif
-
-#include "graph.h"
-#include "metrics.h"
-#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";
-const int kCurrentVersion = 4;
-
-// Record size is currently limited to less than the full 32 bit, due to
-// internal buffers having to have this size.
-const unsigned kMaxRecordSize = (1 << 19) - 1;
-
-DepsLog::~DepsLog() {
-  Close();
-  for (const Deps* deps : deps_)
-    delete deps;
-}
-
-bool DepsLog::OpenForWrite(const string& path, string* err) {
-  if (needs_recompaction_) {
-    if (!Recompact(path, err))
-      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;
-}
-
-bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
-                         const vector<Node*>& nodes) {
-  return RecordDeps(node, mtime, nodes.size(),
-                    nodes.empty() ? NULL : (Node**)&nodes.front());
-}
-
-bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
-                         int node_count, Node** nodes) {
-  // Track whether there's any new data to be recorded.
-  bool made_change = false;
-
-  // Assign ids to all nodes that are missing one.
-  if (node->id() < 0) {
-    if (!RecordId(node))
-      return false;
-    made_change = true;
-  }
-  for (int i = 0; i < node_count; ++i) {
-    if (nodes[i]->id() < 0) {
-      if (!RecordId(nodes[i]))
-        return false;
-      made_change = true;
-    }
-  }
-
-  // See if the new data is different than the existing data, if any.
-  if (!made_change) {
-    Deps* deps = GetDeps(node);
-    if (!deps ||
-        deps->mtime != mtime ||
-        deps->node_count != node_count) {
-      made_change = true;
-    } else {
-      for (int i = 0; i < node_count; ++i) {
-        if (deps->nodes[i] != nodes[i]) {
-          made_change = true;
-          break;
-        }
-      }
-    }
-  }
-
-  // Don't write anything if there's no new info.
-  if (!made_change)
-    return true;
-
-  // Update on-disk representation.
-  unsigned size = 4 * (1 + 2 + node_count);
-  if (size > kMaxRecordSize) {
-    errno = ERANGE;
-    return false;
-  }
-
-  if (!OpenForWriteIfNeeded()) {
-    return false;
-  }
-  size |= 0x80000000;  // Deps record: set high bit.
-  if (fwrite(&size, 4, 1, file_) < 1)
-    return false;
-  int id = node->id();
-  if (fwrite(&id, 4, 1, file_) < 1)
-    return false;
-  uint32_t mtime_part = static_cast<uint32_t>(mtime & 0xffffffff);
-  if (fwrite(&mtime_part, 4, 1, file_) < 1)
-    return false;
-  mtime_part = static_cast<uint32_t>((mtime >> 32) & 0xffffffff);
-  if (fwrite(&mtime_part, 4, 1, file_) < 1)
-    return false;
-  for (int i = 0; i < node_count; ++i) {
-    id = nodes[i]->id();
-    if (fwrite(&id, 4, 1, file_) < 1)
-      return false;
-  }
-  if (fflush(file_) != 0)
-    return false;
-
-  // Update in-memory representation.
-  Deps* deps = new Deps(mtime, node_count);
-  for (int i = 0; i < node_count; ++i)
-    deps->nodes[i] = nodes[i];
-  UpdateDeps(node->id(), deps);
-
-  return true;
-}
-
-void DepsLog::Close() {
-  OpenForWriteIfNeeded();  // create the file even if nothing has been recorded
-  if (file_)
-    fclose(file_);
-  file_ = NULL;
-}
-
-LoadStatus DepsLog::Load(const string& path, State* state, string* err) {
-  METRIC_RECORD_LOAD(".ninja_deps load");
-  char buf[kMaxRecordSize + 1];
-  FILE* f = fopen(path.c_str(), "rb");
-  if (!f) {
-    if (errno == ENOENT)
-      return LOAD_NOT_FOUND;
-    *err = strerror(errno);
-    return LOAD_ERROR;
-  }
-
-  bool valid_header = true;
-  int version = 0;
-  if (!fgets(buf, sizeof(buf), f) || fread(&version, 4, 1, f) < 1)
-    valid_header = false;
-  // Note: For version differences, this should migrate to the new format.
-  // But the v1 format could sometimes (rarely) end up with invalid data, so
-  // don't migrate v1 to v3 to force a rebuild. (v2 only existed for a few days,
-  // and there was no release with it, so pretend that it never happened.)
-  if (!valid_header || strcmp(buf, kFileSignature) != 0 ||
-      version != kCurrentVersion) {
-    if (version == 1)
-      *err = "deps log version change; rebuilding";
-    else
-      *err = "bad deps log signature or version; starting over";
-    fclose(f);
-    unlink(path.c_str());
-    // Don't report this as a failure.  An empty deps log will cause
-    // us to rebuild the outputs anyway.
-    return LOAD_SUCCESS;
-  }
-
-  long offset;
-  bool read_failed = false;
-  int unique_dep_record_count = 0;
-  int total_dep_record_count = 0;
-  for (;;) {
-    offset = ftell(f);
-
-    unsigned size;
-    if (fread(&size, 4, 1, f) < 1) {
-      if (!feof(f))
-        read_failed = true;
-      break;
-    }
-    bool is_deps = (size >> 31) != 0;
-    size = size & 0x7FFFFFFF;
-
-    if (size > kMaxRecordSize || fread(buf, size, 1, f) < 1) {
-      read_failed = true;
-      break;
-    }
-
-    if (is_deps) {
-      assert(size % 4 == 0);
-      int* deps_data = reinterpret_cast<int*>(buf);
-      int out_id = deps_data[0];
-      TimeStamp mtime;
-      mtime = (TimeStamp)(((uint64_t)(unsigned int)deps_data[2] << 32) |
-                          (uint64_t)(unsigned int)deps_data[1]);
-      deps_data += 3;
-      int deps_count = (size / 4) - 3;
-
-      Deps* deps = new Deps(mtime, deps_count);
-      for (int i = 0; i < deps_count; ++i) {
-        assert(deps_data[i] < (int)nodes_.size());
-        assert(nodes_[deps_data[i]]);
-        deps->nodes[i] = nodes_[deps_data[i]];
-      }
-
-      total_dep_record_count++;
-      if (!UpdateDeps(out_id, deps))
-        ++unique_dep_record_count;
-    } else {
-      int path_size = size - 4;
-      assert(path_size > 0);  // CanonicalizePath() rejects empty paths.
-      // There can be up to 3 bytes of padding.
-      if (buf[path_size - 1] == '\0') --path_size;
-      if (buf[path_size - 1] == '\0') --path_size;
-      if (buf[path_size - 1] == '\0') --path_size;
-      StringPiece subpath(buf, path_size);
-      // It is not necessary to pass in a correct slash_bits here. It will
-      // either be a Node that's in the manifest (in which case it will already
-      // have a correct slash_bits that GetNode will look up), or it is an
-      // implicit dependency from a .d which does not affect the build command
-      // (and so need not have its slashes maintained).
-      Node* node = state->GetNode(subpath, 0);
-
-      // Check that the expected index matches the actual index. This can only
-      // happen if two ninja processes write to the same deps log concurrently.
-      // (This uses unary complement to make the checksum look less like a
-      // dependency record entry.)
-      unsigned checksum = *reinterpret_cast<unsigned*>(buf + size - 4);
-      int expected_id = ~checksum;
-      int id = nodes_.size();
-      if (id != expected_id) {
-        read_failed = true;
-        break;
-      }
-
-      assert(node->id() < 0);
-      node->set_id(id);
-      nodes_.push_back(node);
-    }
-  }
-
-  if (read_failed) {
-    // An error occurred while loading; try to recover by truncating the
-    // file to the last fully-read record.
-    if (ferror(f)) {
-      *err = strerror(ferror(f));
-    } else {
-      *err = "premature end of file";
-    }
-    fclose(f);
-
-    if (!Truncate(path, offset, err))
-      return LOAD_ERROR;
-
-    // The truncate succeeded; we'll just report the load error as a
-    // warning because the build can proceed.
-    *err += "; recovering";
-    return LOAD_SUCCESS;
-  }
-
-  fclose(f);
-
-  // Rebuild the log if there are too many dead records.
-  int kMinCompactionEntryCount = 1000;
-  int kCompactionRatio = 3;
-  if (total_dep_record_count > kMinCompactionEntryCount &&
-      total_dep_record_count > unique_dep_record_count * kCompactionRatio) {
-    needs_recompaction_ = true;
-  }
-
-  return LOAD_SUCCESS;
-}
-
-DepsLog::Deps* DepsLog::GetDeps(Node* node) {
-  // Abort if the node has no id (never referenced in the deps) or if
-  // there's no deps recorded for the node.
-  if (node->id() < 0 || node->id() >= (int)deps_.size())
-    return NULL;
-  return deps_[node->id()];
-}
-
-Node* DepsLog::GetFirstReverseDepsNode(Node* node) {
-  for (size_t id = 0; id < deps_.size(); ++id) {
-    Deps* deps = deps_[id];
-    if (!deps)
-      continue;
-    for (int i = 0; i < deps->node_count; ++i) {
-      if (deps->nodes[i] == node)
-        return nodes_[id];
-    }
-  }
-  return NULL;
-}
-
-bool DepsLog::Recompact(const string& path, string* err) {
-  METRIC_RECORD(".ninja_deps recompact");
-
-  Close();
-  string temp_path = path + ".recompact";
-
-  // OpenForWrite() opens for append.  Make sure it's not appending to a
-  // left-over file from a previous recompaction attempt that crashed somehow.
-  unlink(temp_path.c_str());
-
-  DepsLog new_log;
-  if (!new_log.OpenForWrite(temp_path, err))
-    return false;
-
-  // Clear all known ids so that new ones can be reassigned.  The new indices
-  // will refer to the ordering in new_log, not in the current log.
-  for (vector<Node*>::iterator i = nodes_.begin(); i != nodes_.end(); ++i)
-    (*i)->set_id(-1);
-
-  // Write out all deps again.
-  for (int old_id = 0; old_id < (int)deps_.size(); ++old_id) {
-    Deps* deps = deps_[old_id];
-    if (!deps) continue;  // If nodes_[old_id] is a leaf, it has no deps.
-
-    if (!IsDepsEntryLiveFor(nodes_[old_id]))
-      continue;
-
-    if (!new_log.RecordDeps(nodes_[old_id], deps->mtime,
-                            deps->node_count, deps->nodes)) {
-      new_log.Close();
-      return false;
-    }
-  }
-
-  new_log.Close();
-
-  // All nodes now have ids that refer to new_log, so steal its data.
-  deps_.swap(new_log.deps_);
-  nodes_.swap(new_log.nodes_);
-
-  if (unlink(path.c_str()) < 0) {
-    *err = strerror(errno);
-    return false;
-  }
-
-  if (rename(temp_path.c_str(), path.c_str()) < 0) {
-    *err = strerror(errno);
-    return false;
-  }
-
-  return true;
-}
-
-bool DepsLog::IsDepsEntryLiveFor(const Node* node) {
-  // Skip entries that don't have in-edges or whose edges don't have a
-  // "deps" attribute. They were in the deps log from previous builds, but
-  // the the files they were for were removed from the build and their deps
-  // entries are no longer needed.
-  // (Without the check for "deps", a chain of two or more nodes that each
-  // had deps wouldn't be collected in a single recompaction.)
-  return node->in_edge() && !node->in_edge()->GetBinding("deps").empty();
-}
-
-bool DepsLog::UpdateDeps(int out_id, Deps* deps) {
-  if (out_id >= (int)deps_.size()) {
-    deps_.resize(out_id + 1);
-  }
-
-  bool delete_old = deps_[out_id] != NULL;
-  if (delete_old)
-    delete deps_[out_id];
-  deps_[out_id] = deps;
-  return delete_old;
-}
-
-bool DepsLog::RecordId(Node* node) {
-  int path_size = node->path().size();
-  int padding = (4 - path_size % 4) % 4;  // Pad path to 4 byte boundary.
-
-  unsigned size = path_size + padding + 4;
-  if (size > kMaxRecordSize) {
-    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().empty());
-    return false;
-  }
-  if (padding && fwrite("\0\0", padding, 1, file_) < 1)
-    return false;
-  int id = nodes_.size();
-  unsigned checksum = ~(unsigned)id;
-  if (fwrite(&checksum, 4, 1, file_) < 1)
-    return false;
-  if (fflush(file_) != 0)
-    return false;
-
-  node->set_id(id);
-  nodes_.push_back(node);
-
-  return true;
-}
-
-bool DepsLog::OpenForWriteIfNeeded() {
-  if (file_path_.empty()) {
-    return true;
-  }
-  file_ = fopen(file_path_.c_str(), "ab");
-  if (!file_) {
-    return false;
-  }
-  // Set the buffer size to this and flush the file buffer after every record
-  // to make sure records aren't written partially.
-  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
deleted file mode 100644
index 166310f..0000000
--- a/src/deps_log.h
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2012 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_DEPS_LOG_H_
-#define NINJA_DEPS_LOG_H_
-
-#include <string>
-#include <vector>
-
-#include <stdio.h>
-
-#include "load_status.h"
-#include "timestamp.h"
-
-struct Node;
-struct State;
-
-/// As build commands run they can output extra dependency information
-/// (e.g. header dependencies for C source) dynamically.  DepsLog collects
-/// that information at build time and uses it for subsequent builds.
-///
-/// The on-disk format is based on two primary design constraints:
-/// - it must be written to as a stream (during the build, which may be
-///   interrupted);
-/// - it can be read all at once on startup.  (Alternative designs, where
-///   it contains indexing information, were considered and discarded as
-///   too complicated to implement; if the file is small than reading it
-///   fully on startup is acceptable.)
-/// Here are some stats from the Windows Chrome dependency files, to
-/// help guide the design space.  The total text in the files sums to
-/// 90mb so some compression is warranted to keep load-time fast.
-/// There's about 10k files worth of dependencies that reference about
-/// 40k total paths totalling 2mb of unique strings.
-///
-/// Based on these stats, here's the current design.
-/// The file is structured as version header followed by a sequence of records.
-/// Each record is either a path string or a dependency list.
-/// Numbering the path strings in file order gives them dense integer ids.
-/// A dependency list maps an output id to a list of input ids.
-///
-/// Concretely, a record is:
-///    four bytes record length, high bit indicates record type
-///      (but max record sizes are capped at 512kB)
-///    path records contain the string name of the path, followed by up to 3
-///      padding bytes to align on 4 byte boundaries, followed by the
-///      one's complement of the expected index of the record (to detect
-///      concurrent writes of multiple ninja processes to the log).
-///    dependency records are an array of 4-byte integers
-///      [output path id,
-///       output path mtime (lower 4 bytes), output path mtime (upper 4 bytes),
-///       input path id, input path id...]
-///      (The mtime is compared against the on-disk output path mtime
-///      to verify the stored data is up-to-date.)
-/// If two records reference the same output the latter one in the file
-/// wins, allowing updates to just be appended to the file.  A separate
-/// repacking step can run occasionally to remove dead records.
-struct DepsLog {
-  DepsLog() : needs_recompaction_(false), file_(NULL) {}
-  ~DepsLog();
-
-  // Writing (build-time) interface.
-  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();
-
-  // Reading (startup-time) interface.
-  struct Deps {
-    Deps(int64_t mtime, int node_count)
-        : mtime(mtime), node_count(node_count), nodes(new Node*[node_count]) {}
-    ~Deps() { delete [] nodes; }
-    TimeStamp mtime;
-    int node_count;
-    Node** nodes;
-  };
-  LoadStatus Load(const std::string& path, State* state, std::string* err);
-  Deps* GetDeps(Node* node);
-  Node* GetFirstReverseDepsNode(Node* node);
-
-  /// Rewrite the known log entries, throwing away old data.
-  bool Recompact(const std::string& path, std::string* err);
-
-  /// Returns if the deps entry for a node is still reachable from the manifest.
-  ///
-  /// The deps log can contain deps entries for files that were built in the
-  /// past but are no longer part of the manifest.  This function returns if
-  /// this is the case for a given node.  This function is slow, don't call
-  /// it from code that runs on every build.
-  static bool IsDepsEntryLiveFor(const Node* node);
-
-  /// Used for tests.
-  const std::vector<Node*>& nodes() const { return nodes_; }
-  const std::vector<Deps*>& deps() const { return deps_; }
-
-  /// Return the number of output paths in the deps log.
-  size_t size() const { return nodes_.size(); }
-
- private:
-  // Updates the in-memory representation.  Takes ownership of |deps|.
-  // Returns true if a prior deps record was deleted.
-  bool UpdateDeps(int out_id, Deps* deps);
-  // 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.
-  std::vector<Node*> nodes_;
-  /// Maps id -> deps of that id.
-  std::vector<Deps*> deps_;
-
-  friend struct DepsLogTest;
-};
-
-#endif  // NINJA_DEPS_LOG_H_
diff --git a/src/deps_log_test.cc b/src/deps_log_test.cc
deleted file mode 100644
index 274e700..0000000
--- a/src/deps_log_test.cc
+++ /dev/null
@@ -1,545 +0,0 @@
-// Copyright 2012 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 "deps_log.h"
-
-#include <sys/stat.h>
-#ifndef _WIN32
-#include <unistd.h>
-#endif
-
-#include "graph.h"
-#include "util.h"
-#include "test.h"
-
-using namespace std;
-
-namespace {
-
-const char kTestFilename[] = "DepsLogTest-tempfile";
-
-struct DepsLogTest : public testing::Test {
-  virtual void SetUp() {
-    // In case a crashing test left a stale file behind.
-    unlink(kTestFilename);
-  }
-  virtual void TearDown() {
-    unlink(kTestFilename);
-  }
-};
-
-TEST_F(DepsLogTest, WriteRead) {
-  State state1;
-  DepsLog log1;
-  string err;
-  EXPECT_TRUE(log1.OpenForWrite(kTestFilename, &err));
-  ASSERT_EQ("", err);
-
-  {
-    vector<Node*> deps;
-    deps.push_back(state1.GetNode("foo.h", 0));
-    deps.push_back(state1.GetNode("bar.h", 0));
-    log1.RecordDeps(state1.GetNode("out.o", 0), 1, deps);
-
-    deps.clear();
-    deps.push_back(state1.GetNode("foo.h", 0));
-    deps.push_back(state1.GetNode("bar2.h", 0));
-    log1.RecordDeps(state1.GetNode("out2.o", 0), 2, deps);
-
-    DepsLog::Deps* log_deps = log1.GetDeps(state1.GetNode("out.o", 0));
-    ASSERT_TRUE(log_deps);
-    ASSERT_EQ(1, log_deps->mtime);
-    ASSERT_EQ(2, log_deps->node_count);
-    ASSERT_EQ("foo.h", log_deps->nodes[0]->path());
-    ASSERT_EQ("bar.h", log_deps->nodes[1]->path());
-  }
-
-  log1.Close();
-
-  State state2;
-  DepsLog log2;
-  EXPECT_TRUE(log2.Load(kTestFilename, &state2, &err));
-  ASSERT_EQ("", err);
-
-  ASSERT_EQ(log1.nodes().size(), log2.nodes().size());
-  for (int i = 0; i < (int)log1.nodes().size(); ++i) {
-    Node* node1 = log1.nodes()[i];
-    Node* node2 = log2.nodes()[i];
-    ASSERT_EQ(i, node1->id());
-    ASSERT_EQ(node1->id(), node2->id());
-  }
-
-  // Spot-check the entries in log2.
-  DepsLog::Deps* log_deps = log2.GetDeps(state2.GetNode("out2.o", 0));
-  ASSERT_TRUE(log_deps);
-  ASSERT_EQ(2, log_deps->mtime);
-  ASSERT_EQ(2, log_deps->node_count);
-  ASSERT_EQ("foo.h", log_deps->nodes[0]->path());
-  ASSERT_EQ("bar2.h", log_deps->nodes[1]->path());
-}
-
-TEST_F(DepsLogTest, LotsOfDeps) {
-  const int kNumDeps = 100000;  // More than 64k.
-
-  State state1;
-  DepsLog log1;
-  string err;
-  EXPECT_TRUE(log1.OpenForWrite(kTestFilename, &err));
-  ASSERT_EQ("", err);
-
-  {
-    vector<Node*> deps;
-    for (int i = 0; i < kNumDeps; ++i) {
-      char buf[32];
-      sprintf(buf, "file%d.h", i);
-      deps.push_back(state1.GetNode(buf, 0));
-    }
-    log1.RecordDeps(state1.GetNode("out.o", 0), 1, deps);
-
-    DepsLog::Deps* log_deps = log1.GetDeps(state1.GetNode("out.o", 0));
-    ASSERT_EQ(kNumDeps, log_deps->node_count);
-  }
-
-  log1.Close();
-
-  State state2;
-  DepsLog log2;
-  EXPECT_TRUE(log2.Load(kTestFilename, &state2, &err));
-  ASSERT_EQ("", err);
-
-  DepsLog::Deps* log_deps = log2.GetDeps(state2.GetNode("out.o", 0));
-  ASSERT_EQ(kNumDeps, log_deps->node_count);
-}
-
-// Verify that adding the same deps twice doesn't grow the file.
-TEST_F(DepsLogTest, DoubleEntry) {
-  // Write some deps to the file and grab its size.
-  int file_size;
-  {
-    State state;
-    DepsLog log;
-    string err;
-    EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err));
-    ASSERT_EQ("", err);
-
-    vector<Node*> deps;
-    deps.push_back(state.GetNode("foo.h", 0));
-    deps.push_back(state.GetNode("bar.h", 0));
-    log.RecordDeps(state.GetNode("out.o", 0), 1, deps);
-    log.Close();
-#ifdef __USE_LARGEFILE64
-    struct stat64 st;
-    ASSERT_EQ(0, stat64(kTestFilename, &st));
-#else
-    struct stat st;
-    ASSERT_EQ(0, stat(kTestFilename, &st));
-#endif
-    file_size = (int)st.st_size;
-    ASSERT_GT(file_size, 0);
-  }
-
-  // Now reload the file, and read the same deps.
-  {
-    State state;
-    DepsLog log;
-    string err;
-    EXPECT_TRUE(log.Load(kTestFilename, &state, &err));
-
-    EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err));
-    ASSERT_EQ("", err);
-
-    vector<Node*> deps;
-    deps.push_back(state.GetNode("foo.h", 0));
-    deps.push_back(state.GetNode("bar.h", 0));
-    log.RecordDeps(state.GetNode("out.o", 0), 1, deps);
-    log.Close();
-#ifdef __USE_LARGEFILE64
-    struct stat64 st;
-    ASSERT_EQ(0, stat64(kTestFilename, &st));
-#else
-    struct stat st;
-    ASSERT_EQ(0, stat(kTestFilename, &st));
-#endif
-    int file_size_2 = (int)st.st_size;
-    ASSERT_EQ(file_size, file_size_2);
-  }
-}
-
-// Verify that adding the new deps works and can be compacted away.
-TEST_F(DepsLogTest, Recompact) {
-  const char kManifest[] =
-"rule cc\n"
-"  command = cc\n"
-"  deps = gcc\n"
-"build out.o: cc\n"
-"build other_out.o: cc\n";
-
-  // Write some deps to the file and grab its size.
-  int file_size;
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, kManifest));
-    DepsLog log;
-    string err;
-    ASSERT_TRUE(log.OpenForWrite(kTestFilename, &err));
-    ASSERT_EQ("", err);
-
-    vector<Node*> deps;
-    deps.push_back(state.GetNode("foo.h", 0));
-    deps.push_back(state.GetNode("bar.h", 0));
-    log.RecordDeps(state.GetNode("out.o", 0), 1, deps);
-
-    deps.clear();
-    deps.push_back(state.GetNode("foo.h", 0));
-    deps.push_back(state.GetNode("baz.h", 0));
-    log.RecordDeps(state.GetNode("other_out.o", 0), 1, deps);
-
-    log.Close();
-#ifdef __USE_LARGEFILE64
-    struct stat64 st;
-    ASSERT_EQ(0, stat64(kTestFilename, &st));
-#else
-    struct stat st;
-    ASSERT_EQ(0, stat(kTestFilename, &st));
-#endif
-    file_size = (int)st.st_size;
-    ASSERT_GT(file_size, 0);
-  }
-
-  // Now reload the file, and add slightly different deps.
-  int file_size_2;
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, kManifest));
-    DepsLog log;
-    string err;
-    ASSERT_TRUE(log.Load(kTestFilename, &state, &err));
-
-    ASSERT_TRUE(log.OpenForWrite(kTestFilename, &err));
-    ASSERT_EQ("", err);
-
-    vector<Node*> deps;
-    deps.push_back(state.GetNode("foo.h", 0));
-    log.RecordDeps(state.GetNode("out.o", 0), 1, deps);
-    log.Close();
-
-#ifdef __USE_LARGEFILE64
-    struct stat64 st;
-    ASSERT_EQ(0, stat64(kTestFilename, &st));
-#else
-    struct stat st;
-    ASSERT_EQ(0, stat(kTestFilename, &st));
-#endif
-    file_size_2 = (int)st.st_size;
-    // The file should grow to record the new deps.
-    ASSERT_GT(file_size_2, file_size);
-  }
-
-  // Now reload the file, verify the new deps have replaced the old, then
-  // recompact.
-  int file_size_3;
-  {
-    State state;
-    ASSERT_NO_FATAL_FAILURE(AssertParse(&state, kManifest));
-    DepsLog log;
-    string err;
-    ASSERT_TRUE(log.Load(kTestFilename, &state, &err));
-
-    Node* out = state.GetNode("out.o", 0);
-    DepsLog::Deps* deps = log.GetDeps(out);
-    ASSERT_TRUE(deps);
-    ASSERT_EQ(1, deps->mtime);
-    ASSERT_EQ(1, deps->node_count);
-    ASSERT_EQ("foo.h", deps->nodes[0]->path());
-
-    Node* other_out = state.GetNode("other_out.o", 0);
-    deps = log.GetDeps(other_out);
-    ASSERT_TRUE(deps);
-    ASSERT_EQ(1, deps->mtime);
-    ASSERT_EQ(2, deps->node_count);
-    ASSERT_EQ("foo.h", deps->nodes[0]->path());
-    ASSERT_EQ("baz.h", deps->nodes[1]->path());
-
-    ASSERT_TRUE(log.Recompact(kTestFilename, &err));
-
-    // The in-memory deps graph should still be valid after recompaction.
-    deps = log.GetDeps(out);
-    ASSERT_TRUE(deps);
-    ASSERT_EQ(1, deps->mtime);
-    ASSERT_EQ(1, deps->node_count);
-    ASSERT_EQ("foo.h", deps->nodes[0]->path());
-    ASSERT_EQ(out, log.nodes()[out->id()]);
-
-    deps = log.GetDeps(other_out);
-    ASSERT_TRUE(deps);
-    ASSERT_EQ(1, deps->mtime);
-    ASSERT_EQ(2, deps->node_count);
-    ASSERT_EQ("foo.h", deps->nodes[0]->path());
-    ASSERT_EQ("baz.h", deps->nodes[1]->path());
-    ASSERT_EQ(other_out, log.nodes()[other_out->id()]);
-
-    // The file should have shrunk a bit for the smaller deps.
-#ifdef __USE_LARGEFILE64
-    struct stat64 st;
-    ASSERT_EQ(0, stat64(kTestFilename, &st));
-#else
-    struct stat st;
-    ASSERT_EQ(0, stat(kTestFilename, &st));
-#endif
-    file_size_3 = (int)st.st_size;
-    ASSERT_LT(file_size_3, file_size_2);
-  }
-
-  // Now reload the file and recompact with an empty manifest. The previous
-  // entries should be removed.
-  {
-    State state;
-    // Intentionally not parsing kManifest here.
-    DepsLog log;
-    string err;
-    ASSERT_TRUE(log.Load(kTestFilename, &state, &err));
-
-    Node* out = state.GetNode("out.o", 0);
-    DepsLog::Deps* deps = log.GetDeps(out);
-    ASSERT_TRUE(deps);
-    ASSERT_EQ(1, deps->mtime);
-    ASSERT_EQ(1, deps->node_count);
-    ASSERT_EQ("foo.h", deps->nodes[0]->path());
-
-    Node* other_out = state.GetNode("other_out.o", 0);
-    deps = log.GetDeps(other_out);
-    ASSERT_TRUE(deps);
-    ASSERT_EQ(1, deps->mtime);
-    ASSERT_EQ(2, deps->node_count);
-    ASSERT_EQ("foo.h", deps->nodes[0]->path());
-    ASSERT_EQ("baz.h", deps->nodes[1]->path());
-
-    ASSERT_TRUE(log.Recompact(kTestFilename, &err));
-
-    // The previous entries should have been removed.
-    deps = log.GetDeps(out);
-    ASSERT_FALSE(deps);
-
-    deps = log.GetDeps(other_out);
-    ASSERT_FALSE(deps);
-
-    // The .h files pulled in via deps should no longer have ids either.
-    ASSERT_EQ(-1, state.LookupNode("foo.h")->id());
-    ASSERT_EQ(-1, state.LookupNode("baz.h")->id());
-
-    // The file should have shrunk more.
-#ifdef __USE_LARGEFILE64
-    struct stat64 st;
-    ASSERT_EQ(0, stat64(kTestFilename, &st));
-#else
-    struct stat st;
-    ASSERT_EQ(0, stat(kTestFilename, &st));
-#endif
-    int file_size_4 = (int)st.st_size;
-    ASSERT_LT(file_size_4, file_size_3);
-  }
-}
-
-// Verify that invalid file headers cause a new build.
-TEST_F(DepsLogTest, InvalidHeader) {
-  const char *kInvalidHeaders[] = {
-    "",                              // Empty file.
-    "# ninjad",                      // Truncated first line.
-    "# ninjadeps\n",                 // No version int.
-    "# ninjadeps\n\001\002",         // Truncated version int.
-    "# ninjadeps\n\001\002\003\004"  // Invalid version int.
-  };
-  for (size_t i = 0; i < sizeof(kInvalidHeaders) / sizeof(kInvalidHeaders[0]);
-       ++i) {
-    FILE* deps_log = fopen(kTestFilename, "wb");
-    ASSERT_TRUE(deps_log != NULL);
-    ASSERT_EQ(
-        strlen(kInvalidHeaders[i]),
-        fwrite(kInvalidHeaders[i], 1, strlen(kInvalidHeaders[i]), deps_log));
-    ASSERT_EQ(0 ,fclose(deps_log));
-
-    string err;
-    DepsLog log;
-    State state;
-    ASSERT_TRUE(log.Load(kTestFilename, &state, &err));
-    EXPECT_EQ("bad deps log signature or version; starting over", err);
-  }
-}
-
-// Simulate what happens when loading a truncated log file.
-TEST_F(DepsLogTest, Truncated) {
-  // Create a file with some entries.
-  {
-    State state;
-    DepsLog log;
-    string err;
-    EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err));
-    ASSERT_EQ("", err);
-
-    vector<Node*> deps;
-    deps.push_back(state.GetNode("foo.h", 0));
-    deps.push_back(state.GetNode("bar.h", 0));
-    log.RecordDeps(state.GetNode("out.o", 0), 1, deps);
-
-    deps.clear();
-    deps.push_back(state.GetNode("foo.h", 0));
-    deps.push_back(state.GetNode("bar2.h", 0));
-    log.RecordDeps(state.GetNode("out2.o", 0), 2, deps);
-
-    log.Close();
-  }
-
-  // Get the file size.
-#ifdef __USE_LARGEFILE64
-  struct stat64 st;
-  ASSERT_EQ(0, stat64(kTestFilename, &st));
-#else
-  struct stat st;
-  ASSERT_EQ(0, stat(kTestFilename, &st));
-#endif
-
-  // Try reloading at truncated sizes.
-  // Track how many nodes/deps were found; they should decrease with
-  // smaller sizes.
-  int node_count = 5;
-  int deps_count = 2;
-  for (int size = (int)st.st_size; size > 0; --size) {
-    string err;
-    ASSERT_TRUE(Truncate(kTestFilename, size, &err));
-
-    State state;
-    DepsLog log;
-    EXPECT_TRUE(log.Load(kTestFilename, &state, &err));
-    if (!err.empty()) {
-      // At some point the log will be so short as to be unparsable.
-      break;
-    }
-
-    ASSERT_GE(node_count, (int)log.nodes().size());
-    node_count = log.nodes().size();
-
-    // Count how many non-NULL deps entries there are.
-    int new_deps_count = 0;
-    for (vector<DepsLog::Deps*>::const_iterator i = log.deps().begin();
-         i != log.deps().end(); ++i) {
-      if (*i)
-        ++new_deps_count;
-    }
-    ASSERT_GE(deps_count, new_deps_count);
-    deps_count = new_deps_count;
-  }
-}
-
-// Run the truncation-recovery logic.
-TEST_F(DepsLogTest, TruncatedRecovery) {
-  // Create a file with some entries.
-  {
-    State state;
-    DepsLog log;
-    string err;
-    EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err));
-    ASSERT_EQ("", err);
-
-    vector<Node*> deps;
-    deps.push_back(state.GetNode("foo.h", 0));
-    deps.push_back(state.GetNode("bar.h", 0));
-    log.RecordDeps(state.GetNode("out.o", 0), 1, deps);
-
-    deps.clear();
-    deps.push_back(state.GetNode("foo.h", 0));
-    deps.push_back(state.GetNode("bar2.h", 0));
-    log.RecordDeps(state.GetNode("out2.o", 0), 2, deps);
-
-    log.Close();
-  }
-
-  // Shorten the file, corrupting the last record.
-  {
-#ifdef __USE_LARGEFILE64
-    struct stat64 st;
-    ASSERT_EQ(0, stat64(kTestFilename, &st));
-#else
-    struct stat st;
-    ASSERT_EQ(0, stat(kTestFilename, &st));
-#endif
-    string err;
-    ASSERT_TRUE(Truncate(kTestFilename, st.st_size - 2, &err));
-  }
-
-  // Load the file again, add an entry.
-  {
-    State state;
-    DepsLog log;
-    string err;
-    EXPECT_TRUE(log.Load(kTestFilename, &state, &err));
-    ASSERT_EQ("premature end of file; recovering", err);
-    err.clear();
-
-    // The truncated entry should've been discarded.
-    EXPECT_NULL(log.GetDeps(state.GetNode("out2.o", 0)));
-
-    EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err));
-    ASSERT_EQ("", err);
-
-    // Add a new entry.
-    vector<Node*> deps;
-    deps.push_back(state.GetNode("foo.h", 0));
-    deps.push_back(state.GetNode("bar2.h", 0));
-    log.RecordDeps(state.GetNode("out2.o", 0), 3, deps);
-
-    log.Close();
-  }
-
-  // Load the file a third time to verify appending after a mangled
-  // entry doesn't break things.
-  {
-    State state;
-    DepsLog log;
-    string err;
-    EXPECT_TRUE(log.Load(kTestFilename, &state, &err));
-
-    // The truncated entry should exist.
-    DepsLog::Deps* deps = log.GetDeps(state.GetNode("out2.o", 0));
-    ASSERT_TRUE(deps);
-  }
-}
-
-TEST_F(DepsLogTest, ReverseDepsNodes) {
-  State state;
-  DepsLog log;
-  string err;
-  EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err));
-  ASSERT_EQ("", err);
-
-  vector<Node*> deps;
-  deps.push_back(state.GetNode("foo.h", 0));
-  deps.push_back(state.GetNode("bar.h", 0));
-  log.RecordDeps(state.GetNode("out.o", 0), 1, deps);
-
-  deps.clear();
-  deps.push_back(state.GetNode("foo.h", 0));
-  deps.push_back(state.GetNode("bar2.h", 0));
-  log.RecordDeps(state.GetNode("out2.o", 0), 2, deps);
-
-  log.Close();
-
-  Node* rev_deps = log.GetFirstReverseDepsNode(state.GetNode("foo.h", 0));
-  EXPECT_TRUE(rev_deps == state.GetNode("out.o", 0) ||
-              rev_deps == state.GetNode("out2.o", 0));
-
-  rev_deps = log.GetFirstReverseDepsNode(state.GetNode("bar.h", 0));
-  EXPECT_TRUE(rev_deps == state.GetNode("out.o", 0));
-}
-
-}  // anonymous namespace
diff --git a/src/disk_interface.cc b/src/disk_interface.cc
deleted file mode 100644
index ff7f515..0000000
--- a/src/disk_interface.cc
+++ /dev/null
@@ -1,212 +0,0 @@
-// 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.
-
-#include "disk_interface.h"
-
-#include <algorithm>
-
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#ifdef _WIN32
-#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) {
-#ifdef _WIN32
-  static const char kPathSeparators[] = "\\/";
-#else
-  static const char kPathSeparators[] = "/";
-#endif
-  static const char* const kEnd = kPathSeparators + sizeof(kPathSeparators) - 1;
-
-  string::size_type slash_pos = path.find_last_of(kPathSeparators);
-  if (slash_pos == string::npos)
-    return string();  // Nothing to do.
-  while (slash_pos > 0 &&
-         std::find(kPathSeparators, kEnd, path[slash_pos - 1]) != kEnd)
-    --slash_pos;
-  return path.substr(0, slash_pos);
-}
-
-int MakeDir(const string& path) {
-#ifdef _WIN32
-  return _mkdir(path.c_str());
-#else
-  return mkdir(path.c_str(), 0777);
-#endif
-}
-
-}  // namespace
-
-// DiskInterface ---------------------------------------------------------------
-
-bool DiskInterface::MakeDirs(const string& path) {
-  string dir = DirName(path);
-  if (dir.empty())
-    return true;  // Reached root; assume it's there.
-  string err;
-  TimeStamp mtime = Stat(dir, &err);
-  if (mtime < 0) {
-    Error("%s", err.c_str());
-    return false;
-  }
-  if (mtime > 0)
-    return true;  // Exists already; we're done.
-
-  // Directory doesn't exist.  Try creating its parent first.
-  bool success = MakeDirs(dir);
-  if (!success)
-    return false;
-  return MakeDir(dir);
-}
-
-// RealDiskInterface -----------------------------------------------------------
-
-TimeStamp RealDiskInterface::Stat(const string& path, string* err) const {
-  METRIC_RECORD("node stat");
-  return stat_cache_.Stat(path, err);
-}
-
-bool RealDiskInterface::WriteFile(const string& path, const string& contents) {
-  FILE* fp = fopen(path.c_str(), "w");
-  if (fp == NULL) {
-    Error("WriteFile(%s): Unable to create file. %s",
-          path.c_str(), strerror(errno));
-    return false;
-  }
-
-  stat_cache_.Invalidate(path);
-  if (fwrite(contents.data(), 1, contents.length(), fp) < contents.length())  {
-    Error("WriteFile(%s): Unable to write to the file. %s",
-          path.c_str(), strerror(errno));
-    fclose(fp);
-    return false;
-  }
-
-  if (fclose(fp) == EOF) {
-    Error("WriteFile(%s): Unable to close the file. %s",
-          path.c_str(), strerror(errno));
-    return false;
-  }
-
-  return true;
-}
-
-bool RealDiskInterface::MakeDir(const string& path) {
-  int ret = ::MakeDir(path);
-  if (ret < 0 && errno == EEXIST)
-    return true;
-
-  int saved_errno = errno;
-  // Invalidate just in case the call modified something on the disk.
-  stat_cache_.Invalidate(path);
-  if (ret < 0) {
-    Error("mkdir(%s): %s", path.c_str(), strerror(saved_errno));
-    return false;
-  }
-  return true;
-}
-
-FileReader::Status RealDiskInterface::ReadFile(const string& path,
-                                               string* contents,
-                                               string* err) {
-  switch (::ReadFile(path, contents, err)) {
-  case 0:       return Okay;
-  case -ENOENT: return NotFound;
-  default:      return OtherError;
-  }
-}
-
-int RealDiskInterface::RemoveFile(const string& path) {
-  stat_cache_.Invalidate(path);
-#ifdef _WIN32
-  DWORD attributes = GetFileAttributesA(path.c_str());
-  if (attributes == INVALID_FILE_ATTRIBUTES) {
-    DWORD win_err = GetLastError();
-    if (win_err == ERROR_FILE_NOT_FOUND || win_err == ERROR_PATH_NOT_FOUND) {
-      return 1;
-    }
-  } else if (attributes & FILE_ATTRIBUTE_READONLY) {
-    // On non-Windows systems, remove() will happily delete read-only files.
-    // On Windows Ninja should behave the same:
-    //   https://github.com/ninja-build/ninja/issues/1886
-    // Skip error checking.  If this fails, accept whatever happens below.
-    SetFileAttributesA(path.c_str(), attributes & ~FILE_ATTRIBUTE_READONLY);
-  }
-  if (attributes & FILE_ATTRIBUTE_DIRECTORY) {
-    // remove() deletes both files and directories. On Windows we have to 
-    // select the correct function (DeleteFile will yield Permission Denied when
-    // used on a directory)
-    // This fixes the behavior of ninja -t clean in some cases
-    // https://github.com/ninja-build/ninja/issues/828
-    if (!RemoveDirectoryA(path.c_str())) {
-      DWORD win_err = GetLastError();
-      if (win_err == ERROR_FILE_NOT_FOUND || win_err == ERROR_PATH_NOT_FOUND) {
-        return 1;
-      }
-      // Report remove(), not RemoveDirectory(), for cross-platform consistency.
-      Error("remove(%s): %s", path.c_str(), GetLastErrorString().c_str());
-      return -1;
-    }
-  } else {
-    if (!DeleteFileA(path.c_str())) {
-      DWORD win_err = GetLastError();
-      if (win_err == ERROR_FILE_NOT_FOUND || win_err == ERROR_PATH_NOT_FOUND) {
-        return 1;
-      }
-      // Report as remove(), not DeleteFile(), for cross-platform consistency.
-      Error("remove(%s): %s", path.c_str(), GetLastErrorString().c_str());
-      return -1;
-    }
-  }
-#else
-  if (remove(path.c_str()) < 0) {
-    switch (errno) {
-      case ENOENT:
-        return 1;
-      default:
-        Error("remove(%s): %s", path.c_str(), strerror(errno));
-        return -1;
-    }
-  }
-#endif
-  return 0;
-}
-
-void RealDiskInterface::AllowStatCache(bool allow) {
-  stat_cache_.Enable(allow);
-}
-
-void RealDiskInterface::Sync() {
-  stat_cache_.Sync();
-}
-
-void RealDiskInterface::FlushCache() {
-  stat_cache_.Flush();
-}
diff --git a/src/disk_interface.h b/src/disk_interface.h
deleted file mode 100644
index 27960aa..0000000
--- a/src/disk_interface.h
+++ /dev/null
@@ -1,149 +0,0 @@
-// 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.
-
-#ifndef NINJA_DISK_INTERFACE_H_
-#define NINJA_DISK_INTERFACE_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "stat_cache.h"
-#include "timestamp.h"
-
-/// Interface for reading files from disk.  See DiskInterface for details.
-/// This base offers the minimum interface needed just to read files.
-struct FileReader {
-  virtual ~FileReader() {}
-
-  /// Result of ReadFile.
-  enum Status {
-    Okay,
-    NotFound,
-    OtherError
-  };
-
-  /// Read and store in given string.  On success, return Okay.
-  /// On error, return another Status and fill |err|.
-  virtual Status ReadFile(const std::string& path, std::string* contents,
-                          std::string* err) = 0;
-};
-
-/// Interface for accessing the disk.
-///
-/// Abstract so it can be mocked out for tests.  The real implementation
-/// is RealDiskInterface.
-struct DiskInterface: public FileReader {
-  /// stat() a file, returning the mtime, or 0 if missing and -1 on
-  /// other errors.
-  virtual TimeStamp Stat(const std::string& path, std::string* err) const = 0;
-
-  /// Create a directory, returning false on failure.
-  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 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 std::string& path) = 0;
-
-  /// Create all the parent directories for path; like mkdir -p
-  /// `basename path`.
-  bool MakeDirs(const std::string& path);
-
-  /// Sync with real filesystem state, which is useful when a timestamp cache
-  /// is implemented using a directory-watching system service. Calling this
-  /// is only needed when calling Stat() on files that may have been modified
-  /// through a different interface (e.g. files modified by command
-  /// sub-processes).
-  virtual void Sync() {}
-};
-
-/// Implementation of FileReader that tracks opened file paths and their
-/// timestamps. This is useful to quickly check whether one of the Ninja
-/// input manifests has changed, since even for a large Fuchsia build, there
-/// are only around 7000 files, compared to the 1,000,000 file paths in the
-/// corresponding build graph. This class will probably become obsolete when a
-/// proper filesystem-watching timestamp cache is implemented.
-struct PathRecordingFileReader : public FileReader {
-  explicit PathRecordingFileReader(DiskInterface* disk_interface)
-      : disk_interface_(disk_interface) {}
-
-  Status ReadFile(const std::string& path, std::string* contents,
-                  std::string* err) override {
-    entries_.emplace_back(path, disk_interface_->Stat(path, err));
-    return disk_interface_->ReadFile(path, contents, err);
-  }
-
-  /// Drop all timestamps from the cache.
-  void Reset() { entries_.clear(); }
-
-  /// Return true if any recorded path was modified.
-  bool CheckOutOfDate() const {
-    for (const auto& entry : entries_) {
-      /// Note that Ninja never follows symlinks by design, even for its input
-      /// manifest files, so this implementation just calls Stat() to avoid
-      /// changing its behavior.
-      if (disk_interface_->Stat(entry.path, nullptr) != entry.mtime)
-        return true;
-    }
-    return false;
-  }
-
- private:
-  struct Entry {
-    Entry(const std::string& path, TimeStamp mtime)
-        : path(path), mtime(mtime) {}
-
-    std::string path;
-    TimeStamp mtime;
-  };
-
-  DiskInterface* disk_interface_;
-  std::vector<Entry> entries_;
-};
-
-/// Implementation of DiskInterface that actually hits the disk.
-struct RealDiskInterface : public DiskInterface {
-  RealDiskInterface() = default;
-  virtual ~RealDiskInterface() = default;
-  TimeStamp Stat(const std::string& path, std::string* err) const override;
-  bool MakeDir(const std::string& path) override;
-  bool WriteFile(const std::string& path, const std::string& contents) override;
-  Status ReadFile(const std::string& path, std::string* contents,
-                  std::string* err) override;
-  int RemoveFile(const std::string& path) override;
-
-  /// Whether stat information can be cached.  Only has an effect on Windows.
-  void AllowStatCache(bool allow);
-
-  /// If StatCache is allowed, synchronize it with the current filesystem
-  /// state. This is used to drain pending events from filesystem monitoring
-  /// services like inotify on Linux.
-  void Sync() override;
-
-  /// Remove all cached stat information, if any.
-  void FlushCache();
-
- private:
-  StatCache stat_cache_;
-};
-
-#endif  // NINJA_DISK_INTERFACE_H_
diff --git a/src/disk_interface_test.cc b/src/disk_interface_test.cc
deleted file mode 100644
index d37c412..0000000
--- a/src/disk_interface_test.cc
+++ /dev/null
@@ -1,359 +0,0 @@
-// 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.
-
-#include <assert.h>
-#include <stdio.h>
-#ifdef _WIN32
-#include <io.h>
-#include <windows.h>
-#endif
-
-#include "disk_interface.h"
-#include "graph.h"
-#include "test.h"
-
-using namespace std;
-
-namespace {
-
-struct DiskInterfaceTest : public testing::Test {
-  virtual void SetUp() {
-    // These tests do real disk accesses, so create a temp dir.
-    temp_dir_.CreateAndEnter("Ninja-DiskInterfaceTest");
-  }
-
-  virtual void TearDown() {
-    temp_dir_.Cleanup();
-  }
-
-  bool Touch(const char* path) {
-    FILE *f = fopen(path, "w");
-    if (!f)
-      return false;
-    return fclose(f) == 0;
-  }
-
-  ScopedTempDir temp_dir_;
-  RealDiskInterface disk_;
-};
-
-TEST_F(DiskInterfaceTest, StatMissingFile) {
-  string err;
-  EXPECT_EQ(0, disk_.Stat("nosuchfile", &err));
-  EXPECT_EQ("", err);
-
-  // On Windows, the errno for a file in a nonexistent directory
-  // is different.
-  EXPECT_EQ(0, disk_.Stat("nosuchdir/nosuchfile", &err));
-  EXPECT_EQ("", err);
-
-  // On POSIX systems, the errno is different if a component of the
-  // path prefix is not a directory.
-  ASSERT_TRUE(Touch("notadir"));
-  EXPECT_EQ(0, disk_.Stat("notadir/nosuchfile", &err));
-  EXPECT_EQ("", err);
-}
-
-TEST_F(DiskInterfaceTest, StatMissingFileWithCache) {
-  disk_.AllowStatCache(true);
-  string err;
-
-  if (RunsUnderWine())  // This test fails under Wine.
-    return;
-
-  // On Windows, the errno for FindFirstFileExA, which is used when the stat
-  // cache is enabled, is different when the directory name is not a directory.
-  ASSERT_TRUE(Touch("notadir"));
-  EXPECT_EQ(0, disk_.Stat("notadir/nosuchfile", &err));
-  EXPECT_EQ("", err);
-}
-
-TEST_F(DiskInterfaceTest, StatBadPath) {
-  // This test fails under Wine.
-  if (RunsUnderWine())
-    return;
-
-  string err;
-#ifdef _WIN32
-  string bad_path("cc:\\foo");
-  EXPECT_EQ(-1, disk_.Stat(bad_path, &err));
-  EXPECT_NE("", err);
-#else
-  string too_long_name(512, 'x');
-  EXPECT_EQ(-1, disk_.Stat(too_long_name, &err));
-  EXPECT_NE("", err);
-#endif
-}
-
-TEST_F(DiskInterfaceTest, StatExistingFile) {
-  string err;
-  ASSERT_TRUE(Touch("file"));
-  EXPECT_GT(disk_.Stat("file", &err), 1);
-  EXPECT_EQ("", err);
-}
-
-TEST_F(DiskInterfaceTest, StatExistingDir) {
-  string err;
-  ASSERT_TRUE(disk_.MakeDir("subdir"));
-  ASSERT_TRUE(disk_.MakeDir("subdir/subsubdir"));
-  EXPECT_GT(disk_.Stat("..", &err), 1);
-  EXPECT_EQ("", err);
-  EXPECT_GT(disk_.Stat(".", &err), 1);
-  EXPECT_EQ("", err);
-  EXPECT_GT(disk_.Stat("subdir", &err), 1);
-  EXPECT_EQ("", err);
-  EXPECT_GT(disk_.Stat("subdir/subsubdir", &err), 1);
-  EXPECT_EQ("", err);
-
-  EXPECT_EQ(disk_.Stat("subdir", &err),
-            disk_.Stat("subdir/.", &err));
-  EXPECT_EQ(disk_.Stat("subdir", &err),
-            disk_.Stat("subdir/subsubdir/..", &err));
-  EXPECT_EQ(disk_.Stat("subdir/subsubdir", &err),
-            disk_.Stat("subdir/subsubdir/.", &err));
-}
-
-#ifdef _WIN32
-TEST_F(DiskInterfaceTest, StatCache) {
-  string err;
-
-  ASSERT_TRUE(Touch("file1"));
-  ASSERT_TRUE(Touch("fiLE2"));
-  ASSERT_TRUE(disk_.MakeDir("subdir"));
-  ASSERT_TRUE(disk_.MakeDir("subdir/subsubdir"));
-  ASSERT_TRUE(Touch("subdir\\subfile1"));
-  ASSERT_TRUE(Touch("subdir\\SUBFILE2"));
-  ASSERT_TRUE(Touch("subdir\\SUBFILE3"));
-
-  disk_.AllowStatCache(false);
-  TimeStamp parent_stat_uncached = disk_.Stat("..", &err);
-  disk_.AllowStatCache(true);
-
-  EXPECT_GT(disk_.Stat("FIle1", &err), 1);
-  EXPECT_EQ("", err);
-  EXPECT_GT(disk_.Stat("file1", &err), 1);
-  EXPECT_EQ("", err);
-
-  EXPECT_GT(disk_.Stat("subdir/subfile2", &err), 1);
-  EXPECT_EQ("", err);
-  EXPECT_GT(disk_.Stat("sUbdir\\suBFile1", &err), 1);
-  EXPECT_EQ("", err);
-
-  EXPECT_GT(disk_.Stat("..", &err), 1);
-  EXPECT_EQ("", err);
-  EXPECT_GT(disk_.Stat(".", &err), 1);
-  EXPECT_EQ("", err);
-  EXPECT_GT(disk_.Stat("subdir", &err), 1);
-  EXPECT_EQ("", err);
-  EXPECT_GT(disk_.Stat("subdir/subsubdir", &err), 1);
-  EXPECT_EQ("", err);
-
-#if 0  // TODO: Investigate why. Also see https://github.com/ninja-build/ninja/pull/1423
-  EXPECT_EQ(disk_.Stat("subdir", &err),
-            disk_.Stat("subdir/.", &err));
-  EXPECT_EQ("", err);
-  EXPECT_EQ(disk_.Stat("subdir", &err),
-            disk_.Stat("subdir/subsubdir/..", &err));
-#endif
-  EXPECT_EQ("", err);
-  EXPECT_EQ(disk_.Stat("..", &err), parent_stat_uncached);
-  EXPECT_EQ("", err);
-  EXPECT_EQ(disk_.Stat("subdir/subsubdir", &err),
-            disk_.Stat("subdir/subsubdir/.", &err));
-  EXPECT_EQ("", err);
-
-  if (RunsUnderWine())  // This test fails under Wine.
-    return;
-
-  // Test error cases.
-  string bad_path("cc:\\foo");
-  EXPECT_EQ(-1, disk_.Stat(bad_path, &err));
-  EXPECT_NE("", err); err.clear();
-  EXPECT_EQ(-1, disk_.Stat(bad_path, &err));
-  EXPECT_NE("", err); err.clear();
-  EXPECT_EQ(0, disk_.Stat("nosuchfile", &err));
-  EXPECT_EQ("", err);
-  EXPECT_EQ(0, disk_.Stat("nosuchdir/nosuchfile", &err));
-  EXPECT_EQ("", err);
-}
-#endif
-
-TEST_F(DiskInterfaceTest, ReadFile) {
-  string err;
-  std::string content;
-  ASSERT_EQ(DiskInterface::NotFound,
-            disk_.ReadFile("foobar", &content, &err));
-  EXPECT_EQ("", content);
-  EXPECT_NE("", err); // actual value is platform-specific
-  err.clear();
-
-  const char* kTestFile = "testfile";
-  FILE* f = fopen(kTestFile, "wb");
-  ASSERT_TRUE(f);
-  const char* kTestContent = "test content\nok";
-  fprintf(f, "%s", kTestContent);
-  ASSERT_EQ(0, fclose(f));
-
-  ASSERT_EQ(DiskInterface::Okay,
-            disk_.ReadFile(kTestFile, &content, &err));
-  EXPECT_EQ(kTestContent, content);
-  EXPECT_EQ("", err);
-}
-
-TEST_F(DiskInterfaceTest, MakeDirs) {
-  string path = "path/with/double//slash/";
-  EXPECT_TRUE(disk_.MakeDirs(path));
-  FILE* f = fopen((path + "a_file").c_str(), "w");
-  EXPECT_TRUE(f);
-  EXPECT_EQ(0, fclose(f));
-#ifdef _WIN32
-  string path2 = "another\\with\\back\\\\slashes\\";
-  EXPECT_TRUE(disk_.MakeDirs(path2));
-  FILE* f2 = fopen((path2 + "a_file").c_str(), "w");
-  EXPECT_TRUE(f2);
-  EXPECT_EQ(0, fclose(f2));
-#endif
-}
-
-TEST_F(DiskInterfaceTest, RemoveFile) {
-  const char* kFileName = "file-to-remove";
-  ASSERT_TRUE(Touch(kFileName));
-  EXPECT_EQ(0, disk_.RemoveFile(kFileName));
-  EXPECT_EQ(1, disk_.RemoveFile(kFileName));
-  EXPECT_EQ(1, disk_.RemoveFile("does not exist"));
-#ifdef _WIN32
-  ASSERT_TRUE(Touch(kFileName));
-  EXPECT_EQ(0, system((std::string("attrib +R ") + kFileName).c_str()));
-  EXPECT_EQ(0, disk_.RemoveFile(kFileName));
-  EXPECT_EQ(1, disk_.RemoveFile(kFileName));
-#endif
-}
-
-TEST_F(DiskInterfaceTest, RemoveDirectory) {
-  const char* kDirectoryName = "directory-to-remove";
-  EXPECT_TRUE(disk_.MakeDir(kDirectoryName));
-  EXPECT_EQ(0, disk_.RemoveFile(kDirectoryName));
-  EXPECT_EQ(1, disk_.RemoveFile(kDirectoryName));
-  EXPECT_EQ(1, disk_.RemoveFile("does not exist"));
-}
-
-struct StatTest : public StateTestWithBuiltinRules,
-                  public DiskInterface {
-  StatTest() : scan_(&state_, NULL, NULL, this, NULL) {}
-
-  // DiskInterface implementation.
-  virtual TimeStamp Stat(const string& path, string* err) const;
-  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;
-  }
-
-  DependencyScan scan_;
-  map<string, TimeStamp> mtimes_;
-  mutable vector<string> stats_;
-};
-
-TimeStamp StatTest::Stat(const string& path, string* err) const {
-  stats_.push_back(path);
-  map<string, TimeStamp>::const_iterator i = mtimes_.find(path);
-  if (i == mtimes_.end())
-    return 0;  // File not found.
-  return i->second;
-}
-
-TEST_F(StatTest, Simple) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat in\n"));
-
-  Node* out = GetNode("out");
-  string err;
-  EXPECT_TRUE(out->Stat(this, &err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(1u, stats_.size());
-  scan_.RecomputeDirty(out, NULL, NULL);
-  ASSERT_EQ(2u, stats_.size());
-  ASSERT_EQ("out", stats_[0]);
-  ASSERT_EQ("in",  stats_[1]);
-}
-
-TEST_F(StatTest, TwoStep) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat mid\n"
-"build mid: cat in\n"));
-
-  Node* out = GetNode("out");
-  string err;
-  EXPECT_TRUE(out->Stat(this, &err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(1u, stats_.size());
-  scan_.RecomputeDirty(out, NULL, NULL);
-  ASSERT_EQ(3u, stats_.size());
-  ASSERT_EQ("out", stats_[0]);
-  ASSERT_TRUE(GetNode("out")->dirty());
-  ASSERT_EQ("mid",  stats_[1]);
-  ASSERT_TRUE(GetNode("mid")->dirty());
-  ASSERT_EQ("in",  stats_[2]);
-}
-
-TEST_F(StatTest, Tree) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat mid1 mid2\n"
-"build mid1: cat in11 in12\n"
-"build mid2: cat in21 in22\n"));
-
-  Node* out = GetNode("out");
-  string err;
-  EXPECT_TRUE(out->Stat(this, &err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(1u, stats_.size());
-  scan_.RecomputeDirty(out, NULL, NULL);
-  ASSERT_EQ(1u + 6u, stats_.size());
-  ASSERT_EQ("mid1", stats_[1]);
-  ASSERT_TRUE(GetNode("mid1")->dirty());
-  ASSERT_EQ("in11", stats_[2]);
-}
-
-TEST_F(StatTest, Middle) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat mid\n"
-"build mid: cat in\n"));
-
-  mtimes_["in"] = 1;
-  mtimes_["mid"] = 0;  // missing
-  mtimes_["out"] = 1;
-
-  Node* out = GetNode("out");
-  string err;
-  EXPECT_TRUE(out->Stat(this, &err));
-  EXPECT_EQ("", err);
-  ASSERT_EQ(1u, stats_.size());
-  scan_.RecomputeDirty(out, NULL, NULL);
-  ASSERT_FALSE(GetNode("in")->dirty());
-  ASSERT_TRUE(GetNode("mid")->dirty());
-  ASSERT_TRUE(GetNode("out")->dirty());
-}
-
-}  // namespace
diff --git a/src/dyndep.cc b/src/dyndep.cc
deleted file mode 100644
index 7e49a75..0000000
--- a/src/dyndep.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2015 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 "dyndep.h"
-
-#include <assert.h>
-#include <stdio.h>
-
-#include "debug_flags.h"
-#include "disk_interface.h"
-#include "dyndep_parser.h"
-#include "graph.h"
-#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);
-}
-
-bool DyndepLoader::LoadDyndeps(Node* node, DyndepFile* ddf,
-                               std::string* err) const {
-  // We are loading the dyndep file now so it is no longer pending.
-  node->set_dyndep_pending(false);
-
-  // Load the dyndep information from the file.
-  EXPLAIN("loading dyndep file '%s'", node->path().c_str());
-  if (!LoadDyndepFile(node, ddf, err))
-    return false;
-
-  // Update each edge that specified this node as its dyndep binding.
-  std::vector<Edge*> const& out_edges = node->out_edges();
-  for (std::vector<Edge*>::const_iterator oe = out_edges.begin();
-       oe != out_edges.end(); ++oe) {
-    Edge* const edge = *oe;
-    if (edge->dyndep_ != node)
-      continue;
-
-    DyndepFile::iterator ddi = ddf->find(edge);
-    if (ddi == ddf->end()) {
-      *err = ("'" + edge->outputs_[0]->path() + "' "
-              "not mentioned in its dyndep file "
-              "'" + node->path() + "'");
-      return false;
-    }
-
-    ddi->second.used_ = true;
-    Dyndeps const& dyndeps = ddi->second;
-    if (!UpdateEdge(edge, &dyndeps, err)) {
-      return false;
-    }
-  }
-
-  // Reject extra outputs in dyndep file.
-  for (DyndepFile::const_iterator oe = ddf->begin(); oe != ddf->end();
-       ++oe) {
-    if (!oe->second.used_) {
-      Edge* const edge = oe->first;
-      *err = ("dyndep file '" + node->path() + "' mentions output "
-              "'" + edge->outputs_[0]->path() + "' whose build statement "
-              "does not have a dyndep binding for the file");
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool DyndepLoader::UpdateEdge(Edge* edge, Dyndeps const* dyndeps,
-                              std::string* err) const {
-  // Add dyndep-discovered bindings to the edge.
-  // We know the edge already has its own binding
-  // scope because it has a "dyndep" binding.
-  if (dyndeps->restat_)
-    edge->SetRestat();
-
-  if (!edge->UpdateDynamicImplicitOutputs(dyndeps->implicit_outputs_.size(),
-                                          dyndeps->implicit_outputs_.data(),
-                                          err)) {
-    return false;
-  }
-
-  // Add the dyndep-discovered inputs to the edge.
-  edge->UpdateDynamicImplicitDeps(dyndeps->implicit_inputs_.size(),
-                                  dyndeps->implicit_inputs_.data());
-
-  return true;
-}
-
-bool DyndepLoader::LoadDyndepFile(Node* file, DyndepFile* ddf,
-                                  std::string* err) const {
-  DyndepParser parser(state_, disk_interface_, ddf);
-  return parser.Load(file->path(), err);
-}
diff --git a/src/dyndep.h b/src/dyndep.h
deleted file mode 100644
index 907f921..0000000
--- a/src/dyndep.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2015 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_DYNDEP_LOADER_H_
-#define NINJA_DYNDEP_LOADER_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-struct DiskInterface;
-struct Edge;
-struct Node;
-struct State;
-
-/// Store dynamically-discovered dependency information for one edge.
-struct Dyndeps {
-  Dyndeps() : used_(false), restat_(false) {}
-  bool used_;
-  bool restat_;
-  std::vector<Node*> implicit_inputs_;
-  std::vector<Node*> implicit_outputs_;
-};
-
-/// Store data loaded from one dyndep file.  Map from an edge
-/// to its dynamically-discovered dependency information.
-/// This is a struct rather than a typedef so that we can
-/// forward-declare it in other headers.
-struct DyndepFile: public std::map<Edge*, Dyndeps> {};
-
-/// DyndepLoader loads dynamically discovered dependencies, as
-/// referenced via the "dyndep" attribute in build files.
-struct DyndepLoader {
-  DyndepLoader(State* state, DiskInterface* disk_interface)
-      : state_(state), disk_interface_(disk_interface) {}
-
-  /// Load a dyndep file from the given node's path and update the
-  /// 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, std::string* err) const;
-  bool LoadDyndeps(Node* node, DyndepFile* ddf, std::string* err) const;
-
- private:
-  bool LoadDyndepFile(Node* file, DyndepFile* ddf, std::string* err) const;
-
-  bool UpdateEdge(Edge* edge, Dyndeps const* dyndeps, std::string* err) const;
-
-  State* state_;
-  DiskInterface* disk_interface_;
-};
-
-#endif  // NINJA_DYNDEP_LOADER_H_
diff --git a/src/dyndep_parser.cc b/src/dyndep_parser.cc
deleted file mode 100644
index 1b4dddd..0000000
--- a/src/dyndep_parser.cc
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2015 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 "dyndep_parser.h"
-
-#include <vector>
-
-#include "dyndep.h"
-#include "graph.h"
-#include "state.h"
-#include "util.h"
-#include "version.h"
-
-using namespace std;
-
-DyndepParser::DyndepParser(State* state, FileReader* file_reader,
-                           DyndepFile* dyndep_file)
-    : Parser(state, file_reader)
-    , dyndep_file_(dyndep_file) {
-}
-
-bool DyndepParser::Parse(const string& filename, const string& input,
-                         string* err) {
-  lexer_.Start(filename, input);
-
-  // Require a supported ninja_dyndep_version value immediately so
-  // we can exit before encountering any syntactic surprises.
-  bool haveDyndepVersion = false;
-
-  for (;;) {
-    Lexer::Token token = lexer_.ReadToken();
-    switch (token) {
-    case Lexer::BUILD: {
-      if (!haveDyndepVersion)
-        return lexer_.Error("expected 'ninja_dyndep_version = ...'", err);
-      if (!ParseEdge(err))
-        return false;
-      break;
-    }
-    case Lexer::IDENT: {
-      lexer_.UnreadToken();
-      if (haveDyndepVersion)
-        return lexer_.Error(string("unexpected ") + Lexer::TokenName(token),
-                            err);
-      if (!ParseDyndepVersion(err))
-        return false;
-      haveDyndepVersion = true;
-      break;
-    }
-    case Lexer::ERROR:
-      return lexer_.Error(lexer_.DescribeLastError(), err);
-    case Lexer::TEOF:
-      if (!haveDyndepVersion)
-        return lexer_.Error("expected 'ninja_dyndep_version = ...'", err);
-      return true;
-    case Lexer::NEWLINE:
-      break;
-    default:
-      return lexer_.Error(string("unexpected ") + Lexer::TokenName(token),
-                          err);
-    }
-  }
-  return false;  // not reached
-}
-
-bool DyndepParser::ParseDyndepVersion(string* err) {
-  string name;
-  EvalString let_value;
-  if (!ParseLet(&name, &let_value, err))
-    return false;
-  if (name != "ninja_dyndep_version") {
-    return lexer_.Error("expected 'ninja_dyndep_version = ...'", err);
-  }
-  string version = let_value.Evaluate(&env_);
-  int major, minor;
-  ParseVersion(version, &major, &minor);
-  if (major != 1 || minor != 0) {
-    return lexer_.Error(
-      string("unsupported 'ninja_dyndep_version = ") + version + "'", err);
-    return false;
-  }
-  return true;
-}
-
-bool DyndepParser::ParseLet(string* key, EvalString* value, string* err) {
-  if (!lexer_.ReadIdent(key))
-    return lexer_.Error("expected variable name", err);
-  if (!ExpectToken(Lexer::EQUALS, err))
-    return false;
-  if (!lexer_.ReadVarValue(value, err))
-    return false;
-  return true;
-}
-
-bool DyndepParser::ParseEdge(string* err) {
-  // Parse one explicit output.  We expect it to already have an edge.
-  // We will record its dynamically-discovered dependency information.
-  Dyndeps* dyndeps = NULL;
-  {
-    EvalString out0;
-    if (!lexer_.ReadPath(&out0, err))
-      return false;
-    if (out0.empty())
-      return lexer_.Error("expected path", err);
-
-    string path = out0.Evaluate(&env_);
-    if (path.empty())
-      return lexer_.Error("empty path", err);
-    uint64_t slash_bits;
-    CanonicalizePath(&path, &slash_bits);
-    Node* node = state_->LookupNode(path);
-    if (!node || !node->in_edge())
-      return lexer_.Error("no build statement exists for '" + path + "'", err);
-    Edge* edge = node->in_edge();
-    std::pair<DyndepFile::iterator, bool> res =
-      dyndep_file_->insert(DyndepFile::value_type(edge, Dyndeps()));
-    if (!res.second)
-      return lexer_.Error("multiple statements for '" + path + "'", err);
-    dyndeps = &res.first->second;
-  }
-
-  // Disallow explicit outputs.
-  {
-    EvalString out;
-    if (!lexer_.ReadPath(&out, err))
-      return false;
-    if (!out.empty())
-      return lexer_.Error("explicit outputs not supported", err);
-  }
-
-  // Parse implicit outputs, if any.
-  vector<EvalString> outs;
-  if (lexer_.PeekToken(Lexer::PIPE)) {
-    for (;;) {
-      EvalString out;
-      if (!lexer_.ReadPath(&out, err))
-        return err;
-      if (out.empty())
-        break;
-      outs.push_back(out);
-    }
-  }
-
-  if (!ExpectToken(Lexer::COLON, err))
-    return false;
-
-  string rule_name;
-  if (!lexer_.ReadIdent(&rule_name) || rule_name != "dyndep")
-    return lexer_.Error("expected build command name 'dyndep'", err);
-
-  // Disallow explicit inputs.
-  {
-    EvalString in;
-    if (!lexer_.ReadPath(&in, err))
-      return false;
-    if (!in.empty())
-      return lexer_.Error("explicit inputs not supported", err);
-  }
-
-  // Parse implicit inputs, if any.
-  vector<EvalString> ins;
-  if (lexer_.PeekToken(Lexer::PIPE)) {
-    for (;;) {
-      EvalString in;
-      if (!lexer_.ReadPath(&in, err))
-        return err;
-      if (in.empty())
-        break;
-      ins.push_back(in);
-    }
-  }
-
-  // Disallow order-only inputs.
-  if (lexer_.PeekToken(Lexer::PIPE2))
-    return lexer_.Error("order-only inputs not supported", err);
-
-  if (!ExpectToken(Lexer::NEWLINE, err))
-    return false;
-
-  if (lexer_.PeekToken(Lexer::INDENT)) {
-    string key;
-    EvalString val;
-    if (!ParseLet(&key, &val, err))
-      return false;
-    if (key != "restat")
-      return lexer_.Error("binding is not 'restat'", err);
-    string value = val.Evaluate(&env_);
-    dyndeps->restat_ = !value.empty();
-  }
-
-  dyndeps->implicit_inputs_.reserve(ins.size());
-  for (vector<EvalString>::iterator i = ins.begin(); i != ins.end(); ++i) {
-    string path = i->Evaluate(&env_);
-    if (path.empty())
-      return lexer_.Error("empty path", err);
-    uint64_t slash_bits;
-    CanonicalizePath(&path, &slash_bits);
-    Node* n = state_->GetNode(path, slash_bits);
-    dyndeps->implicit_inputs_.push_back(n);
-  }
-
-  dyndeps->implicit_outputs_.reserve(outs.size());
-  for (vector<EvalString>::iterator i = outs.begin(); i != outs.end(); ++i) {
-    string path = i->Evaluate(&env_);
-    if (path.empty())
-      return lexer_.Error("empty path", err);
-    string path_err;
-    uint64_t slash_bits;
-    CanonicalizePath(&path, &slash_bits);
-    Node* n = state_->GetNode(path, slash_bits);
-    dyndeps->implicit_outputs_.push_back(n);
-  }
-
-  return true;
-}
diff --git a/src/dyndep_parser.h b/src/dyndep_parser.h
deleted file mode 100644
index 8f4c28d..0000000
--- a/src/dyndep_parser.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2015 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_DYNDEP_PARSER_H_
-#define NINJA_DYNDEP_PARSER_H_
-
-#include "eval_env.h"
-#include "parser.h"
-
-struct DyndepFile;
-struct EvalString;
-
-/// Parses dyndep files.
-struct DyndepParser: public Parser {
-  DyndepParser(State* state, FileReader* file_reader,
-               DyndepFile* dyndep_file);
-
-  /// Parse a text string of input.  Used by tests.
-  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 std::string& filename, const std::string& input,
-             std:: 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_;
-};
-
-#endif  // NINJA_DYNDEP_PARSER_H_
diff --git a/src/dyndep_parser_test.cc b/src/dyndep_parser_test.cc
deleted file mode 100644
index 1bba7ba..0000000
--- a/src/dyndep_parser_test.cc
+++ /dev/null
@@ -1,514 +0,0 @@
-// Copyright 2015 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 "dyndep_parser.h"
-
-#include <map>
-#include <vector>
-
-#include "dyndep.h"
-#include "graph.h"
-#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_);
-    string err;
-    EXPECT_TRUE(parser.ParseTest(input, &err));
-    ASSERT_EQ("", err);
-  }
-
-  virtual void SetUp() {
-    ::AssertParse(&state_,
-"rule touch\n"
-"  command = touch $out\n"
-"build out otherout: touch\n");
-  }
-
-  State state_;
-  VirtualFileSystem fs_;
-  DyndepFile dyndep_file_;
-};
-
-TEST_F(DyndepParserTest, Empty) {
-  const char kInput[] =
-"";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:1: expected 'ninja_dyndep_version = ...'\n", err);
-}
-
-TEST_F(DyndepParserTest, Version1) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1\n"));
-}
-
-TEST_F(DyndepParserTest, Version1Extra) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1-extra\n"));
-}
-
-TEST_F(DyndepParserTest, Version1_0) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1.0\n"));
-}
-
-TEST_F(DyndepParserTest, Version1_0Extra) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1.0-extra\n"));
-}
-
-TEST_F(DyndepParserTest, CommentVersion) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"# comment\n"
-"ninja_dyndep_version = 1\n"));
-}
-
-TEST_F(DyndepParserTest, BlankLineVersion) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"\n"
-"ninja_dyndep_version = 1\n"));
-}
-
-TEST_F(DyndepParserTest, VersionCRLF) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1\r\n"));
-}
-
-TEST_F(DyndepParserTest, CommentVersionCRLF) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"# comment\r\n"
-"ninja_dyndep_version = 1\r\n"));
-}
-
-TEST_F(DyndepParserTest, BlankLineVersionCRLF) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"\r\n"
-"ninja_dyndep_version = 1\r\n"));
-}
-
-TEST_F(DyndepParserTest, VersionUnexpectedEOF) {
-  const char kInput[] =
-"ninja_dyndep_version = 1.0";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:1: unexpected EOF\n"
-            "ninja_dyndep_version = 1.0\n"
-            "                          ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, UnsupportedVersion0) {
-  const char kInput[] =
-"ninja_dyndep_version = 0\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:1: unsupported 'ninja_dyndep_version = 0'\n"
-            "ninja_dyndep_version = 0\n"
-            "                        ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, UnsupportedVersion1_1) {
-  const char kInput[] =
-"ninja_dyndep_version = 1.1\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:1: unsupported 'ninja_dyndep_version = 1.1'\n"
-            "ninja_dyndep_version = 1.1\n"
-            "                          ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, DuplicateVersion) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"ninja_dyndep_version = 1\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:2: unexpected identifier\n", err);
-}
-
-TEST_F(DyndepParserTest, MissingVersionOtherVar) {
-  const char kInput[] =
-"not_ninja_dyndep_version = 1\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:1: expected 'ninja_dyndep_version = ...'\n"
-            "not_ninja_dyndep_version = 1\n"
-            "                            ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, MissingVersionBuild) {
-  const char kInput[] =
-"build out: dyndep\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:1: expected 'ninja_dyndep_version = ...'\n", err);
-}
-
-TEST_F(DyndepParserTest, UnexpectedEqual) {
-  const char kInput[] =
-"= 1\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:1: unexpected '='\n", err);
-}
-
-TEST_F(DyndepParserTest, UnexpectedIndent) {
-  const char kInput[] =
-" = 1\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:1: unexpected indent\n", err);
-}
-
-TEST_F(DyndepParserTest, OutDuplicate) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build out: dyndep\n"
-"build out: dyndep\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:3: multiple statements for 'out'\n"
-            "build out: dyndep\n"
-            "         ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, OutDuplicateThroughOther) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build out: dyndep\n"
-"build otherout: dyndep\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:3: multiple statements for 'otherout'\n"
-            "build otherout: dyndep\n"
-            "              ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, NoOutEOF) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:2: unexpected EOF\n"
-            "build\n"
-            "     ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, NoOutColon) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build :\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:2: expected path\n"
-            "build :\n"
-            "      ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, OutNoStatement) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build missing: dyndep\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:2: no build statement exists for 'missing'\n"
-            "build missing: dyndep\n"
-            "             ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, OutEOF) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build out";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:2: unexpected EOF\n"
-            "build out\n"
-            "         ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, OutNoRule) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build out:";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:2: expected build command name 'dyndep'\n"
-            "build out:\n"
-            "          ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, OutBadRule) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build out: touch";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:2: expected build command name 'dyndep'\n"
-            "build out: touch\n"
-            "           ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, BuildEOF) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build out: dyndep";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:2: unexpected EOF\n"
-            "build out: dyndep\n"
-            "                 ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, ExplicitOut) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build out exp: dyndep\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:2: explicit outputs not supported\n"
-            "build out exp: dyndep\n"
-            "             ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, ExplicitIn) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build out: dyndep exp\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:2: explicit inputs not supported\n"
-            "build out: dyndep exp\n"
-            "                     ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, OrderOnlyIn) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build out: dyndep ||\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:2: order-only inputs not supported\n"
-            "build out: dyndep ||\n"
-            "                  ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, BadBinding) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build out: dyndep\n"
-"  not_restat = 1\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:3: binding is not 'restat'\n"
-            "  not_restat = 1\n"
-            "                ^ near here", err);
-}
-
-TEST_F(DyndepParserTest, RestatTwice) {
-  const char kInput[] =
-"ninja_dyndep_version = 1\n"
-"build out: dyndep\n"
-"  restat = 1\n"
-"  restat = 1\n";
-  DyndepParser parser(&state_, &fs_, &dyndep_file_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:4: unexpected indent\n", err);
-}
-
-TEST_F(DyndepParserTest, NoImplicit) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1\n"
-"build out: dyndep\n"));
-
-  EXPECT_EQ(1u, dyndep_file_.size());
-  DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
-  ASSERT_NE(i, dyndep_file_.end());
-  EXPECT_EQ(false, i->second.restat_);
-  EXPECT_EQ(0u, i->second.implicit_outputs_.size());
-  EXPECT_EQ(0u, i->second.implicit_inputs_.size());
-}
-
-TEST_F(DyndepParserTest, EmptyImplicit) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1\n"
-"build out | : dyndep |\n"));
-
-  EXPECT_EQ(1u, dyndep_file_.size());
-  DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
-  ASSERT_NE(i, dyndep_file_.end());
-  EXPECT_EQ(false, i->second.restat_);
-  EXPECT_EQ(0u, i->second.implicit_outputs_.size());
-  EXPECT_EQ(0u, i->second.implicit_inputs_.size());
-}
-
-TEST_F(DyndepParserTest, ImplicitIn) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1\n"
-"build out: dyndep | impin\n"));
-
-  EXPECT_EQ(1u, dyndep_file_.size());
-  DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
-  ASSERT_NE(i, dyndep_file_.end());
-  EXPECT_EQ(false, i->second.restat_);
-  EXPECT_EQ(0u, i->second.implicit_outputs_.size());
-  ASSERT_EQ(1u, i->second.implicit_inputs_.size());
-  EXPECT_EQ("impin", i->second.implicit_inputs_[0]->path());
-}
-
-TEST_F(DyndepParserTest, ImplicitIns) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1\n"
-"build out: dyndep | impin1 impin2\n"));
-
-  EXPECT_EQ(1u, dyndep_file_.size());
-  DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
-  ASSERT_NE(i, dyndep_file_.end());
-  EXPECT_EQ(false, i->second.restat_);
-  EXPECT_EQ(0u, i->second.implicit_outputs_.size());
-  ASSERT_EQ(2u, i->second.implicit_inputs_.size());
-  EXPECT_EQ("impin1", i->second.implicit_inputs_[0]->path());
-  EXPECT_EQ("impin2", i->second.implicit_inputs_[1]->path());
-}
-
-TEST_F(DyndepParserTest, ImplicitOut) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1\n"
-"build out | impout: dyndep\n"));
-
-  EXPECT_EQ(1u, dyndep_file_.size());
-  DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
-  ASSERT_NE(i, dyndep_file_.end());
-  EXPECT_EQ(false, i->second.restat_);
-  ASSERT_EQ(1u, i->second.implicit_outputs_.size());
-  EXPECT_EQ("impout", i->second.implicit_outputs_[0]->path());
-  EXPECT_EQ(0u, i->second.implicit_inputs_.size());
-}
-
-TEST_F(DyndepParserTest, ImplicitOuts) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1\n"
-"build out | impout1 impout2 : dyndep\n"));
-
-  EXPECT_EQ(1u, dyndep_file_.size());
-  DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
-  ASSERT_NE(i, dyndep_file_.end());
-  EXPECT_EQ(false, i->second.restat_);
-  ASSERT_EQ(2u, i->second.implicit_outputs_.size());
-  EXPECT_EQ("impout1", i->second.implicit_outputs_[0]->path());
-  EXPECT_EQ("impout2", i->second.implicit_outputs_[1]->path());
-  EXPECT_EQ(0u, i->second.implicit_inputs_.size());
-}
-
-TEST_F(DyndepParserTest, ImplicitInsAndOuts) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1\n"
-"build out | impout1 impout2: dyndep | impin1 impin2\n"));
-
-  EXPECT_EQ(1u, dyndep_file_.size());
-  DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
-  ASSERT_NE(i, dyndep_file_.end());
-  EXPECT_EQ(false, i->second.restat_);
-  ASSERT_EQ(2u, i->second.implicit_outputs_.size());
-  EXPECT_EQ("impout1", i->second.implicit_outputs_[0]->path());
-  EXPECT_EQ("impout2", i->second.implicit_outputs_[1]->path());
-  ASSERT_EQ(2u, i->second.implicit_inputs_.size());
-  EXPECT_EQ("impin1", i->second.implicit_inputs_[0]->path());
-  EXPECT_EQ("impin2", i->second.implicit_inputs_[1]->path());
-}
-
-TEST_F(DyndepParserTest, Restat) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1\n"
-"build out: dyndep\n"
-"  restat = 1\n"));
-
-  EXPECT_EQ(1u, dyndep_file_.size());
-  DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
-  ASSERT_NE(i, dyndep_file_.end());
-  EXPECT_EQ(true, i->second.restat_);
-  EXPECT_EQ(0u, i->second.implicit_outputs_.size());
-  EXPECT_EQ(0u, i->second.implicit_inputs_.size());
-}
-
-TEST_F(DyndepParserTest, OtherOutput) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1\n"
-"build otherout: dyndep\n"));
-
-  EXPECT_EQ(1u, dyndep_file_.size());
-  DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
-  ASSERT_NE(i, dyndep_file_.end());
-  EXPECT_EQ(false, i->second.restat_);
-  EXPECT_EQ(0u, i->second.implicit_outputs_.size());
-  EXPECT_EQ(0u, i->second.implicit_inputs_.size());
-}
-
-TEST_F(DyndepParserTest, MultipleEdges) {
-    ::AssertParse(&state_,
-"build out2: touch\n");
-  ASSERT_EQ(2u, state_.edges_.size());
-  ASSERT_EQ(1u, state_.edges_[1]->outputs_.size());
-  EXPECT_EQ("out2", state_.edges_[1]->outputs_[0]->path());
-  EXPECT_EQ(0u, state_.edges_[0]->inputs_.size());
-
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"ninja_dyndep_version = 1\n"
-"build out: dyndep\n"
-"build out2: dyndep\n"
-"  restat = 1\n"));
-
-  EXPECT_EQ(2u, dyndep_file_.size());
-  {
-    DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
-    ASSERT_NE(i, dyndep_file_.end());
-    EXPECT_EQ(false, i->second.restat_);
-    EXPECT_EQ(0u, i->second.implicit_outputs_.size());
-    EXPECT_EQ(0u, i->second.implicit_inputs_.size());
-  }
-  {
-    DyndepFile::iterator i = dyndep_file_.find(state_.edges_[1]);
-    ASSERT_NE(i, dyndep_file_.end());
-    EXPECT_EQ(true, i->second.restat_);
-    EXPECT_EQ(0u, i->second.implicit_outputs_.size());
-    EXPECT_EQ(0u, i->second.implicit_inputs_.size());
-  }
-}
diff --git a/src/edit_distance.cc b/src/edit_distance.cc
deleted file mode 100644
index 34bf0e5..0000000
--- a/src/edit_distance.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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.
-
-#include "edit_distance.h"
-
-#include <algorithm>
-#include <vector>
-
-using namespace std;
-
-int EditDistance(const StringPiece& s1,
-                 const StringPiece& s2,
-                 bool allow_replacements,
-                 int max_edit_distance) {
-  // The algorithm implemented below is the "classic"
-  // dynamic-programming algorithm for computing the Levenshtein
-  // distance, which is described here:
-  //
-  //   http://en.wikipedia.org/wiki/Levenshtein_distance
-  //
-  // Although the algorithm is typically described using an m x n
-  // array, only one row plus one element are used at a time, so this
-  // implementation just keeps one vector for the row.  To update one entry,
-  // only the entries to the left, top, and top-left are needed.  The left
-  // entry is in row[x-1], the top entry is what's in row[x] from the last
-  // iteration, and the top-left entry is stored in previous.
-  int m = s1.len_;
-  int n = s2.len_;
-
-  vector<int> row(n + 1);
-  for (int i = 1; i <= n; ++i)
-    row[i] = i;
-
-  for (int y = 1; y <= m; ++y) {
-    row[0] = y;
-    int best_this_row = row[0];
-
-    int previous = y - 1;
-    for (int x = 1; x <= n; ++x) {
-      int old_row = row[x];
-      if (allow_replacements) {
-        row[x] = min(previous + (s1.str_[y - 1] == s2.str_[x - 1] ? 0 : 1),
-                     min(row[x - 1], row[x]) + 1);
-      }
-      else {
-        if (s1.str_[y - 1] == s2.str_[x - 1])
-          row[x] = previous;
-        else
-          row[x] = min(row[x - 1], row[x]) + 1;
-      }
-      previous = old_row;
-      best_this_row = min(best_this_row, row[x]);
-    }
-
-    if (max_edit_distance && best_this_row > max_edit_distance)
-      return max_edit_distance + 1;
-  }
-
-  return row[n];
-}
diff --git a/src/edit_distance.h b/src/edit_distance.h
deleted file mode 100644
index 45ae4ae..0000000
--- a/src/edit_distance.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.
-
-#ifndef NINJA_EDIT_DISTANCE_H_
-#define NINJA_EDIT_DISTANCE_H_
-
-#include "string_piece.h"
-
-int EditDistance(const StringPiece& s1,
-                 const StringPiece& s2,
-                 bool allow_replacements = true,
-                 int max_edit_distance = 0);
-
-#endif  // NINJA_EDIT_DISTANCE_H_
diff --git a/src/edit_distance_test.cc b/src/edit_distance_test.cc
deleted file mode 100644
index 9dc0f82..0000000
--- a/src/edit_distance_test.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.
-
-#include "edit_distance.h"
-
-#include "test.h"
-
-TEST(EditDistanceTest, TestEmpty) {
-  EXPECT_EQ(5, EditDistance("", "ninja"));
-  EXPECT_EQ(5, EditDistance("ninja", ""));
-  EXPECT_EQ(0, EditDistance("", ""));
-}
-
-TEST(EditDistanceTest, TestMaxDistance) {
-  const bool allow_replacements = true;
-  for (int max_distance = 1; max_distance < 7; ++max_distance) {
-    EXPECT_EQ(max_distance + 1,
-              EditDistance("abcdefghijklmnop", "ponmlkjihgfedcba",
-                           allow_replacements, max_distance));
-  }
-}
-
-TEST(EditDistanceTest, TestAllowReplacements) {
-  bool allow_replacements = true;
-  EXPECT_EQ(1, EditDistance("ninja", "njnja", allow_replacements));
-  EXPECT_EQ(1, EditDistance("njnja", "ninja", allow_replacements));
-
-  allow_replacements = false;
-  EXPECT_EQ(2, EditDistance("ninja", "njnja", allow_replacements));
-  EXPECT_EQ(2, EditDistance("njnja", "ninja", allow_replacements));
-}
-
-TEST(EditDistanceTest, TestBasics) {
-  EXPECT_EQ(0, EditDistance("browser_tests", "browser_tests"));
-  EXPECT_EQ(1, EditDistance("browser_test", "browser_tests"));
-  EXPECT_EQ(1, EditDistance("browser_tests", "browser_test"));
-}
diff --git a/src/eval_env.cc b/src/eval_env.cc
deleted file mode 100644
index 675bb83..0000000
--- a/src/eval_env.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-// 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.
-
-#include <assert.h>
-
-#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())
-    return i->second;
-  if (parent_)
-    return parent_->LookupVariable(var);
-  return "";
-}
-
-void BindingEnv::AddBinding(const string& key, const string& val) {
-  bindings_[key] = val;
-}
-
-void BindingEnv::AddRule(Rule* rule) {
-  assert(LookupRuleCurrentScope(rule->name()) == NULL);
-  rules_.emplace(rule->name(), std::unique_ptr<Rule>(rule));
-}
-
-const Rule* BindingEnv::LookupRuleCurrentScope(const string& rule_name) {
-  auto it = rules_.find(rule_name);
-  if (it == rules_.end())
-    return NULL;
-  return it->second.get();
-}
-
-const Rule* BindingEnv::LookupRule(const string& rule_name) {
-  auto it = rules_.find(rule_name);
-  if (it != rules_.end())
-    return it->second.get();
-  if (parent_)
-    return parent_->LookupRule(rule_name);
-  return NULL;
-}
-
-void Rule::AddBinding(const string& key, const EvalString& val) {
-  bindings_[key] = val;
-}
-
-const EvalString* Rule::GetBinding(const string& key) const {
-  Bindings::const_iterator i = bindings_.find(key);
-  if (i == bindings_.end())
-    return NULL;
-  return &i->second;
-}
-
-// static
-bool Rule::IsReservedBinding(const string& var) {
-  return var == "command" ||
-      var == "depfile" ||
-      var == "dyndep" ||
-      var == "description" ||
-      var == "deps" ||
-      var == "generator" ||
-      var == "pool" ||
-      var == "restat" ||
-      var == "rspfile" ||
-      var == "rspfile_content" ||
-      var == "msvc_deps_prefix";
-}
-
-string BindingEnv::LookupWithFallback(const string& var,
-                                      const EvalString* eval,
-                                      Env* env) {
-  map<string, string>::iterator i = bindings_.find(var);
-  if (i != bindings_.end())
-    return i->second;
-
-  if (eval)
-    return eval->Evaluate(env);
-
-  if (parent_)
-    return parent_->LookupVariable(var);
-
-  return "";
-}
-
-string EvalString::Evaluate(Env* env) const {
-  string result;
-  for (TokenList::const_iterator i = parsed_.begin(); i != parsed_.end(); ++i) {
-    if (i->second == RAW)
-      result.append(i->first);
-    else
-      result.append(env->LookupVariable(i->first));
-  }
-  return result;
-}
-
-void EvalString::AddText(StringPiece text) {
-  // Add it to the end of an existing RAW token if possible.
-  if (!parsed_.empty() && parsed_.back().second == RAW) {
-    parsed_.back().first.append(text.str_, text.len_);
-  } else {
-    parsed_.push_back(make_pair(text.AsString(), RAW));
-  }
-}
-void EvalString::AddSpecial(StringPiece text) {
-  parsed_.push_back(make_pair(text.AsString(), SPECIAL));
-}
-
-string EvalString::Serialize() const {
-  string result;
-  for (TokenList::const_iterator i = parsed_.begin();
-       i != parsed_.end(); ++i) {
-    result.append("[");
-    if (i->second == SPECIAL)
-      result.append("$");
-    result.append(i->first);
-    result.append("]");
-  }
-  return result;
-}
-
-string EvalString::Unparse() const {
-  string result;
-  for (TokenList::const_iterator i = parsed_.begin();
-       i != parsed_.end(); ++i) {
-    bool special = (i->second == SPECIAL);
-    if (special)
-      result.append("${");
-    result.append(i->first);
-    if (special)
-      result.append("}");
-  }
-  return result;
-}
diff --git a/src/eval_env.h b/src/eval_env.h
deleted file mode 100644
index 2c69d94..0000000
--- a/src/eval_env.h
+++ /dev/null
@@ -1,123 +0,0 @@
-// 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.
-
-#ifndef NINJA_EVAL_ENV_H_
-#define NINJA_EVAL_ENV_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "string_piece.h"
-
-struct Rule;
-
-/// An interface for a scope for variable (e.g. "$foo") lookups.
-struct Env {
-  virtual ~Env() {}
-  virtual std::string LookupVariable(const std::string& var) = 0;
-};
-
-/// A tokenized string that contains variable references.
-/// Can be evaluated relative to an Env.
-struct EvalString {
-  /// @return The evaluated string with variable expanded using value found in
-  ///         environment @a env.
-  std::string Evaluate(Env* env) const;
-
-  /// @return The string with variables not expanded.
-  std::string Unparse() const;
-
-  void Clear() { parsed_.clear(); }
-  bool empty() const { return parsed_.empty(); }
-
-  void AddText(StringPiece text);
-  void AddSpecial(StringPiece text);
-
-  /// Construct a human-readable representation of the parsed state,
-  /// for use in tests.
-  std::string Serialize() const;
-
-private:
-  enum TokenType { RAW, SPECIAL };
-  typedef std::vector<std::pair<std::string, TokenType> > TokenList;
-  TokenList parsed_;
-};
-
-/// An invocable build command and associated metadata (description, etc.).
-struct Rule {
-  Rule(StringPiece name)
-      : name_(name.str_, name.len_), is_phony_(name_ == "phony") {}
-
-  const std::string& name() const { return name_; }
-
-  bool is_phony() const { return is_phony_; }
-
-  void AddBinding(const std::string& key, const EvalString& val);
-
-  static bool IsReservedBinding(const std::string& var);
-
-  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;
-
-  std::string name_;
-  bool is_phony_;
-  typedef std::map<std::string, EvalString> Bindings;
-  Bindings bindings_;
-};
-
-/// An Env which contains a mapping of variables to values
-/// as well as a pointer to a parent scope.
-struct BindingEnv : public Env {
-  BindingEnv() : parent_(NULL) {}
-  explicit BindingEnv(BindingEnv* parent) : parent_(parent) {}
-
-  BindingEnv(const BindingEnv&) = delete;
-  BindingEnv& operator=(const BindingEnv&) = delete;
-
-  BindingEnv(BindingEnv&&) noexcept = default;
-  BindingEnv& operator=(BindingEnv&&) noexcept = default;
-
-  virtual ~BindingEnv() {}
-  virtual std::string LookupVariable(const std::string& var);
-
-  /// Add a new rule, takes ownership.
-  void AddRule(Rule* rule);
-  const Rule* LookupRule(const std::string& rule_name);
-  const Rule* LookupRuleCurrentScope(const std::string& rule_name);
-
-  using RuleMapType = std::map<std::string, std::unique_ptr<const Rule>>;
-  const RuleMapType& GetRules() const { return rules_; }
-
-  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).
-  std::string LookupWithFallback(const std::string& var, const EvalString* eval,
-                                 Env* env);
-
-private:
-  std::map<std::string, std::string> bindings_;
-  RuleMapType rules_;
-  BindingEnv* parent_;
-};
-
-#endif  // NINJA_EVAL_ENV_H_
diff --git a/src/exit_status.h b/src/exit_status.h
deleted file mode 100644
index dd45efc..0000000
--- a/src/exit_status.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.
-
-#ifndef NINJA_EXIT_STATUS_H_
-#define NINJA_EXIT_STATUS_H_
-
-enum ExitStatus {
-  ExitSuccess,
-  ExitFailure,
-  ExitInterrupted,
-  ExitTimeout,
-};
-
-#endif  // NINJA_EXIT_STATUS_H_
diff --git a/src/gen_doxygen_mainpage.sh b/src/gen_doxygen_mainpage.sh
deleted file mode 100755
index d159947..0000000
--- a/src/gen_doxygen_mainpage.sh
+++ /dev/null
@@ -1,92 +0,0 @@
-#!/bin/sh
-
-# 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.
-
-set -o errexit
-set -o nounset
-
-STATUS=0
-
-# Print each of its arguments on stderr (one per line) prefixed by the
-# basename of this script.
-stderr()
-{
-  local me=$(basename "$0")
-  local i
-  for i
-  do
-    echo >&2 "$me: $i"
-  done
-}
-
-# Print each of its arguments on stderr (one per line) prefixed by the
-# basename of this script and 'error'.
-error()
-{
-  local i
-  for i
-  do
-    stderr "error: $i"
-  done
-  STATUS=1
-}
-
-generate_header()
-{
-  cat <<EOF
-/**
- * \\mainpage
-EOF
-}
-
-generate_footer()
-{
-  cat <<EOF
- */
-EOF
-}
-
-include_file()
-{
-  local file="$1"
-  if ! [ -r "$file" ]
-  then
-    error "'$file' is not readable."
-    return
-  fi
-  cat <<EOF
- * \\section $file
- * \\verbatim
-EOF
-  cat < "$file"
-  cat <<EOF
- \\endverbatim
-EOF
-}
-
-if [ $# -eq 0 ]
-then
-  echo >&2 "usage: $0 inputs..."
-  exit 1
-fi
-
-generate_header
-for i in "$@"
-do
-  include_file "$i"
-done
-generate_footer
-
-exit $STATUS
diff --git a/src/getopt.c b/src/getopt.c
deleted file mode 100644
index 861f07f..0000000
--- a/src/getopt.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/****************************************************************************
-
-getopt.c - Read command line options
-
-AUTHOR: Gregory Pietsch
-CREATED Fri Jan 10 21:13:05 1997
-
-DESCRIPTION:
-
-The getopt() function parses the command line arguments.  Its arguments argc
-and argv are the argument count and array as passed to the main() function
-on program invocation.  The argument optstring is a list of available option
-characters.  If such a character is followed by a colon (`:'), the option
-takes an argument, which is placed in optarg.  If such a character is
-followed by two colons, the option takes an optional argument, which is
-placed in optarg.  If the option does not take an argument, optarg is NULL.
-
-The external variable optind is the index of the next array element of argv
-to be processed; it communicates from one call to the next which element to
-process.
-
-The getopt_long() function works like getopt() except that it also accepts
-long options started by two dashes `--'.  If these take values, it is either
-in the form
-
---arg=value
-
- or
-
---arg value
-
-It takes the additional arguments longopts which is a pointer to the first
-element of an array of type GETOPT_LONG_OPTION_T.  The last element of the
-array has to be filled with NULL for the name field.
-
-The longind pointer points to the index of the current long option relative
-to longopts if it is non-NULL.
-
-The getopt() function returns the option character if the option was found
-successfully, `:' if there was a missing parameter for one of the options,
-`?' for an unknown option character, and EOF for the end of the option list.
-
-The getopt_long() function's return value is described in the header file.
-
-The function getopt_long_only() is identical to getopt_long(), except that a
-plus sign `+' can introduce long options as well as `--'.
-
-The following describes how to deal with options that follow non-option
-argv-elements.
-
-If the caller did not specify anything, the default is REQUIRE_ORDER if the
-environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise.
-
-REQUIRE_ORDER means don't recognize them as options; stop option processing
-when the first non-option is seen.  This is what Unix does.  This mode of
-operation is selected by either setting the environment variable
-POSIXLY_CORRECT, or using `+' as the first character of the optstring
-parameter.
-
-PERMUTE is the default.  We permute the contents of ARGV as we scan, so that
-eventually all the non-options are at the end.  This allows options to be
-given in any order, even with programs that were not written to expect this.
-
-RETURN_IN_ORDER is an option available to programs that were written to
-expect options and other argv-elements in any order and that care about the
-ordering of the two.  We describe each non-option argv-element as if it were
-the argument of an option with character code 1.  Using `-' as the first
-character of the optstring parameter selects this mode of operation.
-
-The special argument `--' forces an end of option-scanning regardless of the
-value of ordering.  In the case of RETURN_IN_ORDER, only `--' can cause
-getopt() and friends to return EOF with optind != argc.
-
-COPYRIGHT NOTICE AND DISCLAIMER:
-
-Copyright (C) 1997 Gregory Pietsch
-
-This file and the accompanying getopt.h header file are hereby placed in the
-public domain without restrictions.  Just give the author credit, don't
-claim you wrote it or prevent anyone else from using it.
-
-Gregory Pietsch's current e-mail address:
-gpietsch@comcast.net
-****************************************************************************/
-
-/* include files */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifndef GETOPT_H
-#include "getopt.h"
-#endif
-
-/* macros */
-
-/* types */
-typedef enum GETOPT_ORDERING_T
-{
-  PERMUTE,
-  RETURN_IN_ORDER,
-  REQUIRE_ORDER
-} GETOPT_ORDERING_T;
-
-/* globally-defined variables */
-char *optarg = NULL;
-int optind = 0;
-int opterr = 1;
-int optopt = '?';
-
-/* functions */
-
-/* reverse_argv_elements:  reverses num elements starting at argv */
-static void
-reverse_argv_elements (char **argv, int num)
-{
-  int i;
-  char *tmp;
-
-  for (i = 0; i < (num >> 1); i++)
-    {
-      tmp = argv[i];
-      argv[i] = argv[num - i - 1];
-      argv[num - i - 1] = tmp;
-    }
-}
-
-/* permute: swap two blocks of argv-elements given their lengths */
-static void
-permute (char **argv, int len1, int len2)
-{
-  reverse_argv_elements (argv, len1);
-  reverse_argv_elements (argv, len1 + len2);
-  reverse_argv_elements (argv, len2);
-}
-
-/* is_option: is this argv-element an option or the end of the option list? */
-static int
-is_option (char *argv_element, int only)
-{
-  return ((argv_element == NULL)
-          || (argv_element[0] == '-') || (only && argv_element[0] == '+'));
-}
-
-/* getopt_internal:  the function that does all the dirty work */
-static int
-getopt_internal (int argc, char **argv, char *shortopts,
-                 GETOPT_LONG_OPTION_T * longopts, int *longind, int only)
-{
-  GETOPT_ORDERING_T ordering = PERMUTE;
-  static size_t optwhere = 0;
-  size_t permute_from = 0;
-  int num_nonopts = 0;
-  int optindex = 0;
-  size_t match_chars = 0;
-  char *possible_arg = NULL;
-  int longopt_match = -1;
-  int has_arg = -1;
-  char *cp = NULL;
-  int arg_next = 0;
-
-  /* first, deal with silly parameters and easy stuff */
-  if (argc == 0 || argv == NULL || (shortopts == NULL && longopts == NULL))
-    return (optopt = '?');
-  if (optind >= argc || argv[optind] == NULL)
-    return EOF;
-  if (strcmp (argv[optind], "--") == 0)
-    {
-      optind++;
-      return EOF;
-    }
-  /* if this is our first time through */
-  if (optind == 0)
-    optind = optwhere = 1;
-
-  /* define ordering */
-  if (shortopts != NULL && (*shortopts == '-' || *shortopts == '+'))
-    {
-      ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER;
-      shortopts++;
-    }
-  else
-    ordering = (getenv ("POSIXLY_CORRECT") != NULL) ? REQUIRE_ORDER : PERMUTE;
-
-  /*
-   * based on ordering, find our next option, if we're at the beginning of
-   * one
-   */
-  if (optwhere == 1)
-    {
-      switch (ordering)
-        {
-        case PERMUTE:
-          permute_from = optind;
-          num_nonopts = 0;
-          while (!is_option (argv[optind], only))
-            {
-              optind++;
-              num_nonopts++;
-            }
-          if (argv[optind] == NULL)
-            {
-              /* no more options */
-              optind = permute_from;
-              return EOF;
-            }
-          else if (strcmp (argv[optind], "--") == 0)
-            {
-              /* no more options, but have to get `--' out of the way */
-              permute (argv + permute_from, num_nonopts, 1);
-              optind = permute_from + 1;
-              return EOF;
-            }
-          break;
-        case RETURN_IN_ORDER:
-          if (!is_option (argv[optind], only))
-            {
-              optarg = argv[optind++];
-              return (optopt = 1);
-            }
-          break;
-        case REQUIRE_ORDER:
-          if (!is_option (argv[optind], only))
-            return EOF;
-          break;
-        }
-    }
-  /* we've got an option, so parse it */
-
-  /* first, is it a long option? */
-  if (longopts != NULL
-      && (memcmp (argv[optind], "--", 2) == 0
-          || (only && argv[optind][0] == '+')) && optwhere == 1)
-    {
-      /* handle long options */
-      if (memcmp (argv[optind], "--", 2) == 0)
-        optwhere = 2;
-      longopt_match = -1;
-      possible_arg = strchr (argv[optind] + optwhere, '=');
-      if (possible_arg == NULL)
-        {
-          /* no =, so next argv might be arg */
-          match_chars = strlen (argv[optind]);
-          possible_arg = argv[optind] + match_chars;
-          match_chars = match_chars - optwhere;
-        }
-      else
-        match_chars = (possible_arg - argv[optind]) - optwhere;
-      for (optindex = 0; longopts[optindex].name != NULL; optindex++)
-        {
-          if (memcmp (argv[optind] + optwhere,
-                      longopts[optindex].name, match_chars) == 0)
-            {
-              /* do we have an exact match? */
-              if (match_chars == strlen (longopts[optindex].name))
-                {
-                  longopt_match = optindex;
-                  break;
-                }
-              /* do any characters match? */
-              else
-                {
-                  if (longopt_match < 0)
-                    longopt_match = optindex;
-                  else
-                    {
-                      /* we have ambiguous options */
-                      if (opterr)
-                        fprintf (stderr, "%s: option `%s' is ambiguous "
-                                 "(could be `--%s' or `--%s')\n",
-                                 argv[0],
-                                 argv[optind],
-                                 longopts[longopt_match].name,
-                                 longopts[optindex].name);
-                      return (optopt = '?');
-                    }
-                }
-            }
-        }
-      if (longopt_match >= 0)
-        has_arg = longopts[longopt_match].has_arg;
-    }
-  /* if we didn't find a long option, is it a short option? */
-  if (longopt_match < 0 && shortopts != NULL)
-    {
-      cp = strchr (shortopts, argv[optind][optwhere]);
-      if (cp == NULL)
-        {
-          /* couldn't find option in shortopts */
-          if (opterr)
-            fprintf (stderr,
-                     "%s: invalid option -- `-%c'\n",
-                     argv[0], argv[optind][optwhere]);
-          optwhere++;
-          if (argv[optind][optwhere] == '\0')
-            {
-              optind++;
-              optwhere = 1;
-            }
-          return (optopt = '?');
-        }
-      has_arg = ((cp[1] == ':')
-                 ? ((cp[2] == ':') ? OPTIONAL_ARG : required_argument) : no_argument);
-      possible_arg = argv[optind] + optwhere + 1;
-      optopt = *cp;
-    }
-  /* get argument and reset optwhere */
-  arg_next = 0;
-  switch (has_arg)
-    {
-    case OPTIONAL_ARG:
-      if (*possible_arg == '=')
-        possible_arg++;
-      if (*possible_arg != '\0')
-        {
-          optarg = possible_arg;
-          optwhere = 1;
-        }
-      else
-        optarg = NULL;
-      break;
-    case required_argument:
-      if (*possible_arg == '=')
-        possible_arg++;
-      if (*possible_arg != '\0')
-        {
-          optarg = possible_arg;
-          optwhere = 1;
-        }
-      else if (optind + 1 >= argc)
-        {
-          if (opterr)
-            {
-              fprintf (stderr, "%s: argument required for option `", argv[0]);
-              if (longopt_match >= 0)
-                fprintf (stderr, "--%s'\n", longopts[longopt_match].name);
-              else
-                fprintf (stderr, "-%c'\n", *cp);
-            }
-          optind++;
-          return (optopt = ':');
-        }
-      else
-        {
-          optarg = argv[optind + 1];
-          arg_next = 1;
-          optwhere = 1;
-        }
-      break;
-    case no_argument:
-      if (longopt_match < 0)
-        {
-          optwhere++;
-          if (argv[optind][optwhere] == '\0')
-            optwhere = 1;
-        }
-      else
-        optwhere = 1;
-      optarg = NULL;
-      break;
-    }
-
-  /* do we have to permute or otherwise modify optind? */
-  if (ordering == PERMUTE && optwhere == 1 && num_nonopts != 0)
-    {
-      permute (argv + permute_from, num_nonopts, 1 + arg_next);
-      optind = permute_from + 1 + arg_next;
-    }
-  else if (optwhere == 1)
-    optind = optind + 1 + arg_next;
-
-  /* finally return */
-  if (longopt_match >= 0)
-    {
-      if (longind != NULL)
-        *longind = longopt_match;
-      if (longopts[longopt_match].flag != NULL)
-        {
-          *(longopts[longopt_match].flag) = longopts[longopt_match].val;
-          return 0;
-        }
-      else
-        return longopts[longopt_match].val;
-    }
-  else
-    return optopt;
-}
-
-#ifndef _AIX
-int
-getopt (int argc, char **argv, char *optstring)
-{
-  return getopt_internal (argc, argv, optstring, NULL, NULL, 0);
-}
-#endif
-
-int
-getopt_long (int argc, char **argv, const char *shortopts,
-             const GETOPT_LONG_OPTION_T * longopts, int *longind)
-{
-  return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)longopts, longind, 0);
-}
-
-int
-getopt_long_only (int argc, char **argv, const char *shortopts,
-                  const GETOPT_LONG_OPTION_T * longopts, int *longind)
-{
-  return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)longopts, longind, 1);
-}
-
-/* end of file GETOPT.C */
diff --git a/src/getopt.h b/src/getopt.h
deleted file mode 100644
index 965dc29..0000000
--- a/src/getopt.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef GETOPT_H
-#define GETOPT_H
-
-/* include files needed by this include file */
-
-/* macros defined by this include file */
-#define no_argument       0
-#define required_argument 1
-#define OPTIONAL_ARG      2
-
-/* types defined by this include file */
-
-/* GETOPT_LONG_OPTION_T: The type of long option */
-typedef struct GETOPT_LONG_OPTION_T
-{
-  const char *name;             /* the name of the long option */
-  int has_arg;                  /* one of the above macros */
-  int *flag;                    /* determines if getopt_long() returns a
-                                 * value for a long option; if it is
-                                 * non-NULL, 0 is returned as a function
-                                 * value and the value of val is stored in
-                                 * the area pointed to by flag.  Otherwise,
-                                 * val is returned. */
-  int val;                      /* determines the value to return if flag is
-                                 * NULL. */
-} GETOPT_LONG_OPTION_T;
-
-typedef GETOPT_LONG_OPTION_T option;
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-  /* externally-defined variables */
-  extern char *optarg;
-  extern int optind;
-  extern int opterr;
-  extern int optopt;
-
-  /* function prototypes */
-#ifndef _AIX
-  int getopt (int argc, char **argv, char *optstring);
-#endif
-  int getopt_long (int argc, char **argv, const char *shortopts,
-                   const GETOPT_LONG_OPTION_T * longopts, int *longind);
-  int getopt_long_only (int argc, char **argv, const char *shortopts,
-                        const GETOPT_LONG_OPTION_T * longopts, int *longind);
-
-#ifdef __cplusplus
-};
-
-#endif
-
-#endif /* GETOPT_H */
-
-/* END OF FILE getopt.h */
diff --git a/src/graph.cc b/src/graph.cc
deleted file mode 100644
index af639df..0000000
--- a/src/graph.cc
+++ /dev/null
@@ -1,900 +0,0 @@
-// 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.
-
-#include "graph.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <algorithm>
-#include <deque>
-#include <set>
-
-#include "build_log.h"
-#include "debug_flags.h"
-#include "depfile_parser.h"
-#include "deps_log.h"
-#include "disk_interface.h"
-#include "manifest_parser.h"
-#include "metrics.h"
-#include "state.h"
-#include "util.h"
-
-using namespace std;
-
-bool Node::Stat(DiskInterface* disk_interface, string* err) {
-  mtime_ = disk_interface->Stat(path_, err);
-  if (mtime_ == -1) {
-    return false;
-  }
-  exists_ = (mtime_ != 0) ? ExistenceStatusExists : ExistenceStatusMissing;
-  return true;
-}
-
-void Node::UpdatePhonyMtime(TimeStamp mtime) {
-  if (!exists()) {
-    mtime_ = std::max(mtime_, mtime);
-  }
-}
-
-bool DependencyScan::RecomputeDirty(Node* initial_node,
-                                    std::vector<Node*>* validation_nodes,
-                                    string* err) {
-  std::vector<Node*> stack;
-  std::vector<Node*> new_validation_nodes;
-
-  std::deque<Node*> nodes(1, initial_node);
-
-  // RecomputeNodeDirty might return new validation nodes that need to be
-  // checked for dirty state, keep a queue of nodes to visit.
-  while (!nodes.empty()) {
-    Node* node = nodes.front();
-    nodes.pop_front();
-
-    stack.clear();
-    new_validation_nodes.clear();
-
-    if (!RecomputeNodeDirty(node, &stack, &new_validation_nodes, err))
-      return false;
-    nodes.insert(nodes.end(), new_validation_nodes.begin(),
-                              new_validation_nodes.end());
-    if (!new_validation_nodes.empty()) {
-      assert(validation_nodes &&
-          "validations require RecomputeDirty to be called with validation_nodes");
-      validation_nodes->insert(validation_nodes->end(),
-                           new_validation_nodes.begin(),
-                           new_validation_nodes.end());
-    }
-  }
-
-  return true;
-}
-
-bool DependencyScan::RecomputeNodeDirty(Node* node, std::vector<Node*>* stack,
-                                        std::vector<Node*>* validation_nodes,
-                                        string* err) {
-  Edge* edge = node->in_edge();
-  if (!edge) {
-    // If we already visited this leaf node then we are done.
-    if (node->status_known())
-      return true;
-    // This node has no in-edge; it is dirty if it is missing.
-    if (!node->StatIfNecessary(disk_interface_, err))
-      return false;
-    if (!node->exists())
-      EXPLAIN("%s has no in-edge and is missing", node->path().c_str());
-    node->set_dirty(!node->exists());
-    return true;
-  }
-
-  // If we already finished this edge then we are done.
-  if (edge->mark_ == Edge::VisitDone)
-    return true;
-
-  // If we encountered this edge earlier in the call stack we have a cycle.
-  if (!VerifyDAG(node, stack, err))
-    return false;
-
-  // Mark the edge temporarily while in the call stack.
-  edge->mark_ = Edge::VisitInStack;
-  stack->push_back(node);
-
-  bool dirty = false;
-  edge->outputs_ready_ = true;
-  edge->deps_missing_ = false;
-
-  if (!edge->deps_loaded_) {
-    // This is our first encounter with this edge.
-    // If there is a pending dyndep file, visit it now:
-    // * If the dyndep file is ready then load it now to get any
-    //   additional inputs and outputs for this and other edges.
-    //   Once the dyndep file is loaded it will no longer be pending
-    //   if any other edges encounter it, but they will already have
-    //   been updated.
-    // * If the dyndep file is not ready then since is known to be an
-    //   input to this edge, the edge will not be considered ready below.
-    //   Later during the build the dyndep file will become ready and be
-    //   loaded to update this edge before it can possibly be scheduled.
-    if (edge->dyndep_ && edge->dyndep_->dyndep_pending()) {
-      if (!RecomputeNodeDirty(edge->dyndep_, stack, validation_nodes, err))
-        return false;
-
-      if (!edge->dyndep_->in_edge() ||
-          edge->dyndep_->in_edge()->outputs_ready()) {
-        // The dyndep file is ready, so load it now.
-        if (!LoadDyndeps(edge->dyndep_, err))
-          return false;
-      }
-    }
-  }
-
-  // Load output mtimes so we can compare them to the most recent input below.
-  for (vector<Node*>::iterator o = edge->outputs_.begin();
-       o != edge->outputs_.end(); ++o) {
-    if (!(*o)->StatIfNecessary(disk_interface_, err))
-      return false;
-  }
-
-  if (!edge->deps_loaded_) {
-    // This is our first encounter with this edge.  Load discovered deps.
-    edge->deps_loaded_ = true;
-    if (!dep_loader_.LoadDeps(edge, err)) {
-      if (!err->empty())
-        return false;
-      // Failed to load dependency info: rebuild to regenerate it.
-      // LoadDeps() did EXPLAIN() already, no need to do it here.
-      dirty = edge->deps_missing_ = true;
-    }
-  }
-
-  // Store any validation nodes from the edge for adding to the initial
-  // nodes.  Don't recurse into them, that would trigger the dependency
-  // cycle detector if the validation node depends on this node.
-  // RecomputeDirty will add the validation nodes to the initial nodes
-  // and recurse into them.
-  validation_nodes->insert(validation_nodes->end(),
-      edge->validations_.begin(), edge->validations_.end());
-
-  // Visit all inputs; we're dirty if any of the inputs are dirty.
-  Node* most_recent_input = NULL;
-  for (vector<Node*>::iterator i = edge->inputs_.begin();
-       i != edge->inputs_.end(); ++i) {
-    // Visit this input.
-    if (!RecomputeNodeDirty(*i, stack, validation_nodes, err))
-      return false;
-
-    // If an input is not ready, neither are our outputs.
-    if (Edge* in_edge = (*i)->in_edge()) {
-      if (!in_edge->outputs_ready_)
-        edge->outputs_ready_ = false;
-    }
-
-    if (!edge->is_order_only(i - edge->inputs_.begin())) {
-      // If a regular input is dirty (or missing), we're dirty.
-      // Otherwise consider mtime.
-      if ((*i)->dirty()) {
-        EXPLAIN("%s is dirty", (*i)->path().c_str());
-        dirty = true;
-      } else {
-        if (!most_recent_input || (*i)->mtime() > most_recent_input->mtime()) {
-          most_recent_input = *i;
-        }
-      }
-    }
-  }
-
-  // We may also be dirty due to output state: missing outputs, out of
-  // date outputs, etc.  Visit all outputs and determine whether they're dirty.
-  if (!dirty)
-    if (!RecomputeOutputsDirty(edge, most_recent_input, &dirty, err))
-      return false;
-
-  // Finally, visit each output and update their dirty state if necessary.
-  for (vector<Node*>::iterator o = edge->outputs_.begin();
-       o != edge->outputs_.end(); ++o) {
-    if (dirty)
-      (*o)->MarkDirty();
-  }
-
-  // If an edge is dirty, its outputs are normally not ready.  (It's
-  // possible to be clean but still not be ready in the presence of
-  // order-only inputs.)
-  // But phony edges with no inputs have nothing to do, so are always
-  // ready.
-  if (dirty && !(edge->is_phony() && edge->inputs_.empty()))
-    edge->outputs_ready_ = false;
-
-  // Mark the edge as finished during this walk now that it will no longer
-  // be in the call stack.
-  edge->mark_ = Edge::VisitDone;
-  assert(stack->back() == node);
-  stack->pop_back();
-
-  return true;
-}
-
-bool DependencyScan::VerifyDAG(Node* node, vector<Node*>* stack, string* err) {
-  Edge* edge = node->in_edge();
-  assert(edge != NULL);
-
-  // If we have no temporary mark on the edge then we do not yet have a cycle.
-  if (edge->mark_ != Edge::VisitInStack)
-    return true;
-
-  // We have this edge earlier in the call stack.  Find it.
-  vector<Node*>::iterator start = stack->begin();
-  while (start != stack->end() && (*start)->in_edge() != edge)
-    ++start;
-  assert(start != stack->end());
-
-  // Make the cycle clear by reporting its start as the node at its end
-  // instead of some other output of the starting edge.  For example,
-  // running 'ninja b' on
-  //   build a b: cat c
-  //   build c: cat a
-  // should report a -> c -> a instead of b -> c -> a.
-  *start = node;
-
-  // Construct the error message rejecting the cycle.
-  *err = "dependency cycle: ";
-  for (vector<Node*>::const_iterator i = start; i != stack->end(); ++i) {
-    err->append((*i)->path());
-    err->append(" -> ");
-  }
-  err->append((*start)->path());
-
-  if ((start + 1) == stack->end() && edge->maybe_phonycycle_diagnostic()) {
-    // The manifest parser would have filtered out the self-referencing
-    // input if it were not configured to allow the error.
-    err->append(" [-w phonycycle=err]");
-  }
-
-  return false;
-}
-
-bool DependencyScan::RecomputeOutputsDirty(Edge* edge, Node* most_recent_input,
-                                           bool* outputs_dirty, string* err) {
-  for (vector<Node*>::iterator o = edge->outputs_.begin();
-       o != edge->outputs_.end(); ++o) {
-    if (RecomputeOutputDirty(edge, most_recent_input, *o)) {
-      *outputs_dirty = true;
-      return true;
-    }
-  }
-  return true;
-}
-
-bool DependencyScan::RecomputeOutputDirty(const Edge* edge,
-                                          const Node* most_recent_input,
-                                          Node* output) {
-  if (edge->is_phony()) {
-    // Phony edges don't write any output.  Outputs are only dirty if
-    // there are no inputs and we're missing the output.
-    if (edge->inputs_.empty() && !output->exists()) {
-      EXPLAIN("output %s of phony edge with no inputs doesn't exist",
-              output->path().c_str());
-      return true;
-    }
-
-    // Update the mtime with the newest input. Dependents can thus call mtime()
-    // on the fake node and get the latest mtime of the dependencies
-    if (most_recent_input) {
-      output->UpdatePhonyMtime(most_recent_input->mtime());
-    }
-
-    // Phony edges are clean, nothing to do
-    return false;
-  }
-
-  // Dirty if we're missing the output.
-  if (!output->exists()) {
-    EXPLAIN("output %s doesn't exist", output->path().c_str());
-    return true;
-  }
-
-  BuildLog::LogEntry* entry = 0;
-
-  // If this is a restat rule, we may have cleaned the output in a
-  // previous run and stored the command start time in the build log.
-  // We don't want to consider a restat rule's outputs as dirty unless
-  // an input changed since the last run, so we'll skip checking the
-  // output file's actual mtime and simply check the recorded mtime from
-  // the log against the most recent input's mtime (see below)
-  bool used_restat = false;
-  if (edge->has_restat() && build_log() &&
-      (entry = build_log()->LookupByOutput(output->path()))) {
-    used_restat = true;
-  }
-
-  // Dirty if the output is older than the input.
-  if (!used_restat && most_recent_input && output->mtime() < most_recent_input->mtime()) {
-    EXPLAIN("output %s older than most recent input %s "
-            "(%" PRId64 " vs %" PRId64 ")",
-            output->path().c_str(),
-            most_recent_input->path().c_str(),
-            output->mtime(), most_recent_input->mtime());
-    return true;
-  }
-
-  if (build_log()) {
-    bool generator = edge->is_generator();
-    if (entry || (entry = build_log()->LookupByOutput(output->path()))) {
-      if (!generator && edge->GetCommandHash() != entry->command_hash) {
-        // May also be dirty due to the command changing since the last build.
-        // But if this is a generator rule, the command changing does not make us
-        // dirty.
-        EXPLAIN("command line changed for %s", output->path().c_str());
-        return true;
-      }
-      if (most_recent_input && entry->mtime < most_recent_input->mtime()) {
-        // May also be dirty due to the mtime in the log being older than the
-        // mtime of the most recent input.  This can occur even when the mtime
-        // on disk is newer if a previous run wrote to the output file but
-        // exited with an error or was interrupted. If this was a restat rule,
-        // then we only check the recorded mtime against the most recent input
-        // mtime and ignore the actual output's mtime above.
-        EXPLAIN("recorded mtime of %s older than most recent input %s (%" PRId64 " vs %" PRId64 ")",
-                output->path().c_str(), most_recent_input->path().c_str(),
-                entry->mtime, most_recent_input->mtime());
-        return true;
-      }
-    }
-    if (!entry && !generator) {
-      EXPLAIN("command line not found in log for %s", output->path().c_str());
-      return true;
-    }
-  }
-
-  return false;
-}
-
-bool DependencyScan::LoadDyndeps(Node* node, string* err) const {
-  return dyndep_loader_.LoadDyndeps(node, err);
-}
-
-bool DependencyScan::LoadDyndeps(Node* node, DyndepFile* ddf,
-                                 string* err) const {
-  return dyndep_loader_.LoadDyndeps(node, ddf, err);
-}
-
-void Edge::SetRestat() {
-  env_->AddBinding("restat", "1");
-  has_restat_ = 1;
-}
-
-bool Edge::has_restat() const {
-  if (has_restat_ < 0)
-    has_restat_ = GetBindingBool("restat") ? 1 : 0;
-  return has_restat_ != 0;
-}
-
-bool Edge::is_generator() const {
-  if (is_generator_ < 0)
-    is_generator_ = GetBindingBool("generator") ? 1 : 0;
-  return is_generator_ != 0;
-}
-
-bool Edge::AllInputsReady() const {
-  for (vector<Node*>::const_iterator i = inputs_.begin();
-       i != inputs_.end(); ++i) {
-    if ((*i)->in_edge() && !(*i)->in_edge()->outputs_ready())
-      return false;
-  }
-  return true;
-}
-
-/// An Env for an Edge, providing $in and $out.
-struct EdgeEnv : public Env {
-  enum EscapeKind { kShellEscape, kDoNotEscape };
-
-  EdgeEnv(const Edge* const edge, const EscapeKind escape)
-      : edge_(edge), escape_in_out_(escape), recursive_(false) {}
-  virtual string LookupVariable(const string& var);
-
-  /// Given a span of Nodes, construct a list of paths suitable for a command
-  /// line.
-  std::string MakePathList(const Node* const* span, size_t size, char sep) const;
-
- private:
-  vector<string> lookups_;
-  const Edge* const edge_;
-  EscapeKind escape_in_out_;
-  bool recursive_;
-};
-
-string EdgeEnv::LookupVariable(const string& var) {
-  if (var == "in" || var == "in_newline") {
-    int explicit_deps_count = edge_->inputs_.size() - edge_->implicit_deps_ -
-      edge_->order_only_deps_;
-    return MakePathList(edge_->inputs_.data(), explicit_deps_count,
-                        var == "in" ? ' ' : '\n');
-  } else if (var == "out") {
-    int explicit_outs_count = edge_->outputs_.size() - edge_->implicit_outs_;
-    return MakePathList(&edge_->outputs_[0], explicit_outs_count, ' ');
-  }
-
-  if (recursive_) {
-    vector<string>::const_iterator it;
-    if ((it = find(lookups_.begin(), lookups_.end(), var)) != lookups_.end()) {
-      string cycle;
-      for (; it != lookups_.end(); ++it)
-        cycle.append(*it + " -> ");
-      cycle.append(var);
-      Fatal(("cycle in rule variables: " + cycle).c_str());
-    }
-  }
-
-  // See notes on BindingEnv::LookupWithFallback.
-  const EvalString* eval = edge_->rule_->GetBinding(var);
-  bool record_varname = recursive_ && eval;
-  if (record_varname)
-    lookups_.push_back(var);
-
-  // In practice, variables defined on rules never use another rule variable.
-  // For performance, only start checking for cycles after the first lookup.
-  recursive_ = true;
-  std::string result = edge_->env_->LookupWithFallback(var, eval, this);
-  if (record_varname)
-    lookups_.pop_back();
-  return result;
-}
-
-std::string EdgeEnv::MakePathList(const Node* const* const span,
-                                  const size_t size, const char sep) const {
-  string result;
-  for (const Node* const* i = span; i != span + size; ++i) {
-    if (!result.empty())
-      result.push_back(sep);
-    const string& path = (*i)->PathDecanonicalized();
-    if (escape_in_out_ == kShellEscape) {
-#ifdef _WIN32
-      GetWin32EscapedString(path, &result);
-#else
-      GetShellEscapedString(path, &result);
-#endif
-    } else {
-      result.append(path);
-    }
-  }
-  return result;
-}
-
-void Edge::CollectInputs(bool shell_escape,
-                         std::vector<std::string>* out) const {
-  for (std::vector<Node*>::const_iterator it = inputs_.begin();
-       it != inputs_.end(); ++it) {
-    std::string path = (*it)->PathDecanonicalized();
-    if (shell_escape) {
-      std::string unescaped;
-      unescaped.swap(path);
-#ifdef _WIN32
-      GetWin32EscapedString(unescaped, &path);
-#else
-      GetShellEscapedString(unescaped, &path);
-#endif
-    }
-#if __cplusplus >= 201103L
-    out->push_back(std::move(path));
-#else
-    out->push_back(path);
-#endif
-  }
-}
-
-std::string Edge::EvaluateCommand(const bool incl_rsp_file) const {
-  string command = GetBinding("command");
-  if (incl_rsp_file) {
-    string rspfile_content = GetBinding("rspfile_content");
-    if (!rspfile_content.empty())
-      command += ";rspfile=" + rspfile_content;
-  }
-  return command;
-}
-
-std::string Edge::GetBinding(const std::string& key) const {
-  EdgeEnv env(this, EdgeEnv::kShellEscape);
-  return env.LookupVariable(key);
-}
-
-bool Edge::GetBindingBool(const string& key) const {
-  return !GetBinding(key).empty();
-}
-
-uint64_t Edge::GetCommandHash() const {
-  if (!has_command_hash_) {
-    std::string command = EvaluateCommand(/* incl_rsp_file */ true);
-    command_hash_ = BuildLog::LogEntry::HashCommand(command);
-    has_command_hash_ = true;
-  }
-  return command_hash_;
-}
-
-string Edge::GetUnescapedDepfile() const {
-  EdgeEnv env(this, EdgeEnv::kDoNotEscape);
-  return env.LookupVariable("depfile");
-}
-
-string Edge::GetUnescapedDyndep() const {
-  EdgeEnv env(this, EdgeEnv::kDoNotEscape);
-  return env.LookupVariable("dyndep");
-}
-
-std::string Edge::GetUnescapedRspfile() const {
-  EdgeEnv env(this, EdgeEnv::kDoNotEscape);
-  return env.LookupVariable("rspfile");
-}
-
-void Edge::Dump(const char* prefix) const {
-  printf("%s[ ", prefix);
-  for (vector<Node*>::const_iterator i = inputs_.begin();
-       i != inputs_.end() && *i != NULL; ++i) {
-    printf("%s ", (*i)->path().c_str());
-  }
-  printf("--%s-> ", rule_->name().c_str());
-  for (vector<Node*>::const_iterator i = outputs_.begin();
-       i != outputs_.end() && *i != NULL; ++i) {
-    printf("%s ", (*i)->path().c_str());
-  }
-  if (!validations_.empty()) {
-    printf(" validations ");
-    for (std::vector<Node*>::const_iterator i = validations_.begin();
-         i != validations_.end() && *i != NULL; ++i) {
-      printf("%s ", (*i)->path().c_str());
-    }
-  }
-  if (pool_) {
-    if (!pool_->name().empty()) {
-      printf("(in pool '%s')", pool_->name().c_str());
-    }
-  } else {
-    printf("(null pool?)");
-  }
-  printf("] 0x%p\n", this);
-}
-
-void Edge::UpdateDynamicImplicitDeps(size_t new_count, Node* const* new_deps) {
-  size_t cur_count =
-      static_cast<size_t>(implicit_deps_ - static_implicit_deps_);
-  auto cur_deps = inputs_.end() - order_only_deps_ - cur_count;
-
-  // Most of the time, the content of depfiles will not change between
-  // command invocations, and thus |new_deps| will already be recorded
-  // in this edge. Detect when this is the case and exit immediately.
-  if (cur_count == new_count &&
-      !memcmp(&(*cur_deps), new_deps, cur_count * sizeof(Node*))) {
-    return;
-  }
-
-  // If there are no recorded deps, insert the new ones directly.
-  // This happens the first time this function is called for a given
-  // Edge instance.
-  if (cur_count == 0) {
-    auto it = inputs_.insert(cur_deps, new_count, nullptr);
-    implicit_deps_ += new_count;
-    for (size_t n = 0; n < new_count; ++n) {
-      Node* node = new_deps[n];
-      *it++ = node;
-      node->AddOutEdge(this);
-    }
-    return;
-  }
-
-  // This is the general case where the content of a depfile changed since
-  // the last build invocation. This is rare but can happen, for example
-  // when depfile inputs have content-hash based names that change with
-  // the content of another input.
-  //
-  // Because benchmarking shows that modifying the build graph is slow for
-  // very large build plans, try to minimize changes by detecting the set of
-  // nodes to remove from the current edge, then the set of new ones to add.
-  std::set<Node*> cur_set(cur_deps, cur_deps + cur_count);
-  std::set<Node*> new_set(new_deps, new_deps + new_count);
-
-  // Remove all nodes that are no longer in |new_deps|.
-  {
-    auto it = cur_deps;
-    for (size_t n = 0; n < cur_count;) {
-      Node* node = *it;
-      if (!new_set.count(node)) {
-        node->RemoveOutEdge(this);
-        it = inputs_.erase(it);
-        implicit_deps_ -= 1;
-        cur_count -= 1;
-      } else {
-        ++it;
-        ++n;
-      }
-    }
-    cur_deps = inputs_.end() - order_only_deps_ - cur_count;
-  }
-
-  // Add any edge in |new_deps| that is not in the current set.
-  {
-    auto it = cur_deps + cur_count;
-    for (size_t n = 0; n < new_count; ++n) {
-      Node* node = new_deps[n];
-      if (cur_set.count(node))
-        continue;
-      implicit_deps_ += 1;
-      it = inputs_.insert(it, node) + 1;
-      node->AddOutEdge(this);
-    }
-  }
-}
-
-bool Edge::UpdateDynamicImplicitOutputs(size_t new_count, Node* const* new_outs,
-                                        std::string* err) {
-  size_t cur_count =
-      static_cast<size_t>(implicit_outs_ - static_implicit_outs_);
-  auto cur_outs = outputs_.end() - cur_count;
-
-  // Most of the time, the content of dyndep files will not change.
-  if (cur_count == new_count &&
-      !memcmp(&(*cur_outs), new_outs, cur_count * sizeof(Node*))) {
-    return true;
-  }
-
-  // If there are no recorded outputs, insert the new ones directly.
-  if (cur_count == 0) {
-    auto it = outputs_.insert(cur_outs, new_count, nullptr);
-    implicit_outs_ += new_count;
-    for (size_t n = 0; n < new_count; ++n) {
-      Node* node = new_outs[n];
-      if (node->in_edge()) {
-        // This node already has an edge producing it.
-        *err = "multiple rules generate " + node->path();
-        return false;
-      }
-      *it++ = node;
-      node->set_in_edge(this);
-    }
-    return true;
-  }
-
-  // This is the general case where the content of a dyndep file changed since
-  // the last build invocation.
-  std::set<Node*> cur_set(cur_outs, cur_outs + cur_count);
-  std::set<Node*> new_set(new_outs, new_outs + new_count);
-
-  // Remove all nodes that are no longer in |new_outs|.
-  {
-    auto it = cur_outs;
-    for (size_t n = 0; n < cur_count;) {
-      Node* node = *it;
-      assert(node->in_edge() == this);
-      if (!new_set.count(node)) {
-        node->set_in_edge(nullptr);
-        it = outputs_.erase(it);
-        implicit_outs_ -= 1;
-        cur_count -= 1;
-      } else {
-        ++it;
-        ++n;
-      }
-    }
-    cur_outs = outputs_.end() - cur_count;
-  }
-
-  // Add any edge in |new_outs| that is not in the current set.
-  {
-    auto it = cur_outs + cur_count;
-    for (size_t n = 0; n < new_count; ++n) {
-      Node* node = new_outs[n];
-      if (cur_set.count(node))
-        continue;
-      if (node->in_edge()) {
-        // This node already has an edge producing it.
-        *err = "multiple rules generate " + node->path();
-        return false;
-      }
-      node->set_in_edge(this);
-      implicit_outs_ += 1;
-      it = outputs_.insert(it, node) + 1;
-    }
-  }
-  return true;
-}
-
-bool Edge::is_phony() const {
-  return rule_->is_phony();
-}
-
-bool Edge::use_console() const {
-  return pool()->is_console();
-}
-
-bool Edge::maybe_phonycycle_diagnostic() const {
-  // CMake 2.8.12.x and 3.0.x produced self-referencing phony rules
-  // of the form "build a: phony ... a ...".   Restrict our
-  // "phonycycle" diagnostic option to the form it used.
-  return is_phony() && outputs_.size() == 1 && implicit_outs_ == 0 &&
-      implicit_deps_ == 0;
-}
-
-// static
-string Node::PathDecanonicalized(const string& path, uint64_t slash_bits) {
-  string result = path;
-#ifdef _WIN32
-  uint64_t mask = 1;
-  for (char* c = &result[0]; (c = strchr(c, '/')) != NULL;) {
-    if (slash_bits & mask)
-      *c = '\\';
-    c++;
-    mask <<= 1;
-  }
-#endif
-  return result;
-}
-
-void Node::RemoveOutEdge(Edge* edge) {
-  auto it = std::find(out_edges_.begin(), out_edges_.end(), edge);
-  assert(it != out_edges_.end());
-  // order is not important here, avoid O(n) deletion cost.
-  *it = out_edges_.back();
-  out_edges_.pop_back();
-}
-
-void Node::Dump(const char* prefix) const {
-  printf("%s <%s 0x%p> mtime: %" PRId64 "%s, (:%s), ",
-         prefix, path().c_str(), this,
-         mtime(), exists() ? "" : " (:missing)",
-         dirty() ? " dirty" : " clean");
-  if (in_edge()) {
-    in_edge()->Dump("in-edge: ");
-  } else {
-    printf("no in-edge\n");
-  }
-  printf(" out edges:\n");
-  for (vector<Edge*>::const_iterator e = out_edges().begin();
-       e != out_edges().end() && *e != NULL; ++e) {
-    (*e)->Dump(" +- ");
-  }
-  if (!validation_out_edges().empty()) {
-    printf(" validation out edges:\n");
-    for (std::vector<Edge*>::const_iterator e = validation_out_edges().begin();
-         e != validation_out_edges().end() && *e != NULL; ++e) {
-      (*e)->Dump(" +- ");
-    }
-  }
-}
-
-bool ImplicitDepLoader::LoadDeps(Edge* edge, string* err) {
-  string deps_type = edge->GetBinding("deps");
-  if (!deps_type.empty())
-    return LoadDepsFromLog(edge, err);
-
-  string depfile = edge->GetUnescapedDepfile();
-  if (!depfile.empty())
-    return LoadDepFile(edge, depfile, err);
-
-  // No deps to load.
-  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");
-  // Read depfile content.  Treat a missing depfile as empty.
-  string content;
-  switch (disk_interface_->ReadFile(path, &content, err)) {
-  case DiskInterface::Okay:
-    break;
-  case DiskInterface::NotFound:
-    err->clear();
-    break;
-  case DiskInterface::OtherError:
-    *err = "loading '" + path + "': " + *err;
-    return false;
-  }
-  // On a missing depfile: return false and empty *err.
-  if (content.empty()) {
-    EXPLAIN("depfile '%s' is missing", path.c_str());
-    return false;
-  }
-
-  DepfileParser depfile(depfile_parser_options_
-                        ? *depfile_parser_options_
-                        : DepfileParserOptions());
-  string depfile_err;
-  if (!depfile.Parse(&content, &depfile_err)) {
-    *err = path + ": " + depfile_err;
-    return false;
-  }
-
-  if (depfile.outs_.empty()) {
-    *err = path + ": no outputs declared";
-    return false;
-  }
-
-  uint64_t unused;
-  std::vector<StringPiece>::iterator primary_out = depfile.outs_.begin();
-  CanonicalizePath(const_cast<char*>(primary_out->str_), &primary_out->len_,
-                   &unused);
-
-  // Check that this depfile matches the edge's output, if not return false to
-  // mark the edge as dirty.
-  Node* first_output = edge->outputs_[0];
-  StringPiece opath = StringPiece(first_output->path());
-  if (opath != *primary_out) {
-    EXPLAIN("expected depfile '%s' to mention '%s', got '%s'", path.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;
-    }
-  }
-
-  return ProcessDepfileDeps(edge, &depfile.ins_, err);
-}
-
-bool ImplicitDepLoader::ProcessDepfileDeps(
-    Edge* edge, std::vector<StringPiece>* depfile_ins, std::string* err) {
-  std::vector<Node*> new_deps;
-  new_deps.reserve(depfile_ins->size());
-  for (StringPiece dep : *depfile_ins) {
-    uint64_t slash_bits;
-    CanonicalizePath(const_cast<char*>(dep.str_), &dep.len_, &slash_bits);
-    new_deps.push_back(state_->GetNode(dep, slash_bits));
-  }
-  edge->UpdateDynamicImplicitDeps(new_deps.size(), new_deps.data());
-  return true;
-}
-
-bool ImplicitDepLoader::LoadDepsFromLog(Edge* edge, string* err) {
-  // NOTE: deps are only supported for single-target edges.
-  Node* output = edge->outputs_[0];
-  DepsLog::Deps* deps = deps_log_ ? deps_log_->GetDeps(output) : NULL;
-  if (!deps) {
-    EXPLAIN("deps for '%s' are missing", output->path().c_str());
-    return false;
-  }
-
-  // Deps are invalid if the output is newer than the deps.
-  if (output->mtime() > deps->mtime) {
-    EXPLAIN("stored deps info out of date for '%s' (%" PRId64 " vs %" PRId64 ")",
-            output->path().c_str(), deps->mtime, output->mtime());
-    return false;
-  }
-
-  edge->UpdateDynamicImplicitDeps(static_cast<size_t>(deps->node_count),
-                                  deps->nodes);
-  return true;
-}
-
-vector<Node*>::iterator ImplicitDepLoader::PreallocateSpace(Edge* edge,
-                                                            int count) {
-  edge->inputs_.insert(edge->inputs_.end() - edge->order_only_deps_,
-                       (size_t)count, 0);
-  edge->implicit_deps_ += count;
-  return edge->inputs_.end() - edge->order_only_deps_ - count;
-}
diff --git a/src/graph.h b/src/graph.h
deleted file mode 100644
index 2cda42b..0000000
--- a/src/graph.h
+++ /dev/null
@@ -1,450 +0,0 @@
-// 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.
-
-#ifndef NINJA_GRAPH_H_
-#define NINJA_GRAPH_H_
-
-#include <algorithm>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "dyndep.h"
-#include "eval_env.h"
-#include "timestamp.h"
-#include "util.h"
-
-struct BuildLog;
-struct DepfileParserOptions;
-struct DiskInterface;
-struct DepsLog;
-struct Edge;
-struct Node;
-struct Pool;
-struct State;
-
-/// Information about a node in the dependency graph: the file, whether
-/// it's dirty, mtime, etc.
-struct Node {
-  Node(const std::string& path, uint64_t slash_bits)
-      : path_(path),
-        slash_bits_(slash_bits),
-        mtime_(-1),
-        exists_(ExistenceStatusUnknown),
-        dirty_(false),
-        dyndep_pending_(false),
-        in_edge_(NULL),
-        id_(-1) {}
-
-  /// Return false on error.
-  bool Stat(DiskInterface* disk_interface, std::string* err);
-
-  /// If the file doesn't exist, set the mtime_ from its dependencies
-  void UpdatePhonyMtime(TimeStamp mtime);
-
-  /// Return false on error.
-  bool StatIfNecessary(DiskInterface* disk_interface, std::string* err) {
-    if (status_known())
-      return true;
-    return Stat(disk_interface, err);
-  }
-
-  /// Mark as not-yet-stat()ed and not dirty.
-  void ResetState() {
-    mtime_ = -1;
-    exists_ = ExistenceStatusUnknown;
-    dirty_ = false;
-    dyndep_pending_ = false;
-  }
-
-  /// Mark the Node as already-stat()ed and missing.
-  void MarkMissing() {
-    if (mtime_ == -1) {
-      mtime_ = 0;
-    }
-    exists_ = ExistenceStatusMissing;
-  }
-
-  bool exists() const {
-    return exists_ == ExistenceStatusExists;
-  }
-
-  bool status_known() const {
-    return exists_ != ExistenceStatusUnknown;
-  }
-
-  const std::string& path() const { return path_; }
-  /// Get |path()| but use slash_bits to convert back to original slash styles.
-  std::string PathDecanonicalized() const {
-    return PathDecanonicalized(path_, 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_; }
-
-  bool dirty() const { return dirty_; }
-  void set_dirty(bool dirty) { dirty_ = dirty; }
-  void MarkDirty() { dirty_ = true; }
-
-  bool dyndep_pending() const { return dyndep_pending_; }
-  void set_dyndep_pending(bool pending) { dyndep_pending_ = pending; }
-
-  Edge* in_edge() const { return in_edge_; }
-  void set_in_edge(Edge* edge) { in_edge_ = edge; }
-
-  /// Indicates whether this node was generated from a depfile or dyndep file,
-  /// instead of being a regular input or output from the Ninja manifest.
-  bool generated_by_dep_loader() const { return generated_by_dep_loader_; }
-
-  void set_generated_by_dep_loader(bool value) {
-    generated_by_dep_loader_ = value;
-  }
-
-  int id() const { return id_; }
-  void set_id(int id) { id_ = id; }
-
-  const std::vector<Edge*>& out_edges() const { return out_edges_; }
-  const std::vector<Edge*>& validation_out_edges() const { return validation_out_edges_; }
-  void AddOutEdge(Edge* edge) { out_edges_.push_back(edge); }
-  void RemoveOutEdge(Edge* edge);
-  void AddValidationOutEdge(Edge* edge) { validation_out_edges_.push_back(edge); }
-
-  void Dump(const char* prefix="") const;
-
-private:
-  std::string path_;
-
-  /// Set bits starting from lowest for backslashes that were normalized to
-  /// forward slashes by CanonicalizePath. See |PathDecanonicalized|.
-  uint64_t slash_bits_;
-
-  /// Possible values of mtime_:
-  ///   -1: file hasn't been examined
-  ///   0:  we looked, and file doesn't exist
-  ///   >0: actual file's mtime, or the latest mtime of its dependencies if it doesn't exist
-  TimeStamp mtime_;
-
-  enum ExistenceStatus {
-    /// The file hasn't been examined.
-    ExistenceStatusUnknown,
-    /// The file doesn't exist. mtime_ will be the latest mtime of its dependencies.
-    ExistenceStatusMissing,
-    /// The path is an actual file. mtime_ will be the file's mtime.
-    ExistenceStatusExists
-  };
-  ExistenceStatus exists_;
-
-  /// Dirty is true when the underlying file is out-of-date.
-  /// But note that Edge::outputs_ready_ is also used in judging which
-  /// edges to build.
-  bool dirty_;
-
-  /// Store whether dyndep information is expected from this node but
-  /// has not yet been loaded.
-  bool dyndep_pending_;
-
-  /// Set to true when this node comes from a depfile, a dyndep file or the
-  /// deps log. If it does not have a producing edge, the build should not
-  /// abort if it is missing (as for regular source inputs). By default
-  /// all nodes have this flag set to true, since the deps and build logs
-  /// can be loaded before the manifest.
-  bool generated_by_dep_loader_ = true;
-
-  /// The Edge that produces this Node, or NULL when there is no
-  /// known edge to produce it.
-  Edge* in_edge_;
-
-  /// All Edges that use this Node as an input.
-  std::vector<Edge*> out_edges_;
-
-  /// All Edges that use this Node as a validation.
-  std::vector<Edge*> validation_out_edges_;
-
-  /// A dense integer id for the node, assigned and used by DepsLog.
-  int id_;
-};
-
-/// An edge in the dependency graph; links between Nodes using Rules.
-struct Edge {
-  enum VisitMark {
-    VisitNone,
-    VisitInStack,
-    VisitDone
-  };
-
-  Edge()
-      : rule_(NULL), pool_(NULL), dyndep_(NULL), env_(NULL), mark_(VisitNone),
-        id_(0), outputs_ready_(false), deps_loaded_(false),
-        deps_missing_(false), has_restat_(-1), is_generator_(-1),
-        command_start_time_(0), static_implicit_deps_(0), implicit_deps_(0),
-        order_only_deps_(0), static_implicit_outs_(0), implicit_outs_(0) {}
-
-  /// Return true if all inputs' in-edges are ready.
-  bool AllInputsReady() const;
-
-  /// Expand all variables in a command and return it as a string.
-  /// If incl_rsp_file is enabled, the string will also contain the
-  /// full contents of a response file (if applicable)
-  std::string EvaluateCommand(bool incl_rsp_file = false) const;
-
-  /// Returns the shell-escaped value of |key|.
-  std::string GetBinding(const std::string& key) const;
-  bool GetBindingBool(const std::string& key) const;
-
-  /// Like GetBinding("depfile"), but without shell escaping.
-  std::string GetUnescapedDepfile() const;
-  /// Like GetBinding("dyndep"), but without shell escaping.
-  std::string GetUnescapedDyndep() const;
-  /// Like GetBinding("rspfile"), but without shell escaping.
-  std::string GetUnescapedRspfile() const;
-
-  void Dump(const char* prefix="") const;
-
-  /// Append all edge explicit inputs to |*out|. Possibly with shell escaping.
-  void CollectInputs(bool shell_escape, std::vector<std::string>* out) const;
-
-  /// Reset state of edge for next build / dependency scan.
-  void ResetState() {
-    outputs_ready_ = false;
-    deps_missing_ = false;
-    mark_ = VisitNone;
-  }
-
-  const Rule* rule_;
-  Pool* pool_;
-  std::vector<Node*> inputs_;
-  std::vector<Node*> outputs_;
-  std::vector<Node*> validations_;
-  Node* dyndep_;
-  BindingEnv* env_;
-  VisitMark mark_;
-  size_t id_;
-  bool outputs_ready_;
-
-  /// Set to true to indicate that this edge contains extra dependencies that
-  /// were loaded from depfiles, the deps log, or dyndep files.
-  bool deps_loaded_;
-
-  bool deps_missing_;
-
-  /// True for special phony edges that are created when loading extra
-  /// dependencies from depfiles or the deps log that do not have a
-  /// generating edge.
-  bool generated_by_dep_loader_;
-
-  /// Return the command hash for this edge.
-  uint64_t GetCommandHash() const;
-
-  /// True if command_hash_ is valid. Modified by const method.
-  mutable bool has_command_hash_ = false;
-  mutable uint64_t command_hash_ = 0;
-
-  TimeStamp command_start_time_;
-
-  const Rule& rule() const { return *rule_; }
-  Pool* pool() const { return pool_; }
-  int weight() const { return 1; }
-  bool outputs_ready() const { return outputs_ready_; }
-
-  /// Return true if "restat" is set for this edge.
-  bool has_restat() const;
-  mutable int has_restat_ = -1;  // computed on-demand by const method.
-
-  /// Return true if "generator" is set for this edge.
-  bool is_generator() const;
-  mutable int is_generator_ = -1;  // computed on-demand by const method.
-
-  void SetRestat();
-
-  // There are four types of inputs.
-  // 1) explicit deps, which show up as $in on the command line;
-  // 2) static implicit deps, which the target depends on implicitly (e.g. C
-  //    headers), as they appear in the build plan, and changes in them cause
-  //    the target to be rebuild.
-  // 3) dynamic implicit deps, which come from depfiles, the deps log or
-  //    dyndep files. They never appear in the build plan, and are inserted
-  //    into the build plan during incremental builds. They are otherwise
-  //    considered implicit dependencies.
-  // 4) order-only deps, which are needed before the target builds but which
-  //                     don't cause the target to rebuild.
-  // These are stored in inputs_ in that order, and we keep counts of
-  // #2, #3 and #4 when we need to access the various subsets.
-  //
-  //                static_implicit_deps_
-  //                    |
-  //  inputs_ [...|<----*----->|            |<--order_only_deps_-->]
-  //              |<------implicit_deps_--->|
-  //
-  int static_implicit_deps_;
-  int implicit_deps_;
-  int order_only_deps_;
-  bool is_implicit(size_t index) {
-    return index >= inputs_.size() - order_only_deps_ - implicit_deps_ &&
-        !is_order_only(index);
-  }
-  bool is_order_only(size_t index) {
-    return index >= inputs_.size() - order_only_deps_;
-  }
-
-  // There are three types of outputs.
-  // 1) explicit outs, which show up as $out on the command line;
-  // 2) static implicit outs, that the target generates in the build plan, and
-  //    which are not listed as part of $out.
-  // 3) dynamic implicit outs. which do not appear in the build plan, but
-  //    inserted into the build graph through dyndep files only.
-  // These are stored in outputs_ in that order, and we keep a count of
-  // #2 and #3 to use when we need to access the various subsets.
-  //
-  //               static_implicit_outs_
-  //                        |
-  //  outputs_ [.....|<-----*------>|                 ]
-  //                 |<--------implicit_outs_-------->|
-  //
-  int static_implicit_outs_;
-  int implicit_outs_;
-  bool is_implicit_out(size_t index) const {
-    return index >= outputs_.size() - implicit_outs_;
-  }
-
-  /// Update the set of dynamic implicit inputs for this edge. These can
-  /// come from the deps log, a depfile, or a dyndep file. This method tries
-  /// to minimize the changes to the build graph during incremental builds.
-  void UpdateDynamicImplicitDeps(size_t new_count, Node* const* new_deps);
-
-  /// Update the set of dynamic implicit outputs for this edge. These only
-  /// come from dyndep files. On success, return true. On failure, which means
-  /// that one of the new outputs already has a producing edge, set |*err|
-  /// then return false.
-  bool UpdateDynamicImplicitOutputs(size_t new_count, Node* const* new_outs,
-                                    std::string* err);
-
-  bool is_phony() const;
-  bool use_console() const;
-  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.
-struct ImplicitDepLoader {
-  ImplicitDepLoader(State* state, DepsLog* deps_log,
-                    DiskInterface* disk_interface,
-                    DepfileParserOptions const* depfile_parser_options)
-      : state_(state), disk_interface_(disk_interface), deps_log_(deps_log),
-        depfile_parser_options_(depfile_parser_options) {}
-
-  /// 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, std::string* err);
-
-  DepsLog* deps_log() const {
-    return deps_log_;
-  }
-
- protected:
-  /// Process loaded implicit dependencies for \a edge and update the graph
-  /// @return false on error (without filling \a err if info is just missing)
-  virtual bool ProcessDepfileDeps(Edge* edge,
-                                  std::vector<StringPiece>* depfile_ins,
-                                  std::string* err);
-
-  /// 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 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, std::string* err);
-
-  /// Preallocate \a count spaces in the input array on \a edge, returning
-  /// an iterator pointing at the first new space.
-  std::vector<Node*>::iterator PreallocateSpace(Edge* edge, int count);
-
-  State* state_;
-  DiskInterface* disk_interface_;
-  DepsLog* deps_log_;
-  DepfileParserOptions const* depfile_parser_options_;
-};
-
-
-/// DependencyScan manages the process of scanning the files in a graph
-/// and updating the dirty/outputs_ready state of all the nodes and edges.
-struct DependencyScan {
-  DependencyScan(State* state, BuildLog* build_log, DepsLog* deps_log,
-                 DiskInterface* disk_interface,
-                 DepfileParserOptions const* depfile_parser_options)
-      : build_log_(build_log),
-        disk_interface_(disk_interface),
-        dep_loader_(state, deps_log, disk_interface, depfile_parser_options),
-        dyndep_loader_(state, disk_interface) {}
-
-  /// Update the |dirty_| state of the given nodes by transitively inspecting
-  /// their input edges.
-  /// Examine inputs, outputs, and command lines to judge whether an edge
-  /// needs to be re-run, and update outputs_ready_ and each outputs' |dirty_|
-  /// state accordingly.
-  /// Appends any validation nodes found to the nodes parameter.
-  /// Returns false on failure.
-  bool RecomputeDirty(Node* node, std::vector<Node*>* validation_nodes, 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, std::string* err);
-
-  BuildLog* build_log() const {
-    return build_log_;
-  }
-  void set_build_log(BuildLog* log) {
-    build_log_ = log;
-  }
-
-  DepsLog* deps_log() const {
-    return dep_loader_.deps_log();
-  }
-
-  /// Load a dyndep file from the given node's path and update the
-  /// 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, std::string* err) const;
-  bool LoadDyndeps(Node* node, DyndepFile* ddf, std::string* err) const;
-
- private:
-  bool RecomputeNodeDirty(Node* node, std::vector<Node*>* stack,
-                          std::vector<Node*>* validation_nodes, 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(const Edge* edge, const Node* most_recent_input,
-                            Node* output);
-
-  BuildLog* build_log_;
-  DiskInterface* disk_interface_;
-  ImplicitDepLoader dep_loader_;
-  DyndepLoader dyndep_loader_;
-};
-
-#endif  // NINJA_GRAPH_H_
diff --git a/src/graph_test.cc b/src/graph_test.cc
deleted file mode 100644
index 8a738ec..0000000
--- a/src/graph_test.cc
+++ /dev/null
@@ -1,1166 +0,0 @@
-// 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.
-
-#include "graph.h"
-#include "build.h"
-
-#include "test.h"
-
-using namespace std;
-
-struct GraphTest : public StateTestWithBuiltinRules {
-  GraphTest() : scan_(&state_, NULL, NULL, &fs_, NULL) {}
-
-  VirtualFileSystem fs_;
-  DependencyScan scan_;
-};
-
-TEST_F(GraphTest, MissingImplicit) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat in | implicit\n"));
-  fs_.Create("in", "");
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  // A missing implicit dep *should* make the output dirty.
-  // (In fact, a build will fail.)
-  // This is a change from prior semantics of ninja.
-  EXPECT_TRUE(GetNode("out")->dirty());
-}
-
-TEST_F(GraphTest, ModifiedImplicit) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat in | implicit\n"));
-  fs_.Create("in", "");
-  fs_.Create("out", "");
-  fs_.Tick();
-  fs_.Create("implicit", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  // A modified implicit dep should make the output dirty.
-  EXPECT_TRUE(GetNode("out")->dirty());
-}
-
-TEST_F(GraphTest, FunkyMakefilePath) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule catdep\n"
-"  depfile = $out.d\n"
-"  command = cat $in > $out\n"
-"build out.o: catdep foo.cc\n"));
-  fs_.Create("foo.cc",  "");
-  fs_.Create("out.o.d", "out.o: ./foo/../implicit.h\n");
-  fs_.Create("out.o", "");
-  fs_.Tick();
-  fs_.Create("implicit.h", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  // implicit.h has changed, though our depfile refers to it with a
-  // non-canonical path; we should still find it.
-  EXPECT_TRUE(GetNode("out.o")->dirty());
-}
-
-TEST_F(GraphTest, ExplicitImplicit) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule catdep\n"
-"  depfile = $out.d\n"
-"  command = cat $in > $out\n"
-"build implicit.h: cat data\n"
-"build out.o: catdep foo.cc || implicit.h\n"));
-  fs_.Create("implicit.h", "");
-  fs_.Create("foo.cc", "");
-  fs_.Create("out.o.d", "out.o: implicit.h\n");
-  fs_.Create("out.o", "");
-  fs_.Tick();
-  fs_.Create("data", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  // We have both an implicit and an explicit dep on implicit.h.
-  // The implicit dep should "win" (in the sense that it should cause
-  // the output to be dirty).
-  EXPECT_TRUE(GetNode("out.o")->dirty());
-}
-
-TEST_F(GraphTest, ImplicitOutputParse) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out | out.imp: cat in\n"));
-
-  Edge* edge = GetNode("out")->in_edge();
-  EXPECT_EQ(2, edge->outputs_.size());
-  EXPECT_EQ("out", edge->outputs_[0]->path());
-  EXPECT_EQ("out.imp", edge->outputs_[1]->path());
-  EXPECT_EQ(1, edge->implicit_outs_);
-  EXPECT_EQ(edge, GetNode("out.imp")->in_edge());
-}
-
-TEST_F(GraphTest, ImplicitOutputMissing) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out | out.imp: cat in\n"));
-  fs_.Create("in", "");
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_TRUE(GetNode("out")->dirty());
-  EXPECT_TRUE(GetNode("out.imp")->dirty());
-}
-
-TEST_F(GraphTest, ImplicitOutputOutOfDate) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out | out.imp: cat in\n"));
-  fs_.Create("out.imp", "");
-  fs_.Tick();
-  fs_.Create("in", "");
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_TRUE(GetNode("out")->dirty());
-  EXPECT_TRUE(GetNode("out.imp")->dirty());
-}
-
-TEST_F(GraphTest, ImplicitOutputOnlyParse) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build | out.imp: cat in\n"));
-
-  Edge* edge = GetNode("out.imp")->in_edge();
-  EXPECT_EQ(1, edge->outputs_.size());
-  EXPECT_EQ("out.imp", edge->outputs_[0]->path());
-  EXPECT_EQ(1, edge->implicit_outs_);
-  EXPECT_EQ(edge, GetNode("out.imp")->in_edge());
-}
-
-TEST_F(GraphTest, ImplicitOutputOnlyMissing) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build | out.imp: cat in\n"));
-  fs_.Create("in", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.imp"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_TRUE(GetNode("out.imp")->dirty());
-}
-
-TEST_F(GraphTest, ImplicitOutputOnlyOutOfDate) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build | out.imp: cat in\n"));
-  fs_.Create("out.imp", "");
-  fs_.Tick();
-  fs_.Create("in", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.imp"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_TRUE(GetNode("out.imp")->dirty());
-}
-
-TEST_F(GraphTest, PathWithCurrentDirectory) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule catdep\n"
-"  depfile = $out.d\n"
-"  command = cat $in > $out\n"
-"build ./out.o: catdep ./foo.cc\n"));
-  fs_.Create("foo.cc", "");
-  fs_.Create("out.o.d", "out.o: foo.cc\n");
-  fs_.Create("out.o", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_FALSE(GetNode("out.o")->dirty());
-}
-
-TEST_F(GraphTest, RootNodes) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out1: cat in1\n"
-"build mid1: cat in1\n"
-"build out2: cat mid1\n"
-"build out3 out4: cat mid1\n"));
-
-  string err;
-  vector<Node*> root_nodes = state_.RootNodes(&err);
-  EXPECT_EQ(4u, root_nodes.size());
-  for (size_t i = 0; i < root_nodes.size(); ++i) {
-    string name = root_nodes[i]->path();
-    EXPECT_EQ("out", name.substr(0, 3));
-  }
-}
-
-TEST_F(GraphTest, CollectInputs) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-      &state_,
-      "build out$ 1: cat in1 in2 in$ with$ space | implicit || order_only\n"));
-
-  std::vector<std::string> inputs;
-  Edge* edge = GetNode("out 1")->in_edge();
-
-  // Test without shell escaping.
-  inputs.clear();
-  edge->CollectInputs(false, &inputs);
-  EXPECT_EQ(5u, inputs.size());
-  EXPECT_EQ("in1", inputs[0]);
-  EXPECT_EQ("in2", inputs[1]);
-  EXPECT_EQ("in with space", inputs[2]);
-  EXPECT_EQ("implicit", inputs[3]);
-  EXPECT_EQ("order_only", inputs[4]);
-
-  // Test with shell escaping.
-  inputs.clear();
-  edge->CollectInputs(true, &inputs);
-  EXPECT_EQ(5u, inputs.size());
-  EXPECT_EQ("in1", inputs[0]);
-  EXPECT_EQ("in2", inputs[1]);
-#ifdef _WIN32
-  EXPECT_EQ("\"in with space\"", inputs[2]);
-#else
-  EXPECT_EQ("'in with space'", inputs[2]);
-#endif
-  EXPECT_EQ("implicit", inputs[3]);
-  EXPECT_EQ("order_only", inputs[4]);
-}
-
-TEST_F(GraphTest, VarInOutPathEscaping) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build a$ b: cat no'space with$ space$$ no\"space2\n"));
-
-  Edge* edge = GetNode("a b")->in_edge();
-#ifdef _WIN32
-  EXPECT_EQ("cat no'space \"with space$\" \"no\\\"space2\" > \"a b\"",
-      edge->EvaluateCommand());
-#else
-  EXPECT_EQ("cat 'no'\\''space' 'with space$' 'no\"space2' > 'a b'",
-      edge->EvaluateCommand());
-#endif
-}
-
-// Regression test for https://github.com/ninja-build/ninja/issues/380
-TEST_F(GraphTest, DepfileWithCanonicalizablePath) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule catdep\n"
-"  depfile = $out.d\n"
-"  command = cat $in > $out\n"
-"build ./out.o: catdep ./foo.cc\n"));
-  fs_.Create("foo.cc", "");
-  fs_.Create("out.o.d", "out.o: bar/../foo.cc\n");
-  fs_.Create("out.o", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_FALSE(GetNode("out.o")->dirty());
-}
-
-// Regression test for https://github.com/ninja-build/ninja/issues/404
-TEST_F(GraphTest, DepfileRemoved) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule catdep\n"
-"  depfile = $out.d\n"
-"  command = cat $in > $out\n"
-"build ./out.o: catdep ./foo.cc\n"));
-  fs_.Create("foo.h", "");
-  fs_.Create("foo.cc", "");
-  fs_.Tick();
-  fs_.Create("out.o.d", "out.o: foo.h\n");
-  fs_.Create("out.o", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), NULL, &err));
-  ASSERT_EQ("", err);
-  EXPECT_FALSE(GetNode("out.o")->dirty());
-
-  fs_.RemoveFile("out.o.d");
-
-  // Note that State::Reset() does not remove the recorded deps from the edge
-  // so a new dependency scan will ingore the depfile being removed.
-  state_.Reset();
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), NULL, &err));
-  ASSERT_EQ("", err);
-  EXPECT_FALSE(GetNode("out.o")->dirty());
-
-  // Set the edge's |deps_are_invalid_| flag to ensure the next dependency
-  // scan will try to reload the depfile.
-  state_.Reset();
-  GetNode("out.o")->in_edge()->deps_loaded_ = false;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), NULL, &err));
-  ASSERT_EQ("", err);
-  EXPECT_TRUE(GetNode("out.o")->dirty());
-}
-
-// Regression test for https://fxbug.dev/135792
-TEST_F(GraphTest, DepfileOutputChanged) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-                                      "rule catdep\n"
-                                      "  depfile = $out.d\n"
-                                      "  command = echo OUT > $out\n"
-                                      "build ./out: catdep\n"));
-  // Create three files as if 'out' had been built by a command that generated
-  // a depfile pointing to blobs/1, all three files have the same timestamp
-  // so the corresponding Node should not be dirty.
-  fs_.Create("out.d", "out: blobs/1\n");
-  fs_.Create("out", "");
-  fs_.Create("blobs/1", "1");
-
-  Node* out_node = GetNode("out");
-  Edge* out_edge = out_node->in_edge();
-  EXPECT_TRUE(out_edge->inputs_.empty());
-
-  // Perform a dependency scan, then verify that the node is not dirty, and
-  // that blobs/1 was injected into the edge's inputs.
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("", err);
-  EXPECT_FALSE(out_node->dirty());
-  ASSERT_EQ(1u, out_edge->inputs_.size());
-  EXPECT_EQ(out_edge->inputs_[0]->path(), "blobs/1");
-
-  // Simulate a command that builds out while generating a depfile
-  // pointing to a different file. All three files have the same timestamp.
-  fs_.Tick();
-  fs_.Create("blobs/2", "2");
-  fs_.WriteFile("out.d", "out: blobs/2");
-  fs_.WriteFile("out", "");
-
-  state_.Reset();
-  out_edge->deps_loaded_ = false;
-
-  GetNode("out")->in_edge()->deps_loaded_ = false;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("", err);
-  EXPECT_FALSE(out_node->dirty());
-
-  // Verify that blobs/1 was removed from the list of inputs.
-  EXPECT_EQ(1u, out_edge->inputs_.size());
-  EXPECT_EQ(out_edge->inputs_[0]->path(), "blobs/2");
-}
-
-// Check that rule-level variables are in scope for eval.
-TEST_F(GraphTest, RuleVariablesInScope) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule r\n"
-"  depfile = x\n"
-"  command = depfile is $depfile\n"
-"build out: r in\n"));
-  Edge* edge = GetNode("out")->in_edge();
-  EXPECT_EQ("depfile is x", edge->EvaluateCommand());
-}
-
-// Check that build statements can override rule builtins like depfile.
-TEST_F(GraphTest, DepfileOverride) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule r\n"
-"  depfile = x\n"
-"  command = unused\n"
-"build out: r in\n"
-"  depfile = y\n"));
-  Edge* edge = GetNode("out")->in_edge();
-  EXPECT_EQ("y", edge->GetBinding("depfile"));
-}
-
-// Check that overridden values show up in expansion of rule-level bindings.
-TEST_F(GraphTest, DepfileOverrideParent) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule r\n"
-"  depfile = x\n"
-"  command = depfile is $depfile\n"
-"build out: r in\n"
-"  depfile = y\n"));
-  Edge* edge = GetNode("out")->in_edge();
-  EXPECT_EQ("depfile is y", edge->GetBinding("command"));
-}
-
-// Verify that building a nested phony rule prints "no work to do"
-TEST_F(GraphTest, NestedPhonyPrintsDone) {
-  AssertParse(&state_,
-"build n1: phony \n"
-"build n2: phony n1\n"
-  );
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("n2"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  Plan plan_;
-  EXPECT_TRUE(plan_.AddTarget(GetNode("n2"), &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_EQ(0, plan_.command_edge_count());
-  ASSERT_FALSE(plan_.more_to_do());
-}
-
-TEST_F(GraphTest, PhonySelfReferenceError) {
-  ManifestParserOptions parser_opts;
-  parser_opts.phony_cycle_action_ = kPhonyCycleActionError;
-  AssertParse(&state_,
-"build a: phony a\n",
-  parser_opts);
-
-  string err;
-  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("a"), NULL, &err));
-  ASSERT_EQ("dependency cycle: a -> a [-w phonycycle=err]", err);
-}
-
-TEST_F(GraphTest, DependencyCycle) {
-  AssertParse(&state_,
-"build out: cat mid\n"
-"build mid: cat in\n"
-"build in: cat pre\n"
-"build pre: cat out\n");
-
-  string err;
-  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("dependency cycle: out -> mid -> in -> pre -> out", err);
-}
-
-TEST_F(GraphTest, CycleInEdgesButNotInNodes1) {
-  string err;
-  AssertParse(&state_,
-"build a b: cat a\n");
-  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("b"), NULL, &err));
-  ASSERT_EQ("dependency cycle: a -> a", err);
-}
-
-TEST_F(GraphTest, CycleInEdgesButNotInNodes2) {
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build b a: cat a\n"));
-  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("b"), NULL, &err));
-  ASSERT_EQ("dependency cycle: a -> a", err);
-}
-
-TEST_F(GraphTest, CycleInEdgesButNotInNodes3) {
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build a b: cat c\n"
-"build c: cat a\n"));
-  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("b"), NULL, &err));
-  ASSERT_EQ("dependency cycle: a -> c -> a", err);
-}
-
-TEST_F(GraphTest, CycleInEdgesButNotInNodes4) {
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build d: cat c\n"
-"build c: cat b\n"
-"build b: cat a\n"
-"build a e: cat d\n"
-"build f: cat e\n"));
-  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("f"), NULL, &err));
-  ASSERT_EQ("dependency cycle: a -> d -> c -> b -> a", err);
-}
-
-// Verify that cycles in graphs with multiple outputs are handled correctly
-// in RecomputeDirty() and don't cause deps to be loaded multiple times.
-TEST_F(GraphTest, CycleWithLengthZeroFromDepfile) {
-  AssertParse(&state_,
-"rule deprule\n"
-"   depfile = dep.d\n"
-"   command = unused\n"
-"build a b: deprule\n"
-  );
-  fs_.Create("dep.d", "a: b\n");
-
-  string err;
-  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("a"), NULL, &err));
-  ASSERT_EQ("dependency cycle: b -> b", err);
-
-  // Despite the depfile causing edge to be a cycle (it has outputs a and b,
-  // but the depfile also adds b as an input), the deps should have been loaded
-  // only once:
-  Edge* edge = GetNode("a")->in_edge();
-  EXPECT_EQ(1, edge->inputs_.size());
-  EXPECT_EQ("b", edge->inputs_[0]->path());
-}
-
-// Like CycleWithLengthZeroFromDepfile but with a higher cycle length.
-TEST_F(GraphTest, CycleWithLengthOneFromDepfile) {
-  AssertParse(&state_,
-"rule deprule\n"
-"   depfile = dep.d\n"
-"   command = unused\n"
-"rule r\n"
-"   command = unused\n"
-"build a b: deprule\n"
-"build c: r b\n"
-  );
-  fs_.Create("dep.d", "a: c\n");
-
-  string err;
-  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("a"), NULL, &err));
-  ASSERT_EQ("dependency cycle: b -> c -> b", err);
-
-  // Despite the depfile causing edge to be a cycle (|edge| has outputs a and b,
-  // but c's in_edge has b as input but the depfile also adds |edge| as
-  // output)), the deps should have been loaded only once:
-  Edge* edge = GetNode("a")->in_edge();
-  EXPECT_EQ(1, edge->inputs_.size());
-  EXPECT_EQ("c", edge->inputs_[0]->path());
-}
-
-// Like CycleWithLengthOneFromDepfile but building a node one hop away from
-// the cycle.
-TEST_F(GraphTest, CycleWithLengthOneFromDepfileOneHopAway) {
-  AssertParse(&state_,
-"rule deprule\n"
-"   depfile = dep.d\n"
-"   command = unused\n"
-"rule r\n"
-"   command = unused\n"
-"build a b: deprule\n"
-"build c: r b\n"
-"build d: r a\n"
-  );
-  fs_.Create("dep.d", "a: c\n");
-
-  string err;
-  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("d"), NULL, &err));
-  ASSERT_EQ("dependency cycle: b -> c -> b", err);
-
-  // Despite the depfile causing edge to be a cycle (|edge| has outputs a and b,
-  // but c's in_edge has b as input but the depfile also adds |edge| as
-  // output)), the deps should have been loaded only once:
-  Edge* edge = GetNode("a")->in_edge();
-  EXPECT_EQ(1, edge->inputs_.size());
-  EXPECT_EQ("c", edge->inputs_[0]->path());
-}
-
-#ifdef _WIN32
-TEST_F(GraphTest, Decanonicalize) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out\\out1: cat src\\in1\n"
-"build out\\out2/out3\\out4: cat mid1\n"
-"build out3 out4\\foo: cat mid1\n"));
-
-  string err;
-  vector<Node*> root_nodes = state_.RootNodes(&err);
-  EXPECT_EQ(4u, root_nodes.size());
-  EXPECT_EQ(root_nodes[0]->path(), "out/out1");
-  EXPECT_EQ(root_nodes[1]->path(), "out/out2/out3/out4");
-  EXPECT_EQ(root_nodes[2]->path(), "out3");
-  EXPECT_EQ(root_nodes[3]->path(), "out4/foo");
-  EXPECT_EQ(root_nodes[0]->PathDecanonicalized(), "out\\out1");
-  EXPECT_EQ(root_nodes[1]->PathDecanonicalized(), "out\\out2/out3\\out4");
-  EXPECT_EQ(root_nodes[2]->PathDecanonicalized(), "out3");
-  EXPECT_EQ(root_nodes[3]->PathDecanonicalized(), "out4\\foo");
-}
-#endif
-
-TEST_F(GraphTest, DyndepLoadTrivial) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build out: r in || dd\n"
-"  dyndep = dd\n"
-  );
-  fs_.Create("dd",
-"ninja_dyndep_version = 1\n"
-"build out: dyndep\n"
-  );
-
-  string err;
-  ASSERT_TRUE(GetNode("dd")->dyndep_pending());
-  EXPECT_TRUE(scan_.LoadDyndeps(GetNode("dd"), &err));
-  EXPECT_EQ("", err);
-  EXPECT_FALSE(GetNode("dd")->dyndep_pending());
-
-  Edge* edge = GetNode("out")->in_edge();
-  ASSERT_EQ(1u, edge->outputs_.size());
-  EXPECT_EQ("out", edge->outputs_[0]->path());
-  ASSERT_EQ(2u, edge->inputs_.size());
-  EXPECT_EQ("in", edge->inputs_[0]->path());
-  EXPECT_EQ("dd", edge->inputs_[1]->path());
-  EXPECT_EQ(0u, edge->implicit_deps_);
-  EXPECT_EQ(1u, edge->order_only_deps_);
-  EXPECT_FALSE(edge->GetBindingBool("restat"));
-}
-
-TEST_F(GraphTest, DyndepLoadImplicit) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build out1: r in || dd\n"
-"  dyndep = dd\n"
-"build out2: r in\n"
-  );
-  fs_.Create("dd",
-"ninja_dyndep_version = 1\n"
-"build out1: dyndep | out2\n"
-  );
-
-  string err;
-  ASSERT_TRUE(GetNode("dd")->dyndep_pending());
-  EXPECT_TRUE(scan_.LoadDyndeps(GetNode("dd"), &err));
-  EXPECT_EQ("", err);
-  EXPECT_FALSE(GetNode("dd")->dyndep_pending());
-
-  Edge* edge = GetNode("out1")->in_edge();
-  ASSERT_EQ(1u, edge->outputs_.size());
-  EXPECT_EQ("out1", edge->outputs_[0]->path());
-  ASSERT_EQ(3u, edge->inputs_.size());
-  EXPECT_EQ("in", edge->inputs_[0]->path());
-  EXPECT_EQ("out2", edge->inputs_[1]->path());
-  EXPECT_EQ("dd", edge->inputs_[2]->path());
-  EXPECT_EQ(1u, edge->implicit_deps_);
-  EXPECT_EQ(1u, edge->order_only_deps_);
-  EXPECT_FALSE(edge->GetBindingBool("restat"));
-}
-
-TEST_F(GraphTest, DyndepLoadMissingFile) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build out: r in || dd\n"
-"  dyndep = dd\n"
-  );
-
-  string err;
-  ASSERT_TRUE(GetNode("dd")->dyndep_pending());
-  EXPECT_FALSE(scan_.LoadDyndeps(GetNode("dd"), &err));
-  EXPECT_EQ("loading 'dd': No such file or directory", err);
-}
-
-TEST_F(GraphTest, DyndepLoadMissingEntry) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build out: r in || dd\n"
-"  dyndep = dd\n"
-  );
-  fs_.Create("dd",
-"ninja_dyndep_version = 1\n"
-  );
-
-  string err;
-  ASSERT_TRUE(GetNode("dd")->dyndep_pending());
-  EXPECT_FALSE(scan_.LoadDyndeps(GetNode("dd"), &err));
-  EXPECT_EQ("'out' not mentioned in its dyndep file 'dd'", err);
-}
-
-TEST_F(GraphTest, DyndepLoadExtraEntry) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build out: r in || dd\n"
-"  dyndep = dd\n"
-"build out2: r in || dd\n"
-  );
-  fs_.Create("dd",
-"ninja_dyndep_version = 1\n"
-"build out: dyndep\n"
-"build out2: dyndep\n"
-  );
-
-  string err;
-  ASSERT_TRUE(GetNode("dd")->dyndep_pending());
-  EXPECT_FALSE(scan_.LoadDyndeps(GetNode("dd"), &err));
-  EXPECT_EQ("dyndep file 'dd' mentions output 'out2' whose build statement "
-            "does not have a dyndep binding for the file", err);
-}
-
-TEST_F(GraphTest, DyndepLoadOutputWithMultipleRules1) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build out1 | out-twice.imp: r in1\n"
-"build out2: r in2 || dd\n"
-"  dyndep = dd\n"
-  );
-  fs_.Create("dd",
-"ninja_dyndep_version = 1\n"
-"build out2 | out-twice.imp: dyndep\n"
-  );
-
-  string err;
-  ASSERT_TRUE(GetNode("dd")->dyndep_pending());
-  EXPECT_FALSE(scan_.LoadDyndeps(GetNode("dd"), &err));
-  EXPECT_EQ("multiple rules generate out-twice.imp", err);
-}
-
-TEST_F(GraphTest, DyndepLoadOutputWithMultipleRules2) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build out1: r in1 || dd1\n"
-"  dyndep = dd1\n"
-"build out2: r in2 || dd2\n"
-"  dyndep = dd2\n"
-  );
-  fs_.Create("dd1",
-"ninja_dyndep_version = 1\n"
-"build out1 | out-twice.imp: dyndep\n"
-  );
-  fs_.Create("dd2",
-"ninja_dyndep_version = 1\n"
-"build out2 | out-twice.imp: dyndep\n"
-  );
-
-  string err;
-  ASSERT_TRUE(GetNode("dd1")->dyndep_pending());
-  EXPECT_TRUE(scan_.LoadDyndeps(GetNode("dd1"), &err));
-  EXPECT_EQ("", err);
-  ASSERT_TRUE(GetNode("dd2")->dyndep_pending());
-  EXPECT_FALSE(scan_.LoadDyndeps(GetNode("dd2"), &err));
-  EXPECT_EQ("multiple rules generate out-twice.imp", err);
-}
-
-TEST_F(GraphTest, DyndepLoadMultiple) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build out1: r in1 || dd\n"
-"  dyndep = dd\n"
-"build out2: r in2 || dd\n"
-"  dyndep = dd\n"
-"build outNot: r in3 || dd\n"
-  );
-  fs_.Create("dd",
-"ninja_dyndep_version = 1\n"
-"build out1 | out1imp: dyndep | in1imp\n"
-"build out2: dyndep | in2imp\n"
-"  restat = 1\n"
-  );
-
-  string err;
-  ASSERT_TRUE(GetNode("dd")->dyndep_pending());
-  EXPECT_TRUE(scan_.LoadDyndeps(GetNode("dd"), &err));
-  EXPECT_EQ("", err);
-  EXPECT_FALSE(GetNode("dd")->dyndep_pending());
-
-  Edge* edge1 = GetNode("out1")->in_edge();
-  ASSERT_EQ(2u, edge1->outputs_.size());
-  EXPECT_EQ("out1", edge1->outputs_[0]->path());
-  EXPECT_EQ("out1imp", edge1->outputs_[1]->path());
-  EXPECT_EQ(1u, edge1->implicit_outs_);
-  ASSERT_EQ(3u, edge1->inputs_.size());
-  EXPECT_EQ("in1", edge1->inputs_[0]->path());
-  EXPECT_EQ("in1imp", edge1->inputs_[1]->path());
-  EXPECT_EQ("dd", edge1->inputs_[2]->path());
-  EXPECT_EQ(1u, edge1->implicit_deps_);
-  EXPECT_EQ(1u, edge1->order_only_deps_);
-  EXPECT_FALSE(edge1->GetBindingBool("restat"));
-  EXPECT_EQ(edge1, GetNode("out1imp")->in_edge());
-  Node* in1imp = GetNode("in1imp");
-  ASSERT_EQ(1u, in1imp->out_edges().size());
-  EXPECT_EQ(edge1, in1imp->out_edges()[0]);
-
-  Edge* edge2 = GetNode("out2")->in_edge();
-  ASSERT_EQ(1u, edge2->outputs_.size());
-  EXPECT_EQ("out2", edge2->outputs_[0]->path());
-  EXPECT_EQ(0u, edge2->implicit_outs_);
-  ASSERT_EQ(3u, edge2->inputs_.size());
-  EXPECT_EQ("in2", edge2->inputs_[0]->path());
-  EXPECT_EQ("in2imp", edge2->inputs_[1]->path());
-  EXPECT_EQ("dd", edge2->inputs_[2]->path());
-  EXPECT_EQ(1u, edge2->implicit_deps_);
-  EXPECT_EQ(1u, edge2->order_only_deps_);
-  EXPECT_TRUE(edge2->GetBindingBool("restat"));
-  Node* in2imp = GetNode("in2imp");
-  ASSERT_EQ(1u, in2imp->out_edges().size());
-  EXPECT_EQ(edge2, in2imp->out_edges()[0]);
-}
-
-TEST_F(GraphTest, DyndepFileMissing) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build out: r || dd\n"
-"  dyndep = dd\n"
-  );
-
-  string err;
-  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("loading 'dd': No such file or directory", err);
-}
-
-TEST_F(GraphTest, DyndepFileError) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build out: r || dd\n"
-"  dyndep = dd\n"
-  );
-  fs_.Create("dd",
-"ninja_dyndep_version = 1\n"
-  );
-
-  string err;
-  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("'out' not mentioned in its dyndep file 'dd'", err);
-}
-
-TEST_F(GraphTest, DyndepImplicitInputNewer) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build out: r || dd\n"
-"  dyndep = dd\n"
-  );
-  fs_.Create("dd",
-"ninja_dyndep_version = 1\n"
-"build out: dyndep | in\n"
-  );
-  fs_.Create("out", "");
-  fs_.Tick();
-  fs_.Create("in", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_FALSE(GetNode("in")->dirty());
-  EXPECT_FALSE(GetNode("dd")->dirty());
-
-  // "out" is dirty due to dyndep-specified implicit input
-  EXPECT_TRUE(GetNode("out")->dirty());
-}
-
-TEST_F(GraphTest, DyndepFileReady) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build dd: r dd-in\n"
-"build out: r || dd\n"
-"  dyndep = dd\n"
-  );
-  fs_.Create("dd-in", "");
-  fs_.Create("dd",
-"ninja_dyndep_version = 1\n"
-"build out: dyndep | in\n"
-  );
-  fs_.Create("out", "");
-  fs_.Tick();
-  fs_.Create("in", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_FALSE(GetNode("in")->dirty());
-  EXPECT_FALSE(GetNode("dd")->dirty());
-  EXPECT_TRUE(GetNode("dd")->in_edge()->outputs_ready());
-
-  // "out" is dirty due to dyndep-specified implicit input
-  EXPECT_TRUE(GetNode("out")->dirty());
-}
-
-TEST_F(GraphTest, DyndepFileNotClean) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build dd: r dd-in\n"
-"build out: r || dd\n"
-"  dyndep = dd\n"
-  );
-  fs_.Create("dd", "this-should-not-be-loaded");
-  fs_.Tick();
-  fs_.Create("dd-in", "");
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_TRUE(GetNode("dd")->dirty());
-  EXPECT_FALSE(GetNode("dd")->in_edge()->outputs_ready());
-
-  // "out" is clean but not ready since "dd" is not ready
-  EXPECT_FALSE(GetNode("out")->dirty());
-  EXPECT_FALSE(GetNode("out")->in_edge()->outputs_ready());
-}
-
-TEST_F(GraphTest, DyndepFileNotReady) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build tmp: r\n"
-"build dd: r dd-in || tmp\n"
-"build out: r || dd\n"
-"  dyndep = dd\n"
-  );
-  fs_.Create("dd", "this-should-not-be-loaded");
-  fs_.Create("dd-in", "");
-  fs_.Tick();
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_FALSE(GetNode("dd")->dirty());
-  EXPECT_FALSE(GetNode("dd")->in_edge()->outputs_ready());
-  EXPECT_FALSE(GetNode("out")->dirty());
-  EXPECT_FALSE(GetNode("out")->in_edge()->outputs_ready());
-}
-
-TEST_F(GraphTest, DyndepFileSecondNotReady) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build dd1: r dd1-in\n"
-"build dd2-in: r || dd1\n"
-"  dyndep = dd1\n"
-"build dd2: r dd2-in\n"
-"build out: r || dd2\n"
-"  dyndep = dd2\n"
-  );
-  fs_.Create("dd1", "");
-  fs_.Create("dd2", "");
-  fs_.Create("dd2-in", "");
-  fs_.Tick();
-  fs_.Create("dd1-in", "");
-  fs_.Create("out", "");
-
-  string err;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  ASSERT_EQ("", err);
-
-  EXPECT_TRUE(GetNode("dd1")->dirty());
-  EXPECT_FALSE(GetNode("dd1")->in_edge()->outputs_ready());
-  EXPECT_FALSE(GetNode("dd2")->dirty());
-  EXPECT_FALSE(GetNode("dd2")->in_edge()->outputs_ready());
-  EXPECT_FALSE(GetNode("out")->dirty());
-  EXPECT_FALSE(GetNode("out")->in_edge()->outputs_ready());
-}
-
-TEST_F(GraphTest, DyndepFileCircular) {
-  AssertParse(&state_,
-"rule r\n"
-"  command = unused\n"
-"build out: r in || dd\n"
-"  depfile = out.d\n"
-"  dyndep = dd\n"
-"build in: r circ\n"
-  );
-  fs_.Create("out.d", "out: inimp\n");
-  fs_.Create("dd",
-"ninja_dyndep_version = 1\n"
-"build out | circ: dyndep\n"
-  );
-  fs_.Create("out", "");
-
-  Edge* edge = GetNode("out")->in_edge();
-  string err;
-  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-  EXPECT_EQ("dependency cycle: circ -> in -> circ", err);
-
-  // Verify that "out.d" was loaded exactly once despite
-  // circular reference discovered from dyndep file.
-  ASSERT_EQ(3u, edge->inputs_.size());
-  EXPECT_EQ("in", edge->inputs_[0]->path());
-  EXPECT_EQ("inimp", edge->inputs_[1]->path());
-  EXPECT_EQ("dd", edge->inputs_[2]->path());
-  EXPECT_EQ(1u, edge->implicit_deps_);
-  EXPECT_EQ(1u, edge->order_only_deps_);
-}
-
-TEST_F(GraphTest, DyndepLoadIncremental) {
-  AssertParse(&state_,
-              "rule r\n"
-              "  command = unused\n"
-              "build out: r in || dd\n"
-              "  dyndep = dd\n");
-
-  // First version of the dyndep file adds one implicit output, and
-  // one implicit input.
-  fs_.Create("dd",
-             "ninja_dyndep_version = 1\n"
-             "build out | implicit_out: dyndep | implicit1\n");
-
-  string err;
-  ASSERT_TRUE(GetNode("dd")->dyndep_pending());
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
-
-  EXPECT_EQ("", err);
-  Node* out_node = GetNode("out");
-  Edge* edge = out_node->in_edge();
-
-  // Check that implicit_out was inserted as a dynamic implicit output.
-  ASSERT_EQ(2u, edge->outputs_.size());
-  EXPECT_EQ(0, edge->static_implicit_outs_);
-  EXPECT_EQ(1, edge->implicit_outs_);
-  EXPECT_EQ("out", edge->outputs_[0]->path());
-  EXPECT_EQ("implicit_out", edge->outputs_[1]->path());
-
-  // Check that implicit1 was inserted as a dynamic implicit input,
-  // i.e. before order-only deps in the inputs_ array.
-  ASSERT_EQ(3u, edge->inputs_.size());
-  EXPECT_EQ("in", edge->inputs_[0]->path());
-  EXPECT_EQ("implicit1", edge->inputs_[1]->path());
-  EXPECT_EQ("dd", edge->inputs_[2]->path());
-  EXPECT_EQ(0u, edge->static_implicit_deps_);
-  EXPECT_EQ(1u, edge->implicit_deps_);
-  EXPECT_EQ(1u, edge->order_only_deps_);
-  EXPECT_FALSE(edge->GetBindingBool("restat"));
-
-  // Perform a second scan, forcing a reload of the dyndep information.
-  // and verify that nothing changed.
-  state_.Reset();
-  edge->deps_loaded_ = false;
-  edge->dyndep_->set_dyndep_pending(true);
-  EXPECT_TRUE(scan_.RecomputeDirty(out_node, NULL, &err));
-
-  EXPECT_EQ("", err);
-  ASSERT_EQ(2u, edge->outputs_.size());
-  EXPECT_EQ(0, edge->static_implicit_outs_);
-  EXPECT_EQ(1, edge->implicit_outs_);
-  EXPECT_EQ("out", edge->outputs_[0]->path());
-  EXPECT_EQ("implicit_out", edge->outputs_[1]->path());
-
-  ASSERT_EQ(3u, edge->inputs_.size());
-  EXPECT_EQ("in", edge->inputs_[0]->path());
-  EXPECT_EQ("implicit1", edge->inputs_[1]->path());
-  EXPECT_EQ("dd", edge->inputs_[2]->path());
-  EXPECT_EQ(0u, edge->static_implicit_deps_);
-  EXPECT_EQ(1u, edge->implicit_deps_);
-  EXPECT_EQ(1u, edge->order_only_deps_);
-  EXPECT_FALSE(edge->GetBindingBool("restat"));
-
-  // Now modify the dyndep file content to add a new implicit output,
-  // and two new implicit inputs. Note that some of the new files are listed
-  // _before_ the current ones.
-  fs_.Tick();
-  fs_.WriteFile("dd",
-                "ninja_dyndep_version = 1\n"
-                "build out | implicit_out2 implicit_out: dyndep | implicit2 "
-                "implicit1 implicit3\n");
-
-  state_.Reset();
-  edge->deps_loaded_ = false;
-  edge->dyndep_->set_dyndep_pending(true);
-  EXPECT_TRUE(scan_.RecomputeDirty(out_node, NULL, &err));
-
-  EXPECT_EQ("", err);
-  // Verify that the new implicit output was inserted _after_ the first one
-  // even though it appeared before it in the dyndep file.
-  ASSERT_EQ(3u, edge->outputs_.size());
-  EXPECT_EQ(0, edge->static_implicit_outs_);
-  EXPECT_EQ(2, edge->implicit_outs_);
-  EXPECT_EQ("out", edge->outputs_[0]->path());
-  EXPECT_EQ("implicit_out", edge->outputs_[1]->path());
-  EXPECT_EQ("implicit_out2", edge->outputs_[2]->path());
-
-  // Verify that the new implicits input were inserted _after_ the first one
-  // even though some appeared before it in the dyndep file.
-  ASSERT_EQ(5u, edge->inputs_.size());
-  EXPECT_EQ("in", edge->inputs_[0]->path());
-  EXPECT_EQ("implicit1", edge->inputs_[1]->path());
-  EXPECT_EQ("implicit2", edge->inputs_[2]->path());
-  EXPECT_EQ("implicit3", edge->inputs_[3]->path());
-  EXPECT_EQ("dd", edge->inputs_[4]->path());
-  EXPECT_EQ(0u, edge->static_implicit_deps_);
-  EXPECT_EQ(3u, edge->implicit_deps_);
-  EXPECT_EQ(1u, edge->order_only_deps_);
-  EXPECT_FALSE(edge->GetBindingBool("restat"));
-
-  // Modify the dyndep file again to remove all implicit outputs, and the
-  // two implicit inputs.
-  fs_.Tick();
-  fs_.WriteFile("dd",
-                "ninja_dyndep_version = 1\n"
-                "build out: dyndep | implicit2\n");
-
-  state_.Reset();
-  edge->deps_loaded_ = false;
-  edge->dyndep_->set_dyndep_pending(true);
-  EXPECT_TRUE(scan_.RecomputeDirty(out_node, NULL, &err));
-
-  EXPECT_EQ("", err);
-  // Verify that all dynamic implicit outputs were removed.
-  ASSERT_EQ(1u, edge->outputs_.size());
-  EXPECT_EQ(0, edge->static_implicit_outs_);
-  EXPECT_EQ(0, edge->implicit_outs_);
-  EXPECT_EQ("out", edge->outputs_[0]->path());
-
-  // Verify that only one dynamic implicit input remains.
-  ASSERT_EQ(3u, edge->inputs_.size());
-  EXPECT_EQ("in", edge->inputs_[0]->path());
-  EXPECT_EQ("implicit2", edge->inputs_[1]->path());
-  EXPECT_EQ("dd", edge->inputs_[2]->path());
-  EXPECT_EQ(0u, edge->static_implicit_deps_);
-  EXPECT_EQ(1u, edge->implicit_deps_);
-  EXPECT_EQ(1u, edge->order_only_deps_);
-  EXPECT_FALSE(edge->GetBindingBool("restat"));
-}
-
-TEST_F(GraphTest, Validation) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"build out: cat in |@ validate\n"
-"build validate: cat in\n"));
-
-  fs_.Create("in", "");
-  string err;
-  std::vector<Node*> validation_nodes;
-  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), &validation_nodes, &err));
-  ASSERT_EQ("", err);
-
-  ASSERT_EQ(validation_nodes.size(), 1);
-  EXPECT_EQ(validation_nodes[0]->path(), "validate");
-
-  EXPECT_TRUE(GetNode("out")->dirty());
-  EXPECT_TRUE(GetNode("validate")->dirty());
-}
-
-// Check that phony's dependencies' mtimes are propagated.
-TEST_F(GraphTest, PhonyDepsMtimes) {
-  string err;
-  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
-"rule touch\n"
-" command = touch $out\n"
-"build in_ph: phony in1\n"
-"build out1: touch in_ph\n"
-));
-  fs_.Create("in1", "");
-  fs_.Create("out1", "");
-  Node* out1 = GetNode("out1");
-  Node* in1  = GetNode("in1");
-
-  EXPECT_TRUE(scan_.RecomputeDirty(out1, NULL, &err));
-  EXPECT_TRUE(!out1->dirty());
-
-  // Get the mtime of out1
-  ASSERT_TRUE(in1->Stat(&fs_, &err));
-  ASSERT_TRUE(out1->Stat(&fs_, &err));
-  TimeStamp out1Mtime1 = out1->mtime();
-  TimeStamp in1Mtime1 = in1->mtime();
-
-  // Touch in1. This should cause out1 to be dirty
-  state_.Reset();
-  fs_.Tick();
-  fs_.Create("in1", "");
-
-  ASSERT_TRUE(in1->Stat(&fs_, &err));
-  EXPECT_GT(in1->mtime(), in1Mtime1);
-
-  EXPECT_TRUE(scan_.RecomputeDirty(out1, NULL, &err));
-  EXPECT_GT(in1->mtime(), in1Mtime1);
-  EXPECT_EQ(out1->mtime(), out1Mtime1);
-  EXPECT_TRUE(out1->dirty());
-}
diff --git a/src/graphviz.cc b/src/graphviz.cc
deleted file mode 100644
index 37b7108..0000000
--- a/src/graphviz.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-// 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.
-
-#include "graphviz.h"
-
-#include <stdio.h>
-#include <algorithm>
-
-#include "dyndep.h"
-#include "graph.h"
-
-using namespace std;
-
-void GraphViz::AddTarget(Node* node) {
-  if (visited_nodes_.find(node) != visited_nodes_.end())
-    return;
-
-  string pathstr = node->path();
-  replace(pathstr.begin(), pathstr.end(), '\\', '/');
-  printf("\"%p\" [label=\"%s\"]\n", node, pathstr.c_str());
-  visited_nodes_.insert(node);
-
-  Edge* edge = node->in_edge();
-
-  if (!edge) {
-    // Leaf node.
-    // Draw as a rect?
-    return;
-  }
-
-  if (visited_edges_.find(edge) != visited_edges_.end())
-    return;
-  visited_edges_.insert(edge);
-
-  if (edge->dyndep_ && edge->dyndep_->dyndep_pending()) {
-    std::string err;
-    if (!dyndep_loader_.LoadDyndeps(edge->dyndep_, &err)) {
-      Warning("%s\n", err.c_str());
-    }
-  }
-
-  if (edge->inputs_.size() == 1 && edge->outputs_.size() == 1) {
-    // Can draw simply.
-    // Note extra space before label text -- this is cosmetic and feels
-    // like a graphviz bug.
-    printf("\"%p\" -> \"%p\" [label=\" %s\"]\n",
-           edge->inputs_[0], edge->outputs_[0], edge->rule_->name().c_str());
-  } else {
-    printf("\"%p\" [label=\"%s\", shape=ellipse]\n",
-           edge, edge->rule_->name().c_str());
-    for (vector<Node*>::iterator out = edge->outputs_.begin();
-         out != edge->outputs_.end(); ++out) {
-      printf("\"%p\" -> \"%p\"\n", edge, *out);
-    }
-    for (vector<Node*>::iterator in = edge->inputs_.begin();
-         in != edge->inputs_.end(); ++in) {
-      const char* order_only = "";
-      if (edge->is_order_only(in - edge->inputs_.begin()))
-        order_only = " style=dotted";
-      printf("\"%p\" -> \"%p\" [arrowhead=none%s]\n", (*in), edge, order_only);
-    }
-  }
-
-  for (vector<Node*>::iterator in = edge->inputs_.begin();
-       in != edge->inputs_.end(); ++in) {
-    AddTarget(*in);
-  }
-}
-
-void GraphViz::Start() {
-  printf("digraph ninja {\n");
-  printf("rankdir=\"LR\"\n");
-  printf("node [fontsize=10, shape=box, height=0.25]\n");
-  printf("edge [fontsize=10]\n");
-}
-
-void GraphViz::Finish() {
-  printf("}\n");
-}
diff --git a/src/graphviz.h b/src/graphviz.h
deleted file mode 100644
index 3a3282e..0000000
--- a/src/graphviz.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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.
-
-#ifndef NINJA_GRAPHVIZ_H_
-#define NINJA_GRAPHVIZ_H_
-
-#include <set>
-
-#include "dyndep.h"
-#include "graph.h"
-
-struct DiskInterface;
-struct Node;
-struct Edge;
-struct State;
-
-/// Runs the process of creating GraphViz .dot file output.
-struct GraphViz {
-  GraphViz(State* state, DiskInterface* disk_interface)
-      : dyndep_loader_(state, disk_interface) {}
-  void Start();
-  void AddTarget(Node* node);
-  void Finish();
-
-  DyndepLoader dyndep_loader_;
-  std::set<Node*> visited_nodes_;
-  EdgeSet visited_edges_;
-};
-
-#endif  // NINJA_GRAPHVIZ_H_
diff --git a/src/hash_collision_bench.cc b/src/hash_collision_bench.cc
deleted file mode 100644
index 8f37ed0..0000000
--- a/src/hash_collision_bench.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2012 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 "build_log.h"
-
-#include <algorithm>
-
-#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+1];
-  for (int i = 0; i < len; ++i)
-    (*s)[i] = (char)random(32, 127);
-  (*s)[len] = '\0';
-}
-
-int main() {
-  const int N = 20 * 1000 * 1000;
-
-  // Leak these, else 10% of the runtime is spent destroying strings.
-  char** commands = new char*[N];
-  pair<uint64_t, int>* hashes = new pair<uint64_t, int>[N];
-
-  srand((int)time(NULL));
-
-  for (int i = 0; i < N; ++i) {
-    RandomCommand(&commands[i]);
-    hashes[i] = make_pair(BuildLog::LogEntry::HashCommand(commands[i]), i);
-  }
-
-  sort(hashes, hashes + N);
-
-  int collision_count = 0;
-  for (int i = 1; i < N; ++i) {
-    if (hashes[i - 1].first == hashes[i].first) {
-      if (strcmp(commands[hashes[i - 1].second],
-                 commands[hashes[i].second]) != 0) {
-        printf("collision!\n  string 1: '%s'\n  string 2: '%s'\n",
-               commands[hashes[i - 1].second],
-               commands[hashes[i].second]);
-        collision_count++;
-      }
-    }
-  }
-  printf("\n\n%d collisions after %d runs\n", collision_count, N);
-}
diff --git a/src/hash_map.h b/src/hash_map.h
deleted file mode 100644
index 4353609..0000000
--- a/src/hash_map.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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.
-
-#ifndef NINJA_MAP_H_
-#define NINJA_MAP_H_
-
-#include <algorithm>
-#include <string.h>
-#include "string_piece.h"
-#include "util.h"
-
-// MurmurHash2, by Austin Appleby
-static inline
-unsigned int MurmurHash2(const void* key, size_t len) {
-  static const unsigned int seed = 0xDECAFBAD;
-  const unsigned int m = 0x5bd1e995;
-  const int r = 24;
-  unsigned int h = seed ^ len;
-  const unsigned char* data = (const unsigned char*)key;
-  while (len >= 4) {
-    unsigned int k;
-    memcpy(&k, data, sizeof k);
-    k *= m;
-    k ^= k >> r;
-    k *= m;
-    h *= m;
-    h ^= k;
-    data += 4;
-    len -= 4;
-  }
-  switch (len) {
-  case 3: h ^= data[2] << 16;
-          NINJA_FALLTHROUGH;
-  case 2: h ^= data[1] << 8;
-          NINJA_FALLTHROUGH;
-  case 1: h ^= data[0];
-    h *= m;
-  };
-  h ^= h >> 13;
-  h *= m;
-  h ^= h >> 15;
-  return h;
-}
-
-#include <unordered_map>
-
-namespace std {
-template<>
-struct hash<StringPiece> {
-  typedef StringPiece argument_type;
-  typedef size_t result_type;
-
-  size_t operator()(StringPiece key) const {
-    return MurmurHash2(key.str_, key.len_);
-  }
-};
-}
-
-/// A template for hash_maps keyed by a StringPiece whose string is
-/// owned externally (typically by the values).  Use like:
-/// ExternalStringHash<Foo*>::Type foos; to make foos into a hash
-/// mapping StringPiece => Foo*.
-template<typename V>
-struct ExternalStringHashMap {
-  typedef std::unordered_map<StringPiece, V> Type;
-};
-
-#endif // NINJA_MAP_H_
diff --git a/src/includes_normalize-win32.cc b/src/includes_normalize-win32.cc
deleted file mode 100644
index 081e364..0000000
--- a/src/includes_normalize-win32.cc
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright 2012 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 "includes_normalize.h"
-
-#include "string_piece.h"
-#include "string_piece_util.h"
-#include "util.h"
-
-#include <algorithm>
-#include <iterator>
-#include <sstream>
-
-#include <windows.h>
-
-using namespace std;
-
-namespace {
-
-bool InternalGetFullPathName(const StringPiece& file_name, char* buffer,
-                             size_t buffer_length, string *err) {
-  DWORD result_size = GetFullPathNameA(file_name.AsString().c_str(),
-                                       buffer_length, buffer, NULL);
-  if (result_size == 0) {
-    *err = "GetFullPathNameA(" + file_name.AsString() + "): " +
-        GetLastErrorString();
-    return false;
-  } else if (result_size > buffer_length) {
-    *err = "path too long";
-    return false;
-  }
-  return true;
-}
-
-bool IsPathSeparator(char c) {
-  return c == '/' ||  c == '\\';
-}
-
-// Return true if paths a and b are on the same windows drive.
-// Return false if this function cannot check
-// whether or not on the same windows drive.
-bool SameDriveFast(StringPiece a, StringPiece b) {
-  if (a.size() < 3 || b.size() < 3) {
-    return false;
-  }
-
-  if (!islatinalpha(a[0]) || !islatinalpha(b[0])) {
-    return false;
-  }
-
-  if (ToLowerASCII(a[0]) != ToLowerASCII(b[0])) {
-    return false;
-  }
-
-  if (a[1] != ':' || b[1] != ':') {
-    return false;
-  }
-
-  return IsPathSeparator(a[2]) && IsPathSeparator(b[2]);
-}
-
-// Return true if paths a and b are on the same Windows drive.
-bool SameDrive(StringPiece a, StringPiece b, string* err)  {
-  if (SameDriveFast(a, b)) {
-    return true;
-  }
-
-  char a_absolute[_MAX_PATH];
-  char b_absolute[_MAX_PATH];
-  if (!InternalGetFullPathName(a, a_absolute, sizeof(a_absolute), err)) {
-    return false;
-  }
-  if (!InternalGetFullPathName(b, b_absolute, sizeof(b_absolute), err)) {
-    return false;
-  }
-  char a_drive[_MAX_DIR];
-  char b_drive[_MAX_DIR];
-  _splitpath(a_absolute, a_drive, NULL, NULL, NULL);
-  _splitpath(b_absolute, b_drive, NULL, NULL, NULL);
-  return _stricmp(a_drive, b_drive) == 0;
-}
-
-// Check path |s| is FullPath style returned by GetFullPathName.
-// This ignores difference of path separator.
-// This is used not to call very slow GetFullPathName API.
-bool IsFullPathName(StringPiece s) {
-  if (s.size() < 3 ||
-      !islatinalpha(s[0]) ||
-      s[1] != ':' ||
-      !IsPathSeparator(s[2])) {
-    return false;
-  }
-
-  // Check "." or ".." is contained in path.
-  for (size_t i = 2; i < s.size(); ++i) {
-    if (!IsPathSeparator(s[i])) {
-      continue;
-    }
-
-    // Check ".".
-    if (i + 1 < s.size() && s[i+1] == '.' &&
-        (i + 2 >= s.size() || IsPathSeparator(s[i+2]))) {
-      return false;
-    }
-
-    // Check "..".
-    if (i + 2 < s.size() && s[i+1] == '.' && s[i+2] == '.' &&
-        (i + 3 >= s.size() || IsPathSeparator(s[i+3]))) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-}  // anonymous namespace
-
-IncludesNormalize::IncludesNormalize(const string& relative_to) {
-  string err;
-  relative_to_ = AbsPath(relative_to, &err);
-  if (!err.empty()) {
-    Fatal("Initializing IncludesNormalize(): %s", err.c_str());
-  }
-  split_relative_to_ = SplitStringPiece(relative_to_, '/');
-}
-
-string IncludesNormalize::AbsPath(StringPiece s, string* err) {
-  if (IsFullPathName(s)) {
-    string result = s.AsString();
-    for (size_t i = 0; i < result.size(); ++i) {
-      if (result[i] == '\\') {
-        result[i] = '/';
-      }
-    }
-    return result;
-  }
-
-  char result[_MAX_PATH];
-  if (!InternalGetFullPathName(s, result, sizeof(result), err)) {
-    return "";
-  }
-  for (char* c = result; *c; ++c)
-    if (*c == '\\')
-      *c = '/';
-  return result;
-}
-
-string IncludesNormalize::Relativize(
-    StringPiece path, const vector<StringPiece>& start_list, string* err) {
-  string abs_path = AbsPath(path, err);
-  if (!err->empty())
-    return "";
-  vector<StringPiece> path_list = SplitStringPiece(abs_path, '/');
-  int i;
-  for (i = 0; i < static_cast<int>(min(start_list.size(), path_list.size()));
-       ++i) {
-    if (!EqualsCaseInsensitiveASCII(start_list[i], path_list[i])) {
-      break;
-    }
-  }
-
-  vector<StringPiece> rel_list;
-  rel_list.reserve(start_list.size() - i + path_list.size() - i);
-  for (int j = 0; j < static_cast<int>(start_list.size() - i); ++j)
-    rel_list.push_back("..");
-  for (int j = i; j < static_cast<int>(path_list.size()); ++j)
-    rel_list.push_back(path_list[j]);
-  if (rel_list.size() == 0)
-    return ".";
-  return JoinStringPiece(rel_list, '/');
-}
-
-bool IncludesNormalize::Normalize(const string& input,
-                                  string* result, string* err) const {
-  char copy[_MAX_PATH + 1];
-  size_t len = input.size();
-  if (len > _MAX_PATH) {
-    *err = "path too long";
-    return false;
-  }
-  strncpy(copy, input.c_str(), input.size() + 1);
-  uint64_t slash_bits;
-  CanonicalizePath(copy, &len, &slash_bits);
-  StringPiece partially_fixed(copy, len);
-  string abs_input = AbsPath(partially_fixed, err);
-  if (!err->empty())
-    return false;
-
-  if (!SameDrive(abs_input, relative_to_, err)) {
-    if (!err->empty())
-      return false;
-    *result = partially_fixed.AsString();
-    return true;
-  }
-  *result = Relativize(abs_input, split_relative_to_, err);
-  if (!err->empty())
-    return false;
-  return true;
-}
diff --git a/src/includes_normalize.h b/src/includes_normalize.h
deleted file mode 100644
index 7d50556..0000000
--- a/src/includes_normalize.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2012 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 <string>
-#include <vector>
-
-struct StringPiece;
-
-/// Utility functions for normalizing include paths on Windows.
-/// TODO: this likely duplicates functionality of CanonicalizePath; refactor.
-struct IncludesNormalize {
-  /// Normalize path relative to |relative_to|.
-  IncludesNormalize(const std::string& relative_to);
-
-  // Internal utilities made available for testing, maybe useful otherwise.
-  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 std::string& input, std::string* result,
-                 std::string* err) const;
-
- private:
-  std::string relative_to_;
-  std::vector<StringPiece> split_relative_to_;
-};
diff --git a/src/includes_normalize_test.cc b/src/includes_normalize_test.cc
deleted file mode 100644
index 5d99396..0000000
--- a/src/includes_normalize_test.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2012 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 "includes_normalize.h"
-
-#include <algorithm>
-
-#include <direct.h>
-
-#include "string_piece_util.h"
-#include "test.h"
-#include "util.h"
-
-using namespace std;
-
-namespace {
-
-string GetCurDir() {
-  char buf[_MAX_PATH];
-  _getcwd(buf, sizeof(buf));
-  vector<StringPiece> parts = SplitStringPiece(buf, '\\');
-  return parts[parts.size() - 1].AsString();
-}
-
-string NormalizeAndCheckNoError(const string& input) {
-  string result, err;
-  IncludesNormalize normalizer(".");
-  EXPECT_TRUE(normalizer.Normalize(input, &result, &err));
-  EXPECT_EQ("", err);
-  return result;
-}
-
-string NormalizeRelativeAndCheckNoError(const string& input,
-                                        const string& relative_to) {
-  string result, err;
-  IncludesNormalize normalizer(relative_to);
-  EXPECT_TRUE(normalizer.Normalize(input, &result, &err));
-  EXPECT_EQ("", err);
-  return result;
-}
-
-}  // namespace
-
-TEST(IncludesNormalize, Simple) {
-  EXPECT_EQ("b", NormalizeAndCheckNoError("a\\..\\b"));
-  EXPECT_EQ("b", NormalizeAndCheckNoError("a\\../b"));
-  EXPECT_EQ("a/b", NormalizeAndCheckNoError("a\\.\\b"));
-  EXPECT_EQ("a/b", NormalizeAndCheckNoError("a\\./b"));
-}
-
-TEST(IncludesNormalize, WithRelative) {
-  string err;
-  string currentdir = GetCurDir();
-  EXPECT_EQ("c", NormalizeRelativeAndCheckNoError("a/b/c", "a/b"));
-  EXPECT_EQ("a",
-            NormalizeAndCheckNoError(IncludesNormalize::AbsPath("a", &err)));
-  EXPECT_EQ("", err);
-  EXPECT_EQ(string("../") + currentdir + string("/a"),
-            NormalizeRelativeAndCheckNoError("a", "../b"));
-  EXPECT_EQ(string("../") + currentdir + string("/a/b"),
-            NormalizeRelativeAndCheckNoError("a/b", "../c"));
-  EXPECT_EQ("../../a", NormalizeRelativeAndCheckNoError("a", "b/c"));
-  EXPECT_EQ(".", NormalizeRelativeAndCheckNoError("a", "a"));
-}
-
-TEST(IncludesNormalize, Case) {
-  EXPECT_EQ("b", NormalizeAndCheckNoError("Abc\\..\\b"));
-  EXPECT_EQ("BdEf", NormalizeAndCheckNoError("Abc\\..\\BdEf"));
-  EXPECT_EQ("A/b", NormalizeAndCheckNoError("A\\.\\b"));
-  EXPECT_EQ("a/b", NormalizeAndCheckNoError("a\\./b"));
-  EXPECT_EQ("A/B", NormalizeAndCheckNoError("A\\.\\B"));
-  EXPECT_EQ("A/B", NormalizeAndCheckNoError("A\\./B"));
-}
-
-TEST(IncludesNormalize, DifferentDrive) {
-  EXPECT_EQ("stuff.h",
-            NormalizeRelativeAndCheckNoError("p:\\vs08\\stuff.h", "p:\\vs08"));
-  EXPECT_EQ("stuff.h",
-            NormalizeRelativeAndCheckNoError("P:\\Vs08\\stuff.h", "p:\\vs08"));
-  EXPECT_EQ("p:/vs08/stuff.h",
-            NormalizeRelativeAndCheckNoError("p:\\vs08\\stuff.h", "c:\\vs08"));
-  EXPECT_EQ("P:/vs08/stufF.h", NormalizeRelativeAndCheckNoError(
-                                   "P:\\vs08\\stufF.h", "D:\\stuff/things"));
-  EXPECT_EQ("P:/vs08/stuff.h", NormalizeRelativeAndCheckNoError(
-                                   "P:/vs08\\stuff.h", "D:\\stuff/things"));
-  EXPECT_EQ("P:/wee/stuff.h",
-            NormalizeRelativeAndCheckNoError("P:/vs08\\../wee\\stuff.h",
-                                             "D:\\stuff/things"));
-}
-
-TEST(IncludesNormalize, LongInvalidPath) {
-  const char kLongInputString[] =
-      "C:\\Program Files (x86)\\Microsoft Visual Studio "
-      "12.0\\VC\\INCLUDEwarning #31001: The dll for reading and writing the "
-      "pdb (for example, mspdb110.dll) could not be found on your path. This "
-      "is usually a configuration error. Compilation will continue using /Z7 "
-      "instead of /Zi, but expect a similar error when you link your program.";
-  // Too long, won't be canonicalized. Ensure doesn't crash.
-  string result, err;
-  IncludesNormalize normalizer(".");
-  EXPECT_FALSE(
-      normalizer.Normalize(kLongInputString, &result, &err));
-  EXPECT_EQ("path too long", err);
-
-
-  // Construct max size path having cwd prefix.
-  // kExactlyMaxPath = "$cwd\\a\\aaaa...aaaa\0";
-  char kExactlyMaxPath[_MAX_PATH + 1];
-  ASSERT_NOT_NULL(_getcwd(kExactlyMaxPath, sizeof kExactlyMaxPath));
-
-  int cwd_len = strlen(kExactlyMaxPath);
-  ASSERT_LE(cwd_len + 3 + 1, _MAX_PATH)
-  kExactlyMaxPath[cwd_len] = '\\';
-  kExactlyMaxPath[cwd_len + 1] = 'a';
-  kExactlyMaxPath[cwd_len + 2] = '\\';
-
-  kExactlyMaxPath[cwd_len + 3] = 'a';
-
-  for (int i = cwd_len + 4; i < _MAX_PATH; ++i) {
-    if (i > cwd_len + 4 && i < _MAX_PATH - 1 && i % 10 == 0)
-      kExactlyMaxPath[i] = '\\';
-    else
-      kExactlyMaxPath[i] = 'a';
-  }
-
-  kExactlyMaxPath[_MAX_PATH] = '\0';
-  EXPECT_EQ(strlen(kExactlyMaxPath), _MAX_PATH);
-
-  string forward_slashes(kExactlyMaxPath);
-  replace(forward_slashes.begin(), forward_slashes.end(), '\\', '/');
-  // Make sure a path that's exactly _MAX_PATH long is canonicalized.
-  EXPECT_EQ(forward_slashes.substr(cwd_len + 1),
-            NormalizeAndCheckNoError(kExactlyMaxPath));
-}
-
-TEST(IncludesNormalize, ShortRelativeButTooLongAbsolutePath) {
-  string result, err;
-  IncludesNormalize normalizer(".");
-  // A short path should work
-  EXPECT_TRUE(normalizer.Normalize("a", &result, &err));
-  EXPECT_EQ("", err);
-
-  // Construct max size path having cwd prefix.
-  // kExactlyMaxPath = "aaaa\\aaaa...aaaa\0";
-  char kExactlyMaxPath[_MAX_PATH + 1];
-  for (int i = 0; i < _MAX_PATH; ++i) {
-    if (i < _MAX_PATH - 1 && i % 10 == 4)
-      kExactlyMaxPath[i] = '\\';
-    else
-      kExactlyMaxPath[i] = 'a';
-  }
-  kExactlyMaxPath[_MAX_PATH] = '\0';
-  EXPECT_EQ(strlen(kExactlyMaxPath), _MAX_PATH);
-
-  // Make sure a path that's exactly _MAX_PATH long fails with a proper error.
-  EXPECT_FALSE(normalizer.Normalize(kExactlyMaxPath, &result, &err));
-  EXPECT_TRUE(err.find("GetFullPathName") != string::npos);
-}
diff --git a/src/inline.sh b/src/inline.sh
deleted file mode 100755
index 5092fa2..0000000
--- a/src/inline.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-#
-# Copyright 2001 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.
-
-# This quick script converts a text file into an #include-able header.
-# It expects the name of the variable as its first argument, and reads
-# stdin and writes stdout.
-
-varname="$1"
-
-# '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/interrupt_handling-posix.cc b/src/interrupt_handling-posix.cc
deleted file mode 100644
index fa47131..0000000
--- a/src/interrupt_handling-posix.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2023 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 <stdio.h>
-#include <unistd.h>
-
-#include "interrupt_handling.h"
-#include "util.h"
-
-// Set to 1 to print debug messages to stderr during development
-#define DEBUG 0
-
-namespace {
-
-// Retrieve a signal mask for SIGINT/SIGHUP/SIGTERM
-sigset_t GetInterruptSignalMask() {
-  sigset_t mask;
-  sigemptyset(&mask);
-  sigaddset(&mask, SIGINT);
-  sigaddset(&mask, SIGHUP);
-  sigaddset(&mask, SIGTERM);
-  return mask;
-}
-
-// Set the signal action for a given |signum|, returning the previous one
-// in |*old_action| is |old_action != nullptr|.
-void SetSignalAction(int signum, const struct sigaction* action,
-                     struct sigaction* old_action) {
-  if (sigaction(signum, action, old_action) < 0)
-    ErrnoFatal("sigaction");
-}
-
-}  // namespace
-
-//////////////////////////////////////////////////////////////////////////
-///
-///  InterruptBlocker
-///
-
-InterruptBlocker::InterruptBlocker() {
-  sigset_t block_interrupts = GetInterruptSignalMask();
-  if (sigprocmask(SIG_BLOCK, &block_interrupts, &prev_signal_mask_) < 0)
-    ErrnoFatal("sigprocmask");
-}
-
-InterruptBlocker::~InterruptBlocker() {
-  if (sigprocmask(SIG_SETMASK, &prev_signal_mask_, nullptr) < 0)
-    ErrnoFatal("sigprocmask");
-}
-
-//////////////////////////////////////////////////////////////////////////
-///
-///  InterruptHandlerBase
-///
-
-InterruptHandlerBase::InterruptHandlerBase(const struct sigaction& action) {
-  // Block the signals before changing the handlers.
-  sigset_t mask = GetInterruptSignalMask();
-  sigprocmask(SIG_BLOCK, &mask, &old_mask_);
-
-  SetSignalAction(SIGINT, &action, &old_int_action_);
-  SetSignalAction(SIGHUP, &action, &old_hup_action_);
-  SetSignalAction(SIGTERM, &action, &old_term_action_);
-
-  // Unblock the signals now.
-  sigprocmask(SIG_UNBLOCK, &mask, nullptr);
-}
-
-InterruptHandlerBase::~InterruptHandlerBase() {
-  // Block the signal before changing the action handlers.
-  sigset_t mask = GetInterruptSignalMask();
-  sigprocmask(SIG_BLOCK, &mask, nullptr);
-
-  SetSignalAction(SIGINT, &old_int_action_, nullptr);
-  SetSignalAction(SIGHUP, &old_hup_action_, nullptr);
-  SetSignalAction(SIGTERM, &old_term_action_, nullptr);
-
-  // Restore the original signal mask.
-  sigprocmask(SIG_SETMASK, &old_mask_, nullptr);
-}
-
-//////////////////////////////////////////////////////////////////////////
-///
-///  InterruptCatcher
-///
-
-InterruptCatcher::InterruptCatcher() : InterruptHandlerBase(MakeAction()) {
-  s_interrupted_ = 0;
-  HandlePendingInterrupt();
-}
-
-InterruptCatcher::~InterruptCatcher() = default;
-
-#if DEBUG
-#define WRITE(msg) ::write(2, msg, sizeof(msg) - 1)
-#else
-#define WRITE(msg) (void)(msg)
-#endif
-
-// static
-struct sigaction InterruptCatcher::MakeAction() {
-  struct sigaction result = {};
-  result.sa_handler = [](int signum) {
-    s_interrupted_ = signum;
-    if (signum == SIGINT)
-      WRITE("\nSIGINT SIGNALED\n");
-    else if (signum == SIGHUP)
-      WRITE("\nSIGHUP SIGNALED\n");
-    else if (signum == SIGTERM)
-      WRITE("\nSIGTERM SIGNALED\n");
-  };
-  return result;
-}
-
-// static
-void InterruptCatcher::HandlePendingInterrupt() {
-  sigset_t pending;
-  sigemptyset(&pending);
-  if (sigpending(&pending) == -1) {
-    perror("ninja: sigpending");
-    return;
-  }
-  if (sigismember(&pending, SIGINT)) {
-    WRITE("\nSIGINT PENDING\n");
-    s_interrupted_ = SIGINT;
-  } else if (sigismember(&pending, SIGTERM)) {
-    WRITE("\nSIGTERM PENDING\n");
-    s_interrupted_ = SIGTERM;
-  } else if (sigismember(&pending, SIGHUP)) {
-    WRITE("\nSIGHUP PENDING\n");
-    s_interrupted_ = SIGHUP;
-  }
-}
-
-// static
-volatile sig_atomic_t InterruptCatcher::s_interrupted_ = 0;
-
-//////////////////////////////////////////////////////////////////////////
-///
-///  InterruptForwarder
-///
-
-#include <unistd.h>
-
-InterruptForwarder::InterruptForwarder(pid_t process_group)
-    : InterruptHandlerBase(MakeAction()), old_process_group_(s_process_group_) {
-  s_process_group_ = process_group;
-}
-
-InterruptForwarder::~InterruptForwarder() {
-  s_process_group_ = old_process_group_;
-}
-
-// static
-struct sigaction InterruptForwarder::MakeAction() {
-  struct sigaction result = {};
-  result.sa_handler = [](int signum) {
-    // Send the interrupt to the server's process group
-    kill(-s_process_group_, signum);
-    WRITE("\nINTERRUPT FORWARDED\n");
-  };
-  return result;
-}
-
-// static
-pid_t InterruptForwarder::s_process_group_ = 0;
diff --git a/src/interrupt_handling-win32.cc b/src/interrupt_handling-win32.cc
deleted file mode 100644
index a0b866c..0000000
--- a/src/interrupt_handling-win32.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2023 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 "interrupt_handling.h"
-#include "util.h"
-
-//////////////////////////////////////////////////////////////////////////
-///
-///  InterruptCompletionPortHandler
-///
-
-InterruptCompletionPortHandler::InterruptCompletionPortHandler(
-    HANDLE ioport, ULONG_PTR completion_key)
-    : old_ioport_(s_ioport_), old_completion_key_(s_completion_key_) {
-  s_ioport_ = ioport;
-  s_completion_key_ = completion_key;
-
-  if (!SetConsoleCtrlHandler(HandlerRoutine, TRUE))
-    Win32Fatal("SetConsoleCtrlHandler");
-}
-
-InterruptCompletionPortHandler::~InterruptCompletionPortHandler() {
-  s_ioport_ = old_ioport_;
-  s_completion_key_ = old_completion_key_;
-
-  if (!SetConsoleCtrlHandler(HandlerRoutine, FALSE))
-    Win32Fatal("SetConsoleCtrlHandler");
-}
-
-// static
-BOOL InterruptCompletionPortHandler::HandlerRoutine(DWORD dwCtrlType) {
-  if (dwCtrlType != CTRL_C_EVENT && dwCtrlType != CTRL_BREAK_EVENT)
-    return FALSE;
-
-  if (!PostQueuedCompletionStatus(s_ioport_, 0, s_completion_key_, nullptr))
-    Win32Fatal("PostQueuedCompletionStatus");
-
-  return TRUE;
-}
-
-// static
-HANDLE InterruptCompletionPortHandler::s_ioport_ = INVALID_HANDLE_VALUE;
-
-// static
-ULONG_PTR InterruptCompletionPortHandler::s_completion_key_ = 0;
-
-//////////////////////////////////////////////////////////////////////////
-///
-///  InterruptForwarder
-///
-
-InterruptForwarder::InterruptForwarder(DWORD pgid)
-    : old_process_group_id_(s_process_group_id_) {
-  s_process_group_id_ = pgid;
-  if (!SetConsoleCtrlHandler(InterruptForwarder::HandlerRoutine, TRUE))
-    Win32Fatal("SetConsoleCtrlHandler");
-}
-
-InterruptForwarder::~InterruptForwarder() {
-  s_process_group_id_ = old_process_group_id_;
-  if (!SetConsoleCtrlHandler(InterruptForwarder::HandlerRoutine, FALSE))
-    Win32Fatal("SetConsoleCtrlHandler");
-}
-
-// static
-BOOL InterruptForwarder::HandlerRoutine(DWORD dwCtrlType) {
-  if (dwCtrlType != CTRL_C_EVENT && dwCtrlType != CTRL_BREAK_EVENT)
-    return FALSE;
-
-  if (!GenerateConsoleCtrlEvent(dwCtrlType, s_process_group_id_))
-    Win32Fatal("GenerateConsoleCtrlEvent");
-
-  return TRUE;
-}
-
-// static
-DWORD InterruptForwarder::s_process_group_id_ = 0;
diff --git a/src/interrupt_handling.h b/src/interrupt_handling.h
deleted file mode 100644
index 6dc562c..0000000
--- a/src/interrupt_handling.h
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2023 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_INTERRUPT_HANDLING_H_
-#define NINJA_INTERRUPT_HANDLING_H_
-
-/// Convenience classes used to control how user interruption
-/// is handled by Ninja at various times. This means Ctrl+C and Ctrl+Break
-/// events on Win32, and SIGINT/SIGHUP/SIGTERM ones on Posix.
-
-#ifdef _WIN32
-
-#include <windows.h>
-
-/// On Ctrl-C or Ctrl-Break, post en empty i/o completion packet
-/// to a given i/o completion queue. Useful to catch signals when
-/// waiting for overlapped i/o on Win32.
-struct InterruptCompletionPortHandler {
-  InterruptCompletionPortHandler(HANDLE ioport, ULONG_PTR completion_key = 0);
-  ~InterruptCompletionPortHandler();
-
- private:
-  static BOOL WINAPI HandlerRoutine(DWORD dwCtrlType);
-  HANDLE old_ioport_;
-  ULONG_PTR old_completion_key_;
-  static HANDLE s_ioport_;
-  static ULONG_PTR s_completion_key_;
-};
-
-/// Forward all Ctrl-C and Ctrl-Break signals to a different
-/// process group.
-struct InterruptForwarder {
-  InterruptForwarder(DWORD process_group_id);
-  ~InterruptForwarder();
-
- private:
-  static BOOL WINAPI HandlerRoutine(DWORD dwCtrlType);
-  DWORD old_process_group_id_;
-  static DWORD s_process_group_id_;
-};
-
-#else  // !_WIN32
-
-#include <signal.h>
-
-/// A class used to block all SIGINT/SIGHUP/SIGTERM signals
-/// in the current process. Restores the previous signal
-/// mask in the destructor.
-struct InterruptBlocker {
-  InterruptBlocker();
-  ~InterruptBlocker();
-
-  const sigset_t& old_mask() const { return prev_signal_mask_; }
-
- private:
-  sigset_t prev_signal_mask_;
-};
-
-/// Base class for all interrupt handlers.
-struct InterruptHandlerBase {
-  /// Constructor sets a new signal handler for SIGINT/SIGHUP/SIGTERM
-  /// and unblocks these signals!
-  InterruptHandlerBase(const struct sigaction& action);
-
-  /// Destructor restores previous interrupt handlers and signal mask.
-  ~InterruptHandlerBase();
-
-  /// Return the signal mask before construction. This will be restored
-  /// on destruction as well.
-  sigset_t old_mask() const { return old_mask_; }
-
- private:
-  struct sigaction old_int_action_;
-  struct sigaction old_hup_action_;
-  struct sigaction old_term_action_;
-  sigset_t old_mask_;
-};
-
-/// Catch all SIGINT/SIGHUP/SIGTERM signals and stores the
-/// corresponding signal number into a global interrupted()
-/// variable. This can also detect pending signals.
-struct InterruptCatcher : public InterruptHandlerBase {
-  InterruptCatcher();
-  ~InterruptCatcher();
-
-  /// Return interrupt signal number, or 0 if there were none.
-  int interrupted() const { return s_interrupted_; }
-
-  /// Clear the interrupted signal number.
-  void Clear() { s_interrupted_ = 0; }
-
-  /// Handle any pending interruption signal. This updates
-  /// the interrupted() value but does not cancel the signals.
-  static void HandlePendingInterrupt();
-
- private:
-  static struct sigaction MakeAction();
-  static volatile sig_atomic_t s_interrupted_;
-};
-
-/// Forward all SIGINT/SIGHUP/SIGTERM signal to a different
-/// process group
-struct InterruptForwarder : public InterruptHandlerBase {
-  explicit InterruptForwarder(pid_t process_group);
-  ~InterruptForwarder();
-
- private:
-  static struct sigaction MakeAction();
-  pid_t old_process_group_ = -1;
-  static pid_t s_process_group_;
-};
-
-#endif  // !_WIN32
-
-#endif  // NINJA_INTERRUPT_HANDLING_H_
diff --git a/src/interrupt_handling_test.cc b/src/interrupt_handling_test.cc
deleted file mode 100644
index 2df18db..0000000
--- a/src/interrupt_handling_test.cc
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright 2023 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 "interrupt_handling.h"
-
-#include "test.h"
-#include "util.h"
-
-#ifdef _WIN32
-
-// TODO(digit): Write real test for _WIN32
-char dummy_;
-
-#else  // !_WIN32
-
-#include <sys/signal.h>
-#include <unistd.h>
-
-namespace {
-
-// Retrieve a signal mask for SIGINT/SIGHUP/SIGTERM
-sigset_t GetInterruptSignalMask() {
-  sigset_t mask;
-  sigemptyset(&mask);
-  sigaddset(&mask, SIGINT);
-  sigaddset(&mask, SIGHUP);
-  sigaddset(&mask, SIGTERM);
-  return mask;
-}
-
-// Set the signal action for a given |signum|, returning the previous one
-// in |*old_action| is |old_action != nullptr|.
-void SetSignalAction(int signum, const struct sigaction* action,
-                     struct sigaction* old_action) {
-  if (sigaction(signum, action, old_action) < 0)
-    ErrnoFatal("sigaction");
-}
-
-// Base class for all tests, used to set the signal mask and actions for
-// interrupts to the same base state.
-class InterruptHandlingTest : public ::testing::Test {
- public:
-  InterruptHandlingTest() {
-    // Block signals before changing the action handler + save previous mask.
-    sigset_t mask = GetInterruptSignalMask();
-    sigprocmask(SIG_BLOCK, &mask, &prev_mask_);
-
-    // Change signal handlers.
-    struct sigaction sigint_action = {};
-    sigint_action.sa_handler = [](int) { s_got_sigint = 1; };
-    SetSignalAction(SIGINT, &sigint_action, &prev_sigint_action_);
-
-    struct sigaction sighup_action = {};
-    sighup_action.sa_handler = [](int) { s_got_sighup = 1; };
-    SetSignalAction(SIGHUP, &sighup_action, &prev_sighup_action_);
-
-    struct sigaction sigterm_action = {};
-    sigterm_action.sa_handler = [](int) { s_got_sigterm = 1; };
-    SetSignalAction(SIGTERM, &sigterm_action, &prev_sigterm_action_);
-
-    // Unblock signals.
-    sigprocmask(SIG_UNBLOCK, &mask, nullptr);
-  }
-
-  ~InterruptHandlingTest() {
-    // Block signals before changing handlers.
-    sigset_t mask = GetInterruptSignalMask();
-    sigprocmask(SIG_BLOCK, &mask, nullptr);
-
-    // Restore previous handlers.
-    SetSignalAction(SIGINT, &prev_sigint_action_, nullptr);
-    SetSignalAction(SIGHUP, &prev_sighup_action_, nullptr);
-    SetSignalAction(SIGTERM, &prev_sigterm_action_, nullptr);
-
-    // Clear flags for next test.
-    Clear();
-
-    // Restore previous signal mask.
-    sigprocmask(SIG_SETMASK, &prev_mask_, nullptr);
-  }
-
-  void Clear() {
-    s_got_sigint = 0;
-    s_got_sighup = 0;
-    s_got_sigterm = 0;
-  }
-
-  void SendSelfSignal(int signum) { ::kill(getpid(), signum); }
-
-  sigset_t prev_mask_;
-  struct sigaction prev_sigint_action_;
-  struct sigaction prev_sighup_action_;
-  struct sigaction prev_sigterm_action_;
-
-  static volatile sig_atomic_t s_got_sigint;
-  static volatile sig_atomic_t s_got_sighup;
-  static volatile sig_atomic_t s_got_sigterm;
-};
-
-volatile sig_atomic_t InterruptHandlingTest::s_got_sigint = 0;
-volatile sig_atomic_t InterruptHandlingTest::s_got_sighup = 0;
-volatile sig_atomic_t InterruptHandlingTest::s_got_sigterm = 0;
-
-}  // namespace
-
-TEST_F(InterruptHandlingTest, SendSelfSignals) {
-  // Verify that the interrupt signals are not blocked
-  sigset_t empty_mask;
-  sigemptyset(&empty_mask);
-  sigset_t cur_mask;
-  sigprocmask(SIG_BLOCK, &empty_mask, &cur_mask);
-  ASSERT_FALSE(sigismember(&cur_mask, SIGINT));
-  ASSERT_FALSE(sigismember(&cur_mask, SIGHUP));
-  ASSERT_FALSE(sigismember(&cur_mask, SIGTERM));
-
-  SendSelfSignal(SIGINT);
-  ASSERT_TRUE(s_got_sigint);
-
-  SendSelfSignal(SIGHUP);
-  ASSERT_TRUE(s_got_sighup);
-
-  SendSelfSignal(SIGTERM);
-  ASSERT_TRUE(s_got_sigterm);
-
-  Clear();
-  ASSERT_FALSE(s_got_sigint);
-  ASSERT_FALSE(s_got_sighup);
-  ASSERT_FALSE(s_got_sigterm);
-}
-
-TEST_F(InterruptHandlingTest, InterruptBlocker) {
-  {
-    InterruptBlocker blocker;
-
-    SendSelfSignal(SIGINT);
-    ASSERT_FALSE(s_got_sigint);
-
-    SendSelfSignal(SIGHUP);
-    ASSERT_FALSE(s_got_sighup);
-
-    SendSelfSignal(SIGTERM);
-    ASSERT_FALSE(s_got_sigterm);
-  }
-  ASSERT_TRUE(s_got_sigint);
-  ASSERT_TRUE(s_got_sighup);
-  ASSERT_TRUE(s_got_sigterm);
-}
-
-TEST_F(InterruptHandlingTest, InterruptCatcher) {
-  {
-    InterruptCatcher catcher;
-
-    SendSelfSignal(SIGINT);
-    ASSERT_FALSE(s_got_sigint);
-    ASSERT_EQ(SIGINT, catcher.interrupted());
-
-    SendSelfSignal(SIGHUP);
-    ASSERT_FALSE(s_got_sighup);
-    ASSERT_EQ(SIGHUP, catcher.interrupted());
-
-    SendSelfSignal(SIGTERM);
-    ASSERT_FALSE(s_got_sigterm);
-    ASSERT_EQ(SIGTERM, catcher.interrupted());
-  }
-
-  // Verify that a second instance does not keep the old interrupted()
-  // value from a stale global variable.
-  {
-    InterruptCatcher catcher;
-    ASSERT_EQ(0, catcher.interrupted());
-  }
-}
-
-TEST_F(InterruptHandlingTest, InterruptForwarder) {
-  ASSERT_FALSE(s_got_sigint);
-
-  // Create child process with fork.
-  pid_t child_pid = fork();
-  ASSERT_GE(child_pid, 0);
-
-  if (child_pid == 0) {
-    // In the child process, do nothing, just wait for an interrupt.
-    sleep(10);
-    exit(0);
-  }
-
-  InterruptForwarder forwarder(child_pid);
-
-  SendSelfSignal(SIGINT);
-  ASSERT_FALSE(s_got_sigint);
-}
-
-#endif  // !_WIN32
diff --git a/src/ipc_handle-posix.cc b/src/ipc_handle-posix.cc
deleted file mode 100644
index 09d3c78..0000000
--- a/src/ipc_handle-posix.cc
+++ /dev/null
@@ -1,757 +0,0 @@
-// Copyright 2023 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 <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include "ipc_handle.h"
-#include "util.h"  // For StringFormat() and GetLastErrorString()
-
-namespace {
-
-// helper macro to loop on EINTR during syscalls.
-// Important: Do not use it for close(), use CloseFd() instead.
-#define HANDLE_EINTR(x)                                     \
-  ({                                                        \
-    decltype(x) eintr_wrapper_result;                       \
-    do {                                                    \
-      eintr_wrapper_result = (x);                           \
-    } while (eintr_wrapper_result == -1 && errno == EINTR); \
-    eintr_wrapper_result;                                   \
-  })
-
-// Close file descriptor if needed, preserving errno
-// since EINTR can happen during a close(), but there
-// is nothing that can be done when it does (since
-// it is impossible to tell whether the descriptor
-// was already closed or not, the result being kernel
-// and system specific).
-void CloseFd(int& fd) {
-  if (fd >= 0) {
-    int save_errno = errno;
-    ::close(fd);
-    fd = -1;
-    errno = save_errno;
-  }
-}
-
-// Convenience function to write the errno message to a string
-// and return false.
-bool SetErrnoMessage(std::string* error_message) {
-  *error_message = strerror(errno);
-  return false;
-}
-
-// Return true if |fd| is in non-blocking mode.
-bool IsNonBlockingFd(int fd) {
-  int flags = fcntl(fd, F_GETFL);
-  return (flags >= 0) && (flags & O_NONBLOCK) != 0;
-}
-
-// Set the non-blocking flags of |fd| to |enabled|
-void SetNonBlockingFd(int fd, bool enabled) {
-  int flags = fcntl(fd, F_GETFL);
-  if (flags < 0)
-    return;
-
-  int new_flags = enabled ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK);
-  if (new_flags != flags)
-    fcntl(fd, F_SETFL, new_flags);
-}
-
-bool IsClosedOnExec(int fd) {
-  int flags = fcntl(fd, F_GETFD);
-  return (flags >= 0) && (flags & FD_CLOEXEC) != 0;
-}
-
-void SetClosedOnExecFlag(int fd, bool enabled) {
-  if (fd >= 0) {
-    int flags = fcntl(fd, F_GETFD);
-    int new_flags = enabled ? (flags | FD_CLOEXEC) : (flags & ~FD_CLOEXEC);
-    if (flags != new_flags)
-      fcntl(fd, F_SETFD, new_flags);
-  }
-}
-
-// Create a new unix-domain socket, potentially in non-blocking mode,
-// always with CLOEXEC.
-int CreateUnixSocket(bool non_blocking) {
-#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
-  int flags = SOCK_STREAM | SOCK_CLOEXEC | (non_blocking ? SOCK_NONBLOCK : 0);
-  return socket(AF_UNIX, flags, 0);
-#else   // !SOCK_NONBLOCK || !SOCK_CLOEXEC
-  int sock = socket(AF_UNIX, SOCK_STREAM, 0);
-  if (sock < 0)
-    return -1;
-
-  int flags = fcntl(sock, F_GETFD);
-  fcntl(sock, F_SETFD, flags | FD_CLOEXEC);
-
-  if (non_blocking)
-    SetNonBlockingFd(sock, true);
-
-  return sock;
-#endif  // !SOCK_NONBLOCK || !SOCK_CLOEXEC
-}
-
-// Convenience class to wait for a single file descriptor to become
-// either readable or writable. Usage is:
-//
-//  - Create instance.
-//  - Call Wait() passing a timeout.
-//
-struct PosixIoConditionWaiter {
-  // Constructor. Set |writable| to true to wait for write events,
-  // otherwise for |read| events.
-  PosixIoConditionWaiter(int fd, bool writable) : fd_(fd), writable_(writable) {
-    FD_ZERO(&fds_);
-  }
-
-  // Wait for the specific condition. On success return true.
-  // On failure, set |*error| then return false. In all cases
-  // |*did_timeout| will be set to true only in case of timeout.
-  bool Wait(int64_t timeout_ms, bool* did_timeout, std::string* error) {
-    // Reset fds_ in case Wait() is called multiple times.
-    FD_SET(fd_, &fds_);
-
-    struct timespec* ts = nullptr;
-    struct timespec timeout_ts;
-    if (timeout_ms >= 0) {
-      timeout_ts.tv_sec = static_cast<time_t>(timeout_ms / 1000);
-      timeout_ts.tv_nsec =
-          static_cast<int32_t>((timeout_ms % 1000) * 1000000LL);
-      ts = &timeout_ts;
-    }
-
-    *did_timeout = false;
-
-    fd_set* readable = writable_ ? nullptr : &fds_;
-    fd_set* writable = writable_ ? &fds_ : nullptr;
-    int ret = pselect(fd_ + 1, readable, writable, nullptr, ts, nullptr);
-    if (ret < 0)
-      return SetErrnoMessage(error);
-
-    if (!FD_ISSET(fd_, &fds_)) {
-      *did_timeout = true;
-      *error = "timed out";
-      return false;
-    }
-    return true;
-  }
-
-  const int fd_;
-  const bool writable_;
-  fd_set fds_;
-};
-
-// Retrieve non-blocking socket connection status.
-int GetSocketConnectStatus(int fd) {
-  int so_error = 0;
-  socklen_t so_error_len = sizeof(so_error);
-  int ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
-  if (ret < 0)
-    return ret;
-
-  return so_error;
-}
-
-// Set USE_LINUX_NAMESPACE to 1 to use Linux abstract
-// unix namespace, which do not require a filesystem
-// entry point.
-#ifdef __linux__
-#define USE_LINUX_NAMESPACE 1
-#endif
-
-#if !USE_LINUX_NAMESPACE
-// Return runtime directory where to create a Unix socket.
-// Only used for non-Linux systems. Callers can assume
-// that the directory already exists (otherwise, the system
-// is not configured properly, and an error on bind or
-// connect operation is expected).
-std::string GetRuntimeDirectory() {
-  std::string result;
-  // XDG_RUNTIME_DIR might be defined on BSDs and other operating
-  // systems.
-  const char* xdg_runtime_dir = getenv("XDG_RUNTIME_DIR");
-  if (xdg_runtime_dir) {
-    result = xdg_runtime_dir;
-  }
-  if (result.empty()) {
-    const char* tmp = getenv("TMPDIR");
-    if (!tmp || !tmp[0])
-      tmp = "/tmp";
-    result = tmp;
-  }
-  return result;
-}
-#endif  // !USE_LINUX_NAMESPACE
-
-// Return the Unix socket path to be used for |service_name|.
-std::string CreateUnixSocketPath(StringPiece service_name) {
-  // On Linux, use the abstract namespace by creating a string with
-  // a NUL byte at the front. On other platform, use the runtime
-  // directory instead.
-#if USE_LINUX_NAMESPACE
-  std::string result(1, '\0');
-#else
-  std::string result = GetRuntimeDirectory() + "/";
-#endif
-  result += "basic_ipc-";
-  const char* user = getenv("USER");
-  if (!user || !user[0])
-    user = "unknown_user";
-  result += user;
-  result += "-";
-  result += service_name.AsString();
-  return result;
-}
-
-// Convenience class to model a Unix socket address.
-// Usage is:
-//  1) Create instance, passing service name.
-//  2) Call valid() to check the instance. If false the
-//     service name was too long.
-//  3) Use address() and size() to pass to sendmsg().
-class LocalAddress {
- public:
-  LocalAddress(StringPiece service_name) {
-    local_ = {};
-    local_.sun_family = AF_UNIX;
-    std::string path = CreateUnixSocketPath(service_name);
-    if (path.size() >= sizeof(local_.sun_path))
-      return;  // Service name is too long.
-
-    memcpy(local_.sun_path, path.data(), path.size());
-    local_.sun_path[path.size()] = '\0';
-    size_ = offsetof(sockaddr_un, sun_path) + path.size() + 1;
-  }
-
-  bool valid() const { return size_ > 0; }
-  sockaddr* address() const { return const_cast<sockaddr*>(&generic_); }
-  size_t size() const { return size_; }
-  const char* path() const { return local_.sun_path; }
-  std::string pid_path() const {
-    return StringFormat("%s.pid", local_.sun_path);
-  }
-
- private:
-  size_t size_ = 0;
-  union {
-    sockaddr_un local_;
-    sockaddr generic_;
-  };
-};
-
-}  // namespace
-
-// static
-constexpr int IpcHandle::kInvalid;
-
-// static
-IpcHandle::HandleType IpcHandle::CloneNativeHandle(HandleType handle,
-                                                   bool inherited) {
-  int fd = ::dup(handle);
-  SetClosedOnExecFlag(fd, inherited);
-  return fd;
-}
-
-void IpcHandle::Close() {
-  CloseFd(handle_);
-}
-
-int IpcHandle::ReleaseNativeHandle() {
-  int result = handle_;
-  handle_ = -1;
-  return result;
-}
-
-ssize_t IpcHandle::Read(void* buff, size_t buffer_size,
-                        std::string* error_message) const {
-  auto* buffer = static_cast<char*>(buff);
-  ssize_t result = 0;
-  while (buffer_size > 0) {
-    ssize_t count = read(handle_, buffer, buffer_size);
-    if (count < 0) {
-      if (errno == EINTR)
-        continue;
-      if (result > 0) {
-        // Ignore this error to return the current read result.
-        // This assumes the error will repeat on the next call.
-        break;
-      }
-      *error_message = strerror(errno);
-      return -1;
-    } else if (count == 0) {
-      break;
-    }
-    buffer += count;
-    buffer_size -= static_cast<size_t>(count);
-    result += count;
-  }
-  return result;
-}
-
-ssize_t IpcHandle::Write(const void* buff, size_t buffer_size,
-                         std::string* error_message) const {
-  auto* buffer = static_cast<const char*>(buff);
-  ssize_t result = 0;
-  while (buffer_size > 0) {
-    ssize_t count = write(handle_, buffer, buffer_size);
-    if (count < 0) {
-      if (errno == EINTR)
-        continue;
-      if (result > 0) {
-        break;
-      }
-      *error_message = strerror(errno);
-      return -1;
-    } else if (count == 0) {
-      break;
-    }
-    buffer += count;
-    buffer_size -= static_cast<size_t>(count);
-    result += count;
-  }
-  return result;
-}
-
-bool IpcHandle::SendNativeHandle(HandleType native,
-                                 std::string* error_message) const {
-  char ch = 'x';
-  iovec iov = { &ch, 1 };
-  union {
-    char buf[CMSG_SPACE(sizeof(int))];
-    cmsghdr align;
-  } control;
-  memset(control.buf, 0, sizeof(control.buf));
-
-  msghdr header = {};
-  header.msg_iov = &iov;
-  header.msg_iovlen = 1;
-  header.msg_control = control.buf;
-  header.msg_controllen = sizeof(control.buf);
-
-  cmsghdr* control_header = CMSG_FIRSTHDR(&header);
-  control_header->cmsg_len = CMSG_LEN(sizeof(int));
-  control_header->cmsg_level = SOL_SOCKET;
-  control_header->cmsg_type = SCM_RIGHTS;
-  reinterpret_cast<int*>(CMSG_DATA(control_header))[0] = native;
-
-  ssize_t ret = HANDLE_EINTR(sendmsg(handle_, &header, 0));
-  if (ret == -1)
-    return SetErrnoMessage(error_message);
-
-  return true;
-}
-
-bool IpcHandle::ReceiveNativeHandle(IpcHandle* native,
-                                    std::string* error_message) const {
-  char ch = '\0';
-  iovec iov = { &ch, 1 };
-  union {
-    char buf[CMSG_SPACE(sizeof(int))];
-    cmsghdr align;
-  } control;
-  memset(control.buf, 0, sizeof(control.buf));
-
-  msghdr header = {};
-  header.msg_iov = &iov;
-  header.msg_iovlen = 1;
-  header.msg_control = control.buf;
-  header.msg_controllen = sizeof(control.buf);
-
-  ssize_t ret = HANDLE_EINTR(recvmsg(handle_, &header, 0));
-  if (ret == -1)
-    return SetErrnoMessage(error_message);
-
-  cmsghdr* control_header = CMSG_FIRSTHDR(&header);
-  if (!control_header || control_header->cmsg_len != CMSG_LEN(sizeof(int)) ||
-      control_header->cmsg_level != SOL_SOCKET ||
-      control_header->cmsg_type != SCM_RIGHTS) {
-    *error_message =
-        std::string("Invalid data when receiving file descriptor!");
-    return false;
-  }
-  *native = IpcHandle(reinterpret_cast<int*>(CMSG_DATA(control_header))[0]);
-  return true;
-}
-
-bool IpcHandle::IsInheritable() const {
-  return IsClosedOnExec(handle_);
-}
-
-void IpcHandle::SetInheritable(bool enabled) {
-  SetClosedOnExecFlag(handle_, enabled);
-}
-
-bool IpcHandle::IsNonBlocking() const {
-  return IsNonBlockingFd(handle_);
-}
-
-void IpcHandle::SetNonBlocking(bool enable) {
-  SetNonBlockingFd(handle_, enable);
-}
-
-// static
-IpcHandle::HandleType IpcHandle::NativeForStdio(FILE* file) {
-  return fileno(file);
-}
-
-// static
-IpcHandle IpcHandle::CloneFromStdio(FILE* file) {
-  fflush(file);
-  return { CloneNativeHandle(fileno(file)) };
-}
-
-bool IpcHandle::CloneIntoStdio(FILE* file) {
-  if (file != stdout && file != stderr && file != stdin) {
-    errno = EINVAL;
-    return false;
-  }
-  if (handle_ < 0) {
-    errno = EINVAL;
-    return false;
-  }
-
-  fflush(file);
-  int ret = ::dup2(handle_, fileno(file));
-  if (ret < 0)
-    return false;
-
-  return true;
-}
-
-void IpcServiceHandle::Close() {
-  this->IpcHandle::Close();
-  if (!socket_path_.empty() && socket_path_[0] != '\0') {
-    // Remove socket and pid file.
-    unlink(socket_path_.c_str());
-
-    std::string pid_path = socket_path_;
-    pid_path += ".pid";
-    unlink(pid_path.c_str());
-
-    socket_path_.clear();
-  }
-}
-
-IpcServiceHandle::~IpcServiceHandle() {
-  Close();
-}
-
-#if !USE_LINUX_NAMESPACE
-// Try to read the pidfile for |address| if it exists, and return the server
-// process id it contains. Return 0 if there is no pid file or if it is
-// malformed. Return -1 and set |*err| if the pid file could not be read
-// (likely a permission issue).
-int ReadPidFile(const std::string& pid_path, std::string* err) {
-  // Try to open the pid file.
-  FILE* pid_file = fopen(pid_path.c_str(), "r");
-  if (!pid_file) {
-    if (errno != ENOENT) {
-      *err = StringFormat("Cannot open pid file: %s", strerror(errno));
-      return -1;
-    }
-    // There is no pid file.
-    return 0;
-  }
-
-  int server_pid = -1;
-  int ret = fscanf(pid_file, "%d", &server_pid);
-  (void)fclose(pid_file);
-
-  if (ret != 1 || server_pid <= 0) {
-    // A malformed pid file, consider server not running and
-    // do not report error.
-    return 0;
-  }
-
-  return server_pid;
-}
-
-#endif  // !USE_LINUX_NAMESPACE
-
-// static
-IpcServiceHandle IpcServiceHandle::BindTo(StringPiece service_name,
-                                          std::string* error_message) {
-  LocalAddress address(service_name);
-  if (!address.valid()) {
-    *error_message = std::string("Service name too long");
-    return {};
-  }
-#if !USE_LINUX_NAMESPACE
-  // Try to see if another server is already running. Use a .pid file
-  // that contains the server's process PID to do that, and check whether
-  // it is still alive.
-  std::string pid_path = address.pid_path();
-  int server_pid = ReadPidFile(pid_path, error_message);
-  if (server_pid < 0)
-    return {};
-
-  if (server_pid > 0 && kill(server_pid, 0) == 0) {
-    // The server process is still running.
-    *error_message = "already in use";
-    return {};
-  }
-
-  // Create new temporary pid file before doing an atomic filesystem rename.
-  int cur_pid = getpid();
-  std::string temp_pid_path =
-      StringFormat("%s.temp.%d", pid_path.c_str(), cur_pid);
-  {
-    bool pid_file_error = false;
-    FILE* pid_file = fopen(temp_pid_path.c_str(), "w");
-    if (!pid_file) {
-      pid_file_error = true;
-    } else {
-      if (fprintf(pid_file, "%d", cur_pid) <= 0)
-        pid_file_error = true;
-      fclose(pid_file);
-    }
-    if (pid_file_error) {
-      *error_message = "Cannot create temporary pid file: ";
-      *error_message += strerror(errno);
-      return {};
-    }
-  }
-  // atomically rename the temporary file.
-  // Note that EINTR can happen in practice in rename() :-(
-  if (HANDLE_EINTR(rename(temp_pid_path.c_str(), pid_path.c_str())) < 0) {
-    *error_message = "Cannot rename pid file: ";
-    *error_message += strerror(errno);
-    return {};
-  }
-
-  // Remove stale socket if any.
-  if (server_pid > 0)
-    (void)unlink(address.path());
-
-#endif  // !USE_LINUX_NAMESPACE
-
-  int server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
-  if (server_fd == -1) {
-    SetErrnoMessage(error_message);
-    return {};
-  }
-  if (bind(server_fd, address.address(), address.size()) < 0 ||
-      listen(server_fd, 1) < 0) {
-    CloseFd(server_fd);
-    SetErrnoMessage(error_message);
-    return {};
-  }
-  IpcServiceHandle result(server_fd, address.path());
-  return result;
-}
-
-IpcHandle IpcServiceHandle::AcceptClient(std::string* error_message) const {
-  int client = HANDLE_EINTR(accept(handle_, nullptr, nullptr));
-  if (client < 0) {
-    SetErrnoMessage(error_message);
-    return {};
-  }
-  return { client };
-}
-
-IpcHandle IpcServiceHandle::AcceptClient(int64_t timeout_ms, bool* did_timeout,
-                                         std::string* error_message) const {
-  PosixIoConditionWaiter waiter(handle_, false);
-  if (!waiter.Wait(timeout_ms, did_timeout, error_message))
-    return {};
-
-  int client = HANDLE_EINTR(accept(handle_, nullptr, nullptr));
-  if (client < 0) {
-    SetErrnoMessage(error_message);
-    return {};
-  }
-  return { client };
-}
-
-// static
-bool IpcServiceHandle::IsBound(StringPiece service_name) {
-  LocalAddress address(service_name);
-#if !USE_LINUX_NAMESPACE
-  std::string pid_path = address.pid_path();
-  std::string error;
-  int server_pid = ReadPidFile(pid_path, &error);
-  if (server_pid <= 0) {
-    // No pid file means there is no server running.
-    return false;
-  } else if (kill(server_pid, 0) == 0) {
-    // Server is still running.
-    return true;
-  }
-#endif  // !USE_LINUX_NAMESPACE
-  int server_fd = CreateUnixSocket(false);
-  if (server_fd == -1)
-    return false;
-
-  bool result;
-  if (bind(server_fd, address.address(), address.size()) == 0) {
-    // fprintf(stderr, "IsBound(): bind() succeeded!\n");
-    result = false;
-  } else if (errno == EADDRINUSE) {
-    // fprintf(stderr, "IsBound(): address in use!\n");
-    result = true;
-  } else {
-    // fprintf(stderr, "IsBound(): bind() returned error: %s\n",
-    // strerror(errno));
-    result = false;
-  }
-  CloseFd(server_fd);
-  return result;
-}
-
-// static
-IpcHandle IpcServiceHandle::ConnectTo(StringPiece service_name,
-                                      std::string* error_message) {
-  LocalAddress address(service_name);
-  if (!address.valid()) {
-    *error_message = std::string("Service name too long");
-    return {};
-  }
-  int client_fd = CreateUnixSocket(false);
-  if (client_fd == -1) {
-    SetErrnoMessage(error_message);
-    return {};
-  }
-  if (HANDLE_EINTR(connect(client_fd, address.address(), address.size())) < 0) {
-    SetErrnoMessage(error_message);
-    CloseFd(client_fd);
-    return {};
-  }
-  return { client_fd };
-}
-
-// static
-IpcHandle IpcServiceHandle::ConnectTo(StringPiece service_name,
-                                      int64_t timeout_ms, bool* did_timeout,
-                                      std::string* error_message) {
-  bool did_connect = false;
-  *did_timeout = false;
-  IpcHandle client = AsyncConnectTo(service_name, &did_connect, error_message);
-  if (!client)
-    return {};
-
-  if (did_connect)
-    return client;
-
-  PosixIoConditionWaiter waiter(client.native_handle(), false);
-  if (!waiter.Wait(timeout_ms, did_timeout, error_message)) {
-    return false;
-  }
-
-  int so_error = GetSocketConnectStatus(client.native_handle());
-  if (so_error != 0) {
-    SetErrnoMessage(error_message);
-    return {};
-  }
-
-  client.SetNonBlocking(false);
-  return client;
-}
-
-// static
-IpcHandle IpcServiceHandle::AsyncConnectTo(StringPiece service_name,
-                                           bool* did_connect,
-                                           std::string* error_message) {
-  LocalAddress address(service_name);
-  if (!address.valid()) {
-    *error_message = std::string("Service name too long");
-    return {};
-  }
-  int client_fd = CreateUnixSocket(true);
-  if (client_fd == -1) {
-    SetErrnoMessage(error_message);
-    return {};
-  }
-
-  if (!HANDLE_EINTR(connect(client_fd, address.address(), address.size()))) {
-    // Connection completed immediately!
-    *did_connect = true;
-    return { client_fd };
-  }
-
-  if (errno == EINPROGRESS) {
-    // Connection could not be completed immediately.
-    *did_connect = false;
-    return { client_fd };
-  }
-
-  SetErrnoMessage(error_message);
-  CloseFd(client_fd);
-  return {};
-}
-
-// static
-int IpcHandle::GetNativeAsyncConnectStatus(int fd) {
-  return GetSocketConnectStatus(fd);
-}
-
-// static
-bool IpcHandle::CreatePipe(IpcHandle* read, IpcHandle* write,
-                           std::string* error_message) {
-  int fds[2] = { -1, -1 };
-  if (pipe(fds) != 0)
-    return SetErrnoMessage(error_message);
-
-  *read = fds[0];
-  *write = fds[1];
-  return true;
-}
-
-bool IpcHandle::CreateAsyncPipe(IpcHandle* read, IpcHandle* write,
-                                std::string* error_message) {
-  if (!CreatePipe(read, write, error_message))
-    return false;
-
-  read->SetNonBlocking(true);
-  write->SetNonBlocking(true);
-  return true;
-}
-
-bool IpcHandle::ReadFull(void* buffer, size_t buffer_size,
-                         std::string* error_message) const {
-  ssize_t count = Read(buffer, buffer_size, error_message);
-  if (count < 0)
-    return false;
-  if (count != static_cast<ssize_t>(buffer_size)) {
-    *error_message =
-        StringFormat("Received %zu bytes, expected %zu", count, buffer_size);
-    return false;
-  }
-  return true;
-}
-
-bool IpcHandle::WriteFull(const void* buffer, size_t buffer_size,
-                          std::string* error_message) const {
-  ssize_t count = Write(buffer, buffer_size, error_message);
-  if (count < 0)
-    return false;
-  if (count != static_cast<ssize_t>(buffer_size)) {
-    *error_message =
-        StringFormat("Sent %zu bytes, expected %zu", count, buffer_size);
-    return false;
-  }
-  return true;
-}
-
-std::string IpcHandle::display() const {
-  return StringFormat("fd=%d", handle_);
-}
diff --git a/src/ipc_handle-win32.cc b/src/ipc_handle-win32.cc
deleted file mode 100644
index a28f4a6..0000000
--- a/src/ipc_handle-win32.cc
+++ /dev/null
@@ -1,498 +0,0 @@
-// Copyright 2023 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.
-
-// Must appear before <stdio.h> which includes <fileapi.h> which will complain
-// of "No Target Architecture" for some unknown reason (!?)
-#include <fcntl.h>
-#include <stdio.h>
-#include <windows.h>
-
-// Must appear after <windows.h>
-#include <io.h>
-#include <lmcons.h>  // required for UNLEN
-
-#include "ipc_handle.h"
-#include "util.h"  // For StringFormat() and GetLastErrorString()
-
-namespace {
-
-std::string Win32ErrorMessage(const char* prefix, LONG error) {
-  return StringFormat("%s: %s", prefix, GetLastErrorString(error).c_str());
-}
-
-std::string Win32ErrorMessage(const char* prefix) {
-  return Win32ErrorMessage(prefix, GetLastError());
-}
-
-std::wstring CurrentUserName() {
-  wchar_t user[UNLEN + 1];
-  DWORD count = UNLEN + 1;
-  if (!GetUserNameW(user, &count) || count < 2) {
-    return std::wstring(L"unknown_user");
-  }
-  // count includes the terminating zero.
-  return std::wstring(user, count - 1);
-}
-
-std::wstring GetNamedPipePath(StringPiece service_name) {
-  std::wstring result = L"\\\\.\\pipe\\basic_ipc-";
-  result += CurrentUserName();
-  result += L'-';
-  result += ConvertToUnicodeString(service_name.str_, service_name.len_);
-  return result;
-}
-
-HANDLE CreateNamedPipeHandle(const std::wstring& pipe_path, bool async,
-                             std::string* error_message) {
-  HANDLE handle = CreateNamedPipeW(
-      pipe_path.data(),
-      PIPE_ACCESS_DUPLEX | (async ? FILE_FLAG_OVERLAPPED : 0),  // bidirectional
-      PIPE_TYPE_BYTE |                             // write bytes, not messages
-          PIPE_READMODE_BYTE |                     // read bytes, not messages
-          PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,  // local only
-      1,                                           // max. instances
-      4096,                                        // out buffer size
-      4096,                                        // in buffer size
-      0,                                           // default time out
-      nullptr);                                    // default security attribute
-  if (handle == INVALID_HANDLE_VALUE)
-    *error_message = Win32ErrorMessage("Could not create named pipe");
-
-  return handle;
-}
-
-HANDLE ConnectToNamedPipe(const std::wstring& pipe_path, bool async,
-                          std::string* error_message) {
-  HANDLE handle = CreateFileW(pipe_path.data(), GENERIC_READ | GENERIC_WRITE,
-                              0,           // no sharing
-                              nullptr,     // default security attributes
-                              CREATE_NEW,  // fail if it already exists
-                              async ? FILE_FLAG_OVERLAPPED : 0,
-                              nullptr);  // no template file
-  if (handle == INVALID_HANDLE_VALUE)
-    *error_message = Win32ErrorMessage("Coult not connect pipe");
-
-  return handle;
-}
-
-std::wstring GetUniqueNamedPipePath() {
-  // Do not use CreatePipe because these are documented as only
-  // unidirectional and synchronous only. Instead create a
-  // named pipe with a unique name. This matches the current
-  // implementation in Windows, though it may change in future
-  // releases of the platform, see:
-  // https://stackoverflow.com/questions/60645/overlapped-i-o-on-anonymous-pipe/51448441#51448441
-  static LONG serial_number = 1;
-  wchar_t pipe_path[64];
-  swprintf_s(pipe_path, 64, L"\\\\.\\pipe\\IpcHandle.%08x.%08x",
-             GetCurrentProcessId(), InterlockedIncrement(&serial_number));
-  return std::wstring(pipe_path);
-}
-
-}  // namespace
-
-// INVALID_HANDLE_VALUE expands to an expression that includes
-// a reinterpret_cast<>, which is why it cannot be used to
-// define a constexpr static member.
-
-// static
-const HANDLE IpcHandle::kInvalid = INVALID_HANDLE_VALUE;
-
-// static
-void IpcHandle::Close() {
-  if (handle_ != kInvalid) {
-    CloseHandle(handle_);
-    handle_ = kInvalid;
-  }
-}
-
-HANDLE IpcHandle::ReleaseNativeHandle() {
-  HANDLE result = handle_;
-  handle_ = INVALID_HANDLE_VALUE;
-  return result;
-}
-
-bool IpcHandle::IsInheritable() const {
-  DWORD flags;
-  if (!GetHandleInformation(handle_, &flags))
-    return false;
-  return (flags & HANDLE_FLAG_INHERIT) != 0;
-}
-
-void IpcHandle::SetInheritable(bool enabled) {
-  if (!SetHandleInformation(handle_, HANDLE_FLAG_INHERIT,
-                            enabled ? HANDLE_FLAG_INHERIT : 0)) {
-    Win32Fatal("SetHandleInformation");
-  }
-}
-
-// static
-IpcHandle::HandleType IpcHandle::CloneNativeHandle(HandleType handle,
-                                                   bool inherited) {
-  HANDLE process = GetCurrentProcess();
-  HANDLE peer = INVALID_HANDLE_VALUE;
-  if (!DuplicateHandle(process, handle, process, &peer, 0, inherited,
-                       DUPLICATE_SAME_ACCESS)) {
-    return INVALID_HANDLE_VALUE;
-  }
-  return peer;
-}
-
-// static
-IpcHandle::HandleType IpcHandle::NativeForStdio(FILE* file) {
-  int fd = _fileno(file);
-  intptr_t int_handle = _get_osfhandle(fd);
-  if (int_handle < 0)
-    return INVALID_HANDLE_VALUE;
-  return reinterpret_cast<HANDLE>(int_handle);
-}
-
-// static
-IpcHandle IpcHandle::CloneFromStdio(FILE* file) {
-  return { CloneNativeHandle(NativeForStdio(file)) };
-}
-
-bool IpcHandle::CloneIntoStdio(FILE* file) {
-  HANDLE new_handle = CloneNativeHandle(handle_);
-  // Ensure low-level Win32 operations will write to the new handle.
-  // by calling SetStdHandle.
-  DWORD std_index = 0;
-  int std_fd;
-  int open_flags;
-  if (file == stdout) {
-    std_index = STD_OUTPUT_HANDLE;
-    std_fd = 1;
-    open_flags = _O_WRONLY | _fmode;
-  } else if (file == stderr) {
-    std_index = STD_ERROR_HANDLE;
-    std_fd = 2;
-    open_flags = _O_WRONLY | _fmode;
-  } else if (file == stdin) {
-    std_index = STD_INPUT_HANDLE;
-    std_fd = 0;
-    open_flags = _O_RDONLY | _fmode;
-  } else {
-    errno = EINVAL;
-    return false;
-  }
-  SetStdHandle(std_index, new_handle);
-  int new_fd =
-      ::_open_osfhandle(reinterpret_cast<intptr_t>(new_handle), open_flags);
-  ::_dup2(new_fd, std_fd);
-  ::close(new_fd);
-  return true;
-}
-
-ssize_t IpcHandle::Read(void* buff, size_t buffer_size,
-                        std::string* error_message) const {
-  auto* buffer = static_cast<char*>(buff);
-  DWORD count = 0;
-  if (!ReadFile(handle_, buffer, buffer_size, &count, nullptr)) {
-    DWORD error = GetLastError();
-    if (error == ERROR_BROKEN_PIPE)  // Pipe was closed.
-      return 0;
-    *error_message = Win32ErrorMessage("Could not read from pipe");
-    return -1;
-  }
-  return static_cast<ssize_t>(count);
-}
-
-ssize_t IpcHandle::Write(const void* buff, size_t buffer_size,
-                         std::string* error_message) const {
-  const auto* buffer = static_cast<const char*>(buff);
-  DWORD count = 0;
-  if (!WriteFile(handle_, buffer, buffer_size, &count, nullptr)) {
-    LONG error = GetLastError();
-    if (error == ERROR_BROKEN_PIPE)  // Pipe was closed.
-      return 0;
-    *error_message = Win32ErrorMessage("Could not write to pipe", error);
-    return -1;
-  }
-  return static_cast<ssize_t>(count);
-}
-
-struct HandleMessage {
-  HANDLE process_id;
-  HANDLE handle;
-};
-
-bool IpcHandle::SendNativeHandle(HandleType native,
-                                 std::string* error_message) const {
-  // Send a message that contains the current process ID, and the handle
-  // through the named pipe. The ReceiveNativeHandle() method will use them
-  // to call DuplicateHandle(). Note that this does not work for console
-  // input/output handles (the handles can be duplicated, but trying to use them
-  // from a different process returns an error), so in addition to using this
-  // method, the sender should use a specialized class to redirect stdout/stderr
-  // using new named pipe handles. See the Win32StdOutputBridge class.
-  HandleMessage msg;
-  msg.process_id =
-      OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
-  msg.handle = native;
-
-  ssize_t count = Write(&msg, sizeof(msg), error_message);
-  if (count < 0)
-    return false;
-  if (count != static_cast<ssize_t>(sizeof(msg))) {
-    *error_message = "Error when sending handle";
-    return false;
-  }
-  return true;
-}
-
-bool IpcHandle::ReceiveNativeHandle(IpcHandle* handle,
-                                    std::string* error_message) const {
-  HandleMessage msg;
-  ssize_t count = Read(&msg, sizeof(msg), error_message);
-  if (count < 0)
-    return false;
-  if (count != static_cast<ssize_t>(sizeof(msg))) {
-    *error_message = "Error when receiving handle";
-    return false;
-  }
-
-  // Create a duplicate of the source handle in the current process.
-  HANDLE native = INVALID_HANDLE_VALUE;
-  if (!DuplicateHandle(msg.process_id,       // source process
-                       msg.handle,           // source handle
-                       GetCurrentProcess(),  // target process
-                       &native,              // target handle pointer
-                       0,      // ignored with DUPLICATE_SAME_ACCESS
-                       FALSE,  // not inheritable
-                       DUPLICATE_SAME_ACCESS)) {
-    *error_message = Win32ErrorMessage("Could not duplicate handle");
-    return false;
-  }
-  *handle = IpcHandle(native);
-  return true;
-}
-
-IpcServiceHandle::~IpcServiceHandle() {
-  Close();
-}
-
-void IpcServiceHandle::Close() {
-  this->IpcHandle::Close();
-}
-
-// static
-IpcServiceHandle IpcServiceHandle::BindTo(StringPiece service_name,
-                                          std::string* error_message) {
-  return IpcServiceHandle(CreateNamedPipeHandle(GetNamedPipePath(service_name),
-                                                true, error_message));
-}
-
-IpcHandle IpcServiceHandle::AcceptClient(std::string* error_message) const {
-  // Duplicate the handle to return it into a new IpcHandle. This
-  // will allow the caller to communicate with the client, and the next
-  // ConnectNamedPipe() call will wait for another client instead.
-  HANDLE peer = IpcHandle::CloneNativeHandle(handle_);
-  if (peer == INVALID_HANDLE_VALUE) {
-    DWORD error = GetLastError();
-    *error_message =
-        Win32ErrorMessage("Could not duplicate client pipe handle", error);
-    return {};
-  }
-  if (!ConnectNamedPipe(peer, NULL)) {
-    DWORD error = GetLastError();
-    // ERROR_PIPE_CONNECTED is not an actual error and means that
-    // a client is already connected, which happens during unit-testing.
-    if (error != ERROR_PIPE_CONNECTED) {
-      ::CloseHandle(peer);
-      *error_message =
-          Win32ErrorMessage("Could not accept named pipe client", error);
-      return {};
-    }
-  }
-  return IpcHandle(peer);
-}
-
-IpcHandle IpcServiceHandle::AcceptClient(int64_t timeout_ms, bool* did_timeout,
-                                         std::string* error_message) const {
-  *did_timeout = false;
-  // Duplicate the handle to return it into a new IpcHandle. This
-  // will allow the caller to communicate with the client, and the next
-  // ConnectNamedPipe() call will wait for another client instead.
-  HANDLE peer = IpcHandle::CloneNativeHandle(handle_);
-  if (peer == INVALID_HANDLE_VALUE) {
-    DWORD error = GetLastError();
-    *error_message =
-        Win32ErrorMessage("Could not duplicate client pipe handle", error);
-    return {};
-  }
-
-  HANDLE result = INVALID_HANDLE_VALUE;
-  OVERLAPPED overlapped = {};
-  overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
-
-  do {
-    if (ConnectNamedPipe(peer, &overlapped)) {
-      // Should not happen with overlapped i/o, but just in case.
-      result = peer;
-      peer = INVALID_HANDLE_VALUE;
-      break;
-    }
-
-    DWORD error = GetLastError();
-    if (error == ERROR_PIPE_CONNECTED) {
-      // Immediate connection, success!
-      result = peer;
-      peer = INVALID_HANDLE_VALUE;
-      break;
-    }
-
-    if (error != ERROR_IO_PENDING) {
-      // Something unexpected happened here!
-      *error_message =
-          Win32ErrorMessage("Could not accept named pipe client", error);
-      break;
-    }
-
-    // Wait for connection.
-    DWORD timeout =
-        (timeout_ms < 0) ? INFINITE : static_cast<DWORD>(timeout_ms);
-    DWORD ret = WaitForSingleObject(overlapped.hEvent, timeout);
-
-    if (ret == WAIT_TIMEOUT) {
-      *did_timeout = true;
-      *error_message = "timed out";
-      break;
-    }
-
-    if (ret != WAIT_OBJECT_0) {
-      Win32Fatal("WaitForSingleObject");
-    }
-
-    // Success!
-    result = peer;
-    peer = INVALID_HANDLE_VALUE;
-
-  } while (0);
-
-  ::CloseHandle(overlapped.hEvent);
-  if (peer != INVALID_HANDLE_VALUE)
-    ::CloseHandle(peer);
-
-  return { result };
-}
-
-// static
-bool IpcServiceHandle::IsBound(StringPiece service_name) {
-  std::wstring pipe_path = GetNamedPipePath(service_name);
-  if (WaitNamedPipeW(pipe_path.data(), 1))
-    return true;
-
-  DWORD error = GetLastError();
-  if (error == ERROR_SEM_TIMEOUT)
-    return true;
-
-  return false;
-}
-
-// static
-IpcHandle IpcServiceHandle::ConnectTo(StringPiece service_name,
-                                      std::string* error_message) {
-#if 0
-  // For some reason, the line below generates code that crashes
-  // at runtime when compiled with the Mingw64 toolchain, so use
-  // the equivalent below.
-  return { ConnectToNamedPipe(GetNamedPipePath(service_name), true, error_message) };
-#else
-  std::wstring pipe_path = GetNamedPipePath(service_name);
-  HANDLE handle = ConnectToNamedPipe(pipe_path, true, error_message);
-  return { handle };
-#endif
-}
-
-// static
-IpcHandle IpcServiceHandle::ConnectTo(StringPiece service_name,
-                                      int64_t timeout_ms, bool* did_timeout,
-                                      std::string* error_message) {
-  // On Windows, connecting to a named pipe either succeeds or fails immediately
-  *did_timeout = (timeout_ms > 0);
-  return ConnectTo(service_name, error_message);
-}
-
-// static
-IpcHandle IpcServiceHandle::AsyncConnectTo(StringPiece service_name,
-                                           bool* did_connect,
-                                           std::string* error_message) {
-  IpcHandle result =
-      ConnectToNamedPipe(GetNamedPipePath(service_name), true, error_message);
-  if (result) {
-    // On Win32, connecting to a named pipe always fails or succeeds
-    // immediately.
-    *did_connect = true;
-  }
-  return result;
-}
-
-static bool CreatePipeInternal(IpcHandle* read, IpcHandle* write, bool async,
-                               std::string* error_message) {
-  std::wstring pipe_path = GetUniqueNamedPipePath();
-  *read = IpcHandle(
-      CreateNamedPipeHandle(std::wstring(pipe_path), async, error_message));
-  if (!*read)
-    return false;
-
-  *write = IpcHandle(ConnectToNamedPipe(pipe_path, async, error_message));
-  if (!*write) {
-    read->Close();
-    return false;
-  }
-  return true;
-}
-
-// static
-bool IpcHandle::CreatePipe(IpcHandle* read, IpcHandle* write,
-                           std::string* error_message) {
-  return CreatePipeInternal(read, write, false, error_message);
-}
-
-// static
-bool IpcHandle::CreateAsyncPipe(IpcHandle* read, IpcHandle* write,
-                                std::string* error_message) {
-  return CreatePipeInternal(read, write, true, error_message);
-}
-
-bool IpcHandle::ReadFull(void* buffer, size_t buffer_size,
-                         std::string* error_message) const {
-  ssize_t count = Read(buffer, buffer_size, error_message);
-  if (count < 0)
-    return false;
-  if (count != static_cast<ssize_t>(buffer_size)) {
-    *error_message = StringFormat("Received %u bytes, expected %u",
-                                  static_cast<unsigned>(count),
-                                  static_cast<unsigned>(buffer_size));
-    return false;
-  }
-  return true;
-}
-
-bool IpcHandle::WriteFull(const void* buffer, size_t buffer_size,
-                          std::string* error_message) const {
-  ssize_t count = Write(buffer, buffer_size, error_message);
-  if (count < 0)
-    return false;
-  if (count != static_cast<ssize_t>(buffer_size)) {
-    *error_message =
-        StringFormat("Sent %u bytes, expected %u", static_cast<unsigned>(count),
-                     static_cast<unsigned>(buffer_size));
-  }
-  return true;
-}
-
-std::string IpcHandle::display() const {
-  return StringFormat("handle=%p", handle_);
-}
diff --git a/src/ipc_handle.h b/src/ipc_handle.h
deleted file mode 100644
index f58f7cd..0000000
--- a/src/ipc_handle.h
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright 2023 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_IPC_HANDLE_H_
-#define NINJA_IPC_HANDLE_H_
-
-#include <stddef.h>
-
-#include <string>
-#include <string_view>
-
-#include "string_piece.h"
-
-#ifdef _WIN32
-#include <basetsd.h>
-#include <windows.h>
-using ssize_t = SSIZE_T;
-#else
-#include <signal.h>
-#endif
-
-/// Support for basic inter-process communication.
-///
-/// The IpcHandle models a scoped pipe handle (Win32) or unix socket file
-/// descriptor (Unix) and provides method to read/write data through
-/// them, as well as passing other handles/file descriptors.
-///
-/// For Win32, all handles are created with FILE_FLAG_OVERLAPPED and
-/// support overlapped operations. For Posix, the non-blocking flag of
-/// a descriptor can be checked and changed with IsNonBlocking() and
-/// SetNonBlocking() methods.
-///
-
-/// Wrapper for a local Unix socket or Win32 named pipe handle
-/// used for inter-process communication.
-class IpcHandle {
- public:
-#ifdef _WIN32
-  using HandleType = HANDLE;
-  static const HandleType kInvalid;
-#else
-  using HandleType = int;
-  static constexpr int kInvalid = -1;
-#endif
-
-  IpcHandle() = default;
-  IpcHandle(HandleType handle) : handle_(handle) {}
-
-  /// Disallow copy operations.
-  IpcHandle(const IpcHandle&) = delete;
-  IpcHandle& operator=(const IpcHandle&) = delete;
-
-  /// Allow move operations.
-  IpcHandle(IpcHandle&& other) noexcept : handle_(other.handle_) {
-    other.handle_ = kInvalid;
-  }
-  IpcHandle& operator=(IpcHandle&& other) noexcept {
-    if (this != &other) {
-      this->~IpcHandle();
-      new (this) IpcHandle(std::move(other));
-    }
-    return *this;
-  }
-
-  ~IpcHandle() { Close(); }
-
-  /// bool conversion allows easy checks for valid handles with:
-  ///  if (!handle) {  ... handle is invalid };
-  explicit operator bool() const noexcept { return handle_ != kInvalid; }
-
-  /// Try to read |buffer_size| bytes into |buffer|. On success
-  /// return the number of bytes actually read into the buffer,
-  /// which will be 0 if the connection was closed by the peer.
-  /// On failure, return -1 and sets |*error_message|.
-  ssize_t Read(void* buffer, size_t buffer_size,
-               std::string* error_message) const;
-
-  /// Read |buffer_size| bytes exactly into |buffer|. On success
-  /// return true. On failure, return false and set |*error_message|.
-  bool ReadFull(void* buffer, size_t buffer_size,
-                std::string* error_message) const;
-
-  /// Try to write |buffer_size| bytes form |buffer|. On success
-  /// return the number of bytes actually written to the handle,
-  /// which will be 0 if the connection was called by the peer.
-  /// On failure, return -1 and sets |*error_message|.
-  ssize_t Write(const void* buffer, size_t buffer_size,
-                std::string* error_message) const;
-
-  /// Write |buffer_size| bytes exactly from |buffer|. On success
-  /// return true. On failure, return false and set |*error_message|.
-  bool WriteFull(const void* buffer, size_t buffer_size,
-                 std::string* error_message) const;
-
-  /// Send a |native| handle to the peer. On success return true.
-  /// On failure, return false and sets |*error_message|.
-  bool SendNativeHandle(HandleType native, std::string* error_message) const;
-
-  /// Receive a |native| handle from the peer. On success return true
-  /// and sets |*handle|. On failure, return false and sets |*error_message|.
-  bool ReceiveNativeHandle(IpcHandle* handle, std::string* error_message) const;
-
-  /// Return true if the handle is inheritable (on Win32), or is _not_ closed
-  /// on exec (on Posix).
-  bool IsInheritable() const;
-
-  /// Reset the inheritable / non-O_CLOEXEC flag for this handle.
-  void SetInheritable(bool enable);
-
-#ifndef _WIN32
-  /// Return true if the file descriptor is in non-blocking mode.
-  bool IsNonBlocking() const;
-
-  /// Reset the O_NONBLOCK flag for the corresponding file descriptor.
-  void SetNonBlocking(bool enable);
-
-  /// Return the current status of an asynchronous AsyncClientTo() connection.
-  /// This only makes sense on Posix, and this function should only be called
-  /// after a writable event was detected on the native handle with select()
-  /// or one of its variants. It returns an errno value, which will be 0 if
-  /// the connection succeeded, EAGAIN or EINPROGRESS in case of a spurious
-  /// select() wakeup, or any other error value in case of failed connection,
-  /// or using an invalid handle.
-  static int GetNativeAsyncConnectStatus(int fd);
-#endif
-
-  /// Create anonymous bi-directional pipe. On success return true and
-  /// sets |*read| and |*write|. On failure, return false and sets
-  /// |*error_message|.
-  static bool CreatePipe(IpcHandle* read, IpcHandle* write,
-                         std::string* error_message);
-
-  /// Same as CreatePipe() but returns handles that can be used for asychronous
-  /// operations (i.e. O_NONBLOCK on Posix, and FILE_FLAG_OVERLAPPED on Win32).
-  static bool CreateAsyncPipe(IpcHandle* read, IpcHandle* write,
-                              std::string* error_message);
-
-  /// Close the handle, making it invalid.
-  void Close();
-
-  /// Clone a native handle.
-  static HandleType CloneNativeHandle(HandleType handle,
-                                      bool inherited = false);
-
-  /// Clone existing instance. Result is not inheritable on Win32, and has
-  /// O_CLOEXEC on Posix.
-  IpcHandle Clone() { return { CloneNativeHandle(handle_) }; };
-
-  /// Flush |file| then clone its handle. Result is not inheritable on Win32,
-  /// and has O_CLOEXEC on Posix.
-  static IpcHandle CloneFromStdio(FILE* file);
-
-  /// Clone the handle into an stdio FILE instance.
-  /// |file| can only be one of stdout, stderr, or stdin.
-  /// On success return true, on failure, set errno (even on Win32)
-  /// then return false.
-  bool CloneIntoStdio(FILE* file);
-
-  /// Return the native handle value for an stdio stream.
-  static HandleType NativeForStdio(FILE* file);
-
-  /// Return native handle value.
-  HandleType native_handle() const { return handle_; }
-
-  /// Release the native handle, transferring ownership to the caller.
-  HandleType ReleaseNativeHandle();
-
-  /// Return user visible string for this handle.
-  std::string display() const;
-
- protected:
-  HandleType handle_ = kInvalid;
-};
-
-/// Models an IpcHandle used to bind to specific service.
-/// Only one process can bind to a specific named service at
-/// a time on a given machine.
-class IpcServiceHandle : public IpcHandle {
- public:
-  IpcServiceHandle() = default;
-  ~IpcServiceHandle();
-
-  IpcServiceHandle(IpcServiceHandle&&) noexcept = default;
-  IpcServiceHandle& operator=(IpcServiceHandle&&) noexcept = default;
-
-  /// Create a server handle for |service_name|, which is an arbitrary name
-  /// used to identify a specific global service, which can have only one
-  /// serving instance per (machine, user) combination.
-  ///
-  /// On success, return a valid IpcHandle, that can be used with
-  /// AcceptClient(). On failure, return an invalid handle, and sets
-  /// |*error_message|.
-  ///
-  /// This will fail if another server is already running with the
-  /// same name on the current machine (for the same user). Closing
-  /// the service handle will release the corresponding socket or
-  /// named pipe immediately, and of course the destructor closes
-  /// automatically.
-  ///
-  /// Note that the implementation should be resilient to program
-  /// crashes as well, i.e. on Linux and Win32, it uses kernel features
-  /// that ensure proper socket/pipe cleanup on process exit. On
-  /// other Unix systems, a Unix-domain socket and associated PID file
-  /// are used to detect stale socket files and remove them properly.
-  static IpcServiceHandle BindTo(StringPiece service_name,
-                                 std::string* error_message);
-
-  /// Return true if a given service is already bound. This is racy by
-  /// definition, but useful during unit-tests.
-  static bool IsBound(StringPiece service_name);
-
-  /// Accept one client connection. This is only valid for instances
-  /// returned from BindTo().
-  IpcHandle AcceptClient(std::string* error_message) const;
-
-  /// Accept one client connection, with a timeout. On success, return a valid
-  /// IpcHandle value. On failure, set |*did_timeout| to true if the timeout
-  /// occured, and set |*error_message| to an error message.
-  IpcHandle AcceptClient(int64_t timeout_ms, bool* did_timeout,
-                         std::string* error_message) const;
-
-  /// Connect to the server implementing |service_name|.
-  /// On success, return valid IpcHandle. On failure, set |*error_message|
-  /// then return an invalid value.
-  static IpcHandle ConnectTo(StringPiece service_name,
-                             std::string* error_message);
-
-  /// Connect to the server implementing |service_name|, with a timeout
-  /// in milliseconds. On success, return a valid IpcHandle. On error or
-  /// timeout, set |*error_message| and |*did_timeout| before returning
-  /// an invalid value.
-  static IpcHandle ConnectTo(StringPiece service_name, int64_t timeout_ms,
-                             bool* did_timeout, std::string* error_message);
-
-  /// Connect asychronously to local |service_name|. On success, set
-  /// |*did_connect| and return a valid handle. On failure, set |*error_message|
-  /// and return an invalid handle.
-  ///
-  /// Note that the connection can happen immediately, in which case
-  /// |*did_connect| will be set to true.
-  ///
-  /// On Win32, the returned handle has FILE_FLAG_OVERLAPPED and connection
-  /// always succeeds.
-  ///
-  /// On Posix, the returned handle is non-blocking, and the caller should
-  /// wait for a writable event on it (using select() or one of its variants)
-  /// then use GetNativeAsyncConnectStatus() on the native_handle() value.
-  static IpcHandle AsyncConnectTo(StringPiece service_name, bool* did_connect,
-                                  std::string* error_message);
-
-  /// Close the handle, make it invalid and remove service socket.
-  void Close();
-
- private:
-#ifdef _WIN32
-  IpcServiceHandle(IpcHandle::HandleType handle) : IpcHandle(handle) {}
-#else
-  IpcServiceHandle(IpcHandle::HandleType handle, const std::string& path)
-      : IpcHandle(handle), socket_path_(path) {}
-
-  std::string socket_path_;
-#endif
-};
-
-#ifndef _WIN32
-/// Helper class to temporarily disable SIGPIPE, which halts
-/// the current process by default on Posix. These happen when IPC
-/// pipes are broken by the client.
-class SigPipeIgnore {
- public:
-  SigPipeIgnore() {
-    struct sigaction new_handler = {};
-    new_handler.sa_handler = SIG_IGN;
-    sigaction(SIGPIPE, &new_handler, &prev_handler_);
-  }
-
-  ~SigPipeIgnore() { sigaction(SIGPIPE, &prev_handler_, nullptr); }
-
- private:
-  struct sigaction prev_handler_;
-};
-#endif  // !_WIN32
-
-#endif  // NINJA_IPC_HANDLE_H_
diff --git a/src/ipc_handle_test.cc b/src/ipc_handle_test.cc
deleted file mode 100644
index 47412e2..0000000
--- a/src/ipc_handle_test.cc
+++ /dev/null
@@ -1,307 +0,0 @@
-// Copyright 2023 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 "ipc_handle.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include "test.h"
-
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <fcntl.h>
-#include <unistd.h>
-#endif
-
-namespace {
-
-IpcHandle::HandleType CreateTestNativeHandle() {
-#ifdef _WIN32
-  return CreateFileW(L"NUL", GENERIC_READ | GENERIC_WRITE, 0, nullptr,
-                     OPEN_EXISTING, 0, NULL);
-#else
-  return open("/dev/null", O_RDWR);
-#endif
-}
-
-IpcHandle CreateTestHandle() {
-  return { CreateTestNativeHandle() };
-}
-
-// Create a pipe for testing. On success return true and
-// set |*read| and |*write| to be the read and write ends
-// of the pipe. Note that the pipe is unidirectional due
-// to portability with Windows.
-bool CreateTestPipe(IpcHandle* read, IpcHandle* write) {
-  std::string error;
-  if (!IpcHandle::CreatePipe(read, write, &error)) {
-    fprintf(stderr, "ERROR: when creating pipe: %s\n", error.c_str());
-    return false;
-  }
-  return true;
-}
-
-}  // namespace
-
-TEST(IpcHandle, Constructor) {
-  // Default constructor makes invalid handle
-  IpcHandle empty;
-  EXPECT_FALSE(empty);
-  EXPECT_EQ(IpcHandle::kInvalid, empty.native_handle());
-
-  // Constructor gets test native handle
-  IpcHandle::HandleType test_native_handle = CreateTestNativeHandle();
-  IpcHandle test_handle(test_native_handle);
-  EXPECT_TRUE(test_handle);
-  EXPECT_EQ(test_native_handle, test_handle.native_handle());
-
-  // Move constructor works.
-  IpcHandle test_handle2 = std::move(test_handle);
-  EXPECT_TRUE(test_handle2);
-  EXPECT_EQ(test_native_handle, test_handle2.native_handle());
-  EXPECT_FALSE(test_handle);
-  EXPECT_EQ(IpcHandle::kInvalid, test_handle.native_handle());
-}
-
-TEST(IpcHandle, Close) {
-  IpcHandle test_handle = CreateTestHandle();
-  EXPECT_TRUE(test_handle);
-  EXPECT_NE(IpcHandle::kInvalid, test_handle.native_handle());
-
-  test_handle.Close();
-  EXPECT_FALSE(test_handle);
-  EXPECT_EQ(IpcHandle::kInvalid, test_handle.native_handle());
-
-  // Ensure closing a closed handle doesn't crash.
-  test_handle.Close();
-  EXPECT_FALSE(test_handle);
-  EXPECT_EQ(IpcHandle::kInvalid, test_handle.native_handle());
-}
-
-TEST(IpcHandle, ReadWrite) {
-  const char kInputData[] = "Hello World!";
-  const size_t kInputDataSize = sizeof(kInputData);  // includes terminating \0
-  IpcHandle pipe_read;
-  IpcHandle pipe_write;
-  ASSERT_TRUE(CreateTestPipe(&pipe_read, &pipe_write));
-
-  std::string error_message;
-  ssize_t count = pipe_write.Write(kInputData, kInputDataSize, &error_message);
-  EXPECT_EQ(static_cast<ssize_t>(kInputDataSize), count);
-  EXPECT_TRUE(error_message.empty());
-
-  char data[kInputDataSize] = {};
-  count = pipe_read.Read(data, sizeof(data), &error_message);
-  EXPECT_EQ(static_cast<ssize_t>(kInputDataSize), count);
-  EXPECT_TRUE(error_message.empty());
-
-  // Check transfered content.
-  EXPECT_TRUE(!memcmp(data, kInputData, kInputDataSize));
-
-  // Close the write pipe, trying to read should result in zero
-  // being returned without an error (indicating closed pipe).
-  pipe_write.Close();
-  count = pipe_read.Read(data, kInputDataSize, &error_message);
-  EXPECT_EQ(0, count);
-  EXPECT_TRUE(error_message.empty());
-}
-
-TEST(IpcHandle, Clone) {
-  const char kInputData[] = "Hello World!";
-  const size_t kInputDataSize = sizeof(kInputData);  // includes terminating \0
-  IpcHandle pipe_read;
-  IpcHandle pipe_write;
-  ASSERT_TRUE(CreateTestPipe(&pipe_read, &pipe_write));
-
-  // Clone pipe_read, then close it.
-  IpcHandle pipe_read2 = pipe_read.Clone();
-  pipe_read.Close();
-
-  std::string error_message;
-  ssize_t count = pipe_write.Write(kInputData, kInputDataSize, &error_message);
-  EXPECT_EQ(static_cast<ssize_t>(kInputDataSize), count);
-  EXPECT_TRUE(error_message.empty());
-
-  char data[kInputDataSize] = {};
-  count = pipe_read2.Read(data, sizeof(data), &error_message);
-  EXPECT_EQ(static_cast<ssize_t>(kInputDataSize), count);
-  EXPECT_TRUE(error_message.empty());
-
-  // Check transfered content.
-  EXPECT_TRUE(!memcmp(data, kInputData, kInputDataSize));
-
-  // Close the write pipe, trying to read should result in zero
-  // being returned without an error (indicating closed pipe).
-  pipe_write.Close();
-  count = pipe_read2.Read(data, kInputDataSize, &error_message);
-  EXPECT_EQ(0, count);
-  EXPECT_TRUE(error_message.empty());
-}
-
-TEST(IpcHandle, ReadWriteFull) {
-  const char kInputData[] = "Hello World!";
-  const size_t kInputDataSize = sizeof(kInputData);  // includes terminating \0
-  IpcHandle pipe_read;
-  IpcHandle pipe_write;
-  ASSERT_TRUE(CreateTestPipe(&pipe_read, &pipe_write));
-
-  std::string error_message;
-  EXPECT_TRUE(pipe_write.WriteFull(kInputData, kInputDataSize, &error_message));
-  EXPECT_TRUE(error_message.empty());
-
-  char data[kInputDataSize] = {};
-  EXPECT_TRUE(pipe_read.ReadFull(data, kInputDataSize, &error_message));
-  EXPECT_TRUE(error_message.empty());
-
-  // Check transfered content.
-  EXPECT_TRUE(!memcmp(data, kInputData, kInputDataSize));
-
-  // Close the write pipe, trying to read should result in an error.
-  pipe_write.Close();
-  EXPECT_FALSE(pipe_read.ReadFull(data, kInputDataSize, &error_message));
-  EXPECT_FALSE(error_message.empty());
-}
-
-TEST(IpcHandle, BindConnectAndAccept) {
-  std::string error_message;
-  StringPiece service = "test_service";
-
-  ASSERT_FALSE(IpcServiceHandle::IsBound(service));
-
-  // Tring to connect to a service without a server should fail.
-  IpcHandle no_client = IpcServiceHandle::ConnectTo(service, &error_message);
-  EXPECT_FALSE(no_client);
-  EXPECT_FALSE(error_message.empty());
-
-  ASSERT_FALSE(IpcServiceHandle::IsBound(service));
-
-  // Create server
-  IpcServiceHandle server = IpcServiceHandle::BindTo(service, &error_message);
-  ASSERT_TRUE(server);
-  EXPECT_FALSE(error_message.empty());
-  error_message.clear();
-
-  ASSERT_TRUE(IpcServiceHandle::IsBound(service));
-
-  // Trying to create a secondary server for the same service should fail.
-  IpcServiceHandle no_server =
-      IpcServiceHandle::BindTo(service, &error_message);
-  ASSERT_FALSE(no_server);
-  EXPECT_FALSE(error_message.empty());
-  error_message.clear();
-
-  // Connecto the server, and receive a peer handle.
-  IpcHandle client = IpcServiceHandle::ConnectTo(service, &error_message);
-  EXPECT_TRUE(client);
-  EXPECT_TRUE(error_message.empty());
-
-  IpcHandle peer = server.AcceptClient(&error_message);
-  EXPECT_TRUE(peer);
-  EXPECT_TRUE(error_message.empty());
-
-  // Send data from the client to the peer.
-  const char kInput[] = "sending data";
-  const size_t kInputSize = sizeof(kInput);
-  EXPECT_TRUE(client.WriteFull(kInput, kInputSize, &error_message));
-  EXPECT_TRUE(error_message.empty());
-
-  char output[kInputSize] = {};
-  EXPECT_TRUE(peer.ReadFull(output, sizeof(output), &error_message));
-  EXPECT_TRUE(error_message.empty());
-
-  EXPECT_TRUE(!memcmp(output, kInput, kInputSize));
-
-  // Close all handles and verify that IsBound() returns false.
-  // Note that on Unix, only closing the server handle is necessary for this,
-  // but the way Win32 named pipes work require all client handles closed too.
-  peer.Close();
-  client.Close();
-  server.Close();
-  ASSERT_FALSE(IpcServiceHandle::IsBound(service));
-}
-
-TEST(IpcHandle, BindAcceptWithTimeout) {
-  std::string error_message;
-  StringPiece service = "test_service";
-
-  // Create server
-  IpcServiceHandle server = IpcServiceHandle::BindTo(service, &error_message);
-  ASSERT_TRUE(server);
-  EXPECT_TRUE(error_message.empty());
-
-  // Accepting should time out since no client is trying to connect.
-  bool did_timeout = false;
-  IpcHandle connection = server.AcceptClient(10, &did_timeout, &error_message);
-  EXPECT_FALSE(connection);
-  EXPECT_TRUE(did_timeout);
-  EXPECT_FALSE(error_message.empty());
-  error_message.clear();
-
-  // Connecto the server, and receive a peer handle.
-  IpcHandle client = IpcServiceHandle::ConnectTo(service, &error_message);
-  EXPECT_TRUE(client);
-  EXPECT_TRUE(error_message.empty());
-
-  // Accepting should not work.
-  connection = server.AcceptClient(10, &did_timeout, &error_message);
-  EXPECT_TRUE(connection);
-  EXPECT_FALSE(did_timeout);
-  EXPECT_TRUE(error_message.empty());
-}
-
-TEST(IpcHandle, SendAndReceiveNativeHandle) {
-  IpcHandle pipe1_read;
-  IpcHandle pipe1_write;
-  ASSERT_TRUE(CreateTestPipe(&pipe1_read, &pipe1_write));
-
-  std::string error_message;
-  StringPiece service = "test_service";
-  IpcServiceHandle server = IpcServiceHandle::BindTo(service, &error_message);
-  ASSERT_TRUE(server);
-  EXPECT_TRUE(error_message.empty());
-
-  IpcHandle client = IpcServiceHandle::ConnectTo(service, &error_message);
-  EXPECT_TRUE(client);
-  EXPECT_TRUE(error_message.empty());
-
-  IpcHandle peer = server.AcceptClient(&error_message);
-  EXPECT_TRUE(peer);
-  EXPECT_TRUE(error_message.empty());
-
-  // Send pipe1_write.native_handle() from client to peer.
-  EXPECT_TRUE(
-      client.SendNativeHandle(pipe1_write.native_handle(), &error_message));
-  EXPECT_TRUE(error_message.empty());
-
-  IpcHandle received;
-  EXPECT_TRUE(peer.ReceiveNativeHandle(&received, &error_message));
-  EXPECT_TRUE(error_message.empty());
-
-  // Write to |received|, this should send data to the first pipe.
-  const char kInputData[] = "Bonjour monde!";
-  const size_t kInputDataSize = sizeof(kInputData);
-
-  EXPECT_TRUE(received.WriteFull(kInputData, kInputDataSize, &error_message));
-  EXPECT_TRUE(error_message.empty());
-
-  char data[kInputDataSize] = {};
-  ssize_t count = pipe1_read.Read(data, sizeof(data), &error_message);
-  EXPECT_EQ(static_cast<ssize_t>(sizeof(data)), count);
-  EXPECT_TRUE(error_message.empty());
-
-  // Verify content.
-  EXPECT_TRUE(!memcmp(data, kInputData, kInputDataSize));
-}
diff --git a/src/ipc_utils.cc b/src/ipc_utils.cc
deleted file mode 100644
index ca08848..0000000
--- a/src/ipc_utils.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2023 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 "ipc_utils.h"
-
-#include "util.h"
-
-#ifndef _WIN32
-#include <sys/signal.h>
-#include <unistd.h>
-#endif
-
-RemoteArguments::RemoteArguments(int argc, char** argv) {
-  if (argc > 0) {
-    args_.reserve(static_cast<size_t>(argc));
-    for (int n = 0; n < argc; ++n) {
-      args_.push_back(argv[n]);
-    }
-  }
-}
-
-void RemoteArguments::Reset(const std::vector<std::string>& args) {
-  args_ = args;
-}
-
-char** RemoteArguments::argv() const {
-  if (args_.empty())
-    return nullptr;
-
-  argv_.clear();
-  argv_.reserve(args_.size());
-  for (const auto& arg : args_)
-    argv_.push_back(const_cast<char*>(arg.data()));
-  return argv_.data();
-}
-
-void RemoteArguments::InsertAt(size_t pos, std::string arg) {
-  if (pos > args_.size())
-    pos = args_.size();
-  args_.insert(args_.begin() + pos, std::move(arg));
-}
-
-template <>
-bool RemoteWrite<std::string>(const std::string& str, IpcHandle& con,
-                              std::string* error) {
-  size_t size = str.size();
-  return RemoteWrite(size, con, error) &&
-         con.WriteFull(str.data(), size, error);
-}
-
-template <>
-bool RemoteWrite<RemoteArguments>(const RemoteArguments& args, IpcHandle& con,
-                                  std::string* error) {
-  size_t size = args.args().size();
-  if (!RemoteWrite(size, con, error))
-    return false;
-  for (const auto& arg : args.args()) {
-    if (!RemoteWrite(arg, con, error))
-      return false;
-  }
-  return true;
-}
-
-template <>
-bool RemoteRead<std::string>(std::string& str, IpcHandle& con,
-                             std::string* error) {
-  size_t size;
-  if (!RemoteRead(size, con, error))
-    return false;
-  str.resize(size);
-  if (!size)
-    return true;
-  return con.ReadFull(const_cast<char*>(str.data()), size, error);
-}
-
-template <>
-bool RemoteRead<RemoteArguments>(RemoteArguments& args, IpcHandle& con,
-                                 std::string* error) {
-  size_t size;
-  if (!RemoteRead(size, con, error))
-    return false;
-  std::vector<std::string> vec;
-  vec.resize(size);
-  for (auto& arg : vec) {
-    if (!RemoteRead(arg, con, error))
-      return false;
-  }
-  args.Reset(std::move(vec));
-  return true;
-}
-
-void WireEncoder::Write(const void* buffer, size_t size) {
-  result_.append(static_cast<const char*>(buffer), size);
-}
-
-void WireEncoder::Write(const std::string& str) {
-  Write(static_cast<uint32_t>(str.size()));
-  Write(str.data(), str.size());
-}
-
-WireDecoder::WireDecoder(const void* buffer, size_t size)
-    : p_(static_cast<const char*>(buffer)), end_(p_ + size) {}
-
-WireDecoder::WireDecoder(const std::string& str)
-    : WireDecoder(str.data(), str.size()) {}
-
-void WireDecoder::Read(void* buffer, size_t size) {
-  if (p_ + size <= end_) {
-    ::memcpy(buffer, p_, size);
-    p_ += size;
-  } else {
-    // To avoid relying on un-initialized memory at runtime
-    // if the client fails to check for errors.
-    ::memset(buffer, '\0', size);
-    p_ = end_;
-    has_error_ = true;
-  }
-}
-
-void WireDecoder::Read(std::string& str) {
-  uint32_t size = 0;
-  Read(size);
-  std::string result;
-  if (size) {
-    result.resize(size);
-    Read(const_cast<char*>(result.data()), result.size());
-  }
-  str = std::move(result);
-}
-
-#ifndef _WIN32
-SigPipeBlocker::SigPipeBlocker() {
-  struct sigaction action = {};
-  action.sa_handler = SIG_IGN;
-  if (sigaction(SIGPIPE, &action, &prev_action_) < 0)
-    ErrnoFatal("sigaction");
-}
-
-SigPipeBlocker::~SigPipeBlocker() {
-  if (sigaction(SIGPIPE, &prev_action_, nullptr) < 0)
-    ErrnoFatal("sigaction");
-}
-#endif  // !_WIN32
diff --git a/src/ipc_utils.h b/src/ipc_utils.h
deleted file mode 100644
index 8e3ecf0..0000000
--- a/src/ipc_utils.h
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2023 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_SRC_IPC_UTILS_H_
-#define NINJA_SRC_IPC_UTILS_H_
-
-#include <string>
-#include <vector>
-
-#include "ipc_handle.h"
-
-/// Convenience wrapper for an std::vector<std::string> that can save
-/// the content of an (argc, argv) list of command-line arguments.
-struct RemoteArguments {
-  RemoteArguments() = default;
-  RemoteArguments(int argc, char** argv);
-
-  void Reset(const std::vector<std::string>& args);
-
-  const std::vector<std::string>& args() const { return args_; }
-
-  /// Export instance as (argc, argv) pair.
-  int argc() const { return static_cast<int>(args_.size()); }
-  char** argv() const;
-
-  void InsertAt(size_t pos, std::string arg);
-
- protected:
-  std::vector<std::string> args_;
-  mutable std::vector<char*> argv_;
-};
-
-/// Helper template to write values through an IpcHandle.
-template <typename T>
-bool RemoteWrite(const T& obj, IpcHandle& con, std::string* error) {
-  return con.WriteFull(&obj, sizeof(obj), error);
-}
-
-template <>
-bool RemoteWrite<std::string>(const std::string& str, IpcHandle& con,
-                              std::string* error);
-
-template <>
-bool RemoteWrite<RemoteArguments>(const RemoteArguments& args, IpcHandle& con,
-                                  std::string* error);
-
-/// Helper template to read values through an IpcHandle
-template <typename T>
-bool RemoteRead(T& obj, IpcHandle& con, std::string* error) {
-  return con.ReadFull(&obj, sizeof(obj), error);
-}
-
-template <>
-bool RemoteRead<std::string>(std::string& str, IpcHandle& con,
-                             std::string* error);
-
-template <>
-bool RemoteRead<RemoteArguments>(RemoteArguments& args, IpcHandle& con,
-                                 std::string* error);
-
-/// Simple class to encode values into a byte stream that
-/// can be sent through IPC to another process. Usage is:
-///
-///  1) Create instance.
-///  2) Call one of the Write() methods any number of times.
-///  3) Call GetResult() to retrieve the result as an std::string.
-///
-struct WireEncoder {
-  void Write(const void* buffer, size_t size);
-  void Write(const std::string& str);
-
-  template <typename T>
-  void Write(const T& v) {
-    Write(&v, sizeof(v));
-  }
-
-  std::string TakeResult() { return std::move(result_); }
-
-  std::string result_;
-};
-
-/// Decode a string of bytes received through IPC into values.
-/// Usage is:
-///    1) Create instance passing the input stream as an std::string
-///    2) Call Read() methods as many times as necessary.
-///    3) Check has_error() after each Read(), or after a series of
-///       Read() calls to see if there was any error (i.e. read overflow).
-///
-struct WireDecoder {
-  WireDecoder(const void* buffer, size_t size);
-  explicit WireDecoder(const std::string& str);
-
-  void Read(void* buffer, size_t size);
-  void Read(std::string& str);
-
-  template <typename T>
-  void Read(T& v) {
-    Read(&v, sizeof(T));
-  }
-
-  bool has_error() const { return has_error_; }
-
-  const char* p_ = nullptr;
-  const char* end_ = nullptr;
-  bool has_error_ = false;
-};
-
-#ifndef _WIN32
-/// Convenience class to ignore SIGPIPE signals when
-/// doing inter-process writes through a pipe.
-class SigPipeBlocker {
- public:
-  SigPipeBlocker();
-  ~SigPipeBlocker();
-
- private:
-  struct sigaction prev_action_;
-};
-#endif  // !_WIN32
-
-#endif  // NINJA_SRC_IPC_UTILS_H_
diff --git a/src/ipc_utils_test.cc b/src/ipc_utils_test.cc
deleted file mode 100644
index 7edc5c0..0000000
--- a/src/ipc_utils_test.cc
+++ /dev/null
@@ -1,223 +0,0 @@
-// Copyright 2023 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 "ipc_utils.h"
-
-#include "test.h"
-
-namespace {
-
-#ifndef _WIN32
-// Helper class used to catch SIGPIPE and set a global flag when
-// it happens instead of terminating the current process. Will be
-// used to verify that SigPipeBlocker works.
-struct SigPipeCatcher {
-  SigPipeCatcher() {
-    // Install signal handler.
-    struct sigaction action = {};
-    action.sa_handler = [](int) { sigpipe_happened_ = 1; };
-    sigaction(SIGPIPE, &action, &prev_action_);
-
-    // Unblock signal
-    sigset_t mask;
-    sigemptyset(&mask);
-    sigaddset(&mask, SIGPIPE);
-    sigprocmask(SIG_UNBLOCK, &mask, &prev_mask_);
-  }
-
-  ~SigPipeCatcher() {
-    sigaction(SIGPIPE, &prev_action_, nullptr);
-    sigprocmask(SIG_SETMASK, &prev_mask_, nullptr);
-  }
-
-  void Reset() { sigpipe_happened_ = 0; }
-
-  bool sigpipe_happened() const { return bool(sigpipe_happened_); }
-
-  struct sigaction prev_action_;
-  sigset_t prev_mask_;
-  static volatile sig_atomic_t sigpipe_happened_;
-};
-
-// static
-volatile sig_atomic_t SigPipeCatcher::sigpipe_happened_ = 0;
-
-#endif  // !_WIN32
-
-}  // namespace
-
-TEST(RemoteArguments, DefaultConstruction) {
-  RemoteArguments args;
-  EXPECT_EQ(0, args.argc());
-  EXPECT_FALSE(args.argv());
-  EXPECT_EQ(0u, args.args().size());
-}
-
-TEST(RemoteArguments, Construction) {
-  const char* const kTestArgs[] = {
-    "foo",
-    "bar",
-  };
-  RemoteArguments args(2, (char**)kTestArgs);
-  EXPECT_EQ(2, args.argc());
-  char** argv = args.argv();
-  ASSERT_TRUE(argv);
-  ASSERT_TRUE(argv[0]);
-  ASSERT_TRUE(argv[1]);
-  ASSERT_TRUE(!strcmp(argv[0], kTestArgs[0]));
-  ASSERT_TRUE(!strcmp(argv[1], kTestArgs[1]));
-
-  auto vec = args.args();
-  ASSERT_EQ(2u, vec.size());
-  ASSERT_EQ(vec[0], kTestArgs[0]);
-  ASSERT_EQ(vec[1], kTestArgs[1]);
-}
-
-TEST(RemoteArguments, Reset) {
-  const char* const kTestArgs[] = {
-    "foo",
-    "bar",
-  };
-  RemoteArguments args(2, (char**)kTestArgs);
-  EXPECT_EQ(2, args.argc());
-
-  std::vector<std::string> new_args;
-  new_args.push_back("zoo");
-  args.Reset(new_args);
-
-  EXPECT_EQ(1, args.argc());
-  char** argv = args.argv();
-  ASSERT_TRUE(argv);
-  ASSERT_TRUE(argv[0]);
-  ASSERT_EQ(new_args[0], argv[0]);
-}
-
-TEST(RemoteArguments, InsertAt) {
-  RemoteArguments args;
-  args.InsertAt(10, "foo");
-  ASSERT_EQ(1, args.argc());
-  ASSERT_EQ(args.args()[0], "foo");
-  args.InsertAt(0, "bar");
-  ASSERT_EQ(2, args.argc());
-  ASSERT_EQ(args.args()[0], "bar");
-  ASSERT_EQ(args.args()[1], "foo");
-  args.InsertAt(1, "zoo");
-  ASSERT_EQ(3, args.argc());
-  ASSERT_EQ(args.args()[0], "bar");
-  ASSERT_EQ(args.args()[1], "zoo");
-  ASSERT_EQ(args.args()[2], "foo");
-}
-
-TEST(WireEncoderAndDecoder, SimpleValues) {
-  WireEncoder encoder;
-  uint8_t byte1 = 12;
-  uint32_t word1 = 42;
-  uint8_t byte2 = 56;
-  encoder.Write(byte1);
-  encoder.Write(word1);
-  encoder.Write(byte2);
-
-  std::string r = encoder.TakeResult();
-  ASSERT_EQ(6u, r.size());
-
-  WireDecoder decoder(r);
-  uint8_t rbyte1 = 0;
-  uint32_t rword1 = 0;
-  uint8_t rbyte2 = 0;
-  decoder.Read(rbyte1);
-  ASSERT_FALSE(decoder.has_error());
-  decoder.Read(rword1);
-  ASSERT_FALSE(decoder.has_error());
-  decoder.Read(rbyte2);
-  ASSERT_FALSE(decoder.has_error());
-  ASSERT_EQ(byte1, rbyte1);
-  ASSERT_EQ(word1, rword1);
-  ASSERT_EQ(byte2, rbyte2);
-
-  decoder.Read(rbyte1);
-  ASSERT_TRUE(decoder.has_error());
-}
-
-TEST(WireEncoderAndDecoder, Strings) {
-  static const char* const kStrings[] = {
-    "foo_bar",
-    "",
-    "hello world!",
-  };
-  WireEncoder encoder;
-  size_t expected_size = 0;
-  for (const char* str : kStrings) {
-    encoder.Write(std::string(str));
-    expected_size += 4 + ::strlen(str);
-  }
-
-  std::string r = encoder.TakeResult();
-  ASSERT_EQ(expected_size, r.size());
-
-  WireDecoder decoder(r);
-  std::vector<std::string> result;
-  for (const char* str : kStrings) {
-    result.emplace_back(str);
-    decoder.Read(result.back());
-  }
-  ASSERT_FALSE(decoder.has_error());
-
-  auto it = result.begin();
-  for (const char* str : kStrings) {
-    ASSERT_EQ(*it, str);
-    ++it;
-  }
-}
-
-#ifndef _WIN32
-
-TEST(SigPipeBlocker, Test) {
-  SigPipeCatcher catcher;
-
-  // First, verify that the catcher works properly.
-  std::string error;
-  char byte[1] = { 'x' };
-  IpcHandle read_end, write_end;
-
-  ASSERT_TRUE(IpcHandle::CreatePipe(&read_end, &write_end, &error));
-  read_end.Close();
-  errno = 0;
-  ASSERT_FALSE(write_end.WriteFull(byte, 1, &error));
-  ASSERT_EQ(EPIPE, errno);
-  ASSERT_TRUE(catcher.sigpipe_happened());
-  write_end.Close();
-
-  // Then verify that the blocker works properly.
-  {
-    SigPipeBlocker blocker;
-    catcher.Reset();
-
-    ASSERT_TRUE(IpcHandle::CreatePipe(&read_end, &write_end, &error));
-    read_end.Close();
-    errno = 0;
-    ASSERT_FALSE(write_end.WriteFull(byte, 1, &error));
-    ASSERT_EQ(EPIPE, errno);
-    ASSERT_FALSE(catcher.sigpipe_happened());
-    write_end.Close();
-  }
-
-  // Do it again, to verify the destructor released the action.
-  ASSERT_TRUE(IpcHandle::CreatePipe(&read_end, &write_end, &error));
-  read_end.Close();
-  errno = 0;
-  ASSERT_FALSE(write_end.WriteFull(byte, 1, &error));
-  ASSERT_EQ(EPIPE, errno);
-  ASSERT_TRUE(catcher.sigpipe_happened());
-}
-#endif  // !_WIN32
diff --git a/src/json.cc b/src/json.cc
deleted file mode 100644
index 4bbf6e1..0000000
--- a/src/json.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2021 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 "json.h"
-
-#include <cstdio>
-#include <string>
-
-std::string EncodeJSONString(const std::string& in) {
-  static const char* hex_digits = "0123456789abcdef";
-  std::string out;
-  out.reserve(in.length() * 1.2);
-  for (std::string::const_iterator it = in.begin(); it != in.end(); ++it) {
-    char c = *it;
-    if (c == '\b')
-      out += "\\b";
-    else if (c == '\f')
-      out += "\\f";
-    else if (c == '\n')
-      out += "\\n";
-    else if (c == '\r')
-      out += "\\r";
-    else if (c == '\t')
-      out += "\\t";
-    else if (0x0 <= c && c < 0x20) {
-      out += "\\u00";
-      out += hex_digits[c >> 4];
-      out += hex_digits[c & 0xf];
-    } else if (c == '\\')
-      out += "\\\\";
-    else if (c == '\"')
-      out += "\\\"";
-    else
-      out += c;
-  }
-  return out;
-}
-
-void PrintJSONString(const std::string& in) {
-  std::string out = EncodeJSONString(in);
-  fwrite(out.c_str(), 1, out.length(), stdout);
-}
diff --git a/src/json.h b/src/json.h
deleted file mode 100644
index f39c759..0000000
--- a/src/json.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2021 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_JSON_H_
-#define NINJA_JSON_H_
-
-#include <string>
-
-// Encode a string in JSON format without encolsing quotes
-std::string EncodeJSONString(const std::string& in);
-
-// Print a string in JSON format to stdout without enclosing quotes
-void PrintJSONString(const std::string& in);
-
-#endif
diff --git a/src/json_test.cc b/src/json_test.cc
deleted file mode 100644
index b4afc73..0000000
--- a/src/json_test.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2021 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 "json.h"
-
-#include "test.h"
-
-TEST(JSONTest, RegularAscii) {
-  EXPECT_EQ(EncodeJSONString("foo bar"), "foo bar");
-}
-
-TEST(JSONTest, EscapedChars) {
-  EXPECT_EQ(EncodeJSONString("\"\\\b\f\n\r\t"),
-            "\\\""
-            "\\\\"
-            "\\b\\f\\n\\r\\t");
-}
-
-// codepoints between 0 and 0x1f should be escaped
-TEST(JSONTest, ControlChars) {
-  EXPECT_EQ(EncodeJSONString("\x01\x1f"), "\\u0001\\u001f");
-}
-
-// Leave them alone as JSON accepts unicode literals
-// out of control character range
-TEST(JSONTest, UTF8) {
-  const char* utf8str = "\xe4\xbd\xa0\xe5\xa5\xbd";
-  EXPECT_EQ(EncodeJSONString(utf8str), utf8str);
-}
diff --git a/src/lexer.cc b/src/lexer.cc
deleted file mode 100644
index b1e1152..0000000
--- a/src/lexer.cc
+++ /dev/null
@@ -1,825 +0,0 @@
-/* Generated by re2c */
-// 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.
-
-#include "lexer.h"
-
-#include <stdio.h>
-
-#include "eval_env.h"
-#include "util.h"
-
-using namespace std;
-
-bool Lexer::Error(const string& message, string* err) {
-  // Compute line/column.
-  int line = 1;
-  const char* line_start = input_.str_;
-  for (const char* p = input_.str_; p < last_token_; ++p) {
-    if (*p == '\n') {
-      ++line;
-      line_start = p + 1;
-    }
-  }
-  int col = last_token_ ? (int)(last_token_ - line_start) : 0;
-
-  *err = StringFormat("%.*s:%d: %s\n", filename_.len_, filename_.str_, line,
-                      message.c_str());
-
-  // Add some context to the message.
-  const int kTruncateColumn = 72;
-  if (col > 0 && col < kTruncateColumn) {
-    int len;
-    bool truncated = true;
-    for (len = 0; len < kTruncateColumn; ++len) {
-      if (line_start[len] == 0 || line_start[len] == '\n') {
-        truncated = false;
-        break;
-      }
-    }
-    *err += string(line_start, len);
-    if (truncated)
-      *err += "...";
-    *err += "\n";
-    *err += string(col, ' ');
-    *err += "^ near here";
-  }
-
-  return false;
-}
-
-Lexer::Lexer(const char* input) {
-  Start("input", input);
-}
-
-void Lexer::Start(StringPiece filename, StringPiece input) {
-  filename_ = filename;
-  input_ = input;
-  ofs_ = input_.str_;
-  last_token_ = NULL;
-}
-
-const char* Lexer::TokenName(Token t) {
-  switch (t) {
-  case ERROR:    return "lexing error";
-  case BUILD:    return "'build'";
-  case COLON:    return "':'";
-  case DEFAULT:  return "'default'";
-  case EQUALS:   return "'='";
-  case IDENT:    return "identifier";
-  case INCLUDE:  return "'include'";
-  case INDENT:   return "indent";
-  case NEWLINE:  return "newline";
-  case PIPE2:    return "'||'";
-  case PIPE:     return "'|'";
-  case PIPEAT:   return "'|@'";
-  case POOL:     return "'pool'";
-  case RULE:     return "'rule'";
-  case SUBNINJA: return "'subninja'";
-  case TEOF:     return "eof";
-  }
-  return NULL;  // not reached
-}
-
-const char* Lexer::TokenErrorHint(Token expected) {
-  switch (expected) {
-  case COLON:
-    return " ($ also escapes ':')";
-  default:
-    return "";
-  }
-}
-
-string Lexer::DescribeLastError() {
-  if (last_token_) {
-    switch (last_token_[0]) {
-    case '\t':
-      return "tabs are not allowed, use spaces";
-    }
-  }
-  return "lexing error";
-}
-
-void Lexer::UnreadToken() {
-  ofs_ = last_token_;
-}
-
-Lexer::Token Lexer::ReadToken() {
-  const char* p = ofs_;
-  const char* q;
-  const char* start;
-  Lexer::Token token;
-  for (;;) {
-    start = p;
-    
-{
-	unsigned char yych;
-	unsigned int yyaccept = 0;
-	static const unsigned char yybm[] = {
-		  0, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128,   0, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		160, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 192, 192, 128, 
-		192, 192, 192, 192, 192, 192, 192, 192, 
-		192, 192, 128, 128, 128, 128, 128, 128, 
-		128, 192, 192, 192, 192, 192, 192, 192, 
-		192, 192, 192, 192, 192, 192, 192, 192, 
-		192, 192, 192, 192, 192, 192, 192, 192, 
-		192, 192, 192, 128, 128, 128, 128, 192, 
-		128, 192, 192, 192, 192, 192, 192, 192, 
-		192, 192, 192, 192, 192, 192, 192, 192, 
-		192, 192, 192, 192, 192, 192, 192, 192, 
-		192, 192, 192, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-	};
-	yych = *p;
-	if (yybm[0+yych] & 32) {
-		goto yy9;
-	}
-	if (yych <= '^') {
-		if (yych <= ',') {
-			if (yych <= '\f') {
-				if (yych <= 0x00) goto yy2;
-				if (yych == '\n') goto yy6;
-				goto yy4;
-			} else {
-				if (yych <= '\r') goto yy8;
-				if (yych == '#') goto yy12;
-				goto yy4;
-			}
-		} else {
-			if (yych <= ':') {
-				if (yych == '/') goto yy4;
-				if (yych <= '9') goto yy13;
-				goto yy16;
-			} else {
-				if (yych <= '=') {
-					if (yych <= '<') goto yy4;
-					goto yy18;
-				} else {
-					if (yych <= '@') goto yy4;
-					if (yych <= 'Z') goto yy13;
-					goto yy4;
-				}
-			}
-		}
-	} else {
-		if (yych <= 'i') {
-			if (yych <= 'b') {
-				if (yych == '`') goto yy4;
-				if (yych <= 'a') goto yy13;
-				goto yy20;
-			} else {
-				if (yych == 'd') goto yy21;
-				if (yych <= 'h') goto yy13;
-				goto yy22;
-			}
-		} else {
-			if (yych <= 'r') {
-				if (yych == 'p') goto yy23;
-				if (yych <= 'q') goto yy13;
-				goto yy24;
-			} else {
-				if (yych <= 'z') {
-					if (yych <= 's') goto yy25;
-					goto yy13;
-				} else {
-					if (yych == '|') goto yy26;
-					goto yy4;
-				}
-			}
-		}
-	}
-yy2:
-	++p;
-	{ token = TEOF;     break; }
-yy4:
-	++p;
-yy5:
-	{ token = ERROR;    break; }
-yy6:
-	++p;
-	{ token = NEWLINE;  break; }
-yy8:
-	yych = *++p;
-	if (yych == '\n') goto yy28;
-	goto yy5;
-yy9:
-	yyaccept = 0;
-	yych = *(q = ++p);
-	if (yybm[0+yych] & 32) {
-		goto yy9;
-	}
-	if (yych <= '\f') {
-		if (yych == '\n') goto yy6;
-	} else {
-		if (yych <= '\r') goto yy30;
-		if (yych == '#') goto yy32;
-	}
-yy11:
-	{ token = INDENT;   break; }
-yy12:
-	yyaccept = 1;
-	yych = *(q = ++p);
-	if (yych <= 0x00) goto yy5;
-	goto yy33;
-yy13:
-	yych = *++p;
-yy14:
-	if (yybm[0+yych] & 64) {
-		goto yy13;
-	}
-	{ token = IDENT;    break; }
-yy16:
-	++p;
-	{ token = COLON;    break; }
-yy18:
-	++p;
-	{ token = EQUALS;   break; }
-yy20:
-	yych = *++p;
-	if (yych == 'u') goto yy36;
-	goto yy14;
-yy21:
-	yych = *++p;
-	if (yych == 'e') goto yy37;
-	goto yy14;
-yy22:
-	yych = *++p;
-	if (yych == 'n') goto yy38;
-	goto yy14;
-yy23:
-	yych = *++p;
-	if (yych == 'o') goto yy39;
-	goto yy14;
-yy24:
-	yych = *++p;
-	if (yych == 'u') goto yy40;
-	goto yy14;
-yy25:
-	yych = *++p;
-	if (yych == 'u') goto yy41;
-	goto yy14;
-yy26:
-	yych = *++p;
-	if (yych == '@') goto yy42;
-	if (yych == '|') goto yy44;
-	{ token = PIPE;     break; }
-yy28:
-	++p;
-	{ token = NEWLINE;  break; }
-yy30:
-	yych = *++p;
-	if (yych == '\n') goto yy28;
-yy31:
-	p = q;
-	if (yyaccept == 0) {
-		goto yy11;
-	} else {
-		goto yy5;
-	}
-yy32:
-	yych = *++p;
-yy33:
-	if (yybm[0+yych] & 128) {
-		goto yy32;
-	}
-	if (yych <= 0x00) goto yy31;
-	++p;
-	{ continue; }
-yy36:
-	yych = *++p;
-	if (yych == 'i') goto yy46;
-	goto yy14;
-yy37:
-	yych = *++p;
-	if (yych == 'f') goto yy47;
-	goto yy14;
-yy38:
-	yych = *++p;
-	if (yych == 'c') goto yy48;
-	goto yy14;
-yy39:
-	yych = *++p;
-	if (yych == 'o') goto yy49;
-	goto yy14;
-yy40:
-	yych = *++p;
-	if (yych == 'l') goto yy50;
-	goto yy14;
-yy41:
-	yych = *++p;
-	if (yych == 'b') goto yy51;
-	goto yy14;
-yy42:
-	++p;
-	{ token = PIPEAT;   break; }
-yy44:
-	++p;
-	{ token = PIPE2;    break; }
-yy46:
-	yych = *++p;
-	if (yych == 'l') goto yy52;
-	goto yy14;
-yy47:
-	yych = *++p;
-	if (yych == 'a') goto yy53;
-	goto yy14;
-yy48:
-	yych = *++p;
-	if (yych == 'l') goto yy54;
-	goto yy14;
-yy49:
-	yych = *++p;
-	if (yych == 'l') goto yy55;
-	goto yy14;
-yy50:
-	yych = *++p;
-	if (yych == 'e') goto yy57;
-	goto yy14;
-yy51:
-	yych = *++p;
-	if (yych == 'n') goto yy59;
-	goto yy14;
-yy52:
-	yych = *++p;
-	if (yych == 'd') goto yy60;
-	goto yy14;
-yy53:
-	yych = *++p;
-	if (yych == 'u') goto yy62;
-	goto yy14;
-yy54:
-	yych = *++p;
-	if (yych == 'u') goto yy63;
-	goto yy14;
-yy55:
-	yych = *++p;
-	if (yybm[0+yych] & 64) {
-		goto yy13;
-	}
-	{ token = POOL;     break; }
-yy57:
-	yych = *++p;
-	if (yybm[0+yych] & 64) {
-		goto yy13;
-	}
-	{ token = RULE;     break; }
-yy59:
-	yych = *++p;
-	if (yych == 'i') goto yy64;
-	goto yy14;
-yy60:
-	yych = *++p;
-	if (yybm[0+yych] & 64) {
-		goto yy13;
-	}
-	{ token = BUILD;    break; }
-yy62:
-	yych = *++p;
-	if (yych == 'l') goto yy65;
-	goto yy14;
-yy63:
-	yych = *++p;
-	if (yych == 'd') goto yy66;
-	goto yy14;
-yy64:
-	yych = *++p;
-	if (yych == 'n') goto yy67;
-	goto yy14;
-yy65:
-	yych = *++p;
-	if (yych == 't') goto yy68;
-	goto yy14;
-yy66:
-	yych = *++p;
-	if (yych == 'e') goto yy70;
-	goto yy14;
-yy67:
-	yych = *++p;
-	if (yych == 'j') goto yy72;
-	goto yy14;
-yy68:
-	yych = *++p;
-	if (yybm[0+yych] & 64) {
-		goto yy13;
-	}
-	{ token = DEFAULT;  break; }
-yy70:
-	yych = *++p;
-	if (yybm[0+yych] & 64) {
-		goto yy13;
-	}
-	{ token = INCLUDE;  break; }
-yy72:
-	yych = *++p;
-	if (yych != 'a') goto yy14;
-	yych = *++p;
-	if (yybm[0+yych] & 64) {
-		goto yy13;
-	}
-	{ token = SUBNINJA; break; }
-}
-
-  }
-
-  last_token_ = start;
-  ofs_ = p;
-  if (token != NEWLINE && token != TEOF)
-    EatWhitespace();
-  return token;
-}
-
-bool Lexer::PeekToken(Token token) {
-  Token t = ReadToken();
-  if (t == token)
-    return true;
-  UnreadToken();
-  return false;
-}
-
-void Lexer::EatWhitespace() {
-  const char* p = ofs_;
-  const char* q;
-  for (;;) {
-    ofs_ = p;
-    
-{
-	unsigned char yych;
-	static const unsigned char yybm[] = {
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		128,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-	};
-	yych = *p;
-	if (yybm[0+yych] & 128) {
-		goto yy81;
-	}
-	if (yych <= 0x00) goto yy77;
-	if (yych == '$') goto yy84;
-	goto yy79;
-yy77:
-	++p;
-	{ break; }
-yy79:
-	++p;
-yy80:
-	{ break; }
-yy81:
-	yych = *++p;
-	if (yybm[0+yych] & 128) {
-		goto yy81;
-	}
-	{ continue; }
-yy84:
-	yych = *(q = ++p);
-	if (yych == '\n') goto yy85;
-	if (yych == '\r') goto yy87;
-	goto yy80;
-yy85:
-	++p;
-	{ continue; }
-yy87:
-	yych = *++p;
-	if (yych == '\n') goto yy89;
-	p = q;
-	goto yy80;
-yy89:
-	++p;
-	{ continue; }
-}
-
-  }
-}
-
-bool Lexer::ReadIdent(string* out) {
-  const char* p = ofs_;
-  const char* start;
-  for (;;) {
-    start = p;
-    
-{
-	unsigned char yych;
-	static const unsigned char yybm[] = {
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0, 128, 128,   0, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128,   0,   0,   0,   0,   0,   0, 
-		  0, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128,   0,   0,   0,   0, 128, 
-		  0, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128, 128, 128, 128, 128, 128, 
-		128, 128, 128,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-		  0,   0,   0,   0,   0,   0,   0,   0, 
-	};
-	yych = *p;
-	if (yybm[0+yych] & 128) {
-		goto yy95;
-	}
-	++p;
-	{
-      last_token_ = start;
-      return false;
-    }
-yy95:
-	yych = *++p;
-	if (yybm[0+yych] & 128) {
-		goto yy95;
-	}
-	{
-      out->assign(start, p - start);
-      break;
-    }
-}
-
-  }
-  last_token_ = start;
-  ofs_ = p;
-  EatWhitespace();
-  return true;
-}
-
-bool Lexer::ReadEvalString(EvalString* eval, bool path, string* err) {
-  const char* p = ofs_;
-  const char* q;
-  const char* start;
-  for (;;) {
-    start = p;
-    
-{
-	unsigned char yych;
-	static const unsigned char yybm[] = {
-		  0,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,   0,  16,  16,   0,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 32,  16,  16,  16,   0,  16,  16,  16, 
-		 16,  16,  16,  16,  16, 208, 144,  16, 
-		208, 208, 208, 208, 208, 208, 208, 208, 
-		208, 208,   0,  16,  16,  16,  16,  16, 
-		 16, 208, 208, 208, 208, 208, 208, 208, 
-		208, 208, 208, 208, 208, 208, 208, 208, 
-		208, 208, 208, 208, 208, 208, 208, 208, 
-		208, 208, 208,  16,  16,  16,  16, 208, 
-		 16, 208, 208, 208, 208, 208, 208, 208, 
-		208, 208, 208, 208, 208, 208, 208, 208, 
-		208, 208, 208, 208, 208, 208, 208, 208, 
-		208, 208, 208,  16,   0,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-		 16,  16,  16,  16,  16,  16,  16,  16, 
-	};
-	yych = *p;
-	if (yybm[0+yych] & 16) {
-		goto yy102;
-	}
-	if (yych <= '\r') {
-		if (yych <= 0x00) goto yy100;
-		if (yych <= '\n') goto yy105;
-		goto yy107;
-	} else {
-		if (yych <= ' ') goto yy105;
-		if (yych <= '$') goto yy109;
-		goto yy105;
-	}
-yy100:
-	++p;
-	{
-      last_token_ = start;
-      return Error("unexpected EOF", err);
-    }
-yy102:
-	yych = *++p;
-	if (yybm[0+yych] & 16) {
-		goto yy102;
-	}
-	{
-      eval->AddText(StringPiece(start, p - start));
-      continue;
-    }
-yy105:
-	++p;
-	{
-      if (path) {
-        p = start;
-        break;
-      } else {
-        if (*start == '\n')
-          break;
-        eval->AddText(StringPiece(start, 1));
-        continue;
-      }
-    }
-yy107:
-	yych = *++p;
-	if (yych == '\n') goto yy110;
-	{
-      last_token_ = start;
-      return Error(DescribeLastError(), err);
-    }
-yy109:
-	yych = *++p;
-	if (yybm[0+yych] & 64) {
-		goto yy122;
-	}
-	if (yych <= ' ') {
-		if (yych <= '\f') {
-			if (yych == '\n') goto yy114;
-			goto yy112;
-		} else {
-			if (yych <= '\r') goto yy117;
-			if (yych <= 0x1F) goto yy112;
-			goto yy118;
-		}
-	} else {
-		if (yych <= '/') {
-			if (yych == '$') goto yy120;
-			goto yy112;
-		} else {
-			if (yych <= ':') goto yy125;
-			if (yych <= '`') goto yy112;
-			if (yych <= '{') goto yy127;
-			goto yy112;
-		}
-	}
-yy110:
-	++p;
-	{
-      if (path)
-        p = start;
-      break;
-    }
-yy112:
-	++p;
-yy113:
-	{
-      last_token_ = start;
-      return Error("bad $-escape (literal $ must be written as $$)", err);
-    }
-yy114:
-	yych = *++p;
-	if (yybm[0+yych] & 32) {
-		goto yy114;
-	}
-	{
-      continue;
-    }
-yy117:
-	yych = *++p;
-	if (yych == '\n') goto yy128;
-	goto yy113;
-yy118:
-	++p;
-	{
-      eval->AddText(StringPiece(" ", 1));
-      continue;
-    }
-yy120:
-	++p;
-	{
-      eval->AddText(StringPiece("$", 1));
-      continue;
-    }
-yy122:
-	yych = *++p;
-	if (yybm[0+yych] & 64) {
-		goto yy122;
-	}
-	{
-      eval->AddSpecial(StringPiece(start + 1, p - start - 1));
-      continue;
-    }
-yy125:
-	++p;
-	{
-      eval->AddText(StringPiece(":", 1));
-      continue;
-    }
-yy127:
-	yych = *(q = ++p);
-	if (yybm[0+yych] & 128) {
-		goto yy131;
-	}
-	goto yy113;
-yy128:
-	yych = *++p;
-	if (yych == ' ') goto yy128;
-	{
-      continue;
-    }
-yy131:
-	yych = *++p;
-	if (yybm[0+yych] & 128) {
-		goto yy131;
-	}
-	if (yych == '}') goto yy134;
-	p = q;
-	goto yy113;
-yy134:
-	++p;
-	{
-      eval->AddSpecial(StringPiece(start + 2, p - start - 3));
-      continue;
-    }
-}
-
-  }
-  last_token_ = start;
-  ofs_ = p;
-  if (path)
-    EatWhitespace();
-  // Non-path strings end in newlines, so there's no whitespace to eat.
-  return true;
-}
diff --git a/src/lexer.h b/src/lexer.h
deleted file mode 100644
index 683fd6c..0000000
--- a/src/lexer.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// 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.
-
-#ifndef NINJA_LEXER_H_
-#define NINJA_LEXER_H_
-
-#include "string_piece.h"
-
-// Windows may #define ERROR.
-#ifdef ERROR
-#undef ERROR
-#endif
-
-struct EvalString;
-
-struct Lexer {
-  Lexer() {}
-  /// Helper ctor useful for tests.
-  explicit Lexer(const char* input);
-
-  enum Token {
-    ERROR,
-    BUILD,
-    COLON,
-    DEFAULT,
-    EQUALS,
-    IDENT,
-    INCLUDE,
-    INDENT,
-    NEWLINE,
-    PIPE,
-    PIPE2,
-    PIPEAT,
-    POOL,
-    RULE,
-    SUBNINJA,
-    TEOF,
-  };
-
-  /// Return a human-readable form of a token, used in error messages.
-  static const char* TokenName(Token t);
-
-  /// Return a human-readable token hint, used in error messages.
-  static const char* TokenErrorHint(Token expected);
-
-  /// If the last token read was an ERROR token, provide more info
-  /// or the empty string.
-  std::string DescribeLastError();
-
-  /// Start parsing some input.
-  void Start(StringPiece filename, StringPiece input);
-
-  /// Read a Token from the Token enum.
-  Token ReadToken();
-
-  /// Rewind to the last read Token.
-  void UnreadToken();
-
-  /// If the next token is \a token, read it and return true.
-  bool PeekToken(Token token);
-
-  /// Read a simple identifier (a rule or variable name).
-  /// Returns false if a name can't be read.
-  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, 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, std::string* err) {
-    return ReadEvalString(value, false, err);
-  }
-
-  /// Construct an error message with context.
-  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, std::string* err);
-
-  StringPiece filename_;
-  StringPiece input_;
-  const char* ofs_;
-  const char* last_token_;
-};
-
-#endif // NINJA_LEXER_H_
diff --git a/src/lexer.in.cc b/src/lexer.in.cc
deleted file mode 100644
index 6f36e6a..0000000
--- a/src/lexer.in.cc
+++ /dev/null
@@ -1,280 +0,0 @@
-// 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.
-
-#include "lexer.h"
-
-#include <stdio.h>
-
-#include "eval_env.h"
-#include "util.h"
-
-using namespace std;
-
-bool Lexer::Error(const string& message, string* err) {
-  // Compute line/column.
-  int line = 1;
-  const char* line_start = input_.str_;
-  for (const char* p = input_.str_; p < last_token_; ++p) {
-    if (*p == '\n') {
-      ++line;
-      line_start = p + 1;
-    }
-  }
-  int col = last_token_ ? (int)(last_token_ - line_start) : 0;
-
-  *err = StringFormat("%.*s:%d: %s\n", filename_.len_, filename_.str_, line,
-                      message.c_str());
-
-  // Add some context to the message.
-  const int kTruncateColumn = 72;
-  if (col > 0 && col < kTruncateColumn) {
-    int len;
-    bool truncated = true;
-    for (len = 0; len < kTruncateColumn; ++len) {
-      if (line_start[len] == 0 || line_start[len] == '\n') {
-        truncated = false;
-        break;
-      }
-    }
-    *err += string(line_start, len);
-    if (truncated)
-      *err += "...";
-    *err += "\n";
-    *err += string(col, ' ');
-    *err += "^ near here";
-  }
-
-  return false;
-}
-
-Lexer::Lexer(const char* input) {
-  Start("input", input);
-}
-
-void Lexer::Start(StringPiece filename, StringPiece input) {
-  filename_ = filename;
-  input_ = input;
-  ofs_ = input_.str_;
-  last_token_ = NULL;
-}
-
-const char* Lexer::TokenName(Token t) {
-  switch (t) {
-  case ERROR:    return "lexing error";
-  case BUILD:    return "'build'";
-  case COLON:    return "':'";
-  case DEFAULT:  return "'default'";
-  case EQUALS:   return "'='";
-  case IDENT:    return "identifier";
-  case INCLUDE:  return "'include'";
-  case INDENT:   return "indent";
-  case NEWLINE:  return "newline";
-  case PIPE2:    return "'||'";
-  case PIPE:     return "'|'";
-  case PIPEAT:   return "'|@'";
-  case POOL:     return "'pool'";
-  case RULE:     return "'rule'";
-  case SUBNINJA: return "'subninja'";
-  case TEOF:     return "eof";
-  }
-  return NULL;  // not reached
-}
-
-const char* Lexer::TokenErrorHint(Token expected) {
-  switch (expected) {
-  case COLON:
-    return " ($ also escapes ':')";
-  default:
-    return "";
-  }
-}
-
-string Lexer::DescribeLastError() {
-  if (last_token_) {
-    switch (last_token_[0]) {
-    case '\t':
-      return "tabs are not allowed, use spaces";
-    }
-  }
-  return "lexing error";
-}
-
-void Lexer::UnreadToken() {
-  ofs_ = last_token_;
-}
-
-Lexer::Token Lexer::ReadToken() {
-  const char* p = ofs_;
-  const char* q;
-  const char* start;
-  Lexer::Token token;
-  for (;;) {
-    start = p;
-    /*!re2c
-    re2c:define:YYCTYPE = "unsigned char";
-    re2c:define:YYCURSOR = p;
-    re2c:define:YYMARKER = q;
-    re2c:yyfill:enable = 0;
-
-    nul = "\000";
-    simple_varname = [a-zA-Z0-9_-]+;
-    varname = [a-zA-Z0-9_.-]+;
-
-    [ ]*"#"[^\000\n]*"\n" { continue; }
-    [ ]*"\r\n" { token = NEWLINE;  break; }
-    [ ]*"\n"   { token = NEWLINE;  break; }
-    [ ]+       { token = INDENT;   break; }
-    "build"    { token = BUILD;    break; }
-    "pool"     { token = POOL;     break; }
-    "rule"     { token = RULE;     break; }
-    "default"  { token = DEFAULT;  break; }
-    "="        { token = EQUALS;   break; }
-    ":"        { token = COLON;    break; }
-    "|@"       { token = PIPEAT;   break; }
-    "||"       { token = PIPE2;    break; }
-    "|"        { token = PIPE;     break; }
-    "include"  { token = INCLUDE;  break; }
-    "subninja" { token = SUBNINJA; break; }
-    varname    { token = IDENT;    break; }
-    nul        { token = TEOF;     break; }
-    [^]        { token = ERROR;    break; }
-    */
-  }
-
-  last_token_ = start;
-  ofs_ = p;
-  if (token != NEWLINE && token != TEOF)
-    EatWhitespace();
-  return token;
-}
-
-bool Lexer::PeekToken(Token token) {
-  Token t = ReadToken();
-  if (t == token)
-    return true;
-  UnreadToken();
-  return false;
-}
-
-void Lexer::EatWhitespace() {
-  const char* p = ofs_;
-  const char* q;
-  for (;;) {
-    ofs_ = p;
-    /*!re2c
-    [ ]+    { continue; }
-    "$\r\n" { continue; }
-    "$\n"   { continue; }
-    nul     { break; }
-    [^]     { break; }
-    */
-  }
-}
-
-bool Lexer::ReadIdent(string* out) {
-  const char* p = ofs_;
-  const char* start;
-  for (;;) {
-    start = p;
-    /*!re2c
-    varname {
-      out->assign(start, p - start);
-      break;
-    }
-    [^] {
-      last_token_ = start;
-      return false;
-    }
-    */
-  }
-  last_token_ = start;
-  ofs_ = p;
-  EatWhitespace();
-  return true;
-}
-
-bool Lexer::ReadEvalString(EvalString* eval, bool path, string* err) {
-  const char* p = ofs_;
-  const char* q;
-  const char* start;
-  for (;;) {
-    start = p;
-    /*!re2c
-    [^$ :\r\n|\000]+ {
-      eval->AddText(StringPiece(start, p - start));
-      continue;
-    }
-    "\r\n" {
-      if (path)
-        p = start;
-      break;
-    }
-    [ :|\n] {
-      if (path) {
-        p = start;
-        break;
-      } else {
-        if (*start == '\n')
-          break;
-        eval->AddText(StringPiece(start, 1));
-        continue;
-      }
-    }
-    "$$" {
-      eval->AddText(StringPiece("$", 1));
-      continue;
-    }
-    "$ " {
-      eval->AddText(StringPiece(" ", 1));
-      continue;
-    }
-    "$\r\n"[ ]* {
-      continue;
-    }
-    "$\n"[ ]* {
-      continue;
-    }
-    "${"varname"}" {
-      eval->AddSpecial(StringPiece(start + 2, p - start - 3));
-      continue;
-    }
-    "$"simple_varname {
-      eval->AddSpecial(StringPiece(start + 1, p - start - 1));
-      continue;
-    }
-    "$:" {
-      eval->AddText(StringPiece(":", 1));
-      continue;
-    }
-    "$". {
-      last_token_ = start;
-      return Error("bad $-escape (literal $ must be written as $$)", err);
-    }
-    nul {
-      last_token_ = start;
-      return Error("unexpected EOF", err);
-    }
-    [^] {
-      last_token_ = start;
-      return Error(DescribeLastError(), err);
-    }
-    */
-  }
-  last_token_ = start;
-  ofs_ = p;
-  if (path)
-    EatWhitespace();
-  // Non-path strings end in newlines, so there's no whitespace to eat.
-  return true;
-}
diff --git a/src/lexer_test.cc b/src/lexer_test.cc
deleted file mode 100644
index c5c416d..0000000
--- a/src/lexer_test.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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.
-
-#include "lexer.h"
-
-#include "eval_env.h"
-#include "test.h"
-
-using namespace std;
-
-TEST(Lexer, ReadVarValue) {
-  Lexer lexer("plain text $var $VaR ${x}\n");
-  EvalString eval;
-  string err;
-  EXPECT_TRUE(lexer.ReadVarValue(&eval, &err));
-  EXPECT_EQ("", err);
-  EXPECT_EQ("[plain text ][$var][ ][$VaR][ ][$x]",
-            eval.Serialize());
-}
-
-TEST(Lexer, ReadEvalStringEscapes) {
-  Lexer lexer("$ $$ab c$: $\ncde\n");
-  EvalString eval;
-  string err;
-  EXPECT_TRUE(lexer.ReadVarValue(&eval, &err));
-  EXPECT_EQ("", err);
-  EXPECT_EQ("[ $ab c: cde]",
-            eval.Serialize());
-}
-
-TEST(Lexer, ReadIdent) {
-  Lexer lexer("foo baR baz_123 foo-bar");
-  string ident;
-  EXPECT_TRUE(lexer.ReadIdent(&ident));
-  EXPECT_EQ("foo", ident);
-  EXPECT_TRUE(lexer.ReadIdent(&ident));
-  EXPECT_EQ("baR", ident);
-  EXPECT_TRUE(lexer.ReadIdent(&ident));
-  EXPECT_EQ("baz_123", ident);
-  EXPECT_TRUE(lexer.ReadIdent(&ident));
-  EXPECT_EQ("foo-bar", ident);
-}
-
-TEST(Lexer, ReadIdentCurlies) {
-  // Verify that ReadIdent includes dots in the name,
-  // but in an expansion $bar.dots stops at the dot.
-  Lexer lexer("foo.dots $bar.dots ${bar.dots}\n");
-  string ident;
-  EXPECT_TRUE(lexer.ReadIdent(&ident));
-  EXPECT_EQ("foo.dots", ident);
-
-  EvalString eval;
-  string err;
-  EXPECT_TRUE(lexer.ReadVarValue(&eval, &err));
-  EXPECT_EQ("", err);
-  EXPECT_EQ("[$bar][.dots ][$bar.dots]",
-            eval.Serialize());
-}
-
-TEST(Lexer, Error) {
-  Lexer lexer("foo$\nbad $");
-  EvalString eval;
-  string err;
-  ASSERT_FALSE(lexer.ReadVarValue(&eval, &err));
-  EXPECT_EQ("input:2: bad $-escape (literal $ must be written as $$)\n"
-            "bad $\n"
-            "    ^ near here"
-            , err);
-}
-
-TEST(Lexer, CommentEOF) {
-  // Verify we don't run off the end of the string when the EOF is
-  // mid-comment.
-  Lexer lexer("# foo");
-  Lexer::Token token = lexer.ReadToken();
-  EXPECT_EQ(Lexer::ERROR, token);
-}
-
-TEST(Lexer, Tabs) {
-  // Verify we print a useful error on a disallowed character.
-  Lexer lexer("   \tfoobar");
-  Lexer::Token token = lexer.ReadToken();
-  EXPECT_EQ(Lexer::INDENT, token);
-  token = lexer.ReadToken();
-  EXPECT_EQ(Lexer::ERROR, token);
-  EXPECT_EQ("tabs are not allowed, use spaces", lexer.DescribeLastError());
-}
diff --git a/src/line_printer.cc b/src/line_printer.cc
deleted file mode 100644
index c883837..0000000
--- a/src/line_printer.cc
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright 2013 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 "line_printer.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifdef _WIN32
-#include <windows.h>
-#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
-#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4
-#endif
-#else
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <termios.h>
-#include <sys/time.h>
-#endif
-
-#include "util.h"
-
-using namespace std;
-
-LinePrinter::LinePrinter() {
-  Reset(getenv("TERM"), getenv("CLICOLOR_FORCE"));
-}
-
-void LinePrinter::Reset(const char* term, const char* clicolor_force) {
-  have_blank_line_ = true;
-  console_locked_ = false;
-  line_buffer_.clear();
-  output_buffer_.clear();
-  line_type_ = FULL;
-
-#ifndef _WIN32
-  smart_terminal_ = isatty(1) && term && string(term) != "dumb";
-#else
-  if (term && string(term) == "dumb") {
-    smart_terminal_ = false;
-  } else {
-    console_ = GetStdHandle(STD_OUTPUT_HANDLE);
-    CONSOLE_SCREEN_BUFFER_INFO csbi;
-    smart_terminal_ = GetConsoleScreenBufferInfo(console_, &csbi);
-  }
-#endif
-  supports_color_ = smart_terminal_;
-#ifdef _WIN32
-  // Try enabling ANSI escape sequence support on Windows 10 terminals.
-  if (supports_color_) {
-    DWORD mode;
-    if (GetConsoleMode(console_, &mode)) {
-      if (!SetConsoleMode(console_, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
-        supports_color_ = false;
-      }
-    }
-  }
-#endif
-  if (!supports_color_) {
-    supports_color_ = clicolor_force && std::string(clicolor_force) != "0";
-  }
-}
-
-void LinePrinter::Print(string to_print, LineType type) {
-  if (console_locked_) {
-    line_buffer_ = to_print;
-    line_type_ = type;
-    return;
-  }
-
-  if (smart_terminal_) {
-    printf("\r");  // Print over previous line, if any.
-    // On Windows, calling a C library function writing to stdout also handles
-    // pausing the executable when the "Pause" key or Ctrl-S is pressed.
-  }
-
-  if (smart_terminal_ && type == ELIDE) {
-#ifdef _WIN32
-    CONSOLE_SCREEN_BUFFER_INFO csbi;
-    GetConsoleScreenBufferInfo(console_, &csbi);
-
-    to_print = ElideMiddle(to_print, static_cast<size_t>(csbi.dwSize.X));
-    if (supports_color_) {  // this means ENABLE_VIRTUAL_TERMINAL_PROCESSING
-                            // succeeded
-      printf("%s\x1B[K", to_print.c_str());  // Clear to end of line.
-      fflush(stdout);
-    } else {
-      // We don't want to have the cursor spamming back and forth, so instead of
-      // printf use WriteConsoleOutput which updates the contents of the buffer,
-      // but doesn't move the cursor position.
-      COORD buf_size = { csbi.dwSize.X, 1 };
-      COORD zero_zero = { 0, 0 };
-      SMALL_RECT target = { csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y,
-                            static_cast<SHORT>(csbi.dwCursorPosition.X +
-                                               csbi.dwSize.X - 1),
-                            csbi.dwCursorPosition.Y };
-      vector<CHAR_INFO> char_data(csbi.dwSize.X);
-      for (size_t i = 0; i < static_cast<size_t>(csbi.dwSize.X); ++i) {
-        char_data[i].Char.AsciiChar = i < to_print.size() ? to_print[i] : ' ';
-        char_data[i].Attributes = csbi.wAttributes;
-      }
-      WriteConsoleOutput(console_, &char_data[0], buf_size, zero_zero, &target);
-    }
-#else
-    // Limit output to width of the terminal if provided so we don't cause
-    // line-wrapping.
-    winsize size;
-    if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) == 0) && size.ws_col) {
-      to_print = ElideMiddle(to_print, size.ws_col);
-    }
-    printf("%s", to_print.c_str());
-    printf("\x1B[K");  // Clear to end of line.
-    fflush(stdout);
-#endif
-
-    have_blank_line_ = false;
-  } else {
-    printf("%s\n", to_print.c_str());
-    fflush(stdout);
-  }
-}
-
-void LinePrinter::PrintOrBuffer(const char* data, size_t size) {
-  if (console_locked_) {
-    output_buffer_.append(data, size);
-  } else {
-    // Avoid printf and C strings, since the actual output might contain null
-    // bytes like UTF-16 does (yuck).
-    fwrite(data, 1, size, stdout);
-  }
-}
-
-void LinePrinter::PrintOnNewLine(const string& to_print) {
-  if (console_locked_ && !line_buffer_.empty()) {
-    output_buffer_.append(line_buffer_);
-    output_buffer_.append(1, '\n');
-    line_buffer_.clear();
-  }
-  if (!have_blank_line_) {
-    PrintOrBuffer("\n", 1);
-  }
-  if (!to_print.empty()) {
-    PrintOrBuffer(&to_print[0], to_print.size());
-  }
-  have_blank_line_ = to_print.empty() || *to_print.rbegin() == '\n';
-}
-
-void LinePrinter::SetConsoleLocked(bool locked) {
-  if (locked == console_locked_)
-    return;
-
-  if (locked)
-    PrintOnNewLine("");
-
-  console_locked_ = locked;
-
-  if (!locked) {
-    PrintOnNewLine(output_buffer_);
-    if (!line_buffer_.empty()) {
-      Print(line_buffer_, line_type_);
-    }
-    output_buffer_.clear();
-    line_buffer_.clear();
-  }
-}
diff --git a/src/line_printer.h b/src/line_printer.h
deleted file mode 100644
index 60e1450..0000000
--- a/src/line_printer.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2013 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_LINE_PRINTER_H_
-#define NINJA_LINE_PRINTER_H_
-
-#include <stddef.h>
-#include <string>
-
-/// Prints lines of text, possibly overprinting previously printed lines
-/// if the terminal supports it.
-struct LinePrinter {
-  LinePrinter();
-
-  bool is_smart_terminal() const { return smart_terminal_; }
-  void set_smart_terminal(bool smart) { smart_terminal_ = smart; }
-
-  bool supports_color() const { return supports_color_; }
-
-  enum LineType {
-    FULL,
-    ELIDE
-  };
-  /// Overprints the current line. If type is ELIDE, elides to_print to fit on
-  /// one line.
-  void Print(std::string to_print, LineType type);
-
-  /// Prints a string on a new line, not overprinting previous output.
-  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.
-  void SetConsoleLocked(bool locked);
-
-  /// Reset LinePrinter instance, re-reading environment variables and other
-  /// console seettings to adapt to changes during incremental builds.
-  /// |term| is the value of the TERM environment variable, or NULL if not
-  /// defined, and |clicolor_force| is the value of the CLICOLOR_FORCE
-  /// environment variable if define, or NULL otherwise.
-  void Reset(const char* term, const char* clicolor_force);
-
- private:
-  /// Whether we can do fancy terminal control codes.
-  bool smart_terminal_;
-
-  /// Whether we can use ISO 6429 (ANSI) color sequences.
-  bool supports_color_;
-
-  /// Whether the caret is at the beginning of a blank line.
-  bool have_blank_line_;
-
-  /// Whether console is locked.
-  bool console_locked_;
-
-  /// Buffered current line while console is locked.
-  std::string line_buffer_;
-
-  /// Buffered line type while console is locked.
-  LineType line_type_;
-
-  /// Buffered console output while console is locked.
-  std::string output_buffer_;
-
-#ifdef _WIN32
-  void* console_;
-#endif
-
-  /// Print the given data to the console, or buffer it if it is locked.
-  void PrintOrBuffer(const char *data, size_t size);
-};
-
-#endif  // NINJA_LINE_PRINTER_H_
diff --git a/src/load_status.h b/src/load_status.h
deleted file mode 100644
index 0b16b1a..0000000
--- a/src/load_status.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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
deleted file mode 100644
index c90b9b6..0000000
--- a/src/manifest_parser.cc
+++ /dev/null
@@ -1,447 +0,0 @@
-// 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.
-
-#include "manifest_parser.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <vector>
-
-#include "graph.h"
-#include "state.h"
-#include "util.h"
-#include "version.h"
-
-using namespace std;
-
-ManifestParser::ManifestParser(State* state, FileReader* file_reader,
-                               ManifestParserOptions options)
-    : Parser(state, file_reader),
-      options_(options), quiet_(false) {
-  env_ = &state->bindings();
-}
-
-bool ManifestParser::Parse(const string& filename, const string& input,
-                           string* err) {
-  lexer_.Start(filename, input);
-
-  for (;;) {
-    Lexer::Token token = lexer_.ReadToken();
-    switch (token) {
-    case Lexer::POOL:
-      if (!ParsePool(err))
-        return false;
-      break;
-    case Lexer::BUILD:
-      if (!ParseEdge(err))
-        return false;
-      break;
-    case Lexer::RULE:
-      if (!ParseRule(err))
-        return false;
-      break;
-    case Lexer::DEFAULT:
-      if (!ParseDefault(err))
-        return false;
-      break;
-    case Lexer::IDENT: {
-      lexer_.UnreadToken();
-      string name;
-      EvalString let_value;
-      if (!ParseLet(&name, &let_value, err))
-        return false;
-      string value = let_value.Evaluate(env_);
-      // Check ninja_required_version immediately so we can exit
-      // before encountering any syntactic surprises.
-      if (name == "ninja_required_version")
-        CheckNinjaVersion(value);
-      env_->AddBinding(name, value);
-      break;
-    }
-    case Lexer::INCLUDE:
-      if (!ParseFileInclude(false, err))
-        return false;
-      break;
-    case Lexer::SUBNINJA:
-      if (!ParseFileInclude(true, err))
-        return false;
-      break;
-    case Lexer::ERROR: {
-      return lexer_.Error(lexer_.DescribeLastError(), err);
-    }
-    case Lexer::TEOF:
-      return true;
-    case Lexer::NEWLINE:
-      break;
-    default:
-      return lexer_.Error(string("unexpected ") + Lexer::TokenName(token),
-                          err);
-    }
-  }
-  return false;  // not reached
-}
-
-
-bool ManifestParser::ParsePool(string* err) {
-  string name;
-  if (!lexer_.ReadIdent(&name))
-    return lexer_.Error("expected pool name", err);
-
-  if (!ExpectToken(Lexer::NEWLINE, err))
-    return false;
-
-  if (state_->LookupPool(name) != NULL)
-    return lexer_.Error("duplicate pool '" + name + "'", err);
-
-  int depth = -1;
-
-  while (lexer_.PeekToken(Lexer::INDENT)) {
-    string key;
-    EvalString value;
-    if (!ParseLet(&key, &value, err))
-      return false;
-
-    if (key == "depth") {
-      string depth_string = value.Evaluate(env_);
-      depth = atol(depth_string.c_str());
-      if (depth < 0)
-        return lexer_.Error("invalid pool depth", err);
-    } else {
-      return lexer_.Error("unexpected variable '" + key + "'", err);
-    }
-  }
-
-  if (depth < 0)
-    return lexer_.Error("expected 'depth =' line", err);
-
-  state_->AddPool(new Pool(name, depth));
-  return true;
-}
-
-
-bool ManifestParser::ParseRule(string* err) {
-  string name;
-  if (!lexer_.ReadIdent(&name))
-    return lexer_.Error("expected rule name", err);
-
-  if (!ExpectToken(Lexer::NEWLINE, err))
-    return false;
-
-  if (env_->LookupRuleCurrentScope(name) != NULL)
-    return lexer_.Error("duplicate rule '" + name + "'", err);
-
-  auto rule = std::unique_ptr<Rule>(new Rule(name));
-
-  while (lexer_.PeekToken(Lexer::INDENT)) {
-    string key;
-    EvalString value;
-    if (!ParseLet(&key, &value, err))
-      return false;
-
-    if (Rule::IsReservedBinding(key)) {
-      rule->AddBinding(key, value);
-    } else {
-      // Die on other keyvals for now; revisit if we want to add a
-      // scope here.
-      return lexer_.Error("unexpected variable '" + key + "'", err);
-    }
-  }
-
-  if (rule->bindings_["rspfile"].empty() !=
-      rule->bindings_["rspfile_content"].empty()) {
-    return lexer_.Error("rspfile and rspfile_content need to be "
-                        "both specified", err);
-  }
-
-  if (rule->bindings_["command"].empty())
-    return lexer_.Error("expected 'command =' line", err);
-
-  env_->AddRule(rule.release());
-  return true;
-}
-
-bool ManifestParser::ParseLet(string* key, EvalString* value, string* err) {
-  if (!lexer_.ReadIdent(key))
-    return lexer_.Error("expected variable name", err);
-  if (!ExpectToken(Lexer::EQUALS, err))
-    return false;
-  if (!lexer_.ReadVarValue(value, err))
-    return false;
-  return true;
-}
-
-bool ManifestParser::ParseDefault(string* err) {
-  EvalString eval;
-  if (!lexer_.ReadPath(&eval, err))
-    return false;
-  if (eval.empty())
-    return lexer_.Error("expected target name", err);
-
-  do {
-    string path = eval.Evaluate(env_);
-    if (path.empty())
-      return lexer_.Error("empty path", err);
-    uint64_t slash_bits;  // Unused because this only does lookup.
-    CanonicalizePath(&path, &slash_bits);
-    std::string default_err;
-    if (!state_->AddDefault(path, &default_err))
-      return lexer_.Error(default_err, err);
-
-    eval.Clear();
-    if (!lexer_.ReadPath(&eval, err))
-      return false;
-  } while (!eval.empty());
-
-  return ExpectToken(Lexer::NEWLINE, err);
-}
-
-bool ManifestParser::ParseEdge(string* err) {
-  vector<EvalString> ins, outs, validations;
-
-  {
-    EvalString out;
-    if (!lexer_.ReadPath(&out, err))
-      return false;
-    while (!out.empty()) {
-      outs.push_back(out);
-
-      out.Clear();
-      if (!lexer_.ReadPath(&out, err))
-        return false;
-    }
-  }
-
-  // Add all implicit outs, counting how many as we go.
-  int implicit_outs = 0;
-  if (lexer_.PeekToken(Lexer::PIPE)) {
-    for (;;) {
-      EvalString out;
-      if (!lexer_.ReadPath(&out, err))
-        return false;
-      if (out.empty())
-        break;
-      outs.push_back(out);
-      ++implicit_outs;
-    }
-  }
-
-  if (outs.empty())
-    return lexer_.Error("expected path", err);
-
-  if (!ExpectToken(Lexer::COLON, err))
-    return false;
-
-  string rule_name;
-  if (!lexer_.ReadIdent(&rule_name))
-    return lexer_.Error("expected build command name", err);
-
-  const Rule* rule = env_->LookupRule(rule_name);
-  if (!rule)
-    return lexer_.Error("unknown build rule '" + rule_name + "'", err);
-
-  for (;;) {
-    // XXX should we require one path here?
-    EvalString in;
-    if (!lexer_.ReadPath(&in, err))
-      return false;
-    if (in.empty())
-      break;
-    ins.push_back(in);
-  }
-
-  // Add all implicit deps, counting how many as we go.
-  int implicit = 0;
-  if (lexer_.PeekToken(Lexer::PIPE)) {
-    for (;;) {
-      EvalString in;
-      if (!lexer_.ReadPath(&in, err))
-        return false;
-      if (in.empty())
-        break;
-      ins.push_back(in);
-      ++implicit;
-    }
-  }
-
-  // Add all order-only deps, counting how many as we go.
-  int order_only = 0;
-  if (lexer_.PeekToken(Lexer::PIPE2)) {
-    for (;;) {
-      EvalString in;
-      if (!lexer_.ReadPath(&in, err))
-        return false;
-      if (in.empty())
-        break;
-      ins.push_back(in);
-      ++order_only;
-    }
-  }
-
-  // Add all validations, counting how many as we go.
-  if (lexer_.PeekToken(Lexer::PIPEAT)) {
-    for (;;) {
-      EvalString validation;
-      if (!lexer_.ReadPath(&validation, err))
-        return false;
-      if (validation.empty())
-        break;
-      validations.push_back(validation);
-    }
-  }
-
-  if (!ExpectToken(Lexer::NEWLINE, err))
-    return false;
-
-  // Bindings on edges are rare, so allocate per-edge envs only when needed.
-  bool has_indent_token = lexer_.PeekToken(Lexer::INDENT);
-  BindingEnv* env = has_indent_token ? state_->CreateNewEnv(env_) : env_;
-  while (has_indent_token) {
-    string key;
-    EvalString val;
-    if (!ParseLet(&key, &val, err))
-      return false;
-
-    env->AddBinding(key, val.Evaluate(env_));
-    has_indent_token = lexer_.PeekToken(Lexer::INDENT);
-  }
-
-  Edge* edge = state_->AddEdge(rule);
-  edge->env_ = env;
-
-  string pool_name = edge->GetBinding("pool");
-  if (!pool_name.empty()) {
-    Pool* pool = state_->LookupPool(pool_name);
-    if (pool == NULL)
-      return lexer_.Error("unknown pool name '" + pool_name + "'", err);
-    edge->pool_ = pool;
-  }
-
-  edge->outputs_.reserve(outs.size());
-  for (size_t i = 0, e = outs.size(); i != e; ++i) {
-    string path = outs[i].Evaluate(env);
-    if (path.empty())
-      return lexer_.Error("empty path", err);
-    uint64_t slash_bits;
-    CanonicalizePath(&path, &slash_bits);
-    if (!state_->AddOut(edge, path, slash_bits)) {
-      if (options_.dupe_edge_action_ == kDupeEdgeActionError) {
-        lexer_.Error("multiple rules generate " + path, err);
-        return false;
-      } else {
-        if (!quiet_) {
-          Warning(
-              "multiple rules generate %s. builds involving this target will "
-              "not be correct; continuing anyway",
-              path.c_str());
-        }
-        if (e - i <= static_cast<size_t>(implicit_outs))
-          --implicit_outs;
-      }
-    }
-  }
-
-  if (edge->outputs_.empty()) {
-    // All outputs of the edge are already created by other edges. Don't add
-    // this edge.  Do this check before input nodes are connected to the edge.
-    state_->edges_.pop_back();
-    delete edge;
-    return true;
-  }
-  edge->static_implicit_outs_ = edge->implicit_outs_ = implicit_outs;
-
-  edge->inputs_.reserve(ins.size());
-  for (vector<EvalString>::iterator i = ins.begin(); i != ins.end(); ++i) {
-    string path = i->Evaluate(env);
-    if (path.empty())
-      return lexer_.Error("empty path", err);
-    uint64_t slash_bits;
-    CanonicalizePath(&path, &slash_bits);
-    state_->AddIn(edge, path, slash_bits);
-  }
-  edge->static_implicit_deps_ = edge->implicit_deps_ = implicit;
-  edge->order_only_deps_ = order_only;
-
-  edge->validations_.reserve(validations.size());
-  for (std::vector<EvalString>::iterator v = validations.begin();
-      v != validations.end(); ++v) {
-    string path = v->Evaluate(env);
-    if (path.empty())
-      return lexer_.Error("empty path", err);
-    uint64_t slash_bits;
-    CanonicalizePath(&path, &slash_bits);
-    state_->AddValidation(edge, path, slash_bits);
-  }
-
-  if (options_.phony_cycle_action_ == kPhonyCycleActionWarn &&
-      edge->maybe_phonycycle_diagnostic()) {
-    // CMake 2.8.12.x and 3.0.x incorrectly write phony build statements
-    // that reference themselves.  Ninja used to tolerate these in the
-    // build graph but that has since been fixed.  Filter them out to
-    // support users of those old CMake versions.
-    Node* out = edge->outputs_[0];
-    vector<Node*>::iterator new_end =
-        remove(edge->inputs_.begin(), edge->inputs_.end(), out);
-    if (new_end != edge->inputs_.end()) {
-      edge->inputs_.erase(new_end, edge->inputs_.end());
-      if (!quiet_) {
-        Warning("phony target '%s' names itself as an input; "
-                "ignoring [-w phonycycle=warn]",
-                out->path().c_str());
-      }
-    }
-  }
-
-  // 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.
-  string dyndep = edge->GetUnescapedDyndep();
-  if (!dyndep.empty()) {
-    uint64_t slash_bits;
-    CanonicalizePath(&dyndep, &slash_bits);
-    edge->dyndep_ = state_->GetNode(dyndep, slash_bits);
-    edge->dyndep_->set_dyndep_pending(true);
-    vector<Node*>::iterator dgi =
-      std::find(edge->inputs_.begin(), edge->inputs_.end(), edge->dyndep_);
-    if (dgi == edge->inputs_.end()) {
-      return lexer_.Error("dyndep '" + dyndep + "' is not an input", err);
-    }
-    assert(!edge->dyndep_->generated_by_dep_loader());
-  }
-
-  return true;
-}
-
-bool ManifestParser::ParseFileInclude(bool new_scope, string* err) {
-  EvalString eval;
-  if (!lexer_.ReadPath(&eval, err))
-    return false;
-  string path = eval.Evaluate(env_);
-
-  ManifestParser subparser(state_, file_reader_, options_);
-  if (new_scope) {
-    subparser.env_ = state_->CreateNewEnv(env_);
-  } else {
-    subparser.env_ = env_;
-  }
-
-  if (!subparser.Load(path, err, &lexer_))
-    return false;
-
-  if (!ExpectToken(Lexer::NEWLINE, err))
-    return false;
-
-  return true;
-}
diff --git a/src/manifest_parser.h b/src/manifest_parser.h
deleted file mode 100644
index 954cf46..0000000
--- a/src/manifest_parser.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.
-
-#ifndef NINJA_MANIFEST_PARSER_H_
-#define NINJA_MANIFEST_PARSER_H_
-
-#include "parser.h"
-
-struct BindingEnv;
-struct EvalString;
-
-enum DupeEdgeAction {
-  kDupeEdgeActionWarn,
-  kDupeEdgeActionError,
-};
-
-enum PhonyCycleAction {
-  kPhonyCycleActionWarn,
-  kPhonyCycleActionError,
-};
-
-struct ManifestParserOptions {
-  ManifestParserOptions()
-      : dupe_edge_action_(kDupeEdgeActionWarn),
-        phony_cycle_action_(kPhonyCycleActionWarn) {}
-  DupeEdgeAction dupe_edge_action_;
-  PhonyCycleAction phony_cycle_action_;
-};
-
-/// Parses .ninja files.
-struct ManifestParser : public Parser {
-  ManifestParser(State* state, FileReader* file_reader,
-                 ManifestParserOptions options = ManifestParserOptions());
-
-  /// Parse a text string of input.  Used by tests.
-  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 std::string& filename, const std::string& input,
-             std::string* err);
-
-  /// Parse various statement types.
-  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, std::string* err);
-
-  BindingEnv* env_;
-  ManifestParserOptions options_;
-  bool quiet_;
-};
-
-#endif  // NINJA_MANIFEST_PARSER_H_
diff --git a/src/manifest_parser_perftest.cc b/src/manifest_parser_perftest.cc
deleted file mode 100644
index fb1dbbf..0000000
--- a/src/manifest_parser_perftest.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2014 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.
-
-// Tests manifest parser performance.  Expects to be run in ninja's root
-// directory.
-
-#include <numeric>
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef _WIN32
-#include "getopt.h"
-#include <direct.h>
-#elif defined(_AIX)
-#include "getopt.h"
-#include <unistd.h>
-#else
-#include <getopt.h>
-#include <unistd.h>
-#endif
-
-#include "disk_interface.h"
-#include "graph.h"
-#include "manifest_parser.h"
-#include "metrics.h"
-#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);
-  if (mtime != 0)  // 0 means that the file doesn't exist yet.
-    return mtime != -1;
-
-  string command = "python misc/write_fake_manifests.py " + dir;
-  printf("Creating manifest data..."); fflush(stdout);
-  int exit_code = system(command.c_str());
-  printf("done.\n");
-  if (exit_code != 0)
-    *err = "Failed to run " + command;
-  return exit_code == 0;
-}
-
-int LoadManifests(bool measure_command_evaluation) {
-  string err;
-  RealDiskInterface disk_interface;
-  State state;
-  ManifestParser parser(&state, &disk_interface);
-  if (!parser.Load("build.ninja", &err)) {
-    fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
-    exit(1);
-  }
-  // Doing an empty build involves reading the manifest and evaluating all
-  // commands required for the requested targets. So include command
-  // evaluation in the perftest by default.
-  int optimization_guard = 0;
-  if (measure_command_evaluation)
-    for (size_t i = 0; i < state.edges_.size(); ++i)
-      optimization_guard += state.edges_[i]->EvaluateCommand().size();
-  return optimization_guard;
-}
-
-int main(int argc, char* argv[]) {
-  bool measure_command_evaluation = true;
-  int opt;
-  while ((opt = getopt(argc, argv, const_cast<char*>("fh"))) != -1) {
-    switch (opt) {
-    case 'f':
-      measure_command_evaluation = false;
-      break;
-    case 'h':
-    default:
-      printf("usage: manifest_parser_perftest\n"
-"\n"
-"options:\n"
-"  -f     only measure manifest load time, not command evaluation time\n"
-             );
-    return 1;
-    }
-  }
-
-  const char kManifestDir[] = "build/manifest_perftest";
-
-  string err;
-  if (!WriteFakeManifests(kManifestDir, &err)) {
-    fprintf(stderr, "Failed to write test data: %s\n", err.c_str());
-    return 1;
-  }
-
-  if (chdir(kManifestDir) < 0)
-    ErrnoFatal("chdir");
-
-  const int kNumRepetitions = 5;
-  vector<int> times;
-  for (int i = 0; i < kNumRepetitions; ++i) {
-    int64_t start = GetTimeMillis();
-    int optimization_guard = LoadManifests(measure_command_evaluation);
-    int delta = (int)(GetTimeMillis() - start);
-    printf("%dms (hash: %x)\n", delta, optimization_guard);
-    times.push_back(delta);
-  }
-
-  int min = *min_element(times.begin(), times.end());
-  int max = *max_element(times.begin(), times.end());
-  float total = accumulate(times.begin(), times.end(), 0.0f);
-  printf("min %dms  max %dms  avg %.1fms\n", min, max, total / times.size());
-}
diff --git a/src/manifest_parser_test.cc b/src/manifest_parser_test.cc
deleted file mode 100644
index b286d85..0000000
--- a/src/manifest_parser_test.cc
+++ /dev/null
@@ -1,1167 +0,0 @@
-// 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.
-
-#include "manifest_parser.h"
-
-#include <map>
-#include <vector>
-
-#include "graph.h"
-#include "state.h"
-#include "test.h"
-
-using namespace std;
-
-struct ParserTest : public testing::Test {
-  void AssertParse(const char* input) {
-    ManifestParser parser(&state, &fs_);
-    string err;
-    EXPECT_TRUE(parser.ParseTest(input, &err));
-    ASSERT_EQ("", err);
-    VerifyGraph(state);
-  }
-
-  State state;
-  VirtualFileSystem fs_;
-};
-
-TEST_F(ParserTest, Empty) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(""));
-}
-
-TEST_F(ParserTest, Rules) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"\n"
-"rule date\n"
-"  command = date > $out\n"
-"\n"
-"build result: cat in_1.cc in-2.O\n"));
-
-  ASSERT_EQ(3u, state.bindings().GetRules().size());
-  const Rule* rule = state.bindings().GetRules().begin()->second.get();
-  EXPECT_EQ("cat", rule->name());
-  EXPECT_EQ("[cat ][$in][ > ][$out]",
-            rule->GetBinding("command")->Serialize());
-}
-
-TEST_F(ParserTest, RuleAttributes) {
-  // Check that all of the allowed rule attributes are parsed ok.
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = a\n"
-"  depfile = a\n"
-"  deps = a\n"
-"  description = a\n"
-"  generator = a\n"
-"  restat = a\n"
-"  rspfile = a\n"
-"  rspfile_content = a\n"
-));
-}
-
-TEST_F(ParserTest, IgnoreIndentedComments) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"  #indented comment\n"
-"rule cat\n"
-"  command = cat $in > $out\n"
-"  #generator = 1\n"
-"  restat = 1 # comment\n"
-"  #comment\n"
-"build result: cat in_1.cc in-2.O\n"
-"  #comment\n"));
-
-  ASSERT_EQ(2u, state.bindings().GetRules().size());
-  const Rule* rule = state.bindings().GetRules().begin()->second.get();
-  EXPECT_EQ("cat", rule->name());
-  Edge* edge = state.GetNode("result", 0)->in_edge();
-  EXPECT_TRUE(edge->GetBindingBool("restat"));
-  EXPECT_FALSE(edge->GetBindingBool("generator"));
-}
-
-TEST_F(ParserTest, IgnoreIndentedBlankLines) {
-  // the indented blanks used to cause parse errors
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"  \n"
-"rule cat\n"
-"  command = cat $in > $out\n"
-"  \n"
-"build result: cat in_1.cc in-2.O\n"
-"  \n"
-"variable=1\n"));
-
-  // the variable must be in the top level environment
-  EXPECT_EQ("1", state.bindings().LookupVariable("variable"));
-}
-
-TEST_F(ParserTest, ResponseFiles) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat_rsp\n"
-"  command = cat $rspfile > $out\n"
-"  rspfile = $rspfile\n"
-"  rspfile_content = $in\n"
-"\n"
-"build out: cat_rsp in\n"
-"  rspfile=out.rsp\n"));
-
-  ASSERT_EQ(2u, state.bindings().GetRules().size());
-  const Rule* rule = state.bindings().GetRules().begin()->second.get();
-  EXPECT_EQ("cat_rsp", rule->name());
-  EXPECT_EQ("[cat ][$rspfile][ > ][$out]",
-            rule->GetBinding("command")->Serialize());
-  EXPECT_EQ("[$rspfile]", rule->GetBinding("rspfile")->Serialize());
-  EXPECT_EQ("[$in]", rule->GetBinding("rspfile_content")->Serialize());
-}
-
-TEST_F(ParserTest, InNewline) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat_rsp\n"
-"  command = cat $in_newline > $out\n"
-"\n"
-"build out: cat_rsp in in2\n"
-"  rspfile=out.rsp\n"));
-
-  ASSERT_EQ(2u, state.bindings().GetRules().size());
-  const Rule* rule = state.bindings().GetRules().begin()->second.get();
-  EXPECT_EQ("cat_rsp", rule->name());
-  EXPECT_EQ("[cat ][$in_newline][ > ][$out]",
-            rule->GetBinding("command")->Serialize());
-
-  Edge* edge = state.edges_[0];
-  EXPECT_EQ("cat in\nin2 > out", edge->EvaluateCommand());
-}
-
-TEST_F(ParserTest, Variables) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"l = one-letter-test\n"
-"rule link\n"
-"  command = ld $l $extra $with_under -o $out $in\n"
-"\n"
-"extra = -pthread\n"
-"with_under = -under\n"
-"build a: link b c\n"
-"nested1 = 1\n"
-"nested2 = $nested1/2\n"
-"build supernested: link x\n"
-"  extra = $nested2/3\n"));
-
-  ASSERT_EQ(2u, state.edges_.size());
-  Edge* edge = state.edges_[0];
-  EXPECT_EQ("ld one-letter-test -pthread -under -o a b c",
-            edge->EvaluateCommand());
-  EXPECT_EQ("1/2", state.bindings().LookupVariable("nested2"));
-
-  edge = state.edges_[1];
-  EXPECT_EQ("ld one-letter-test 1/2/3 -under -o supernested x",
-            edge->EvaluateCommand());
-}
-
-TEST_F(ParserTest, VariableScope) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"foo = bar\n"
-"rule cmd\n"
-"  command = cmd $foo $in $out\n"
-"\n"
-"build inner: cmd a\n"
-"  foo = baz\n"
-"build outer: cmd b\n"
-"\n"  // Extra newline after build line tickles a regression.
-));
-
-  ASSERT_EQ(2u, state.edges_.size());
-  EXPECT_EQ("cmd baz a inner", state.edges_[0]->EvaluateCommand());
-  EXPECT_EQ("cmd bar b outer", state.edges_[1]->EvaluateCommand());
-}
-
-TEST_F(ParserTest, Continuation) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule link\n"
-"  command = foo bar $\n"
-"    baz\n"
-"\n"
-"build a: link c $\n"
-" d e f\n"));
-
-  ASSERT_EQ(2u, state.bindings().GetRules().size());
-  const Rule* rule = state.bindings().GetRules().begin()->second.get();
-  EXPECT_EQ("link", rule->name());
-  EXPECT_EQ("[foo bar baz]", rule->GetBinding("command")->Serialize());
-}
-
-TEST_F(ParserTest, Backslash) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"foo = bar\\baz\n"
-"foo2 = bar\\ baz\n"
-));
-  EXPECT_EQ("bar\\baz", state.bindings().LookupVariable("foo"));
-  EXPECT_EQ("bar\\ baz", state.bindings().LookupVariable("foo2"));
-}
-
-TEST_F(ParserTest, Comment) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"# this is a comment\n"
-"foo = not # a comment\n"));
-  EXPECT_EQ("not # a comment", state.bindings().LookupVariable("foo"));
-}
-
-TEST_F(ParserTest, Dollars) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule foo\n"
-"  command = ${out}bar$$baz$$$\n"
-"blah\n"
-"x = $$dollar\n"
-"build $x: foo y\n"
-));
-  EXPECT_EQ("$dollar", state.bindings().LookupVariable("x"));
-#ifdef _WIN32
-  EXPECT_EQ("$dollarbar$baz$blah", state.edges_[0]->EvaluateCommand());
-#else
-  EXPECT_EQ("'$dollar'bar$baz$blah", state.edges_[0]->EvaluateCommand());
-#endif
-}
-
-TEST_F(ParserTest, EscapeSpaces) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule spaces\n"
-"  command = something\n"
-"build foo$ bar: spaces $$one two$$$ three\n"
-));
-  EXPECT_TRUE(state.LookupNode("foo bar"));
-  EXPECT_EQ(state.edges_[0]->outputs_[0]->path(), "foo bar");
-  EXPECT_EQ(state.edges_[0]->inputs_[0]->path(), "$one");
-  EXPECT_EQ(state.edges_[0]->inputs_[1]->path(), "two$ three");
-  EXPECT_EQ(state.edges_[0]->EvaluateCommand(), "something");
-}
-
-TEST_F(ParserTest, CanonicalizeFile) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build out: cat in/1 in//2\n"
-"build in/1: cat\n"
-"build in/2: cat\n"));
-
-  EXPECT_TRUE(state.LookupNode("in/1"));
-  EXPECT_TRUE(state.LookupNode("in/2"));
-  EXPECT_FALSE(state.LookupNode("in//1"));
-  EXPECT_FALSE(state.LookupNode("in//2"));
-}
-
-#ifdef _WIN32
-TEST_F(ParserTest, CanonicalizeFileBackslashes) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build out: cat in\\1 in\\\\2\n"
-"build in\\1: cat\n"
-"build in\\2: cat\n"));
-
-  Node* node = state.LookupNode("in/1");;
-  EXPECT_TRUE(node);
-  EXPECT_EQ(1, node->slash_bits());
-  node = state.LookupNode("in/2");
-  EXPECT_TRUE(node);
-  EXPECT_EQ(1, node->slash_bits());
-  EXPECT_FALSE(state.LookupNode("in//1"));
-  EXPECT_FALSE(state.LookupNode("in//2"));
-}
-#endif
-
-TEST_F(ParserTest, PathVariables) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"dir = out\n"
-"build $dir/exe: cat src\n"));
-
-  EXPECT_FALSE(state.LookupNode("$dir/exe"));
-  EXPECT_TRUE(state.LookupNode("out/exe"));
-}
-
-TEST_F(ParserTest, CanonicalizePaths) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build ./out.o: cat ./bar/baz/../foo.cc\n"));
-
-  EXPECT_FALSE(state.LookupNode("./out.o"));
-  EXPECT_TRUE(state.LookupNode("out.o"));
-  EXPECT_FALSE(state.LookupNode("./bar/baz/../foo.cc"));
-  EXPECT_TRUE(state.LookupNode("bar/foo.cc"));
-}
-
-#ifdef _WIN32
-TEST_F(ParserTest, CanonicalizePathsBackslashes) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build ./out.o: cat ./bar/baz/../foo.cc\n"
-"build .\\out2.o: cat .\\bar/baz\\..\\foo.cc\n"
-"build .\\out3.o: cat .\\bar\\baz\\..\\foo3.cc\n"
-));
-
-  EXPECT_FALSE(state.LookupNode("./out.o"));
-  EXPECT_FALSE(state.LookupNode(".\\out2.o"));
-  EXPECT_FALSE(state.LookupNode(".\\out3.o"));
-  EXPECT_TRUE(state.LookupNode("out.o"));
-  EXPECT_TRUE(state.LookupNode("out2.o"));
-  EXPECT_TRUE(state.LookupNode("out3.o"));
-  EXPECT_FALSE(state.LookupNode("./bar/baz/../foo.cc"));
-  EXPECT_FALSE(state.LookupNode(".\\bar/baz\\..\\foo.cc"));
-  EXPECT_FALSE(state.LookupNode(".\\bar/baz\\..\\foo3.cc"));
-  Node* node = state.LookupNode("bar/foo.cc");
-  EXPECT_TRUE(node);
-  EXPECT_EQ(0, node->slash_bits());
-  node = state.LookupNode("bar/foo3.cc");
-  EXPECT_TRUE(node);
-  EXPECT_EQ(1, node->slash_bits());
-}
-#endif
-
-TEST_F(ParserTest, DuplicateEdgeWithMultipleOutputs) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build out1 out2: cat in1\n"
-"build out1: cat in2\n"
-"build final: cat out1\n"
-));
-  // AssertParse() checks that the generated build graph is self-consistent.
-  // That's all the checking that this test needs.
-}
-
-TEST_F(ParserTest, NoDeadPointerFromDuplicateEdge) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build out: cat in\n"
-"build out: cat in\n"
-));
-  // AssertParse() checks that the generated build graph is self-consistent.
-  // That's all the checking that this test needs.
-}
-
-TEST_F(ParserTest, DuplicateEdgeWithMultipleOutputsError) {
-  const char kInput[] =
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build out1 out2: cat in1\n"
-"build out1: cat in2\n"
-"build final: cat out1\n";
-  ManifestParserOptions parser_opts;
-  parser_opts.dupe_edge_action_ = kDupeEdgeActionError;
-  ManifestParser parser(&state, &fs_, parser_opts);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("input:5: multiple rules generate out1\n", err);
-}
-
-TEST_F(ParserTest, DuplicateEdgeInIncludedFile) {
-  fs_.Create("sub.ninja",
-    "rule cat\n"
-    "  command = cat $in > $out\n"
-    "build out1 out2: cat in1\n"
-    "build out1: cat in2\n"
-    "build final: cat out1\n");
-  const char kInput[] =
-    "subninja sub.ninja\n";
-  ManifestParserOptions parser_opts;
-  parser_opts.dupe_edge_action_ = kDupeEdgeActionError;
-  ManifestParser parser(&state, &fs_, parser_opts);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("sub.ninja:5: multiple rules generate out1\n", err);
-}
-
-TEST_F(ParserTest, PhonySelfReferenceIgnored) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"build a: phony a\n"
-));
-
-  Node* node = state.LookupNode("a");
-  Edge* edge = node->in_edge();
-  ASSERT_TRUE(edge->inputs_.empty());
-}
-
-TEST_F(ParserTest, PhonySelfReferenceKept) {
-  const char kInput[] =
-"build a: phony a\n";
-  ManifestParserOptions parser_opts;
-  parser_opts.phony_cycle_action_ = kPhonyCycleActionError;
-  ManifestParser parser(&state, &fs_, parser_opts);
-  string err;
-  EXPECT_TRUE(parser.ParseTest(kInput, &err));
-  EXPECT_EQ("", err);
-
-  Node* node = state.LookupNode("a");
-  Edge* edge = node->in_edge();
-  ASSERT_EQ(edge->inputs_.size(), 1);
-  ASSERT_EQ(edge->inputs_[0], node);
-}
-
-TEST_F(ParserTest, ReservedWords) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule build\n"
-"  command = rule run $out\n"
-"build subninja: build include default foo.cc\n"
-"default subninja\n"));
-}
-
-TEST_F(ParserTest, Errors) {
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest(string("subn", 4), &err));
-    EXPECT_EQ("input:1: expected '=', got eof\n"
-              "subn\n"
-              "    ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("foobar", &err));
-    EXPECT_EQ("input:1: expected '=', got eof\n"
-              "foobar\n"
-              "      ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("x 3", &err));
-    EXPECT_EQ("input:1: expected '=', got identifier\n"
-              "x 3\n"
-              "  ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("x = 3", &err));
-    EXPECT_EQ("input:1: unexpected EOF\n"
-              "x = 3\n"
-              "     ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("x = 3\ny 2", &err));
-    EXPECT_EQ("input:2: expected '=', got identifier\n"
-              "y 2\n"
-              "  ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("x = $", &err));
-    EXPECT_EQ("input:1: bad $-escape (literal $ must be written as $$)\n"
-              "x = $\n"
-              "    ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("x = $\n $[\n", &err));
-    EXPECT_EQ("input:2: bad $-escape (literal $ must be written as $$)\n"
-              " $[\n"
-              " ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("x = a$\n b$\n $\n", &err));
-    EXPECT_EQ("input:4: unexpected EOF\n"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("build\n", &err));
-    EXPECT_EQ("input:1: expected path\n"
-              "build\n"
-              "     ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("build x: y z\n", &err));
-    EXPECT_EQ("input:1: unknown build rule 'y'\n"
-              "build x: y z\n"
-              "         ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("build x:: y z\n", &err));
-    EXPECT_EQ("input:1: expected build command name\n"
-              "build x:: y z\n"
-              "        ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule cat\n  command = cat ok\n"
-                                  "build x: cat $\n :\n",
-                                  &err));
-    EXPECT_EQ("input:4: expected newline, got ':'\n"
-              " :\n"
-              " ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule cat\n",
-                                  &err));
-    EXPECT_EQ("input:2: expected 'command =' line\n", err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule cat\n"
-                                  "  command = echo\n"
-                                  "rule cat\n"
-                                  "  command = echo\n", &err));
-    EXPECT_EQ("input:3: duplicate rule 'cat'\n"
-              "rule cat\n"
-              "        ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule cat\n"
-                                  "  command = echo\n"
-                                  "  rspfile = cat.rsp\n", &err));
-    EXPECT_EQ(
-        "input:4: rspfile and rspfile_content need to be both specified\n",
-        err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule cat\n"
-                                  "  command = ${fafsd\n"
-                                  "foo = bar\n",
-                                  &err));
-    EXPECT_EQ("input:2: bad $-escape (literal $ must be written as $$)\n"
-              "  command = ${fafsd\n"
-              "            ^ near here"
-              , err);
-  }
-
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule cat\n"
-                                  "  command = cat\n"
-                                  "build $.: cat foo\n",
-                                  &err));
-    EXPECT_EQ("input:3: bad $-escape (literal $ must be written as $$)\n"
-              "build $.: cat foo\n"
-              "      ^ near here"
-              , err);
-  }
-
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule cat\n"
-                                  "  command = cat\n"
-                                  "build $: cat foo\n",
-                                  &err));
-    EXPECT_EQ("input:3: expected ':', got newline ($ also escapes ':')\n"
-              "build $: cat foo\n"
-              "                ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule %foo\n",
-                                  &err));
-    EXPECT_EQ("input:1: expected rule name\n"
-              "rule %foo\n"
-              "     ^ near here",
-              err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule cc\n"
-                                  "  command = foo\n"
-                                  "  othervar = bar\n",
-                                  &err));
-    EXPECT_EQ("input:3: unexpected variable 'othervar'\n"
-              "  othervar = bar\n"
-              "                ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule cc\n  command = foo\n"
-                                  "build $.: cc bar.cc\n",
-                                  &err));
-    EXPECT_EQ("input:3: bad $-escape (literal $ must be written as $$)\n"
-              "build $.: cc bar.cc\n"
-              "      ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule cc\n  command = foo\n  && bar",
-                                  &err));
-    EXPECT_EQ("input:3: expected variable name\n"
-              "  && bar\n"
-              "  ^ near here",
-              err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule cc\n  command = foo\n"
-                                  "build $: cc bar.cc\n",
-                                  &err));
-    EXPECT_EQ("input:3: expected ':', got newline ($ also escapes ':')\n"
-              "build $: cc bar.cc\n"
-              "                  ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("default\n",
-                                  &err));
-    EXPECT_EQ("input:1: expected target name\n"
-              "default\n"
-              "       ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("default nonexistent\n",
-                                  &err));
-    EXPECT_EQ("input:1: unknown target 'nonexistent'\n"
-              "default nonexistent\n"
-              "                   ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule r\n  command = r\n"
-                                  "build b: r\n"
-                                  "default b:\n",
-                                  &err));
-    EXPECT_EQ("input:4: expected newline, got ':'\n"
-              "default b:\n"
-              "         ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("default $a\n", &err));
-    EXPECT_EQ("input:1: empty path\n"
-              "default $a\n"
-              "          ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("rule r\n"
-                                  "  command = r\n"
-                                  "build $a: r $c\n", &err));
-    // XXX the line number is wrong; we should evaluate paths in ParseEdge
-    // as we see them, not after we've read them all!
-    EXPECT_EQ("input:4: empty path\n", err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    // the indented blank line must terminate the rule
-    // this also verifies that "unexpected (token)" errors are correct
-    EXPECT_FALSE(parser.ParseTest("rule r\n"
-                                  "  command = r\n"
-                                  "  \n"
-                                  "  generator = 1\n", &err));
-    EXPECT_EQ("input:4: unexpected indent\n", err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("pool\n", &err));
-    EXPECT_EQ("input:1: expected pool name\n"
-              "pool\n"
-              "    ^ near here", err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("pool foo\n", &err));
-    EXPECT_EQ("input:2: expected 'depth =' line\n", err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("pool foo\n"
-                                  "  depth = 4\n"
-                                  "pool foo\n", &err));
-    EXPECT_EQ("input:3: duplicate pool 'foo'\n"
-              "pool foo\n"
-              "        ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("pool foo\n"
-                                  "  depth = -1\n", &err));
-    EXPECT_EQ("input:2: invalid pool depth\n"
-              "  depth = -1\n"
-              "            ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    EXPECT_FALSE(parser.ParseTest("pool foo\n"
-                                  "  bar = 1\n", &err));
-    EXPECT_EQ("input:2: unexpected variable 'bar'\n"
-              "  bar = 1\n"
-              "         ^ near here"
-              , err);
-  }
-
-  {
-    State local_state;
-    ManifestParser parser(&local_state, NULL);
-    string err;
-    // Pool names are dereferenced at edge parsing time.
-    EXPECT_FALSE(parser.ParseTest("rule run\n"
-                                  "  command = echo\n"
-                                  "  pool = unnamed_pool\n"
-                                  "build out: run in\n", &err));
-    EXPECT_EQ("input:5: unknown pool name 'unnamed_pool'\n", err);
-  }
-}
-
-TEST_F(ParserTest, MissingInput) {
-  State local_state;
-  ManifestParser parser(&local_state, &fs_);
-  string err;
-  EXPECT_FALSE(parser.Load("build.ninja", &err));
-  EXPECT_EQ("loading 'build.ninja': No such file or directory", err);
-}
-
-TEST_F(ParserTest, MultipleOutputs) {
-  State local_state;
-  ManifestParser parser(&local_state, NULL);
-  string err;
-  EXPECT_TRUE(parser.ParseTest("rule cc\n  command = foo\n  depfile = bar\n"
-                               "build a.o b.o: cc c.cc\n",
-                               &err));
-  EXPECT_EQ("", err);
-}
-
-TEST_F(ParserTest, MultipleOutputsWithDeps) {
-  State local_state;
-  ManifestParser parser(&local_state, NULL);
-  string err;
-  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("", err);
-}
-
-TEST_F(ParserTest, SubNinja) {
-  fs_.Create("test.ninja",
-    "var = inner\n"
-    "build $builddir/inner: varref\n");
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"builddir = some_dir/\n"
-"rule varref\n"
-"  command = varref $var\n"
-"var = outer\n"
-"build $builddir/outer: varref\n"
-"subninja test.ninja\n"
-"build $builddir/outer2: varref\n"));
-  ASSERT_EQ(1u, fs_.files_read_.size());
-
-  EXPECT_EQ("test.ninja", fs_.files_read_[0]);
-  EXPECT_TRUE(state.LookupNode("some_dir/outer"));
-  // Verify our builddir setting is inherited.
-  EXPECT_TRUE(state.LookupNode("some_dir/inner"));
-
-  ASSERT_EQ(3u, state.edges_.size());
-  EXPECT_EQ("varref outer", state.edges_[0]->EvaluateCommand());
-  EXPECT_EQ("varref inner", state.edges_[1]->EvaluateCommand());
-  EXPECT_EQ("varref outer", state.edges_[2]->EvaluateCommand());
-}
-
-TEST_F(ParserTest, MissingSubNinja) {
-  ManifestParser parser(&state, &fs_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest("subninja foo.ninja\n", &err));
-  EXPECT_EQ("input:1: loading 'foo.ninja': No such file or directory\n"
-            "subninja foo.ninja\n"
-            "                  ^ near here"
-            , err);
-}
-
-TEST_F(ParserTest, DuplicateRuleInDifferentSubninjas) {
-  // Test that rules are scoped to subninjas.
-  fs_.Create("test.ninja", "rule cat\n"
-                         "  command = cat\n");
-  ManifestParser parser(&state, &fs_);
-  string err;
-  EXPECT_TRUE(parser.ParseTest("rule cat\n"
-                                "  command = cat\n"
-                                "subninja test.ninja\n", &err));
-}
-
-TEST_F(ParserTest, DuplicateRuleInDifferentSubninjasWithInclude) {
-  // Test that rules are scoped to subninjas even with includes.
-  fs_.Create("rules.ninja", "rule cat\n"
-                         "  command = cat\n");
-  fs_.Create("test.ninja", "include rules.ninja\n"
-                         "build x : cat\n");
-  ManifestParser parser(&state, &fs_);
-  string err;
-  EXPECT_TRUE(parser.ParseTest("include rules.ninja\n"
-                                "subninja test.ninja\n"
-                                "build y : cat\n", &err));
-}
-
-TEST_F(ParserTest, Include) {
-  fs_.Create("include.ninja", "var = inner\n");
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"var = outer\n"
-"include include.ninja\n"));
-
-  ASSERT_EQ(1u, fs_.files_read_.size());
-  EXPECT_EQ("include.ninja", fs_.files_read_[0]);
-  EXPECT_EQ("inner", state.bindings().LookupVariable("var"));
-}
-
-TEST_F(ParserTest, BrokenInclude) {
-  fs_.Create("include.ninja", "build\n");
-  ManifestParser parser(&state, &fs_);
-  string err;
-  EXPECT_FALSE(parser.ParseTest("include include.ninja\n", &err));
-  EXPECT_EQ("include.ninja:1: expected path\n"
-            "build\n"
-            "     ^ near here"
-            , err);
-}
-
-TEST_F(ParserTest, Implicit) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build foo: cat bar | baz\n"));
-
-  Edge* edge = state.LookupNode("foo")->in_edge();
-  ASSERT_TRUE(edge->is_implicit(1));
-}
-
-TEST_F(ParserTest, OrderOnly) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n  command = cat $in > $out\n"
-"build foo: cat bar || baz\n"));
-
-  Edge* edge = state.LookupNode("foo")->in_edge();
-  ASSERT_TRUE(edge->is_order_only(1));
-}
-
-TEST_F(ParserTest, Validations) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n  command = cat $in > $out\n"
-"build foo: cat bar |@ baz\n"));
-
-  Edge* edge = state.LookupNode("foo")->in_edge();
-  ASSERT_EQ(edge->validations_.size(), 1);
-  EXPECT_EQ(edge->validations_[0]->path(), "baz");
-}
-
-TEST_F(ParserTest, ImplicitOutput) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build foo | imp: cat bar\n"));
-
-  Edge* edge = state.LookupNode("imp")->in_edge();
-  ASSERT_EQ(edge->outputs_.size(), 2);
-  EXPECT_TRUE(edge->is_implicit_out(1));
-}
-
-TEST_F(ParserTest, ImplicitOutputEmpty) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build foo | : cat bar\n"));
-
-  Edge* edge = state.LookupNode("foo")->in_edge();
-  ASSERT_EQ(edge->outputs_.size(), 1);
-  EXPECT_FALSE(edge->is_implicit_out(0));
-}
-
-TEST_F(ParserTest, ImplicitOutputDupe) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build foo baz | foo baq foo: cat bar\n"));
-
-  Edge* edge = state.LookupNode("foo")->in_edge();
-  ASSERT_EQ(edge->outputs_.size(), 3);
-  EXPECT_FALSE(edge->is_implicit_out(0));
-  EXPECT_FALSE(edge->is_implicit_out(1));
-  EXPECT_TRUE(edge->is_implicit_out(2));
-}
-
-TEST_F(ParserTest, ImplicitOutputDupes) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build foo foo foo | foo foo foo foo: cat bar\n"));
-
-  Edge* edge = state.LookupNode("foo")->in_edge();
-  ASSERT_EQ(edge->outputs_.size(), 1);
-  EXPECT_FALSE(edge->is_implicit_out(0));
-}
-
-TEST_F(ParserTest, NoExplicitOutput) {
-  ManifestParser parser(&state, NULL);
-  string err;
-  EXPECT_TRUE(parser.ParseTest(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build | imp : cat bar\n", &err));
-}
-
-TEST_F(ParserTest, DefaultDefault) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n  command = cat $in > $out\n"
-"build a: cat foo\n"
-"build b: cat foo\n"
-"build c: cat foo\n"
-"build d: cat foo\n"));
-
-  string err;
-  EXPECT_EQ(4u, state.DefaultNodes(&err).size());
-  EXPECT_EQ("", err);
-}
-
-TEST_F(ParserTest, DefaultDefaultCycle) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n  command = cat $in > $out\n"
-"build a: cat a\n"));
-
-  string err;
-  EXPECT_EQ(0u, state.DefaultNodes(&err).size());
-  EXPECT_EQ("could not determine root nodes of build graph", err);
-}
-
-TEST_F(ParserTest, DefaultStatements) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n  command = cat $in > $out\n"
-"build a: cat foo\n"
-"build b: cat foo\n"
-"build c: cat foo\n"
-"build d: cat foo\n"
-"third = c\n"
-"default a b\n"
-"default $third\n"));
-
-  string err;
-  vector<Node*> nodes = state.DefaultNodes(&err);
-  EXPECT_EQ("", err);
-  ASSERT_EQ(3u, nodes.size());
-  EXPECT_EQ("a", nodes[0]->path());
-  EXPECT_EQ("b", nodes[1]->path());
-  EXPECT_EQ("c", nodes[2]->path());
-}
-
-TEST_F(ParserTest, UTF8) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule utf8\n"
-"  command = true\n"
-"  description = compilaci\xC3\xB3\n"));
-}
-
-TEST_F(ParserTest, CRLF) {
-  State local_state;
-  ManifestParser parser(&local_state, NULL);
-  string err;
-
-  EXPECT_TRUE(parser.ParseTest("# comment with crlf\r\n", &err));
-  EXPECT_TRUE(parser.ParseTest("foo = foo\nbar = bar\r\n", &err));
-  EXPECT_TRUE(parser.ParseTest(
-      "pool link_pool\r\n"
-      "  depth = 15\r\n\r\n"
-      "rule xyz\r\n"
-      "  command = something$expand \r\n"
-      "  description = YAY!\r\n",
-      &err));
-}
-
-TEST_F(ParserTest, DyndepNotSpecified) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build result: cat in\n"));
-  Edge* edge = state.GetNode("result", 0)->in_edge();
-  ASSERT_FALSE(edge->dyndep_);
-}
-
-TEST_F(ParserTest, DyndepNotInput) {
-  State lstate;
-  ManifestParser parser(&lstate, NULL);
-  string err;
-  EXPECT_FALSE(parser.ParseTest(
-"rule touch\n"
-"  command = touch $out\n"
-"build result: touch\n"
-"  dyndep = notin\n",
-                               &err));
-  EXPECT_EQ("input:5: dyndep 'notin' is not an input\n", err);
-}
-
-TEST_F(ParserTest, DyndepExplicitInput) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build result: cat in\n"
-"  dyndep = in\n"));
-  Edge* edge = state.GetNode("result", 0)->in_edge();
-  ASSERT_TRUE(edge->dyndep_);
-  EXPECT_TRUE(edge->dyndep_->dyndep_pending());
-  EXPECT_EQ(edge->dyndep_->path(), "in");
-}
-
-TEST_F(ParserTest, DyndepImplicitInput) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build result: cat in | dd\n"
-"  dyndep = dd\n"));
-  Edge* edge = state.GetNode("result", 0)->in_edge();
-  ASSERT_TRUE(edge->dyndep_);
-  EXPECT_TRUE(edge->dyndep_->dyndep_pending());
-  EXPECT_EQ(edge->dyndep_->path(), "dd");
-}
-
-TEST_F(ParserTest, DyndepOrderOnlyInput) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"build result: cat in || dd\n"
-"  dyndep = dd\n"));
-  Edge* edge = state.GetNode("result", 0)->in_edge();
-  ASSERT_TRUE(edge->dyndep_);
-  EXPECT_TRUE(edge->dyndep_->dyndep_pending());
-  EXPECT_EQ(edge->dyndep_->path(), "dd");
-}
-
-TEST_F(ParserTest, DyndepRuleInput) {
-  ASSERT_NO_FATAL_FAILURE(AssertParse(
-"rule cat\n"
-"  command = cat $in > $out\n"
-"  dyndep = $in\n"
-"build result: cat in\n"));
-  Edge* edge = state.GetNode("result", 0)->in_edge();
-  ASSERT_TRUE(edge->dyndep_);
-  EXPECT_TRUE(edge->dyndep_->dyndep_pending());
-  EXPECT_EQ(edge->dyndep_->path(), "in");
-}
diff --git a/src/metrics.cc b/src/metrics.cc
deleted file mode 100644
index 88d0180..0000000
--- a/src/metrics.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-// 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.
-
-#include "metrics.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <algorithm>
-#include <chrono>
-
-#include "util.h"
-
-using namespace std;
-
-Metrics* g_metrics = NULL;
-
-namespace {
-
-/// Compute a platform-specific high-res timer value that fits into an int64.
-int64_t HighResTimer() {
-  auto now = chrono::steady_clock::now();
-  return chrono::duration_cast<chrono::steady_clock::duration>(
-             now.time_since_epoch())
-      .count();
-}
-
-constexpr int64_t GetFrequency() {
-  // If numerator isn't 1 then we lose precision and that will need to be
-  // assessed.
-  static_assert(std::chrono::steady_clock::period::num == 1,
-                "Numerator must be 1");
-  return std::chrono::steady_clock::period::den /
-         std::chrono::steady_clock::period::num;
-}
-
-int64_t TimerToMicros(int64_t dt) {
-  // dt is in ticks.  We want microseconds.
-  return (dt * 1000000) / GetFrequency();
-}
-
-int64_t TimerToMicros(double dt) {
-  // dt is in ticks.  We want microseconds.
-  return (dt * 1000000) / GetFrequency();
-}
-
-}  // anonymous namespace
-
-ScopedMetric::ScopedMetric(Metric* metric) {
-  metric_ = metric;
-  if (!metric_)
-    return;
-  start_ = HighResTimer();
-}
-ScopedMetric::~ScopedMetric() {
-  if (!metric_)
-    return;
-  metric_->count++;
-  // Leave in the timer's natural frequency to avoid paying the conversion cost
-  // on every measurement.
-  int64_t dt = HighResTimer() - start_;
-  metric_->sum += dt;
-}
-
-Metric* MetricsDomain::NewMetric(StringPiece name) {
-  metrics_.emplace_back(new Metric(name));
-  return metrics_.back().get();
-}
-
-void MetricsDomain::Reset() {
-  for (auto& metric : metrics_) {
-    metric->count = 0;
-    metric->sum = 0;
-  }
-}
-
-int MetricsDomain::ComputeMaxNameWidth(int max_width) {
-  for (const auto& metric : metrics_)
-    max_width = max((int)(metric->name.size()), max_width);
-  return max_width;
-}
-
-// static
-void MetricsDomain::PrintBanner(int max_width) {
-  printf("%-*s\t%-6s\t%-9s\t%s\n", max_width, "metric", "count", "avg (us)",
-         "total (ms)");
-}
-
-void MetricsDomain::Print(int max_width) {
-  for (const auto& metric : metrics_) {
-    uint64_t micros = TimerToMicros(metric->sum);
-    double total = micros / (double)1000;
-    double avg = micros / (double)metric->count;
-    printf("%-*s\t%-6d\t%-8.1f\t%.1f\n", max_width, metric->name.c_str(),
-           metric->count, avg, total);
-  }
-}
-
-void MetricsDomain::Report() {
-  int max_width = ComputeMaxNameWidth(0);
-  PrintBanner(max_width);
-  Print(max_width);
-}
-
-void Metrics::Report() {
-  int max_width = 0;
-  max_width = load_.ComputeMaxNameWidth(max_width);
-  max_width = build_.ComputeMaxNameWidth(max_width);
-
-  MetricsDomain::PrintBanner(max_width);
-  load_.Print(max_width);
-  build_.Print(max_width);
-}
-
-double Stopwatch::Elapsed() const {
-  // Convert to micros after converting to double to minimize error.
-  return 1e-6 * TimerToMicros(static_cast<double>(NowRaw() - started_));
-}
-
-uint64_t Stopwatch::NowRaw() const {
-  return HighResTimer();
-}
-
-int64_t GetTimeMillis() {
-  return TimerToMicros(HighResTimer()) / 1000;
-}
diff --git a/src/metrics.h b/src/metrics.h
deleted file mode 100644
index a105984..0000000
--- a/src/metrics.h
+++ /dev/null
@@ -1,139 +0,0 @@
-// 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.
-
-#ifndef NINJA_METRICS_H_
-#define NINJA_METRICS_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "string_piece.h"
-#include "util.h"  // For int64_t.
-
-/// The Metrics module is used for the debug mode that dumps timing stats of
-/// various actions.  To use, see METRIC_RECORD below.
-
-/// A single metrics we're tracking, like "depfile load time".
-struct Metric {
-  Metric(StringPiece name) : name(name.AsString()) {}
-
-  std::string name;
-  /// Number of times we've hit the code path.
-  int count = 0;
-  /// Total time (in platform-dependent units) we've spent on the code path.
-  int64_t sum = 0;
-};
-
-/// A scoped object for recording a metric across the body of a function.
-/// Used by the METRIC_RECORD macro.
-struct ScopedMetric {
-  explicit ScopedMetric(Metric* metric);
-  ~ScopedMetric();
-
-private:
-  Metric* metric_;
-  /// Timestamp when the measurement started.
-  /// Value is platform-dependent.
-  int64_t start_;
-};
-
-/// A set of metrics scoped to a given domain, e.g. manifest loading, or
-/// build invocation.
-struct MetricsDomain {
-  Metric* NewMetric(StringPiece name);
-
-  /// Reset all Metric instances in this domain.
-  void Reset();
-
-  /// Compute the max width of all metric names in this domain.
-  /// If |cur_max_width| is not 0, then ensure the result is always greater
-  /// or equal to it, which is useful when combining several domain reports.
-  int ComputeMaxNameWidth(int cur_max_width = 0);
-
-  /// Print a one-line table banner describing metric details.
-  static void PrintBanner(int max_width);
-
-  /// Print a summary of all metrics to stdout, without any banner.
-  void Print(int max_width = 0);
-
-  /// Print a summary report for just this domain to stdout.
-  void Report();
-
-private:
- std::vector<std::unique_ptr<Metric>> metrics_;
-};
-
-/// The set of Ninja metrics domains.
-struct Metrics {
- /// Print a summary report for all domains to stdout.
- void Report();
-
- MetricsDomain load_;
- MetricsDomain build_;
-};
-
-/// Get the current time as relative to some epoch.
-/// Epoch varies between platforms; only useful for measuring elapsed time.
-int64_t GetTimeMillis();
-
-/// A simple stopwatch which returns the time
-/// in seconds since Restart() was called.
-struct Stopwatch {
- public:
-  Stopwatch() : started_(0) {}
-
-  /// Seconds since Restart() call.
-  double Elapsed() const;
-
-  void Restart() { started_ = NowRaw(); }
-
- private:
-  uint64_t started_;
-  // Return the current time using the native frequency of the high resolution
-  // timer.
-  uint64_t NowRaw() const;
-};
-
-/// The primary interface to metrics.  Use METRIC_RECORD("foobar") at the top
-/// of a function to get timing stats recorded for each call of the function.
-/// This creates a metric in the "build" domain, for operations performed
-/// when loading the manifest, use METRIC_RECORD_LOAD() instead.
-#define METRIC_RECORD(name)                                 \
-  static Metric* metrics_h_metric =                         \
-      g_metrics ? g_metrics->build_.NewMetric(name) : NULL; \
-  ScopedMetric metrics_h_scoped(metrics_h_metric);
-
-/// A variant of METRIC_RECORD() for timing manifest loading operations.
-#define METRIC_RECORD_LOAD(name)                           \
-  static Metric* metrics_h_metric =                        \
-      g_metrics ? g_metrics->load_.NewMetric(name) : NULL; \
-  ScopedMetric metrics_h_scoped(metrics_h_metric);
-
-/// A variant of METRIC_RECORD that doesn't record anything if |condition|
-/// is false.
-#define METRIC_RECORD_IF(name, condition)                   \
-  static Metric* metrics_h_metric =                         \
-      g_metrics ? g_metrics->build_.NewMetric(name) : NULL; \
-  ScopedMetric metrics_h_scoped((condition) ? metrics_h_metric : NULL);
-
-/// A variant of METRIC_RECORD_IF for timing manifest loading operations.
-#define METRIC_RECORD_LOAD_IF(name, condition)             \
-  static Metric* metrics_h_metric =                        \
-      g_metrics ? g_metrics->load_.NewMetric(name) : NULL; \
-  ScopedMetric metrics_h_scoped((condition) ? metrics_h_metric : NULL);
-
-extern Metrics* g_metrics;
-
-#endif // NINJA_METRICS_H_
diff --git a/src/minidump-win32.cc b/src/minidump-win32.cc
deleted file mode 100644
index 9aea767..0000000
--- a/src/minidump-win32.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2012 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.
-
-#ifdef _MSC_VER
-
-#include <windows.h>
-#include <DbgHelp.h>
-
-#include "util.h"
-
-using namespace std;
-
-typedef BOOL (WINAPI *MiniDumpWriteDumpFunc) (
-    IN HANDLE,
-    IN DWORD,
-    IN HANDLE,
-    IN MINIDUMP_TYPE,
-    IN CONST PMINIDUMP_EXCEPTION_INFORMATION, OPTIONAL
-    IN CONST PMINIDUMP_USER_STREAM_INFORMATION, OPTIONAL
-    IN CONST PMINIDUMP_CALLBACK_INFORMATION OPTIONAL
-    );
-
-/// Creates a windows minidump in temp folder.
-void CreateWin32MiniDump(_EXCEPTION_POINTERS* pep) {
-  char temp_path[MAX_PATH];
-  GetTempPathA(sizeof(temp_path), temp_path);
-  char temp_file[MAX_PATH];
-  sprintf(temp_file, "%s\\ninja_crash_dump_%lu.dmp",
-          temp_path, GetCurrentProcessId());
-
-  // Delete any previous minidump of the same name.
-  DeleteFileA(temp_file);
-
-  // Load DbgHelp.dll dynamically, as library is not present on all
-  // Windows versions.
-  HMODULE dbghelp = LoadLibraryA("dbghelp.dll");
-  if (dbghelp == NULL) {
-    Error("failed to create minidump: LoadLibrary('dbghelp.dll'): %s",
-          GetLastErrorString().c_str());
-    return;
-  }
-
-  MiniDumpWriteDumpFunc mini_dump_write_dump =
-      (MiniDumpWriteDumpFunc)GetProcAddress(dbghelp, "MiniDumpWriteDump");
-  if (mini_dump_write_dump == NULL) {
-    Error("failed to create minidump: GetProcAddress('MiniDumpWriteDump'): %s",
-          GetLastErrorString().c_str());
-    return;
-  }
-
-  HANDLE hFile = CreateFileA(temp_file, GENERIC_READ | GENERIC_WRITE, 0, NULL,
-                             CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-  if (hFile == NULL) {
-    Error("failed to create minidump: CreateFileA(%s): %s",
-          temp_file, GetLastErrorString().c_str());
-    return;
-  }
-
-  MINIDUMP_EXCEPTION_INFORMATION mdei;
-  mdei.ThreadId           = GetCurrentThreadId();
-  mdei.ExceptionPointers  = pep;
-  mdei.ClientPointers     = FALSE;
-  MINIDUMP_TYPE mdt       = (MINIDUMP_TYPE) (MiniDumpWithDataSegs |
-                                             MiniDumpWithHandleData);
-
-  BOOL rv = mini_dump_write_dump(GetCurrentProcess(), GetCurrentProcessId(),
-                                 hFile, mdt, (pep != 0) ? &mdei : 0, 0, 0);
-  CloseHandle(hFile);
-
-  if (!rv) {
-    Error("MiniDumpWriteDump failed: %s", GetLastErrorString().c_str());
-    return;
-  }
-
-  Warning("minidump created: %s", temp_file);
-}
-
-#endif  // _MSC_VER
diff --git a/src/missing_deps.cc b/src/missing_deps.cc
deleted file mode 100644
index de76620..0000000
--- a/src/missing_deps.cc
+++ /dev/null
@@ -1,192 +0,0 @@
-// 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.
-
-#include "missing_deps.h"
-
-#include <string.h>
-
-#include <iostream>
-
-#include "depfile_parser.h"
-#include "deps_log.h"
-#include "disk_interface.h"
-#include "graph.h"
-#include "state.h"
-#include "util.h"
-
-namespace {
-
-/// ImplicitDepLoader variant that stores dep nodes into the given output
-/// without updating graph deps like the base loader does.
-struct NodeStoringImplicitDepLoader : public ImplicitDepLoader {
-  NodeStoringImplicitDepLoader(
-      State* state, DepsLog* deps_log, DiskInterface* disk_interface,
-      DepfileParserOptions const* depfile_parser_options,
-      std::vector<Node*>* dep_nodes_output)
-      : ImplicitDepLoader(state, deps_log, disk_interface,
-                          depfile_parser_options),
-        dep_nodes_output_(dep_nodes_output) {}
-
- protected:
-  virtual bool ProcessDepfileDeps(Edge* edge,
-                                  std::vector<StringPiece>* depfile_ins,
-                                  std::string* err);
-
- private:
-  std::vector<Node*>* dep_nodes_output_;
-};
-
-bool NodeStoringImplicitDepLoader::ProcessDepfileDeps(
-    Edge* edge, std::vector<StringPiece>* depfile_ins, std::string* err) {
-  for (std::vector<StringPiece>::iterator i = depfile_ins->begin();
-       i != depfile_ins->end(); ++i) {
-    uint64_t slash_bits;
-    CanonicalizePath(const_cast<char*>(i->str_), &i->len_, &slash_bits);
-    Node* node = state_->GetNode(*i, slash_bits);
-    dep_nodes_output_->push_back(node);
-  }
-  return true;
-}
-
-}  // namespace
-
-MissingDependencyScannerDelegate::~MissingDependencyScannerDelegate() {}
-
-void MissingDependencyPrinter::OnMissingDep(Node* node, const std::string& path,
-                                            const Rule& generator) {
-  std::cout << "Missing dep: " << node->path() << " uses " << path
-            << " (generated by " << generator.name() << ")\n";
-}
-
-MissingDependencyScanner::MissingDependencyScanner(
-    MissingDependencyScannerDelegate* delegate, DepsLog* deps_log, State* state,
-    DiskInterface* disk_interface)
-    : delegate_(delegate), deps_log_(deps_log), state_(state),
-      disk_interface_(disk_interface), missing_dep_path_count_(0) {}
-
-void MissingDependencyScanner::ProcessNode(Node* node) {
-  if (!node)
-    return;
-  Edge* edge = node->in_edge();
-  if (!edge)
-    return;
-  if (!seen_.insert(node).second)
-    return;
-
-  for (std::vector<Node*>::iterator in = edge->inputs_.begin();
-       in != edge->inputs_.end(); ++in) {
-    ProcessNode(*in);
-  }
-
-  std::string deps_type = edge->GetBinding("deps");
-  if (!deps_type.empty()) {
-    DepsLog::Deps* deps = deps_log_->GetDeps(node);
-    if (deps)
-      ProcessNodeDeps(node, deps->nodes, deps->node_count);
-  } else {
-    DepfileParserOptions parser_opts;
-    std::vector<Node*> depfile_deps;
-    NodeStoringImplicitDepLoader dep_loader(state_, deps_log_, disk_interface_,
-                                            &parser_opts, &depfile_deps);
-    std::string err;
-    dep_loader.LoadDeps(edge, &err);
-    if (!depfile_deps.empty())
-      ProcessNodeDeps(node, &depfile_deps[0], depfile_deps.size());
-  }
-}
-
-void MissingDependencyScanner::ProcessNodeDeps(Node* node, Node** dep_nodes,
-                                               int dep_nodes_count) {
-  Edge* edge = node->in_edge();
-  std::set<Edge*> deplog_edges;
-  for (int i = 0; i < dep_nodes_count; ++i) {
-    Node* deplog_node = dep_nodes[i];
-    // Special exception: A dep on build.ninja can be used to mean "always
-    // rebuild this target when the build is reconfigured", but build.ninja is
-    // often generated by a configuration tool like cmake or gn. The rest of
-    // the build "implicitly" depends on the entire build being reconfigured,
-    // so a missing dep path to build.ninja is not an actual missing dependency
-    // problem.
-    if (deplog_node->path() == "build.ninja")
-      return;
-    Edge* deplog_edge = deplog_node->in_edge();
-    if (deplog_edge) {
-      deplog_edges.insert(deplog_edge);
-    }
-  }
-  std::vector<Edge*> missing_deps;
-  for (std::set<Edge*>::iterator de = deplog_edges.begin();
-       de != deplog_edges.end(); ++de) {
-    if (!PathExistsBetween(*de, edge)) {
-      missing_deps.push_back(*de);
-    }
-  }
-
-  if (!missing_deps.empty()) {
-    std::set<std::string> missing_deps_rule_names;
-    for (std::vector<Edge*>::iterator ne = missing_deps.begin();
-         ne != missing_deps.end(); ++ne) {
-      for (int i = 0; i < dep_nodes_count; ++i) {
-        if (dep_nodes[i]->in_edge() == *ne) {
-          generated_nodes_.insert(dep_nodes[i]);
-          generator_rules_.insert(&(*ne)->rule());
-          missing_deps_rule_names.insert((*ne)->rule().name());
-          delegate_->OnMissingDep(node, dep_nodes[i]->path(), (*ne)->rule());
-        }
-      }
-    }
-    missing_dep_path_count_ += missing_deps_rule_names.size();
-    nodes_missing_deps_.insert(node);
-  }
-}
-
-void MissingDependencyScanner::PrintStats() {
-  std::cout << "Processed " << seen_.size() << " nodes.\n";
-  if (HadMissingDeps()) {
-    std::cout << "Error: There are " << missing_dep_path_count_
-              << " missing dependency paths.\n";
-    std::cout << nodes_missing_deps_.size()
-              << " targets had depfile dependencies on "
-              << generated_nodes_.size() << " distinct generated inputs "
-              << "(from " << generator_rules_.size() << " rules) "
-              << " without a non-depfile dep path to the generator.\n";
-    std::cout << "There might be build flakiness if any of the targets listed "
-                 "above are built alone, or not late enough, in a clean output "
-                 "directory.\n";
-  } else {
-    std::cout << "No missing dependencies on generated files found.\n";
-  }
-}
-
-bool MissingDependencyScanner::PathExistsBetween(Edge* from, Edge* to) {
-  AdjacencyMap::iterator it = adjacency_map_.find(from);
-  if (it != adjacency_map_.end()) {
-    InnerAdjacencyMap::iterator inner_it = it->second.find(to);
-    if (inner_it != it->second.end()) {
-      return inner_it->second;
-    }
-  } else {
-    it = adjacency_map_.insert(std::make_pair(from, InnerAdjacencyMap())).first;
-  }
-  bool found = false;
-  for (size_t i = 0; i < to->inputs_.size(); ++i) {
-    Edge* e = to->inputs_[i]->in_edge();
-    if (e && (e == from || PathExistsBetween(from, e))) {
-      found = true;
-      break;
-    }
-  }
-  it->second.insert(std::make_pair(to, found));
-  return found;
-}
diff --git a/src/missing_deps.h b/src/missing_deps.h
deleted file mode 100644
index 7a615da..0000000
--- a/src/missing_deps.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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_MISSING_DEPS_H_
-#define NINJA_MISSING_DEPS_H_
-
-#include <map>
-#include <set>
-#include <string>
-
-#include <unordered_map>
-
-struct DepsLog;
-struct DiskInterface;
-struct Edge;
-struct Node;
-struct Rule;
-struct State;
-
-class MissingDependencyScannerDelegate {
- public:
-  virtual ~MissingDependencyScannerDelegate();
-  virtual void OnMissingDep(Node* node, const std::string& path,
-                            const Rule& generator) = 0;
-};
-
-class MissingDependencyPrinter : public MissingDependencyScannerDelegate {
-  void OnMissingDep(Node* node, const std::string& path, const Rule& generator);
-  void OnStats(int nodes_processed, int nodes_missing_deps,
-               int missing_dep_path_count, int generated_nodes,
-               int generator_rules);
-};
-
-struct MissingDependencyScanner {
- public:
-  MissingDependencyScanner(MissingDependencyScannerDelegate* delegate,
-                           DepsLog* deps_log, State* state,
-                           DiskInterface* disk_interface);
-  void ProcessNode(Node* node);
-  void PrintStats();
-  bool HadMissingDeps() { return !nodes_missing_deps_.empty(); }
-
-  void ProcessNodeDeps(Node* node, Node** dep_nodes, int dep_nodes_count);
-
-  bool PathExistsBetween(Edge* from, Edge* to);
-
-  MissingDependencyScannerDelegate* delegate_;
-  DepsLog* deps_log_;
-  State* state_;
-  DiskInterface* disk_interface_;
-  std::set<Node*> seen_;
-  std::set<Node*> nodes_missing_deps_;
-  std::set<Node*> generated_nodes_;
-  std::set<const Rule*> generator_rules_;
-  int missing_dep_path_count_;
-
- private:
-  using InnerAdjacencyMap = std::unordered_map<Edge*, bool>;
-  using AdjacencyMap = std::unordered_map<Edge*, InnerAdjacencyMap>;
-  AdjacencyMap adjacency_map_;
-};
-
-#endif  // NINJA_MISSING_DEPS_H_
diff --git a/src/missing_deps_test.cc b/src/missing_deps_test.cc
deleted file mode 100644
index db66885..0000000
--- a/src/missing_deps_test.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-// 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.
-
-#include <memory>
-
-#include "deps_log.h"
-#include "graph.h"
-#include "missing_deps.h"
-#include "state.h"
-#include "test.h"
-
-const char kTestDepsLogFilename[] = "MissingDepTest-tempdepslog";
-
-class MissingDependencyTestDelegate : public MissingDependencyScannerDelegate {
-  void OnMissingDep(Node* node, const std::string& path,
-                    const Rule& generator) {}
-};
-
-struct MissingDependencyScannerTest : public testing::Test {
-  MissingDependencyScannerTest()
-      : generator_rule_("generator_rule"), compile_rule_("compile_rule"),
-        scanner_(&delegate_, &deps_log_, &state_, &filesystem_) {
-    std::string err;
-    deps_log_.OpenForWrite(kTestDepsLogFilename, &err);
-    ASSERT_EQ("", err);
-  }
-
-  MissingDependencyScanner& scanner() { return scanner_; }
-
-  void RecordDepsLogDep(const std::string& from, const std::string& to) {
-    Node* node_deps[] = { state_.LookupNode(to) };
-    deps_log_.RecordDeps(state_.LookupNode(from), 0, 1, node_deps);
-  }
-
-  void ProcessAllNodes() {
-    std::string err;
-    std::vector<Node*> nodes = state_.RootNodes(&err);
-    EXPECT_EQ("", err);
-    for (std::vector<Node*>::iterator it = nodes.begin(); it != nodes.end();
-         ++it) {
-      scanner().ProcessNode(*it);
-    }
-  }
-
-  void CreateInitialState() {
-    EvalString deps_type;
-    deps_type.AddText("gcc");
-    compile_rule_.AddBinding("deps", deps_type);
-    generator_rule_.AddBinding("deps", deps_type);
-    Edge* header_edge = state_.AddEdge(&generator_rule_);
-    state_.AddOut(header_edge, "generated_header", 0);
-    Edge* compile_edge = state_.AddEdge(&compile_rule_);
-    state_.AddOut(compile_edge, "compiled_object", 0);
-  }
-
-  void CreateGraphDependencyBetween(const char* from, const char* to) {
-    Node* from_node = state_.LookupNode(from);
-    Edge* from_edge = from_node->in_edge();
-    state_.AddIn(from_edge, to, 0);
-  }
-
-  void AssertMissingDependencyBetween(const char* flaky, const char* generated,
-                                      Rule* rule) {
-    Node* flaky_node = state_.LookupNode(flaky);
-    ASSERT_EQ(1u, scanner().nodes_missing_deps_.count(flaky_node));
-    Node* generated_node = state_.LookupNode(generated);
-    ASSERT_EQ(1u, scanner().generated_nodes_.count(generated_node));
-    ASSERT_EQ(1u, scanner().generator_rules_.count(rule));
-  }
-
-  MissingDependencyTestDelegate delegate_;
-  Rule generator_rule_;
-  Rule compile_rule_;
-  DepsLog deps_log_;
-  State state_;
-  VirtualFileSystem filesystem_;
-  MissingDependencyScanner scanner_;
-};
-
-TEST_F(MissingDependencyScannerTest, EmptyGraph) {
-  ProcessAllNodes();
-  ASSERT_FALSE(scanner().HadMissingDeps());
-}
-
-TEST_F(MissingDependencyScannerTest, NoMissingDep) {
-  CreateInitialState();
-  ProcessAllNodes();
-  ASSERT_FALSE(scanner().HadMissingDeps());
-}
-
-TEST_F(MissingDependencyScannerTest, MissingDepPresent) {
-  CreateInitialState();
-  // compiled_object uses generated_header, without a proper dependency
-  RecordDepsLogDep("compiled_object", "generated_header");
-  ProcessAllNodes();
-  ASSERT_TRUE(scanner().HadMissingDeps());
-  ASSERT_EQ(1u, scanner().nodes_missing_deps_.size());
-  ASSERT_EQ(1u, scanner().missing_dep_path_count_);
-  AssertMissingDependencyBetween("compiled_object", "generated_header",
-                                 &generator_rule_);
-}
-
-TEST_F(MissingDependencyScannerTest, MissingDepFixedDirect) {
-  CreateInitialState();
-  // Adding the direct dependency fixes the missing dep
-  CreateGraphDependencyBetween("compiled_object", "generated_header");
-  RecordDepsLogDep("compiled_object", "generated_header");
-  ProcessAllNodes();
-  ASSERT_FALSE(scanner().HadMissingDeps());
-}
-
-TEST_F(MissingDependencyScannerTest, MissingDepFixedIndirect) {
-  CreateInitialState();
-  // Adding an indirect dependency also fixes the issue
-  Edge* intermediate_edge = state_.AddEdge(&generator_rule_);
-  state_.AddOut(intermediate_edge, "intermediate", 0);
-  CreateGraphDependencyBetween("compiled_object", "intermediate");
-  CreateGraphDependencyBetween("intermediate", "generated_header");
-  RecordDepsLogDep("compiled_object", "generated_header");
-  ProcessAllNodes();
-  ASSERT_FALSE(scanner().HadMissingDeps());
-}
-
-TEST_F(MissingDependencyScannerTest, CyclicMissingDep) {
-  CreateInitialState();
-  RecordDepsLogDep("generated_header", "compiled_object");
-  RecordDepsLogDep("compiled_object", "generated_header");
-  // In case of a cycle, both paths are reported (and there is
-  // no way to fix the issue by adding deps).
-  ProcessAllNodes();
-  ASSERT_TRUE(scanner().HadMissingDeps());
-  ASSERT_EQ(2u, scanner().nodes_missing_deps_.size());
-  ASSERT_EQ(2u, scanner().missing_dep_path_count_);
-  AssertMissingDependencyBetween("compiled_object", "generated_header",
-                                 &generator_rule_);
-  AssertMissingDependencyBetween("generated_header", "compiled_object",
-                                 &compile_rule_);
-}
-
-TEST_F(MissingDependencyScannerTest, CycleInGraph) {
-  CreateInitialState();
-  CreateGraphDependencyBetween("compiled_object", "generated_header");
-  CreateGraphDependencyBetween("generated_header", "compiled_object");
-  // The missing-deps tool doesn't deal with cycles in the graph, because
-  // there will be an error loading the graph before we get to the tool.
-  // This test is to illustrate that.
-  std::string err;
-  std::vector<Node*> nodes = state_.RootNodes(&err);
-  ASSERT_NE("", err);
-}
-
diff --git a/src/msvc_helper-win32.cc b/src/msvc_helper-win32.cc
deleted file mode 100644
index 1148ae5..0000000
--- a/src/msvc_helper-win32.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// 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.
-
-#include "msvc_helper.h"
-
-#include <windows.h>
-
-#include "util.h"
-
-using namespace std;
-
-namespace {
-
-string Replace(const string& input, const string& find, const string& replace) {
-  string result = input;
-  size_t start_pos = 0;
-  while ((start_pos = result.find(find, start_pos)) != string::npos) {
-    result.replace(start_pos, find.length(), replace);
-    start_pos += replace.length();
-  }
-  return result;
-}
-
-}  // anonymous namespace
-
-string EscapeForDepfile(const string& path) {
-  // Depfiles don't escape single \.
-  return Replace(path, " ", "\\ ");
-}
-
-int CLWrapper::Run(const string& command, string* output) {
-  SECURITY_ATTRIBUTES security_attributes = {};
-  security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
-  security_attributes.bInheritHandle = TRUE;
-
-  // Must be inheritable so subprocesses can dup to children.
-  HANDLE nul =
-      CreateFileA("NUL", GENERIC_READ,
-                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                  &security_attributes, OPEN_EXISTING, 0, NULL);
-  if (nul == INVALID_HANDLE_VALUE)
-    Fatal("couldn't open nul");
-
-  HANDLE stdout_read, stdout_write;
-  if (!CreatePipe(&stdout_read, &stdout_write, &security_attributes, 0))
-    Win32Fatal("CreatePipe");
-
-  if (!SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0))
-    Win32Fatal("SetHandleInformation");
-
-  PROCESS_INFORMATION process_info = {};
-  STARTUPINFOA startup_info = {};
-  startup_info.cb = sizeof(STARTUPINFOA);
-  startup_info.hStdInput = nul;
-  startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
-  startup_info.hStdOutput = stdout_write;
-  startup_info.dwFlags |= STARTF_USESTDHANDLES;
-
-  if (!CreateProcessA(NULL, (char*)command.c_str(), NULL, NULL,
-                      /* inherit handles */ TRUE, 0,
-                      env_block_, NULL,
-                      &startup_info, &process_info)) {
-    Win32Fatal("CreateProcess");
-  }
-
-  if (!CloseHandle(nul) ||
-      !CloseHandle(stdout_write)) {
-    Win32Fatal("CloseHandle");
-  }
-
-  // Read all output of the subprocess.
-  DWORD read_len = 1;
-  while (read_len) {
-    char buf[64 << 10];
-    read_len = 0;
-    if (!::ReadFile(stdout_read, buf, sizeof(buf), &read_len, NULL) &&
-        GetLastError() != ERROR_BROKEN_PIPE) {
-      Win32Fatal("ReadFile");
-    }
-    output->append(buf, read_len);
-  }
-
-  // Wait for it to exit and grab its exit code.
-  if (WaitForSingleObject(process_info.hProcess, INFINITE) == WAIT_FAILED)
-    Win32Fatal("WaitForSingleObject");
-  DWORD exit_code = 0;
-  if (!GetExitCodeProcess(process_info.hProcess, &exit_code))
-    Win32Fatal("GetExitCodeProcess");
-
-  if (!CloseHandle(stdout_read) ||
-      !CloseHandle(process_info.hProcess) ||
-      !CloseHandle(process_info.hThread)) {
-    Win32Fatal("CloseHandle");
-  }
-
-  return exit_code;
-}
diff --git a/src/msvc_helper.h b/src/msvc_helper.h
deleted file mode 100644
index 568b9f9..0000000
--- a/src/msvc_helper.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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.
-
-#include <string>
-
-std::string EscapeForDepfile(const std::string& path);
-
-/// Wraps a synchronous execution of a CL subprocess.
-struct CLWrapper {
-  CLWrapper() : env_block_(NULL) {}
-
-  /// Set the environment block (as suitable for CreateProcess) to be used
-  /// by Run().
-  void SetEnvBlock(void* env_block) { env_block_ = env_block; }
-
-  /// Start a process and gather its raw output.  Returns its exit code.
-  /// Crashes (calls Fatal()) on error.
-  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
deleted file mode 100644
index 7d59307..0000000
--- a/src/msvc_helper_main-win32.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-// 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.
-
-#include "msvc_helper.h"
-
-#include <fcntl.h>
-#include <io.h>
-#include <stdio.h>
-#include <windows.h>
-
-#include "clparser.h"
-#include "util.h"
-
-#include "getopt.h"
-
-using namespace std;
-
-namespace {
-
-void Usage() {
-  printf(
-"usage: ninja -t msvc [options] -- cl.exe /showIncludes /otherArgs\n"
-"options:\n"
-"  -e ENVFILE load environment block from ENVFILE as environment\n"
-"  -o FILE    write output dependency information to FILE.d\n"
-"  -p STRING  localized prefix of msvc's /showIncludes output\n"
-         );
-}
-
-void PushPathIntoEnvironment(const string& env_block) {
-  const char* as_str = env_block.c_str();
-  while (as_str[0]) {
-    if (_strnicmp(as_str, "path=", 5) == 0) {
-      _putenv(as_str);
-      return;
-    } else {
-      as_str = &as_str[strlen(as_str) + 1];
-    }
-  }
-}
-
-void WriteDepFileOrDie(const char* object_path, const CLParser& parse) {
-  string depfile_path = string(object_path) + ".d";
-  FILE* depfile = fopen(depfile_path.c_str(), "w");
-  if (!depfile) {
-    unlink(object_path);
-    Fatal("opening %s: %s", depfile_path.c_str(),
-          GetLastErrorString().c_str());
-  }
-  if (fprintf(depfile, "%s: ", object_path) < 0) {
-    unlink(object_path);
-    fclose(depfile);
-    unlink(depfile_path.c_str());
-    Fatal("writing %s", depfile_path.c_str());
-  }
-  const set<string>& headers = parse.includes_;
-  for (set<string>::const_iterator i = headers.begin();
-       i != headers.end(); ++i) {
-    if (fprintf(depfile, "%s\n", EscapeForDepfile(*i).c_str()) < 0) {
-      unlink(object_path);
-      fclose(depfile);
-      unlink(depfile_path.c_str());
-      Fatal("writing %s", depfile_path.c_str());
-    }
-  }
-  fclose(depfile);
-}
-
-}  // anonymous namespace
-
-int MSVCHelperMain(int argc, char** argv) {
-  const char* output_filename = NULL;
-  const char* envfile = NULL;
-
-  const option kLongOptions[] = {
-    { "help", no_argument, NULL, 'h' },
-    { NULL, 0, NULL, 0 }
-  };
-  int opt;
-  string deps_prefix;
-  while ((opt = getopt_long(argc, argv, "e:o:p:h", kLongOptions, NULL)) != -1) {
-    switch (opt) {
-      case 'e':
-        envfile = optarg;
-        break;
-      case 'o':
-        output_filename = optarg;
-        break;
-      case 'p':
-        deps_prefix = optarg;
-        break;
-      case 'h':
-      default:
-        Usage();
-        return 0;
-    }
-  }
-
-  string env;
-  if (envfile) {
-    string err;
-    if (ReadFile(envfile, &env, &err) != 0)
-      Fatal("couldn't open %s: %s", envfile, err.c_str());
-    PushPathIntoEnvironment(env);
-  }
-
-  char* command = GetCommandLineA();
-  command = strstr(command, " -- ");
-  if (!command) {
-    Fatal("expected command line to end with \" -- command args\"");
-  }
-  command += 4;
-
-  CLWrapper cl;
-  if (!env.empty())
-    cl.SetEnvBlock((void*)env.data());
-  string output;
-  int exit_code = cl.Run(command, &output);
-
-  if (output_filename) {
-    CLParser parser;
-    string err;
-    if (!parser.Parse(output, deps_prefix, &output, &err))
-      Fatal("%s\n", err.c_str());
-    WriteDepFileOrDie(output_filename, parser);
-  }
-
-  if (output.empty())
-    return exit_code;
-
-  // CLWrapper's output already as \r\n line endings, make sure the C runtime
-  // doesn't expand this to \r\r\n.
-  _setmode(_fileno(stdout), _O_BINARY);
-  // Avoid printf and C strings, since the actual output might contain null
-  // bytes like UTF-16 does (yuck).
-  fwrite(&output[0], 1, output.size(), stdout);
-
-  return exit_code;
-}
diff --git a/src/msvc_helper_test.cc b/src/msvc_helper_test.cc
deleted file mode 100644
index d9e2ee6..0000000
--- a/src/msvc_helper_test.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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.
-
-#include "msvc_helper.h"
-
-#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"));
-}
-
-TEST(MSVCHelperTest, EnvBlock) {
-  char env_block[] = "foo=bar\0";
-  CLWrapper cl;
-  cl.SetEnvBlock(env_block);
-  string output;
-  cl.Run("cmd /c \"echo foo is %foo%", &output);
-  ASSERT_EQ("foo is bar\r\n", output);
-}
-
-TEST(MSVCHelperTest, NoReadOfStderr) {
-  CLWrapper cl;
-  string output;
-  cl.Run("cmd /c \"echo to stdout&& echo to stderr 1>&2", &output);
-  ASSERT_EQ("to stdout\r\n", output);
-}
diff --git a/src/ninja.cc b/src/ninja.cc
deleted file mode 100644
index df67736..0000000
--- a/src/ninja.cc
+++ /dev/null
@@ -1,1974 +0,0 @@
-// 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.
-
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <algorithm>
-#include <cstdlib>
-
-#ifdef _WIN32
-#include "getopt.h"
-#include <direct.h>
-#include <windows.h>
-#elif defined(_AIX)
-#include "getopt.h"
-#include <unistd.h>
-#else
-#include <getopt.h>
-#include <unistd.h>
-#endif
-
-#include "async_loop.h"
-#include "browse.h"
-#include "build.h"
-#include "build_config.h"
-#include "build_log.h"
-#include "clean.h"
-#include "debug_flags.h"
-#include "depfile_parser.h"
-#include "deps_log.h"
-#include "disk_interface.h"
-#include "graph.h"
-#include "graphviz.h"
-#include "ipc_utils.h"
-#include "json.h"
-#include "manifest_parser.h"
-#include "metrics.h"
-#include "missing_deps.h"
-#include "persistent_mode.h"
-#include "state.h"
-#include "status.h"
-#include "string_piece.h"
-#include "util.h"
-#include "version.h"
-
-using namespace std;
-
-#ifdef _WIN32
-// Defined in msvc_helper_main-win32.cc.
-int MSVCHelperMain(int argc, char** argv);
-
-// Defined in minidump-win32.cc.
-void CreateWin32MiniDump(_EXCEPTION_POINTERS* pep);
-#endif
-
-namespace {
-
-struct Tool;
-
-/// Command-line options.
-struct Options {
-  /// Directory to change into before running.
-  const char* working_dir = nullptr;
-
-  /// Tool to run rather than building.
-  const Tool* tool = nullptr;
-
-  /// Whether duplicate rules for one target should warn or print an error.
-  bool dupe_edges_should_err = true;
-
-  /// Whether phony cycles should warn or print an error.
-  bool phony_cycle_should_err = false;
-};
-
-/// A special value return by NinjaMain::RunBeforeBuild() to
-/// indicate that the build can proceed after loading the manifest
-/// and the logs. Must be strictly negative.
-static const int kBuildCanProceed = -1;
-
-/// The Ninja main() loads up a series of data structures; various tools need
-/// to poke into these, so store them as fields on an object.
-struct NinjaMain : public BuildLogUser {
-  NinjaMain(const char* ninja_command, const BuildConfig& config)
-      : ninja_command_(ninja_command), config_(&config),
-        status_(new StatusPrinter(config)),
-        path_recording_disk_interface_(&disk_interface_),
-        start_time_millis_(GetTimeMillis()) {}
-
-  /// Command line used to run Ninja.
-  const char* ninja_command_;
-
-  /// Build configuration set from flags (e.g. parallelism).
-  const BuildConfig* config_;
-
-  /// The Status instance to send update status messages.
-  Status* status() const { return status_.get(); }
-
-  std::unique_ptr<Status> status_;
-
-  /// Completely reset state. This gets rid of the current build graph,
-  /// rule definitions, logs and timestamp caches.
-  void Reset() {
-    // Note: state_.Reset() does not fully reset the variable!
-    build_log_ = BuildLog();
-
-    // deps_log_ contains pointers into Node instance owned by state_, so
-    // reset it before it.
-    deps_log_ = DepsLog();
-
-    state_ = State();
-    start_time_millis_ = GetTimeMillis();
-    path_recording_disk_interface_.Reset();
-    disk_interface_.FlushCache();
-  }
-
-  /// Reset just enough state to allow a new (possibly incremental) build.
-  /// This keeps the build graph in memory, but resets its state properly
-  /// to avoid relying on previously computed data from a previous build
-  /// (e.g. timestamps, or undrained pools when the build was
-  /// user-interrupted).
-  void PrepareBuild(const BuildConfig& config) {
-    state_.Reset();
-    start_time_millis_ = GetTimeMillis();
-    config_ = &config;
-    // Reset status, since stdio was redirected when in persistent
-    // server process.
-    status_.reset(new StatusPrinter(config));
-    disk_interface_.Sync();
-  }
-
-  /// Loaded state (rules, nodes).
-  State state_;
-
-  /// Functions for accessing the disk.
-  RealDiskInterface disk_interface_;
-
-  /// A DiskInterface instance that records which input files were opened
-  /// when loading manifests. Used later to shutdown a persistent server
-  /// automatically if any one of these files changed.
-  PathRecordingFileReader path_recording_disk_interface_;
-
-  /// The build directory, used for storing the build log etc.
-  string build_dir_;
-
-  BuildLog build_log_;
-  DepsLog deps_log_;
-
-  /// The type of functions that are the entry points to tools (subcommands).
-  typedef int (NinjaMain::*ToolFunc)(const Options*, int, char**);
-
-  /// Get the Node for a given command-line path, handling features like
-  /// spell correction.
-  Node* CollectTarget(const char* cpath, string* err);
-
-  /// CollectTarget for all command-line arguments, filling in \a targets.
-  bool CollectTargetsFromArgs(int argc, char* argv[],
-                              vector<Node*>* targets, string* err);
-
-  // The various subcommands, run via "-t XXX".
-  int ToolGraph(const Options* options, int argc, char* argv[]);
-  int ToolQuery(const Options* options, int argc, char* argv[]);
-  int ToolDeps(const Options* options, int argc, char* argv[]);
-  int ToolMissingDeps(const Options* options, int argc, char* argv[]);
-  int ToolBrowse(const Options* options, int argc, char* argv[]);
-  int ToolMSVC(const Options* options, int argc, char* argv[]);
-  int ToolTargets(const Options* options, int argc, char* argv[]);
-  int ToolCommands(const Options* options, int argc, char* argv[]);
-  int ToolInputs(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[]);
-  int ToolWinCodePage(const Options* options, int argc, char* argv[]);
-  int ToolServer(const Options* options, int argc, char* argv[]);
-
-  /// Open the build log.
-  /// @return false on error.
-  bool OpenBuildLog(bool recompact_only = false);
-
-  /// Open the deps log: load it, then open for writing.
-  /// @return false on error.
-  bool OpenDepsLog(bool recompact_only = false);
-
-  /// Ensure the build directory exists, creating it if necessary.
-  /// @return false on error.
-  bool EnsureBuildDirExists();
-
-  /// Rebuild the manifest, if necessary.
-  /// Fills in \a err on error.
-  /// @return true if the manifest was rebuilt.
-  bool RebuildManifest(std::string* err, bool silent_dry_run = false);
-
-  /// Perform all operations before the build itself, i.e.
-  /// load the manifest, the build log, the deps log, and
-  /// any tool if needed. Return kBuildCanProceed to indicate that
-  /// the build can proceed after the call, or a positive process
-  /// exit code to tell Ninja to stop.
-  int RunBeforeBuild(const Options& options, int argc, char** argv);
-
-  /// Build the targets listed on the command line.
-  /// @return an exit code.
-  int RunBuild(int argc, char** argv);
-
-  /// Dump the output requested by '-d stats'.
-  void DumpMetrics();
-
-  virtual bool IsPathDead(StringPiece s) const {
-    Node* n = state_.LookupNode(s);
-    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
-    // have an in edge if one of its inputs is another output that's in the deps
-    // log, but having a deps edge product an output that's input to another deps
-    // edge is rare, and the first recompaction will delete all old outputs from
-    // the deps log, and then a second recompaction will clear the build log,
-    // which seems good enough for this corner case.)
-    // Do keep entries around for files which still exist on disk, for
-    // generators that want to use this information.
-    string err;
-    TimeStamp mtime = disk_interface_.Stat(s.AsString(), &err);
-    if (mtime == -1)
-      Error("%s", err.c_str());  // Log and ignore Stat() errors.
-    return mtime == 0;
-  }
-
-  int64_t start_time_millis_;
-};
-
-/// Subtools, accessible via "-t foo".
-struct Tool {
-  /// Short name of the tool.
-  const char* name;
-
-  /// Description (shown in "-t list").
-  const char* desc;
-
-  /// When to run the tool.
-  enum {
-    /// Run after parsing the command-line flags and potentially changing
-    /// the current working directory (as early as possible).
-    RUN_AFTER_FLAGS,
-
-    /// Run after loading build.ninja.
-    RUN_AFTER_LOAD,
-
-    /// Run after loading the build/deps logs.
-    RUN_AFTER_LOGS,
-  } when;
-
-  /// Implementation of the tool.
-  NinjaMain::ToolFunc func;
-};
-
-/// Print usage information.
-void Usage(const BuildConfig& config) {
-  fprintf(stderr,
-"usage: ninja [options] [targets...]\n"
-"\n"
-"if targets are unspecified, builds the 'default' target (see manual).\n"
-"\n"
-"options:\n"
-"  --version      print ninja version (\"%s\")\n"
-"  -v, --verbose  show all command lines while building\n"
-"  --quiet        don't show progress status, just command output\n"
-"\n"
-"  -C DIR   change to DIR before doing anything else\n"
-"  -f FILE  specify input build file [default=build.ninja]\n"
-"\n"
-"  -j N     run N jobs in parallel (0 means infinity) [default=%d on this system]\n"
-"  -k N     keep going until N jobs fail (0 means infinity) [default=1]\n"
-"  -l N     do not start new jobs if the load average is greater than N\n"
-"  -n       dry run (don't run commands but act like they succeeded)\n"
-"\n"
-"  -d MODE  enable debugging (use '-d list' to list modes)\n"
-"  -t TOOL  run a subtool (use '-t list' to list subtools)\n"
-"    terminates toplevel options; further flags are passed to the tool\n"
-"  -w FLAG  adjust warnings (use '-w list' to list warnings)\n",
-          kNinjaVersion, config.parallelism);
-}
-
-/// Choose a default value for the -j (parallelism) flag.
-int GuessParallelism() {
-  switch (int processors = GetProcessorCount()) {
-  case 0:
-  case 1:
-    return 2;
-  case 2:
-    return 3;
-  default:
-    return processors + 2;
-  }
-}
-
-/// Rebuild the build manifest, if necessary.
-/// If \arg silenty_dry_run is true, do not modify anything on disk.
-/// Returns true if the manifest was rebuilt.
-bool NinjaMain::RebuildManifest(std::string* err, bool silent_dry_run) {
-  std::string path = config_->input_file;
-  if (path.empty()) {
-    *err = "empty path";
-    return false;
-  }
-
-  uint64_t slash_bits;  // Unused because this path is only used for lookup.
-  CanonicalizePath(&path, &slash_bits);
-  Node* node = state_.LookupNode(path);
-  if (!node)
-    return false;
-
-  BuildConfig config = *config_;
-  if (silent_dry_run) {
-    config.verbosity = BuildConfig::QUIET;
-    config.dry_run = true;
-  }
-
-  Builder builder(&state_, config, &build_log_, &deps_log_, &disk_interface_,
-                  status(), start_time_millis_);
-
-  if (!builder.AddTarget(node, err))
-    return false;
-
-  if (builder.AlreadyUpToDate())
-    return false;  // Not an error, but we didn't rebuild.
-
-  if (!builder.Build(err))
-    return false;
-
-  // The manifest was only rebuilt if it is now dirty (it may have been cleaned
-  // by a restat).
-  if (!node->dirty()) {
-    // Reset the state to prevent problems like
-    // https://github.com/ninja-build/ninja/issues/874
-    state_.Reset();
-    return false;
-  }
-
-  return true;
-}
-
-Node* NinjaMain::CollectTarget(const char* cpath, string* err) {
-  string path = cpath;
-  if (path.empty()) {
-    *err = "empty path";
-    return NULL;
-  }
-  uint64_t slash_bits;
-  CanonicalizePath(&path, &slash_bits);
-
-  // Special syntax: "foo.cc^" means "the first output of foo.cc".
-  bool first_dependent = false;
-  if (!path.empty() && path[path.size() - 1] == '^') {
-    path.resize(path.size() - 1);
-    first_dependent = true;
-  }
-
-  Node* node = state_.LookupNode(path);
-  if (node) {
-    if (first_dependent) {
-      if (node->out_edges().empty()) {
-        Node* rev_deps = deps_log_.GetFirstReverseDepsNode(node);
-        if (!rev_deps) {
-          *err = "'" + path + "' has no out edge";
-          return NULL;
-        }
-        node = rev_deps;
-      } else {
-        Edge* edge = node->out_edges()[0];
-        if (edge->outputs_.empty()) {
-          edge->Dump();
-          Fatal("edge has no outputs");
-        }
-        node = edge->outputs_[0];
-      }
-    }
-    return node;
-  } else {
-    *err =
-        "unknown target '" + Node::PathDecanonicalized(path, slash_bits) + "'";
-    if (path == "clean") {
-      *err += ", did you mean 'ninja -t clean'?";
-    } else if (path == "help") {
-      *err += ", did you mean 'ninja -h'?";
-    } else {
-      Node* suggestion = state_.SpellcheckNode(path);
-      if (suggestion) {
-        *err += ", did you mean '" + suggestion->path() + "'?";
-      }
-    }
-    return NULL;
-  }
-}
-
-bool NinjaMain::CollectTargetsFromArgs(int argc, char* argv[],
-                                       vector<Node*>* targets, string* err) {
-  if (argc == 0) {
-    *targets = state_.DefaultNodes(err);
-    return err->empty();
-  }
-
-  for (int i = 0; i < argc; ++i) {
-    Node* node = CollectTarget(argv[i], err);
-    if (node == NULL)
-      return false;
-    targets->push_back(node);
-  }
-  return true;
-}
-
-int NinjaMain::ToolGraph(const Options* options, int argc, char* argv[]) {
-  vector<Node*> nodes;
-  string err;
-  if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
-    Error("%s", err.c_str());
-    return 1;
-  }
-
-  GraphViz graph(&state_, &disk_interface_);
-  graph.Start();
-  for (vector<Node*>::const_iterator n = nodes.begin(); n != nodes.end(); ++n)
-    graph.AddTarget(*n);
-  graph.Finish();
-
-  return 0;
-}
-
-int NinjaMain::ToolQuery(const Options* options, int argc, char* argv[]) {
-  if (argc == 0) {
-    Error("expected a target to query");
-    return 1;
-  }
-
-  DyndepLoader dyndep_loader(&state_, &disk_interface_);
-
-  for (int i = 0; i < argc; ++i) {
-    string err;
-    Node* node = CollectTarget(argv[i], &err);
-    if (!node) {
-      Error("%s", err.c_str());
-      return 1;
-    }
-
-    printf("%s:\n", node->path().c_str());
-    if (Edge* edge = node->in_edge()) {
-      if (edge->dyndep_ && edge->dyndep_->dyndep_pending()) {
-        if (!dyndep_loader.LoadDyndeps(edge->dyndep_, &err)) {
-          Warning("%s\n", err.c_str());
-        }
-      }
-      printf("  input: %s\n", edge->rule_->name().c_str());
-      for (int in = 0; in < (int)edge->inputs_.size(); in++) {
-        const char* label = "";
-        if (edge->is_implicit(in))
-          label = "| ";
-        else if (edge->is_order_only(in))
-          label = "|| ";
-        printf("    %s%s\n", label, edge->inputs_[in]->path().c_str());
-      }
-      if (!edge->validations_.empty()) {
-        printf("  validations:\n");
-        for (std::vector<Node*>::iterator validation = edge->validations_.begin();
-             validation != edge->validations_.end(); ++validation) {
-          printf("    %s\n", (*validation)->path().c_str());
-        }
-      }
-    }
-    printf("  outputs:\n");
-    for (vector<Edge*>::const_iterator edge = node->out_edges().begin();
-         edge != node->out_edges().end(); ++edge) {
-      for (vector<Node*>::iterator out = (*edge)->outputs_.begin();
-           out != (*edge)->outputs_.end(); ++out) {
-        printf("    %s\n", (*out)->path().c_str());
-      }
-    }
-    const std::vector<Edge*> validation_edges = node->validation_out_edges();
-    if (!validation_edges.empty()) {
-      printf("  validation for:\n");
-      for (std::vector<Edge*>::const_iterator edge = validation_edges.begin();
-           edge != validation_edges.end(); ++edge) {
-        for (vector<Node*>::iterator out = (*edge)->outputs_.begin();
-             out != (*edge)->outputs_.end(); ++out) {
-          printf("    %s\n", (*out)->path().c_str());
-        }
-      }
-    }
-  }
-  return 0;
-}
-
-#if defined(NINJA_HAVE_BROWSE)
-int NinjaMain::ToolBrowse(const Options* options, int argc, char* argv[]) {
-  RunBrowsePython(&state_, ninja_command_, config_->input_file.c_str(), argc,
-                  argv);
-  // If we get here, the browse failed.
-  return 1;
-}
-#else
-int NinjaMain::ToolBrowse(const Options*, int, char**) {
-  Fatal("browse tool not supported on this platform");
-  return 1;
-}
-#endif
-
-#if defined(_WIN32)
-int NinjaMain::ToolMSVC(const Options* options, int argc, char* argv[]) {
-  // Reset getopt: push one argument onto the front of argv, reset optind.
-  argc++;
-  argv--;
-  optind = 0;
-  return MSVCHelperMain(argc, argv);
-}
-#endif
-
-int ToolTargetsList(const vector<Node*>& nodes, int depth, int indent) {
-  for (vector<Node*>::const_iterator n = nodes.begin();
-       n != nodes.end();
-       ++n) {
-    for (int i = 0; i < indent; ++i)
-      printf("  ");
-    const char* target = (*n)->path().c_str();
-    if ((*n)->in_edge()) {
-      printf("%s: %s\n", target, (*n)->in_edge()->rule_->name().c_str());
-      if (depth > 1 || depth <= 0)
-        ToolTargetsList((*n)->in_edge()->inputs_, depth - 1, indent + 1);
-    } else {
-      printf("%s\n", target);
-    }
-  }
-  return 0;
-}
-
-int ToolTargetsSourceList(State* state) {
-  for (vector<Edge*>::iterator e = state->edges_.begin();
-       e != state->edges_.end(); ++e) {
-    for (vector<Node*>::iterator inps = (*e)->inputs_.begin();
-         inps != (*e)->inputs_.end(); ++inps) {
-      if (!(*inps)->in_edge())
-        printf("%s\n", (*inps)->path().c_str());
-    }
-  }
-  return 0;
-}
-
-int ToolTargetsList(State* state, const string& rule_name) {
-  set<string> rules;
-
-  // Gather the outputs.
-  for (vector<Edge*>::iterator e = state->edges_.begin();
-       e != state->edges_.end(); ++e) {
-    if ((*e)->rule_->name() == rule_name) {
-      for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
-           out_node != (*e)->outputs_.end(); ++out_node) {
-        rules.insert((*out_node)->path());
-      }
-    }
-  }
-
-  // Print them.
-  for (set<string>::const_iterator i = rules.begin();
-       i != rules.end(); ++i) {
-    printf("%s\n", (*i).c_str());
-  }
-
-  return 0;
-}
-
-int ToolTargetsList(State* state) {
-  for (vector<Edge*>::iterator e = state->edges_.begin();
-       e != state->edges_.end(); ++e) {
-    for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
-         out_node != (*e)->outputs_.end(); ++out_node) {
-      printf("%s: %s\n",
-             (*out_node)->path().c_str(),
-             (*e)->rule_->name().c_str());
-    }
-  }
-  return 0;
-}
-
-int NinjaMain::ToolDeps(const Options* options, int argc, char** argv) {
-  vector<Node*> nodes;
-  if (argc == 0) {
-    for (vector<Node*>::const_iterator ni = deps_log_.nodes().begin();
-         ni != deps_log_.nodes().end(); ++ni) {
-      if (DepsLog::IsDepsEntryLiveFor(*ni))
-        nodes.push_back(*ni);
-    }
-  } else {
-    string err;
-    if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
-      Error("%s", err.c_str());
-      return 1;
-    }
-  }
-
-  RealDiskInterface disk_interface;
-  for (vector<Node*>::iterator it = nodes.begin(), end = nodes.end();
-       it != end; ++it) {
-    DepsLog::Deps* deps = deps_log_.GetDeps(*it);
-    if (!deps) {
-      printf("%s: deps not found\n", (*it)->path().c_str());
-      continue;
-    }
-
-    string err;
-    TimeStamp mtime = disk_interface.Stat((*it)->path(), &err);
-    if (mtime == -1)
-      Error("%s", err.c_str());  // Log and ignore Stat() errors;
-    printf("%s: #deps %d, deps mtime %" PRId64 " (%s)\n",
-           (*it)->path().c_str(), deps->node_count, deps->mtime,
-           (!mtime || mtime > deps->mtime ? "STALE":"VALID"));
-    for (int i = 0; i < deps->node_count; ++i)
-      printf("    %s\n", deps->nodes[i]->path().c_str());
-    printf("\n");
-  }
-
-  return 0;
-}
-
-int NinjaMain::ToolMissingDeps(const Options* options, int argc, char** argv) {
-  vector<Node*> nodes;
-  string err;
-  if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
-    Error("%s", err.c_str());
-    return 1;
-  }
-  RealDiskInterface disk_interface;
-  MissingDependencyPrinter printer;
-  MissingDependencyScanner scanner(&printer, &deps_log_, &state_,
-                                   &disk_interface);
-  for (vector<Node*>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
-    scanner.ProcessNode(*it);
-  }
-  scanner.PrintStats();
-  if (scanner.HadMissingDeps())
-    return 3;
-  return 0;
-}
-
-int NinjaMain::ToolTargets(const Options* options, int argc, char* argv[]) {
-  int depth = 1;
-  if (argc >= 1) {
-    string mode = argv[0];
-    if (mode == "rule") {
-      string rule;
-      if (argc > 1)
-        rule = argv[1];
-      if (rule.empty())
-        return ToolTargetsSourceList(&state_);
-      else
-        return ToolTargetsList(&state_, rule);
-    } else if (mode == "depth") {
-      if (argc > 1)
-        depth = atoi(argv[1]);
-    } else if (mode == "all") {
-      return ToolTargetsList(&state_);
-    } else {
-      const char* suggestion =
-          SpellcheckString(mode.c_str(), "rule", "depth", "all", NULL);
-      if (suggestion) {
-        Error("unknown target tool mode '%s', did you mean '%s'?",
-              mode.c_str(), suggestion);
-      } else {
-        Error("unknown target tool mode '%s'", mode.c_str());
-      }
-      return 1;
-    }
-  }
-
-  string err;
-  vector<Node*> root_nodes = state_.RootNodes(&err);
-  if (err.empty()) {
-    return ToolTargetsList(root_nodes, depth, 0);
-  } else {
-    Error("%s", err.c_str());
-    return 1;
-  }
-}
-
-int NinjaMain::ToolRules(const Options* options, int argc, char* argv[]) {
-  // Parse options.
-
-  // The rules tool uses getopt, and expects argv[0] to contain the name of
-  // the tool, i.e. "rules".
-  argc++;
-  argv--;
-
-  bool print_description = false;
-
-  optind = 1;
-  int opt;
-  while ((opt = getopt(argc, argv, const_cast<char*>("hd"))) != -1) {
-    switch (opt) {
-    case 'd':
-      print_description = true;
-      break;
-    case 'h':
-    default:
-      printf("usage: ninja -t rules [options]\n"
-             "\n"
-             "options:\n"
-             "  -d     also print the description of the rule\n"
-             "  -h     print this message\n"
-             );
-    return 1;
-    }
-  }
-  argv += optind;
-  argc -= optind;
-
-  // Print rules
-
-  for (const auto& pair : state_.bindings().GetRules()) {
-    printf("%s", pair.first.c_str());
-    if (print_description) {
-    const Rule* rule = pair.second.get();
-    const EvalString* description = rule->GetBinding("description");
-    if (description != NULL) {
-        printf(": %s", description->Unparse().c_str());
-      }
-    }
-    printf("\n");
-    fflush(stdout);
-  }
-  return 0;
-}
-
-#ifdef _WIN32
-int NinjaMain::ToolWinCodePage(const Options* options, int argc, char* argv[]) {
-  if (argc != 0) {
-    printf("usage: ninja -t wincodepage\n");
-    return 1;
-  }
-  printf("Build file encoding: %s\n", GetACP() == CP_UTF8? "UTF-8" : "ANSI");
-  return 0;
-}
-#endif
-
-enum PrintCommandMode { PCM_Single, PCM_All };
-void PrintCommands(Edge* edge, EdgeSet* seen, PrintCommandMode mode) {
-  if (!edge)
-    return;
-  if (!seen->insert(edge).second)
-    return;
-
-  if (mode == PCM_All) {
-    for (vector<Node*>::iterator in = edge->inputs_.begin();
-         in != edge->inputs_.end(); ++in)
-      PrintCommands((*in)->in_edge(), seen, mode);
-  }
-
-  if (!edge->is_phony())
-    puts(edge->EvaluateCommand().c_str());
-}
-
-int NinjaMain::ToolCommands(const Options* options, int argc, char* argv[]) {
-  // The commands tool uses getopt, and expects argv[0] to contain the name of
-  // the tool, i.e. "commands".
-  ++argc;
-  --argv;
-
-  PrintCommandMode mode = PCM_All;
-
-  optind = 1;
-  int opt;
-  while ((opt = getopt(argc, argv, const_cast<char*>("hs"))) != -1) {
-    switch (opt) {
-    case 's':
-      mode = PCM_Single;
-      break;
-    case 'h':
-    default:
-      printf("usage: ninja -t commands [options] [targets]\n"
-"\n"
-"options:\n"
-"  -s     only print the final command to build [target], not the whole chain\n"
-             );
-    return 1;
-    }
-  }
-  argv += optind;
-  argc -= optind;
-
-  vector<Node*> nodes;
-  string err;
-  if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
-    Error("%s", err.c_str());
-    return 1;
-  }
-
-  EdgeSet seen;
-  for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in)
-    PrintCommands((*in)->in_edge(), &seen, mode);
-
-  return 0;
-}
-
-void CollectInputs(Edge* edge, std::set<Edge*>* seen,
-                   std::vector<std::string>* result) {
-  if (!edge)
-    return;
-  if (!seen->insert(edge).second)
-    return;
-
-  for (vector<Node*>::iterator in = edge->inputs_.begin();
-       in != edge->inputs_.end(); ++in)
-    CollectInputs((*in)->in_edge(), seen, result);
-
-  if (!edge->is_phony()) {
-    edge->CollectInputs(true, result);
-  }
-}
-
-int NinjaMain::ToolInputs(const Options* options, int argc, char* argv[]) {
-  // The inputs tool uses getopt, and expects argv[0] to contain the name of
-  // the tool, i.e. "inputs".
-  argc++;
-  argv--;
-  optind = 1;
-  int opt;
-  const option kLongOptions[] = { { "help", no_argument, NULL, 'h' },
-                                  { NULL, 0, NULL, 0 } };
-  while ((opt = getopt_long(argc, argv, "h", kLongOptions, NULL)) != -1) {
-    switch (opt) {
-    case 'h':
-    default:
-      // clang-format off
-      printf(
-"Usage '-t inputs [options] [targets]\n"
-"\n"
-"List all inputs used for a set of targets. Note that this includes\n"
-"explicit, implicit and order-only inputs, but not validation ones.\n\n"
-"Options:\n"
-"  -h, --help   Print this message.\n");
-      // clang-format on
-      return 1;
-    }
-  }
-  argv += optind;
-  argc -= optind;
-
-  vector<Node*> nodes;
-  string err;
-  if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
-    Error("%s", err.c_str());
-    return 1;
-  }
-
-  std::set<Edge*> seen;
-  std::vector<std::string> result;
-  for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in)
-    CollectInputs((*in)->in_edge(), &seen, &result);
-
-  // Make output deterministic by sorting then removing duplicates.
-  std::sort(result.begin(), result.end());
-  result.erase(std::unique(result.begin(), result.end()), result.end());
-
-  for (size_t n = 0; n < result.size(); ++n)
-    puts(result[n].c_str());
-
-  return 0;
-}
-
-int NinjaMain::ToolClean(const Options* options, int argc, char* argv[]) {
-  // The clean tool uses getopt, and expects argv[0] to contain the name of
-  // the tool, i.e. "clean".
-  argc++;
-  argv--;
-
-  bool generator = false;
-  bool clean_rules = false;
-
-  optind = 1;
-  int opt;
-  while ((opt = getopt(argc, argv, const_cast<char*>("hgr"))) != -1) {
-    switch (opt) {
-    case 'g':
-      generator = true;
-      break;
-    case 'r':
-      clean_rules = true;
-      break;
-    case 'h':
-    default:
-      printf("usage: ninja -t clean [options] [targets]\n"
-"\n"
-"options:\n"
-"  -g     also clean files marked as ninja generator output\n"
-"  -r     interpret targets as a list of rules to clean instead\n"
-             );
-    return 1;
-    }
-  }
-  argv += optind;
-  argc -= optind;
-
-  if (clean_rules && argc == 0) {
-    Error("expected a rule to clean");
-    return 1;
-  }
-
-  Cleaner cleaner(&state_, *config_, &disk_interface_);
-  if (argc >= 1) {
-    if (clean_rules)
-      return cleaner.CleanRules(argc, argv);
-    else
-      return cleaner.CleanTargets(argc, argv);
-  } else {
-    return cleaner.CleanAll(generator);
-  }
-}
-
-int NinjaMain::ToolCleanDead(const Options* options, int argc, char* argv[]) {
-  Cleaner cleaner(&state_, *config_, &disk_interface_);
-  return cleaner.CleanDead(build_log_.entries());
-}
-
-enum EvaluateCommandMode {
-  ECM_NORMAL,
-  ECM_EXPAND_RSPFILE
-};
-std::string EvaluateCommandWithRspfile(const Edge* edge,
-                                       const EvaluateCommandMode mode) {
-  string command = edge->EvaluateCommand();
-  if (mode == ECM_NORMAL)
-    return command;
-
-  string rspfile = edge->GetUnescapedRspfile();
-  if (rspfile.empty())
-    return command;
-
-  size_t index = command.find(rspfile);
-  if (index == 0 || index == string::npos || command[index - 1] != '@')
-    return command;
-
-  string rspfile_content = edge->GetBinding("rspfile_content");
-  size_t newline_index = 0;
-  while ((newline_index = rspfile_content.find('\n', newline_index)) !=
-         string::npos) {
-    rspfile_content.replace(newline_index, 1, 1, ' ');
-    ++newline_index;
-  }
-  command.replace(index - 1, rspfile.length() + 1, rspfile_content);
-  return command;
-}
-
-void printCompdb(const char* const directory, const Edge* const edge,
-                 const EvaluateCommandMode eval_mode) {
-  printf("\n  {\n    \"directory\": \"");
-  PrintJSONString(directory);
-  printf("\",\n    \"command\": \"");
-  PrintJSONString(EvaluateCommandWithRspfile(edge, eval_mode));
-  printf("\",\n    \"file\": \"");
-  PrintJSONString(edge->inputs_[0]->path());
-  printf("\",\n    \"output\": \"");
-  PrintJSONString(edge->outputs_[0]->path());
-  printf("\"\n  }");
-}
-
-int NinjaMain::ToolCompilationDatabase(const Options* options, int argc,
-                                       char* argv[]) {
-  // The compdb tool uses getopt, and expects argv[0] to contain the name of
-  // the tool, i.e. "compdb".
-  argc++;
-  argv--;
-
-  EvaluateCommandMode eval_mode = ECM_NORMAL;
-
-  optind = 1;
-  int opt;
-  while ((opt = getopt(argc, argv, const_cast<char*>("hx"))) != -1) {
-    switch(opt) {
-      case 'x':
-        eval_mode = ECM_EXPAND_RSPFILE;
-        break;
-
-      case 'h':
-      default:
-        printf(
-            "usage: ninja -t compdb [options] [rules]\n"
-            "\n"
-            "options:\n"
-            "  -x     expand @rspfile style response file invocations\n"
-            );
-        return 1;
-    }
-  }
-  argv += optind;
-  argc -= optind;
-
-  bool first = true;
-  vector<char> cwd;
-  char* success = NULL;
-
-  do {
-    cwd.resize(cwd.size() + 1024);
-    errno = 0;
-    success = getcwd(&cwd[0], cwd.size());
-  } while (!success && errno == ERANGE);
-  if (!success) {
-    Error("cannot determine working directory: %s", strerror(errno));
-    return 1;
-  }
-
-  putchar('[');
-  for (vector<Edge*>::iterator e = state_.edges_.begin();
-       e != state_.edges_.end(); ++e) {
-    if ((*e)->inputs_.empty())
-      continue;
-    if (argc == 0) {
-      if (!first) {
-        putchar(',');
-      }
-      printCompdb(&cwd[0], *e, eval_mode);
-      first = false;
-    } else {
-      for (int i = 0; i != argc; ++i) {
-        if ((*e)->rule_->name() == argv[i]) {
-          if (!first) {
-            putchar(',');
-          }
-          printCompdb(&cwd[0], *e, eval_mode);
-          first = false;
-        }
-      }
-    }
-  }
-
-  puts("\n]");
-  return 0;
-}
-
-int NinjaMain::ToolRecompact(const Options* options, int argc, char* argv[]) {
-  if (!EnsureBuildDirExists())
-    return 1;
-
-  if (!OpenBuildLog(/*recompact_only=*/true) ||
-      !OpenDepsLog(/*recompact_only=*/true))
-    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 =
-" 13 ,3;2!2;\n8 ,;<11!;\n5 `'<10!(2`'2!\n11 ,6;, `\\. `\\9 .,c13$ec,.\n6 "
-",2;11!>; `. ,;!2> .e8$2\".2 \"?7$e.\n <:<8!'` 2.3,.2` ,3!' ;,(?7\";2!2'<"
-"; `?6$PF ,;,\n2 `'4!8;<!3'`2 3! ;,`'2`2'3!;4!`2.`!;2 3,2 .<!2'`).\n5 3`5"
-"'2`9 `!2 `4!><3;5! J2$b,`!>;2!:2!`,d?b`!>\n26 `'-;,(<9!> $F3 )3.:!.2 d\""
-"2 ) !>\n30 7`2'<3!- \"=-='5 .2 `2-=\",!>\n25 .ze9$er2 .,cd16$bc.'\n22 .e"
-"14$,26$.\n21 z45$c .\n20 J50$c\n20 14$P\"`?34$b\n20 14$ dbc `2\"?22$?7$c"
-"\n20 ?18$c.6 4\"8?4\" c8$P\n9 .2,.8 \"20$c.3 ._14 J9$\n .2,2c9$bec,.2 `?"
-"21$c.3`4%,3%,3 c8$P\"\n22$c2 2\"?21$bc2,.2` .2,c7$P2\",cb\n23$b bc,.2\"2"
-"?14$2F2\"5?2\",J5$P\" ,zd3$\n24$ ?$3?%3 `2\"2?12$bcucd3$P3\"2 2=7$\n23$P"
-"\" ,3;<5!>2;,. `4\"6?2\"2 ,9;, `\"?2$\n";
-  int count = 0;
-  for (const char* p = urtle; *p; p++) {
-    if ('0' <= *p && *p <= '9') {
-      count = count*10 + *p - '0';
-    } else {
-      for (int i = 0; i < max(count, 1); ++i)
-        printf("%c", *p);
-      count = 0;
-    }
-  }
-  return 0;
-}
-
-int NinjaMain::ToolServer(const Options* options, int argc, char* argv[]) {
-  if (argc == 0 || !strcmp(argv[0], "help")) {
-    printf(
-        "usage: ninja -t server <command>\n"
-        "\n"
-        "commands:\n"
-        "  help      print this message\n"
-        "  status    print server status\n"
-        "  stop      stop server\n"
-        "  pid       print server pid, or -1\n");
-    return 1;
-  }
-  std::string work_dir = GetCurrentDir();
-  const char* command = argv[0];
-  if (!strcmp(command, "status")) {
-    PersistentMode::Status status = PersistentMode::GetCurrentProcessStatus();
-    if (status == PersistentMode::Disabled)
-      printf("persistent mode disabled\n");
-    else if (status == PersistentMode::IsClient) {
-      bool running = PersistentMode::Client().IsServerRunning(work_dir);
-      if (running)
-        printf("server is running for %s\n", work_dir.c_str());
-      else
-        printf("no server found for %s\n", work_dir.c_str());
-    } else {
-      printf("this is a server process for %s\n", work_dir.c_str());
-    }
-    return 0;
-  }
-
-  if (!strcmp(command, "stop")) {
-    std::string err;
-    bool stopped = PersistentMode::Client().StopServer(work_dir, &err);
-    if (stopped)
-      printf("server stopped for %s\n", work_dir.c_str());
-    else
-      printf("no server found for %s\n", work_dir.c_str());
-    return 0;
-  }
-
-  if (!strcmp(command, "pid")) {
-    int server_pid = PersistentMode::Client().GetServerPidFor(work_dir);
-    printf("%d\n", server_pid);
-    return 0;
-  }
-
-  fprintf(stderr, "Invalid command %s, see `-t server help`.\n", command);
-  return 1;
-}
-
-/// Find the function to execute for \a tool_name and return it via \a func.
-/// Returns a Tool, or NULL if Ninja should exit.
-const Tool* ChooseTool(const string& tool_name) {
-  static const Tool kTools[] = {
-    { "browse", "browse dependency graph in a web browser",
-      Tool::RUN_AFTER_LOAD, &NinjaMain::ToolBrowse },
-#ifdef _WIN32
-    { "msvc", "build helper for MSVC cl.exe (DEPRECATED)",
-      Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolMSVC },
-#endif
-    { "clean", "clean built files", Tool::RUN_AFTER_LOAD,
-      &NinjaMain::ToolClean },
-    { "commands", "list all commands required to rebuild given targets",
-      Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCommands },
-    { "inputs", "list all inputs required to rebuild given targets",
-      Tool::RUN_AFTER_LOAD, &NinjaMain::ToolInputs },
-    { "deps", "show dependencies stored in the deps log", Tool::RUN_AFTER_LOGS,
-      &NinjaMain::ToolDeps },
-    { "missingdeps", "check deps log dependencies on generated files",
-      Tool::RUN_AFTER_LOGS, &NinjaMain::ToolMissingDeps },
-    { "graph", "output graphviz dot file for targets", Tool::RUN_AFTER_LOAD,
-      &NinjaMain::ToolGraph },
-    { "query", "show inputs/outputs for a path", Tool::RUN_AFTER_LOGS,
-      &NinjaMain::ToolQuery },
-    { "targets", "list targets by their rule or depth in the DAG",
-      Tool::RUN_AFTER_LOAD, &NinjaMain::ToolTargets },
-    { "compdb", "dump JSON compilation database to stdout",
-      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 },
-    { "server", "interact with persistent server", Tool::RUN_AFTER_FLAGS,
-      &NinjaMain::ToolServer },
-#ifdef _WIN32
-    { "wincodepage", "print the Windows code page used by ninja",
-      Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolWinCodePage },
-#endif
-    { NULL, NULL, Tool::RUN_AFTER_FLAGS, NULL }
-  };
-
-  if (tool_name == "list") {
-    printf("ninja subtools:\n");
-    for (const Tool* tool = &kTools[0]; tool->name; ++tool) {
-      if (tool->desc)
-        printf("%11s  %s\n", tool->name, tool->desc);
-    }
-    return NULL;
-  }
-
-  for (const Tool* tool = &kTools[0]; tool->name; ++tool) {
-    if (tool->name == tool_name)
-      return tool;
-  }
-
-  vector<const char*> words;
-  for (const Tool* tool = &kTools[0]; tool->name; ++tool)
-    words.push_back(tool->name);
-  const char* suggestion = SpellcheckStringV(tool_name, words);
-  if (suggestion) {
-    Fatal("unknown tool '%s', did you mean '%s'?",
-          tool_name.c_str(), suggestion);
-  } else {
-    Fatal("unknown tool '%s'", tool_name.c_str());
-  }
-  return NULL;  // Not reached.
-}
-
-/// Enable a debugging mode.  Returns false if Ninja should exit instead
-/// of continuing.
-bool DebugEnable(const string& name) {
-  if (name == "list") {
-    printf("debugging modes:\n"
-"  stats        print operation counts/timing info\n"
-"  explain      explain what caused a command to execute\n"
-"  keepdepfile  don't delete depfiles after they're read by ninja\n"
-"  keeprsp      don't delete @response files on success\n"
-#ifdef _WIN32
-"  nostatcache  don't batch stat() calls per directory and cache them\n"
-#endif
-"multiple modes can be enabled via -d FOO -d BAR\n");
-    return false;
-  } else if (name == "stats") {
-    g_metrics = new Metrics;
-    return true;
-  } else if (name == "explain") {
-    g_explaining = true;
-    return true;
-  } else if (name == "keepdepfile") {
-    g_keep_depfile = true;
-    return true;
-  } else if (name == "keeprsp") {
-    g_keep_rsp = true;
-    return true;
-  } else if (name == "nostatcache") {
-    g_experimental_statcache = false;
-    return true;
-  } else {
-    const char* suggestion =
-        SpellcheckString(name.c_str(),
-                         "stats", "explain", "keepdepfile", "keeprsp",
-                         "nostatcache", NULL);
-    if (suggestion) {
-      Error("unknown debug setting '%s', did you mean '%s'?",
-            name.c_str(), suggestion);
-    } else {
-      Error("unknown debug setting '%s'", name.c_str());
-    }
-    return false;
-  }
-}
-
-/// 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"
-"  phonycycle={err,warn}  phony build statement references itself\n"
-    );
-    return false;
-  } else if (name == "dupbuild=err") {
-    options->dupe_edges_should_err = true;
-    return true;
-  } else if (name == "dupbuild=warn") {
-    options->dupe_edges_should_err = false;
-    return true;
-  } else if (name == "phonycycle=err") {
-    options->phony_cycle_should_err = true;
-    return true;
-  } else if (name == "phonycycle=warn") {
-    options->phony_cycle_should_err = false;
-    return true;
-  } else if (name == "depfilemulti=err" ||
-             name == "depfilemulti=warn") {
-    Warning("deprecated warning 'depfilemulti'");
-    return true;
-  } else {
-    const char* suggestion =
-        SpellcheckString(name.c_str(), "dupbuild=err", "dupbuild=warn",
-                         "phonycycle=err", "phonycycle=warn", NULL);
-    if (suggestion) {
-      Error("unknown warning flag '%s', did you mean '%s'?",
-            name.c_str(), suggestion);
-    } else {
-      Error("unknown warning flag '%s'", name.c_str());
-    }
-    return false;
-  }
-}
-
-bool NinjaMain::OpenBuildLog(bool recompact_only) {
-  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 false;
-  }
-  if (!err.empty()) {
-    // 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());
-    return success;
-  }
-
-  if (!config_->dry_run) {
-    if (!build_log_.OpenForWrite(log_path, *this, &err)) {
-      Error("opening build log: %s", err.c_str());
-      return false;
-    }
-  }
-
-  return true;
-}
-
-/// Open the deps log: load it, then open for writing.
-/// @return false on error.
-bool NinjaMain::OpenDepsLog(bool recompact_only) {
-  string path = ".ninja_deps";
-  if (!build_dir_.empty())
-    path = build_dir_ + "/" + path;
-
-  string 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 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());
-    return success;
-  }
-
-  if (!config_->dry_run) {
-    if (!deps_log_.OpenForWrite(path, &err)) {
-      Error("opening deps log: %s", err.c_str());
-      return false;
-    }
-  }
-
-  return true;
-}
-
-void NinjaMain::DumpMetrics() {
-  g_metrics->Report();
-
-  printf("\n");
-  int count = (int)state_.paths_.size();
-  int buckets = (int)state_.paths_.bucket_count();
-  printf("path->node hash load %.2f (%d entries / %d buckets)\n",
-         count / (double) buckets, count, buckets);
-
-  printf("paths: %zu, edges: %zu\n", state_.paths_.size(),
-         state_.edges_.size());
-  printf("build_log_entries %zu, deps_log_paths %zu\n", build_log_.size(),
-         deps_log_.size());
-}
-
-bool NinjaMain::EnsureBuildDirExists() {
-  build_dir_ = state_.bindings().LookupVariable("builddir");
-  if (!build_dir_.empty() && !config_->dry_run) {
-    if (!disk_interface_.MakeDirs(build_dir_ + "/.") && errno != EEXIST) {
-      Error("creating build directory %s: %s",
-            build_dir_.c_str(), strerror(errno));
-      return false;
-    }
-  }
-  return true;
-}
-
-int NinjaMain::RunBeforeBuild(const Options& options, int argc, char** argv) {
-  // Fully reset NinjaMain instance on each run. This gets rid of
-  // the currently loaded manifest, if there is one, avoiding unexpected
-  // errors like:
-  //
-  // ```
-  // [0/1](1) Regenerating ninja files
-  // ninja: error: build.ninja:3: duplicate rule 'gn'
-  // rule gn
-  //      ^ near here
-  // ```
-  Reset();
-
-  ManifestParserOptions parser_opts;
-  if (options.dupe_edges_should_err) {
-    parser_opts.dupe_edge_action_ = kDupeEdgeActionError;
-  }
-  if (options.phony_cycle_should_err) {
-    parser_opts.phony_cycle_action_ = kPhonyCycleActionError;
-  }
-
-  ManifestParser parser(&state_, &path_recording_disk_interface_, parser_opts);
-  std::string err;
-  if (!parser.Load(config_->input_file.c_str(), &err)) {
-    status_->Error("%s", err.c_str());
-    return 1;
-  }
-
-  if (options.tool && options.tool->when == Tool::RUN_AFTER_LOAD)
-    return (this->*options.tool->func)(&options, argc, argv);
-
-  if (!EnsureBuildDirExists() || !OpenBuildLog() || !OpenDepsLog())
-    return 1;
-
-  if (options.tool && options.tool->when == Tool::RUN_AFTER_LOGS)
-    return (this->*options.tool->func)(&options, argc, argv);
-
-  return kBuildCanProceed;
-}
-
-int NinjaMain::RunBuild(int argc, char** argv) {
-  string err;
-  vector<Node*> targets;
-  if (!CollectTargetsFromArgs(argc, argv, &targets, &err)) {
-    status_->Error("%s", err.c_str());
-    return 1;
-  }
-
-  disk_interface_.AllowStatCache(g_experimental_statcache);
-
-  Builder builder(&state_, *config_, &build_log_, &deps_log_, &disk_interface_,
-                  status(), start_time_millis_);
-  {
-    METRIC_RECORD("dependency scan");
-    for (size_t i = 0; i < targets.size(); ++i) {
-      if (!builder.AddTarget(targets[i], &err)) {
-        if (!err.empty()) {
-          status_->Error("%s", err.c_str());
-          return 1;
-        } else {
-          // Added a target that is already up-to-date; not really
-          // an error.
-        }
-      }
-    }
-
-    if (builder.AlreadyUpToDate()) {
-      status_->Info("no work to do.");
-      return 0;
-    }
-  }
-
-  if (!builder.Build(&err)) {
-    status_->Info("build stopped: %s.", err.c_str());
-    if (err.find("interrupted by user") != string::npos) {
-      return 2;
-    }
-    return 1;
-  }
-
-  return 0;
-}
-
-#ifdef _MSC_VER
-
-/// This handler processes fatal crashes that you can't catch
-/// Test example: C++ exception in a stack-unwind-block
-/// Real-world example: ninja launched a compiler to process a tricky
-/// C++ input file. The compiler got itself into a state where it
-/// generated 3 GB of output and caused ninja to crash.
-void TerminateHandler() {
-  CreateWin32MiniDump(NULL);
-  Fatal("terminate handler called");
-}
-
-/// On Windows, we want to prevent error dialogs in case of exceptions.
-/// This function handles the exception, and writes a minidump.
-int ExceptionFilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
-  Error("exception: 0x%X", code);  // e.g. EXCEPTION_ACCESS_VIOLATION
-  fflush(stderr);
-  CreateWin32MiniDump(ep);
-  return EXCEPTION_EXECUTE_HANDLER;
-}
-
-#endif  // _MSC_VER
-
-class DeferGuessParallelism {
- public:
-  bool needGuess;
-  BuildConfig* config;
-
-  DeferGuessParallelism(BuildConfig* config)
-      : needGuess(true), config(config) {}
-
-  void Refresh() {
-    if (needGuess) {
-      needGuess = false;
-      config->parallelism = GuessParallelism();
-    }
-  }
-  ~DeferGuessParallelism() { Refresh(); }
-};
-
-/// Parse argv for command-line options.
-/// Returns an exit code, or -1 if Ninja should continue.
-int ReadFlags(int* argc, char*** argv,
-              Options* options, BuildConfig* config) {
-  DeferGuessParallelism deferGuessParallelism(config);
-
-  enum { OPT_VERSION = 1, OPT_QUIET = 2 };
-  const option kLongOptions[] = {
-    { "help", no_argument, NULL, 'h' },
-    { "version", no_argument, NULL, OPT_VERSION },
-    { "verbose", no_argument, NULL, 'v' },
-    { "quiet", no_argument, NULL, OPT_QUIET },
-    { NULL, 0, NULL, 0 }
-  };
-
-  // First grab values from environment variables.
-  config->environment = EnvironmentBlock::CreateFromCurrentEnvironment();
-
-  int opt;
-  while (!options->tool &&
-         (opt = getopt_long(*argc, *argv, "d:f:j:k:l:nt:vw:C:h", kLongOptions,
-                            NULL)) != -1) {
-    switch (opt) {
-      case 'd':
-        if (!DebugEnable(optarg))
-          return 1;
-        break;
-      case 'f':
-        config->input_file = optarg;
-        break;
-      case 'j': {
-        char* end;
-        int value = strtol(optarg, &end, 10);
-        if (*end != 0 || value < 0)
-          Fatal("invalid -j parameter");
-
-        // We want to run N jobs in parallel. For N = 0, INT_MAX
-        // is close enough to infinite for most sane builds.
-        config->parallelism = value > 0 ? value : INT_MAX;
-        deferGuessParallelism.needGuess = false;
-        break;
-      }
-      case 'k': {
-        char* end;
-        int value = strtol(optarg, &end, 10);
-        if (*end != 0)
-          Fatal("-k parameter not numeric; did you mean -k 0?");
-
-        // We want to go until N jobs fail, which means we should allow
-        // N failures and then stop.  For N <= 0, INT_MAX is close enough
-        // to infinite for most sane builds.
-        config->failures_allowed = value > 0 ? value : INT_MAX;
-        break;
-      }
-      case 'l': {
-        char* end;
-        double value = strtod(optarg, &end);
-        if (end == optarg)
-          Fatal("-l parameter not numeric: did you mean -l 0.0?");
-        config->max_load_average = value;
-        break;
-      }
-      case 'n':
-        config->dry_run = true;
-        break;
-      case 't':
-        options->tool = ChooseTool(optarg);
-        if (!options->tool)
-          return 0;
-        break;
-      case 'v':
-        config->verbosity = BuildConfig::VERBOSE;
-        break;
-      case OPT_QUIET:
-        config->verbosity = BuildConfig::NO_STATUS_UPDATE;
-        break;
-      case 'w':
-        if (!WarningEnable(optarg, options))
-          return 1;
-        break;
-      case 'C':
-        options->working_dir = optarg;
-        break;
-      case OPT_VERSION:
-        printf("%s\n", kNinjaVersion);
-        return 0;
-      case 'h':
-      default:
-        deferGuessParallelism.Refresh();
-        Usage(*config);
-        return 1;
-    }
-  }
-  *argv += optind;
-  *argc -= optind;
-
-  return -1;
-}
-
-NORETURN void real_main(int argc, char** argv) {
-  // Use exit() instead of return in this function to avoid potentially
-  // expensive cleanup when destructing NinjaMain.
-  BuildConfig config;
-  Options options;
-
-  // Save original arguments and current directory for persistent mode since
-  // ReadFlags() will modify them.
-  const auto original_args = RemoteArguments(argc, argv).args();
-
-  setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
-  const char* ninja_command = argv[0];
-
-  int exit_code = ReadFlags(&argc, &argv, &options, &config);
-  if (exit_code >= 0)
-    exit(exit_code);
-
-  // Always enable metrics when in persistent server mode,
-  // since the METRIC_RECORD macro probes the value of g_metrics
-  // once per execution, it must be initialized before any
-  // use of that macro to ensure everything works correctly.
-  PersistentMode::Status persistence =
-      PersistentMode::GetCurrentProcessStatus();
-
-  bool dump_metrics = !!g_metrics;
-  if (persistence == PersistentMode::IsServer && !g_metrics)
-    g_metrics = new Metrics();
-
-  NinjaMain ninja(ninja_command, config);
-
-  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
-    // subsequent commands.
-    // Don't print this if a tool is being used, so that tool output
-    // can be piped into a file without this string showing up.
-    if (!options.tool && config.verbosity != BuildConfig::NO_STATUS_UPDATE)
-        ninja.status()->Info("Entering directory `%s'", options.working_dir);
-    if (chdir(options.working_dir) < 0) {
-      Fatal("chdir to '%s' - %s", options.working_dir, strerror(errno));
-    }
-  }
-
-  if (options.tool && options.tool->when == Tool::RUN_AFTER_FLAGS) {
-    // None of the RUN_AFTER_FLAGS actually use a NinjaMain, but it's needed
-    // by other tools.
-    exit((ninja.*options.tool->func)(&options, argc, argv));
-  }
-
-  // A callable object that runs all operations prior to the build itself,
-  // which includes regenerating the build plan files if needed, loading the
-  // build graph, and answering tool requests.
-  //
-  // It returns an exit status code if no more work is needed, or the
-  // special value kBuildCanProceed to indicate that the build can proceed
-  // afterwards.
-  auto run_before_build = [&]() -> int {
-    // Limit number of rebuilds, to prevent infinite loops.
-    const int kCycleLimit = 100;
-    for (int cycle = 1; cycle <= kCycleLimit; ++cycle) {
-      int result = ninja.RunBeforeBuild(options, argc, argv);
-      if (result != kBuildCanProceed)
-        _exit(result);
-
-      // Attempt to rebuild the manifest before building anything else
-      std::string err;
-      if (ninja.RebuildManifest(&err)) {
-        // In dry_run mode the regeneration will succeed without changing the
-        // manifest forever. Better to return immediately.
-        if (config.dry_run)
-          return 0;
-        // Start the build over with the new manifest.
-        continue;
-      } else if (!err.empty()) {
-        ninja.status()->Error("rebuilding '%s': %s",
-                              ninja.config_->input_file.c_str(), err.c_str());
-        return 1;
-      }
-
-      return kBuildCanProceed;
-    }
-    ninja.status()->Error(
-        "manifest '%s' still dirty after %d tries, perhaps system time is not "
-        "set",
-        ninja.config_->input_file.c_str(), kCycleLimit);
-    return 1;
-  };
-
-  PersistentMode::BuildQuery build_query;
-  build_query.config = config;
-  build_query.debug_explaining = g_explaining;
-  build_query.debug_keep_depfile = g_keep_depfile;
-  build_query.debug_keep_rsp = g_keep_rsp;
-  build_query.debug_experimental_statcache = g_experimental_statcache;
-  build_query.dump_metrics = dump_metrics;
-
-  if (options.tool)
-    build_query.tool = options.tool->name;
-
-  for (int n = 0; n < argc; ++n) {
-    build_query.args.push_back(argv[n]);
-  }
-
-  // NOTE: For now, do not run tools in persistent client/server mode.
-  bool use_persistent_mode =
-      !options.tool && (persistence != PersistentMode::Disabled);
-
-  // Note: since the working dir has already been changed here, do not
-  // use options.working_dir, which is no longer valid if it is a relative
-  // path. Compatibility will use the current working directory as the
-  // build dir by default.
-  PersistentMode::Compatibility compatibility;
-  compatibility.SetInputFile(config.input_file);
-  compatibility.SetFlagDupeEdgesShouldErr(options.dupe_edges_should_err);
-  compatibility.SetFlagPhonyCycleShouldErr(options.phony_cycle_should_err);
-
-  if (use_persistent_mode) {
-    if (persistence == PersistentMode::IsServer) {
-      // Persistent server mode. Load the build graph and all other expensive
-      // things first. Exit immediately if there is a problem.
-      PersistentMode::Server server(compatibility);
-
-      std::string err;
-      if (!server.StartLocalServer(&err)) {
-          printf("Could not start local server, aborting: %s\n", err.c_str());
-          exit(1);
-      }
-
-      printf(
-          "\n***********************************************\n"
-          "Server starting, loading build graph...\n");
-      int result = ninja.RunBeforeBuild(options, argc, argv);
-      if (result != kBuildCanProceed)
-          exit(result);
-
-      // Print load metrics
-      printf("Manifest loading metrics\n");
-      g_metrics->load_.Report();
-
-      printf(
-          "%zu nodes, %zu edges, %zu pools\n%zu build log entries, %zu deps "
-          "log paths\n",
-          ninja.state_.paths_.size(), ninja.state_.edges_.size(),
-          ninja.state_.pools_.size(), ninja.build_log_.size(),
-          ninja.deps_log_.size());
-
-      // This callable returns true if the manifest(s) changed since the
-      // last call. Which will force a server restart.
-      auto restart_check = [&]() -> bool {
-        // A fast check that returns true if any input .ninja file was
-        // modified. Happens when the generator was called by the user
-        // before Ninja.
-        return ninja.path_recording_disk_interface_.CheckOutOfDate();
-      };
-
-      // This callable runs the part of the build and returns an exit status.
-      // or the special value PersistentMode::kServerExit to indicate that
-      // the server should exit.
-      auto do_build = [&](const PersistentMode::BuildQuery& query) -> int {
-        if (query.dump_metrics) {
-          // Do not reset the load metrics here, only the build ones.
-          g_metrics->build_.Reset();
-        }
-
-        ninja.PrepareBuild(query.config);
-
-        if (!query.tool.empty()) {
-          // Note that tools are always run on the client process because they
-          // disable persistent mode support (see below). This currently happens
-          // in the run_before_build lambda above.
-          // TODO(digit): Implement tool in the server if it makes sense.
-          fprintf(stderr,
-                  "UNIMPLEMENTED FEATURE: RUNNING TOOLS IN PERSISTENT MODE!\n");
-          return 1;
-        }
-
-        std::string err;
-        if (ninja.RebuildManifest(&err)) {
-          // In dry_run mode the regeneration will succeed without changing the
-          // manifest forever. Better to return with 0.
-          if (query.config.dry_run)
-            return 0;
-          // The manifest has been regenerated, so the build graph in this
-          // server is no longer valid. Tell it to exit so that the next
-          // client invocation will start a new instance that will read
-          // the new manifest.
-          return PersistentMode::kServerExit;
-        }
-
-        RemoteArguments targets;
-        targets.Reset(query.args);
-
-        int result = ninja.RunBuild(targets.argc(), targets.argv());
-
-        if (query.dump_metrics)
-          ninja.DumpMetrics();
-
-        return result;
-      };
-
-      printf("Server mode waiting for client requests\n");
-
-      // Now serve client requests in a loop with |do_build| as the request
-      // handler. This exits the process on completion.
-      server.RunServerThenExit(restart_check, do_build);
-      ninja.status()->Error("Server could not run or exit properly!\n");
-      exit(1);
-    } else {
-      assert(persistence == PersistentMode::IsClient);
-    }
-  }
-
-  // For regular and persistent client builds.
-  // Limit number of rebuilds, to prevent infinite loops.
-  const int kCycleLimit = 100;
-  for (int cycle = 1; cycle <= kCycleLimit; ++cycle) {
-    std::string err;
-
-    //////////////////////////////////////////////////////////
-    // Persistent client build.
-
-    if (use_persistent_mode) {
-      assert(persistence == PersistentMode::IsClient);
-      PersistentMode::Client client;
-      int result = 0;
-      if (!client.RunQuery(compatibility, build_query, &result, &err)) {
-          ninja.status()->Error(
-              "Error contacting server, falling back to local build: %s\n",
-              err.c_str());
-          // Try again with a regular build.
-          persistence = PersistentMode::Disabled;
-          continue;
-      }
-
-      if (result != PersistentMode::kServerExit) {
-          // Normal termination, exit with status code from server.
-          _exit(result);
-      }
-      // The server exited after rebuilding the manifest, loop to
-      // create a new server instance that loads the new manifest
-      // then build with it.
-      continue;
-    }
-
-    //////////////////////////////////////////////////////////
-    // Normal (Non-persistent) builds.
-
-    int result = ninja.RunBeforeBuild(options, argc, argv);
-    if (result != kBuildCanProceed)
-      _exit(result);
-
-    // Attempt to rebuild the manifest before building anything else
-    if (ninja.RebuildManifest(&err)) {
-      // In dry_run mode the regeneration will succeed without changing the
-      // manifest forever. Better to return immediately.
-      if (config.dry_run)
-          _exit(0);
-      // Start the build over with the new manifest.
-      continue;
-    } else if (!err.empty()) {
-      ninja.status()->Error("rebuilding '%s': %s", config.input_file.c_str(),
-                            err.c_str());
-      exit(1);
-    }
-
-    result = ninja.RunBuild(argc, argv);
-    if (g_metrics)
-      ninja.DumpMetrics();
-    _exit(result);
-  }
-
-  ninja.status()->Error(
-      "manifest '%s' still dirty after %d tries, perhaps system time is not "
-      "set",
-      config.input_file.c_str(), kCycleLimit);
-  exit(1);
-}
-
-}  // anonymous namespace
-
-int main(int argc, char** argv) {
-#if defined(_MSC_VER)
-  // Set a handler to catch crashes not caught by the __try..__except
-  // block (e.g. an exception in a stack-unwind-block).
-  std::set_terminate(TerminateHandler);
-  __try {
-    // Running inside __try ... __except suppresses any Windows error
-    // dialogs for errors such as bad_alloc.
-    real_main(argc, argv);
-  }
-  __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
-    // Common error situations return exitCode=1. 2 was chosen to
-    // indicate a more serious problem.
-    return 2;
-  }
-#else
-  real_main(argc, argv);
-#endif
-}
diff --git a/src/ninja_test.cc b/src/ninja_test.cc
deleted file mode 100644
index 44ae03a..0000000
--- a/src/ninja_test.cc
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright 2013 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 <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifdef _WIN32
-#include "getopt.h"
-#elif defined(_AIX)
-#include "getopt.h"
-#include <unistd.h>
-#else
-#include <getopt.h>
-#endif
-
-#include "test.h"
-#include "line_printer.h"
-
-using namespace std;
-
-struct RegisteredTest {
-  testing::Test* (*factory)();
-  const char *name;
-  bool should_run;
-};
-// This can't be a vector because tests call RegisterTest from static
-// initializers and the order static initializers run it isn't specified. So
-// the vector constructor isn't guaranteed to run before all of the
-// RegisterTest() calls.
-static RegisteredTest tests[10000];
-testing::Test* g_current_test;
-static int ntests;
-static LinePrinter printer;
-
-void RegisterTest(testing::Test* (*factory)(), const char* name) {
-  tests[ntests].factory = factory;
-  tests[ntests++].name = name;
-}
-
-namespace {
-string StringPrintf(const char* format, ...) {
-  const int N = 1024;
-  char buf[N];
-
-  va_list ap;
-  va_start(ap, format);
-  vsnprintf(buf, N, format, ap);
-  va_end(ap);
-
-  return buf;
-}
-
-void Usage() {
-  fprintf(stderr,
-"usage: ninja_tests [options]\n"
-"\n"
-"options:\n"
-"  --gtest_filter=POSITIVE_PATTERN[-NEGATIVE_PATTERN]\n"
-"      Run tests whose names match the positive but not the negative pattern.\n"
-"      '*' matches any substring. (gtest's ':', '?' are not implemented).\n");
-}
-
-bool PatternMatchesString(const char* pattern, const char* str) {
-  switch (*pattern) {
-    case '\0':
-    case '-': return *str == '\0';
-    case '*': return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
-                     PatternMatchesString(pattern + 1, str);
-    default:  return *pattern == *str &&
-                     PatternMatchesString(pattern + 1, str + 1);
-  }
-}
-
-bool TestMatchesFilter(const char* test, const char* filter) {
-  // Split --gtest_filter at '-' into positive and negative filters.
-  const char* const dash = strchr(filter, '-');
-  const char* pos = dash == filter ? "*" : filter; //Treat '-test1' as '*-test1'
-  const char* neg = dash ? dash + 1 : "";
-  return PatternMatchesString(pos, test) && !PatternMatchesString(neg, test);
-}
-
-bool ReadFlags(int* argc, char*** argv, const char** test_filter) {
-  enum { OPT_GTEST_FILTER = 1 };
-  const option kLongOptions[] = {
-    { "gtest_filter", required_argument, NULL, OPT_GTEST_FILTER },
-    { NULL, 0, NULL, 0 }
-  };
-
-  int opt;
-  while ((opt = getopt_long(*argc, *argv, "h", kLongOptions, NULL)) != -1) {
-    switch (opt) {
-    case OPT_GTEST_FILTER:
-      if (strchr(optarg, '?') == NULL && strchr(optarg, ':') == NULL) {
-        *test_filter = optarg;
-        break;
-      }  // else fall through.
-    default:
-      Usage();
-      return false;
-    }
-  }
-  *argv += optind;
-  *argc -= optind;
-  return true;
-}
-
-}  // namespace
-
-bool testing::Test::NullFailure(bool null_expected, const char* file, int line,
-                                const char* error, const char* value) {
-  printer.PrintOnNewLine(StringPrintf(
-      "*** Failure in %s:%d\n%s\nExpected: %s\nActual:   %s\n", file, line,
-      error, null_expected ? "nullptr" : "not nullptr", value));
-  failed_ = true;
-  return false;
-}
-
-bool testing::Test::BooleanFailure(bool expected, const char* file, int line,
-                          const char* error, const char* value) {
-  printer.PrintOnNewLine(
-      StringPrintf("*** Failure in %s:%d\n%s\nExpected: %s\nActual:   %s\n",
-                   file, line, error, expected ? "true" : "false", value));
-  failed_ = true;
-  return false;
-}
-
-bool testing::Test::BinopFailure(const char* file, int line,
-                                 const char* error, const char* first_value,
-                                 const char* second_value) {
-  printer.PrintOnNewLine(
-      StringPrintf("*** Failure in %s:%d\n%s\nLeft:  %s\nRight: %s\n", file, line, error, first_value, second_value));
-  failed_ = true;
-  return false;
-}
-
-int main(int argc, char **argv) {
-  int tests_started = 0;
-
-  const char* test_filter = "*";
-  if (!ReadFlags(&argc, &argv, &test_filter))
-    return 1;
-
-  int nactivetests = 0;
-  for (int i = 0; i < ntests; i++)
-    if ((tests[i].should_run = TestMatchesFilter(tests[i].name, test_filter)))
-      ++nactivetests;
-
-  bool passed = true;
-  for (int i = 0; i < ntests; i++) {
-    if (!tests[i].should_run) continue;
-
-    ++tests_started;
-    testing::Test* test = tests[i].factory();
-    printer.Print(
-        StringPrintf("[%d/%d] %s", tests_started, nactivetests, tests[i].name),
-        LinePrinter::ELIDE);
-    test->SetUp();
-    test->Run();
-    test->TearDown();
-    if (test->Failed())
-      passed = false;
-    delete test;
-  }
-
-  printer.PrintOnNewLine(passed ? "passed\n" : "failed\n");
-  return passed ? EXIT_SUCCESS : EXIT_FAILURE;
-}
diff --git a/src/parser.cc b/src/parser.cc
deleted file mode 100644
index 96c90f3..0000000
--- a/src/parser.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2018 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 "parser.h"
-
-#include "disk_interface.h"
-#include "metrics.h"
-
-using namespace std;
-
-bool Parser::Load(const string& filename, string* err, Lexer* parent) {
-  // If |parent| is not NULL, metrics collection has been started by a parent
-  // Parser::Load() in our call stack. Do not start a new one here to avoid
-  // over-counting parsing times.
-  METRIC_RECORD_LOAD_IF(".ninja parse", parent == NULL);
-  string contents;
-  string read_err;
-  if (file_reader_->ReadFile(filename, &contents, &read_err) !=
-      FileReader::Okay) {
-    *err = "loading '" + filename + "': " + read_err;
-    if (parent)
-      parent->Error(string(*err), err);
-    return false;
-  }
-
-  return Parse(filename, contents, err);
-}
-
-bool Parser::ExpectToken(Lexer::Token expected, string* err) {
-  Lexer::Token token = lexer_.ReadToken();
-  if (token != expected) {
-    string message = string("expected ") + Lexer::TokenName(expected);
-    message += string(", got ") + Lexer::TokenName(token);
-    message += Lexer::TokenErrorHint(expected);
-    return lexer_.Error(message, err);
-  }
-  return true;
-}
diff --git a/src/parser.h b/src/parser.h
deleted file mode 100644
index 011fad8..0000000
--- a/src/parser.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2018 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_PARSER_H_
-#define NINJA_PARSER_H_
-
-#include <string>
-
-#include "lexer.h"
-
-struct FileReader;
-struct State;
-
-/// Base class for parsers.
-struct Parser {
-  Parser(State* state, FileReader* file_reader)
-      : state_(state), file_reader_(file_reader) {}
-
-  /// Load and parse a file.
-  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, std::string* err);
-
-  State* state_;
-  FileReader* file_reader_;
-  Lexer lexer_;
-
-private:
-  /// Parse a file, given its contents as a string.
-  virtual bool Parse(const std::string& filename, const std::string& input,
-                     std::string* err) = 0;
-};
-
-#endif  // NINJA_PARSER_H_
diff --git a/src/persistent_mode.cc b/src/persistent_mode.cc
deleted file mode 100644
index 16ef3bc..0000000
--- a/src/persistent_mode.cc
+++ /dev/null
@@ -1,593 +0,0 @@
-// Copyright 2023 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 "persistent_mode.h"
-
-#include <assert.h>
-#include <inttypes.h>
-#include <string.h>
-
-#include "debug_flags.h"
-#include "interrupt_handling.h"
-#include "ipc_handle.h"
-#include "ipc_utils.h"
-#include "metrics.h"
-#include "process_utils.h"
-#include "stdio_redirection.h"
-#include "util.h"
-#include "version.h"
-#ifndef _WIN32
-#include <sys/stat.h>
-#include <unistd.h>
-#endif
-
-#define DEBUG 0
-
-#define SERVER_LOG(...)                    \
-  do {                                     \
-    fprintf(stderr, "NINJA_SERVER_LOG: "); \
-    fprintf(stderr, __VA_ARGS__);          \
-    fprintf(stderr, "\n");                 \
-  } while (0)
-
-#if DEBUG
-#define CLIENT_LOG(...)                    \
-  do {                                     \
-    fprintf(stderr, "NINJA_CLIENT_LOG: "); \
-    fprintf(stderr, __VA_ARGS__);          \
-    fprintf(stderr, "\n");                 \
-  } while (0)
-#else
-#define CLIENT_LOG(...) (void)0
-#endif
-
-namespace {
-
-// Print error message, then return false
-bool PrintError(const char* fmt, ...) {
-  va_list args;
-  va_start(args, fmt);
-  fputs("ERROR: ", stderr);
-  vfprintf(stderr, fmt, args);
-  fputc('\n', stderr);
-  va_end(args);
-  return false;
-}
-
-extern "C" char** environ;
-
-// Return the name of the IPC service for a given current build
-// directory. This allows several servers to co-exist on the same
-// machine, if they are invoked / used from different build
-// directories.
-std::string GetServiceName(const std::string& build_dir) {
-  std::string real_dir = build_dir.empty() ? GetCurrentDir() : build_dir;
-  return StringFormat("ninja-server-%08zx", std::hash<std::string>()(real_dir));
-}
-
-// Name of the environment variable used to control the feature at runtime.
-const char kPersistentModeEnv[] = "NINJA_PERSISTENT_MODE";
-
-// Name of the environment variable used to control the server timeout.
-const char kPersistentTimeoutSecondsEnv[] = "NINJA_PERSISTENT_TIMEOUT_SECONDS";
-
-}  // namespace
-
-////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////
-/////
-/////   C O M P A T I B I L I T Y
-/////
-/////
-
-PersistentMode::Compatibility::Compatibility()
-    : ninja_version_(GetDefaultNinjaVersion()), build_dir_(GetCurrentDir()),
-      input_file_("build.ninja") {}
-
-PersistentMode::Compatibility& PersistentMode::Compatibility::SetInputFile(
-    const std::string& input_file) {
-  input_file_ = input_file;
-  return *this;
-}
-
-// static
-std::string PersistentMode::Compatibility::GetDefaultNinjaVersion() {
-  // Ignore the error returned by GetFileTimestamp() since the executable
-  // is known to exist.
-  std::string err;
-  return StringFormat("%s-%" PRId64, kNinjaVersion,
-                      ::GetFileTimestamp(GetCurrentExecutable(), &err));
-}
-
-PersistentMode::Compatibility&
-PersistentMode::Compatibility::SetNinjaVersionForTest(
-    const std::string& ninja_version) {
-  ninja_version_ = ninja_version;
-  return *this;
-}
-
-PersistentMode::Compatibility& PersistentMode::Compatibility::SetBuildDir(
-    const std::string& build_dir) {
-  build_dir_ = build_dir;
-  return *this;
-}
-
-PersistentMode::Compatibility&
-PersistentMode::Compatibility::SetFlagDupeEdgesShouldErr(bool enabled) {
-  dupe_edges_should_err_ = enabled;
-  return *this;
-}
-
-PersistentMode::Compatibility&
-PersistentMode::Compatibility::SetFlagPhonyCycleShouldErr(bool enabled) {
-  phony_cycle_should_err_ = enabled;
-  return *this;
-}
-
-bool PersistentMode::Compatibility::CheckBuildDir(std::string* err) const {
-  if (build_dir_.empty())
-    return true;
-
-  if (build_dir_[0] != '/' && build_dir_[0] != '\\') {
-    *err = StringFormat("build directory path is not absolute: %s",
-                        build_dir_.c_str());
-    return false;
-  }
-
-  // TODO(digit): What about Win32 drive letters?
-  return true;
-}
-
-// static
-PersistentMode::Compatibility PersistentMode::Compatibility::FromEncodedString(
-    const std::string& str, std::string* error) {
-  error->clear();
-  WireDecoder decoder(str);
-  Compatibility result = {};
-  decoder.Read(result.ninja_version_);
-  decoder.Read(result.build_dir_);
-  decoder.Read(result.input_file_);
-  decoder.Read(result.dupe_edges_should_err_);
-  decoder.Read(result.phony_cycle_should_err_);
-
-  if (decoder.has_error()) {
-    *error = "Truncated PersistentMode::Compatibility encoded string";
-    result = {};
-  }
-  return result;
-}
-
-std::string PersistentMode::Compatibility::ToEncodedString() const {
-  WireEncoder encoder;
-  encoder.Write(ninja_version_);
-  encoder.Write(build_dir_);
-  encoder.Write(input_file_);
-  encoder.Write(dupe_edges_should_err_);
-  encoder.Write(phony_cycle_should_err_);
-  return encoder.TakeResult();
-}
-
-std::string PersistentMode::Compatibility::ToString() const {
-  return StringFormat(
-      "build_dir=%s input_file=%s dupe_edges_should_err=%s "
-      "phony_cycle_shoud_err=%s ninja_version=%s",
-      build_dir_.c_str(), input_file_.c_str(),
-      dupe_edges_should_err_ ? "true" : "false",
-      phony_cycle_should_err_ ? "true" : "false", ninja_version_.c_str());
-}
-
-bool PersistentMode::Compatibility::IsCompatibleWith(
-    const PersistentMode::Compatibility& other, std::string* reason) const {
-  if (ninja_version_ != other.ninja_version_) {
-    *reason =
-        StringFormat("Ninja version mismatch, expected [%s] vs [%s]",
-                     ninja_version_.c_str(), other.ninja_version_.c_str());
-    return false;
-  }
-  if (build_dir_ != other.build_dir_) {
-    *reason = StringFormat("Working dir mismatch, expected [%s] vs [%s]",
-                           build_dir_.c_str(), other.build_dir_.c_str());
-    return false;
-  }
-  if (input_file_ != other.input_file_) {
-    *reason = StringFormat("Input file mismatch, expected [%s] vs [%s]",
-                           input_file_.c_str(), other.input_file_.c_str());
-    return false;
-  }
-  if (dupe_edges_should_err_ != other.dupe_edges_should_err_) {
-    *reason =
-        StringFormat("Flag dupe_edges_should_err mismatch, expected %s vs %s",
-                     dupe_edges_should_err_ ? "true" : "false",
-                     other.dupe_edges_should_err_ ? "true" : "false");
-    return false;
-  }
-  if (phony_cycle_should_err_ != other.phony_cycle_should_err_) {
-    *reason =
-        StringFormat("Flag phony_cycle_should_err mismatch, expected %s vs %s",
-                     phony_cycle_should_err_ ? "true" : "false",
-                     other.phony_cycle_should_err_ ? "true" : "false");
-    return false;
-  }
-  return true;
-}
-
-std::vector<std::string> PersistentMode::Compatibility::ToServerArgs(
-    const std::string& server_executable) const {
-  std::vector<std::string> result;
-  result.push_back(server_executable);
-  result.push_back("-C");
-  result.push_back(build_dir_);
-
-  if (input_file_ != "build.ninja") {
-    result.push_back("-f");
-    result.push_back(input_file_);
-  }
-  if (dupe_edges_should_err_) {
-    result.push_back("-wdupbuild=err");
-  } else {
-    result.push_back("-wdupbuild=warn");
-  }
-  if (phony_cycle_should_err_) {
-    result.push_back("-wphonycycle=err");
-  } else {
-    result.push_back("-wphonycycle=warn");
-  }
-  return result;
-}
-
-////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////
-/////
-/////   B U I L D   Q U E R Y
-/////
-/////
-
-// static
-PersistentMode::BuildQuery PersistentMode::BuildQuery::FromEncodedString(
-    const std::string& str, std::string* error) {
-  BuildQuery result;
-  std::string encoded;
-  WireDecoder decoder(str);
-
-  // Read BuildConfig.
-  decoder.Read(encoded);
-  result.config = BuildConfig::FromEncodedString(encoded, error);
-  if (!error->empty())
-    return {};
-
-  decoder.Read(result.debug_explaining);
-  decoder.Read(result.debug_keep_depfile);
-  decoder.Read(result.debug_keep_rsp);
-  decoder.Read(result.debug_experimental_statcache);
-  decoder.Read(result.dump_metrics);
-  decoder.Read(result.tool);
-  size_t num_args = 0;
-  decoder.Read(num_args);
-  result.args.resize(num_args);
-  for (size_t n = 0; n < num_args; ++n)
-    decoder.Read(result.args[n]);
-
-  if (decoder.has_error()) {
-    *error = "Truncated BuildQuery encoded string";
-    result = {};
-  }
-
-  return result;
-}
-
-std::string PersistentMode::BuildQuery::ToEncodedString() const {
-  WireEncoder encoder;
-  encoder.Write(config.ToEncodedString());
-  encoder.Write(debug_explaining);
-  encoder.Write(debug_keep_depfile);
-  encoder.Write(debug_keep_rsp);
-  encoder.Write(debug_experimental_statcache);
-  encoder.Write(dump_metrics);
-  encoder.Write(tool);
-  encoder.Write(args.size());
-  for (const auto& arg : args)
-    encoder.Write(arg);
-
-  return encoder.TakeResult();
-}
-
-std::string PersistentMode::BuildQuery::ToString() const {
-  std::string result = config.ToString();
-  StringAppendFormat(result,
-                     " explain=%s keep_depfile=%s keep_rsp=%s "
-                     "experimental_statcache=%s dump_metrics=%s",
-                     debug_explaining ? "true" : "false",
-                     debug_keep_depfile ? "true" : "false",
-                     debug_keep_rsp ? "true" : "false",
-                     debug_experimental_statcache ? "true" : "false",
-                     dump_metrics ? "true" : "false");
-
-  if (!tool.empty())
-    StringAppendFormat(result, " tool=%s", tool.c_str());
-
-  for (const auto& arg : args) {
-    result += " ";
-    result += arg;
-  }
-  return result;
-}
-
-void PersistentMode::BuildQuery::WriteGlobalVariables() const {
-  g_explaining = debug_explaining;
-  g_keep_depfile = debug_keep_depfile;
-  g_keep_rsp = debug_keep_rsp;
-  g_experimental_statcache = debug_experimental_statcache;
-}
-
-////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////
-/////
-/////   P E R S I S T E N T   M O D E
-/////
-/////
-
-// static
-PersistentMode::Status PersistentMode::GetCurrentProcessStatus() {
-  const char* env = getenv(kPersistentModeEnv);
-  std::string mode(env ? env : "0");
-  if (mode == "0" || mode == "off")
-    return PersistentMode::Disabled;
-
-  if (mode == "1" || mode == "on" || mode == "client")
-    return PersistentMode::IsClient;
-
-  if (mode == "server")  // Used internally when spawning the server.
-    return PersistentMode::IsServer;
-
-  fprintf(stderr,
-          "WARNING: Unknown %s value '%s', must be one of: 0, 1, on, off, "
-          "client, server\n",
-          kPersistentModeEnv, mode.c_str());
-  return PersistentMode::Disabled;
-}
-
-PersistentMode::Client::Client() : server_executable_(GetCurrentExecutable()) {}
-
-void PersistentMode::Client::SetServerExecutable(
-    const std::string& server_executable) {
-  server_executable_ = server_executable;
-}
-
-// static
-PersistentService::Client PersistentMode::Client::GetService(
-    const std::string& build_dir) {
-  CLIENT_LOG("GetService(%s)", build_dir.c_str());
-  return PersistentService::Client(GetServiceName(build_dir));
-}
-
-bool PersistentMode::Client::IsServerRunning(const std::string& build_dir) {
-  return GetService(build_dir).HasServer();
-}
-
-int PersistentMode::Client::GetServerPidFor(const std::string& build_dir) {
-  return GetService(build_dir).GetServerPid();
-}
-
-bool PersistentMode::Client::StopServer(const std::string& build_dir,
-                                        std::string* err) {
-  return GetService(build_dir).StopServer(err);
-}
-
-bool PersistentMode::Client::RunQuery(const Compatibility& compatibility,
-                                      const BuildQuery& query,
-                                      int* exit_code_ptr, std::string* error) {
-  // Return an error early if the build directory is not valid.
-  if (!compatibility.CheckBuildDir(error))
-    return false;
-
-  // Ensure the persistent mode status is set to 'server' in spawned servers.
-  PersistentService::Config server_config =
-      PersistentService::Config(compatibility.ToServerArgs(server_executable_))
-          .SetWorkingDir(compatibility.build_dir())
-          .SetVersionInfo(compatibility.ToEncodedString())
-          .AddEnvVariable(kPersistentModeEnv, "server");
-  // Set log file path from env. This is a debugging aid.
-  {
-    const char* env = getenv("NINJA_PERSISTENT_LOG_FILE");
-    if (env && env[0]) {
-      server_config.SetLogFile(std::string(env));
-    }
-  }
-
-  // Ensure that the persistent timeout value from the client environment
-  // is passed to new server instances.
-  {
-    const char* env = getenv(kPersistentTimeoutSecondsEnv);
-    if (env)
-      server_config.AddEnvVariable(kPersistentTimeoutSecondsEnv, env);
-  }
-
-  CLIENT_LOG("Connecting to server.");
-  PersistentService::Client client = GetService(compatibility.build_dir());
-  IpcHandle connection = client.Connect(server_config, error);
-  if (!connection) {
-    CLIENT_LOG("Could not connect to server: %s", error->c_str());
-    return false;
-  }
-
-  // Send the query now.
-  CLIENT_LOG("Sending query to server.");
-  if (!RemoteWrite(query.ToEncodedString(), connection, error)) {
-    *error = "Could not send build query: " + *error;
-    return false;
-  }
-
-  // Receive the server PID, to redirect signals to it.
-#ifdef _WIN32
-  DWORD server_pid = 0;
-#else   // !_WIN32
-  pid_t server_pid = -1;
-#endif  // !_WIN32
-  if (!RemoteRead(server_pid, connection, error)) {
-    *error = "Could not receive server pid: " + *error;
-    return false;
-  }
-
-  CLIENT_LOG("Received remote server pid: %d\n", server_pid);
-
-  StdioRedirector stdio_redirect(connection);
-  if (!stdio_redirect.SendStandardDescriptors(error))
-    return false;
-
-  InterruptForwarder interrupt_forwarder(server_pid);
-
-  // Wait for the corresponding exit code.
-  CLIENT_LOG("Waiting for query exit code from server.");
-  int exit_code = -1;
-  if (!RemoteRead(exit_code, connection, error)) {
-    *error = "Could not receive build request exit code: " + *error;
-    return false;
-  }
-  CLIENT_LOG("Query ended with exit code %d", exit_code);
-  *exit_code_ptr = exit_code;
-  return true;
-}
-
-PersistentMode::Server::Server(const Compatibility& compatibility)
-    : compatibility_(compatibility),
-      server_(GetServiceName(compatibility_.build_dir())) {
-  SERVER_LOG("Server for %s", compatibility_.build_dir().c_str());
-
-  // Compute the server connection timeout, default value is 5 minutes
-  // and can be overriden with kPersistentTimeoutSecondsEnv in the
-  // environment.
-  int64_t connection_timeout_ms = 5 * 60 * 1000;
-  const char* env = getenv(kPersistentTimeoutSecondsEnv);
-  if (env) {
-    int64_t timeout_secs = static_cast<int64_t>(atoll(env));
-    if (timeout_secs < 0) {
-      SERVER_LOG(
-          "Ignoring invalid timeout value (%s): must be strictly positive!",
-          env);
-    } else {
-      connection_timeout_ms = timeout_secs * 1000;
-    }
-  }
-  server_.SetConnectionTimeoutMs(connection_timeout_ms);
-}
-
-bool PersistentMode::Server::StartLocalServer(std::string* error) {
-  // Return an error early if the build directory is not valid.
-  if (!compatibility_.CheckBuildDir(error))
-    return false;
-
-  return server_.BindService(error);
-}
-
-void PersistentMode::Server::RunServerThenExit(
-    RestartChecker ninja_restart_check, BuildQueryHandler query_handler) {
-  // PersistentService::Server::VersionCheckHandler used to verify compatibility
-  // and invoke the restart check callback before each query.
-  auto version_check_handler =
-      [this, &ninja_restart_check](const std::string& version) -> std::string {
-    std::string error;
-    auto client_compatibility =
-        Compatibility::FromEncodedString(version, &error);
-    if (!error.empty())
-      return error;
-    std::string reason;
-    if (!compatibility_.IsCompatibleWith(client_compatibility, &reason))
-      return StringFormat("Incompatible build plan: %s", reason.c_str());
-
-    if (ninja_restart_check())
-      return "Build manifest files updated!";
-
-    return {};
-  };
-
-  // A Persistent::Server::RequestHandler instance to run queries on the
-  // server.
-  auto request_handler = [this, &query_handler](IpcHandle connection) -> bool {
-    return RunQueryOnServer(std::move(connection), query_handler);
-  };
-
-  // Ensure that NINJA_PERSISTENT_MODE is disabled by default when
-  // running queries, since Ninja commands can themselves invoke Ninja
-  // (e.g. to perform sub-builds in other directories).
-  //
-  // Persistent mode for these sub-builds is disabled by default, but can
-  // be enabled by the user by adding NINJA_PERSISTENT_MODE to the list in
-  // NINJA_PERSISTENT_PASS_VARIABLES.
-  ScopedEnvironmentVariable no_persistent_mode(kPersistentModeEnv, "0");
-
-  server_.RunServerThenExit(version_check_handler, request_handler);
-}
-
-bool PersistentMode::Server::RunQueryOnServer(
-    IpcHandle connection, const BuildQueryHandler& query_handler) {
-  int64_t query_start_ms = AsyncLoop::NowMs();
-  printf("Starting client request\n");
-  std::string error;
-  SERVER_LOG("New client request from handle %s", connection.display().c_str());
-  // Receive build query.
-  std::string encoded_query;
-  if (!RemoteRead(encoded_query, connection, &error)) {
-    return PrintError("Could not receive build query: %s", error.c_str());
-  }
-
-  auto query =
-      PersistentMode::BuildQuery::FromEncodedString(encoded_query, &error);
-  if (!error.empty())
-    return PrintError("Could not receive build query: %s\n", error.c_str());
-
-  query.WriteGlobalVariables();
-
-  // Send our pid to allow the client to redirect signals to us.
-#ifdef _WIN32
-  DWORD pid = GetCurrentProcessId();
-#else   // !_WIN32
-  pid_t pid = getpid();
-#endif  // !_WIN32
-  if (!RemoteWrite(pid, connection, &error))
-    return PrintError("Could not send server pid: %s", error.c_str());
-
-  // Temporarily redirect stdin/stdout/stderr from client-provided handles.
-  int exit_code;
-  {
-    StdioRedirector stdio_redirect(connection);
-    if (!stdio_redirect.ReceiveStandardDescriptors(&error))
-      return PrintError("Could not receive standard descriptors: %s",
-                        error.c_str());
-
-    exit_code = query_handler(query);
-  }
-
-  if (!RemoteWrite(exit_code, connection, &error)) {
-    return PrintError("Could not send exit_code=%d back to client: %s",
-                      error.c_str());
-  }
-
-  // Keep server running until next client request.
-  SERVER_LOG("Request completed with exit_code=%d", exit_code);
-
-  // Print statistics about the request.
-  int64_t query_time_ms = AsyncLoop::NowMs() - query_start_ms;
-  printf("Request took %s to complete\n",
-         StringFormatDurationMs(query_time_ms).c_str());
-
-  if (exit_code == kServerExit) {
-    printf("Server exiting after query.");
-    return false;
-  }
-
-  return true;
-}
-
-// Avoid compiler warnings in debug mode.
-constexpr int PersistentMode::kServerExit;
diff --git a/src/persistent_mode.h b/src/persistent_mode.h
deleted file mode 100644
index e55a075..0000000
--- a/src/persistent_mode.h
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright 2023 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_PERSISTENT_MODE_H_
-#define NINJA_PERSISTENT_MODE_H_
-
-#include <functional>
-#include <string>
-#include <vector>
-
-#include "build_config.h"
-#include "ipc_utils.h"
-#include "persistent_service.h"
-
-/// Implementation for Ninja's persistent mode.
-///
-/// This class wraps Ninja's persistent mode implementation on top of the
-/// generic PersistentService class. In particular:
-///
-/// - Provides static methods to determine the role of the current process
-///   (based on the NNINJA_PERSISTENT_MODE environment variable).
-///
-/// - Provides a way to check that the client and the server correspond to
-///   the same build plan (see Compatibility).
-///
-/// - Provides client methods to check the status of the server, or stop it
-///   (to implement the `-t server` tool commands).
-///
-/// - Provides a client method to run a query on the server, automatically
-///   starting a new instance if none is available, if the available one
-///   is not compatible with the current build plan, or if any of the input
-///   .ninja manifest files has been updated.
-///
-/// - Provides a way to start the server early, and to process Ninja build
-///   or tool requests on the server.
-///
-/// Example Usage:
-///
-///    // build plan configuration data used to match client/server
-///    // compatibility.
-///    auto compatibility = PersistentMode::Compatibility();
-///    compatibility.SetBuildDir(<absolute_build_dir>);
-///
-///    // An object describing the current Ninja build query or tool
-///    // invocation to perform.
-///    PersistentMode::BuildQuery query;
-///    query.config = build_config;
-///    query.args = RemoteArguments(argc, argv).args();
-///    ...
-///
-///    // A callable used to run the query, either on the server, or in the
-///    // client if launching a new server was not possible.
-///    auto handle_query = [](const PersistentMode::BuildQuery& query) -> int {
-///       ...  // perform build or tool query.
-///       return 0;
-///    };
-///
-///    auto persistent_status = PersistentMode::GetProcessStatus();
-///    is (status == PersistentMode::IsServer) {
-///       PersistentMode::Server server(compatibility);
-///
-///       if (!server.StartLocalServer(&err))
-///         Fatal("Could not start server: %s", err.c_str());
-///
-///       ... load build plan
-///
-///       // A callable used  by the server before running each
-///       // query to verify if the build plan changed (e.g. an
-///       // input build.ninja file was updated on the filesystem).
-///       auto restart_check = []() -> bool {
-///         return false;
-///       };
-///
-///       // Run the server loop till the end.
-///       server.RunServerThenExit(std::move(restart_check),
-///                                std::move(handle_query));
-///    }
-///
-///    if (persistent_status == PersistentMode::Client) {
-///      PersistentMode::Client client;
-///
-///      // Run the query, this takes care of redirecting stdio
-///      // and ensuring Ctrl-C will be handled by the server
-///      // properly (i.e. to stop current query, and not abort
-///      // the server).
-///      int exit_code = -1;
-///      if (!client.RunQuery(compatibility, query, &exit_code, &error)) {
-///        Fatal("Could not run Ninja query: %s", error.c_str());
-///      }
-///
-///      // query was run on the server.
-///      exit(exit_code);
-///    }
-///
-///    assert(persistent_status == PersistentMode::Disabled) {
-///       ... load build plan
-///       ... do a local build as usual.
-///    }
-///
-struct PersistentMode {
-  /// Status of persistent mode for the current process
-  enum Status {
-    Disabled = 0,
-    IsClient,
-    IsServer,
-  };
-
-  /// Return the status of the current process.
-  static Status GetCurrentProcessStatus();
-
-  /// The configuration information that each persistent server must compare
-  /// with each client query to verify that they are compatible, i.e. correspond
-  /// to the same Ninja build plan. Note that some flags change the way
-  /// manifests are loaded, and thus introduce incompatibilities when they
-  /// are different.
-  struct Compatibility {
-    /// Create new instance from command-line options.
-    ///
-    /// |input_file| is an optional pointer to the top-level Ninja manifest
-    /// file name. The nullptr value defaults to "build.ninja".
-    ///
-    /// |build_dir| is an optional pointer to the build directory, the nullptr
-    /// value defaults to the current working directory.
-    ///
-    /// |dupe_edges_should_err| corresponds to the `-w dupbuild=err` option,
-    /// and |phony_cycle_should_err| corresponds to the `-w phonycycle=err` one,
-    /// and both change the way manifest files are loaded.
-    static Compatibility FromOptions(const char* input_file,
-                                     const char* build_dir,
-                                     bool dupe_edges_should_err,
-                                     bool phony_cycle_should_err);
-
-    Compatibility();
-
-    /// Override the ninja_version() string. Only use this for tests.
-    Compatibility& SetNinjaVersionForTest(const std::string& new_version);
-
-    /// Change the input file, default value if "build.ninja"
-    Compatibility& SetInputFile(const std::string& input_file);
-
-    /// Change the build directory, and empty value matches the current working
-    /// directory. WARNING: It is critically important for the client and server
-    /// to use the same value consistenly. Outside of tests, ensure that a
-    /// non-empty value is always an absolute path!
-    Compatibility& SetBuildDir(const std::string& build_dir);
-
-    /// Set the value of the `-w dupedges` flag, which changes the way build
-    /// manifests are loaded. Default value is true.
-    Compatibility& SetFlagDupeEdgesShouldErr(bool enabled);
-
-    /// Set the value of the `-w phonycycle` flag, which changes the way
-    /// build manifests are loaded. Default value is false.
-    Compatibility& SetFlagPhonyCycleShouldErr(bool enabled);
-
-    /// Create new instance from an encoded string.
-    /// On success return new instance after clearing |*error|.
-    /// On failure return empty instance after setting |*error| to non-empty
-    /// string.
-    static Compatibility FromEncodedString(const std::string& str,
-                                           std::string* error);
-
-    /// Convert to string for sending through IPC. Not human-readable.
-    std::string ToEncodedString() const;
-
-    /// Convert to human-readable string for debugging.
-    std::string ToString() const;
-
-    /// Return true if this instance is compatiable with |other|.
-    /// On failure, return false after setting |*reason|.
-    bool IsCompatibleWith(const Compatibility& other,
-                          std::string* reason) const;
-
-    /// Return working directory.
-    const std::string& build_dir() const { return build_dir_; }
-
-    /// Return a string trying to identify the Ninja version being used.
-    /// Note that this may include a timestamp or content hash of the current
-    /// executable as well. The default value is computed by the constructor
-    /// automatically.
-    const std::string& ninja_version() const { return ninja_version_; };
-
-    /// Return a command-line used to start a server compatible with this
-    /// instance.
-    std::vector<std::string> ToServerArgs(
-        const std::string& server_executable) const;
-
-    /// Returns true if the build directory is absolute (or empty, in which
-    /// case this will be interpreted as the absolute path of the current
-    /// directory). On failure, set |*err| then return false.
-    bool CheckBuildDir(std::string* err) const;
-
-   private:
-    /// Return the default Ninja version, called from constructor.
-    static std::string GetDefaultNinjaVersion();
-
-    /// Ninja version. This includes a timestamp of the Ninja executable
-    /// as well. Must be the first field in this struct.
-    std::string ninja_version_;
-
-    /// Current build directory.
-    std::string build_dir_;
-
-    /// Input file name, cannot be empty, relative paths are always
-    /// relative to |build_dir|.
-    std::string input_file_ = "build.ninja";
-
-    /// Options controlling how the manifest is loaded.
-    bool dupe_edges_should_err_ = true;
-    bool phony_cycle_should_err_ = false;
-  };
-
-  /// A callable object that returns true if any condition invalidated
-  /// the content of the in-memory build graph. In practice this would be
-  /// when any of the input .ninja files has changed. A return value of true
-  /// indicates that the server must be stopped, and another one restarted.
-  using RestartChecker = std::function<bool(void)>;
-
-  /// Describe a query from the client to the server. This can be used to
-  /// run either a build or a tool (when the |tool| field is not empty).
-  struct BuildQuery {
-    /// Build configuration
-    BuildConfig config;
-
-    /// Mirror the set of debug flags in "debug_flags.h" that can be set
-    /// individually with `-d <flag>` on the command line that do affect
-    /// each build. These are currently stored in global variables instead
-    /// of BuildConfig :-/
-    bool debug_explaining = false;
-    bool debug_keep_depfile = false;
-    bool debug_keep_rsp = false;
-    bool debug_experimental_statcache = false;
-
-    /// Set to true to dump metrics after a build.
-    bool dump_metrics = false;
-
-    /// Optional tool name, empty means a build is requested, instead of a
-    /// tool run.
-    std::string tool;
-
-    /// List of command-line arguments. If |tool| is empty, this is a list
-    /// of targets and should not contain any option. If |tool| is not empty
-    /// then this is a list of arguments for the tool.
-    std::vector<std::string> args;
-
-    std::string ToEncodedString() const;
-    std::string ToString() const;
-
-    void WriteGlobalVariables() const;
-
-    static BuildQuery FromEncodedString(const std::string& str,
-                                        std::string* error);
-  };
-
-  /// A special value that can be returned by a BuildQueryHandler to
-  /// indicate that the server should exit immediately after
-  /// serving the query.
-  static constexpr int kServerExit = -2;
-
-  /// A callable object that implements a query. The result value can
-  /// be the special kServerExit value to indicate that the server
-  /// should stop immediately. Otherwise, it must be a process exit
-  /// code that is >= 0, corresponding to the result of the query.
-  using BuildQueryHandler = std::function<int(const BuildQuery&)>;
-
-  class Client {
-   public:
-    /// Create new instance.
-    Client();
-
-    /// Set the path to the server executable. By default, this is the value
-    /// returned by GetCurrentExecutable(), but this method allows one to
-    /// override it for testing.
-    void SetServerExecutable(const std::string& server_path);
-
-    /// Return server executable path. Used for testing.
-    const std::string server_executable() const { return server_executable_; }
-
-    /// Return true if a server is already running, serving a given build
-    /// directory. An empty |build_dir| string means the current working
-    /// directory.
-    bool IsServerRunning(const std::string& build_dir);
-
-    /// Retrieve process ID of server, if it exists, for |build_dir|,
-    /// or -1 otherwise. NOTE: DOES NOT WORK ON WINDOWS YET.
-    int GetServerPidFor(const std::string& build_dir);
-
-    /// Stop the server if it exists, return true if a server was running
-    /// before the call for a given build directory. An empty |build_dir|
-    /// string means the current working directory.
-    bool StopServer(const std::string& build_dir, std::string* err);
-
-    /// Ask the server to run a query for us.
-    ///
-    /// |compatibility| is used to connect either launch a new server instance,
-    /// or verify that the existing one serving |compatibility.build_dir()| is
-    /// compatible (if not, that instance is shut down, and a new one is
-    /// launched).
-    ///
-    /// On success return true and set |*exit_code_ptr| to the result of the
-    /// query, on failure to connect to the server, set |*error| and return
-    /// false.
-    bool RunQuery(const Compatibility& compatibility, const BuildQuery& query,
-                  int* exit_code_ptr, std::string* error);
-
-   private:
-    static PersistentService::Client GetService(const std::string& build_dir);
-
-    std::string server_executable_;
-  };
-
-  class Server {
-   public:
-    /// Create new instance. This does not do anything except recording
-    /// the value of |compatibility|.
-    explicit Server(const Compatibility& compatibility);
-
-    /// Set the timeout, in milliseconds, used by server instances waiting
-    /// for new client connections. On expiration, the server will shutdown
-    /// gracefully. A negative value (the default) means no timeout.
-    /// This must be called before StartLocalServer() or RunServerThenExit().
-    void SetConnectionTimeoutMs(int64_t connection_timeout_ms) {
-      server_.SetConnectionTimeoutMs(connection_timeout_ms);
-    }
-
-    /// Start the server in the current process. This can be called before
-    /// RunServerThenExit() to quickly acquire the service named pipe and fail
-    /// if not possible, before performing expensive operations like loading
-    /// the build plan. Called by RunServerThenExit() implicitly otherwise.
-    bool StartLocalServer(std::string* error);
-
-    /// Run the server main loop, which will handle incoming
-    /// build requests by first calling |restart_checker| to verify whether
-    /// a restart is needed (e.g. if the build plan changed), then serve
-    /// the request with |query_handler|. This function never returns.
-    void RunServerThenExit(RestartChecker restart_checker,
-                           BuildQueryHandler query_handler);
-
-   private:
-    bool RunQueryOnServer(IpcHandle connection,
-                          const BuildQueryHandler& query_handler);
-
-    Compatibility compatibility_;
-    int64_t connection_timeout_ms_ = -1;
-    PersistentService::Server server_;
-  };
-};
-
-#endif  // NINJA_PERSISTENT_MODE_H_
diff --git a/src/persistent_mode_test.cc b/src/persistent_mode_test.cc
deleted file mode 100644
index 80a685d..0000000
--- a/src/persistent_mode_test.cc
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright 2023 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 "persistent_mode.h"
-
-#include <inttypes.h>
-#include <stdlib.h>
-
-#include "async_loop.h"
-#include "persistent_mode_test_lib.cc"
-#include "process_utils.h"
-#include "stdio_redirection.h"
-#include "test.h"
-#include "util.h"
-
-TEST(PersistentMode, GetCurrentProcessStatus) {
-  static const char kStatusVarName[] = "NINJA_PERSISTENT_MODE";
-
-  {
-    static const char* const kValues[] = { nullptr, "off", "0" };
-    for (const char* value : kValues) {
-      ScopedEnvironmentVariable env(kStatusVarName, value);
-      EXPECT_EQ(PersistentMode::Disabled,
-                PersistentMode::GetCurrentProcessStatus());
-    }
-  }
-
-  {
-    static const char* const kValues[] = { "on", "1", "client" };
-    for (const char* value : kValues) {
-      ScopedEnvironmentVariable env(kStatusVarName, value);
-      ASSERT_TRUE(getenv(kStatusVarName));
-      EXPECT_EQ(std::string(value), getenv(kStatusVarName));
-      EXPECT_EQ(PersistentMode::IsClient,
-                PersistentMode::GetCurrentProcessStatus());
-    }
-  }
-
-  {
-    static const char* const kValues[] = { "server" };
-    for (const char* value : kValues) {
-      ScopedEnvironmentVariable env(kStatusVarName, value);
-      EXPECT_EQ(PersistentMode::IsServer,
-                PersistentMode::GetCurrentProcessStatus());
-    }
-  }
-}
-
-TEST(PersistentMode, Compatibility) {
-  // Convenience helper to return a value with default values
-  // appropriate for this test.
-  auto new_compat = []() -> PersistentMode::Compatibility {
-    return PersistentMode::Compatibility()
-        .SetNinjaVersionForTest("this_ninja")
-        .SetInputFile("input_file")
-        .SetBuildDir("build_dir");
-  };
-  PersistentMode::Compatibility compat = new_compat();
-
-  std::string reason;
-  ASSERT_TRUE(compat.IsCompatibleWith(compat, &reason));
-
-  std::string encoded = compat.ToEncodedString();
-  std::string error;
-  auto compat2 =
-      PersistentMode::Compatibility::FromEncodedString(encoded, &error);
-  ASSERT_TRUE(error.empty());
-
-  auto to_string = [](const std::vector<std::string>& args) -> std::string {
-    std::string result;
-    for (const auto& arg : args) {
-      if (!result.empty())
-        result += " ";
-      result += arg;
-    }
-    return result;
-  };
-
-  ASSERT_TRUE(compat.IsCompatibleWith(compat2, &reason));
-  ASSERT_TRUE(compat2.IsCompatibleWith(compat, &reason));
-
-  compat2 = new_compat().SetBuildDir("another_build_dir");
-
-  ASSERT_FALSE(compat.IsCompatibleWith(compat2, &reason));
-  EXPECT_EQ(
-      reason,
-      "Working dir mismatch, expected [build_dir] vs [another_build_dir]");
-  EXPECT_EQ(
-      "ninja -C another_build_dir -f input_file -wdupbuild=err "
-      "-wphonycycle=warn",
-      to_string(compat2.ToServerArgs("ninja")));
-
-  compat2 = new_compat().SetInputFile("another_input_file");
-
-  ASSERT_FALSE(compat.IsCompatibleWith(compat2, &reason));
-  EXPECT_EQ(
-      reason,
-      "Input file mismatch, expected [input_file] vs [another_input_file]");
-  EXPECT_EQ(
-      "ninja -C build_dir -f another_input_file -wdupbuild=err "
-      "-wphonycycle=warn",
-      to_string(compat2.ToServerArgs("ninja")));
-
-  compat2 = new_compat().SetFlagDupeEdgesShouldErr(false);
-  ASSERT_FALSE(compat.IsCompatibleWith(compat2, &reason));
-  EXPECT_EQ(reason,
-            "Flag dupe_edges_should_err mismatch, expected true vs false");
-  EXPECT_EQ(
-      "ninja -C build_dir -f input_file -wdupbuild=warn -wphonycycle=warn",
-      to_string(compat2.ToServerArgs("ninja")));
-
-  compat2 = new_compat().SetFlagPhonyCycleShouldErr(true);
-  ASSERT_FALSE(compat.IsCompatibleWith(compat2, &reason));
-  EXPECT_EQ(reason,
-            "Flag phony_cycle_should_err mismatch, expected false vs true");
-  EXPECT_EQ("ninja -C build_dir -f input_file -wdupbuild=err -wphonycycle=err",
-            to_string(compat2.ToServerArgs("ninja")));
-
-  compat2 = compat;
-  compat2.SetNinjaVersionForTest("not_this_ninja");
-  ASSERT_FALSE(compat.IsCompatibleWith(compat2, &reason));
-  EXPECT_EQ(
-      reason,
-      "Ninja version mismatch, expected [this_ninja] vs [not_this_ninja]");
-  EXPECT_EQ("ninja -C build_dir -f input_file -wdupbuild=err -wphonycycle=warn",
-            to_string(compat2.ToServerArgs("ninja")));
-}
-
-// Unfortunately, this test, and PersistentMode in general do not work
-// properly on Windows yet. The root of the problem is that StdioRedirector
-// does not work because it is impossible to pass Win32 console handlers
-// to other processes. Solving this requires an alternative implementation
-// that relies on proxying the console handles through anonymous pipes on
-// the client, which will be provided in a future fix.
-#ifndef _WIN32
-TEST(PersistentModeClient, DefaultMode) {
-  PersistentMode::Client client;
-  client.SetServerExecutable(persistent_mode_test::GetServerExecutable());
-
-  ScopedTempDir test_dir;
-  test_dir.CreateAndEnter("persistent_mode_test");
-  std::string build_dir = GetCurrentDir();
-
-  ASSERT_FALSE(client.IsServerRunning(build_dir));
-
-  auto compat = persistent_mode_test::GetClientCompatibility(build_dir);
-  std::string error;
-  int exit_code = -1;
-
-  auto query = persistent_mode_test::GetClientTestQuery1(build_dir);
-
-  AsyncLoop::ResetForTesting();
-  AsyncLoop& async_loop = AsyncLoop::Get();
-
-  {
-    StdioAsyncStringRedirector buffered_stdout(async_loop, stdout);
-    bool ret = client.RunQuery(compat, query, &exit_code, &error);
-    if (!ret)
-      fprintf(stderr, "\nERROR: %s\n", error.c_str());
-    std::string result;
-    EXPECT_TRUE(buffered_stdout.WaitForResult(&result));
-
-    ASSERT_TRUE(ret);
-    EXPECT_EQ(0u, exit_code);
-    EXPECT_EQ(result, build_dir);
-  }
-
-  ASSERT_TRUE(client.IsServerRunning(build_dir));
-
-  ASSERT_TRUE(client.StopServer(build_dir, &error));
-}
-
-TEST(PersistentModeClient, EnvironmentVariables) {
-  PersistentMode::Client client;
-  client.SetServerExecutable(persistent_mode_test::GetServerExecutable());
-
-  ScopedTempDir test_dir;
-  test_dir.CreateAndEnter("persistent_mode_test");
-  std::string build_dir = test_dir.temp_dir_name_;
-
-  ASSERT_FALSE(client.IsServerRunning(build_dir));
-
-  auto compat = persistent_mode_test::GetClientCompatibility(build_dir);
-  std::string error;
-  int exit_code = -1;
-
-  std::vector<std::string> print_varnames;
-  print_varnames.emplace_back("bar");
-  print_varnames.emplace_back("foo");
-  print_varnames.emplace_back("undefined");
-
-  auto query = persistent_mode_test::GetClientTestQuery2(print_varnames);
-  query.config.environment.Insert("foo", "FOO");
-  query.config.environment.Insert("bar", "BAR");
-  query.config.environment.Remove("undefined");
-
-  AsyncLoop::ResetForTesting();
-  AsyncLoop& async_loop = AsyncLoop::Get();
-
-  // The first query should retrieve the variable values from the client
-  // process that started it.
-  {
-    StdioAsyncStringRedirector buffered_stdout(async_loop, stdout);
-    bool ret = client.RunQuery(compat, query, &exit_code, &error);
-    if (!ret)
-      fprintf(stderr, "\nERROR: %s\n", error.c_str());
-    std::string result;
-    EXPECT_TRUE(buffered_stdout.WaitForResult(&result));
-
-    ASSERT_TRUE(ret);
-    EXPECT_EQ(0u, exit_code);
-    EXPECT_EQ(result, "bar=BAR\nfoo=FOO\nundefined=<UNSET>\n");
-  }
-
-  // Change the local values of 'foo' and 'undefined', and verify that only the
-  // ones listed by passthrough_varnames were modified on the server.
-  {
-    query.config.environment.Insert("foo", "NEW_FOO");
-    query.config.environment.Insert("undefined", "SURPRISE!");
-
-    StdioAsyncStringRedirector buffered_stdout(async_loop, stdout);
-    bool ret = client.RunQuery(compat, query, &exit_code, &error);
-    if (!ret)
-      fprintf(stderr, "\nERROR: %s\n", error.c_str());
-    std::string result;
-    EXPECT_TRUE(buffered_stdout.WaitForResult(&result));
-
-    ASSERT_TRUE(ret);
-    EXPECT_EQ(0u, exit_code);
-    EXPECT_EQ(result, "bar=BAR\nfoo=NEW_FOO\nundefined=SURPRISE!\n");
-  }
-
-  ASSERT_TRUE(client.IsServerRunning(build_dir));
-
-  ASSERT_TRUE(client.StopServer(build_dir, &error));
-}
-
-#endif  // !_WIN32
diff --git a/src/persistent_mode_test_helper.cc b/src/persistent_mode_test_helper.cc
deleted file mode 100644
index ca22500..0000000
--- a/src/persistent_mode_test_helper.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2023 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 <stdio.h>
-#include <stdlib.h>
-
-#include "persistent_mode.h"
-#include "persistent_mode_test_lib.cc"
-#include "util.h"
-
-int main(int argc, char** argv) {
-  fprintf(stderr, "STARTING SERVER IN %s\n", GetCurrentDir().c_str());
-  int64_t connection_timeout_ms = 3000;
-  auto compatibility = persistent_mode_test::GetServerCompatibility(
-      argc, argv, &connection_timeout_ms);
-  persistent_mode_test::RunServerThenExit(compatibility, connection_timeout_ms);
-  return 127;
-}
diff --git a/src/persistent_mode_test_lib.cc b/src/persistent_mode_test_lib.cc
deleted file mode 100644
index 3d45355..0000000
--- a/src/persistent_mode_test_lib.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2023 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 "persistent_mode_test_lib.h"
-
-#ifdef _WIN32
-#include "getopt.h"
-#elif defined(_AIX)
-#include "getopt.h"
-#else
-#include <getopt.h>
-#endif
-
-#include <string>
-
-#include "util.h"
-
-namespace persistent_mode_test {
-
-namespace {
-
-struct ServerState {
-  ServerState(const PersistentMode::Compatibility& compatibility,
-              int64_t connection_timeout_ms)
-      : server_(compatibility) {
-    server_.SetConnectionTimeoutMs(connection_timeout_ms);
-  }
-
-  void RunServerThenExit() {
-    server_.RunServerThenExit(
-        [this]() { return RestartCheck(); },
-        [this](const PersistentMode::BuildQuery& query) -> int {
-          return HandleQuery(query);
-        });
-  }
-
-  bool RestartCheck() { return false; };
-
-  int HandleQuery(const PersistentMode::BuildQuery& query) {
-    if (query.tool == "print-current-dir") {
-      fprintf(stdout, "%s", GetCurrentDir().c_str());
-      return 0;
-    }
-    if (query.tool == "get-env-vars") {
-      for (const auto& varname : query.args) {
-        const char* varvalue = query.config.environment.Get(varname.c_str());
-        if (!varvalue)
-          varvalue = "<UNSET>";
-        fprintf(stdout, "%s=%s\n", varname.c_str(), varvalue);
-      }
-      return 0;
-    }
-    fprintf(stderr, "UNKNOWN QUERY TYPE!\n");
-    return 1;
-  }
-
-  // Create new query to print the current directory.
-  static PersistentMode::BuildQuery MakeQuery1(const std::string& build_dir) {
-    PersistentMode::BuildQuery query;
-    query.tool = "print-current-dir";
-    return query;
-  }
-
-  // Create a new query to print the environment variables of the server
-  // process.
-  static PersistentMode::BuildQuery MakeQuery2(
-      const std::vector<std::string>& print_variables) {
-    PersistentMode::BuildQuery query;
-    query.tool = "get-env-vars";
-    query.args = print_variables;
-    return query;
-  }
-  PersistentMode::Server server_;
-};
-
-}  // namespace
-
-std::string GetServerExecutable() {
-  std::string result =
-      GetCurrentExecutableDir() + "/persistent_mode_test_helper";
-#ifdef _WIN32
-  result += ".exe";
-#endif
-  return result;
-}
-
-PersistentMode::Compatibility GetClientCompatibility(
-    const std::string& build_dir) {
-  PersistentMode::Compatibility result;
-  result.SetNinjaVersionForTest("version-1.0")
-      .SetInputFile("persistent_mode.input")
-      .SetBuildDir(build_dir);
-  return result;
-}
-
-PersistentMode::Compatibility GetServerCompatibility(
-    int argc, char** argv, int64_t* connection_timeout_ms) {
-  const char* progname = argv[0];
-
-  auto print_usage = [progname]() {
-    fprintf(stderr,
-            "Usage: %s [-C BUILD_DIR] [-f INPUT_FILE] [-t TIMEOUT_MILLIS] [-w "
-            "WARNING]+\n",
-            progname);
-    exit(1);
-  };
-
-  PersistentMode::Compatibility result;
-
-  int opt;
-  while ((opt = getopt(argc, argv, const_cast<char*>("C:f:w:t:"))) != -1) {
-    fprintf(stderr, "OPT %c\n", opt);
-    switch (opt) {
-    case 'C':
-      result.SetBuildDir(optarg);
-      break;
-    case 'f':
-      result.SetInputFile(optarg);
-      break;
-    case 'w':
-      if (!strcmp(optarg, "dupbuild=err")) {
-        result.SetFlagDupeEdgesShouldErr(true);
-      } else if (!strcmp(optarg, "dupbuild=warn")) {
-        result.SetFlagDupeEdgesShouldErr(false);
-      } else if (!strcmp(optarg, "phonycycle=err")) {
-        result.SetFlagPhonyCycleShouldErr(true);
-      } else if (!strcmp(optarg, "phonycycle=warn")) {
-        result.SetFlagPhonyCycleShouldErr(false);
-      } else {
-        Fatal("Unknown -d argument value: %s", optarg);
-      }
-      break;
-    case 't':
-      *connection_timeout_ms = static_cast<int64_t>(atoll(optarg));
-      break;
-    default:
-      print_usage();
-    }
-  }
-  fprintf(stderr, "argc=%d optind=%d\n", argc, optind);
-  argc -= optind;
-  argv += optind;
-  if (argc > 0)
-    print_usage();
-
-  // Must match the version in GetClientCompatibility().
-  result.SetNinjaVersionForTest("version-1.0");
-  return result;
-}
-
-PersistentMode::BuildQuery GetClientTestQuery1(const std::string& build_dir) {
-  return ServerState::MakeQuery1(build_dir);
-}
-
-PersistentMode::BuildQuery GetClientTestQuery2(
-    const std::vector<std::string>& print_variables) {
-  return ServerState::MakeQuery2(print_variables);
-}
-
-void RunServerThenExit(const PersistentMode::Compatibility& compatibility,
-                       int64_t connection_timeout_ms) {
-  ServerState state(compatibility, connection_timeout_ms);
-  state.RunServerThenExit();
-}
-
-}  // namespace persistent_mode_test
diff --git a/src/persistent_mode_test_lib.h b/src/persistent_mode_test_lib.h
deleted file mode 100644
index 98b725e..0000000
--- a/src/persistent_mode_test_lib.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2023 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 <vector>
-
-#include "persistent_mode.h"
-
-namespace persistent_mode_test {
-
-// Return path to the server executable for this test.
-extern std::string GetServerExecutable();
-
-// Return a PersistentMode::Compatibility value for the default service
-// implementation.
-extern PersistentMode::Compatibility GetClientCompatibility(
-    const std::string& build_dir);
-
-// Return a PersistentMode::Compatibility value to be used on the server,
-// from the command-line content.
-extern PersistentMode::Compatibility GetServerCompatibility(
-    int argc, char** argv, int64_t* connection_timeout_ms);
-
-extern PersistentMode::BuildQuery GetClientTestQuery1(
-    const std::string& build_dir);
-
-extern PersistentMode::BuildQuery GetClientTestQuery2(
-    const std::vector<std::string>& print_variables);
-
-}  // namespace persistent_mode_test
diff --git a/src/persistent_service.cc b/src/persistent_service.cc
deleted file mode 100644
index 2a3726d..0000000
--- a/src/persistent_service.cc
+++ /dev/null
@@ -1,624 +0,0 @@
-// Copyright 2023 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 "persistent_service.h"
-
-#include "async_loop.h"
-#include "ipc_utils.h"
-#include "util.h"
-
-#define DEBUG 0
-
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#endif
-
-#if DEBUG
-#define SERVER_LOG(...)              \
-  do {                               \
-    fprintf(stderr, "SERVER_LOG: "); \
-    fprintf(stderr, __VA_ARGS__);    \
-    fprintf(stderr, "\n");           \
-  } while (0)
-#define CLIENT_LOG(...)              \
-  do {                               \
-    fprintf(stderr, "CLIENT_LOG: "); \
-    fprintf(stderr, __VA_ARGS__);    \
-    fprintf(stderr, "\n");           \
-  } while (0)
-#else
-#define CLIENT_LOG(...) (void)0
-#define SERVER_LOG(...) (void)0
-#endif
-
-namespace {
-
-// Sleep for |delay_ms| milliseconds.
-void SleepMilliSeconds(int delay_ms) {
-#ifdef _WIN32
-  if (delay_ms > 0)
-    ::Sleep(static_cast<DWORD>(delay_ms));
-#else
-  usleep(static_cast<useconds_t>(delay_ms) * 1000);
-#endif
-}
-
-struct ProcessInfo {
-#ifdef _WIN32
-  HANDLE process_handle;
-#else
-  pid_t process_pid;
-#endif
-};
-
-// Start a new process, with command-line |args|.
-// Uses fork()/exec() on Posix, and CreateProcess on Win32.
-// Return true on success, or set |*err| and return false on failure.
-bool SpawnServerProcess(const PersistentService::Config& config,
-                        ProcessInfo* info, std::string* err) {
-  if (config.command.empty()) {
-    *err = "Empty command line!";
-    return false;
-  }
-
-#ifdef _WIN32
-  std::string command_string;
-  for (const auto& arg : config.command) {
-    std::string escaped;
-    GetWin32EscapedString(arg, &escaped);
-    command_string += escaped;
-    command_string += ' ';
-  }
-  // Remove trailing space if any.
-  if (!command_string.empty())
-    command_string.resize(command_string.size() - 1u);
-
-  SECURITY_ATTRIBUTES security_attributes = {};
-  security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
-  security_attributes.bInheritHandle = TRUE;
-  // Must be inheritable so subprocesses can dup to children.
-  HANDLE nul =
-      CreateFileA("NUL", GENERIC_READ | GENERIC_WRITE,
-                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                  &security_attributes, OPEN_EXISTING, 0, NULL);
-  if (nul == INVALID_HANDLE_VALUE)
-    Win32Fatal("couldn't open nul");
-
-  HANDLE log = nul;
-  std::string log_file = config.log_file;
-  if (log_file.empty()) {
-    // As a debug helper, use the log file from this environment variable.
-    const char* env = getenv("DEBUG_PERSISTENT_SERVICE_LOG_FILE");
-    if (env)
-      log_file = env;
-  }
-  if (!log_file.empty()) {
-    log =
-        CreateFileA(log_file.c_str(), STANDARD_RIGHTS_WRITE | FILE_APPEND_DATA,
-                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                    &security_attributes, OPEN_ALWAYS, 0, NULL);
-    if (log == INVALID_HANDLE_VALUE)
-      Win32Fatal("couldn't open log file", log_file.c_str());
-  }
-
-  STARTUPINFOA startup_info = {};
-  startup_info.cb = sizeof(STARTUPINFO);
-  startup_info.dwFlags = STARTF_USESTDHANDLES;
-  startup_info.hStdInput = nul;
-  startup_info.hStdOutput = log;
-  startup_info.hStdError = log;
-  PROCESS_INFORMATION process_info = {};
-
-  // Ninja handles ctrl-c, except for subprocesses in console pools.
-  DWORD process_flags = CREATE_NEW_PROCESS_GROUP;
-
-  {
-    // TODO(digit): Create new environment variable block and add/replace
-    // the value in it, without touching the parent env.
-    for (const auto& pair : config.env_vars) {
-      const char* varname = pair.first.c_str();
-      const char* value = pair.second.c_str();
-      SetEnvironmentVariable(varname, value);
-    }
-  }
-
-  // Do not prepend 'cmd /c' on Windows, this breaks command
-  // lines greater than 8,191 chars.
-  if (!CreateProcessA(NULL, (char*)command_string.c_str(), NULL, NULL,
-                      /* inherit handles */ TRUE, process_flags, NULL, NULL,
-                      &startup_info, &process_info)) {
-    DWORD error = GetLastError();
-    if (error == ERROR_FILE_NOT_FOUND) {
-      CloseHandle(nul);
-      if (log != nul)
-        CloseHandle(log);
-      // child_ is already NULL;
-      *err =
-          "CreateProcess failed: The system cannot find the file "
-          "specified: [" +
-          command_string + "]";
-      return false;
-    } else {
-      fprintf(stderr, "\nCreateProcess failed. Command attempted:\n\"%s\"\n",
-              command_string.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) {
-        hint = "is the command line too long?";
-      }
-      Win32Fatal("CreateProcess", hint);
-    }
-  }
-
-  CloseHandle(nul);
-  if (log != nul)
-    CloseHandle(log);
-
-  CloseHandle(process_info.hThread);
-  return true;
-#else   // !_WIN32
-  // Build arguments array for future exec() call.
-  std::vector<char*> exec_args;
-  exec_args.reserve(config.command.size() + 1);
-  for (const auto& arg : config.command) {
-    exec_args.push_back(const_cast<char*>(arg.data()));
-    CLIENT_LOG("CMD: [%s]", arg.c_str());
-  }
-  exec_args.push_back(nullptr);
-
-  pid_t process = fork();
-  if (process < 0) {
-    *err = "fork failed()!";
-    return false;
-  }
-
-  if (process == 0) {
-    // Create new session to not receive signals from parent process group.
-    if (setsid() < 0) {
-      fprintf(stderr, "ERROR: setsid() failed: %s\n", strerror(errno));
-      exit(1);
-    }
-
-    // Change current working directory.
-    if (!config.working_dir.empty()) {
-      const char* work_dir = config.working_dir.c_str();
-      if (chdir(work_dir) < 0)
-        ErrnoFatal("chdir", work_dir);
-    }
-
-    // Redirect stdin to /dev/null and stdout/stderr to a log file if
-    // PERSISTENT_SERVER_LOG_FILE is set in the environment, or to
-    // /dev/null otherwise.
-    int null_fd = open("/dev/null", O_RDWR);
-    if (null_fd < 0) {
-      fprintf(stderr, "ERROR: open(/dev/null) failed: %s\n", strerror(errno));
-      exit(1);
-    }
-    int log_fd = null_fd;
-    std::string log_file = config.log_file;
-    if (log_file.empty()) {
-      // As a debug helper, use the log file from this environment variable.
-      const char* env = getenv("DEBUG_PERSISTENT_SERVICE_LOG_FILE");
-      if (env)
-        log_file = env;
-    }
-    if (!log_file.empty()) {
-      log_fd = open(log_file.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0755);
-      if (log_fd < 0) {
-        fprintf(stderr, "ERROR: open(%s) failed: %s\n", log_file.c_str(),
-                strerror(errno));
-        exit(1);
-      }
-    }
-
-    fflush(stdout);
-    fflush(stderr);
-
-    dup2(null_fd, 0);
-    dup2(log_fd, 1);
-    dup2(log_fd, 2);
-
-    // Set extra environment variables.
-    for (const auto& pair : config.env_vars) {
-      const char* varname = pair.first.c_str();
-      const char* value = pair.second.c_str();
-      setenv(varname, value, 1);
-    }
-
-    fprintf(stderr, "\n\nSTARTING NEW PERSISTENT SERVER: %s\n",
-            config.command[0].c_str());
-    execv(config.command[0].c_str(), exec_args.data());
-    fprintf(stderr, "ERROR: exec() failed: %s\n", strerror(errno));
-    exit(1);
-  }
-  // In parent process, do not do anything.
-  info->process_pid = process;
-  return true;
-#endif  // !_WIN32
-}
-
-// Type of commands received from the server.
-enum ServerCommandType {
-  kServerCommandTypeStop,
-  kServerCommandTypeGetPid,
-  kServerCommandTypeClientQuery,
-};
-
-}  // namespace
-
-///////////////////////////////////////////////////////////////////////////
-///
-///   C L I E N T   S I D E
-///
-
-PersistentService::Client::Client(const std::string& service_name)
-    : service_name_(service_name) {}
-
-PersistentService::Client::~Client() = default;
-
-bool PersistentService::Client::HasServer() const {
-  return IpcServiceHandle::IsBound(service_name_);
-}
-
-int PersistentService::Client::GetServerPid() const {
-  std::string err;
-  IpcHandle client = RawConnect(&err);
-  if (!client)
-    return -1;
-
-  uint8_t query_type = kServerCommandTypeGetPid;
-  int server_pid = -1;
-  if (!RemoteWrite(query_type, client, &err) ||
-      !RemoteRead(server_pid, client, &err)) {
-    return -1;
-  }
-  return server_pid;
-}
-
-bool PersistentService::Client::StopServer(std::string* err) const {
-  IpcHandle client = RawConnect(err);
-  if (!client)
-    return false;
-
-  uint8_t query_type = kServerCommandTypeStop;
-  if (!client.Write(&query_type, sizeof(query_type), err)) {
-    *err = StringFormat("Could not stop server: %s", err->c_str());
-    return false;
-  }
-
-  return true;
-}
-
-bool PersistentService::Client::WaitForServerShutdown() {
-  std::string error;
-  for (int retry_count = 20; retry_count > 0; --retry_count) {
-    if (!HasServer())
-      return true;
-
-    SleepMilliSeconds(100);
-  }
-  return false;
-}
-
-IpcHandle PersistentService::Client::Connect(const Config& config,
-                                             std::string* error) {
-  bool try_again = true;
-
-  while (true) {
-    CLIENT_LOG("Trying to connect to server.");
-    IpcHandle client = ConnectOrStartServer(config, error);
-    if (!client)
-      return {};
-
-    CLIENT_LOG("Sending version info to server.");
-    if (!RemoteWrite(config.version_info, client, error)) {
-      *error = "Could not send version info: " + *error;
-      return {};
-    }
-
-    // Receive the |compatible| flag that indicates that the server is
-    // compatible with the current build plan.
-    std::string version_check;
-    if (!RemoteRead(version_check, client, error)) {
-      *error = "Could not read version check result: " + *error;
-      return {};
-    }
-
-    if (version_check.empty()) {
-      // Good, return the handle now.
-      return client;
-    }
-
-    // The server was not compatible with the current client.
-    // Assume it exited, and start another one at least once.
-    CLIENT_LOG("Incompatible server version: %s", version_check.c_str());
-
-    if (!try_again) {
-      // Already tried once, so report failure.
-      CLIENT_LOG("Failed to connect to or start server!");
-      return {};
-    }
-
-    try_again = false;
-    CLIENT_LOG("Waiting for incompatible server shutdown.");
-    if (!WaitForServerShutdown()) {
-      *error = "Could not shutdown incompatible server!?!";
-      return {};
-    }
-  }
-}
-
-IpcHandle PersistentService::Client::RawConnect(std::string* err) const {
-  return IpcServiceHandle::ConnectTo(service_name_, err);
-}
-
-IpcHandle PersistentService::Client::ConnectOrStartServer(
-    const Config& config, std::string* err) const {
-  int retry_count = 5;
-  int retry_delay_ms = 10;
-  bool server_started = false;
-  ProcessInfo info = {};
-  while (true) {
-    // Try to connect to the server first.
-    IpcHandle client = RawConnect(err);
-    if (client) {
-      CLIENT_LOG("Got client connection to server!");
-      uint8_t query_type = kServerCommandTypeClientQuery;
-      if (!client.Write(&query_type, sizeof(query_type), err)) {
-        CLIENT_LOG(
-            "ERROR: Could not write query type, did server disconnect?: %s",
-            err->c_str());
-        client.Close();
-      } else {
-        CLIENT_LOG("Sent query type");
-      }
-      return client;
-    }
-
-    if (!server_started) {
-      CLIENT_LOG("No initial connection. Spawning server");
-      // Spawn a server if one wasn't already started.
-      if (!SpawnServerProcess(config, &info, err)) {
-        CLIENT_LOG("Could not spawn server: %s", err->c_str());
-        return {};
-      }
-      server_started = true;
-
-    } else if (retry_count == 0) {
-      CLIENT_LOG("Failure to connect to server, exiting retry loop: %s",
-                 err->c_str());
-      return {};
-    } else {
-      --retry_count;
-      if (retry_delay_ms < 1024)
-        retry_delay_ms *= 2;
-    }
-
-    CLIENT_LOG("Waiting for %ld milliseconds", (long)retry_delay_ms);
-    SleepMilliSeconds(retry_delay_ms);
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////
-///
-///   S E R V E R   S I D E
-///
-
-PersistentService::Server::Server(const std::string& service_name)
-    : service_name_(service_name) {}
-
-bool PersistentService::Server::BindService(std::string* err) {
-  if (service_handle_) {
-    *err = "Server already started!";
-    return false;
-  }
-  SERVER_LOG("Trying to get service %s", service_name_.c_str());
-  service_handle_ = IpcServiceHandle::BindTo(service_name_, err);
-  if (!service_handle_)
-    SERVER_LOG("Got error %s", err->c_str());
-  else
-    SERVER_LOG("Got it!");
-  return !!service_handle_;
-}
-
-void PersistentService::Server::RunServerThenExit(
-    const VersionCheckHandler& version_check_handler,
-    const RequestHandler& request_handler) {
-  std::string error;
-  if (!service_handle_ && !BindService(&error)) {
-    Error("Could not acquire service handle: %s", error.c_str());
-    exit(1);
-  }
-  SERVER_LOG("Service handle acquired, starting server loop");
-  RunServerThenExitInternal(version_check_handler, std::move(request_handler));
-}
-
-void PersistentService::Server::RunServerThenExitInternal(
-    const VersionCheckHandler& version_check_handler,
-    const RequestHandler& request_handler) {
-  AsyncLoop& async_loop = AsyncLoop::Get();
-  std::string error;
-#ifndef _WIN32
-  SigPipeBlocker sig_pipe_blocker;
-#endif
-
-  /// Convenience class to wait for client connections with a timeout.
-  /// Usage is:
-  ///
-  ///   1) Create class, passing references to an IpcServiceHandle
-  ///      and an AsyncLoop instance.
-  ///
-  ///   2) Call Wait() to wait for a new connection.
-  ///
-  ///   3) Either destroy the instance, or call Close() before that to
-  ///      ensure the corresponding server handle is closed before
-  ///      calling exit().
-  ///
-  class ConnectionWaiter {
-   public:
-    /// Constructor sets up an internal AsyncHandle to do the wait.
-    /// Note that this moves the native service handle into this instance, but
-    /// |service_handle| still needs to be closed manually before calling
-    /// ::exit(), because on MacOS it does extra work to remove a Unix socket
-    /// and pid file.
-    ConnectionWaiter(IpcServiceHandle& service_handle, AsyncLoop& async_loop)
-      : async_loop_(async_loop), async_(
-        AsyncHandle::Create(std::move(service_handle), async_loop, callback())) {}
-
-    /// Wait for a new client connection for |timeout_ms| milliseconds.
-    /// Return AsyncLoop exit status, on success, set |client| to receive
-    /// the new client connection handle.
-    AsyncLoop::ExitStatus Wait(int64_t timeout_ms, IpcHandle& client) {
-      completed_ = false;
-      accepted_ = false;
-
-      int64_t now_ms = async_loop_.NowMs();
-      (void)now_ms;  // silence compiler when SERVER_LOG() expansion is empty.
-
-      if (timeout_ms < 0) {
-        SERVER_LOG("Waiting for new client connection (no timeout)");
-      } else {
-        SERVER_LOG("Waiting for new client connection (for up to %.1f seconds)",
-                  timeout_ms / 1000.);
-      }
-
-      async_.StartAccept();
-      auto status = async_loop_.RunUntil([this]() { return completed_; },
-                                         timeout_ms);
-
-      if (accepted_)
-        client = async_.TakeAcceptedHandle();
-
-      SERVER_LOG("Connection time %s",
-                 StringFormatDurationMs(async_loop_.NowMs() - now_ms).c_str());
-      return status;
-    }
-
-    /// Close the internal handle explicitly.
-    void Close() {
-      async_.Close();
-    }
-
-   private:
-    AsyncLoop& async_loop_;
-    AsyncHandle async_;
-    IpcHandle client_;
-    bool completed_ = false;
-    bool accepted_ = false;
-
-    // Return the AsyncHandle::Callback to be used by |async| in this instance.
-    AsyncHandle::Callback callback() {
-      return [this](AsyncError error, size_t) {
-        completed_ = true;
-        accepted_ = (error == 0);
-      };
-    }
-  };
-
-  ConnectionWaiter waiter(service_handle_, async_loop);
-  while (true) {
-    IpcHandle client;
-    AsyncLoop::ExitStatus status = waiter.Wait(connection_timeout_ms_, client);
-
-    if (status == AsyncLoop::ExitInterrupted)
-      break;
-
-    if (status == AsyncLoop::ExitTimeout) {
-      SERVER_LOG("Timeout waiting for client connection");
-      break;
-    }
-    if (!client) {
-      SERVER_LOG("Could not accept new client: %s", error.c_str());
-      break;
-    }
-
-    SERVER_LOG("Reading query type...");
-    // Get command, which can be 'kill' or 'query' at the moment.
-    uint8_t query_type = 0;
-    if (!client.Read(&query_type, sizeof(query_type), &error)) {
-      SERVER_LOG("Could not read client query type !?");
-      break;
-    }
-
-    SERVER_LOG("Got query_type %d\n", query_type);
-
-    if (query_type == kServerCommandTypeStop) {
-      SERVER_LOG("Client asking server to stop!");
-      break;
-    }
-    if (query_type == kServerCommandTypeGetPid) {
-      SERVER_LOG("Client asking for server pid!");
-#ifdef _WIN32
-      int pid = static_cast<int>(GetCurrentProcessId());
-#else
-      int pid = getpid();
-#endif
-      if (!RemoteWrite(pid, client, &error)) {
-        SERVER_LOG("Could not send pid %d back to client!: %s", pid,
-                   error.c_str());
-        break;
-      }
-      SERVER_LOG("Sent pid %d to client. Looping", pid);
-      continue;
-    }
-    if (query_type != kServerCommandTypeClientQuery) {
-      SERVER_LOG("Unknown client query type: %d", query_type);
-      break;
-    }
-
-    SERVER_LOG("Accepted client connection, checking version info");
-    std::string version_info;
-    if (!RemoteRead(version_info, client, &error)) {
-      SERVER_LOG("Could not client version info: %s", error.c_str());
-      break;
-    }
-
-    std::string version_check = version_check_handler(version_info);
-    if (!RemoteWrite(version_check, client, &error)) {
-      SERVER_LOG("Could not write version check result to client: %s",
-                 error.c_str());
-      break;
-    }
-
-    if (!version_check.empty()) {
-      SERVER_LOG("Incompatible client version info: %s", version_check.c_str());
-      break;
-    }
-
-    if (!request_handler(std::move(client))) {
-      SERVER_LOG("Request handler returned false, exiting server loop");
-      break;
-    }
-    async_loop.ClearInterrupt();
-  }
-  SERVER_LOG("Exiting!");
-
-  // Since calling ::exit() directly here prevents the destructors
-  // of the variables defined in this function from running, close the
-  // waiter handle explicitly.
-  waiter.Close();
-
-  // Note: while the file descriptor was moved to waiter, this
-  // instance must be destroyed explicitly to remove the pid file and
-  // Unix socket filesystem entry on MacOS.
-  service_handle_.Close();
-
-  ::exit(0);
-}
diff --git a/src/persistent_service.h b/src/persistent_service.h
deleted file mode 100644
index d54e3f7..0000000
--- a/src/persistent_service.h
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright 2023 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_PERSISTENT_SERVICE_H_
-#define NINJA_PERSISTENT_SERVICE_H_
-
-#include <functional>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "ipc_handle.h"
-
-/// PersistentService implements a "persistent server" mode for
-/// command-line executables. The main idea is that a client process
-/// uses an anonymous pipe (on Win32) or a Unix domain socket (on Posix)
-/// to connect to a server process, then ask for work to be done by
-/// the server on its behalf.
-///
-/// If a server is not available, the client process will automatically launch
-/// one, as a detached background process. Supports both Posix and Windows.
-///
-/// After creating an instance, usage on the client side is:
-///
-///    1) Create a PersistentService::Config object describing how to launch
-///       the server, if needed.
-///
-///    2) Call CreateClient() which will give an IpcHandle to communicate with
-///       the server from the current process.
-///
-///
-/// While usage on the server is:
-///
-///    1) Call BindService() to immediately bind the service pipe/socket.
-///       This is optional, but is useful when the server needs to perform
-///       a long setup operation before serving client requests.
-///
-///    2) Call RunServerThenExit() to enter an infinite loop to serve
-///       client queries. This takes two callable objects that will be invoked
-///       on each query.
-///
-
-class PersistentService {
- public:
-  /// Convenience struct to hold the configuration used to spawn
-  /// a new server. This includes a command line, optional working directory,
-  /// and other options.
-  struct Config {
-    /// Constructor provides the command used to spawn the new server process.
-    explicit Config(const std::vector<std::string>& server_command)
-        : command(server_command) {}
-
-    /// Set the working directory to be used when running the server process.
-    /// If empty (the default), not change will be applied.
-    Config& SetWorkingDir(const std::string& dir) {
-      working_dir = dir;
-      return *this;
-    }
-
-    /// By default, the server process redirects its stdin/stdout/stderr
-    /// to /dev/null. Call this method to specify the path of a file where
-    /// server logs will be written to instead.
-    Config& SetLogFile(const std::string& log_file_path) {
-      log_file = log_file_path;
-      return *this;
-    }
-
-    /// Add an environment variable definition that will be set before
-    /// spawning a server process.
-    Config& AddEnvVariable(const char* name, const char* value) {
-      env_vars.push_back(std::make_pair(name, value));
-      return *this;
-    }
-
-    /// Set a string describing version information that will be matched
-    /// against each new client connection. A mistmatch will be reported
-    /// then the server will stop automatically.
-    Config& SetVersionInfo(const std::string& info) {
-      version_info = info;
-      return *this;
-    }
-
-    std::vector<std::string> command;
-    std::string working_dir;
-    std::string version_info;
-    std::string log_file;
-    std::vector<std::pair<std::string, std::string>> env_vars;
-  };
-
-  ///////////////////////////////////////////////////////////////////////////
-  ///
-  ///   C L I E N T   S I D E
-  ///
-
-  class Client {
-   public:
-    /// Create new instance. This doesn't do anything yet.
-    /// |service_name| is a unique service name, used to create a named pipe
-    /// on the host system.
-    explicit Client(const std::string& service_name);
-
-    /// Destructor. Note that this does *not* kill any server instance
-    /// started by this client.
-    ~Client();
-
-    /// Returns true if a server is already running for the service.
-    bool HasServer() const;
-
-    /// Return server PID if it exists, or -1 otherwise.
-    int GetServerPid() const;
-
-    /// Stop a server. Return true on success (meaning there was a server, and
-    /// that it was asked to stop), and false otherwise. Note that the function
-    /// returns immediately after sending the stop command. Use
-    /// WaitForServerShutdown() to wait for its complete shutdown if needed.
-    bool StopServer(std::string* err) const;
-
-    /// Wait until the server is properly shutdown after a StopServer() call.
-    /// Returns after 2 seconds max, return true on success, false otherwise.
-    bool WaitForServerShutdown();
-
-    /// Create new client connection. This will start a server automatically
-    /// if one is not already running. If an existing server has incompatible
-    /// version_info, it is also stopped and another instance restarted.
-    ///
-    /// In case of error, return an invalid IpcHandle and sets |*err|.
-    /// In case of success, the result can be used to communicate with the
-    /// server.
-    IpcHandle Connect(const Config& config, std::string* err);
-
-   private:
-    IpcHandle RawConnect(std::string* err) const;
-    IpcHandle ConnectOrStartServer(const Config& config,
-                                   std::string* err) const;
-
-    std::string service_name_;
-  };
-
-  ///////////////////////////////////////////////////////////////////////////
-  ///
-  ///   S E R V E R   S I D E
-  ///
-
-  class Server {
-   public:
-    /// Create new instance, |service_name| is the unique service name
-    /// and |config| is the server configuration that will be used by the
-    /// server.
-    explicit Server(const std::string& service_name);
-
-    /// Change the connection timeout, in milliseconds, used by a server
-    /// loop when waiting for new client connections. On expiration, the server
-    /// will shut down graciously. The default value (-1) means no timeout.
-    void SetConnectionTimeoutMs(int64_t connection_timeout_ms) {
-      connection_timeout_ms_ = connection_timeout_ms;
-    }
-
-    /// Bind to the service named pipe early. This is called implicitly by
-    /// RunServerThenExit() but can be called earlier from a server process
-    /// before expensive operations, in order to avoid races.
-    bool BindService(std::string* err);
-
-    /// A callable that receives a version_info string from the client and
-    /// compares it to its own version. Returns an empty string when the
-    /// versions are compatible, or a failure message otherwise.
-    using VersionCheckHandler = std::function<std::string(const std::string&)>;
-
-    /// A callable object that receives an IpcHandle corresponding to a new
-    /// client request. Returns true to indicate that the server should keep
-    /// running, or false to tell it to exit immediately.
-    using RequestHandler = std::function<bool(IpcHandle)>;
-
-    /// Start a server in the current process, then start a loop that waits for
-    /// a client request. This function never returns (and calls exit() directly
-    /// when needed).
-    ///
-    /// For each request, the client's Config::version_info string is received
-    /// and passed to |version_check_handler| to verify that it is compatible
-    /// with the client. If this callable returns a non-empty string, the loop
-    /// exits after reporting the mismatch to the client.
-    ///
-    /// Otherwise, |request_handler| is invoked, receiving ownership of the
-    /// client connection handle. If this returns true, the function exits.
-    ///
-    /// This function should only be called when starting a server executable.
-    void RunServerThenExit(const VersionCheckHandler& version_check_handler,
-                           const RequestHandler& request_handler);
-
-   private:
-    void RunServerThenExitInternal(
-        const VersionCheckHandler& version_check_handler,
-        const RequestHandler& request_handler);
-
-    std::string service_name_;
-    int64_t connection_timeout_ms_ = -1;
-    IpcServiceHandle service_handle_;
-  };
-};
-
-#endif  // NINJA_PERSISTENT_SERVICE_H_
diff --git a/src/persistent_service_test.cc b/src/persistent_service_test.cc
deleted file mode 100644
index 5fda0d5..0000000
--- a/src/persistent_service_test.cc
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2023 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 "persistent_service.h"
-
-#include "persistent_service_test_lib.cc"
-#include "test.h"
-#include "util.h"
-
-#ifndef _WIN32
-#include <unistd.h>  // For sleep()
-#endif
-
-static std::string kTestServiceName = persistent_service_test::kServiceName;
-
-class PersistentServiceServerTest : public ::testing::Test {
- public:
-  PersistentServiceServerTest() : server(kTestServiceName) {}
-
-  PersistentService::Server server;
-};
-
-class PersistentServiceClientTest : public ::testing::Test {
- public:
-  PersistentServiceClientTest() : client(kTestServiceName) {}
-
-  void TearDown() override {
-    // Ensure any server process started by the test is stopped.
-    if (!client.HasServer())
-      return;
-
-    std::string err;
-    if (!client.StopServer(&err)) {
-      fprintf(stderr, "\nERROR: %s", err.c_str());
-      AddAssertionFailure();
-    } else {
-      if (!client.WaitForServerShutdown()) {
-        fprintf(stderr, "\nERROR: Could not shutdown server!\n");
-        AddAssertionFailure();
-      }
-    }
-  }
-
-  PersistentService::Client client;
-};
-
-TEST_F(PersistentServiceServerTest, BindService) {
-  std::string error;
-  EXPECT_TRUE(server.BindService(&error));
-
-  PersistentService::Client client(kTestServiceName);
-  EXPECT_TRUE(client.HasServer());
-}
-
-TEST_F(PersistentServiceClientTest, DefaultMode) {
-  std::string error;
-  auto config = persistent_service_test::GetServerConfig();
-  IpcHandle conn = client.Connect(config, &error);
-  if (!conn)
-    fprintf(stderr, "ERROR [%s]\n", error.c_str());
-  ASSERT_TRUE(conn);
-
-  EXPECT_TRUE(client.HasServer());
-
-  bool success = persistent_service_test::RunTest(conn, false, &error);
-  if (!success)
-    fprintf(stderr, "ERROR: %s\n", error.c_str());
-  ASSERT_TRUE(success);
-
-  EXPECT_TRUE(client.HasServer());
-
-  success = persistent_service_test::RunTest(conn, true, &error);
-  if (!success)
-    fprintf(stderr, "ERROR: %s\n", error.c_str());
-  ASSERT_TRUE(success);
-
-  ASSERT_TRUE(client.WaitForServerShutdown());
-  ASSERT_FALSE(client.HasServer());
-}
-
-TEST_F(PersistentServiceClientTest, WithConnectionTimeout) {
-  std::string error;
-  auto config = persistent_service_test::GetServerConfig();
-  persistent_service_test::SetServiceConfigTimeoutMs(config, 100);
-  IpcHandle conn = client.Connect(config, &error);
-  if (!conn)
-    fprintf(stderr, "ERROR [%s]\n", error.c_str());
-  ASSERT_TRUE(conn);
-
-  bool success = persistent_service_test::RunTest(conn, false, &error);
-  if (!success)
-    fprintf(stderr, "ERROR: %s\n", error.c_str());
-  ASSERT_TRUE(success);
-
-  conn.Close();
-
-#ifdef _WIN32
-  ::Sleep(1000);
-#else
-  ::sleep(1);
-#endif
-  EXPECT_FALSE(client.HasServer());
-}
-
-TEST_F(PersistentServiceClientTest, WithDifferentVersion) {
-  // First start an instance with the default version.
-  std::string error;
-  auto config = persistent_service_test::GetServerConfig();
-  IpcHandle conn = client.Connect(config, &error);
-  ASSERT_TRUE(conn);
-  bool success = persistent_service_test::RunTest(conn, false, &error);
-  ASSERT_TRUE(success);
-  EXPECT_TRUE(client.HasServer());
-
-  conn.Close();
-
-  persistent_service_test::SetServiceConfigVersion(config, "another");
-  conn = client.Connect(config, &error);
-  if (!conn)
-    fprintf(stderr, "ERROR: %s\n", error.c_str());
-  EXPECT_TRUE(conn);
-  EXPECT_TRUE(client.HasServer());
-}
diff --git a/src/persistent_service_test_helper.cc b/src/persistent_service_test_helper.cc
deleted file mode 100644
index b1e4eca..0000000
--- a/src/persistent_service_test_helper.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2023 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 <stdio.h>
-#include <stdlib.h>
-
-#include "persistent_service.h"
-#include "persistent_service_test_lib.cc"
-
-void PrintUsage(const char* progname) {
-  fprintf(stderr, "Usage: %s [-t<timeout>] [-v<version>]\n", progname);
-}
-
-int main(int argc, char** argv) {
-  const char* progname = argv[0];
-  PersistentService::Server server(persistent_service_test::kServiceName);
-
-  std::string version = persistent_service_test::kDefaultVersion;
-
-  for (; argc > 1; --argc, argv++) {
-    const char* arg = argv[1];
-    if (arg[0] != '-') {
-      PrintUsage(progname);
-      return 1;
-    }
-
-    switch (arg[1]) {
-    case 't':  // -t<value> Server timeout in milliseconds.
-      server.SetConnectionTimeoutMs(static_cast<int64_t>(atoll(arg + 2)));
-      break;
-    case 'v':  // -v<version> is server version.
-      version = arg + 2;
-      break;
-    default:
-      PrintUsage(progname);
-      return 1;
-    }
-  }
-
-  server.RunServerThenExit(
-      persistent_service_test::GetVersionCheckHandler(version),
-      persistent_service_test::RequestHandler);
-
-  return 0;
-}
diff --git a/src/persistent_service_test_lib.cc b/src/persistent_service_test_lib.cc
deleted file mode 100644
index 30735d4..0000000
--- a/src/persistent_service_test_lib.cc
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright 2023 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 "persistent_service_test_lib.h"
-
-#include <inttypes.h>
-
-#include "ipc_utils.h"
-#include "persistent_service.h"
-#include "util.h"
-
-#define DEBUG 0
-
-// Common macros used to print a prefix then an message to stderr.
-#define STDERR_PRINTF(prefix, ...) \
-  do {                             \
-    fputs(prefix, stderr);         \
-    fprintf(stderr, __VA_ARGS__);  \
-    fputs("\n", stderr);           \
-  } while (0)
-
-#if DEBUG
-#define SERVER_LOG(...) STDERR_PRINTF("TEST_SERVER: ", __VA_ARGS__)
-#define CLIENT_LOG(...) STDERR_PRINTF("TEST_CLIENT: ", __VA_ARGS__)
-#else
-#define SERVER_LOG(...) (void)0
-#define CLIENT_LOG(...) (void)0
-#endif
-
-#define SERVER_ERR(...) STDERR_PRINTF("TEST_SERVER: ERROR: ", __VA_ARGS__)
-#define SERVER_WARN(...) STDERR_PRINTF("TEST_SERVER: WARNING: ", __VA_ARGS__)
-
-#define CLIENT_ERR(...) STDERR_PRINTF("TEST_CLIENT: ERROR: ", __VA_ARGS__)
-#define CLIENT_WARN(...) STDERR_PRINTF("TEST_CLIENT: WARNING: ", __VA_ARGS__)
-
-namespace {
-
-std::vector<std::string> GetServerArgs(const std::string* version) {
-  std::vector<std::string> result;
-  std::string program =
-      GetCurrentExecutableDir() + "/persistent_service_test_helper";
-#ifdef _WIN32
-  program.append(".exe");
-#endif
-  result.push_back(std::move(program));
-  if (version)
-    result.push_back(*version);
-  return result;
-}
-
-// This is necessary because RemoteWrite("ping", ...) will send a 5-byte
-// character sequence (including the terminating zero), instead of a
-// string size + its content.
-bool SendString(const char* str, IpcHandle& con, std::string* err) {
-  return RemoteWrite(std::string(str), con, err);
-}
-
-}  // namespace
-
-namespace persistent_service_test {
-
-const char kServiceName[] = "persistent-server-test";
-
-const char kDefaultVersion[] = "default-version";
-
-PersistentService::Config GetServerConfig() {
-  PersistentService::Config config(GetServerArgs(nullptr));
-  return config.SetVersionInfo(kDefaultVersion);
-}
-
-void SetServiceConfigVersion(PersistentService::Config& config,
-                             const std::string& version) {
-  config.SetVersionInfo(version);
-  config.command.push_back(StringFormat("-v%s", version.c_str()));
-}
-
-void SetServiceConfigTimeoutMs(PersistentService::Config& config,
-                               int64_t connection_timeout_ms) {
-  config.command.push_back(StringFormat("-t%" PRId64, connection_timeout_ms));
-}
-
-PersistentService::Server::VersionCheckHandler GetVersionCheckHandler(
-    const std::string& server_version_info) {
-  return [server_version_info](
-             const std::string& client_version_info) -> std::string {
-    if (client_version_info != server_version_info) {
-      return StringFormat("Version mismatch, expected [%s] got [%s]",
-                          server_version_info.c_str(),
-                          client_version_info.c_str());
-    }
-    return {};
-  };
-}
-
-bool RequestHandler(IpcHandle connection) {
-  std::string error;
-  std::string request;
-  bool is_first = true;
-  while (true) {
-    SERVER_LOG("Waiting for request");
-    if (!RemoteRead(request, connection, &error)) {
-      if (!is_first) {
-        SERVER_LOG("Client connection closed");
-        return true;
-      }
-      SERVER_ERR("Could not read request: %s\n", error.c_str());
-      return false;
-    }
-    SERVER_LOG("Received request [%.*s]", (int)request.size(), request.c_str());
-
-    is_first = false;
-
-    if (request == "kill-server") {
-      SERVER_LOG("TEST_SERVER: kill-server command received, exiting");
-      return false;
-    }
-
-    if (request == "ping") {
-      SERVER_LOG("TEST_SERVER: ping request received, sending reply");
-      if (!SendString("pong", connection, &error)) {
-        SERVER_ERR("Could not send reply: %s\n", error.c_str());
-        return false;
-      }
-      SERVER_LOG("pong sent");
-      continue;
-    }
-
-    SERVER_ERR("Unknown request [%s]\n", request.c_str());
-    return false;
-  }
-}
-
-bool RunTest(IpcHandle& client, bool kill_server, std::string* err) {
-  if (!SendString("ping", client, err)) {
-    CLIENT_ERR("Could not send test request: %s\n", err->c_str());
-    return false;
-  }
-  std::string reply;
-  if (!RemoteRead(reply, client, err)) {
-    CLIENT_ERR("Could not receive test reply: %s\n", err->c_str());
-    return false;
-  }
-
-  bool success = (reply == "pong");
-  if (!success) {
-    CLIENT_ERR("Invalid reply [%s] expected [pong]\n", reply.c_str());
-    // Do not return here to ensure the server is killed.
-  }
-
-  if (kill_server) {
-    if (!SendString("kill-server", client, err)) {
-      CLIENT_ERR("Could not kill server: %s\n", err->c_str());
-    }
-
-    PersistentService::Client persistent(kServiceName);
-    if (!persistent.WaitForServerShutdown()) {
-      CLIENT_WARN("Could not wait for server shutdown\n");
-    }
-  }
-  return success;
-}
-
-}  // namespace persistent_service_test
diff --git a/src/persistent_service_test_lib.h b/src/persistent_service_test_lib.h
deleted file mode 100644
index 87431e1..0000000
--- a/src/persistent_service_test_lib.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2023 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_PERSISTENT_SERVICE_TEST_LIB_H_
-#define NINJA_PERSISTENT_SERVICE_TEST_LIB_H_
-
-#include <string>
-#include <vector>
-
-#include "ipc_handle.h"
-
-namespace persistent_service_test {
-
-/// Name of persistent service name for the test.
-extern const char kServiceName[];
-
-/// Default PersistentService::Config::version_info as a C string.
-extern const char kDefaultVersion[];
-
-/// Return the server arguments to pass to PersistentService::Client::Connect()
-/// For this helper, this should only be the name of or path to the executable
-/// itself.
-PersistentService::Config GetServerConfig();
-
-/// Set a non-default service version information.
-/// information for the server.
-void SetServiceConfigVersion(PersistentService::Config& config,
-                             const std::string& version);
-
-/// Set the server connection timeout in milliseconds.
-void SetServiceConfigTimeoutMs(PersistentService::Config& config,
-                               int64_t connection_timeout_ms);
-
-/// Retrieve a VersionCheckHandler instance that expects client version info
-/// to match |server_version_info|.
-PersistentService::Server::VersionCheckHandler GetVersionCheckHandler(
-    const std::string& server_version_info);
-
-/// Implement the request handler for the test handler.
-bool RequestHandler(IpcHandle connection);
-
-/// Run the test. Return true in case of success. In case of failure,
-/// set |*error| and return false. |client| is the handle returned
-/// PersistentService::CreateClient(). If |kill_server| is true, this also
-/// sends a command to kill the server and wait for its proper shutdown.
-bool RunTest(IpcHandle& client, bool kill_server, std::string* error);
-
-}  // namespace persistent_service_test
-
-#endif  // NINJA_PERSISTENT_SERVICE_TEST_LIB_H_
diff --git a/src/process_utils.cc b/src/process_utils.cc
deleted file mode 100644
index 81b574f..0000000
--- a/src/process_utils.cc
+++ /dev/null
@@ -1,282 +0,0 @@
-// Copyright 2023 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 "process_utils.h"
-
-#include <assert.h>
-
-#include <algorithm>
-
-#include "ipc_utils.h"
-#include "util.h"
-
-///////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////
-/////
-/////  ScopedEnvironmentVariable
-/////
-
-ScopedEnvironmentVariable::ScopedEnvironmentVariable(const char* varname,
-                                                     const char* value)
-    : varname_(varname) {
-  const char* env = getenv(varname);
-  if (env) {
-    has_prev_value_ = true;
-    prev_value_ = env;
-  }
-#ifdef _WIN32
-  // On Windows, setting the value to the empty string removes the variable.
-  // The following check is to ensure that UnsetEnv() is always called when
-  // trying to set an undefined |varname| to an empty |value|.
-  if (value && value[0]) {
-#else
-  if (value) {
-#endif
-    if (SetEnv(varname_.c_str(), value) < 0)
-      ErrnoFatal("setenv");
-  } else {
-    UnsetEnv(varname_.c_str());
-  }
-}
-
-ScopedEnvironmentVariable::~ScopedEnvironmentVariable() {
-  if (has_prev_value_) {
-    SetEnv(varname_.c_str(), prev_value_.c_str());
-  } else {
-    UnsetEnv(varname_.c_str());
-  }
-}
-
-ScopedEnvironmentVariable::ScopedEnvironmentVariable(
-    ScopedEnvironmentVariable&&) noexcept = default;
-ScopedEnvironmentVariable& ScopedEnvironmentVariable::operator=(
-    ScopedEnvironmentVariable&&) noexcept = default;
-
-int ScopedEnvironmentVariable::SetEnv(const char* varname, const char* value) {
-#ifdef _WIN32
-  // There is no setenv() on Win32!?
-  // _putenv_s() returns EINVAL in case of error, but also
-  // sets errno, so convert errors to -1 here.
-  return (_putenv_s(varname, value) == 0) ? 0 : -1;
-#else   // !_WIN32
-  return ::setenv(varname, value, 1);
-#endif  // !_WIN32
-}
-
-void ScopedEnvironmentVariable::UnsetEnv(const char* varname) {
-#ifdef _WIN32
-  _putenv_s(varname, "");
-#else   // !_WIN32
-  ::unsetenv(varname);
-#endif  // !_WIN32
-}
-
-///////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////
-/////
-/////  EnvironmentBlock
-/////
-
-EnvironmentBlock::EnvironmentBlock() = default;
-
-extern char** environ;
-
-// static
-EnvironmentBlock EnvironmentBlock::CreateFromCurrentEnvironment() {
-  EnvironmentBlock result;
-
-  for (const char* const* env = environ; *env; ++env) {
-    std::string definition = *env;
-    size_t pos = definition.find('=');
-    if (pos == std::string::npos) {
-      // Should not happen, ignore it.
-      continue;
-    }
-
-    std::string varname = definition.substr(0, pos);
-    std::string varvalue = definition.substr(pos + 1);
-
-#ifdef _WIN32
-    // Empty values are not possible on Win32, so skip them on this platform
-    // if we ever find them in the environ block.
-    if (varvalue.empty())
-      continue;
-#endif
-    result.map_[varname] = varvalue;
-  }
-  return result;
-}
-
-void EnvironmentBlock::MergeWith(const EnvironmentBlock& other) {
-  for (const auto& pair : other.map_)
-    map_.emplace(pair.first, pair.second);
-}
-
-void EnvironmentBlock::Insert(const char* varname, const char* value) {
-  if (!value)
-    value = "";
-  map_[std::string(varname)] = value;
-}
-
-void EnvironmentBlock::Remove(const char* varname) {
-  map_.erase(std::string(varname));
-}
-
-const char* EnvironmentBlock::Get(const char* varname) const {
-  auto it = map_.find(std::string(varname));
-  if (it == map_.end())
-    return nullptr;
-  return it->second.c_str();
-}
-
-std::string EnvironmentBlock::ToEncodedString() const {
-  auto definitions = GetDefinitions();
-  WireEncoder encoder;
-  encoder.Write(map_.size());
-  for (const auto& pair : map_) {
-    encoder.Write(pair.first);
-    encoder.Write(pair.second);
-  }
-  return encoder.TakeResult();
-}
-
-// static
-EnvironmentBlock EnvironmentBlock::FromEncodedString(const std::string& encoded,
-                                                     std::string* error) {
-  error->clear();
-  EnvironmentBlock::MapType map;
-  WireDecoder decoder(encoded);
-  size_t count = 0;
-  decoder.Read(count);
-  for (; count > 0; --count) {
-    std::string varname, varvalue;
-    decoder.Read(varname);
-    decoder.Read(varvalue);
-    map.emplace(varname, std::move(varvalue));
-  }
-  EnvironmentBlock result;
-  if (!decoder.has_error()) {
-    result.map_ = std::move(map);
-  } else {
-    *error = "Truncated encoded EnvironmentBlock string";
-  }
-  return result;
-}
-
-std::string EnvironmentBlock::AsString() const {
-  auto defs = GetDefinitions();
-  std::string result = StringFormat("Environment(%zu)[\n", defs.list.size());
-  for (const auto& def : defs.list)
-    result += StringFormat("  %s\n", def.c_str());
-  result += "]";
-  return result;
-}
-
-bool EnvironmentBlock::operator==(const EnvironmentBlock& other) const {
-  auto defs = GetDefinitions();
-  auto other_defs = other.GetDefinitions();
-  if (defs.total_size != other_defs.total_size)
-    return false;
-  if (defs.list.size() != other_defs.list.size())
-    return false;
-  auto other_it = other_defs.list.begin();
-  for (const auto& def : defs.list) {
-    if (def != *other_it)
-      return false;
-    ++other_it;
-  }
-  return true;
-}
-
-EnvironmentBlock::Definitions EnvironmentBlock::GetDefinitions() const {
-  Definitions result;
-  for (const auto& pair : map_) {
-    result.list.push_back(pair.first + "=" + pair.second);
-    result.total_size += result.list.back().size() + 1;
-  }
-  std::sort(result.list.begin(), result.list.end());
-  return result;
-}
-
-#ifdef _WIN32
-char* EnvironmentBlock::AsAnsiEnvironmentBlock() const {
-  auto definitions = GetDefinitions();
-
-  block_.clear();
-  block_.reserve(definitions.total_size + 1);
-  for (const auto& def : definitions.list) {
-    block_.append(def.c_str(), def.size() + 1);
-  }
-  block_ += '\0';
-
-  return &block_[0];
-}
-
-wchar_t* EnvironmentBlock::AsUnicodeEnvironmentBlock() const {
-  auto definitions = GetDefinitions();
-
-  block_.clear();
-  block_.reserve(definitions.total_size * 2 + 2);
-  for (const auto& def : definitions.list) {
-    std::wstring wdef = ConvertToUnicodeString(def);
-    block_.append(reinterpret_cast<const char*>(wdef.c_str()),
-                  wdef.size() * 2 + 2);
-  }
-  block_ += '\0';
-  block_ += '\0';
-
-  return reinterpret_cast<wchar_t*>(&block_[0]);
-}
-
-#else   // !_WIN32
-char** EnvironmentBlock::AsExecEnvironmentBlock() const {
-  auto definitions = GetDefinitions();
-  block_.clear();
-  block_.reserve(definitions.total_size);
-
-  env_.clear();
-  env_.reserve(definitions.list.size() + 1);
-  for (const auto& def : definitions.list) {
-    char* dst = const_cast<char*>(block_.data()) + block_.size();
-    env_.push_back(dst);
-    block_.append(def.c_str(), def.size() + 1);
-  }
-  assert(block_.size() == definitions.total_size);
-  env_.push_back(nullptr);
-  return &env_.front();
-}
-#endif  // !_WIN32
-
-// static
-std::vector<StringPiece> SplitCommaOrSpaceSeparatedList(StringPiece input) {
-  std::vector<StringPiece> result;
-  const char* p = input.str_;
-  const char* end = p + input.len_;
-
-  while (p < end) {
-    // Find next variable name length.
-    const char* q = p;
-    while (q < end && *q != ' ' && *q != ',')
-      q++;
-
-    size_t len = q - p;
-    if (len > 0)
-      result.emplace_back(p, len);
-    if (q == end)
-      break;
-
-    p = q + 1;
-  }
-  return result;
-}
diff --git a/src/process_utils.h b/src/process_utils.h
deleted file mode 100644
index 6723363..0000000
--- a/src/process_utils.h
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2023 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_PROCESS_UTILS_H
-#define NINJA_PROCESS_UTILS_H
-
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <sys/types.h>
-#endif
-
-#include "string_piece.h"
-
-/// Convenience class to temporarily set the value of an environment variable
-/// in the current process.
-class ScopedEnvironmentVariable {
- public:
-  /// Constructor sets the value of a given environment variable.
-  /// Set |value| to nullptr to remove the variable from the environment.
-  /// Note that on Windows, setting |value| to an empty string will also
-  /// remove the value, while it will set it to the empty string on Posix.
-  ScopedEnvironmentVariable(const char* varname, const char* value);
-
-  /// Destructor restores the previous value.
-  ~ScopedEnvironmentVariable();
-
-  /// Allow move operations.
-  ScopedEnvironmentVariable(ScopedEnvironmentVariable&&) noexcept;
-  ScopedEnvironmentVariable& operator=(ScopedEnvironmentVariable&&) noexcept;
-
- private:
-  int SetEnv(const char* varname, const char* value);
-  void UnsetEnv(const char* varname);
-
-  std::string varname_;
-  std::string prev_value_;
-
-  // On Posix, it is possible to set an environment variable to the empty value
-  // while on Windows, this simply unsets / removes the variable. This flag is
-  // only used on Posix to distinguish between these two cases.
-  bool has_prev_value_ = false;
-};
-
-/// A convenience wrapper for a set of environment variables.
-class EnvironmentBlock {
- public:
-  /// Default constructor creates an empty set.
-  EnvironmentBlock();
-
-  /// Create new instance from current process environment.
-  static EnvironmentBlock CreateFromCurrentEnvironment();
-
-  /// Merge with another instance. This only gets variables from |other|
-  /// which were not set
-  void MergeWith(const EnvironmentBlock& other);
-
-  /// Add a given variable to the set, with its associated value.
-  /// If the variable is already in the set, replace its value.
-  void Insert(const char* varname, const char* value);
-
-  /// Remove |varname| and its associated value from the set.
-  void Remove(const char* varname);
-
-  /// Return the value associated with |varname| in the set, or nullptr
-  /// if it is not in it.
-  const char* Get(const char* varname) const;
-
-  /// Convert this instance to an encoded string, useful to send it
-  /// to another process.
-  std::string ToEncodedString() const;
-
-  /// Decode a new instance from an encoded string. In case of
-  /// failure, return an empty environment block, then set |*err|
-  /// with an error message. On success |*err| is cleared to ease
-  /// error handling on the client side.
-  static EnvironmentBlock FromEncodedString(const std::string& encoded,
-                                            std::string* err);
-
-  /// Convert instance to string for debugging and testing only.
-  std::string AsString() const;
-
-  /// Compare for equality.
-  bool operator==(const EnvironmentBlock& other) const;
-
-  /// Compare for inequality.
-  bool operator!=(const EnvironmentBlock& other) const {
-    return !(*this == other);
-  }
-
-#ifdef _WIN32
-  /// Return the current instance as a Win32 environment block, which is
-  /// a sequence of zero-terminated C strings, followed by a single zero
-  /// (as in `FOO=foo<0>BAR=bar<0><0>`, this is the value expected by
-  /// the `lpEnvironment` parameter of CreateProcessA.
-  ///
-  /// NOTE: The returned address belongs to the instance, but its content
-  /// may become invalid after calling any other methods.
-  char* AsAnsiEnvironmentBlock() const;
-
-  /// Same as AsWin32AnsiEnvironmentBlock(), but uses Unicode characters
-  /// instead. This is the format expected by CreateProcessW.
-  ///
-  /// NOTE: The returned address belongs to the instance, but its content
-  /// may become invalid after calling any other methods.
-  wchar_t* AsUnicodeEnvironmentBlock() const;
-#else   // !_WIN32
-  /// A pointer to an array of zero-terminated C string pointers, followed
-  /// by a NULL pointer. This is the value expected by the execve() function.
-  ///
-  /// NOTE: The returned address belongs to the instance, but its content
-  /// may become invalid after calling any other methods.
-  char** AsExecEnvironmentBlock() const;
-#endif  // !_WIN32
-
- private:
-  struct Definitions {
-    std::vector<std::string> list;
-    size_t total_size = 0;
-  };
-  Definitions GetDefinitions() const;
-
-  using MapType = std::unordered_map<std::string, std::string>;
-  MapType map_;
-  mutable std::string block_;
-#ifndef _WIN32
-  mutable std::vector<char*> env_;
-#endif  // !_WIN32
-};
-
-/// Split an input list separated by commas or spaces into separate items.
-/// Trailing, leading or duplicate separators are ignored.
-std::vector<StringPiece> SplitCommaOrSpaceSeparatedList(StringPiece list);
-
-#endif  // NINJA_PROCESS_UTILS_H
diff --git a/src/process_utils_test.cc b/src/process_utils_test.cc
deleted file mode 100644
index 54ae84e..0000000
--- a/src/process_utils_test.cc
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright 2023 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 "process_utils.h"
-
-#include <stdlib.h>
-
-#include <string>
-
-#include "test.h"
-
-TEST(ProcessUtils, ScopedEnvironmentVariable) {
-  const char kVarName[] = "FOO_FOR_TEST";
-  const char* prev_value = getenv(kVarName);
-  ASSERT_FALSE(prev_value);
-
-  {
-    ScopedEnvironmentVariable scoped_var(kVarName, "");
-#ifdef _WIN32
-    // On Windows, the variable was forcefully removed.
-    ASSERT_FALSE(getenv(kVarName));
-#else
-    // On Posix, the variable was set to the empty string.
-    ASSERT_TRUE(getenv(kVarName));
-    EXPECT_EQ(std::string(""), getenv(kVarName));
-#endif
-  }
-
-  {
-    ScopedEnvironmentVariable scoped_var(kVarName, "value1");
-    EXPECT_EQ(std::string("value1"), getenv(kVarName));
-
-    {
-      ScopedEnvironmentVariable scoped_var2(kVarName, "VALUE2");
-      EXPECT_EQ(std::string("VALUE2"), getenv(kVarName));
-    }
-
-    {
-      ScopedEnvironmentVariable scoped_var2(kVarName, "");
-#ifdef _WIN32
-      ASSERT_FALSE(getenv(kVarName));
-#else
-      ASSERT_TRUE(getenv(kVarName));
-      EXPECT_EQ(std::string(""), getenv(kVarName));
-#endif
-    }
-
-    EXPECT_EQ(std::string("value1"), getenv(kVarName));
-  }
-
-  ASSERT_FALSE(getenv(kVarName));
-}
-
-TEST(ProcessUtils, EnvironmentBlockDefault) {
-  EnvironmentBlock empty_block;
-#ifdef _WIN32
-  char* b = empty_block.AsAnsiEnvironmentBlock();
-  ASSERT_EQ(*b, '\0');
-  ASSERT_EQ(empty_block, empty_block);
-
-  wchar_t* wb = empty_block.AsUnicodeEnvironmentBlock();
-  ASSERT_EQ(*wb, L'\0');
-#else   // !_WIN32
-  char** vec = empty_block.AsExecEnvironmentBlock();
-  ASSERT_FALSE(vec[0]);
-#endif  // !_WIN32
-
-  EXPECT_EQ(empty_block.AsString(), "Environment(0)[\n]");
-}
-
-TEST(ProcessUtils, EnvironmentBlockFromCurrentEnvironment) {
-  const char kDefinedVarName[] = "DEFINED_VARIABLE_FOR_NINJA_TEST";
-  const char kUndefinedVarName[] = "UNDEFINED_VARIABLE_FOR_NINJA_TEST";
-  ASSERT_FALSE(getenv(kDefinedVarName));
-  ASSERT_FALSE(getenv(kUndefinedVarName));
-
-  {
-    ScopedEnvironmentVariable scoped_var(kDefinedVarName, "");
-    EnvironmentBlock block = EnvironmentBlock::CreateFromCurrentEnvironment();
-    EXPECT_FALSE(block.Get(kUndefinedVarName));
-#ifdef _WIN32
-    ASSERT_FALSE(block.Get(kDefinedVarName));
-#else
-    ASSERT_TRUE(block.Get(kDefinedVarName));
-    EXPECT_EQ('\0', block.Get(kDefinedVarName)[0]);
-#endif
-  }
-
-  {
-    EnvironmentBlock block = EnvironmentBlock::CreateFromCurrentEnvironment();
-    EXPECT_FALSE(block.Get(kUndefinedVarName));
-    EXPECT_FALSE(block.Get(kDefinedVarName));
-  }
-}
-
-TEST(ProcessUtils, EnvironmentBlockMergeWith) {
-  EnvironmentBlock block;
-  block.Insert("foo", "FOO");
-  block.Insert("bar", "BAR");
-  block.Insert("qux", "");
-  EXPECT_EQ(block.AsString(),
-            "Environment(3)[\n  bar=BAR\n  foo=FOO\n  qux=\n]");
-
-  EXPECT_EQ(block, block);
-
-  EnvironmentBlock block2;
-  block2.Insert("foo", "NOT_FOO");
-  block2.Insert("qux", "QUX");
-  block2.Insert("zoo", "ZOO");
-  EXPECT_EQ(block2.AsString(),
-            "Environment(3)[\n  foo=NOT_FOO\n  qux=QUX\n  zoo=ZOO\n]");
-
-  EXPECT_EQ(block, block);
-  EXPECT_NE(block, block2);
-
-  block.MergeWith(block2);
-  EXPECT_EQ(block.Get("foo"), std::string("FOO"));
-  EXPECT_EQ(block.Get("bar"), std::string("BAR"));
-  EXPECT_EQ(block.Get("qux"), std::string(""));
-  ASSERT_TRUE(block.Get("zoo"));
-  EXPECT_EQ(block.Get("zoo"), std::string("ZOO"));
-
-  EXPECT_EQ(block.AsString(),
-            "Environment(4)[\n  bar=BAR\n  foo=FOO\n  qux=\n  zoo=ZOO\n]");
-}
-
-#ifdef _WIN32
-
-TEST(ProcessUtils, EnvironmentBlockAsAnsiEnvironmentBlock) {
-  EnvironmentBlock block;
-  block.Insert("foo", "FOO");
-  block.Insert("bar", "BARBAR");
-  block.Insert("zoo", "");
-
-  ASSERT_TRUE(block.Get("foo"));
-  EXPECT_EQ(std::string("FOO"), block.Get("foo"));
-  EXPECT_EQ(std::string("BARBAR"), block.Get("bar"));
-  EXPECT_EQ(std::string(""), block.Get("zoo"));
-
-  char* b = block.AsAnsiEnvironmentBlock();
-  ASSERT_FALSE(::memcmp(b, "bar=BARBAR\0foo=FOO\0zoo=\0\0", 25));
-}
-
-TEST(ProcessUtils, EnvironmentBlockAsUnicodeEnvironmentBlock) {
-  EnvironmentBlock block;
-  block.Insert("foo", "FOO");
-  block.Insert("bar", "BARBAR");
-  block.Insert("zoo", "");
-
-  ASSERT_TRUE(block.Get("foo"));
-  EXPECT_EQ(std::string("FOO"), block.Get("foo"));
-  EXPECT_EQ(std::string("BARBAR"), block.Get("bar"));
-  EXPECT_EQ(std::string(""), block.Get("zoo"));
-
-  wchar_t* wb = block.AsUnicodeEnvironmentBlock();
-  ASSERT_FALSE(::wmemcmp(wb, L"bar=BARBAR\0foo=FOO\0zoo=\0\0", 25));
-}
-#else   // !_WIN32
-TEST(ProcessUtils, EnvironmentBlockAsExecEnvironmentBlock) {
-  EnvironmentBlock block;
-  block.Insert("foo", "FOO");
-  block.Insert("bar", "BARBAR");
-  block.Insert("zoo", "");
-
-  ASSERT_TRUE(block.Get("foo"));
-  EXPECT_EQ(std::string("FOO"), block.Get("foo"));
-  EXPECT_EQ(std::string("BARBAR"), block.Get("bar"));
-  EXPECT_EQ(std::string(""), block.Get("zoo"));
-
-  char** vec = block.AsExecEnvironmentBlock();
-  ASSERT_TRUE(vec[0]);
-  ASSERT_TRUE(vec[1]);
-  ASSERT_TRUE(vec[2]);
-  ASSERT_FALSE(vec[3]);
-  EXPECT_EQ(std::string(vec[0]), "bar=BARBAR");
-  EXPECT_EQ(std::string(vec[1]), "foo=FOO");
-  EXPECT_EQ(std::string(vec[2]), "zoo=");
-}
-#endif  // !_WIN32
-
-TEST(ProcessUtils, EnvironmentBlockToEncodedString) {
-  EnvironmentBlock block;
-  block.Insert("foo", "FOO");
-  block.Insert("bar", "BARBAR");
-  block.Insert("zoo", "");
-  EXPECT_EQ(block.AsString(),
-            "Environment(3)[\n  bar=BARBAR\n  foo=FOO\n  zoo=\n]");
-
-  std::string encoded = block.ToEncodedString();
-  ASSERT_FALSE(encoded.empty());
-
-  std::string error;
-  auto block2 = EnvironmentBlock::FromEncodedString(encoded, &error);
-  EXPECT_TRUE(error.empty());
-  EXPECT_EQ(block.AsString(), block2.AsString());
-
-  // Detect errors and return empty instance when decoding truncated string.
-  auto block3 =
-      EnvironmentBlock::FromEncodedString(encoded.substr(0, 10), &error);
-  EXPECT_FALSE(error.empty());
-  EXPECT_EQ(block3.AsString(), "Environment(0)[\n]");
-}
-
-TEST(ProcessUtils, SplitCommaOrSpaceSeparatedList) {
-  std::vector<StringPiece> result;
-
-  // Verify empty inputs.
-  result = SplitCommaOrSpaceSeparatedList("");
-  EXPECT_EQ(result.size(), 0u);
-
-  result = SplitCommaOrSpaceSeparatedList("    ");
-  EXPECT_EQ(result.size(), 0u);
-
-  result = SplitCommaOrSpaceSeparatedList(" ,,, ");
-  EXPECT_EQ(result.size(), 0u);
-
-  result = SplitCommaOrSpaceSeparatedList("  foo,");
-  EXPECT_EQ(result.size(), 1u);
-  EXPECT_EQ(result[0].AsString(), "foo");
-
-  result = SplitCommaOrSpaceSeparatedList("foo bar zoo");
-  EXPECT_EQ(result.size(), 3u);
-  EXPECT_EQ(result[0].AsString(), "foo");
-  EXPECT_EQ(result[1].AsString(), "bar");
-  EXPECT_EQ(result[2].AsString(), "zoo");
-
-  result = SplitCommaOrSpaceSeparatedList("  foo,,bar zoo,");
-  EXPECT_EQ(result.size(), 3u);
-  EXPECT_EQ(result[0].AsString(), "foo");
-  EXPECT_EQ(result[1].AsString(), "bar");
-  EXPECT_EQ(result[2].AsString(), "zoo");
-}
diff --git a/src/stat_cache-posix.cc b/src/stat_cache-posix.cc
deleted file mode 100644
index 2855df3..0000000
--- a/src/stat_cache-posix.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2023 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 <errno.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "stat_cache.h"
-#include "util.h"
-
-// This implementation calls stat() directly and never caches anything.
-class StatCache::Impl {
- public:
-  void Enable(bool) {}
-
-  TimeStamp Stat(const std::string& path, std::string* err) const {
-    return ::GetFileTimestamp(path, err);
-  }
-};
-
-StatCache::StatCache() : impl_(new StatCache::Impl()) {}
-
-StatCache::~StatCache() = default;
-
-void StatCache::Enable(bool enabled) {
-  impl_->Enable(enabled);
-}
-
-void StatCache::Invalidate(const std::string&) {
-  // Nothing to do here.
-}
-
-TimeStamp StatCache::Stat(const std::string& path, std::string* err) const {
-  return impl_->Stat(path, err);
-}
-
-void StatCache::Sync() {}
-
-void StatCache::Flush() {}
diff --git a/src/stat_cache-win32.cc b/src/stat_cache-win32.cc
deleted file mode 100644
index 87bc053..0000000
--- a/src/stat_cache-win32.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2023 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 <windows.h>
-
-#include <algorithm>
-#include <map>
-
-#include "stat_cache.h"
-#include "util.h"
-
-namespace {
-
-bool IsPathSeparator(char ch) {
-  return (ch == '/' || ch == '\\');
-}
-
-// Compute the dirname and basename of a given path.
-// If there is no directory separator, set |*dir| to ".".
-void DecomposePath(const std::string& path, std::string* dir,
-                   std::string* base) {
-  size_t pos = path.size();
-
-  // Find first directory separator before base name.
-  while (pos > 0 && !IsPathSeparator(path[pos - 1]))
-    --pos;
-
-  *base = path.substr(pos);
-
-  // Skip over separator(s) to find directory name, might be empty
-  while (pos > 1 && IsPathSeparator(path[pos - 2]))
-    --pos;
-
-  *dir = path.substr(0, pos);
-}
-
-bool IsWindows7OrLater() {
-  OSVERSIONINFOEX version_info = {
-    sizeof(OSVERSIONINFOEX), 6, 1, 0, 0, { 0 }, 0, 0, 0, 0, 0
-  };
-  DWORDLONG comparison = 0;
-  VER_SET_CONDITION(comparison, VER_MAJORVERSION, VER_GREATER_EQUAL);
-  VER_SET_CONDITION(comparison, VER_MINORVERSION, VER_GREATER_EQUAL);
-  return VerifyVersionInfo(&version_info, VER_MAJORVERSION | VER_MINORVERSION,
-                           comparison);
-}
-
-using DirCache = std::map<std::string, TimeStamp>;
-
-// TODO: Neither a map nor a hashmap seems ideal here.  If the statcache
-// works out, come up with a better data structure.
-using Cache = std::map<std::string, DirCache>;
-
-bool StatAllFilesInDir(const std::string& dir, DirCache* stamps,
-                       std::string* err) {
-  // FindExInfoBasic is 30% faster than FindExInfoStandard.
-  static bool can_use_basic_info = IsWindows7OrLater();
-  // This is not in earlier SDKs.
-  const FINDEX_INFO_LEVELS kFindExInfoBasic =
-      static_cast<FINDEX_INFO_LEVELS>(1);
-  FINDEX_INFO_LEVELS level =
-      can_use_basic_info ? kFindExInfoBasic : FindExInfoStandard;
-  WIN32_FIND_DATAA ffd;
-  HANDLE find_handle = FindFirstFileExA((dir + "\\*").c_str(), level, &ffd,
-                                        FindExSearchNameMatch, NULL, 0);
-
-  if (find_handle == INVALID_HANDLE_VALUE) {
-    DWORD win_err = GetLastError();
-    if (win_err == ERROR_FILE_NOT_FOUND || win_err == ERROR_PATH_NOT_FOUND ||
-        win_err == ERROR_DIRECTORY)
-      return true;
-    *err = StringFormat("FindFirstFileExA(%s): %s", dir.c_str(),
-                        GetLastErrorString().c_str());
-    return false;
-  }
-  do {
-    std::string lowername = ffd.cFileName;
-    if (lowername == "..") {
-      // Seems to just copy the timestamp for ".." from ".", which is wrong.
-      // This is the case at least on NTFS under Windows 7.
-      continue;
-    }
-    std::transform(lowername.begin(), lowername.end(), lowername.begin(),
-                   ::tolower);
-    // C++11 equivalent to
-    // stamps->try_emplace(std::move(lowername), TimeStampFromFile(...))
-    stamps->emplace(
-        std::piecewise_construct, std::forward_as_tuple(std::move(lowername)),
-        std::forward_as_tuple(TimeStampFromFileTime(ffd.ftLastWriteTime)));
-  } while (FindNextFileA(find_handle, &ffd));
-  FindClose(find_handle);
-  return true;
-}
-
-}  // namespace
-
-class StatCache::Impl {
- public:
-  void Enable(bool enabled) {
-    if (!enabled)
-      cache_.clear();
-
-    enabled_ = enabled;
-  }
-
-  TimeStamp Stat(const std::string& path, std::string* err) const {
-    // MSDN: "Naming Files, Paths, and Namespaces"
-    // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
-    if (!path.empty() && path[0] != '\\' && path.size() > MAX_PATH) {
-      *err = StringFormat("Stat(%s): Filename longer than %u characters",
-                          path.c_str(), MAX_PATH);
-      return -1;
-    }
-    if (!enabled_)
-      return ::GetFileTimestamp(path, err);
-
-    std::string dir, base;
-    DecomposePath(path, &dir, &base);
-    if (base == "..") {
-      // StatAllFilesInDir does not report any information for base = "..".
-      base = ".";
-      dir = path;
-    }
-
-    std::string dir_lowercase = dir;
-    std::transform(dir.begin(), dir.end(), dir_lowercase.begin(), ::tolower);
-    std::transform(base.begin(), base.end(), base.begin(), ::tolower);
-
-    // NOTE: The following is the C++11 equivalent of
-    // cache_.try_emplace(std::move(dir_lowercase))
-    auto ret = cache_.emplace(std::piecewise_construct,
-                              std::forward_as_tuple(std::move(dir_lowercase)),
-                              std::forward_as_tuple());
-    Cache::iterator ci = ret.first;
-    if (ret.second) {
-      if (!StatAllFilesInDir(dir.empty() ? "." : dir, &ci->second, err)) {
-        cache_.erase(ci);
-        return -1;
-      }
-    }
-    DirCache::iterator di = ci->second.find(base);
-    return di != ci->second.end() ? di->second : 0;
-  }
-
-  void Sync() {
-    // TODO(digit): Implement this properly!
-    // FOR NOW, drop everything from the cache to pass the unit-tests!
-    cache_.clear();
-  }
-
-  void Flush() { cache_.clear(); }
-
- private:
-  /// Whether stat information can be cached.
-  bool enabled_ = false;
-
-  /// The cache itself.
-  mutable Cache cache_;
-};
-
-StatCache::StatCache() : impl_(new StatCache::Impl()) {}
-
-StatCache::~StatCache() = default;
-
-void StatCache::Enable(bool enabled) {
-  impl_->Enable(enabled);
-}
-
-TimeStamp StatCache::Stat(const std::string& path, std::string* err) const {
-  return impl_->Stat(path, err);
-}
-
-void StatCache::Invalidate(const std::string& path) {
-  // TODO(digit): Only remove entries from the path's parent directory.
-  impl_->Sync();
-}
-
-void StatCache::Sync() {
-  impl_->Sync();
-}
-
-void StatCache::Flush() {
-  impl_->Flush();
-}
diff --git a/src/stat_cache.h b/src/stat_cache.h
deleted file mode 100644
index 7d6322d..0000000
--- a/src/stat_cache.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2023 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_STAT_CACHE_H_
-#define NINJA_STAT_CACHE_H_
-
-#include <memory>
-#include <string>
-
-#include "timestamp.h"
-
-/// Implement a cache for file path timestamps.
-class StatCache {
- public:
-  /// Constructor
-  StatCache();
-
-  /// Destructor
-  ~StatCache();
-
-  /// Enable caching of timestamps. If false (the default), the Stat() performs
-  /// a single stat() operation per file and no caching is performed.
-  void Enable(bool enabled);
-
-  /// Mark a path as invalid.
-  void Invalidate(const std::string& path);
-
-  /// Return the timestamp of a given file path. On error, set |*err| then
-  /// return -1. Otherwise, return 0 if the file is missing, or a strictly
-  /// positive value if it exists.
-  TimeStamp Stat(const std::string& path, std::string* err) const;
-
-  /// Synchronize the cache state with recent filesystem events.
-  /// Call this before one or more Stat() calls.
-  void Sync();
-
-  /// Remove all entries from the cache.
-  void Flush();
-
- private:
-  class Impl;
-  std::unique_ptr<Impl> impl_;
-};
-
-#endif  // NINJA_STAT_CACHE_H_
diff --git a/src/stat_cache_test.cc b/src/stat_cache_test.cc
deleted file mode 100644
index f6b8455..0000000
--- a/src/stat_cache_test.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2023 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 "stat_cache.h"
-
-#include <stdio.h>
-
-#include "test.h"
-#include "util.h"
-
-namespace {
-
-void WriteFile(const std::string& path, const std::string& content) {
-  FILE* f = fopen(path.c_str(), "wb");
-  if (!f)
-    ErrnoFatal("fopen", path.c_str());
-
-  size_t ret = fwrite(content.c_str(), content.size(), 1, f);
-  if (ret != 1)
-    ErrnoFatal("Could not write to %s", path.c_str());
-  fclose(f);
-}
-
-void RemoveFile(const std::string& path) {
-  ::remove(path.c_str());
-}
-
-}  // namespace
-
-TEST(StatCache, CheckMissingTimestamp) {
-  ScopedTempDir temp_dir;
-  temp_dir.CreateAndEnter("StatCacheTest");
-  auto top_dir = GetCurrentDir();
-
-  StatCache cache;
-  cache.Enable(true);
-
-  std::string err;
-  TimeStamp t = cache.Stat(top_dir + "/foo", &err);
-  EXPECT_EQ(0, t);
-  EXPECT_TRUE(err.empty());
-
-  t = cache.Stat(top_dir + "/bar", &err);
-  EXPECT_EQ(0, t);
-  EXPECT_TRUE(err.empty());
-
-  // Try foo again, just in case.
-  t = cache.Stat(top_dir + "/foo", &err);
-  EXPECT_EQ(0, t);
-  EXPECT_TRUE(err.empty());
-}
-
-TEST(StatCache, CheckExistingTimestamp) {
-  ScopedTempDir temp_dir;
-  temp_dir.CreateAndEnter("StatCacheTest");
-  auto top_dir = GetCurrentDir();
-
-  StatCache cache;
-  cache.Enable(true);
-
-  std::string foo_path = top_dir + "/foo";
-
-  WriteFile(foo_path, "foo!!");
-
-  std::string err;
-  TimeStamp t = cache.Stat(foo_path, &err);
-  EXPECT_GE(t, 0);
-  EXPECT_TRUE(err.empty());
-}
-
-TEST(StatCache, CheckCreatedTimestamp) {
-  ScopedTempDir temp_dir;
-  temp_dir.CreateAndEnter("StatCacheTest");
-  auto top_dir = GetCurrentDir();
-
-  StatCache cache;
-  cache.Enable(true);
-
-  std::string foo_path = top_dir + "/foo";
-
-  std::string err;
-  TimeStamp t = cache.Stat(foo_path, &err);
-  EXPECT_EQ(0, t);
-  EXPECT_TRUE(err.empty());
-
-  WriteFile(foo_path, "foo!!");
-  cache.Sync();
-
-  TimeStamp t2 = cache.Stat(foo_path, &err);
-  EXPECT_NE(0, t2);
-  EXPECT_TRUE(err.empty());
-}
-
-TEST(StatCache, CheckDeletedTimestamp) {
-  ScopedTempDir temp_dir;
-  temp_dir.CreateAndEnter("StatCacheTest");
-  auto top_dir = GetCurrentDir();
-
-  StatCache cache;
-  cache.Enable(true);
-
-  std::string foo_path = top_dir + "/foo";
-  WriteFile(foo_path, "foo!!");
-
-  std::string err;
-  TimeStamp t = cache.Stat(foo_path, &err);
-  EXPECT_NE(0, t);
-  EXPECT_TRUE(err.empty());
-
-  RemoveFile(foo_path);
-
-  cache.Sync();
-
-  TimeStamp t2 = cache.Stat(foo_path, &err);
-  EXPECT_EQ(0, t2);
-  EXPECT_TRUE(err.empty());
-}
diff --git a/src/state.cc b/src/state.cc
deleted file mode 100644
index e163599..0000000
--- a/src/state.cc
+++ /dev/null
@@ -1,238 +0,0 @@
-// 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.
-
-#include "state.h"
-
-#include <assert.h>
-#include <stdio.h>
-
-#include "edit_distance.h"
-#include "graph.h"
-#include "metrics.h"
-#include "util.h"
-
-using namespace std;
-
-void Pool::EdgeScheduled(const Edge& edge) {
-  if (depth_ != 0)
-    current_use_ += edge.weight();
-}
-
-void Pool::EdgeFinished(const Edge& edge) {
-  if (depth_ != 0)
-    current_use_ -= edge.weight();
-}
-
-void Pool::DelayEdge(Edge* edge) {
-  assert(depth_ != 0);
-  delayed_.insert(edge);
-}
-
-void Pool::RetrieveReadyEdges(EdgeSet* ready_queue) {
-  DelayedEdges::iterator it = delayed_.begin();
-  while (it != delayed_.end()) {
-    Edge* edge = *it;
-    if (current_use_ + edge->weight() > depth_)
-      break;
-    ready_queue->insert(edge);
-    EdgeScheduled(*edge);
-    ++it;
-  }
-  delayed_.erase(delayed_.begin(), it);
-}
-
-void Pool::Dump() const {
-  printf("%s (%d/%d) ->\n", name_.c_str(), current_use_, depth_);
-  for (DelayedEdges::const_iterator it = delayed_.begin();
-       it != delayed_.end(); ++it)
-  {
-    printf("\t");
-    (*it)->Dump();
-  }
-}
-
-void Pool::Reset() {
-  current_use_ = 0;
-  delayed_.clear();
-}
-
-State::State() {
-  // Create top-level scope.
-  bindings_.emplace_back(new BindingEnv());
-
-  // Add the phony rule to it.
-  phony_rule_ = new Rule("phony");
-  bindings_[0]->AddRule(phony_rule_);
-
-  // Create default and console pools.
-  default_pool_ = new Pool("", 0);
-  console_pool_ = new Pool("console", 1);
-  AddPool(default_pool_);
-  AddPool(console_pool_);
-}
-
-State::~State() {
-  // Delete Edge instances.
-  for (Edge* edge : edges_)
-    delete edge;
-
-  // Delete Node instances.
-  for (auto& pair : paths_)
-    delete pair.second;
-}
-
-void State::AddPool(Pool* pool) {
-  auto ret = pools_.emplace(pool->name(), pool);
-  assert(ret.second && "Duplicate pool insertion!");
-}
-
-Pool* State::LookupPool(const string& pool_name) {
-  auto it = pools_.find(pool_name);
-  if (it == pools_.end())
-    return NULL;
-  return it->second.get();
-}
-
-Edge* State::AddEdge(const Rule* rule) {
-  Edge* edge = new Edge();
-  edge->rule_ = rule;
-  edge->pool_ = default_pool_;
-  edge->env_ = bindings_[0].get();
-  edge->id_ = edges_.size();
-  edges_.push_back(edge);
-  return edge;
-}
-
-Node* State::GetNode(StringPiece path, uint64_t slash_bits) {
-  Node* node = LookupNode(path);
-  if (node)
-    return node;
-  node = new Node(path.AsString(), slash_bits);
-  paths_[node->path()] = node;
-  return node;
-}
-
-Node* State::LookupNode(StringPiece path) const {
-  Paths::const_iterator i = paths_.find(path);
-  if (i != paths_.end())
-    return i->second;
-  return NULL;
-}
-
-Node* State::SpellcheckNode(const string& path) {
-  const bool kAllowReplacements = true;
-  const int kMaxValidEditDistance = 3;
-
-  int min_distance = kMaxValidEditDistance + 1;
-  Node* result = NULL;
-  for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) {
-    int distance = EditDistance(
-        i->first, path, kAllowReplacements, kMaxValidEditDistance);
-    if (distance < min_distance && i->second) {
-      min_distance = distance;
-      result = i->second;
-    }
-  }
-  return result;
-}
-
-void State::AddIn(Edge* edge, StringPiece path, uint64_t slash_bits) {
-  Node* node = GetNode(path, slash_bits);
-  node->set_generated_by_dep_loader(false);
-  edge->inputs_.push_back(node);
-  node->AddOutEdge(edge);
-}
-
-bool State::AddOut(Edge* edge, StringPiece path, uint64_t slash_bits) {
-  Node* node = GetNode(path, slash_bits);
-  if (node->in_edge())
-    return false;
-  edge->outputs_.push_back(node);
-  node->set_in_edge(edge);
-  node->set_generated_by_dep_loader(false);
-  return true;
-}
-
-void State::AddValidation(Edge* edge, StringPiece path, uint64_t slash_bits) {
-  Node* node = GetNode(path, slash_bits);
-  edge->validations_.push_back(node);
-  node->AddValidationOutEdge(edge);
-  node->set_generated_by_dep_loader(false);
-}
-
-bool State::AddDefault(StringPiece path, string* err) {
-  Node* node = LookupNode(path);
-  if (!node) {
-    *err = "unknown target '" + path.AsString() + "'";
-    return false;
-  }
-  defaults_.push_back(node);
-  return true;
-}
-
-vector<Node*> State::RootNodes(string* err) const {
-  vector<Node*> root_nodes;
-  // Search for nodes with no output.
-  for (vector<Edge*>::const_iterator e = edges_.begin();
-       e != edges_.end(); ++e) {
-    for (vector<Node*>::const_iterator out = (*e)->outputs_.begin();
-         out != (*e)->outputs_.end(); ++out) {
-      if ((*out)->out_edges().empty())
-        root_nodes.push_back(*out);
-    }
-  }
-
-  if (!edges_.empty() && root_nodes.empty())
-    *err = "could not determine root nodes of build graph";
-
-  return root_nodes;
-}
-
-vector<Node*> State::DefaultNodes(string* err) const {
-  return defaults_.empty() ? RootNodes(err) : defaults_;
-}
-
-BindingEnv* State::CreateNewEnv(BindingEnv* parent) {
-  bindings_.emplace_back(new BindingEnv(parent));
-  return bindings_.back().get();
-}
-
-void State::Reset() {
-  METRIC_RECORD("state reset");
-  for (auto& pair : pools_)
-    pair.second->Reset();
-  for (auto& pair : paths_)
-    pair.second->ResetState();
-  for (Edge* edge : edges_)
-    edge->ResetState();
-}
-
-void State::Dump() {
-  for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) {
-    Node* node = i->second;
-    printf("%s %s [id:%d]\n",
-           node->path().c_str(),
-           node->status_known() ? (node->dirty() ? "dirty" : "clean")
-                                : "unknown",
-           node->id());
-  }
-  if (!pools_.empty()) {
-    printf("resource_pools:\n");
-    for (const auto& pair : pools_) {
-      if (!pair.second->name().empty()) {
-        pair.second->Dump();
-      }
-    }
-  }
-}
diff --git a/src/state.h b/src/state.h
deleted file mode 100644
index f965805..0000000
--- a/src/state.h
+++ /dev/null
@@ -1,190 +0,0 @@
-// 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.
-
-#ifndef NINJA_STATE_H_
-#define NINJA_STATE_H_
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "eval_env.h"
-#include "graph.h"
-#include "hash_map.h"
-#include "util.h"
-
-struct Edge;
-struct Node;
-struct Rule;
-
-/// A pool for delayed edges.
-/// Pools are scoped to a State. Edges within a State will share Pools. A Pool
-/// will keep a count of the total 'weight' of the currently scheduled edges. If
-/// a Plan attempts to schedule an Edge which would cause the total weight to
-/// exceed the depth of the Pool, the Pool will enqueue the Edge instead of
-/// allowing the Plan to schedule it. The Pool will relinquish queued Edges when
-/// the total scheduled weight diminishes enough (i.e. when a scheduled edge
-/// completes).
-struct Pool {
-  Pool(const std::string& name, int depth)
-      : name_(name), current_use_(0), depth_(depth),
-        is_console_(name == "console"), delayed_() {}
-
-  /// A depth of 0 is infinite
-  bool is_valid() const { return depth_ >= 0; }
-
-  /// Return true if this is the console pool.
-  bool is_console() const { return is_console_; }
-
-  int depth() const { return depth_; }
-  const std::string& name() const { return name_; }
-  int current_use() const { return current_use_; }
-
-  /// true if the Pool might delay this edge
-  bool ShouldDelayEdge() const { return depth_ != 0; }
-
-  /// informs this Pool that the given edge is committed to be run.
-  /// Pool will count this edge as using resources from this pool.
-  void EdgeScheduled(const Edge& edge);
-
-  /// informs this Pool that the given edge is no longer runnable, and should
-  /// relinquish its resources back to the pool
-  void EdgeFinished(const Edge& edge);
-
-  /// adds the given edge to this Pool to be delayed.
-  void DelayEdge(Edge* edge);
-
-  /// Pool will add zero or more edges to the ready_queue
-  void RetrieveReadyEdges(EdgeSet* ready_queue);
-
-  /// Dump the Pool and its edges (useful for debugging).
-  void Dump() const;
-
-  /// Reset state.
-  void Reset();
-
- private:
-  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_;
-  bool is_console_;
-
-  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 std::set<Edge*, WeightedEdgeCmp> DelayedEdges;
-  DelayedEdges delayed_;
-};
-
-/// Global state (file status) for a single run.
-struct State {
-  State();
-
-  ~State();
-
-  State(State&&) noexcept = default;
-  State& operator=(State&&) noexcept = default;
-
-  State(const State&) = delete;
-  State& operator=(const State&) = delete;
-
-  /// Add pool instance, takes ownership.
-  void AddPool(Pool* pool);
-
-  Pool* LookupPool(const std::string& pool_name);
-
-  /// Return pointer to the default pool. This one is always created implicitly.
-  Pool* default_pool() const;
-
-  /// Return pointer to the console_pool(). This one is always created
-  /// implicitly.
-  Pool* console_pool() const;
-
-  /// Return pointer to phony rule. This one is always created implicitly.
-  const Rule* phony_rule() const { return phony_rule_; }
-
-  /// Allocate new Rule instance.
-  Rule* NewRule(StringPiece name);
-
-  Edge* AddEdge(const Rule* rule);
-
-  Node* GetNode(StringPiece path, uint64_t slash_bits);
-  Node* LookupNode(StringPiece path) const;
-  Node* SpellcheckNode(const std::string& path);
-
-  /// Add input / output / validation nodes to a given edge. This also
-  /// ensure that the generated_by_dep_loader() flag for all these nodes
-  /// is set to false, to indicate that they come from the input manifest.
-  void AddIn(Edge* edge, StringPiece path, uint64_t slash_bits);
-  bool AddOut(Edge* edge, StringPiece path, uint64_t slash_bits);
-  void AddValidation(Edge* edge, StringPiece path, uint64_t slash_bits);
-  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.
-  void Reset();
-
-  /// Dump the nodes and Pools (useful for debugging).
-  void Dump();
-
-  /// @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.
-  std::vector<Node*> RootNodes(std::string* error) const;
-  std::vector<Node*> DefaultNodes(std::string* error) const;
-
-  /// Create new BindingEnv instance.
-  BindingEnv* CreateNewEnv(BindingEnv* parent);
-
-  /// Return top-level BindingEnv instance.
-  BindingEnv& bindings() const { return *bindings_[0]; }
-
-  /// Mapping of path -> Node.
-  /// NOTE: This owns all Node instances, but a DepsLog instance contains
-  /// pointers to them as well.
-  typedef ExternalStringHashMap<Node*>::Type Paths;
-  Paths paths_;
-
-  /// All the pools used in the graph.
-  std::map<std::string, std::unique_ptr<Pool>> pools_;
-
-  /// The default and console pools. These points to elements of pools_.
-  Pool* default_pool_ = nullptr;
-  Pool* console_pool_ = nullptr;
-
-  /// All the edges of the graph.
-  /// NOTE: This owns all Edge instances.
-  std::vector<Edge*> edges_;
-
-  Rule* phony_rule_ = nullptr;
-
-  /// Note: BindingEnv need pointer stability (as they all include a parent
-  /// pointer)
-  std::vector<std::unique_ptr<BindingEnv>> bindings_;
-
-  /// Points to elements of paths_.
-  std::vector<Node*> defaults_;
-};
-
-#endif  // NINJA_STATE_H_
diff --git a/src/state_test.cc b/src/state_test.cc
deleted file mode 100644
index 0bc1519..0000000
--- a/src/state_test.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.
-
-#include "graph.h"
-#include "state.h"
-#include "test.h"
-
-using namespace std;
-
-namespace {
-
-TEST(State, Basic) {
-  State state;
-
-  EvalString command;
-  command.AddText("cat ");
-  command.AddSpecial("in");
-  command.AddText(" > ");
-  command.AddSpecial("out");
-
-  Rule* rule = new Rule("cat");
-  rule->AddBinding("command", command);
-  state.bindings().AddRule(rule);
-
-  Edge* edge = state.AddEdge(rule);
-  state.AddIn(edge, "in1", 0);
-  state.AddIn(edge, "in2", 0);
-  state.AddOut(edge, "out", 0);
-
-  EXPECT_EQ("cat in1 in2 > out", edge->EvaluateCommand());
-
-  EXPECT_FALSE(state.GetNode("in1", 0)->dirty());
-  EXPECT_FALSE(state.GetNode("in2", 0)->dirty());
-  EXPECT_FALSE(state.GetNode("out", 0)->dirty());
-}
-
-}  // namespace
diff --git a/src/status.cc b/src/status.cc
deleted file mode 100644
index 378edc7..0000000
--- a/src/status.cc
+++ /dev/null
@@ -1,468 +0,0 @@
-// Copyright 2016 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 "status.h"
-
-#include <assert.h>
-#include <stdarg.h>
-#include <stdlib.h>
-
-#ifdef _WIN32
-#include <fcntl.h>
-#include <io.h>
-#undef min  // min() is defined as a macro in minwindef.h
-#endif
-
-#include "async_loop.h"
-#include "build_config.h"
-#include "debug_flags.h"
-
-using namespace std;
-
-namespace {
-
-void StringAppendRate(std::string& str, double rate) {
-  if (rate == -1)
-    str.push_back('?');
-  else
-    StringAppendFormat(str, "%1.f", rate);
-}
-
-}  // namespace
-
-StatusPrinter::StatusPrinter(const BuildConfig& config)
-    : config_(config), started_edges_(0),
-      finished_edges_(0), total_edges_(0), running_edges_(0), time_millis_(0),
-      current_rate_(config.parallelism), format_(config_.status_format())  {
-  // LinePrinter constructor uses these environment variables to determine
-  // properties of the current terminal.
-  printer_.Reset(config.environment.Get("TERM"),
-                 config.environment.Get("CLICOLOR_FORCE"));
-
-  // Don't do anything fancy in verbose mode.
-  if (config_.verbosity != BuildConfig::NORMAL)
-    printer_.set_smart_terminal(false);
-
-  if (printer_.is_smart_terminal() && !config_.dry_run) {
-    max_pending_height_ = config_.status_max_commands();
-
-    // Since elapsed times are displayed to the first decimal digit
-    // only, there is no point in using a value smaller than 0.1 seconds
-    // for the refresh timeout.
-    const int64_t minimal_refresh_timeout_ms = 100;
-    int64_t config_refresh = config_.status_refresh_millis();
-    if (config_refresh && config_refresh > minimal_refresh_timeout_ms)
-      refresh_timeout_ms_ = config_refresh;
-    else
-      refresh_timeout_ms_ = minimal_refresh_timeout_ms;
-  }
-}
-
-StatusPrinter::~StatusPrinter() = default;
-
-void StatusPrinter::PlanHasTotalEdges(int total) {
-  total_edges_ = total;
-}
-
-void StatusPrinter::BuildEdgeStarted(const Edge* edge) {
-  int64_t start_time_millis = GetCurrentBuildTimeMs();
-  ++started_edges_;
-  ++running_edges_;
-  time_millis_ = start_time_millis;
-
-  pending_edges_[edge] = start_time_millis;
-
-  if (edge->use_console()) {
-    // This command will print its output directly to stdout, so
-    // clear the pending edges to let Ninja update the status and
-    // lock the line printer.
-    DisableTimer();
-    ClearPendingEdges();
-    PrintStatus(edge, start_time_millis);
-    printer_.SetConsoleLocked(true);
-  } else if (printer_.is_smart_terminal()) {
-    PrintStatus(edge, start_time_millis);
-    BuildRefresh(start_time_millis);
-  }
-}
-
-void StatusPrinter::BuildEdgeFinished(Edge* edge, bool success,
-                                      const string& output) {
-  int64_t end_time_millis = GetCurrentBuildTimeMs();
-  time_millis_ = end_time_millis;
-  ++finished_edges_;
-
-  auto it = pending_edges_.find(edge);
-  assert(it != pending_edges_.end());
-  pending_edges_.erase(it);
-
-  --running_edges_;
-
-  if (edge->use_console()) {
-    printer_.SetConsoleLocked(false);
-    EnableTimer();
-  }
-
-  if (config_.verbosity == BuildConfig::QUIET)
-    return;
-
-  if (!edge->use_console()) {
-    PrintStatus(edge, end_time_millis);
-    if (success && output.empty()) {
-      BuildRefresh(end_time_millis);
-    } else {
-      // Ninja is going to print something so clear
-      // any pending edges first.
-      ClearPendingEdges();
-    }
-  }
-
-  // Print the command that is spewing before printing its output.
-  if (!success) {
-    string outputs;
-    for (vector<Node*>::const_iterator o = edge->outputs_.begin();
-         o != edge->outputs_.end(); ++o)
-      outputs += (*o)->path() + " ";
-
-    if (printer_.supports_color()) {
-        printer_.PrintOnNewLine("\x1B[31m" "FAILED: " "\x1B[0m" + outputs + "\n");
-    } else {
-        printer_.PrintOnNewLine("FAILED: " + outputs + "\n");
-    }
-    printer_.PrintOnNewLine(edge->EvaluateCommand() + "\n");
-  }
-
-  if (!output.empty()) {
-    // ninja sets stdout and stderr of subprocesses to a pipe, to be able to
-    // check if the output is empty. Some compilers, e.g. clang, check
-    // isatty(stderr) to decide if they should print colored output.
-    // To make it possible to use colored output with ninja, subprocesses should
-    // be run with a flag that forces them to always print color escape codes.
-    // To make sure these escape codes don't show up in a file if ninja's output
-    // is piped to a file, ninja strips ansi escape codes again if it's not
-    // writing to a |smart_terminal_|.
-    // (Launching subprocesses in pseudo ttys doesn't work because there are
-    // only a few hundred available on some systems, and ninja can launch
-    // thousands of parallel compile commands.)
-    string final_output;
-    if (!printer_.supports_color())
-      final_output = StripAnsiEscapeCodes(output);
-    else
-      final_output = output;
-
-#ifdef _WIN32
-    // Fix extra CR being added on Windows, writing out CR CR LF (#773)
-    _setmode(_fileno(stdout), _O_BINARY);  // Begin Windows extra CR fix
-#endif
-
-    printer_.PrintOnNewLine(final_output);
-
-#ifdef _WIN32
-    _setmode(_fileno(stdout), _O_TEXT);  // End Windows extra CR fix
-#endif
-  }
-}
-
-void StatusPrinter::BuildLoadDyndeps() {
-  // The DependencyScan calls EXPLAIN() to print lines explaining why
-  // 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
-  // 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
-  // new build status line will appear.
-  if (g_explaining) {
-    ClearPendingEdges();
-    printer_.PrintOnNewLine("");
-  }
-}
-
-void StatusPrinter::DisableTimer() {
-  if (timer_)
-    timer_.Cancel();
-}
-
-void StatusPrinter::EnableTimer() {
-  if (timer_)
-    timer_.SetDurationMs(refresh_timeout_ms_);
-}
-
-int64_t StatusPrinter::GetCurrentBuildTimeMs() const {
-  return AsyncLoop::NowMs() - start_build_time_ms_;
-}
-
-void StatusPrinter::BuildStarted() {
-  started_edges_ = 0;
-  finished_edges_ = 0;
-  running_edges_ = 0;
-
-  if (refresh_timeout_ms_ > 0) {
-    if (!timer_) {
-      start_build_time_ms_ = AsyncLoop::NowMs();
-      timer_ = AsyncTimer::CreateWithDuration(
-          refresh_timeout_ms_, AsyncLoop::Get(), [this] {
-            int64_t cur_time_ms = GetCurrentBuildTimeMs();
-            BuildRefresh(cur_time_ms);
-            timer_.SetDurationMs(refresh_timeout_ms_);
-          });
-    }
-    EnableTimer();
-  }
-
-  // Reset last_update_time_ms_ because this function can be called
-  // multiple times, but with different starting epochs, which can
-  // confuse the logic in this code. As an example: Ninja starts
-  // a build then decides to launch the regenerator, which takes
-  // about 5 seconds to generate a new build plan. Ninja then starts
-  // another build. Without the reset, pending commands will not be
-  // displayed for about 5 seconds after the start of the second
-  // build!
-  last_update_time_ms_ = -1;
-}
-
-void StatusPrinter::BuildFinished() {
-  if (timer_) {
-    timer_.Close();
-  }
-  start_build_time_ms_ = 0;
-
-  printer_.SetConsoleLocked(false);
-  ClearPendingEdges();
-  printer_.PrintOnNewLine("");
-}
-
-string StatusPrinter::FormatProgressStatus(const char* progress_status_format,
-                                           int64_t time_millis) const {
-  string out;
-  for (const char* s = progress_status_format; *s != '\0'; ++s) {
-    if (*s == '%') {
-      ++s;
-      switch (*s) {
-      case '%':
-        out.push_back('%');
-        break;
-
-        // Started edges.
-      case 's':
-        StringAppendFormat(out, "%d", started_edges_);
-        break;
-
-        // Total edges.
-      case 't':
-        StringAppendFormat(out, "%d", total_edges_);
-        break;
-
-        // Running edges.
-      case 'r':
-        StringAppendFormat(out, "%d", running_edges_);
-        break;
-
-        // Unstarted edges.
-      case 'u':
-        StringAppendFormat(out, "%d", total_edges_ - started_edges_);
-        break;
-
-        // Finished edges.
-      case 'f':
-        StringAppendFormat(out, "%d", finished_edges_);
-        break;
-
-        // Overall finished edges per second.
-      case 'o':
-        StringAppendRate(out, finished_edges_ / (time_millis_ / 1e3));
-        break;
-
-        // Current rate, average over the last '-j' jobs.
-      case 'c':
-        current_rate_.UpdateRate(finished_edges_, time_millis_);
-        StringAppendRate(out, current_rate_.rate());
-        break;
-
-        // Percentage
-      case 'p': {
-        int percent = (100 * finished_edges_) / total_edges_;
-        StringAppendFormat(out, "%3i%%", percent);
-        break;
-      }
-
-      case 'e':
-        StringAppendFormat(out, "%.3f", time_millis_ / 1e3);
-        break;
-
-      default:
-        Fatal("unknown placeholder '%%%c' in $NINJA_STATUS", *s);
-        return "";
-      }
-    } else {
-      out.push_back(*s);
-    }
-  }
-
-  return out;
-}
-
-void StatusPrinter::PrintStatus(const Edge* edge, int64_t time_millis) {
-  if (config_.verbosity == BuildConfig::QUIET
-      || config_.verbosity == BuildConfig::NO_STATUS_UPDATE)
-    return;
-
-  bool force_full_command = config_.verbosity == BuildConfig::VERBOSE;
-
-  string to_print = edge->GetBinding("description");
-  if (to_print.empty() || force_full_command)
-    to_print = edge->GetBinding("command");
-
-  to_print = FormatProgressStatus(format_.c_str(), time_millis) +
-             to_print;
-
-  last_status_ = std::move(to_print);
-
-  printer_.Print(last_status_,
-                 force_full_command ? LinePrinter::FULL : LinePrinter::ELIDE);
-}
-
-void StatusPrinter::BuildRefresh(int64_t cur_time_ms) {
-  if (last_update_time_ms_ >= 0) {
-    int64_t since_last_ms = cur_time_ms - last_update_time_ms_;
-    if (since_last_ms < refresh_timeout_ms_) {
-      // No need to update more than necessary when tasks complete
-      // really really fast.
-      return;
-    }
-  }
-  last_update_time_ms_ = cur_time_ms;
-  PrintPendingEdges(cur_time_ms);
-}
-
-void StatusPrinter::ClearPendingEdges() {
-  if (last_pending_height_ == 0)
-    return;
-
-  // repeat "go down 1 line; erase whole line" |last_height_| times.
-  for (size_t n = 0; n < last_pending_height_; ++n) {
-    printf("\x1B[1B\x1B[2K");
-  }
-  // move up |last_height_| lines.
-  printf("\x1B[%dA", static_cast<int>(last_pending_height_));
-  fflush(stdout);
-
-  last_pending_height_ = 0;
-}
-
-void StatusPrinter::PrintPendingEdges(int64_t cur_time_ms) {
-  if (!max_pending_height_)
-    return;
-
-  // Find the N-th older running edges, where N is max_height_.
-  // Reuse the sorted_pending_edges_ vector between calls.
-  auto& sorted_edges = sorted_pending_edges_;
-  sorted_edges.assign(pending_edges_.begin(), pending_edges_.end());
-
-  auto less = [](const EdgeInfo& a, const EdgeInfo& b) -> bool {
-    return a.second < b.second;
-  };
-  size_t count = std::min(sorted_edges.size(), max_pending_height_);
-
-  std::partial_sort(sorted_edges.begin(), sorted_edges.begin() + count,
-                    sorted_edges.end(), less);
-
-  std::string pending_line;
-  for (size_t n = 0; n < count; ++n) {
-    EdgeInfo& pair = sorted_edges[n];
-
-    // Format the elapsed time in a human friendly format.
-    std::string elapsed;
-    int64_t elapsed_ms = cur_time_ms - pair.second;
-    if (elapsed_ms < 0) {
-      elapsed = "??????";
-    } else {
-      if (elapsed_ms < 60000) {
-        StringAppendFormat(elapsed, "%d.%ds",
-                           static_cast<int>((elapsed_ms / 1000)),
-                           static_cast<int>((elapsed_ms % 1000) / 100));
-      } else {
-        StringAppendFormat(elapsed, "%dm%ds",
-                           static_cast<int>((elapsed_ms / 60000)),
-                           static_cast<int>((elapsed_ms % 60000) / 1000));
-      }
-    }
-
-    // Get edge description or command.
-    std::string description = pair.first->GetBinding("description");
-    if (description.empty())
-      description = pair.first->GetBinding("command");
-
-    // Format '<elapsed> | <description>' where <elapsed> is
-    // right-justified.
-    size_t justification_width = 6;
-    size_t justified_elapsed_width =
-        std::min(justification_width, elapsed.size());
-    size_t needed_capacity = justified_elapsed_width + 3 + description.size();
-    if (needed_capacity > pending_line.capacity())
-      pending_line.reserve(needed_capacity);
-    if (elapsed.size() < justification_width) {
-      pending_line.assign(justification_width - elapsed.size(), ' ');
-    } else {
-      pending_line.clear();
-    }
-    pending_line.append(elapsed);
-    pending_line.append(" | ", 3);
-    pending_line.append(description);
-
-    printf("\n");
-    printer_.Print(pending_line, LinePrinter::ELIDE);
-  }
-
-  // Clear previous lines that are not needed anymore.
-  size_t next_height = count;
-  for (; count < last_pending_height_; ++count) {
-    // Go to next line + clear entire line.
-    printf("\n\x1B[2K");
-  }
-
-  if (count > 0) {
-    // Move up to the top status line. Then print the status
-    // again to reposition the cursor to the right position.
-    // Note that using ASCII sequences to save/restore the
-    // cursor position does not work reliably in all terminals
-    // (and terminal emulators like mosh or asciinema).
-    printf("\x1B[%dA", static_cast<int>(count));
-    printer_.Print(last_status_, LinePrinter::ELIDE);
-  }
-
-  last_pending_height_ = next_height;
-}
-
-void StatusPrinter::Warning(const char* msg, ...) {
-  va_list ap;
-  va_start(ap, msg);
-  ::Warning(msg, ap);
-  va_end(ap);
-}
-
-void StatusPrinter::Error(const char* msg, ...) {
-  va_list ap;
-  va_start(ap, msg);
-  ::Error(msg, ap);
-  va_end(ap);
-}
-
-void StatusPrinter::Info(const char* msg, ...) {
-  va_list ap;
-  va_start(ap, msg);
-  ::Info(msg, ap);
-  va_end(ap);
-}
diff --git a/src/status.h b/src/status.h
deleted file mode 100644
index 3c6119a..0000000
--- a/src/status.h
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2016 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_STATUS_H_
-#define NINJA_STATUS_H_
-
-#include <memory>
-#include <queue>
-#include <string>
-#include <unordered_map>
-
-#include "async_loop.h"
-#include "build.h"
-#include "line_printer.h"
-
-/// Abstract interface to object that tracks the status of a build:
-/// completion fraction, printing updates.
-struct Status {
-  virtual void PlanHasTotalEdges(int total) = 0;
-  virtual void BuildEdgeStarted(const Edge* edge) = 0;
-  virtual void BuildEdgeFinished(Edge* edge, bool success,
-                                 const std::string& output) = 0;
-  virtual void BuildLoadDyndeps() = 0;
-  virtual void BuildStarted() = 0;
-  virtual void BuildFinished() = 0;
-
-  virtual void Info(const char* msg, ...) = 0;
-  virtual void Warning(const char* msg, ...) = 0;
-  virtual void Error(const char* msg, ...) = 0;
-
-  virtual ~Status() { }
-};
-
-/// Implementation of the Status interface that prints the status as
-/// human-readable strings to stdout
-struct StatusPrinter : Status {
-  explicit StatusPrinter(const BuildConfig& config);
-  void PlanHasTotalEdges(int total) override;
-  void BuildEdgeStarted(const Edge* edge) override;
-  void BuildEdgeFinished(Edge* edge, bool success,
-                         const std::string& output) override;
-  void BuildLoadDyndeps() override;
-  void BuildStarted() override;
-  void BuildFinished() override;
-
-  void Info(const char* msg, ...) override;
-  void Warning(const char* msg, ...) override;
-  void Error(const char* msg, ...) override;
-
-  virtual ~StatusPrinter();
-
-  /// Format the progress status string by replacing the placeholders.
-  /// See the user manual for more information about the available
-  /// placeholders.
-  /// @param progress_status_format The format of the progress status.
-  /// @param status The status of the edge.
-  std::string FormatProgressStatus(const char* progress_status_format,
-                                   int64_t time_millis) const;
-
- private:
-  void PrintStatus(const Edge* edge, int64_t time_millis);
-
-  void BuildRefresh(int64_t current_time_ms);
-  void EnableTimer();
-  void DisableTimer();
-
-  int64_t GetCurrentBuildTimeMs() const;
-
-  const BuildConfig& config_;
-
-  int started_edges_, finished_edges_, total_edges_, running_edges_;
-  int64_t time_millis_;
-
-  /// Prints progress output.
-  LinePrinter printer_;
-
-  /// The custom progress status format to use.
-  const char* progress_status_format_;
-
-  struct SlidingRateInfo {
-    SlidingRateInfo(int n) : rate_(-1), N(n), last_update_(-1) {}
-
-    double rate() { return rate_; }
-
-    void UpdateRate(int update_hint, int64_t time_millis) {
-      if (update_hint == last_update_)
-        return;
-      last_update_ = update_hint;
-
-      if (times_.size() == N)
-        times_.pop();
-      times_.push(time_millis);
-      if (times_.back() != times_.front())
-        rate_ = times_.size() / ((times_.back() - times_.front()) / 1e3);
-    }
-
-  private:
-    double rate_;
-    const size_t N;
-    std::queue<double> times_;
-    int last_update_;
-  };
-
-  /// Called to refresh the pending list if needed.
-  void BuildRefresh();
-
-  mutable SlidingRateInfo current_rate_;
-
-  /// Support for printing pending edges below the status on smart terminals.
-  void PrintPendingEdges(int64_t cur_time_millis);
-  void ClearPendingEdges();
-
-  std::string format_;
-  int64_t refresh_timeout_ms_ = -1;
-  size_t max_pending_height_ = 0;
-  size_t last_pending_height_ = 0;
-  int64_t start_build_time_ms_ = 0;
-  int64_t last_update_time_ms_ = -1;
-  std::string last_status_;
-
-  AsyncLoop* async_loop_ = nullptr;
-  AsyncTimer timer_;
-
-  // Record pending edges
-  using EdgeMap = std::unordered_map<const Edge*, int64_t>;
-  EdgeMap pending_edges_;
-
-  // Used on each PrintPendingEdges() call to minimize heap allocations.
-  // Note that EdgeMap::value_type.first has type |const Edge* const| and
-  // thus EdgeMap::value_type is not copyable and cannot be used as an
-  // std::vector<> item type.
-  using EdgeInfo = std::pair<const Edge*, int64_t>;
-  std::vector<EdgeInfo> sorted_pending_edges_;
-};
-
-#endif // NINJA_STATUS_H_
diff --git a/src/status_test.cc b/src/status_test.cc
deleted file mode 100644
index 9d94e8b..0000000
--- a/src/status_test.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.
-
-#include "status.h"
-
-#include "build_config.h"
-#include "test.h"
-
-TEST(StatusTest, StatusFormatElapsed) {
-  BuildConfig config;
-  StatusPrinter status(config);
-
-  status.BuildStarted();
-  // Before any task is done, the elapsed time must be zero.
-  EXPECT_EQ("[%/e0.000]",
-            status.FormatProgressStatus("[%%/e%e]", 0));
-}
-
-TEST(StatusTest, StatusFormatReplacePlaceholder) {
-  BuildConfig config;
-  StatusPrinter status(config);
-
-  EXPECT_EQ("[%/s0/t0/r0/u0/f0]",
-            status.FormatProgressStatus("[%%/s%s/t%t/r%r/u%u/f%f]", 0));
-}
diff --git a/src/stdio_redirection.cc b/src/stdio_redirection.cc
deleted file mode 100644
index 246a9bb..0000000
--- a/src/stdio_redirection.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2023 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 "stdio_redirection.h"
-
-#include <thread>
-
-#include "util.h"
-
-StdioRedirector::StdioRedirector(IpcHandle& connection)
-    : connection_(connection) {}
-
-StdioRedirector::~StdioRedirector() {
-  auto do_close = [](IpcHandle& old_handle, FILE* stream) {
-    if (old_handle) {
-      old_handle.CloneIntoStdio(stream);
-      old_handle.Close();
-    };
-  };
-  fflush(stderr);
-  do_close(old_stderr_, stderr);
-
-  fflush(stdout);
-  do_close(old_stdout_, stdout);
-
-  do_close(old_stdin_, stdin);
-}
-
-bool StdioRedirector::SendStandardDescriptors(std::string* err) {
-  auto do_send = [this, err](FILE* stream) -> bool {
-    return connection_.SendNativeHandle(IpcHandle::NativeForStdio(stream), err);
-  };
-  return do_send(stdin) && do_send(stdout) && do_send(stderr);
-}
-
-bool StdioRedirector::ReceiveStandardDescriptors(std::string* err) {
-  auto do_receive = [this, err](FILE* stream, IpcHandle& old_handle) {
-    IpcHandle new_handle;
-    if (!connection_.ReceiveNativeHandle(&new_handle, err))
-      return false;
-    if (!new_handle) {
-      *err = "Received invalid standard descriptor";
-      return false;
-    }
-    old_handle = IpcHandle::CloneFromStdio(stream);
-    if (!old_handle) {
-      *err = "Could not save current standard descriptor";
-      return false;
-    }
-    if (!new_handle.CloneIntoStdio(stream)) {
-      *err = "Could not redirect standard descriptor";
-      return false;
-    }
-    return true;
-  };
-  return do_receive(stdin, old_stdin_) && do_receive(stdout, old_stdout_) &&
-         do_receive(stderr, old_stderr_);
-}
-
-StdioAsyncStringRedirector::StdioAsyncStringRedirector(AsyncLoop& async_loop,
-                                                       FILE* stream)
-    : stream_(stream), saved_handle_(IpcHandle::CloneFromStdio(stream)),
-      async_loop_(async_loop) {
-  fflush(stream_);
-  IpcHandle read_handle, write_handle;
-  std::string error;
-  if (!IpcHandle::CreateAsyncPipe(&read_handle, &write_handle, &error))
-    Fatal("ScopedBufferingStdio::CreatePipe: %s", error.c_str());
-
-  // Ensure the read handle is never copied to remote processes.
-  // IpcHandle::Clone() returns a new instance with CLOEXEC on Posix.
-  read_handle.SetInheritable(false);
-
-  read_handle_ = AsyncHandle::Create(std::move(read_handle), async_loop_,
-      [this](AsyncError error, size_t size) {
-        if (error || size == 0) {
-          Close();
-        } else {
-          result_.append(buffer_, size);
-          read_handle_.StartRead(buffer_, sizeof(buffer_));
-        }
-      });
-  read_handle_.StartRead(buffer_, sizeof(buffer_));
-
-#ifndef _WIN32
-  // Ensure the write handle is in blocking mode since it will be
-  // used as the new stdio descriptor.
-  write_handle.SetNonBlocking(false);
-#endif
-  write_handle.CloneIntoStdio(stream_);
-  write_handle.Close();
-}
-
-StdioAsyncStringRedirector::~StdioAsyncStringRedirector() {
-  Close();
-  Restore();
-}
-
-void StdioAsyncStringRedirector::Restore() {
-  fflush(stream_);
-  if (saved_handle_) {
-    saved_handle_.CloneIntoStdio(stream_);
-    saved_handle_.Close();
-  }
-}
-
-bool StdioAsyncStringRedirector::IsActive() const {
-  if (!read_handle_.IsRunning())
-    return false;
-
-  async_loop_.RunOnce(0);
-  return read_handle_.IsRunning();
-}
-
-bool StdioAsyncStringRedirector::WaitForResult(std::string* result,
-                                               int64_t timeout_ms) {
-  Restore();
-  auto status =
-      async_loop_.RunUntil([this]() { return !read_handle_; }, timeout_ms);
-  *result = result_;
-  return status != AsyncLoop::ExitTimeout;
-}
-
-void StdioAsyncStringRedirector::Close() {
-  read_handle_.Close();
-}
diff --git a/src/stdio_redirection.h b/src/stdio_redirection.h
deleted file mode 100644
index 631f76e..0000000
--- a/src/stdio_redirection.h
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2023 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_STDIO_REDIRECTION_H_
-#define NINJA_STDIO_REDIRECTION_H_
-
-#include <stdio.h>
-
-#include <string>
-
-#include "async_loop.h"
-#include "ipc_handle.h"
-
-/// Multiple classes related to redirecting stdio streams.
-
-/// A class used to manage redirection of stdin/stdout/stderr
-/// between two processes, using an IpcHandle for communication.
-///
-/// IMPORTANT: THIS DOES NOT WORK ON WINDOWS. Due to Win32
-/// technical limitations (i.e. DuplicateHandle() will always
-/// fail to duplicate console handlers from another process,
-/// which happens during ReceiveStandardDescriptors).
-///
-/// Usage is:
-///   1) Create instance, passing a reference to the handle.
-///
-///   2) On the client, call SendStandardDescriptors() to send
-///      standard descriptors to the server. This does not change
-///      the current process.
-///
-///   3) On the server, call ReceiveStandardDescriptors() to
-///      receive them from the handle, and modify the process'
-///      current standard descriptors to use them.
-///
-///   4) The destructor will restore the previous standard
-///      descriptors, in the case where ReceiveStandardDescriptors()
-///      was called.
-///
-class StdioRedirector {
- public:
-  StdioRedirector(IpcHandle& connection);
-  ~StdioRedirector();
-
-  bool SendStandardDescriptors(std::string* err);
-  bool ReceiveStandardDescriptors(std::string* err);
-
- protected:
-  IpcHandle& connection_;
-  IpcHandle old_stdin_;
-  IpcHandle old_stdout_;
-  IpcHandle old_stderr_;
-};
-
-/// A class used to redirect an stdout or stderr to a string buffer.
-/// temporarily. Only use this for testing for small outputs, as
-/// its implementation relies on async i/o on an anonymous pipe
-/// for properly reading the data. In practice, a blocking printf()
-/// call will deadlock if the pipe fills up entirely!
-///
-/// Usage is:
-///   - Create instance, passing an AsyncLoop reference and
-///     the stdout or stderr FILE pointer.
-///
-///   - Do small fprintf() or fputs() of the stream, the data
-///     will be sent to the pipe, if this happens on the same
-///     thread than the one running the AsyncLoop, a deadlock
-///     will happen when the pipe is full!
-///
-///   - Call Restore() to restore the stdio stream to its
-///     previous state. This does not destroyed data in the
-///     pipe or in the buffer.
-///
-///   - Call WaitForResult() to receive the result after
-///     draining the pipe completely. This calls Restore()
-///     implicitly.
-///
-class StdioAsyncStringRedirector {
- public:
-  /// Constructor flushes |stream|, which must be stdout or stderr,
-  /// then redirects its underlying file descriptor / handle to the
-  /// write end of a pipe, whose read end is managed by this instance
-  /// using asynchronous read operations. |async_loop| is a reference
-  /// to the global AsyncLoop instance.
-  ///
-  /// On Posix, the write end is in blocking mode and does _not_
-  /// close on exec(), intentionally, allowing it to be passed
-  /// to other processes during fork() + exec().
-  StdioAsyncStringRedirector(AsyncLoop& async_loop, FILE* stream);
-
-  /// Destructor restores previous stream handle.
-  ~StdioAsyncStringRedirector();
-
-  /// Flush the stream, close it, then restore its previous handle.
-  /// Can be called multiple times safely. Invoked implicitly by
-  /// the destructor and by WaitForResult().
-  void Restore();
-
-  /// Return true if the write end of the pipe has not been closed.
-  /// Note that normally Restore() closes it, unless another handle
-  /// exists on the system pointing to the pipe's write end
-  /// (e.g. when stdout was passed to another process).
-  bool IsActive() const;
-
-  /// Call Restore() then return buffered result after waiting
-  /// at most |timeout_ms| for the pipe's write end to be closed
-  /// (which may be prevented by another active file descriptor
-  /// pointing to it, e.g. when stdout was passed to another
-  /// process before this call).
-  ///
-  /// Set |*result| to the buffered output. Return true in case of
-  /// success, meaning the pipe is closed and the result is
-  /// complete, or false in case of timeout, meaning the result
-  /// might be incomplete, since there is no guarantee that the
-  /// peer has properly flushed its stdout.
-  bool WaitForResult(std::string* result, int64_t timeout_ms = 1000);
-
- private:
-  void StartRead();
-  void Close();
-
-  FILE* stream_;
-  int stream_fd_;
-  IpcHandle saved_handle_;
-  AsyncLoop& async_loop_;
-  AsyncHandle read_handle_;
-  std::string result_;
-  char buffer_[256];  // TODO(digit): Read directly into |result_|.
-};
-
-#endif  // NINJA_STDIO_REDIRECTION_H_
diff --git a/src/stdio_redirection_test.cc b/src/stdio_redirection_test.cc
deleted file mode 100644
index 80fb941..0000000
--- a/src/stdio_redirection_test.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2023 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 "stdio_redirection.h"
-
-#include "async_loop.h"
-#include "test.h"
-
-TEST(StdioAsyncStringRedirector, Test) {
-  auto async_loop = AsyncLoop::CreateLocal();
-  std::string result;
-  {
-    StdioAsyncStringRedirector async_stdout(*async_loop, stdout);
-    // IMPORTANT: Do not include \n in the input because fprintf()
-    // may or may not translate that into \r\n depending on too many
-    // factors to handle here.
-    fprintf(stdout, "Hello!");
-    EXPECT_TRUE(async_stdout.WaitForResult(&result));
-  }
-  EXPECT_EQ(result, "Hello!");
-}
-
-TEST(StdioAsyncStringRedirector, TestWithTimeout) {
-  auto async_loop = AsyncLoop::CreateLocal();
-  std::string result;
-  bool ret;
-  IpcHandle duplicate_stdout_fd;
-  {
-    StdioAsyncStringRedirector async_stdout(*async_loop, stdout);
-    fprintf(stdout, "Hello!");
-    fflush(stdout);
-
-    // Duplicate stdout handle, which will prevent the internal
-    // pipe to be closed properly by WaitForResult() which will
-    // timeout after 10ms.
-    duplicate_stdout_fd = IpcHandle::CloneFromStdio(stdout);
-    ret = async_stdout.WaitForResult(&result, 10LL);
-  }
-  EXPECT_FALSE(ret);
-  EXPECT_TRUE(duplicate_stdout_fd);
-  EXPECT_EQ(result, "Hello!");
-}
diff --git a/src/string_piece.h b/src/string_piece.h
deleted file mode 100644
index 1c0bee6..0000000
--- a/src/string_piece.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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.
-
-#ifndef NINJA_STRINGPIECE_H_
-#define NINJA_STRINGPIECE_H_
-
-#include <string>
-
-#include <string.h>
-
-/// StringPiece represents a slice of a string whose memory is managed
-/// externally.  It is useful for reducing the number of std::strings
-/// we need to allocate.
-struct StringPiece {
-  typedef const char* const_iterator;
-
-  StringPiece() : str_(NULL), len_(0) {}
-
-  /// The constructors intentionally allow for implicit conversions.
-  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) {}
-
-  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.
-  std::string AsString() const {
-    return len_ ? std::string(str_, len_) : std::string();
-  }
-
-  const_iterator begin() const {
-    return str_;
-  }
-
-  const_iterator end() const {
-    return str_ + len_;
-  }
-
-  char operator[](size_t pos) const {
-    return str_[pos];
-  }
-
-  size_t size() const {
-    return len_;
-  }
-
-  const char* str_;
-  size_t len_;
-};
-
-#endif  // NINJA_STRINGPIECE_H_
diff --git a/src/string_piece_util.cc b/src/string_piece_util.cc
deleted file mode 100644
index 69513f5..0000000
--- a/src/string_piece_util.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2017 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 "string_piece_util.h"
-
-#include <algorithm>
-#include <string>
-#include <vector>
-using namespace std;
-
-vector<StringPiece> SplitStringPiece(StringPiece input, char sep) {
-  vector<StringPiece> elems;
-  elems.reserve(count(input.begin(), input.end(), sep) + 1);
-
-  StringPiece::const_iterator pos = input.begin();
-
-  for (;;) {
-    const char* next_pos = find(pos, input.end(), sep);
-    if (next_pos == input.end()) {
-      elems.push_back(StringPiece(pos, input.end() - pos));
-      break;
-    }
-    elems.push_back(StringPiece(pos, next_pos - pos));
-    pos = next_pos + 1;
-  }
-
-  return elems;
-}
-
-string JoinStringPiece(const vector<StringPiece>& list, char sep) {
-  if (list.empty()) {
-    return "";
-  }
-
-  string ret;
-
-  {
-    size_t cap = list.size() - 1;
-    for (size_t i = 0; i < list.size(); ++i) {
-      cap += list[i].len_;
-    }
-    ret.reserve(cap);
-  }
-
-  for (size_t i = 0; i < list.size(); ++i) {
-    if (i != 0) {
-      ret += sep;
-    }
-    ret.append(list[i].str_, list[i].len_);
-  }
-
-  return ret;
-}
-
-bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b) {
-  if (a.len_ != b.len_) {
-    return false;
-  }
-
-  for (size_t i = 0; i < a.len_; ++i) {
-    if (ToLowerASCII(a.str_[i]) != ToLowerASCII(b.str_[i])) {
-      return false;
-    }
-  }
-
-  return true;
-}
diff --git a/src/string_piece_util.h b/src/string_piece_util.h
deleted file mode 100644
index 28470f1..0000000
--- a/src/string_piece_util.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2017 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_STRINGPIECE_UTIL_H_
-#define NINJA_STRINGPIECE_UTIL_H_
-
-#include <string>
-#include <vector>
-
-#include "string_piece.h"
-
-std::vector<StringPiece> SplitStringPiece(StringPiece input, 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;
-}
-
-bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b);
-
-#endif  // NINJA_STRINGPIECE_UTIL_H_
diff --git a/src/string_piece_util_test.cc b/src/string_piece_util_test.cc
deleted file mode 100644
index 61586dd..0000000
--- a/src/string_piece_util_test.cc
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2017 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 "string_piece_util.h"
-
-#include "test.h"
-
-using namespace std;
-
-TEST(StringPieceUtilTest, SplitStringPiece) {
-  {
-    string input("a:b:c");
-    vector<StringPiece> list = SplitStringPiece(input, ':');
-
-    EXPECT_EQ(list.size(), 3);
-
-    EXPECT_EQ(list[0], "a");
-    EXPECT_EQ(list[1], "b");
-    EXPECT_EQ(list[2], "c");
-  }
-
-  {
-    string empty;
-    vector<StringPiece> list = SplitStringPiece(empty, ':');
-
-    EXPECT_EQ(list.size(), 1);
-
-    EXPECT_EQ(list[0], "");
-  }
-
-  {
-    string one("a");
-    vector<StringPiece> list = SplitStringPiece(one, ':');
-
-    EXPECT_EQ(list.size(), 1);
-
-    EXPECT_EQ(list[0], "a");
-  }
-
-  {
-    string sep_only(":");
-    vector<StringPiece> list = SplitStringPiece(sep_only, ':');
-
-    EXPECT_EQ(list.size(), 2);
-
-    EXPECT_EQ(list[0], "");
-    EXPECT_EQ(list[1], "");
-  }
-
-  {
-    string sep(":a:b:c:");
-    vector<StringPiece> list = SplitStringPiece(sep, ':');
-
-    EXPECT_EQ(list.size(), 5);
-
-    EXPECT_EQ(list[0], "");
-    EXPECT_EQ(list[1], "a");
-    EXPECT_EQ(list[2], "b");
-    EXPECT_EQ(list[3], "c");
-    EXPECT_EQ(list[4], "");
-  }
-}
-
-TEST(StringPieceUtilTest, JoinStringPiece) {
-  {
-    string input("a:b:c");
-    vector<StringPiece> list = SplitStringPiece(input, ':');
-
-    EXPECT_EQ("a:b:c", JoinStringPiece(list, ':'));
-    EXPECT_EQ("a/b/c", JoinStringPiece(list, '/'));
-  }
-
-  {
-    string empty;
-    vector<StringPiece> list = SplitStringPiece(empty, ':');
-
-    EXPECT_EQ("", JoinStringPiece(list, ':'));
-  }
-
-  {
-    vector<StringPiece> empty_list;
-
-    EXPECT_EQ("", JoinStringPiece(empty_list, ':'));
-  }
-
-  {
-    string one("a");
-    vector<StringPiece> single_list = SplitStringPiece(one, ':');
-
-    EXPECT_EQ("a", JoinStringPiece(single_list, ':'));
-  }
-
-  {
-    string sep(":a:b:c:");
-    vector<StringPiece> list = SplitStringPiece(sep, ':');
-
-    EXPECT_EQ(":a:b:c:", JoinStringPiece(list, ':'));
-  }
-}
-
-TEST(StringPieceUtilTest, ToLowerASCII) {
-  EXPECT_EQ('a', ToLowerASCII('A'));
-  EXPECT_EQ('z', ToLowerASCII('Z'));
-  EXPECT_EQ('a', ToLowerASCII('a'));
-  EXPECT_EQ('z', ToLowerASCII('z'));
-  EXPECT_EQ('/', ToLowerASCII('/'));
-  EXPECT_EQ('1', ToLowerASCII('1'));
-}
-
-TEST(StringPieceUtilTest, EqualsCaseInsensitiveASCII) {
-  EXPECT_TRUE(EqualsCaseInsensitiveASCII("abc", "abc"));
-  EXPECT_TRUE(EqualsCaseInsensitiveASCII("abc", "ABC"));
-  EXPECT_TRUE(EqualsCaseInsensitiveASCII("abc", "aBc"));
-  EXPECT_TRUE(EqualsCaseInsensitiveASCII("AbC", "aBc"));
-  EXPECT_TRUE(EqualsCaseInsensitiveASCII("", ""));
-
-  EXPECT_FALSE(EqualsCaseInsensitiveASCII("a", "ac"));
-  EXPECT_FALSE(EqualsCaseInsensitiveASCII("/", "\\"));
-  EXPECT_FALSE(EqualsCaseInsensitiveASCII("1", "10"));
-}
diff --git a/src/subprocess-posix.cc b/src/subprocess-posix.cc
deleted file mode 100644
index 90a5a57..0000000
--- a/src/subprocess-posix.cc
+++ /dev/null
@@ -1,264 +0,0 @@
-// Copyright 2012 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 <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <spawn.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/select.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include "process_utils.h"
-#include "subprocess.h"
-
-extern char** environ;
-
-#include "util.h"
-
-using namespace std;
-
-Subprocess::Subprocess(SubprocessSet& subprocess_set, bool use_console)
-    : subprocess_set_(subprocess_set), pid_(-1), use_console_(use_console) {}
-
-Subprocess::~Subprocess() {
-  Stop();
-  // Reap child if forgotten.
-  if (pid_ != -1)
-    Finish();
-}
-
-void Subprocess::Stop() {
-  async_fd_.Close();
-}
-
-bool Subprocess::Start(const string& command) {
-  SubprocessSet* set = &subprocess_set_;
-  int output_pipe[2];
-  if (pipe(output_pipe) < 0)
-    ErrnoFatal("pipe");
-  IpcHandle fd = IpcHandle(output_pipe[0]);
-  fd.SetInheritable(false);
-
-  posix_spawn_file_actions_t action;
-  int err = posix_spawn_file_actions_init(&action);
-  if (err != 0)
-    ErrnoFatal("posix_spawn_file_actions_init", err);
-
-  err = posix_spawn_file_actions_addclose(&action, output_pipe[0]);
-  if (err != 0)
-    ErrnoFatal("posix_spawn_file_actions_addclose", err);
-
-  posix_spawnattr_t attr;
-  err = posix_spawnattr_init(&attr);
-  if (err != 0)
-    ErrnoFatal("posix_spawnattr_init", err);
-
-  short flags = 0;
-
-  flags |= POSIX_SPAWN_SETSIGMASK;
-  sigset_t old_mask = set->async_loop_.GetOldSignalMask();
-
-#ifndef _NDEBUG
-  // Consistency check, ensure that SIGINT/SIGHUP/SIGTERM can reach
-  // spawned processes.
-  if (sigismember(&old_mask, SIGINT))
-    Fatal("SubprocessSet: SIGINT is blocked in current signal mask");
-  if (sigismember(&old_mask, SIGHUP))
-    Fatal("SubprocessSet: SIGHUP is blocked in current signal mask");
-  if (sigismember(&old_mask, SIGTERM))
-    Fatal("SubprocessSet: SIGTERM is blocked in current signal mask");
-#endif
-
-  err = posix_spawnattr_setsigmask(&attr, &old_mask);
-  if (err != 0)
-    ErrnoFatal("posix_spawnattr_setsigmask", err);
-  // Signals which are set to be caught in the calling process image are set to
-  // default action in the new process image, so no explicit
-  // POSIX_SPAWN_SETSIGDEF parameter is needed.
-
-  if (!use_console_) {
-    // Put the child in its own process group, so ctrl-c won't reach it.
-    flags |= POSIX_SPAWN_SETPGROUP;
-    // No need to posix_spawnattr_setpgroup(&attr, 0), it's the default.
-
-    // Open /dev/null over stdin.
-    err = posix_spawn_file_actions_addopen(&action, 0, "/dev/null", O_RDONLY,
-          0);
-    if (err != 0) {
-      ErrnoFatal("posix_spawn_file_actions_addopen", err);
-    }
-
-    err = posix_spawn_file_actions_adddup2(&action, output_pipe[1], 1);
-    if (err != 0)
-      ErrnoFatal("posix_spawn_file_actions_adddup2", err);
-    err = posix_spawn_file_actions_adddup2(&action, output_pipe[1], 2);
-    if (err != 0)
-      ErrnoFatal("posix_spawn_file_actions_adddup2", err);
-    err = posix_spawn_file_actions_addclose(&action, output_pipe[1]);
-    if (err != 0)
-      ErrnoFatal("posix_spawn_file_actions_addclose", err);
-    // In the console case, output_pipe is still inherited by the child and
-    // closed when the subprocess finishes, which then notifies ninja.
-  }
-#ifdef POSIX_SPAWN_USEVFORK
-  flags |= POSIX_SPAWN_USEVFORK;
-#endif
-
-  err = posix_spawnattr_setflags(&attr, flags);
-  if (err != 0)
-    ErrnoFatal("posix_spawnattr_setflags", err);
-
-  char** env = environ;
-  if (set->environment_)
-    env = set->environment_->AsExecEnvironmentBlock();
-
-  const char* spawned_args[] = { "/bin/sh", "-c", command.c_str(), NULL };
-  err = posix_spawn(&pid_, "/bin/sh", &action, &attr,
-                    const_cast<char**>(spawned_args), env);
-  if (err != 0)
-    ErrnoFatal("posix_spawn", err);
-
-  err = posix_spawnattr_destroy(&attr);
-  if (err != 0)
-    ErrnoFatal("posix_spawnattr_destroy", err);
-  err = posix_spawn_file_actions_destroy(&action);
-  if (err != 0)
-    ErrnoFatal("posix_spawn_file_actions_destroy", err);
-
-  close(output_pipe[1]);
-
-  async_fd_ = AsyncHandle::Create(std::move(fd), subprocess_set_.async_loop_,
-      [this](AsyncError error, size_t size) {
-        if (error)
-          Fatal("read: %s", strerror(error));
-
-        if (size == 0) {
-          Stop();
-          subprocess_set_.OnProcessCompletion(this);
-          return;
-        }
-        // Append result, continue reading.
-        buf_.append(read_buf_, size);
-        async_fd_.StartRead(read_buf_, sizeof(read_buf_));
-      });
-
-  async_fd_.StartRead(read_buf_, sizeof(read_buf_));
-  return true;
-}
-
-ExitStatus Subprocess::Finish() {
-  assert(pid_ != -1);
-  int status;
-  if (waitpid(pid_, &status, 0) < 0)
-    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)
-      return ExitSuccess;
-  } else if (WIFSIGNALED(status)) {
-    if (WTERMSIG(status) == SIGINT || WTERMSIG(status) == SIGTERM
-        || WTERMSIG(status) == SIGHUP)
-      return ExitInterrupted;
-  }
-  return ExitFailure;
-}
-
-bool Subprocess::Done() const {
-  return !async_fd_;
-}
-
-const string& Subprocess::GetOutput() const {
-  return buf_;
-}
-
-SubprocessSet::SubprocessSet()
-    : async_loop_(AsyncLoop::Get()), interrupt_catcher_(async_loop_) {}
-
-SubprocessSet::SubprocessSet(const EnvironmentBlock& environment)
-    : async_loop_(AsyncLoop::Get()), interrupt_catcher_(async_loop_),
-      environment_(&environment) {}
-
-SubprocessSet::~SubprocessSet() {
-  Clear();
-}
-
-Subprocess* SubprocessSet::Add(const string& command, bool use_console) {
-  auto subprocess =
-      std::unique_ptr<Subprocess>(new Subprocess(*this, use_console));
-  if (!subprocess->Start(command)) {
-    return 0;
-  }
-
-  Subprocess* result = subprocess.get();
-  running_.push_back(std::move(subprocess));
-  return result;
-}
-
-void SubprocessSet::OnProcessCompletion(Subprocess* subprocess) {
-  // Move the subprocess from the running_ vector to the finished_ queue.
-  for (auto it = running_.begin(); it != running_.end(); ++it) {
-    if (it->get() == subprocess) {
-      finished_.emplace(it->release());
-      running_.erase(it);
-      return;
-    }
-  }
-}
-
-bool SubprocessSet::DoWork() {
-  size_t running_count = running_.size();
-  if (!running_count)
-    return false;
-
-  AsyncLoop::ExitStatus loop_status =
-      async_loop_.RunUntil([this, &running_count]() -> bool {
-        return running_.size() != running_count;
-      });
-
-  return loop_status == AsyncLoop::ExitInterrupted;
-}
-
-std::unique_ptr<Subprocess> SubprocessSet::NextFinished() {
-  if (finished_.empty())
-    return {};
-
-  std::unique_ptr<Subprocess> subproc = std::move(finished_.front());
-  finished_.pop();
-  return subproc;
-}
-
-void SubprocessSet::Clear() {
-  int int_signal = async_loop_.GetInterruptSignal();
-  for (auto& subproc : running_) {
-    if (!subproc->use_console_)
-      kill(-subproc->pid_, int_signal);
-  }
-  running_.clear();
-}
diff --git a/src/subprocess-win32.cc b/src/subprocess-win32.cc
deleted file mode 100644
index 859873a..0000000
--- a/src/subprocess-win32.cc
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright 2012 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 <assert.h>
-#include <stdio.h>
-
-#include <algorithm>
-
-#include "process_utils.h"
-#include "subprocess.h"
-#include "util.h"
-
-using namespace std;
-
-Subprocess::Subprocess(SubprocessSet& subprocess_set, bool use_console)
-    : subprocess_set_(subprocess_set), use_console_(use_console) {}
-
-Subprocess::~Subprocess() {
-  Stop();
-  // Reap child if forgotten.
-  if (child_)
-    Finish();
-}
-
-void Subprocess::Stop() {
-  pipe_.Close();
-}
-
-HANDLE Subprocess::SetupPipe() {
-  char pipe_name[100];
-  snprintf(pipe_name, sizeof(pipe_name),
-           "\\\\.\\pipe\\ninja_pid%lu_sp%p", GetCurrentProcessId(), this);
-
-  IpcHandle pipe_handle = ::CreateNamedPipeA(
-      pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE,
-      PIPE_UNLIMITED_INSTANCES, 0, 0, INFINITE, NULL);
-  if (!pipe_handle)
-    Win32Fatal("CreateNamedPipe");
-
-  AsyncLoop& async_loop = subprocess_set_.async_loop_;
-
-  pipe_ = AsyncHandle::Create(
-    std::move(pipe_handle), subprocess_set_.async_loop_,
-    [this](AsyncError error, size_t size) {
-      if (error) {
-        if (error != ERROR_BROKEN_PIPE)
-          Win32Fatal("GetOverlappedResult", error);
-        Stop();
-        subprocess_set_.OnProcessCompletion(this);
-        return;
-      }
-      if (!is_reading_) {
-        IpcHandle pipe_handle = pipe_.TakeAcceptedHandle();
-        pipe_.ResetHandle(std::move(pipe_handle));
-        is_reading_ = true;
-      } else {
-        buf_.append(read_buf_, size);
-      }
-      pipe_.StartRead(read_buf_, sizeof(read_buf_));
-    });
-
-  pipe_.StartAccept();
-
-  // Get the write end of the pipe as a handle inheritable across processes.
-  HANDLE output_write_handle =
-      CreateFileA(pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
-  HANDLE output_write_child;
-  if (!DuplicateHandle(GetCurrentProcess(), output_write_handle,
-                       GetCurrentProcess(), &output_write_child,
-                       0, TRUE, DUPLICATE_SAME_ACCESS)) {
-    Win32Fatal("DuplicateHandle");
-  }
-  CloseHandle(output_write_handle);
-
-  return output_write_child;
-}
-
-bool Subprocess::Start(const string& command) {
-  IpcHandle child_pipe = SetupPipe();
-
-  SECURITY_ATTRIBUTES security_attributes = {};
-  security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
-  security_attributes.bInheritHandle = TRUE;
-  // Must be inheritable so subprocesses can dup to children.
-  IpcHandle nul =
-      CreateFileA("NUL", GENERIC_READ,
-                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                  &security_attributes, OPEN_EXISTING, 0, NULL);
-  if (!nul)
-    Fatal("couldn't open nul");
-
-  STARTUPINFOA startup_info = {};
-  startup_info.cb = sizeof(STARTUPINFO);
-  if (!use_console_) {
-    startup_info.dwFlags = STARTF_USESTDHANDLES;
-    startup_info.hStdInput = nul.native_handle();
-    startup_info.hStdOutput = child_pipe.native_handle();
-    startup_info.hStdError = child_pipe.native_handle();
-  }
-  // In the console case, child_pipe is still inherited by the child and closed
-  // when the subprocess finishes, which then notifies ninja.
-
-  PROCESS_INFORMATION process_info = {};
-
-  // Ninja handles ctrl-c, except for subprocesses in console pools.
-  DWORD process_flags = use_console_ ? 0 : CREATE_NEW_PROCESS_GROUP;
-
-  // Compute environment pointer.
-  LPVOID environment = NULL;
-  if (subprocess_set_.environment_)
-    environment = subprocess_set_.environment_->AsAnsiEnvironmentBlock();
-
-  // Do not prepend 'cmd /c' on Windows, this breaks command
-  // lines greater than 8,191 chars.
-  if (!CreateProcessA(NULL, (char*)command.c_str(), NULL, NULL,
-                      /* inherit handles */ TRUE, process_flags, environment,
-                      NULL, &startup_info, &process_info)) {
-    DWORD error = GetLastError();
-    if (error == ERROR_FILE_NOT_FOUND) {
-      // File (program) not found error is treated as a normal build
-      // action failure.
-      Stop();
-      // child_ is already NULL;
-      buf_ = "CreateProcess failed: The system cannot find the file "
-          "specified.\n";
-      return true;
-    } else {
-      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);
-    }
-  }
-
-  // Close pipe channel only used by the child.
-  CloseHandle(process_info.hThread);
-  child_ = IpcHandle(process_info.hProcess);
-
-  return true;
-}
-
-ExitStatus Subprocess::Finish() {
-  if (!child_)
-    return ExitFailure;
-
-  // TODO: add error handling for all of these.
-  WaitForSingleObject(child_.native_handle(), INFINITE);
-
-  DWORD exit_code = 0;
-  GetExitCodeProcess(child_.native_handle(), &exit_code);
-
-  child_.Close();
-
-  return exit_code == 0              ? ExitSuccess :
-         exit_code == CONTROL_C_EXIT ? ExitInterrupted :
-                                       ExitFailure;
-}
-
-bool Subprocess::Done() const {
-  return !pipe_;
-}
-
-const string& Subprocess::GetOutput() const {
-  return buf_;
-}
-
-SubprocessSet::SubprocessSet()
-    : async_loop_(AsyncLoop::Get()), interrupt_catcher_(async_loop_) {}
-
-SubprocessSet::SubprocessSet(const EnvironmentBlock& environment)
-    : async_loop_(AsyncLoop::Get()), interrupt_catcher_(async_loop_),
-      environment_(&environment) {}
-
-SubprocessSet::~SubprocessSet() {
-  Clear();
-}
-
-Subprocess *SubprocessSet::Add(const string& command, bool use_console) {
-  std::unique_ptr<Subprocess> subprocess(new Subprocess(*this, use_console));
-  if (!subprocess->Start(command)) {
-    return 0;
-  }
-  Subprocess* result = subprocess.get();
-  if (subprocess->child_)
-    running_.push_back(std::move(subprocess));
-  else
-    finished_.push(std::move(subprocess));
-  return result;
-}
-
-void SubprocessSet::OnProcessCompletion(Subprocess* subprocess) {
-  // Move the subprocess from the running_ vector to the finished_ queue.
-  for (auto it = running_.begin(); it != running_.end(); ++it) {
-    if (it->get() == subprocess) {
-      finished_.emplace(std::move(*it));
-      running_.erase(it);
-      return;
-    }
-  }
-  assert(false && "Unknown subprocess pointer!");
-}
-
-bool SubprocessSet::DoWork() {
-  size_t running_count = running_.size();
-  if (!running_count)
-    return false;
-
-  AsyncLoop::ExitStatus loop_status =
-      async_loop_.RunUntil([this, &running_count]() -> bool {
-        return running_.size() != running_count;
-      });
-
-  return loop_status == AsyncLoop::ExitInterrupted;
-}
-
-std::unique_ptr<Subprocess> SubprocessSet::NextFinished() {
-  if (finished_.empty())
-    return {};
-
-  std::unique_ptr<Subprocess> subproc = std::move(finished_.front());
-  finished_.pop();
-  return subproc;
-}
-
-void SubprocessSet::Clear() {
-  for (auto& subproc : running_) {
-    // Since the foreground process is in our process group, it will receive a
-    // CTRL_C_EVENT or CTRL_BREAK_EVENT at the same time as us.
-    if (subproc->child_ && !subproc->use_console_) {
-      if (!GenerateConsoleCtrlEvent(
-              CTRL_BREAK_EVENT,
-              GetProcessId(subproc->child_.native_handle()))) {
-        Win32Fatal("GenerateConsoleCtrlEvent");
-      }
-    }
-  }
-  running_.clear();
-}
diff --git a/src/subprocess.h b/src/subprocess.h
deleted file mode 100644
index e6490fd..0000000
--- a/src/subprocess.h
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2012 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_SUBPROCESS_H_
-#define NINJA_SUBPROCESS_H_
-
-#include <memory>
-#include <queue>
-#include <string>
-#include <vector>
-
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <signal.h>
-#endif
-
-#include "async_loop.h"
-#include "exit_status.h"
-#include "interrupt_handling.h"
-#include "ipc_handle.h"
-
-class EnvironmentBlock;
-
-struct SubprocessSet;
-
-/// Subprocess wraps a single async subprocess.  It is entirely
-/// passive: it expects the caller to notify it when its fds are ready
-/// for reading, as well as call Finish() to reap the child once done()
-/// is true.
-struct Subprocess {
-  ~Subprocess();
-
-  /// Returns ExitSuccess on successful process exit, ExitInterrupted if
-  /// the process was interrupted, ExitFailure if it otherwise failed.
-  /// Should only be called on an instance where Done() returns true.
-  ExitStatus Finish();
-
-  /// Return true if the a subprocess has completed. Only used for testing.
-  bool Done() const;
-
-  /// Retrieve buffered output (combined stdout/stderr) for a given
-  /// subprocess. Will be empty for subprocesses belonging to the 'console'
-  /// pool. Only call this when Done() returns true, or after a call to
-  /// Finish().
-  const std::string& GetOutput() const;
-
- private:
-  Subprocess(SubprocessSet& subprocess_set, bool use_console);
-  bool Start(const std::string& command);
-
-  SubprocessSet& subprocess_set_;
-  std::string buf_;
-
-#ifdef _WIN32
-  /// Set up pipe_ as the parent-side pipe of the subprocess; return the
-  /// other end of the pipe, usable in the child process.
-  HANDLE SetupPipe();
-
-  IpcHandle child_;
-  AsyncHandle pipe_;
-  bool is_reading_ = false;
-#else
-  AsyncHandle async_fd_;
-  pid_t pid_;
-#endif
-  bool use_console_;
-  char read_buf_[4 << 10];
-
-  void Stop();
-
-  friend struct SubprocessSet;
-};
-
-/// SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
-/// DoWork() waits for any state change in subprocesses; finished_
-/// is a queue of subprocesses as they finish.
-struct SubprocessSet {
-  SubprocessSet();
-
-  explicit SubprocessSet(const EnvironmentBlock& environment);
-
-  ~SubprocessSet();
-
-  /// Start a new subprocess, and return a pointer to the corresponding
-  /// instance, which is still owned by the SubprocessSet.
-  Subprocess* Add(const std::string& command, bool use_console = false);
-
-  /// Wait for any subprocess to complete. Returns true if interrupted
-  /// or false otherwise.
-  bool DoWork();
-
-  /// Return next finished process, or null if there is none.
-  /// The returned instance must be destroyed before this SubprocessSet.
-  std::unique_ptr<Subprocess> NextFinished();
-
-  /// Remove all remaining processes forcibly.
-  void Clear();
-
-  std::vector<std::unique_ptr<Subprocess>> running_;
-  std::queue<std::unique_ptr<Subprocess>> finished_;
-
- private:
-  friend struct Subprocess;
-
-  AsyncLoop& async_loop_;
-  AsyncLoop::ScopedInterruptCatcher interrupt_catcher_;
-  const EnvironmentBlock* environment_ = nullptr;
-
-  // Called from an asynchronous callback when a subprocess completes.
-  void OnProcessCompletion(Subprocess* subprocess);
-};
-
-#endif // NINJA_SUBPROCESS_H_
diff --git a/src/subprocess_test.cc b/src/subprocess_test.cc
deleted file mode 100644
index 3aa4089..0000000
--- a/src/subprocess_test.cc
+++ /dev/null
@@ -1,279 +0,0 @@
-// Copyright 2012 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 "subprocess.h"
-
-#include "test.h"
-
-#ifndef _WIN32
-// SetWithLots need setrlimit.
-#include <stdio.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <unistd.h>
-#endif
-
-using namespace std;
-
-namespace {
-
-#ifdef _WIN32
-const char* kSimpleCommand = "cmd /c dir \\";
-#else
-const char* kSimpleCommand = "ls /";
-#endif
-
-struct SubprocessTest : public testing::Test {
-  void SetUp() { AsyncLoop::ResetForTesting(); }
-
-  SubprocessSet subprocs_;
-};
-
-}  // anonymous namespace
-
-// Run a command that fails and emits to stderr.
-TEST_F(SubprocessTest, BadCommandStderr) {
-  Subprocess* subproc = subprocs_.Add("cmd /c ninja_no_such_command");
-  ASSERT_NE((Subprocess *) 0, subproc);
-
-  while (!subproc->Done()) {
-    // Pretend we discovered that stderr was ready for writing.
-    subprocs_.DoWork();
-  }
-
-  EXPECT_EQ(ExitFailure, subproc->Finish());
-  EXPECT_NE("", subproc->GetOutput());
-}
-
-// Run a command that does not exist
-TEST_F(SubprocessTest, NoSuchCommand) {
-  Subprocess* subproc = subprocs_.Add("ninja_no_such_command");
-  ASSERT_NE((Subprocess *) 0, subproc);
-
-  while (!subproc->Done()) {
-    // Pretend we discovered that stderr was ready for writing.
-    subprocs_.DoWork();
-  }
-
-  EXPECT_EQ(ExitFailure, subproc->Finish());
-  EXPECT_NE("", subproc->GetOutput());
-#ifdef _WIN32
-  ASSERT_EQ("CreateProcess failed: The system cannot find the file "
-            "specified.\n", subproc->GetOutput());
-#endif
-}
-
-#ifndef _WIN32
-
-TEST_F(SubprocessTest, InterruptChild) {
-  Subprocess* subproc = subprocs_.Add("kill -INT $$");
-  ASSERT_NE((Subprocess *) 0, subproc);
-
-  while (!subproc->Done()) {
-    subprocs_.DoWork();
-  }
-
-  EXPECT_EQ(ExitInterrupted, subproc->Finish());
-}
-
-TEST_F(SubprocessTest, InterruptParent) {
-  Subprocess* subproc = subprocs_.Add("kill -INT $PPID ; sleep 1");
-  ASSERT_NE((Subprocess *) 0, subproc);
-
-  while (!subproc->Done()) {
-    bool interrupted = subprocs_.DoWork();
-    if (interrupted)
-      return;
-  }
-
-  ASSERT_FALSE("We should have been interrupted");
-}
-
-TEST_F(SubprocessTest, InterruptChildWithSigTerm) {
-  Subprocess* subproc = subprocs_.Add("kill -TERM $$");
-  ASSERT_NE((Subprocess *) 0, subproc);
-
-  while (!subproc->Done()) {
-    subprocs_.DoWork();
-  }
-
-  EXPECT_EQ(ExitInterrupted, subproc->Finish());
-}
-
-TEST_F(SubprocessTest, InterruptParentWithSigTerm) {
-  Subprocess* subproc = subprocs_.Add("kill -TERM $PPID ; sleep 1");
-  ASSERT_NE((Subprocess *) 0, subproc);
-
-  while (!subproc->Done()) {
-    bool interrupted = subprocs_.DoWork();
-    if (interrupted)
-      return;
-  }
-
-  ASSERT_FALSE("We should have been interrupted");
-}
-
-TEST_F(SubprocessTest, InterruptChildWithSigHup) {
-  Subprocess* subproc = subprocs_.Add("kill -HUP $$");
-  ASSERT_NE((Subprocess *) 0, subproc);
-
-  while (!subproc->Done()) {
-    subprocs_.DoWork();
-  }
-
-  EXPECT_EQ(ExitInterrupted, subproc->Finish());
-}
-
-TEST_F(SubprocessTest, InterruptParentWithSigHup) {
-  Subprocess* subproc = subprocs_.Add("kill -HUP $PPID ; sleep 1");
-  ASSERT_NE((Subprocess *) 0, subproc);
-
-  while (!subproc->Done()) {
-    bool interrupted = subprocs_.DoWork();
-    if (interrupted)
-      return;
-  }
-
-  ASSERT_FALSE("We should have been interrupted");
-}
-
-TEST_F(SubprocessTest, Timeout) {
-  Subprocess* subproc = subprocs_.Add("sleep 1");
-  ASSERT_NE((Subprocess*)0, subproc);
-
-  int timeout_counter = 0;
-  while (!subproc->Done()) {
-    bool interrupted = subprocs_.DoWork();
-    if (interrupted) {
-      ASSERT_GT(timeout_counter, 0);
-      break;
-    }
-    timeout_counter++;
-  }
-}
-
-TEST_F(SubprocessTest, Console) {
-  // Skip test if we don't have the console ourselves.
-  if (isatty(0) && isatty(1) && isatty(2)) {
-    Subprocess* subproc =
-        subprocs_.Add("test -t 0 -a -t 1 -a -t 2", /*use_console=*/true);
-    ASSERT_NE((Subprocess*)0, subproc);
-
-    while (!subproc->Done()) {
-      subprocs_.DoWork();
-    }
-
-    EXPECT_EQ(ExitSuccess, subproc->Finish());
-  }
-}
-
-#endif
-
-TEST_F(SubprocessTest, SetWithSingle) {
-  Subprocess* subproc = subprocs_.Add(kSimpleCommand);
-  ASSERT_NE((Subprocess *) 0, subproc);
-
-  while (!subproc->Done()) {
-    subprocs_.DoWork();
-  }
-  ASSERT_EQ(ExitSuccess, subproc->Finish());
-  ASSERT_NE("", subproc->GetOutput());
-
-  ASSERT_EQ(1u, subprocs_.finished_.size());
-}
-
-TEST_F(SubprocessTest, SetWithMulti) {
-  Subprocess* processes[3];
-  const char* kCommands[3] = {
-    kSimpleCommand,
-#ifdef _WIN32
-    "cmd /c echo hi",
-    "cmd /c time /t",
-#else
-    "id -u",
-    "pwd",
-#endif
-  };
-
-  for (int i = 0; i < 3; ++i) {
-    processes[i] = subprocs_.Add(kCommands[i]);
-    ASSERT_NE((Subprocess *) 0, processes[i]);
-  }
-
-  ASSERT_EQ(3u, subprocs_.running_.size());
-  for (int i = 0; i < 3; ++i) {
-    ASSERT_FALSE(processes[i]->Done());
-    ASSERT_EQ("", processes[i]->GetOutput());
-  }
-
-  while (!processes[0]->Done() || !processes[1]->Done() ||
-         !processes[2]->Done()) {
-    ASSERT_GT(subprocs_.running_.size(), 0u);
-    subprocs_.DoWork();
-  }
-
-  ASSERT_EQ(0u, subprocs_.running_.size());
-  ASSERT_EQ(3u, subprocs_.finished_.size());
-
-  for (int i = 0; i < 3; ++i) {
-    ASSERT_EQ(ExitSuccess, processes[i]->Finish());
-    ASSERT_NE("", processes[i]->GetOutput());
-  }
-}
-
-#if defined(USE_KQUEUE) || defined(USE_PPOLL)
-TEST_F(SubprocessTest, SetWithLots) {
-  // Arbitrary big number; needs to be over 1024 to confirm we're no longer
-  // hostage to pselect.
-  const unsigned kNumProcs = 1025;
-
-  // Make sure [ulimit -n] isn't going to stop us from working.
-  rlimit rlim;
-  ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlim));
-  if (rlim.rlim_cur < kNumProcs) {
-    printf("Raise [ulimit -n] above %u (currently %lu) to make this test go\n",
-           kNumProcs, static_cast<unsigned long>(rlim.rlim_cur));
-    return;
-  }
-
-  vector<Subprocess*> procs;
-  for (size_t i = 0; i < kNumProcs; ++i) {
-    Subprocess* subproc = subprocs_.Add("/bin/echo");
-    ASSERT_NE((Subprocess *) 0, subproc);
-    procs.push_back(subproc);
-  }
-  while (!subprocs_.running_.empty())
-    subprocs_.DoWork();
-  for (size_t i = 0; i < procs.size(); ++i) {
-    ASSERT_EQ(ExitSuccess, procs[i]->Finish());
-    ASSERT_NE("", procs[i]->GetOutput());
-  }
-  ASSERT_EQ(kNumProcs, subprocs_.finished_.size());
-}
-#endif  // USE_KQUEUE || USE_PPOLL
-
-// TODO: this test could work on Windows, just not sure how to simply
-// read stdin.
-#ifndef _WIN32
-// Verify that a command that attempts to read stdin correctly thinks
-// that stdin is closed.
-TEST_F(SubprocessTest, ReadStdin) {
-  Subprocess* subproc = subprocs_.Add("cat -");
-  while (!subproc->Done()) {
-    subprocs_.DoWork();
-  }
-  ASSERT_EQ(ExitSuccess, subproc->Finish());
-  ASSERT_EQ(1u, subprocs_.finished_.size());
-}
-#endif  // _WIN32
diff --git a/src/test.cc b/src/test.cc
deleted file mode 100644
index d64743f..0000000
--- a/src/test.cc
+++ /dev/null
@@ -1,306 +0,0 @@
-// 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.
-
-#ifdef _WIN32
-#include <direct.h>  // Has to be before util.h is included.
-#endif
-
-#include "test.h"
-
-#include <algorithm>
-
-#include <errno.h>
-#include <stdlib.h>
-#ifdef _WIN32
-#include <io.h>
-#include <sys/stat.h>
-#include <windows.h>
-#else
-#include <unistd.h>
-#endif
-
-#include "build_log.h"
-#include "graph.h"
-#include "manifest_parser.h"
-#include "util.h"
-
-#ifdef _AIX
-extern "C" {
-        // GCC "helpfully" strips the definition of mkdtemp out on AIX.
-        // The function is still present, so if we define it ourselves
-        // it will work perfectly fine.
-        extern char* mkdtemp(char* name_template);
-}
-#endif
-
-using namespace std;
-
-namespace {
-
-#ifdef _WIN32
-/// Windows has no mkdtemp.  Implement it in terms of _mktemp_s.
-char* mkdtemp(char* name_template) {
-  // The mktemp_s() implementation of the Wine C runtime is broken and
-  // will consistently fail after 26 calls(!) by returning EEXIST.
-  // Reimplement the function in this case.
-  const size_t max_tries = 32;
-  bool found_one = false;
-  size_t len = ::strlen(name_template);
-  // Count the number of X's in the template, must be at least 6.
-  size_t num_xs = 0;
-  while (num_xs < len && name_template[len - 1 - num_xs] == 'X')
-    num_xs++;
-  if (num_xs < 6) {
-    errno = EINVAL;
-    perror("_mktemp_s");
-    return NULL;
-  }
-
-  // rand() is really not very random on Wine by default :-/
-  // leading to surprising conflicts. Same is true for GetCurrentProcessId()
-  // or GetCurrentProcess() so use time
-  FILETIME ft = {};
-  ::GetSystemTimeAsFileTime(&ft);
-  srand(static_cast<unsigned>(ft.dwLowDateTime));
-
-  auto get_random_alnum = []() -> char {
-    int index = rand() % 62;
-    if (index < 26)
-      return static_cast<char>('A' + index);
-    index -= 26;
-    if (index < 26)
-      return static_cast<char>('a' + index);
-    index -= 26;
-    return static_cast<char>('0' + index);
-  };
-  char* start = name_template + len - num_xs;
-  for (size_t tries = 0; tries < max_tries; ++tries) {
-    for (size_t n = 0; n < num_xs; ++n)
-      start[n] = get_random_alnum();
-    struct _stat st = {};
-    int ret = _stat(name_template, &st);
-    if (ret < 0 && errno == ENOENT) {
-      errno = 0;
-      found_one = true;
-      break;
-    }
-  }
-  if (!found_one) {
-    // The Posix mkdtemp() specification does not specify which errno
-    // value to use in this case, neither does the Linux manpage, so
-    // just select EINVAL, which is what the Win32 _mktemp_s() returns
-    // on such failures (note: the Wine version returns EEXIST!).
-    errno = EINVAL;
-    perror("_mktemp_s");
-    return NULL;
-  }
-
-  int err = _mkdir(name_template);
-  if (err < 0) {
-    perror("mkdir");
-    return NULL;
-  }
-
-  return name_template;
-}
-#endif  // _WIN32
-
-/// Return system temporary directory. Result always has a trailing separator,
-/// except when empty.
-std::string GetSystemTempDir() {
-#ifdef _WIN32
-  std::string result;
-  result.resize(PATH_MAX);
-  DWORD ret = GetTempPath(result.size(), &result[0]);
-  result.resize(static_cast<size_t>(ret));
-  if (!result.empty()) {
-    if (result.back() != '/' && result.back() != '\\')
-      result.push_back('\\');
-  }
-  return result;
-#else
-  std::string result = "/tmp/";
-  const char* tempdir = getenv("TMPDIR");
-  if (tempdir) {
-    result = tempdir;
-    if (!result.empty() && result.back() != '/')
-      result.push_back('/');
-  }
-  return result;
-#endif
-}
-
-}  // anonymous namespace
-
-
-::testing::AsString<void*, void>::AsString(const void* ptr) {
-  char temp[32];
-  ::snprintf(temp, sizeof(temp), "%p", ptr);
-  str_ = temp;
-}
-
-StateTestWithBuiltinRules::StateTestWithBuiltinRules() {
-  AddCatRule(&state_);
-}
-
-void StateTestWithBuiltinRules::AddCatRule(State* state) {
-  AssertParse(state,
-"rule cat\n"
-"  command = cat $in > $out\n");
-}
-
-Node* StateTestWithBuiltinRules::GetNode(const string& path) {
-  EXPECT_FALSE(strpbrk(path.c_str(), "/\\"));
-  return state_.GetNode(path, 0);
-}
-
-void AssertParse(State* state, const char* input,
-                 ManifestParserOptions opts) {
-  ManifestParser parser(state, NULL, opts);
-  string err;
-  EXPECT_TRUE(parser.ParseTest(input, &err));
-  ASSERT_EQ("", err);
-  VerifyGraph(*state);
-}
-
-void AssertHash(const char* expected, uint64_t actual) {
-  ASSERT_EQ(BuildLog::LogEntry::HashCommand(expected), actual);
-}
-
-void VerifyGraph(const State& state) {
-  for (vector<Edge*>::const_iterator e = state.edges_.begin();
-       e != state.edges_.end(); ++e) {
-    // All edges need at least one output.
-    EXPECT_FALSE((*e)->outputs_.empty());
-    // Check that the edge's inputs have the edge as out-edge.
-    for (vector<Node*>::const_iterator in_node = (*e)->inputs_.begin();
-         in_node != (*e)->inputs_.end(); ++in_node) {
-      const vector<Edge*>& out_edges = (*in_node)->out_edges();
-      EXPECT_NE(find(out_edges.begin(), out_edges.end(), *e),
-                out_edges.end());
-    }
-    // Check that the edge's outputs have the edge as in-edge.
-    for (vector<Node*>::const_iterator out_node = (*e)->outputs_.begin();
-         out_node != (*e)->outputs_.end(); ++out_node) {
-      EXPECT_EQ((*out_node)->in_edge(), *e);
-    }
-  }
-
-  // The union of all in- and out-edges of each nodes should be exactly edges_.
-  set<const Edge*> node_edge_set;
-  for (State::Paths::const_iterator p = state.paths_.begin();
-       p != state.paths_.end(); ++p) {
-    const Node* n = p->second;
-    if (n->in_edge())
-      node_edge_set.insert(n->in_edge());
-    node_edge_set.insert(n->out_edges().begin(), n->out_edges().end());
-  }
-  set<const Edge*> edge_set(state.edges_.begin(), state.edges_.end());
-  EXPECT_EQ(node_edge_set, edge_set);
-}
-
-void VirtualFileSystem::Create(const string& path,
-                               const string& contents) {
-  files_[path].mtime = now_;
-  files_[path].contents = contents;
-  files_created_.insert(path);
-}
-
-TimeStamp VirtualFileSystem::Stat(const string& path, string* err) const {
-  FileMap::const_iterator i = files_.find(path);
-  if (i != files_.end()) {
-    *err = i->second.stat_error;
-    return i->second.mtime;
-  }
-  return 0;
-}
-
-bool VirtualFileSystem::WriteFile(const string& path, const string& contents) {
-  Create(path, contents);
-  return true;
-}
-
-bool VirtualFileSystem::MakeDir(const string& path) {
-  directories_made_.push_back(path);
-  return true;  // success
-}
-
-FileReader::Status VirtualFileSystem::ReadFile(const string& path,
-                                               string* contents,
-                                               string* err) {
-  files_read_.push_back(path);
-  FileMap::iterator i = files_.find(path);
-  if (i != files_.end()) {
-    *contents = i->second.contents;
-    return Okay;
-  }
-  *err = strerror(ENOENT);
-  return NotFound;
-}
-
-int VirtualFileSystem::RemoveFile(const string& path) {
-  if (find(directories_made_.begin(), directories_made_.end(), path)
-      != directories_made_.end())
-    return -1;
-  FileMap::iterator i = files_.find(path);
-  if (i != files_.end()) {
-    files_.erase(i);
-    files_removed_.insert(path);
-    return 0;
-  } else {
-    return 1;
-  }
-}
-
-ScopedTempDir::ScopedTempDir() : original_dir_(GetCurrentDir()) {}
-
-ScopedTempDir::~ScopedTempDir() {
-  Cleanup();
-}
-
-void ScopedTempDir::CreateAndEnter(const string& name) {
-  temp_dir_name_ = GetSystemTempDir();
-  if (temp_dir_name_.empty())
-    Fatal("couldn't get system temp dir");
-
-  // Create a temporary subdirectory of that.
-  temp_dir_name_ += name;
-  temp_dir_name_ += "-XXXXXX";
-  char* tempname = mkdtemp(&temp_dir_name_[0]);
-  if (!tempname)
-    ErrnoFatal("mkdtemp");
-
-  // chdir into the new temporary directory.
-  if (chdir(temp_dir_name_.c_str()) < 0)
-    ErrnoFatal("chdir");
-}
-
-void ScopedTempDir::Cleanup() {
-  if (temp_dir_name_.empty())
-    return;  // Something went wrong earlier or already cleaned.
-
-  // Move out of the directory we're about to clobber.
-  if (chdir(original_dir_.c_str()) < 0)
-    ErrnoFatal("chdir");
-
-#ifdef _WIN32
-  string command = "rmdir /s /q " + temp_dir_name_;
-#else
-  string command = "rm -rf " + temp_dir_name_;
-#endif
-  if (system(command.c_str()) < 0)
-    ErrnoFatal("system");
-
-  temp_dir_name_.clear();
-}
diff --git a/src/test.h b/src/test.h
deleted file mode 100644
index b03d902..0000000
--- a/src/test.h
+++ /dev/null
@@ -1,384 +0,0 @@
-// 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.
-
-#ifndef NINJA_TEST_H_
-#define NINJA_TEST_H_
-
-#include <stddef.h>
-
-#include "disk_interface.h"
-#include "manifest_parser.h"
-#include "state.h"
-#include "util.h"
-
-// A tiny testing framework inspired by googletest, but much simpler and
-// faster to compile. It supports most things commonly used from googltest. The
-// most noticeable things missing: EXPECT_* and ASSERT_* don't support
-// streaming notes to them with operator<<, and for failing tests the lhs and
-// rhs are not printed. That's so that this header does not have to include
-// sstream, which slows down building ninja_test almost 20%.
-namespace testing {
-class Test {
-  bool failed_;
-  int assertion_failures_;
- public:
-  Test() : failed_(false), assertion_failures_(0) {}
-  virtual ~Test() {}
-  virtual void SetUp() {}
-  virtual void TearDown() {}
-  virtual void Run() = 0;
-
-  bool Failed() const { return failed_; }
-  int AssertionFailures() const { return assertion_failures_; }
-  void AddAssertionFailure() { assertion_failures_++; }
-  bool NullFailure(bool expected, const char* file, int line, const char* error,
-                   const char* value);
-  bool BooleanFailure(bool expected, const char* file, int line,
-                      const char* error, const char* value);
-  bool BinopFailure(const char* file, int line, const char* error, const char* first_value, const char* second_value);
-};
-
-/// std::void_t<T> is only available since C++17, so use
-/// ::testing::Void<T>::type for the same thing. Used by AsString<> below.
-template <class ...>
-struct Void {
-  using type = void;
-};
-
-/// Expand to a type expression that is only valid if |expression| compiles
-/// properly. Only useful for C++ SFINAE.
-#define TESTING_ENABLE_IF_EXPRESSION_COMPILES(expression) \
-  typename ::testing::Void<decltype(expression)>::type
-
-/// Expand to a type expression that is only valid if type T provides
-/// an AsString() method. Note: for simplicity, there is no check that
-/// the result is convertible into an std::string here.
-#define TESTING_ENABLE_IF_METHOD_AS_STRING_EXISTS_FOR_TYPE(T) \
-  TESTING_ENABLE_IF_EXPRESSION_COMPILES(std::declval<T>().AsString())
-
-/// Expand to a type expression that is only valid if type T is supported
-/// as an std::to_string() argument type.
-#define TESTING_ENABLE_IF_STD_TO_STRING_SUPPORTS_TYPE(T) \
-  TESTING_ENABLE_IF_EXPRESSION_COMPILES(std::to_string(std::declval<T>()))
-
-/// RemoveCVRef<T> remove references as well as const and volatile modifier.
-/// Used by AsString<> below.
-template <typename T>
-struct RemoveCVRef {
-  using type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
-};
-
-/// Expand to the base type of expression value |v|, which means without
-/// any reference, const or volatile qualifier. This can be used as a
-/// type argument when defining template specializations.
-#define TESTING_BASE_TYPE_FOR_VALUE(v) \
-  typename ::testing::RemoveCVRef<decltype(v)>::type
-
-/// ConstRefT<T>::type is a const reference type that binds to a value of type
-/// T.
-template <typename T>
-struct ConstRefT {
-  using type = const typename std::remove_const<
-      typename std::remove_reference<T>::type>::type&;
-};
-
-#define TESTING_CONST_REF_TYPE_FOR_VALUE(v) \
-  typename ::testing::ConstRefT<decltype(v)>::type
-
-/// ::testing::AsString<T> is a helper struct used to convert expression
-/// in EXPECT_XXX and ASSERT_XXX macros into the string representation of
-/// their value. This uses C++11 template metadata magic which can be easily
-/// confusing, so as a short technical note:
-///
-/// - An AsString<T> value is an object that provides a `c_str()` method that
-///   will be used to print it in case of test failure.
-///
-/// - By default, AsString<T>::c_str() will return `"<UNPRINTABLE>"`. This
-///   would happen when T is an std::pair<> or something more complex.
-///
-/// - If type T has an AsString() method, it will be used automatically
-///   to retrieve a printable version of the value. E.g. StringPiece!
-///
-/// - If type T is supported by std::to_string(), the latter is used
-///   automatically as well (so all integral and floating point values).
-///
-/// - AsString<T*>::c_str() will return an hexadecimal address (just like %p)
-///
-
-/// The generic / fallback version.
-template <typename T, typename Enable = void>
-struct AsString {
-  AsString(const T& value) {}
-  const char* c_str() const { return "<UNPRINTABLE>"; }
-};
-
-/// Print booleans as either "true" or "false".
-template <>
-struct AsString<bool, void> {
-  AsString(bool value) : value_(value) {}
-  const char* c_str() const { return value_ ? "true" : "false"; }
-  bool value_;
-};
-
-/// Print pointers with %p by default. See implementation in ninja_test.cc
-template <>
-struct AsString<void*, void> {
-  AsString(const void* ptr);
-  const char* c_str() const { return str_.c_str(); }
-  std::string str_;
-};
-
-template <typename T>
-struct AsString<T*, void> : public AsString<void*, void> {
-  AsString(const T* ptr) : AsString<void*, void>(ptr) {}
-};
-
-/// Anything supported by std::to_string() is supported implicitly too.
-template <typename T>
-struct AsString<T, TESTING_ENABLE_IF_STD_TO_STRING_SUPPORTS_TYPE(T)> {
-  AsString(const T value) : str_(std::to_string(value)) {}
-  const char* c_str() const { return str_.c_str(); }
-  std::string str_;
-};
-
-/// Anything that has an AsString() method is supported implicitly too.
-/// For example, StringPiece!
-template <typename T>
-struct AsString<T, TESTING_ENABLE_IF_METHOD_AS_STRING_EXISTS_FOR_TYPE(T)> {
-  AsString(const T& value) : str_(value.AsString()) {}
-  const char* c_str() const { return str_.c_str(); }
-  std::string str_;
-};
-
-/// Support for std::string, avoids a copy.
-template <>
-struct AsString<std::string> {
-  AsString(const std::string& value) : str_(value) {}
-  const char* c_str() const { return str_.c_str(); }
-  const std::string& str_;
-};
-
-/// Support for literal C strings.
-template <size_t N>
-struct AsString<char [N], void> {
-  AsString(const char* value) : value_(value) {}
-  const char* c_str() const { return value_; }
-  const char* value_;
-};
-
-/// Support for C string pointers.
-template <>
-struct AsString<const char*> {
-  AsString(const char* value) : value_(value) {}
-  const char* c_str() const { return value_; }
-  const char* value_;
-};
-
-template <>
-struct AsString<char*> : public AsString<const char*> {
-  AsString(const char* value) : AsString<const char*>(value) {}
-};
-
-}
-
-void RegisterTest(testing::Test* (*)(), const char*);
-
-extern testing::Test* g_current_test;
-#define TEST_F_(x, y, name)                                           \
-  struct y : public x {                                               \
-    static testing::Test* Create() { return g_current_test = new y; } \
-    virtual void Run();                                               \
-  };                                                                  \
-  struct Register##y {                                                \
-    Register##y() { RegisterTest(y::Create, name); }                  \
-  };                                                                  \
-  Register##y g_register_##y;                                         \
-  void y::Run()
-
-#define TEST_F(x, y) TEST_F_(x, x##y, #x "." #y)
-#define TEST(x, y) TEST_F_(testing::Test, x##y, #x "." #y)
-
-/// Generic EXPECT macro for binary operations. The use of a lambda here
-/// is necessary to ensure that the expressions in (a) and (b) are only
-/// evaluated once at runtime in case of failure.
-#define EXPECT_BINARY_OP(a, b, op)                                             \
-  ([](TESTING_CONST_REF_TYPE_FOR_VALUE(a) va,                                  \
-      TESTING_CONST_REF_TYPE_FOR_VALUE(b) vb) -> bool {                        \
-    return ((va op vb)                                                         \
-                ? true                                                         \
-                : g_current_test->BinopFailure(                                \
-                      __FILE__, __LINE__, #a " " #op " " #b,                   \
-                      ::testing::AsString<TESTING_BASE_TYPE_FOR_VALUE(va)>(va) \
-                          .c_str(),                                            \
-                      ::testing::AsString<TESTING_BASE_TYPE_FOR_VALUE(vb)>(vb) \
-                          .c_str()));                                          \
-  }(a, b))
-
-#define EXPECT_EQ(a, b) EXPECT_BINARY_OP(a, b, ==)
-#define EXPECT_NE(a, b) EXPECT_BINARY_OP(a, b, !=)
-#define EXPECT_GT(a, b) EXPECT_BINARY_OP(a, b, >)
-#define EXPECT_LT(a, b) EXPECT_BINARY_OP(a, b, <)
-#define EXPECT_GE(a, b) EXPECT_BINARY_OP(a, b, >=)
-#define EXPECT_LE(a, b) EXPECT_BINARY_OP(a, b, <=)
-
-/// Generic EXPECT macro for boolean comparisons.
-#define EXPECT_BOOLEAN_OP(a, expected)                                        \
-  ([](TESTING_CONST_REF_TYPE_FOR_VALUE(a) va) -> bool {                       \
-    return (static_cast<bool>(va) == expected)                                \
-               ? true                                                         \
-               : g_current_test->BooleanFailure(                              \
-                     expected, __FILE__, __LINE__, #a,                        \
-                     ::testing::AsString<TESTING_BASE_TYPE_FOR_VALUE(va)>(va) \
-                         .c_str());                                           \
-  }(a))
-
-#define EXPECT_TRUE(a) EXPECT_BOOLEAN_OP(a, true)
-#define EXPECT_FALSE(a) EXPECT_BOOLEAN_OP(a, false)
-
-/// Generic EXPECT macro for pointer nullptr comparisons.
-/// Note that boolean comparisons should work too, but the message in case
-/// of failure is slightly clearer when using this macro.
-#define EXPECT_NULL_OP(a, expected)                                           \
-  ([](TESTING_CONST_REF_TYPE_FOR_VALUE(a) va) -> bool {                       \
-    return (expected == ((va) == nullptr))                                    \
-               ? true                                                         \
-               : g_current_test->NullFailure(                                 \
-                     expected, __FILE__, __LINE__, #a,                        \
-                     ::testing::AsString<TESTING_BASE_TYPE_FOR_VALUE(va)>(va) \
-                         .c_str());                                           \
-  }(a))
-
-#define EXPECT_NULL(a) EXPECT_NULL_OP(a, true)
-#define EXPECT_NOT_NULL(a) EXPECT_NULL_OP(a, false)
-
-#define ASSERT_EQ(a, b) \
-  if (!EXPECT_EQ(a, b)) { g_current_test->AddAssertionFailure(); return; }
-#define ASSERT_NE(a, b) \
-  if (!EXPECT_NE(a, b)) { g_current_test->AddAssertionFailure(); return; }
-#define ASSERT_GT(a, b) \
-  if (!EXPECT_GT(a, b)) { g_current_test->AddAssertionFailure(); return; }
-#define ASSERT_LT(a, b) \
-  if (!EXPECT_LT(a, b)) { g_current_test->AddAssertionFailure(); return; }
-#define ASSERT_GE(a, b) \
-  if (!EXPECT_GE(a, b)) { g_current_test->AddAssertionFailure(); return; }
-#define ASSERT_LE(a, b) \
-  if (!EXPECT_LE(a, b)) { g_current_test->AddAssertionFailure(); return; }
-#define ASSERT_TRUE(a)  \
-  if (!EXPECT_TRUE(a))  { g_current_test->AddAssertionFailure(); return; }
-#define ASSERT_FALSE(a) \
-  if (!EXPECT_FALSE(a)) { g_current_test->AddAssertionFailure(); return; }
-#define ASSERT_NULL(a)                     \
-  if (!EXPECT_NULL(a)) {                   \
-    g_current_test->AddAssertionFailure(); \
-    return;                                \
-  }
-#define ASSERT_NOT_NULL(a)                 \
-  if (!EXPECT_NOT_NULL(a)) {               \
-    g_current_test->AddAssertionFailure(); \
-    return;                                \
-  }
-#define ASSERT_NO_FATAL_FAILURE(a)                           \
-  {                                                          \
-    int fail_count = g_current_test->AssertionFailures();    \
-    a;                                                       \
-    if (fail_count != g_current_test->AssertionFailures()) { \
-      g_current_test->AddAssertionFailure();                 \
-      return;                                                \
-    }                                                        \
-  }
-
-// Support utilities for tests.
-
-struct Node;
-
-/// A base test fixture that includes a State object with a
-/// builtin "cat" rule.
-struct StateTestWithBuiltinRules : public testing::Test {
-  StateTestWithBuiltinRules();
-
-  /// Add a "cat" rule to \a state.  Used by some tests; it's
-  /// otherwise done by the ctor to state_.
-  void AddCatRule(State* state);
-
-  /// Short way to get a Node by its path from state_.
-  Node* GetNode(const std::string& path);
-
-  State state_;
-};
-
-void AssertParse(State* state, const char* input,
-                 ManifestParserOptions = ManifestParserOptions());
-void AssertHash(const char* expected, uint64_t actual);
-void VerifyGraph(const State& state);
-
-/// An implementation of DiskInterface that uses an in-memory representation
-/// of disk state.  It also logs file accesses and directory creations
-/// so it can be used by tests to verify disk access patterns.
-struct VirtualFileSystem : public DiskInterface {
-  VirtualFileSystem() : now_(1) {}
-
-  /// "Create" a file with contents.
-  void Create(const std::string& path, const std::string& contents);
-
-  /// Tick "time" forwards; subsequent file operations will be newer than
-  /// previous ones.
-  int Tick() {
-    return ++now_;
-  }
-
-  // DiskInterface
-  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;
-    std::string stat_error;  // If mtime is -1.
-    std::string contents;
-  };
-
-  std::vector<std::string> directories_made_;
-  std::vector<std::string> files_read_;
-  typedef std::map<std::string, Entry> FileMap;
-  FileMap files_;
-  std::set<std::string> files_removed_;
-  std::set<std::string> files_created_;
-
-  /// A simple fake timestamp for file operations.
-  int now_;
-};
-
-struct ScopedTempDir {
-  ScopedTempDir();
-
-  ~ScopedTempDir();
-
-  /// Create a temporary directory and chdir into it.
-  void CreateAndEnter(const std::string& name);
-
-  /// Clean up the temporary directory.
-  void Cleanup();
-
-  /// The current directory when creating this instance.
-  std::string original_dir_;
-
-  /// The subdirectory name for our dir, or empty if it hasn't been set up.
-  std::string temp_dir_name_;
-};
-
-#endif // NINJA_TEST_H_
diff --git a/src/timestamp.h b/src/timestamp.h
deleted file mode 100644
index 6a7ccd0..0000000
--- a/src/timestamp.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.
-
-#ifndef NINJA_TIMESTAMP_H_
-#define NINJA_TIMESTAMP_H_
-
-#ifdef _WIN32
-#include "win32port.h"
-#else
-#ifndef __STDC_FORMAT_MACROS
-#define __STDC_FORMAT_MACROS
-#endif
-#include <inttypes.h>
-#endif
-
-// When considering file modification times we only care to compare
-// them against one another -- we never convert them to an absolute
-// real time.  On POSIX we use timespec (seconds&nanoseconds since epoch)
-// and on Windows we use a different value.  Both fit in an int64.
-typedef int64_t TimeStamp;
-
-#endif  // NINJA_TIMESTAMP_H_
diff --git a/src/util.cc b/src/util.cc
deleted file mode 100644
index 5b5fbf9..0000000
--- a/src/util.cc
+++ /dev/null
@@ -1,1176 +0,0 @@
-// 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.
-
-#include "util.h"
-
-#ifdef __CYGWIN__
-#include <windows.h>
-#include <io.h>
-#elif defined(_WIN32)
-#include <windows.h>
-#include <direct.h>
-#include <io.h>
-#include <share.h>
-#endif
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#ifndef _WIN32
-#include <unistd.h>
-#include <sys/time.h>
-#endif
-
-#include <vector>
-
-#if defined(__APPLE__)
-#include <mach-o/dyld.h>
-#include <sys/sysctl.h>
-#elif defined(__FreeBSD__)
-#include <sys/sysctl.h>
-#elif defined(__SVR4) && defined(__sun)
-#include <unistd.h>
-#include <sys/loadavg.h>
-#elif defined(_AIX) && !defined(__PASE__)
-#include <libperfstat.h>
-#elif defined(linux) || defined(__GLIBC__)
-#include <sys/sysinfo.h>
-#include <fstream>
-#include <map>
-#include "string_piece_util.h"
-#endif
-
-#if defined(__FreeBSD__)
-#include <sys/cpuset.h>
-#endif
-
-#include "edit_distance.h"
-
-using namespace std;
-
-void Fatal(const char* msg, ...) {
-  va_list ap;
-  fprintf(stderr, "ninja: fatal: ");
-  va_start(ap, msg);
-  vfprintf(stderr, msg, ap);
-  va_end(ap);
-  fprintf(stderr, "\n");
-#ifdef _WIN32
-  // On Windows, some tools may inject extra threads.
-  // exit() may block on locks held by those threads, so forcibly exit.
-  fflush(stderr);
-  fflush(stdout);
-  ExitProcess(1);
-#else
-  exit(1);
-#endif
-}
-
-void Warning(const char* msg, va_list ap) {
-  fprintf(stderr, "ninja: warning: ");
-  vfprintf(stderr, msg, ap);
-  fprintf(stderr, "\n");
-}
-
-void Warning(const char* msg, ...) {
-  va_list ap;
-  va_start(ap, msg);
-  Warning(msg, ap);
-  va_end(ap);
-}
-
-void Error(const char* msg, va_list ap) {
-  fprintf(stderr, "ninja: error: ");
-  vfprintf(stderr, msg, ap);
-  fprintf(stderr, "\n");
-}
-
-void Error(const char* msg, ...) {
-  va_list ap;
-  va_start(ap, msg);
-  Error(msg, ap);
-  va_end(ap);
-}
-
-void Info(const char* msg, va_list ap) {
-  fprintf(stdout, "ninja: ");
-  vfprintf(stdout, msg, ap);
-  fprintf(stdout, "\n");
-}
-
-void Info(const char* msg, ...) {
-  va_list ap;
-  va_start(ap, msg);
-  Info(msg, ap);
-  va_end(ap);
-}
-
-std::string StringFormat(const char* fmt, ...) {
-  va_list ap;
-  va_start(ap, fmt);
-  std::string result;
-  StringAppendFormat(result, fmt, ap);
-  va_end(ap);
-  return result;
-}
-
-std::string StringFormat(const char* fmt, va_list ap) {
-  std::string result;
-  StringAppendFormat(result, fmt, ap);
-  return result;
-}
-
-void StringAppendFormat(std::string& str, const char* fmt, ...) {
-  va_list ap;
-  va_start(ap, fmt);
-  StringAppendFormat(str, fmt, ap);
-  va_end(ap);
-}
-
-void StringAppendFormat(std::string& str, const char* fmt, va_list ap) {
-  // First try with a small buffer that should cover most cases without
-  // heap allocations.
-  char buf[32];
-  va_list ap2;
-  va_copy(ap2, ap);
-  int ret = vsnprintf(buf, sizeof(buf), fmt, ap2);
-  va_end(ap2);
-  if (ret >= 0 && static_cast<size_t>(ret) < sizeof(buf)) {
-    str.append(buf, static_cast<size_t>(ret));
-    return;
-  }
-
-  // This did not work, so try with larger buffers in the string itself.
-  size_t org_size = str.size();
-  str.resize(org_size + 128);
-  const int max_retries = 10;
-  for (int retries = 0; retries < max_retries; ++retries) {
-    size_t available = str.size() - org_size + 1;
-    va_copy(ap2, ap);
-    int ret = vsnprintf(&str[org_size], available, fmt, ap2);
-    va_end(ap2);
-
-    if (ret >= 0 && static_cast<size_t>(ret) < available) {
-      // Success, shrink to correct size then return.
-      str.resize(org_size + static_cast<size_t>(ret));
-      return;
-    }
-
-    if (ret < 0) {
-      // Some versions of the MS runtime returned -1 in case of truncation!
-      // For these, simply double the buffer size and retry.
-      str.resize(org_size + available * 2);
-    } else {
-      // Ensure correct size for second try.
-      str.resize(org_size + static_cast<size_t>(ret));
-    }
-  }
-  Fatal("Could not format string!");
-}
-
-#ifdef _WIN32
-std::wstring ConvertToUnicodeString(const char* str, size_t size) {
-  std::wstring result;
-  if (size > 0) {
-    int int_size = static_cast<int>(size);
-    if (static_cast<size_t>(int_size) != size)
-      Fatal("Input UTF-8 string is far too long!");
-
-    int wide_size = MultiByteToWideChar(CP_UTF8, 0, str, int_size, nullptr, 0);
-    if (wide_size <= 0)
-      Win32Fatal("MultiByteToWideChar");
-
-    result.resize(static_cast<size_t>(wide_size));
-    MultiByteToWideChar(CP_UTF8, 0, str, int_size, &result[0], wide_size);
-  }
-  return result;
-}
-
-std::wstring ConvertToUnicodeString(const std::string& str) {
-  return ConvertToUnicodeString(str.c_str(), str.size());
-}
-
-std::string ConvertFromUnicodeString(const wchar_t* str, size_t size) {
-  std::string result;
-  if (size > 0) {
-    int int_size = static_cast<int>(size);
-    if (int_size != size)
-      Fatal("Input Unicode string is far too long!");
-
-    int utf8_size =
-        WideCharToMultiByte(CP_UTF8, 0, str, int_size, NULL, 0, NULL, NULL);
-    if (utf8_size <= 0)
-      Win32Fatal("WideCharToMultiByte");
-
-    result.resize(static_cast<size_t>(utf8_size));
-    WideCharToMultiByte(CP_UTF8, 0, str, int_size, &result[0], utf8_size, NULL,
-                        NULL);
-  }
-  return result;
-}
-
-std::string ConvertFromUnicodeString(const std::wstring& str) {
-  return ConvertFromUnicodeString(str.c_str(), str.size());
-}
-
-#endif  // _WIN32
-
-void CanonicalizePath(string* path, uint64_t* slash_bits) {
-  size_t len = path->size();
-  char* str = 0;
-  if (len > 0)
-    str = &(*path)[0];
-  CanonicalizePath(str, &len, slash_bits);
-  path->resize(len);
-}
-
-static bool IsPathSeparator(char c) {
-#ifdef _WIN32
-  return c == '/' || c == '\\';
-#else
-  return c == '/';
-#endif
-}
-
-void CanonicalizePath(char* path, size_t* len, uint64_t* slash_bits) {
-  // WARNING: this function is performance-critical; please benchmark
-  // any changes you make to it.
-  if (*len == 0) {
-    return;
-  }
-
-  const int kMaxPathComponents = 60;
-  char* components[kMaxPathComponents];
-  int component_count = 0;
-
-  char* start = path;
-  char* dst = start;
-  const char* src = start;
-  const char* end = start + *len;
-
-  if (IsPathSeparator(*src)) {
-#ifdef _WIN32
-
-    // network path starts with //
-    if (*len > 1 && IsPathSeparator(*(src + 1))) {
-      src += 2;
-      dst += 2;
-    } else {
-      ++src;
-      ++dst;
-    }
-#else
-    ++src;
-    ++dst;
-#endif
-  }
-
-  while (src < end) {
-    if (*src == '.') {
-      if (src + 1 == end || IsPathSeparator(src[1])) {
-        // '.' component; eliminate.
-        src += 2;
-        continue;
-      } else if (src[1] == '.' && (src + 2 == end || IsPathSeparator(src[2]))) {
-        // '..' component.  Back up if possible.
-        if (component_count > 0) {
-          dst = components[component_count - 1];
-          src += 3;
-          --component_count;
-        } else {
-          *dst++ = *src++;
-          *dst++ = *src++;
-          *dst++ = *src++;
-        }
-        continue;
-      }
-    }
-
-    if (IsPathSeparator(*src)) {
-      src++;
-      continue;
-    }
-
-    if (component_count == kMaxPathComponents)
-      Fatal("path has too many components : %s", path);
-    components[component_count] = dst;
-    ++component_count;
-
-    while (src != end && !IsPathSeparator(*src))
-      *dst++ = *src++;
-    *dst++ = *src++;  // Copy '/' or final \0 character as well.
-  }
-
-  if (dst == start) {
-    *dst++ = '.';
-    *dst++ = '\0';
-  }
-
-  *len = dst - start - 1;
-#ifdef _WIN32
-  uint64_t bits = 0;
-  uint64_t bits_mask = 1;
-
-  for (char* c = start; c < start + *len; ++c) {
-    switch (*c) {
-      case '\\':
-        bits |= bits_mask;
-        *c = '/';
-        NINJA_FALLTHROUGH;
-      case '/':
-        bits_mask <<= 1;
-    }
-  }
-
-  *slash_bits = bits;
-#else
-  *slash_bits = 0;
-#endif
-}
-
-static inline bool IsKnownShellSafeCharacter(char ch) {
-  if ('A' <= ch && ch <= 'Z') return true;
-  if ('a' <= ch && ch <= 'z') return true;
-  if ('0' <= ch && ch <= '9') return true;
-
-  switch (ch) {
-    case '_':
-    case '+':
-    case '-':
-    case '.':
-    case '/':
-      return true;
-    default:
-      return false;
-  }
-}
-
-static inline bool IsKnownWin32SafeCharacter(char ch) {
-  switch (ch) {
-    case ' ':
-    case '"':
-      return false;
-    default:
-      return true;
-  }
-}
-
-static inline bool StringNeedsShellEscaping(const string& input) {
-  for (size_t i = 0; i < input.size(); ++i) {
-    if (!IsKnownShellSafeCharacter(input[i])) return true;
-  }
-  return false;
-}
-
-static inline bool StringNeedsWin32Escaping(const string& input) {
-  for (size_t i = 0; i < input.size(); ++i) {
-    if (!IsKnownWin32SafeCharacter(input[i])) return true;
-  }
-  return false;
-}
-
-void GetShellEscapedString(const string& input, string* result) {
-  assert(result);
-
-  if (!StringNeedsShellEscaping(input)) {
-    result->append(input);
-    return;
-  }
-
-  const char kQuote = '\'';
-  const char kEscapeSequence[] = "'\\'";
-
-  result->push_back(kQuote);
-
-  string::const_iterator span_begin = input.begin();
-  for (string::const_iterator it = input.begin(), end = input.end(); it != end;
-       ++it) {
-    if (*it == kQuote) {
-      result->append(span_begin, it);
-      result->append(kEscapeSequence);
-      span_begin = it;
-    }
-  }
-  result->append(span_begin, input.end());
-  result->push_back(kQuote);
-}
-
-
-void GetWin32EscapedString(const string& input, string* result) {
-  assert(result);
-  if (!StringNeedsWin32Escaping(input)) {
-    result->append(input);
-    return;
-  }
-
-  const char kQuote = '"';
-  const char kBackslash = '\\';
-
-  result->push_back(kQuote);
-  size_t consecutive_backslash_count = 0;
-  string::const_iterator span_begin = input.begin();
-  for (string::const_iterator it = input.begin(), end = input.end(); it != end;
-       ++it) {
-    switch (*it) {
-      case kBackslash:
-        ++consecutive_backslash_count;
-        break;
-      case kQuote:
-        result->append(span_begin, it);
-        result->append(consecutive_backslash_count + 1, kBackslash);
-        span_begin = it;
-        consecutive_backslash_count = 0;
-        break;
-      default:
-        consecutive_backslash_count = 0;
-        break;
-    }
-  }
-  result->append(span_begin, input.end());
-  result->append(consecutive_backslash_count, kBackslash);
-  result->push_back(kQuote);
-}
-
-int ReadFile(const string& path, string* contents, string* err) {
-#ifdef _WIN32
-  // This makes a ninja run on a set of 1500 manifest files about 4% faster
-  // than using the generic fopen code below.
-  err->clear();
-  HANDLE f = ::CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
-                           OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
-  if (f == INVALID_HANDLE_VALUE) {
-    err->assign(GetLastErrorString());
-    return -ENOENT;
-  }
-
-  for (;;) {
-    DWORD len;
-    char buf[64 << 10];
-    if (!::ReadFile(f, buf, sizeof(buf), &len, NULL)) {
-      err->assign(GetLastErrorString());
-      contents->clear();
-      ::CloseHandle(f);
-      return -EIO;
-    }
-    if (len == 0)
-      break;
-    contents->append(buf, len);
-  }
-  ::CloseHandle(f);
-  return 0;
-#else
-  FILE* f = fopen(path.c_str(), "rb");
-  if (!f) {
-    err->assign(strerror(errno));
-    return -errno;
-  }
-
-#ifdef __USE_LARGEFILE64
-  struct stat64 st;
-  if (fstat64(fileno(f), &st) < 0) {
-#else
-  struct stat st;
-  if (fstat(fileno(f), &st) < 0) {
-#endif
-    err->assign(strerror(errno));
-    fclose(f);
-    return -errno;
-  }
-
-  // +1 is for the resize in ManifestParser::Load
-  contents->reserve(st.st_size + 1);
-
-  char buf[64 << 10];
-  size_t len;
-  while (!feof(f) && (len = fread(buf, 1, sizeof(buf), f)) > 0) {
-    contents->append(buf, len);
-  }
-  if (ferror(f)) {
-    err->assign(strerror(errno));  // XXX errno?
-    contents->clear();
-    fclose(f);
-    return -errno;
-  }
-  fclose(f);
-  return 0;
-#endif
-}
-
-void SetCloseOnExec(int fd) {
-#ifndef _WIN32
-  int flags = fcntl(fd, F_GETFD);
-  if (flags < 0) {
-    perror("fcntl(F_GETFD)");
-  } else {
-    if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
-      perror("fcntl(F_SETFD)");
-  }
-#else
-  HANDLE hd = (HANDLE) _get_osfhandle(fd);
-  if (! SetHandleInformation(hd, HANDLE_FLAG_INHERIT, 0)) {
-    fprintf(stderr, "SetHandleInformation(): %s", GetLastErrorString().c_str());
-  }
-#endif  // ! _WIN32
-}
-
-
-const char* SpellcheckStringV(const string& text,
-                              const vector<const char*>& words) {
-  const bool kAllowReplacements = true;
-  const int kMaxValidEditDistance = 3;
-
-  int min_distance = kMaxValidEditDistance + 1;
-  const char* result = NULL;
-  for (vector<const char*>::const_iterator i = words.begin();
-       i != words.end(); ++i) {
-    int distance = EditDistance(*i, text, kAllowReplacements,
-                                kMaxValidEditDistance);
-    if (distance < min_distance) {
-      min_distance = distance;
-      result = *i;
-    }
-  }
-  return result;
-}
-
-const char* SpellcheckString(const char* text, ...) {
-  // Note: This takes a const char* instead of a string& because using
-  // va_start() with a reference parameter is undefined behavior.
-  va_list ap;
-  va_start(ap, text);
-  vector<const char*> words;
-  const char* word;
-  while ((word = va_arg(ap, const char*)))
-    words.push_back(word);
-  va_end(ap);
-  return SpellcheckStringV(text, words);
-}
-
-std::string GetCurrentDir() {
-  std::string result;
-  result.resize(128);
-  while (true) {
-    if (getcwd(&result[0], result.size()) != nullptr) {
-      result.resize(strlen(result.data()));
-      return result;
-    }
-    if (errno != ERANGE)
-      ErrnoFatal("Could not get current directory");
-
-    result.resize(result.size() * 2);
-  }
-}
-
-std::string GetCurrentExecutable() {
-  // See
-  // https://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
-#ifdef _WIN32
-  wchar_t filename_wide[MAX_PATH];
-  DWORD size_wide = GetModuleFileNameW(nullptr, filename_wide, MAX_PATH);
-  return ConvertFromUnicodeString(filename_wide, size_wide);
-#elif defined(__APPLE__)
-  uint32_t size = 0;
-  _NSGetExecutablePath(nullptr, &size);
-  std::string result;
-  result.resize(size);
-  // NOTE: std::string::data() is |char*| since C++17 but
-  // was |const char*| before that, so use an explicit const_cast<>
-  // below to compile in both modes.
-  _NSGetExecutablePath(const_cast<char*>(result.data()), &size);
-  return result;
-#elif defined(sun) || defined(__sun)  // Solaris
-  return std::string(getexename());
-#else                                 // Linux and BSDs
-  static const char kProbePath[] =
-#ifdef __linux__
-      "/proc/self/exe";
-#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
-      "/proc/curproc/file";
-#elif defined(__NetBSD__)
-      "/proc/curproc/exe";
-#else
-#error "Unknown system!"
-#endif
-  char dest_path[PATH_MAX] = {};
-  if (readlink(kProbePath, dest_path, PATH_MAX) < 0)
-    ErrnoFatal("readlink");
-  return std::string(dest_path);
-#endif
-}
-
-std::string GetCurrentExecutableDir() {
-  std::string program = GetCurrentExecutable();
-#ifdef _WIN32
-  char sep = '\\';
-#else
-  char sep = '/';
-#endif
-  size_t pos = program.rfind(sep);
-  if (pos == std::string::npos || pos == 0)
-    Fatal("Could not get path to current executable!");
-  return program.substr(0, pos);
-}
-#ifdef _WIN32
-std::string GetLastErrorString(unsigned err) {
-  char* msg_buf;
-  FormatMessageA(
-        FORMAT_MESSAGE_ALLOCATE_BUFFER |
-        FORMAT_MESSAGE_FROM_SYSTEM |
-        FORMAT_MESSAGE_IGNORE_INSERTS,
-        NULL,
-        err,
-        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-        (char*)&msg_buf,
-        0,
-        NULL);
-  std::string msg = msg_buf;
-  LocalFree(msg_buf);
-  return msg;
-}
-
-std::string GetLastErrorString() {
-  return GetLastErrorString(GetLastError());
-}
-
-void Win32Fatal(const char* function, const char* hint) {
-  Win32Fatal(function, GetLastError(), hint);
-}
-
-void Win32Fatal(const char* function, unsigned long error, const char* hint) {
-  if (hint) {
-    Fatal("%s: %s (%s)", function, GetLastErrorString(error).c_str(), hint);
-  } else {
-    Fatal("%s: %s", function, GetLastErrorString(error).c_str());
-  }
-}
-#endif  // _WIN32
-
-void ErrnoFatal(const char* function, const char* hint) {
-  ErrnoFatal(function, errno, hint);
-}
-
-void ErrnoFatal(const char* function, int errnum, const char* hint) {
-  if (hint) {
-    Fatal("%s: %s (%s)", function, strerror(errnum), hint);
-  } else {
-    Fatal("%s: %s", function, strerror(errnum));
-  }
-}
-
-bool islatinalpha(int c) {
-  // isalpha() is locale-dependent.
-  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
-}
-
-string StripAnsiEscapeCodes(const string& in) {
-  string stripped;
-  stripped.reserve(in.size());
-
-  for (size_t i = 0; i < in.size(); ++i) {
-    if (in[i] != '\33') {
-      // Not an escape code.
-      stripped.push_back(in[i]);
-      continue;
-    }
-
-    // Only strip CSIs for now.
-    if (i + 1 >= in.size()) break;
-    if (in[i + 1] != '[') continue;  // Not a CSI.
-    i += 2;
-
-    // Skip everything up to and including the next [a-zA-Z].
-    while (i < in.size() && !islatinalpha(in[i]))
-      ++i;
-  }
-  return stripped;
-}
-
-#if defined(linux) || defined(__GLIBC__)
-std::pair<int64_t, bool> readCount(const std::string& path) {
-  std::ifstream file(path.c_str());
-  if (!file.is_open())
-    return std::make_pair(0, false);
-  int64_t n = 0;
-  file >> n;
-  if (file.good())
-    return std::make_pair(n, true);
-  return std::make_pair(0, false);
-}
-
-struct MountPoint {
-  int mountId;
-  int parentId;
-  StringPiece deviceId;
-  StringPiece root;
-  StringPiece mountPoint;
-  vector<StringPiece> options;
-  vector<StringPiece> optionalFields;
-  StringPiece fsType;
-  StringPiece mountSource;
-  vector<StringPiece> superOptions;
-  bool parse(const string& line) {
-    vector<StringPiece> pieces = SplitStringPiece(line, ' ');
-    if (pieces.size() < 10)
-      return false;
-    size_t optionalStart = 0;
-    for (size_t i = 6; i < pieces.size(); i++) {
-      if (pieces[i] == "-") {
-        optionalStart = i + 1;
-        break;
-      }
-    }
-    if (optionalStart == 0)
-      return false;
-    if (optionalStart + 3 != pieces.size())
-      return false;
-    mountId = atoi(pieces[0].AsString().c_str());
-    parentId = atoi(pieces[1].AsString().c_str());
-    deviceId = pieces[2];
-    root = pieces[3];
-    mountPoint = pieces[4];
-    options = SplitStringPiece(pieces[5], ',');
-    optionalFields =
-        vector<StringPiece>(&pieces[6], &pieces[optionalStart - 1]);
-    fsType = pieces[optionalStart];
-    mountSource = pieces[optionalStart + 1];
-    superOptions = SplitStringPiece(pieces[optionalStart + 2], ',');
-    return true;
-  }
-  string translate(string& path) const {
-    // path must be sub dir of root
-    if (path.compare(0, root.len_, root.str_, root.len_) != 0) {
-      return string();
-    }
-    path.erase(0, root.len_);
-    if (path == ".." || (path.length() > 2 && path.compare(0, 3, "../") == 0)) {
-      return string();
-    }
-    return mountPoint.AsString() + "/" + path;
-  }
-};
-
-struct CGroupSubSys {
-  int id;
-  string name;
-  vector<string> subsystems;
-  bool parse(string& line) {
-    size_t first = line.find(':');
-    if (first == string::npos)
-      return false;
-    line[first] = '\0';
-    size_t second = line.find(':', first + 1);
-    if (second == string::npos)
-      return false;
-    line[second] = '\0';
-    id = atoi(line.c_str());
-    name = line.substr(second + 1);
-    vector<StringPiece> pieces =
-        SplitStringPiece(StringPiece(line.c_str() + first + 1), ',');
-    for (size_t i = 0; i < pieces.size(); i++) {
-      subsystems.push_back(pieces[i].AsString());
-    }
-    return true;
-  }
-};
-
-map<string, string> ParseMountInfo(map<string, CGroupSubSys>& subsystems) {
-  map<string, string> cgroups;
-  ifstream mountinfo("/proc/self/mountinfo");
-  if (!mountinfo.is_open())
-    return cgroups;
-  while (!mountinfo.eof()) {
-    string line;
-    getline(mountinfo, line);
-    MountPoint mp;
-    if (!mp.parse(line))
-      continue;
-    if (mp.fsType != "cgroup")
-      continue;
-    for (size_t i = 0; i < mp.superOptions.size(); i++) {
-      string opt = mp.superOptions[i].AsString();
-      map<string, CGroupSubSys>::iterator subsys = subsystems.find(opt);
-      if (subsys == subsystems.end())
-        continue;
-      string newPath = mp.translate(subsys->second.name);
-      if (!newPath.empty())
-        cgroups.insert(make_pair(opt, newPath));
-    }
-  }
-  return cgroups;
-}
-
-map<string, CGroupSubSys> ParseSelfCGroup() {
-  map<string, CGroupSubSys> cgroups;
-  ifstream cgroup("/proc/self/cgroup");
-  if (!cgroup.is_open())
-    return cgroups;
-  string line;
-  while (!cgroup.eof()) {
-    getline(cgroup, line);
-    CGroupSubSys subsys;
-    if (!subsys.parse(line))
-      continue;
-    for (size_t i = 0; i < subsys.subsystems.size(); i++) {
-      cgroups.insert(make_pair(subsys.subsystems[i], subsys));
-    }
-  }
-  return cgroups;
-}
-
-int ParseCPUFromCGroup() {
-  map<string, CGroupSubSys> subsystems = ParseSelfCGroup();
-  map<string, string> cgroups = ParseMountInfo(subsystems);
-  map<string, string>::iterator cpu = cgroups.find("cpu");
-  if (cpu == cgroups.end())
-    return -1;
-  std::pair<int64_t, bool> quota = readCount(cpu->second + "/cpu.cfs_quota_us");
-  if (!quota.second || quota.first == -1)
-    return -1;
-  std::pair<int64_t, bool> period =
-      readCount(cpu->second + "/cpu.cfs_period_us");
-  if (!period.second)
-    return -1;
-  if (period.first == 0)
-    return -1;
-  return quota.first / period.first;
-}
-#endif
-
-int GetProcessorCount() {
-#ifdef _WIN32
-  DWORD cpuCount = 0;
-#ifndef _WIN64
-  // Need to use GetLogicalProcessorInformationEx to get real core count on
-  // machines with >64 cores. See https://stackoverflow.com/a/31209344/21475
-  DWORD len = 0;
-  if (!GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &len)
-        && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
-    std::vector<char> buf(len);
-    int cores = 0;
-    if (GetLogicalProcessorInformationEx(RelationProcessorCore,
-          reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(
-            buf.data()), &len)) {
-      for (DWORD i = 0; i < len; ) {
-        auto info = reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(
-            buf.data() + i);
-        if (info->Relationship == RelationProcessorCore &&
-            info->Processor.GroupCount == 1) {
-          for (KAFFINITY core_mask = info->Processor.GroupMask[0].Mask;
-               core_mask; core_mask >>= 1) {
-            cores += (core_mask & 1);
-          }
-        }
-        i += info->Size;
-      }
-      if (cores != 0) {
-        cpuCount = cores;
-      }
-    }
-  }
-#endif
-  if (cpuCount == 0) {
-    cpuCount = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
-  }
-  JOBOBJECT_CPU_RATE_CONTROL_INFORMATION info;
-  // reference:
-  // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_cpu_rate_control_information
-  if (QueryInformationJobObject(NULL, JobObjectCpuRateControlInformation, &info,
-                                sizeof(info), NULL)) {
-    if (info.ControlFlags & (JOB_OBJECT_CPU_RATE_CONTROL_ENABLE |
-                             JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP)) {
-      return cpuCount * info.CpuRate / 10000;
-    }
-  }
-  return cpuCount;
-#else
-  int cgroupCount = -1;
-  int schedCount = -1;
-#if defined(linux) || defined(__GLIBC__)
-  cgroupCount = ParseCPUFromCGroup();
-#endif
-  // 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) {
-    schedCount = CPU_COUNT(&set);
-  }
-#endif
-  if (cgroupCount >= 0 && schedCount >= 0) return std::min(cgroupCount, schedCount);
-  if (cgroupCount < 0 && schedCount < 0) return sysconf(_SC_NPROCESSORS_ONLN);
-  return std::max(cgroupCount, schedCount);
-#endif
-}
-
-#if defined(_WIN32) || defined(__CYGWIN__)
-static double CalculateProcessorLoad(uint64_t idle_ticks, uint64_t total_ticks)
-{
-  static uint64_t previous_idle_ticks = 0;
-  static uint64_t previous_total_ticks = 0;
-  static double previous_load = -0.0;
-
-  uint64_t idle_ticks_since_last_time = idle_ticks - previous_idle_ticks;
-  uint64_t total_ticks_since_last_time = total_ticks - previous_total_ticks;
-
-  bool first_call = (previous_total_ticks == 0);
-  bool ticks_not_updated_since_last_call = (total_ticks_since_last_time == 0);
-
-  double load;
-  if (first_call || ticks_not_updated_since_last_call) {
-    load = previous_load;
-  } else {
-    // Calculate load.
-    double idle_to_total_ratio =
-        ((double)idle_ticks_since_last_time) / total_ticks_since_last_time;
-    double load_since_last_call = 1.0 - idle_to_total_ratio;
-
-    // Filter/smooth result when possible.
-    if(previous_load > 0) {
-      load = 0.9 * previous_load + 0.1 * load_since_last_call;
-    } else {
-      load = load_since_last_call;
-    }
-  }
-
-  previous_load = load;
-  previous_total_ticks = total_ticks;
-  previous_idle_ticks = idle_ticks;
-
-  return load;
-}
-
-static uint64_t FileTimeToTickCount(const FILETIME & ft)
-{
-  uint64_t high = (((uint64_t)(ft.dwHighDateTime)) << 32);
-  uint64_t low  = ft.dwLowDateTime;
-  return (high | low);
-}
-
-double GetLoadAverage() {
-  FILETIME idle_time, kernel_time, user_time;
-  BOOL get_system_time_succeeded =
-      GetSystemTimes(&idle_time, &kernel_time, &user_time);
-
-  double posix_compatible_load;
-  if (get_system_time_succeeded) {
-    uint64_t idle_ticks = FileTimeToTickCount(idle_time);
-
-    // kernel_time from GetSystemTimes already includes idle_time.
-    uint64_t total_ticks =
-        FileTimeToTickCount(kernel_time) + FileTimeToTickCount(user_time);
-
-    double processor_load = CalculateProcessorLoad(idle_ticks, total_ticks);
-    posix_compatible_load = processor_load * GetProcessorCount();
-
-  } else {
-    posix_compatible_load = -0.0;
-  }
-
-  return posix_compatible_load;
-}
-#elif defined(__PASE__)
-double GetLoadAverage() {
-  return -0.0f;
-}
-#elif defined(_AIX)
-double GetLoadAverage() {
-  perfstat_cpu_total_t cpu_stats;
-  if (perfstat_cpu_total(NULL, &cpu_stats, sizeof(cpu_stats), 1) < 0) {
-    return -0.0f;
-  }
-
-  // Calculation taken from comment in libperfstats.h
-  return double(cpu_stats.loadavg[0]) / double(1 << SBITS);
-}
-#elif defined(__UCLIBC__) || (defined(__BIONIC__) && __ANDROID_API__ < 29)
-double GetLoadAverage() {
-  struct sysinfo si;
-  if (sysinfo(&si) != 0)
-    return -0.0f;
-  return 1.0 / (1 << SI_LOAD_SHIFT) * si.loads[0];
-}
-#elif defined(__HAIKU__)
-double GetLoadAverage() {
-    return -0.0f;
-}
-#else
-double GetLoadAverage() {
-  double loadavg[3] = { 0.0f, 0.0f, 0.0f };
-  if (getloadavg(loadavg, 3) < 0) {
-    // Maybe we should return an error here or the availability of
-    // getloadavg(3) should be checked when ninja is configured.
-    return -0.0f;
-  }
-  return loadavg[0];
-}
-#endif // _WIN32
-
-string ElideMiddle(const string& str, size_t width) {
-  switch (width) {
-      case 0: return "";
-      case 1: return ".";
-      case 2: return "..";
-      case 3: return "...";
-  }
-  const int kMargin = 3;  // Space for "...".
-  string result = str;
-  if (result.size() > width) {
-    size_t elide_size = (width - kMargin) / 2;
-    result = result.substr(0, elide_size)
-      + "..."
-      + result.substr(result.size() - elide_size, elide_size);
-  }
-  return result;
-}
-
-bool Truncate(const string& path, size_t size, string* err) {
-#ifdef _WIN32
-  int fh = _sopen(path.c_str(), _O_RDWR | _O_CREAT, _SH_DENYNO,
-                  _S_IREAD | _S_IWRITE);
-  int success = _chsize(fh, size);
-  _close(fh);
-#else
-  int success = truncate(path.c_str(), size);
-#endif
-  // Both truncate() and _chsize() return 0 on success and set errno and return
-  // -1 on failure.
-  if (success < 0) {
-    *err = strerror(errno);
-    return false;
-  }
-  return true;
-}
-
-bool RunsUnderWine() {
-#ifdef _WIN32
-  auto probe_wine = []() -> bool {
-    HMODULE module = ::GetModuleHandle("ntdll.dll");
-    if (!module)
-      return false;
-    return ::GetProcAddress(module, "wine_get_version") != nullptr;
-  };
-  static bool runs_under_wine = probe_wine();
-  return runs_under_wine;
-#else
-  return false;
-#endif
-}
-
-#ifdef _WIN32
-int64_t TimeStampFromFileTime(const FILETIME& filetime) {
-  // FILETIME is in 100-nanosecond increments since the Windows epoch.
-  // We don't much care about epoch correctness but we do want the
-  // resulting value to fit in a 64-bit integer.
-  uint64_t mtime = ((uint64_t)filetime.dwHighDateTime << 32) |
-                   ((uint64_t)filetime.dwLowDateTime);
-  // 1600 epoch -> 2000 epoch (subtract 400 years).
-  return (int64_t)mtime - 12622770400LL * (1000000000LL / 100);
-}
-#endif  // _WIN32
-
-int64_t GetFileTimestamp(const std::string& path, std::string* error) {
-#ifdef _WIN32
-  WIN32_FILE_ATTRIBUTE_DATA attrs;
-  if (!GetFileAttributesExA(path.c_str(), GetFileExInfoStandard, &attrs)) {
-    DWORD win_err = GetLastError();
-    if (win_err == ERROR_FILE_NOT_FOUND || win_err == ERROR_PATH_NOT_FOUND)
-      return 0;
-
-    *error = StringFormat("GetFileAttributesExA(%s): %s", path.c_str(),
-                          GetLastErrorString(win_err).c_str());
-    return -1;
-  }
-  return TimeStampFromFileTime(attrs.ftLastWriteTime);
-#else  // !_WIN32
-#ifdef __USE_LARGEFILE64
-  struct stat64 st;
-  if (stat64(path.c_str(), &st) < 0) {
-#else
-  struct stat st;
-  if (stat(path.c_str(), &st) < 0) {
-#endif
-    if (errno == ENOENT || errno == ENOTDIR)
-      return 0;
-    *error = StringFormat("stat(%s): %s", path.c_str(), strerror(errno));
-    return -1;
-  }
-  // Some users (Flatpak) set mtime to 0, this should be harmless
-  // and avoids conflicting with our return value of 0 meaning
-  // that it doesn't exist.
-  if (st.st_mtime == 0)
-    return 1;
-#if defined(_AIX)
-  return (int64_t)st.st_mtime * 1000000000LL + st.st_mtime_n;
-#elif defined(__APPLE__)
-  return ((int64_t)st.st_mtimespec.tv_sec * 1000000000LL +
-          st.st_mtimespec.tv_nsec);
-#elif defined(st_mtime)  // A macro, so we're likely on modern POSIX.
-return (int64_t)st.st_mtim.tv_sec * 1000000000LL + st.st_mtim.tv_nsec;
-#else                    // !defined(st_mtime)
-return (int64_t)st.st_mtime * 1000000000LL + st.st_mtimensec;
-#endif                   // !defined(st_mtime)
-#endif                   // !_WIN32
-}
-
-void AppendStringFormatDurationMs(std::string& out, int64_t duration_ms) {
-  if (duration_ms < 0) {
-    out += '-';
-    duration_ms = -duration_ms;
-  }
-  if (duration_ms < 1000) {
-    StringAppendFormat(out, "%u ms", static_cast<unsigned>(duration_ms));
-  } else if (duration_ms < 10000) {
-    StringAppendFormat(out, "%u.%02u s",
-                       static_cast<unsigned>(duration_ms / 1000),
-                       static_cast<unsigned>((duration_ms % 1000) / 10));
-  } else if (duration_ms < 60000) {
-    StringAppendFormat(out, "%u.%01u s",
-                       static_cast<unsigned>(duration_ms / 1000),
-                       static_cast<unsigned>((duration_ms % 1000) / 100));
-  } else {
-    int64_t seconds = duration_ms / 1000;
-    if (seconds < 3600) {
-      StringAppendFormat(out, "%u:%02u min",
-                         static_cast<unsigned>(seconds / 60),
-                         static_cast<unsigned>(seconds % 60));
-    } else {
-      StringAppendFormat(out, "%u:%02u:%02u hr",
-                         static_cast<unsigned>(seconds / 3600),
-                         static_cast<unsigned>((seconds % 3600) / 60),
-                         static_cast<unsigned>(seconds % 60));
-    }
-  }
-}
-
-std::string StringFormatDurationMs(int64_t duration_ms) {
-  std::string result;
-  AppendStringFormatDurationMs(result, duration_ms);
-  return result;
-}
diff --git a/src/util.h b/src/util.h
deleted file mode 100644
index c260b76..0000000
--- a/src/util.h
+++ /dev/null
@@ -1,183 +0,0 @@
-// 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.
-
-#ifndef NINJA_UTIL_H_
-#define NINJA_UTIL_H_
-
-#ifdef _WIN32
-#include <windows.h>
-#undef ERROR
-#undef min
-#undef max
-#include "win32port.h"
-#else
-#include <stdint.h>
-#endif
-
-#include <stdarg.h>
-
-#include <string>
-#include <vector>
-
-#ifdef _MSC_VER
-#define NORETURN __declspec(noreturn)
-#else
-#define NORETURN __attribute__((noreturn))
-#endif
-
-/// Log a fatal message and exit.
-NORETURN void Fatal(const char* msg, ...);
-
-// Have a generic fall-through for different versions of C/C++.
-#if defined(__cplusplus) && __cplusplus >= 201703L
-#define NINJA_FALLTHROUGH [[fallthrough]]
-#elif defined(__cplusplus) && __cplusplus >= 201103L && defined(__clang__)
-#define NINJA_FALLTHROUGH [[clang::fallthrough]]
-#elif defined(__cplusplus) && __cplusplus >= 201103L && defined(__GNUC__) && \
-    __GNUC__ >= 7
-#define NINJA_FALLTHROUGH [[gnu::fallthrough]]
-#elif defined(__GNUC__) && __GNUC__ >= 7 // gcc 7
-#define NINJA_FALLTHROUGH __attribute__ ((fallthrough))
-#else // C++11 on gcc 6, and all other cases
-#define NINJA_FALLTHROUGH
-#endif
-
-/// Log a warning message.
-void Warning(const char* msg, ...);
-void Warning(const char* msg, va_list ap);
-
-/// Log an error message.
-void Error(const char* msg, ...);
-void Error(const char* msg, va_list ap);
-
-/// Log an informational message.
-void Info(const char* msg, ...);
-void Info(const char* msg, va_list ap);
-
-/// Format a string.
-std::string StringFormat(const char* fmt, ...);
-std::string StringFormat(const char* fmt, va_list ap);
-void StringAppendFormat(std::string& str, const char* fmt, ...);
-void StringAppendFormat(std::string& str, const char* fmt, va_list ap);
-
-/// 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)
-void CanonicalizePath(std::string* path, uint64_t* slash_bits);
-void CanonicalizePath(char* path, size_t* len, uint64_t* slash_bits);
-
-/// 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 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 std::string& path, std::string* contents, std::string* err);
-
-/// Get the timestamp of a given file. On success return a positive timestamp
-/// in nanoseconds, or 0 if the file is missing. Otherwise, in case of failure,
-/// return -1 after setting |*error|.
-int64_t GetFileTimestamp(const std::string& path, std::string* error);
-
-#ifdef _WIN32
-/// Convert a Win32 FILETIME value into a TimeStamp value.
-int64_t TimeStampFromFileTime(const FILETIME& filetime);
-#endif  // _WIN32
-
-/// 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 std::string& text,
-                              const std::vector<const char*>& words);
-
-/// Like SpellcheckStringV, but takes a NULL-terminated list.
-const char* SpellcheckString(const char* text, ...);
-
-bool islatinalpha(int c);
-
-/// Removes all Ansi escape codes (http://www.termsys.demon.co.uk/vtansi.htm).
-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.
-int GetProcessorCount();
-
-/// @return the load average of the machine. A negative value is returned
-/// on error.
-double GetLoadAverage();
-
-/// Elide the given string @a str with '...' in the middle if the length
-/// exceeds @a width.
-std::string ElideMiddle(const std::string& str, size_t width);
-
-/// Truncates a file to the given size.
-bool Truncate(const std::string& path, size_t size, std::string* err);
-
-/// Return absolute path of current directory.
-/// NOTE: GetCurrentDirectory() is a macro in Win32.
-std::string GetCurrentDir();
-
-/// Return absolute path of current executable.
-std::string GetCurrentExecutable();
-
-/// Return absolute path of current executable's directory.
-std::string GetCurrentExecutableDir();
-
-#ifdef _MSC_VER
-#define snprintf _snprintf
-#define fileno _fileno
-#define unlink _unlink
-#define chdir _chdir
-#define strtoull _strtoui64
-#define getcwd _getcwd
-#define PATH_MAX _MAX_PATH
-#endif
-
-#ifdef _WIN32
-/// Convert the value returned by GetLastError() into a string.
-std::string GetLastErrorString();
-std::string GetLastErrorString(unsigned error);
-
-/// Calls Fatal() with a function name and GetLastErrorString.
-NORETURN void Win32Fatal(const char* function, const char* hint = NULL);
-NORETURN void Win32Fatal(const char* function, unsigned long error,
-                         const char* hint = NULL);
-#endif  // !_WIN32
-
-NORETURN void ErrnoFatal(const char* function, const char* hint = NULL);
-NORETURN void ErrnoFatal(const char* function, int errnum, const char* hint = NULL);
-
-/// Convert Unide code to Utf8 string.
-std::string ConvertFromUnicodeString(const wchar_t* str, size_t size);
-std::string ConvertFromUnicodeString(const std::wstring& str);
-
-/// Convert UTF8 string to a Win32  unicode string.
-std::wstring ConvertToUnicodeString(const char* str, size_t size);
-std::wstring ConvertToUnicodeString(const std::string& str);
-
-/// Convert a duration in milliseconds into a human-readable string.
-void AppendStringFormatDurationMs(std::string& out, int64_t duration_ms);
-std::string StringFormatDurationMs(int64_t duration_ms);
-
-/// Returns true if this is a Win32 program running under Wine. Only used
-/// to work-around Wine emulation bugs during unit-testing.
-bool RunsUnderWine();
-
-#endif  // NINJA_UTIL_H_
diff --git a/src/util_test.cc b/src/util_test.cc
deleted file mode 100644
index a9a7956..0000000
--- a/src/util_test.cc
+++ /dev/null
@@ -1,518 +0,0 @@
-// 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.
-
-#include "util.h"
-
-#include "test.h"
-
-using namespace std;
-
-namespace {
-
-void CanonicalizePath(string* path) {
-  uint64_t unused;
-  ::CanonicalizePath(path, &unused);
-}
-
-}  // namespace
-
-TEST(CanonicalizePath, PathSamples) {
-  string path;
-
-  CanonicalizePath(&path);
-  EXPECT_EQ("", path);
-
-  path = "foo.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo.h", path);
-
-  path = "./foo.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo.h", path);
-
-  path = "./foo/./bar.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo/bar.h", path);
-
-  path = "./x/foo/../bar.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("x/bar.h", path);
-
-  path = "./x/foo/../../bar.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("bar.h", path);
-
-  path = "foo//bar";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo/bar", path);
-
-  path = "foo//.//..///bar";
-  CanonicalizePath(&path);
-  EXPECT_EQ("bar", path);
-
-  path = "./x/../foo/../../bar.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("../bar.h", path);
-
-  path = "foo/./.";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo", path);
-
-  path = "foo/bar/..";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo", path);
-
-  path = "foo/.hidden_bar";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo/.hidden_bar", path);
-
-  path = "/foo";
-  CanonicalizePath(&path);
-  EXPECT_EQ("/foo", path);
-
-  path = "//foo";
-  CanonicalizePath(&path);
-#ifdef _WIN32
-  EXPECT_EQ("//foo", path);
-#else
-  EXPECT_EQ("/foo", path);
-#endif
-
-  path = "/";
-  CanonicalizePath(&path);
-  EXPECT_EQ("", path);
-
-  path = "/foo/..";
-  CanonicalizePath(&path);
-  EXPECT_EQ("", path);
-
-  path = ".";
-  CanonicalizePath(&path);
-  EXPECT_EQ(".", path);
-
-  path = "./.";
-  CanonicalizePath(&path);
-  EXPECT_EQ(".", path);
-
-  path = "foo/..";
-  CanonicalizePath(&path);
-  EXPECT_EQ(".", path);
-}
-
-#ifdef _WIN32
-TEST(CanonicalizePath, PathSamplesWindows) {
-  string path;
-
-  CanonicalizePath(&path);
-  EXPECT_EQ("", path);
-
-  path = "foo.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo.h", path);
-
-  path = ".\\foo.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo.h", path);
-
-  path = ".\\foo\\.\\bar.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo/bar.h", path);
-
-  path = ".\\x\\foo\\..\\bar.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("x/bar.h", path);
-
-  path = ".\\x\\foo\\..\\..\\bar.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("bar.h", path);
-
-  path = "foo\\\\bar";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo/bar", path);
-
-  path = "foo\\\\.\\\\..\\\\\\bar";
-  CanonicalizePath(&path);
-  EXPECT_EQ("bar", path);
-
-  path = ".\\x\\..\\foo\\..\\..\\bar.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("../bar.h", path);
-
-  path = "foo\\.\\.";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo", path);
-
-  path = "foo\\bar\\..";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo", path);
-
-  path = "foo\\.hidden_bar";
-  CanonicalizePath(&path);
-  EXPECT_EQ("foo/.hidden_bar", path);
-
-  path = "\\foo";
-  CanonicalizePath(&path);
-  EXPECT_EQ("/foo", path);
-
-  path = "\\\\foo";
-  CanonicalizePath(&path);
-  EXPECT_EQ("//foo", path);
-
-  path = "\\";
-  CanonicalizePath(&path);
-  EXPECT_EQ("", path);
-}
-
-TEST(CanonicalizePath, SlashTracking) {
-  string path;
-  uint64_t slash_bits;
-
-  path = "foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("foo.h", path);
-  EXPECT_EQ(0, slash_bits);
-
-  path = "a\\foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("a/foo.h", path);
-  EXPECT_EQ(1, slash_bits);
-
-  path = "a/bcd/efh\\foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("a/bcd/efh/foo.h", path);
-  EXPECT_EQ(4, slash_bits);
-
-  path = "a\\bcd/efh\\foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("a/bcd/efh/foo.h", path);
-  EXPECT_EQ(5, slash_bits);
-
-  path = "a\\bcd\\efh\\foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("a/bcd/efh/foo.h", path);
-  EXPECT_EQ(7, slash_bits);
-
-  path = "a/bcd/efh/foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("a/bcd/efh/foo.h", path);
-  EXPECT_EQ(0, slash_bits);
-
-  path = "a\\./efh\\foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("a/efh/foo.h", path);
-  EXPECT_EQ(3, slash_bits);
-
-  path = "a\\../efh\\foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("efh/foo.h", path);
-  EXPECT_EQ(1, slash_bits);
-
-  path = "a\\b\\c\\d\\e\\f\\g\\foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("a/b/c/d/e/f/g/foo.h", path);
-  EXPECT_EQ(127, slash_bits);
-
-  path = "a\\b\\c\\..\\..\\..\\g\\foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("g/foo.h", path);
-  EXPECT_EQ(1, slash_bits);
-
-  path = "a\\b/c\\../../..\\g\\foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("g/foo.h", path);
-  EXPECT_EQ(1, slash_bits);
-
-  path = "a\\b/c\\./../..\\g\\foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("a/g/foo.h", path);
-  EXPECT_EQ(3, slash_bits);
-
-  path = "a\\b/c\\./../..\\g/foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("a/g/foo.h", path);
-  EXPECT_EQ(1, slash_bits);
-
-  path = "a\\\\\\foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("a/foo.h", path);
-  EXPECT_EQ(1, slash_bits);
-
-  path = "a/\\\\foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("a/foo.h", path);
-  EXPECT_EQ(0, slash_bits);
-
-  path = "a\\//foo.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ("a/foo.h", path);
-  EXPECT_EQ(1, slash_bits);
-}
-
-TEST(CanonicalizePath, CanonicalizeNotExceedingLen) {
-  // Make sure searching \/ doesn't go past supplied len.
-  char buf[] = "foo/bar\\baz.h\\";  // Last \ past end.
-  uint64_t slash_bits;
-  size_t size = 13;
-  ::CanonicalizePath(buf, &size, &slash_bits);
-  EXPECT_EQ(0, strncmp("foo/bar/baz.h", buf, size));
-  EXPECT_EQ(2, slash_bits);  // Not including the trailing one.
-}
-
-TEST(CanonicalizePath, TooManyComponents) {
-  string path;
-  uint64_t slash_bits;
-
-  // 64 is OK.
-  path = "a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./"
-         "a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./x.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ(slash_bits, 0x0);
-
-  // Backslashes version.
-  path =
-      "a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\"
-      "a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\"
-      "a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\"
-      "a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\x.h";
-
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ(slash_bits, 0xffffffff);
-
-  // 65 is OK if #component is less than 60 after path canonicalization.
-  path = "a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./"
-         "a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./a/./x/y.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ(slash_bits, 0x0);
-
-  // Backslashes version.
-  path =
-      "a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\"
-      "a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\"
-      "a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\"
-      "a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\a\\.\\x\\y.h";
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ(slash_bits, 0x1ffffffff);
-
-
-  // 59 after canonicalization is OK.
-  path = "a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/"
-         "a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/x/y.h";
-  EXPECT_EQ(58, std::count(path.begin(), path.end(), '/'));
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ(slash_bits, 0x0);
-
-  // Backslashes version.
-  path =
-      "a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\"
-      "a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\"
-      "a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\"
-      "a\\a\\a\\a\\a\\a\\a\\a\\a\\x\\y.h";
-  EXPECT_EQ(58, std::count(path.begin(), path.end(), '\\'));
-  CanonicalizePath(&path, &slash_bits);
-  EXPECT_EQ(slash_bits, 0x3ffffffffffffff);
-}
-#endif
-
-TEST(CanonicalizePath, UpDir) {
-  string path, err;
-  path = "../../foo/bar.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("../../foo/bar.h", path);
-
-  path = "test/../../foo/bar.h";
-  CanonicalizePath(&path);
-  EXPECT_EQ("../foo/bar.h", path);
-}
-
-TEST(CanonicalizePath, AbsolutePath) {
-  string path = "/usr/include/stdio.h";
-  string err;
-  CanonicalizePath(&path);
-  EXPECT_EQ("/usr/include/stdio.h", path);
-}
-
-TEST(CanonicalizePath, NotNullTerminated) {
-  string path;
-  size_t len;
-  uint64_t unused;
-
-  path = "foo/. bar/.";
-  len = strlen("foo/.");  // Canonicalize only the part before the space.
-  CanonicalizePath(&path[0], &len, &unused);
-  EXPECT_EQ(strlen("foo"), len);
-  EXPECT_EQ("foo/. bar/.", string(path));
-
-  path = "foo/../file bar/.";
-  len = strlen("foo/../file");
-  CanonicalizePath(&path[0], &len, &unused);
-  EXPECT_EQ(strlen("file"), len);
-  EXPECT_EQ("file ./file bar/.", string(path));
-}
-
-TEST(PathEscaping, TortureTest) {
-  string result;
-
-  GetWin32EscapedString("foo bar\\\"'$@d!st!c'\\path'\\", &result);
-  EXPECT_EQ("\"foo bar\\\\\\\"'$@d!st!c'\\path'\\\\\"", result);
-  result.clear();
-
-  GetShellEscapedString("foo bar\"/'$@d!st!c'/path'", &result);
-  EXPECT_EQ("'foo bar\"/'\\''$@d!st!c'\\''/path'\\'''", result);
-}
-
-TEST(PathEscaping, SensiblePathsAreNotNeedlesslyEscaped) {
-  const char* path = "some/sensible/path/without/crazy/characters.c++";
-  string result;
-
-  GetWin32EscapedString(path, &result);
-  EXPECT_EQ(path, result);
-  result.clear();
-
-  GetShellEscapedString(path, &result);
-  EXPECT_EQ(path, result);
-}
-
-TEST(PathEscaping, SensibleWin32PathsAreNotNeedlesslyEscaped) {
-  const char* path = "some\\sensible\\path\\without\\crazy\\characters.c++";
-  string result;
-
-  GetWin32EscapedString(path, &result);
-  EXPECT_EQ(path, result);
-}
-
-TEST(StripAnsiEscapeCodes, EscapeAtEnd) {
-  string stripped = StripAnsiEscapeCodes("foo\33");
-  EXPECT_EQ("foo", stripped);
-
-  stripped = StripAnsiEscapeCodes("foo\33[");
-  EXPECT_EQ("foo", stripped);
-}
-
-TEST(StripAnsiEscapeCodes, StripColors) {
-  // An actual clang warning.
-  string input = "\33[1maffixmgr.cxx:286:15: \33[0m\33[0;1;35mwarning: "
-                 "\33[0m\33[1musing the result... [-Wparentheses]\33[0m";
-  string stripped = StripAnsiEscapeCodes(input);
-  EXPECT_EQ("affixmgr.cxx:286:15: warning: using the result... [-Wparentheses]",
-            stripped);
-}
-
-TEST(ElideMiddle, NothingToElide) {
-  string input = "Nothing to elide in this short string.";
-  EXPECT_EQ(input, ElideMiddle(input, 80));
-  EXPECT_EQ(input, ElideMiddle(input, 38));
-  EXPECT_EQ("", ElideMiddle(input, 0));
-  EXPECT_EQ(".", ElideMiddle(input, 1));
-  EXPECT_EQ("..", ElideMiddle(input, 2));
-  EXPECT_EQ("...", ElideMiddle(input, 3));
-}
-
-TEST(ElideMiddle, ElideInTheMiddle) {
-  string input = "01234567890123456789";
-  string elided = ElideMiddle(input, 10);
-  EXPECT_EQ("012...789", elided);
-  EXPECT_EQ("01234567...23456789", ElideMiddle(input, 19));
-}
-
-TEST(StringFormat, StringFormatWithVarargs) {
-  std::string str = StringFormat("%s %d %s", "foo", 42, "bar");
-  EXPECT_EQ("foo 42 bar", str);
-}
-
-TEST(StringFormat, StringFormatWithValist) {
-  auto f = [](const char* fmt, ...) {
-    va_list args;
-    va_start(args, fmt);
-    std::string result = StringFormat(fmt, args);
-    va_end(args);
-    return result;
-  };
-
-  std::string str = f("%s %d %s", "foo", 42, "bar");
-  EXPECT_EQ("foo 42 bar", str);
-}
-
-TEST(StringFormat, StringAppendFormatWithVarargs) {
-  std::string str("foo");
-  StringAppendFormat(str, " %d %s", 42, "bar");
-  EXPECT_EQ("foo 42 bar", str);
-}
-
-TEST(StringFormat, StringAppendFormatWithVarargsAndLongResult) {
-  std::string str("foo");
-  std::string bar("xxxxxxxx");
-  bar += bar;
-  bar += bar;
-  bar += bar;
-  bar += bar;
-  bar += bar;
-  StringAppendFormat(str, " %d %s --", 42, bar.c_str());
-
-  std::string expected = std::string("foo 42 ") + bar + " --";
-  EXPECT_EQ(expected, str);
-}
-
-TEST(StringFormat, StringAppendFormatWithValist) {
-  std::string str;
-  auto f = [&str](const char* fmt, ...) {
-    va_list args;
-    va_start(args, fmt);
-    StringAppendFormat(str, fmt, args);
-    va_end(args);
-  };
-
-  f("%s %d %s", "foo", 42, "bar");
-  EXPECT_EQ("foo 42 bar", str);
-}
-
-TEST(RunsUnderWine, Test) {
-  // Try to run Determine
-  bool expected = false;
-#ifdef _WIN32
-  expected = getenv("WINELOADER") || getenv("WINEUSERNAME") ||
-             getenv("WINEDEBUG") || getenv("WINEDLLDIR0");
-#endif
-  ASSERT_EQ(expected, RunsUnderWine());
-}
-
-#ifdef _WIN32
-TEST(ConvertToUnicodeString, Test) {
-  EXPECT_EQ(std::wstring(L"Bébé"), ConvertToUnicodeString("Bébé"));
-}
-
-TEST(ConvertFromUnicodeString, Test) {
-  EXPECT_EQ(std::string("Bébé"), ConvertFromUnicodeString(L"Bébé"));
-}
-#endif  // _WIN32
-
-TEST(StringFormatDurationMs, Test) {
-  EXPECT_EQ(StringFormatDurationMs(0), "0 ms");
-  EXPECT_EQ(StringFormatDurationMs(123), "123 ms");
-  EXPECT_EQ(StringFormatDurationMs(995), "995 ms");
-  EXPECT_EQ(StringFormatDurationMs(1000), "1.00 s");
-  EXPECT_EQ(StringFormatDurationMs(3148), "3.14 s");
-  EXPECT_EQ(StringFormatDurationMs(9999), "9.99 s");
-  EXPECT_EQ(StringFormatDurationMs(10000), "10.0 s");
-  EXPECT_EQ(StringFormatDurationMs(59999), "59.9 s");
-  EXPECT_EQ(StringFormatDurationMs(60000), "1:00 min");
-  EXPECT_EQ(StringFormatDurationMs(157892), "2:37 min");
-  EXPECT_EQ(StringFormatDurationMs(3599999), "59:59 min");
-  EXPECT_EQ(StringFormatDurationMs(3600000), "1:00:00 hr");
-  EXPECT_EQ(StringFormatDurationMs(1000000000), "277:46:40 hr");
-
-  EXPECT_EQ(StringFormatDurationMs(-123), "-123 ms");
-  EXPECT_EQ(StringFormatDurationMs(-995), "-995 ms");
-  EXPECT_EQ(StringFormatDurationMs(-1000), "-1.00 s");
-  EXPECT_EQ(StringFormatDurationMs(3148), "3.14 s");
-}
diff --git a/src/version.cc b/src/version.cc
deleted file mode 100644
index d306957..0000000
--- a/src/version.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2013 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 "version.h"
-
-#include <stdlib.h>
-
-#include "util.h"
-
-using namespace std;
-
-const char* kNinjaVersion = "1.12.0.git";
-
-void ParseVersion(const string& version, int* major, int* minor) {
-  size_t end = version.find('.');
-  *major = atoi(version.substr(0, end).c_str());
-  *minor = 0;
-  if (end != string::npos) {
-    size_t start = end + 1;
-    end = version.find('.', start);
-    *minor = atoi(version.substr(start, end).c_str());
-  }
-}
-
-void CheckNinjaVersion(const string& version) {
-  int bin_major, bin_minor;
-  ParseVersion(kNinjaVersion, &bin_major, &bin_minor);
-  int file_major, file_minor;
-  ParseVersion(version, &file_major, &file_minor);
-
-  if (bin_major > file_major) {
-    Warning("ninja executable version (%s) greater than build file "
-            "ninja_required_version (%s); versions may be incompatible.",
-            kNinjaVersion, version.c_str());
-    return;
-  }
-
-  if ((bin_major == file_major && bin_minor < file_minor) ||
-      bin_major < file_major) {
-    Fatal("ninja version (%s) incompatible with build file "
-          "ninja_required_version version (%s).",
-          kNinjaVersion, version.c_str());
-  }
-}
diff --git a/src/version.h b/src/version.h
deleted file mode 100644
index 9d84ecb..0000000
--- a/src/version.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2013 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_VERSION_H_
-#define NINJA_VERSION_H_
-
-#include <string>
-
-/// 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 std::string& version, int* major, int* minor);
-
-/// Check whether \a version is compatible with the current Ninja version,
-/// aborting if not.
-void CheckNinjaVersion(const std::string& required_version);
-
-#endif  // NINJA_VERSION_H_
diff --git a/src/win32port.h b/src/win32port.h
deleted file mode 100644
index e542536..0000000
--- a/src/win32port.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2012 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_WIN32PORT_H_
-#define NINJA_WIN32PORT_H_
-
-#if defined(__MINGW32__) || defined(__MINGW64__)
-#ifndef __STDC_FORMAT_MACROS
-#define __STDC_FORMAT_MACROS
-#endif
-#include <inttypes.h>
-#endif
-
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-/// A 64-bit integer type
-typedef signed long long int64_t;
-typedef unsigned long long uint64_t;
-
-// printf format specifier for uint64_t, from C99.
-#ifndef PRIu64
-#define PRId64 "I64d"
-#define PRIu64 "I64u"
-#define PRIx64 "I64x"
-#endif
-
-#endif // NINJA_WIN32PORT_H_
-
diff --git a/windows/ninja.manifest b/windows/ninja.manifest
deleted file mode 100644
index 47949dd..0000000
--- a/windows/ninja.manifest
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
-  <application>
-    <windowsSettings>
-      <activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
-      <longPathAware  xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
-    </windowsSettings>
-  </application>
-</assembly>