New Upstream Snapshot - android-platform-build-kati

Ready changes

Summary

Merged new upstream version: 10.0.0+r32+git20220314.09dfa26c4e59+git20230118.1.ee53893 (was: 10.0.0+r32+git20220314.09dfa26c4e59).

Resulting package

Built on 2023-01-27T15:12 (took 4m27s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-snapshots ckati-dbgsymapt install -t fresh-snapshots ckati

Lintian Result

Diff

diff --git a/.github/workflows/cpp-ci.yml b/.github/workflows/cpp-ci.yml
deleted file mode 100644
index afa5012..0000000
--- a/.github/workflows/cpp-ci.yml
+++ /dev/null
@@ -1,58 +0,0 @@
-name: Build and Test
-
-on:
-  push:
-    branches: [ master ]
-  pull_request:
-    branches: [ master ]
-
-jobs:
-  build:
-
-    runs-on: ubuntu-latest
-
-    env:
-      CXX: clang++-12
-      CLANG_FORMAT: clang-format-12
-
-    steps:
-    - uses: actions/checkout@v2
-    - name: install ninja
-      run: |
-        mkdir -p ${GITHUB_WORKSPACE}/ninja-bin; cd ${GITHUB_WORKSPACE}/ninja-bin
-        wget https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-linux.zip
-        unzip ninja-linux.zip
-        rm ninja-linux.zip
-        echo "${GITHUB_WORKSPACE}/ninja-bin" >> "$GITHUB_PATH"
-    - name: install GNU Make
-      run: |
-        mkdir -p ${GITHUB_WORKSPACE}/make-bin/tmp; cd ${GITHUB_WORKSPACE}/make-bin/tmp
-        wget http://mirrors.kernel.org/ubuntu/pool/main/m/make-dfsg/make_4.2.1-1.2_amd64.deb
-        ar xv make_4.2.1-1.2_amd64.deb
-        tar xf data.tar.xz
-        mv usr/bin/make ../
-        cd ..
-        rm -rf tmp/
-        echo "${GITHUB_WORKSPACE}/make-bin" >> "$GITHUB_PATH"
-    - name: make info
-      run: make info
-    - name: make
-      run: make -j4 ckati ckati_tests
-    - name: clang format
-      run: ./clang-format-check
-    - name: run standalone tests
-      run: go test --ckati
-    - name: run ninja tests
-      run: go test --ckati --ninja
-    - name: run ninja all targets tests
-      run: go test --ckati --ninja --all
-    - name: run ninja unit tests
-      run: ./ninja_test
-    - name: run stringpiece unit tests
-      run: ./string_piece_test
-    - name: run strutil unit tests
-      run: ./strutil_test
-    - name: run find unit tests
-      run: ./find_test
-    - name: run JSON dump tests
-      run: testcase/dump/run.sh
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index ea52501..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,19 +0,0 @@
-kati
-!golang/cmd/kati/
-ckati
-para
-*.o
-*.d
-out/
-repo/android/
-repo/glog/
-repo/maloader/
-testcase_parse_benchmark_test.go
-bench-old.out
-bench-new.out
-find_test
-ninja_test
-string_piece_test
-strutil_bench
-strutil_test
-version.cc
diff --git a/AUTHORS b/AUTHORS
index 0acaa9e..79bbb8f 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -8,6 +8,7 @@
 #
 # Please keep the list sorted.
 
+Delilah Hoare <delilah@dhoare.me>
 Google Inc.
 Koichi Shiraishi <zchee.io@gmail.com>
 Kouhei Sutou <kou@cozmixng.org>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 3c2e7d4..3d447d5 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -24,6 +24,7 @@
 
 Colin Cross <ccross@google.com>
 Dan Willemsen <dwillemsen@google.com>
+Delilah Hoare <delilah@dhoare.me>
 Fumitoshi Ukai <ukai@google.com>
 Koichi Shiraishi <zchee.io@gmail.com>
 Kouhei Sutou <kou@cozmixng.org>
diff --git a/Dockerfile b/Dockerfile
index b4423be..834e6c0 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,16 +1,27 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
-RUN apt-get update && apt-get install -y make git-core build-essential curl ninja-build python python3
+RUN apt-get update && apt-get install -y make git-core build-essential curl ninja-build python3 wget
 
 # Install Go
 RUN \
   mkdir -p /goroot && \
   curl https://storage.googleapis.com/golang/go1.14.9.linux-amd64.tar.gz | tar xvzf - -C /goroot --strip-components=1
 
-# Set environment variables for Go.
+# Install Make, we emulate Make 4.2.1 instead of the default 4.3 currently
+RUN \
+  mkdir -p /make/tmp && \
+  cd /make/tmp && \
+  wget http://mirrors.kernel.org/ubuntu/pool/main/m/make-dfsg/make_4.2.1-1.2_amd64.deb && \
+  ar xv make_4.2.1-1.2_amd64.deb && \
+  tar xf data.tar.xz && \
+  mv usr/bin/make ../ && \
+  cd .. && \
+  rm -rf tmp/
+
+# Set environment variables for Go and Make.
 ENV GOROOT /goroot
 ENV GOPATH /gopath
-ENV PATH $GOROOT/bin:$GOPATH/bin:$PATH
+ENV PATH $GOROOT/bin:$GOPATH/bin:/make:$PATH
 
 # Copy project code.
 COPY . /src
diff --git a/Makefile b/Makefile
index e1b9d46..8766443 100644
--- a/Makefile
+++ b/Makefile
@@ -25,6 +25,9 @@ info: ckati
 	@echo CKATI VERSION
 	./ckati -f Makefile version
 	@echo
+	@echo BASH VERSION
+	-/bin/bash --version | head -n 1
+	@echo
 	@echo SHELL VERSION
 	@echo $(SHELL)
 	$(SHELL) --version | head -n 1
@@ -33,6 +36,7 @@ version:
 	@echo $(MAKE_VERSION)
 
 test: all ckati_tests
+	go test --ckati
 	go test --ckati --ninja
 
 clean: ckati_clean
diff --git a/Makefile.ckati b/Makefile.ckati
index e86f15f..322d747 100644
--- a/Makefile.ckati
+++ b/Makefile.ckati
@@ -43,7 +43,6 @@ KATI_CXX_SRCS := \
 	rule.cc \
 	stats.cc \
 	stmt.cc \
-	string_piece.cc \
 	stringprintf.cc \
 	strutil.cc \
 	symtab.cc \
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..1ee860c
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,2 @@
+include platform/build/soong:/OWNERS
+
diff --git a/README.md b/README.md
index 889abf2..ff3c150 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ $ make ckati
 
 The above command produces a `ckati` binary in the project root.
 
-Testing (best ran in a Ubuntu 20.04 environment):
+Testing (best ran in a Ubuntu 22.04 environment):
 
 ```
 $ make test
diff --git a/debian/changelog b/debian/changelog
index 6ba8111..876e2b4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+android-platform-build-kati (10.0.0+r32+git20220314.09dfa26c4e59+git20230118.1.ee53893-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Fri, 27 Jan 2023 15:08:52 -0000
+
 android-platform-build-kati (10.0.0+r32+git20220314.09dfa26c4e59-4) unstable; urgency=medium
 
   * Instead of editing the Makefile at build time,
diff --git a/debian/patches/0001-Make-sure-PATH_MAX-is-defined-on-GNU-Hurd.patch b/debian/patches/0001-Make-sure-PATH_MAX-is-defined-on-GNU-Hurd.patch
index 9a5fb4d..9ccc6d7 100644
--- a/debian/patches/0001-Make-sure-PATH_MAX-is-defined-on-GNU-Hurd.patch
+++ b/debian/patches/0001-Make-sure-PATH_MAX-is-defined-on-GNU-Hurd.patch
@@ -8,10 +8,10 @@ Signed-off-by: Andrej Shadura <andrew.shadura@collabora.co.uk>
  src/strutil.h  | 5 +++++
  2 files changed, 5 insertions(+), 1 deletion(-)
 
-diff --git a/src/strutil.cc b/src/strutil.cc
-index 8c4bdc0..0b5f268 100644
---- a/src/strutil.cc
-+++ b/src/strutil.cc
+Index: android-platform-build-kati.git/src/strutil.cc
+===================================================================
+--- android-platform-build-kati.git.orig/src/strutil.cc
++++ android-platform-build-kati.git/src/strutil.cc
 @@ -17,7 +17,6 @@
  #include "strutil.h"
  
@@ -20,13 +20,13 @@ index 8c4bdc0..0b5f268 100644
  #include <unistd.h>
  
  #include <algorithm>
-diff --git a/src/strutil.h b/src/strutil.h
-index d573b79..7fefb32 100644
---- a/src/strutil.h
-+++ b/src/strutil.h
-@@ -17,6 +17,11 @@
- 
+Index: android-platform-build-kati.git/src/strutil.h
+===================================================================
+--- android-platform-build-kati.git.orig/src/strutil.h
++++ android-platform-build-kati.git/src/strutil.h
+@@ -18,6 +18,11 @@
  #include <string>
+ #include <string_view>
  #include <vector>
 +#include <limits.h>
 +// GNU Hurd doesn't have PATH_MAX
@@ -34,5 +34,5 @@ index d573b79..7fefb32 100644
 +#define PATH_MAX 4096
 +#endif
  
- #include "string_piece.h"
- 
+ class WordScanner {
+  public:
diff --git a/debian/patches/0002-Link-against-lrt-lpthread-on-GNU-Hurd-too.patch b/debian/patches/0002-Link-against-lrt-lpthread-on-GNU-Hurd-too.patch
index 6159e29..e288bd5 100644
--- a/debian/patches/0002-Link-against-lrt-lpthread-on-GNU-Hurd-too.patch
+++ b/debian/patches/0002-Link-against-lrt-lpthread-on-GNU-Hurd-too.patch
@@ -7,11 +7,11 @@ Signed-off-by: Andrej Shadura <andrew.shadura@collabora.co.uk>
  Makefile.ckati | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
-diff --git a/Makefile.ckati b/Makefile.ckati
-index e86f15f..68a2ff3 100644
---- a/Makefile.ckati
-+++ b/Makefile.ckati
-@@ -74,7 +74,7 @@ KATI_CXXFLAGS += -O -DNOLOG
+Index: android-platform-build-kati.git/Makefile.ckati
+===================================================================
+--- android-platform-build-kati.git.orig/Makefile.ckati
++++ android-platform-build-kati.git/Makefile.ckati
+@@ -73,7 +73,7 @@ KATI_CXXFLAGS += -O -DNOLOG
  KATI_CXXFLAGS += -march=native
  #KATI_CXXFLAGS += -pg
  
diff --git a/debian/patches/0003-Implement-GNU-Hurd-and-BSD-support-inspired-by-the-L.patch b/debian/patches/0003-Implement-GNU-Hurd-and-BSD-support-inspired-by-the-L.patch
index 640e046..bfcca1d 100644
--- a/debian/patches/0003-Implement-GNU-Hurd-and-BSD-support-inspired-by-the-L.patch
+++ b/debian/patches/0003-Implement-GNU-Hurd-and-BSD-support-inspired-by-the-L.patch
@@ -8,10 +8,10 @@ Signed-off-by: Andrej Shadura <andrew.shadura@collabora.co.uk>
  src/fileutil.cc | 35 +++++++++++++++++++++++++++++++----
  1 file changed, 31 insertions(+), 4 deletions(-)
 
-diff --git a/src/fileutil.cc b/src/fileutil.cc
-index 14ee68a..c36acff 100644
---- a/src/fileutil.cc
-+++ b/src/fileutil.cc
+Index: android-platform-build-kati.git/src/fileutil.cc
+===================================================================
+--- android-platform-build-kati.git.orig/src/fileutil.cc
++++ android-platform-build-kati.git/src/fileutil.cc
 @@ -29,6 +29,9 @@
  #if defined(__APPLE__)
  #include <mach-o/dyld.h>
@@ -22,7 +22,7 @@ index 14ee68a..c36acff 100644
  
  #include <unordered_map>
  
-@@ -179,14 +182,38 @@ int RunCommand(const string& shell,
+@@ -179,14 +182,38 @@ int RunCommand(const std::string& shell,
  }
  
  std::string GetExecutablePath() {
diff --git a/debian/patches/0004-Don-t-overwrite-KATI_CXXFLAGS-so-that-the-can-be-pre.patch b/debian/patches/0004-Don-t-overwrite-KATI_CXXFLAGS-so-that-the-can-be-pre.patch
index f7d63f9..a524be5 100644
--- a/debian/patches/0004-Don-t-overwrite-KATI_CXXFLAGS-so-that-the-can-be-pre.patch
+++ b/debian/patches/0004-Don-t-overwrite-KATI_CXXFLAGS-so-that-the-can-be-pre.patch
@@ -6,11 +6,11 @@ Subject: Don’t overwrite KATI_CXXFLAGS so that the can be pre-set by the syste
  Makefile.ckati | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
-diff --git a/Makefile.ckati b/Makefile.ckati
-index 68a2ff3..68b5f64 100644
---- a/Makefile.ckati
-+++ b/Makefile.ckati
-@@ -69,7 +69,7 @@ KATI_CXX_TEST_OBJS := $(patsubst $(KATI_SRC_PATH)/%.cc,$(KATI_INTERMEDIATES_PATH
+Index: android-platform-build-kati.git/Makefile.ckati
+===================================================================
+--- android-platform-build-kati.git.orig/Makefile.ckati
++++ android-platform-build-kati.git/Makefile.ckati
+@@ -68,7 +68,7 @@ KATI_CXX_TEST_OBJS := $(patsubst $(KATI_
  KATI_CXX_TEST_EXES := $(patsubst $(KATI_INTERMEDIATES_PATH)/%.o,$(KATI_BIN_PATH)/%,\
  	$(KATI_CXX_TEST_OBJS))
  
diff --git a/debian/patches/0005-Drop-march-native.patch b/debian/patches/0005-Drop-march-native.patch
index fc1060f..3d47d02 100644
--- a/debian/patches/0005-Drop-march-native.patch
+++ b/debian/patches/0005-Drop-march-native.patch
@@ -6,11 +6,11 @@ Subject: Drop -march=native
  Makefile.ckati | 1 -
  1 file changed, 1 deletion(-)
 
-diff --git a/Makefile.ckati b/Makefile.ckati
-index 68b5f64..4989ef3 100644
---- a/Makefile.ckati
-+++ b/Makefile.ckati
-@@ -71,7 +71,6 @@ KATI_CXX_TEST_EXES := $(patsubst $(KATI_INTERMEDIATES_PATH)/%.o,$(KATI_BIN_PATH)
+Index: android-platform-build-kati.git/Makefile.ckati
+===================================================================
+--- android-platform-build-kati.git.orig/Makefile.ckati
++++ android-platform-build-kati.git/Makefile.ckati
+@@ -70,7 +70,6 @@ KATI_CXX_TEST_EXES := $(patsubst $(KATI_
  
  KATI_CXXFLAGS += -g -W -Wall -MMD -MP
  KATI_CXXFLAGS += -O -DNOLOG
diff --git a/run_test.go b/run_test.go
index 7c574fc..d115125 100644
--- a/run_test.go
+++ b/run_test.go
@@ -69,7 +69,7 @@ var normalizeMakeLog = []normalization{
 	// GNU make 4.0 has this output.
 	{regexp.MustCompile(`Makefile:\d+: commands for target ".*?" failed\n`), ""},
 	// We treat some warnings as errors.
-	{regexp.MustCompile(`/bin/(ba)?sh: line 0: `), ""},
+	{regexp.MustCompile(`/bin/(ba)?sh: line 1: `), ""},
 	// Normalization for "include foo" with C++ kati
 	{regexp.MustCompile(`(: \S+: No such file or directory)\n\*\*\* No rule to make target "[^"]+".`), "$1"},
 	// GNU make 4.0 prints the file:line as part of the error message, e.g.:
@@ -89,7 +89,7 @@ var normalizeKati = []normalization{
 	// kati specific log messages
 	{regexp.MustCompile(`\*kati\*[^\n]*`), ""},
 	{regexp.MustCompile(`c?kati: `), ""},
-	{regexp.MustCompile(`/bin/sh: line 0: `), ""},
+	{regexp.MustCompile(`/bin/(ba)?sh: line 1: `), ""},
 	{regexp.MustCompile(`/bin/sh: `), ""},
 	{regexp.MustCompile(`.*: warning for parse error in an unevaluated line: [^\n]*`), ""},
 	{regexp.MustCompile(`([^\n ]+: )?FindEmulator: `), ""},
diff --git a/src/Android.bp b/src/Android.bp
index 0fa4159..c56ab34 100644
--- a/src/Android.bp
+++ b/src/Android.bp
@@ -52,7 +52,6 @@ cc_library_host_static {
         "rule.cc",
         "stats.cc",
         "stmt.cc",
-        "string_piece.cc",
         "stringprintf.cc",
         "strutil.cc",
         "symtab.cc",
@@ -69,7 +68,7 @@ cc_binary_host {
     whole_static_libs: ["libckati"],
     target: {
         linux_glibc: {
-            shared_libs: ["libjemalloc"],
+            shared_libs: ["libjemalloc5"],
         },
     },
 }
@@ -88,8 +87,6 @@ cc_test_host {
     srcs: [
         "find_test.cc",
         "ninja_test.cc",
-        "string_piece_test.cc",
-        "strutil_bench.cc",
         "strutil_test.cc",
     ],
     gtest: false,
@@ -104,3 +101,12 @@ cc_benchmark_host {
     ],
     static_libs: ["libckati"],
 }
+
+cc_test_host {
+    name: "ckati_strutil_bench",
+    defaults: ["ckati_defaults"],
+    srcs: [
+        "strutil_bench.cc",
+    ],
+    static_libs: ["libckati"],
+}
diff --git a/src/command.cc b/src/command.cc
index 5268b9e..cc58616 100644
--- a/src/command.cc
+++ b/src/command.cc
@@ -21,6 +21,7 @@
 
 #include "dep.h"
 #include "eval.h"
+#include "fileutil.h"
 #include "flags.h"
 #include "log.h"
 #include "strutil.h"
@@ -35,13 +36,13 @@ class AutoVar : public Var {
 
   virtual void AppendVar(Evaluator*, Value*) override { CHECK(false); }
 
-  virtual StringPiece String() const override {
+  virtual std::string_view String() const override {
     ERROR("$(value %s) is not implemented yet", sym_);
     return "";
   }
 
-  virtual string DebugString() const override {
-    return string("AutoVar(") + sym_ + ")";
+  virtual std::string DebugString() const override {
+    return std::string("AutoVar(") + sym_ + ")";
   }
 
   virtual bool IsFunc(Evaluator*) const override { return true; }
@@ -59,7 +60,7 @@ class AutoVar : public Var {
    public:                                                            \
     name(CommandEvaluator* ce, const char* sym) : AutoVar(ce, sym) {} \
     virtual ~name() = default;                                        \
-    virtual void Eval(Evaluator* ev, string* s) const override;       \
+    virtual void Eval(Evaluator* ev, std::string* s) const override;  \
   }
 
 DECLARE_AUTO_VAR_CLASS(AutoAtVar);
@@ -67,6 +68,7 @@ DECLARE_AUTO_VAR_CLASS(AutoLessVar);
 DECLARE_AUTO_VAR_CLASS(AutoHatVar);
 DECLARE_AUTO_VAR_CLASS(AutoPlusVar);
 DECLARE_AUTO_VAR_CLASS(AutoStarVar);
+DECLARE_AUTO_VAR_CLASS(AutoQuestionVar);
 DECLARE_AUTO_VAR_CLASS(AutoNotImplementedVar);
 
 class AutoSuffixDVar : public AutoVar {
@@ -74,7 +76,7 @@ class AutoSuffixDVar : public AutoVar {
   AutoSuffixDVar(CommandEvaluator* ce, const char* sym, Var* wrapped)
       : AutoVar(ce, sym), wrapped_(wrapped) {}
   virtual ~AutoSuffixDVar() = default;
-  virtual void Eval(Evaluator* ev, string* s) const override;
+  virtual void Eval(Evaluator* ev, std::string* s) const override;
 
  private:
   Var* wrapped_;
@@ -85,24 +87,24 @@ class AutoSuffixFVar : public AutoVar {
   AutoSuffixFVar(CommandEvaluator* ce, const char* sym, Var* wrapped)
       : AutoVar(ce, sym), wrapped_(wrapped) {}
   virtual ~AutoSuffixFVar() = default;
-  virtual void Eval(Evaluator* ev, string* s) const override;
+  virtual void Eval(Evaluator* ev, std::string* s) const override;
 
  private:
   Var* wrapped_;
 };
 
-void AutoAtVar::Eval(Evaluator*, string* s) const {
+void AutoAtVar::Eval(Evaluator*, std::string* s) const {
   *s += ce_->current_dep_node()->output.str();
 }
 
-void AutoLessVar::Eval(Evaluator*, string* s) const {
+void AutoLessVar::Eval(Evaluator*, std::string* s) const {
   auto& ai = ce_->current_dep_node()->actual_inputs;
   if (!ai.empty())
     *s += ai[0].str();
 }
 
-void AutoHatVar::Eval(Evaluator*, string* s) const {
-  unordered_set<StringPiece> seen;
+void AutoHatVar::Eval(Evaluator*, std::string* s) const {
+  std::unordered_set<std::string_view> seen;
   WordWriter ww(s);
   for (Symbol ai : ce_->current_dep_node()->actual_inputs) {
     if (seen.insert(ai.str()).second)
@@ -110,47 +112,83 @@ void AutoHatVar::Eval(Evaluator*, string* s) const {
   }
 }
 
-void AutoPlusVar::Eval(Evaluator*, string* s) const {
+void AutoPlusVar::Eval(Evaluator*, std::string* s) const {
   WordWriter ww(s);
   for (Symbol ai : ce_->current_dep_node()->actual_inputs) {
     ww.Write(ai.str());
   }
 }
 
-void AutoStarVar::Eval(Evaluator*, string* s) const {
+void AutoStarVar::Eval(Evaluator*, std::string* s) const {
   const DepNode* n = ce_->current_dep_node();
   if (!n->output_pattern.IsValid())
     return;
   Pattern pat(n->output_pattern.str());
-  pat.Stem(n->output.str()).AppendToString(s);
+  s->append(pat.Stem(n->output.str()));
 }
 
-void AutoNotImplementedVar::Eval(Evaluator* ev, string*) const {
+void AutoQuestionVar::Eval(Evaluator* ev, std::string* s) const {
+  std::unordered_set<std::string_view> seen;
+
+  if (ev->avoid_io()) {
+    // Check timestamps using the shell at the start of rule execution
+    // instead.
+    *s += "${KATI_NEW_INPUTS}";
+    if (!ce_->found_new_inputs()) {
+      std::string def;
+
+      WordWriter ww(&def);
+      ww.Write("KATI_NEW_INPUTS=$(find");
+      for (Symbol ai : ce_->current_dep_node()->actual_inputs) {
+        if (seen.insert(ai.str()).second) {
+          ww.Write(ai.str());
+        }
+      }
+      ww.Write("$(test -e");
+      ww.Write(ce_->current_dep_node()->output.str());
+      ww.Write("&& echo -newer");
+      ww.Write(ce_->current_dep_node()->output.str());
+      ww.Write(")) && export KATI_NEW_INPUTS");
+      ev->add_delayed_output_command(def);
+      ce_->set_found_new_inputs(true);
+    }
+  } else {
+    WordWriter ww(s);
+    double target_age = GetTimestamp(ce_->current_dep_node()->output.str());
+    for (Symbol ai : ce_->current_dep_node()->actual_inputs) {
+      if (seen.insert(ai.str()).second && GetTimestamp(ai.str()) > target_age) {
+        ww.Write(ai.str());
+      }
+    }
+  }
+}
+
+void AutoNotImplementedVar::Eval(Evaluator* ev, std::string*) const {
   ev->Error(StringPrintf("Automatic variable `$%s' isn't supported yet", sym_));
 }
 
-void AutoSuffixDVar::Eval(Evaluator* ev, string* s) const {
-  string buf;
+void AutoSuffixDVar::Eval(Evaluator* ev, std::string* s) const {
+  std::string buf;
   wrapped_->Eval(ev, &buf);
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(buf)) {
+  for (std::string_view tok : WordScanner(buf)) {
     ww.Write(Dirname(tok));
   }
 }
 
-void AutoSuffixFVar::Eval(Evaluator* ev, string* s) const {
-  string buf;
+void AutoSuffixFVar::Eval(Evaluator* ev, std::string* s) const {
+  std::string buf;
   wrapped_->Eval(ev, &buf);
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(buf)) {
+  for (std::string_view tok : WordScanner(buf)) {
     ww.Write(Basename(tok));
   }
 }
 
-void ParseCommandPrefixes(StringPiece* s, bool* echo, bool* ignore_error) {
+void ParseCommandPrefixes(std::string_view* s, bool* echo, bool* ignore_error) {
   *s = TrimLeftSpace(*s);
   while (true) {
-    char c = s->get(0);
+    char c = s->empty() ? 0 : s->front();
     if (c == '@') {
       *echo = false;
     } else if (c == '-') {
@@ -179,9 +217,9 @@ CommandEvaluator::CommandEvaluator(Evaluator* ev) : ev_(ev) {
   INSERT_AUTO_VAR(AutoHatVar, "^");
   INSERT_AUTO_VAR(AutoPlusVar, "+");
   INSERT_AUTO_VAR(AutoStarVar, "*");
+  INSERT_AUTO_VAR(AutoQuestionVar, "?");
   // TODO: Implement them.
   INSERT_AUTO_VAR(AutoNotImplementedVar, "%");
-  INSERT_AUTO_VAR(AutoNotImplementedVar, "?");
   INSERT_AUTO_VAR(AutoNotImplementedVar, "|");
 }
 
@@ -191,10 +229,11 @@ std::vector<Command> CommandEvaluator::Eval(const DepNode& n) {
   ev_->set_current_scope(n.rule_vars);
   ev_->SetEvaluatingCommand(true);
   current_dep_node_ = &n;
+  found_new_inputs_ = false;
   for (Value* v : n.cmds) {
     ev_->set_loc(v->Location());
-    const string&& cmds_buf = v->Eval(ev_);
-    StringPiece cmds = cmds_buf;
+    const std::string&& cmds_buf = v->Eval(ev_);
+    std::string_view cmds = cmds_buf;
     bool global_echo = !g_flags.is_silent_mode;
     bool global_ignore_error = false;
     ParseCommandPrefixes(&cmds, &global_echo, &global_ignore_error);
@@ -204,8 +243,8 @@ std::vector<Command> CommandEvaluator::Eval(const DepNode& n) {
       size_t lf_cnt;
       size_t index = FindEndOfLine(cmds, 0, &lf_cnt);
       if (index == cmds.size())
-        index = string::npos;
-      StringPiece cmd = TrimLeftSpace(cmds.substr(0, index));
+        index = std::string::npos;
+      std::string_view cmd = TrimLeftSpace(cmds.substr(0, index));
       cmds = cmds.substr(index + 1);
 
       bool echo = global_echo;
@@ -214,11 +253,11 @@ std::vector<Command> CommandEvaluator::Eval(const DepNode& n) {
 
       if (!cmd.empty()) {
         Command& command = result.emplace_back(n.output);
-        command.cmd = cmd.as_string();
+        command.cmd = std::string(cmd);
         command.echo = echo;
         command.ignore_error = ignore_error;
       }
-      if (index == string::npos)
+      if (index == std::string::npos)
         break;
     }
     continue;
@@ -226,11 +265,12 @@ std::vector<Command> CommandEvaluator::Eval(const DepNode& n) {
 
   if (!ev_->delayed_output_commands().empty()) {
     std::vector<Command> output_commands;
-    for (const string& cmd : ev_->delayed_output_commands()) {
+    for (const std::string& cmd : ev_->delayed_output_commands()) {
       Command& c = output_commands.emplace_back(n.output);
       c.cmd = cmd;
       c.echo = false;
       c.ignore_error = false;
+      c.force_no_subshell = true;
     }
     // Prepend |output_commands|.
     result.swap(output_commands);
diff --git a/src/command.h b/src/command.h
index 017f6bb..102c508 100644
--- a/src/command.h
+++ b/src/command.h
@@ -19,17 +19,17 @@
 
 #include "symtab.h"
 
-using namespace std;
-
 struct DepNode;
 class Evaluator;
 
 struct Command {
-  explicit Command(Symbol o) : output(o), echo(true), ignore_error(false) {}
+  explicit Command(Symbol o)
+      : output(o), echo(true), ignore_error(false), force_no_subshell(false) {}
   Symbol output;
-  string cmd;
+  std::string cmd;
   bool echo;
   bool ignore_error;
+  bool force_no_subshell;
 };
 
 class CommandEvaluator {
@@ -38,10 +38,13 @@ class CommandEvaluator {
   std::vector<Command> Eval(const DepNode& n);
   const DepNode* current_dep_node() const { return current_dep_node_; }
   Evaluator* evaluator() const { return ev_; }
+  bool found_new_inputs() const { return found_new_inputs_; }
+  void set_found_new_inputs(bool val) { found_new_inputs_ = val; }
 
  private:
   Evaluator* ev_;
   const DepNode* current_dep_node_;
+  bool found_new_inputs_;
 };
 
 #endif  // COMMAND_H_
diff --git a/src/dep.cc b/src/dep.cc
index bf4c947..0391cb7 100644
--- a/src/dep.cc
+++ b/src/dep.cc
@@ -39,17 +39,16 @@ namespace {
 static std::vector<std::unique_ptr<DepNode>> g_dep_node_pool;
 
 static Symbol ReplaceSuffix(Symbol s, Symbol newsuf) {
-  string r;
-  AppendString(StripExt(s.str()), &r);
+  std::string r{StripExt(s.str())};
   r += '.';
-  AppendString(newsuf.str(), &r);
+  r += newsuf.str();
   return Intern(r);
 }
 
 void ApplyOutputPattern(const Rule& r,
                         Symbol output,
-                        const vector<Symbol>& inputs,
-                        vector<Symbol>* out_inputs) {
+                        const std::vector<Symbol>& inputs,
+                        std::vector<Symbol>* out_inputs) {
   if (inputs.empty())
     return;
   if (r.is_suffix_rule) {
@@ -65,7 +64,7 @@ void ApplyOutputPattern(const Rule& r,
   CHECK(r.output_patterns.size() == 1);
   Pattern pat(r.output_patterns[0].str());
   for (Symbol input : inputs) {
-    string buf;
+    std::string buf;
     pat.AppendSubst(output.str(), input.str(), &buf);
     out_inputs->push_back(Intern(buf));
   }
@@ -73,9 +72,9 @@ void ApplyOutputPattern(const Rule& r,
 
 class RuleTrie {
   struct Entry {
-    Entry(const Rule* r, StringPiece s) : rule(r), suffix(s) {}
+    Entry(const Rule* r, std::string_view s) : rule(r), suffix(s) {}
     const Rule* rule;
-    StringPiece suffix;
+    std::string_view suffix;
   };
 
  public:
@@ -85,7 +84,7 @@ class RuleTrie {
       delete p.second;
   }
 
-  void Add(StringPiece name, const Rule* rule) {
+  void Add(std::string_view name, const Rule* rule) {
     if (name.empty() || name[0] == '%') {
       rules_.push_back(Entry(rule, name));
       return;
@@ -98,7 +97,7 @@ class RuleTrie {
     p.first->second->Add(name.substr(1), rule);
   }
 
-  void Get(StringPiece name, vector<const Rule*>* rules) const {
+  void Get(std::string_view name, std::vector<const Rule*>* rules) const {
     for (const Entry& ent : rules_) {
       if ((ent.suffix.empty() && name.empty()) ||
           HasSuffix(name, ent.suffix.substr(1))) {
@@ -121,29 +120,29 @@ class RuleTrie {
   }
 
  private:
-  vector<Entry> rules_;
-  unordered_map<char, RuleTrie*> children_;
+  std::vector<Entry> rules_;
+  std::unordered_map<char, RuleTrie*> children_;
 };
 
 bool IsSuffixRule(Symbol output) {
   if (output.empty() || !IsSpecialTarget(output))
     return false;
-  const StringPiece rest = StringPiece(output.str()).substr(1);
+  const std::string_view rest = std::string_view(output.str()).substr(1);
   size_t dot_index = rest.find('.');
   // If there is only a single dot or the third dot, this is not a
   // suffix rule.
-  if (dot_index == string::npos ||
-      rest.substr(dot_index + 1).find('.') != string::npos) {
+  if (dot_index == std::string::npos ||
+      rest.substr(dot_index + 1).find('.') != std::string::npos) {
     return false;
   }
   return true;
 }
 
 struct RuleMerger {
-  vector<const Rule*> rules;
-  vector<pair<Symbol, RuleMerger*>> implicit_outputs;
-  vector<Symbol> symlink_outputs;
-  vector<Symbol> validations;
+  std::vector<const Rule*> rules;
+  std::vector<std::pair<Symbol, RuleMerger*>> implicit_outputs;
+  std::vector<Symbol> symlink_outputs;
+  std::vector<Symbol> validations;
   const Rule* primary_rule;
   const RuleMerger* parent;
   Symbol parent_sym;
@@ -153,7 +152,7 @@ struct RuleMerger {
       : primary_rule(nullptr), parent(nullptr), is_double_colon(false) {}
 
   void AddImplicitOutput(Symbol output, RuleMerger* merger) {
-    implicit_outputs.push_back(make_pair(output, merger));
+    implicit_outputs.push_back(std::make_pair(output, merger));
   }
 
   void AddSymlinkOutput(Symbol output) { symlink_outputs.push_back(output); }
@@ -292,8 +291,8 @@ DepNode::DepNode(Symbol o, bool p, bool r)
 class DepBuilder {
  public:
   DepBuilder(Evaluator* ev,
-             const vector<const Rule*>& rules,
-             const unordered_map<Symbol, Vars*>& rule_vars)
+             const std::vector<const Rule*>& rules,
+             const std::unordered_map<Symbol, Vars*>& rule_vars)
       : ev_(ev),
         rule_vars_(rule_vars),
         implicit_rules_(new RuleTrie()),
@@ -315,7 +314,7 @@ class DepBuilder {
 
   void HandleSpecialTargets() {
     Loc loc;
-    vector<Symbol> targets;
+    std::vector<Symbol> targets;
 
     if (GetRuleInputs(Intern(".PHONY"), &targets, &loc)) {
       for (Symbol t : targets)
@@ -355,7 +354,7 @@ class DepBuilder {
 
   ~DepBuilder() {}
 
-  void Build(vector<Symbol> targets, vector<NamedDepNode>* nodes) {
+  void Build(std::vector<Symbol> targets, std::vector<NamedDepNode>* nodes) {
     if (!first_rule_.IsValid()) {
       ERROR("*** No targets.");
     }
@@ -402,7 +401,7 @@ class DepBuilder {
            ::Exists(target.str());
   }
 
-  bool GetRuleInputs(Symbol s, vector<Symbol>* o, Loc* l) {
+  bool GetRuleInputs(Symbol s, std::vector<Symbol>* o, Loc* l) {
     auto found = rules_.find(s);
     if (found == rules_.end())
       return false;
@@ -417,7 +416,7 @@ class DepBuilder {
     return true;
   }
 
-  void PopulateRules(const vector<const Rule*>& rules) {
+  void PopulateRules(const std::vector<const Rule*>& rules) {
     for (const Rule* rule : rules) {
       if (rule->outputs.empty()) {
         PopulateImplicitRule(rule);
@@ -435,10 +434,10 @@ class DepBuilder {
       }
       auto var = vars->Lookup(implicit_outputs_var_name_);
       if (var->IsDefined()) {
-        string implicit_outputs;
+        std::string implicit_outputs;
         var->Eval(ev_, &implicit_outputs);
 
-        for (StringPiece output : WordScanner(implicit_outputs)) {
+        for (std::string_view output : WordScanner(implicit_outputs)) {
           Symbol sym = Intern(TrimLeadingCurdir(output));
           rules_[sym].SetImplicitOutput(sym, p.first, &p.second);
           p.second.AddImplicitOutput(sym, &rules_[sym]);
@@ -447,10 +446,10 @@ class DepBuilder {
 
       var = vars->Lookup(validations_var_name_);
       if (var->IsDefined()) {
-        string validations;
+        std::string validations;
         var->Eval(ev_, &validations);
 
-        for (StringPiece validation : WordScanner(validations)) {
+        for (std::string_view validation : WordScanner(validations)) {
           Symbol sym = Intern(TrimLeadingCurdir(validation));
           p.second.AddValidation(sym);
         }
@@ -458,10 +457,10 @@ class DepBuilder {
 
       var = vars->Lookup(symlink_outputs_var_name_);
       if (var->IsDefined()) {
-        string symlink_outputs;
+        std::string symlink_outputs;
         var->Eval(ev_, &symlink_outputs);
 
-        for (StringPiece output : WordScanner(symlink_outputs)) {
+        for (std::string_view output : WordScanner(symlink_outputs)) {
           Symbol sym = Intern(TrimLeadingCurdir(output));
           p.second.AddSymlinkOutput(sym);
         }
@@ -480,12 +479,12 @@ class DepBuilder {
                output.c_str());
     }
 
-    const StringPiece rest = StringPiece(output.str()).substr(1);
+    const std::string_view rest = std::string_view(output.str()).substr(1);
     size_t dot_index = rest.find('.');
 
-    StringPiece input_suffix = rest.substr(0, dot_index);
-    StringPiece output_suffix = rest.substr(dot_index + 1);
-    shared_ptr<Rule> r = make_shared<Rule>(*rule);
+    std::string_view input_suffix = rest.substr(0, dot_index);
+    std::string_view output_suffix = rest.substr(dot_index + 1);
+    std::shared_ptr<Rule> r = std::make_shared<Rule>(*rule);
     r->inputs.clear();
     r->inputs.push_back(Intern(input_suffix));
     r->is_suffix_rule = true;
@@ -512,7 +511,7 @@ class DepBuilder {
       return false;
     if (!rule->cmds.empty())
       return false;
-    const string& i = rule->inputs[0].str();
+    const std::string& i = rule->inputs[0].str();
     return (i == "RCS/%,v" || i == "RCS/%" || i == "%,v" || i == "s.%" ||
             i == "SCCS/s.%");
   }
@@ -551,14 +550,14 @@ class DepBuilder {
   bool CanPickImplicitRule(const Rule* rule,
                            Symbol output,
                            DepNode* n,
-                           shared_ptr<Rule>* out_rule) {
+                           std::shared_ptr<Rule>* out_rule) {
     Symbol matched;
     for (Symbol output_pattern : rule->output_patterns) {
       Pattern pat(output_pattern.str());
       if (pat.Match(output.str())) {
         bool ok = true;
         for (Symbol input : rule->inputs) {
-          string buf;
+          std::string buf;
           pat.AppendSubst(output.str(), input.str(), &buf);
           if (!Exists(Intern(buf))) {
             ok = false;
@@ -575,14 +574,14 @@ class DepBuilder {
     if (!matched.IsValid())
       return false;
 
-    *out_rule = make_shared<Rule>(*rule);
+    *out_rule = std::make_shared<Rule>(*rule);
     if ((*out_rule)->output_patterns.size() > 1) {
       // We should mark all other output patterns as used.
       Pattern pat(matched.str());
       for (Symbol output_pattern : rule->output_patterns) {
         if (output_pattern == matched)
           continue;
-        string buf;
+        std::string buf;
         pat.AppendSubst(output.str(), output_pattern.str(), &buf);
         done_[Intern(buf)] = n;
       }
@@ -610,7 +609,7 @@ class DepBuilder {
   bool PickRule(Symbol output,
                 DepNode* n,
                 const RuleMerger** out_rule_merger,
-                shared_ptr<Rule>* pattern_rule,
+                std::shared_ptr<Rule>* pattern_rule,
                 Vars** out_var) {
     const RuleMerger* rule_merger = LookupRuleMerger(output);
     Vars* vars = LookupRuleVars(output);
@@ -624,7 +623,7 @@ class DepBuilder {
       return true;
     }
 
-    vector<const Rule*> irules;
+    std::vector<const Rule*> irules;
     implicit_rules_->Get(output.str(), &irules);
     for (auto iter = irules.rbegin(); iter != irules.rend(); ++iter) {
       if (!CanPickImplicitRule(*iter, output, n, pattern_rule))
@@ -638,8 +637,8 @@ class DepBuilder {
       return true;
     }
 
-    StringPiece output_suffix = GetExt(output.str());
-    if (output_suffix.get(0) != '.')
+    std::string_view output_suffix = GetExt(output.str());
+    if (output_suffix.empty() || output_suffix.front() != '.')
       return rule_merger != nullptr;
     output_suffix = output_suffix.substr(1);
 
@@ -647,7 +646,7 @@ class DepBuilder {
     if (found == suffix_rules_.end())
       return rule_merger != nullptr;
 
-    for (const shared_ptr<Rule>& irule : found->second) {
+    for (const std::shared_ptr<Rule>& irule : found->second) {
       CHECK(irule->inputs.size() == 1);
       Symbol input = ReplaceSuffix(output, irule->inputs[0]);
       if (!Exists(input))
@@ -683,7 +682,7 @@ class DepBuilder {
     done_[output] = n;
 
     const RuleMerger* rule_merger = nullptr;
-    shared_ptr<Rule> pattern_rule;
+    std::shared_ptr<Rule> pattern_rule;
     Vars* vars;
     if (!PickRule(output, n, &rule_merger, &pattern_rule, &vars)) {
       return n;
@@ -702,7 +701,7 @@ class DepBuilder {
     else
       RuleMerger().FillDepNode(output, pattern_rule.get(), n);
 
-    vector<unique_ptr<ScopedVar>> sv;
+    std::vector<std::unique_ptr<ScopedVar>> sv;
     ScopedFrame frame(ev_->Enter(FrameType::DEPENDENCY, output.str(), n->loc));
 
     if (vars) {
@@ -715,7 +714,7 @@ class DepBuilder {
           Var* old_var = ev_->LookupVar(name);
           if (old_var->IsDefined()) {
             // TODO: This would be incorrect and has a leak.
-            shared_ptr<string> s = make_shared<string>();
+            std::shared_ptr<std::string> s = std::make_shared<std::string>();
             old_var->Eval(ev_, s.get());
             if (!s->empty())
               *s += ' ';
@@ -743,7 +742,7 @@ class DepBuilder {
     }
 
     if (g_flags.warn_phony_looks_real && n->is_phony &&
-        output.str().find('/') != string::npos) {
+        output.str().find('/') != std::string::npos) {
       if (g_flags.werror_phony_looks_real) {
         ERROR_LOC(
             n->loc,
@@ -760,7 +759,7 @@ class DepBuilder {
     if (!g_flags.writable.empty() && !n->is_phony) {
       bool found = false;
       for (const auto& w : g_flags.writable) {
-        if (StringPiece(output.str()).starts_with(w)) {
+        if (HasPrefix(output.str(), w)) {
           found = true;
           break;
         }
@@ -780,7 +779,7 @@ class DepBuilder {
       done_[output] = n;
 
       if (g_flags.warn_phony_looks_real && n->is_phony &&
-          output.str().find('/') != string::npos) {
+          output.str().find('/') != std::string::npos) {
         if (g_flags.werror_phony_looks_real) {
           ERROR_LOC(n->loc,
                     "*** PHONY target \"%s\" looks like a real file (contains "
@@ -797,7 +796,7 @@ class DepBuilder {
       if (!g_flags.writable.empty() && !n->is_phony) {
         bool found = false;
         for (const auto& w : g_flags.writable) {
-          if (StringPiece(output.str()).starts_with(w)) {
+          if (HasPrefix(output.str(), w)) {
             found = true;
             break;
           }
@@ -820,7 +819,7 @@ class DepBuilder {
 
       bool is_phony = c->is_phony;
       if (!is_phony && !c->has_rule && g_flags.top_level_phony) {
-        is_phony = input.str().find('/') == string::npos;
+        is_phony = input.str().find('/') == std::string::npos;
       }
       if (!n->is_phony && is_phony) {
         if (g_flags.werror_real_to_phony) {
@@ -923,16 +922,18 @@ class DepBuilder {
       return lhs.str() < rhs.str();
     }
   };
-  map<Symbol, RuleMerger, TargetComp> rules_;
-  const unordered_map<Symbol, Vars*>& rule_vars_;
-  unique_ptr<Vars> cur_rule_vars_;
-
-  unique_ptr<RuleTrie> implicit_rules_;
-  typedef unordered_map<StringPiece, vector<shared_ptr<Rule>>> SuffixRuleMap;
+  std::map<Symbol, RuleMerger, TargetComp> rules_;
+  const std::unordered_map<Symbol, Vars*>& rule_vars_;
+  std::unique_ptr<Vars> cur_rule_vars_;
+
+  std::unique_ptr<RuleTrie> implicit_rules_;
+  typedef std::unordered_map<std::string_view,
+                             std::vector<std::shared_ptr<Rule>>>
+      SuffixRuleMap;
   SuffixRuleMap suffix_rules_;
 
   Symbol first_rule_;
-  unordered_map<Symbol, DepNode*> done_;
+  std::unordered_map<Symbol, DepNode*> done_;
   SymbolSet phony_;
   SymbolSet restat_;
   Symbol depfile_var_name_;
@@ -943,10 +944,10 @@ class DepBuilder {
 };
 
 void MakeDep(Evaluator* ev,
-             const vector<const Rule*>& rules,
-             const unordered_map<Symbol, Vars*>& rule_vars,
-             const vector<Symbol>& targets,
-             vector<NamedDepNode>* nodes) {
+             const std::vector<const Rule*>& rules,
+             const std::unordered_map<Symbol, Vars*>& rule_vars,
+             const std::vector<Symbol>& targets,
+             std::vector<NamedDepNode>* nodes) {
   DepBuilder db(ev, rules, rule_vars);
   ScopedTimeReporter tr("make dep (build)");
   db.Build(targets, nodes);
diff --git a/src/dep.h b/src/dep.h
index fc1d855..f801ef2 100644
--- a/src/dep.h
+++ b/src/dep.h
@@ -16,11 +16,11 @@
 #define DEP_H_
 
 #include <string>
+#include <string_view>
 #include <unordered_map>
 #include <vector>
 
 #include "loc.h"
-#include "string_piece.h"
 #include "symtab.h"
 
 class Evaluator;
@@ -30,26 +30,26 @@ class Var;
 class Vars;
 class Frame;
 
-typedef pair<Symbol, struct DepNode*> NamedDepNode;
+typedef std::pair<Symbol, struct DepNode*> NamedDepNode;
 
 struct DepNode {
   DepNode(Symbol output, bool is_phony, bool is_restat);
-  string DebugString();
+  std::string DebugString();
 
   Symbol output;
-  vector<Value*> cmds;
-  vector<NamedDepNode> deps;
-  vector<NamedDepNode> order_onlys;
-  vector<NamedDepNode> validations;
+  std::vector<Value*> cmds;
+  std::vector<NamedDepNode> deps;
+  std::vector<NamedDepNode> order_onlys;
+  std::vector<NamedDepNode> validations;
   bool has_rule;
   bool is_default_target;
   bool is_phony;
   bool is_restat;
-  vector<Symbol> implicit_outputs;
-  vector<Symbol> symlink_outputs;
-  vector<Symbol> actual_inputs;
-  vector<Symbol> actual_order_only_inputs;
-  vector<Symbol> actual_validations;
+  std::vector<Symbol> implicit_outputs;
+  std::vector<Symbol> symlink_outputs;
+  std::vector<Symbol> actual_inputs;
+  std::vector<Symbol> actual_order_only_inputs;
+  std::vector<Symbol> actual_validations;
   Vars* rule_vars;
   Var* depfile_var;
   Var* ninja_pool_var;
@@ -58,10 +58,10 @@ struct DepNode {
 };
 
 void MakeDep(Evaluator* ev,
-             const vector<const Rule*>& rules,
-             const unordered_map<Symbol, Vars*>& rule_vars,
-             const vector<Symbol>& targets,
-             vector<NamedDepNode>* nodes);
+             const std::vector<const Rule*>& rules,
+             const std::unordered_map<Symbol, Vars*>& rule_vars,
+             const std::vector<Symbol>& targets,
+             std::vector<NamedDepNode>* nodes);
 
 bool IsSpecialTarget(Symbol output);
 
diff --git a/src/eval.cc b/src/eval.cc
index 7f9dc6f..aacb871 100644
--- a/src/eval.cc
+++ b/src/eval.cc
@@ -177,12 +177,12 @@ Evaluator::Evaluator()
 
   trace_ = g_flags.dump_variable_assignment_trace || g_flags.dump_include_graph;
   assignment_tracefile_ = nullptr;
-  assignment_count_ = 0;
+  assignment_sep_ = "\n";
 }
 
 Evaluator::~Evaluator() {
   if (assignment_tracefile_ != nullptr && assignment_tracefile_ != stderr) {
-    fclose(assignment_tracefile_);
+      fclose(assignment_tracefile_);
   }
 
   // delete vars_;
@@ -237,7 +237,7 @@ void Evaluator::in_toplevel_makefile() {
 
 Var* Evaluator::EvalRHS(Symbol lhs,
                         Value* rhs_v,
-                        StringPiece orig_rhs,
+                        std::string_view orig_rhs,
                         AssignOp op,
                         bool is_override,
                         bool* needs_assign) {
@@ -315,13 +315,13 @@ void Evaluator::EvalAssign(const AssignStmt* stmt) {
     Error("*** empty variable name.");
 
   if (lhs == kKatiReadonlySym) {
-    string rhs;
+    std::string rhs;
     stmt->rhs->Eval(this, &rhs);
     for (auto const& name : WordScanner(rhs)) {
       Var* var = Intern(name).GetGlobalVar();
       if (!var->IsDefined()) {
-        Error(
-            StringPrintf("*** unknown variable: %s", name.as_string().c_str()));
+        Error(StringPrintf("*** unknown variable: %s",
+                           std::string(name).c_str()));
       }
       var->SetReadOnly();
     }
@@ -345,24 +345,25 @@ void Evaluator::EvalAssign(const AssignStmt* stmt) {
   if (stmt->is_final) {
     var->SetReadOnly();
   }
+  TraceVariableAssign(lhs, var);
 }
 
 // With rule broken into
 //   <before_term> <term> <after_term>
 // parses <before_term> into Symbol instances until encountering ':'
 // Returns the remainder of <before_term>.
-static StringPiece ParseRuleTargets(const Loc& loc,
-                                    const StringPiece& before_term,
-                                    vector<Symbol>* targets,
-                                    bool* is_pattern_rule) {
+static std::string_view ParseRuleTargets(const Loc& loc,
+                                         const std::string_view& before_term,
+                                         std::vector<Symbol>* targets,
+                                         bool* is_pattern_rule) {
   size_t pos = before_term.find(':');
-  if (pos == string::npos) {
+  if (pos == std::string::npos) {
     ERROR_LOC(loc, "*** missing separator.");
   }
-  StringPiece targets_string = before_term.substr(0, pos);
+  std::string_view targets_string = before_term.substr(0, pos);
   size_t pattern_rule_count = 0;
   for (auto const& word : WordScanner(targets_string)) {
-    StringPiece target = TrimLeadingCurdir(word);
+    std::string_view target = TrimLeadingCurdir(word);
     targets->push_back(Intern(target));
     if (Rule::IsPatternRule(target)) {
       ++pattern_rule_count;
@@ -377,7 +378,7 @@ static StringPiece ParseRuleTargets(const Loc& loc,
 }
 
 // Strip leading spaces and trailing spaces and colons.
-static string FormatRuleError(const string& before_term) {
+static std::string FormatRuleError(const std::string& before_term) {
   if (before_term.size() == 0) {
     return before_term;
   }
@@ -395,23 +396,24 @@ static string FormatRuleError(const string& before_term) {
 }
 
 void Evaluator::MarkVarsReadonly(Value* vars_list) {
-  string vars_list_string;
+  std::string vars_list_string;
   vars_list->Eval(this, &vars_list_string);
   for (auto const& name : WordScanner(vars_list_string)) {
     Var* var = current_scope_->Lookup(Intern(name));
     if (!var->IsDefined()) {
-      Error(StringPrintf("*** unknown variable: %s", name.as_string().c_str()));
+      Error(
+          StringPrintf("*** unknown variable: %s", std::string(name).c_str()));
     }
     var->SetReadOnly();
   }
 }
 
-void Evaluator::EvalRuleSpecificAssign(const vector<Symbol>& targets,
+void Evaluator::EvalRuleSpecificAssign(const std::vector<Symbol>& targets,
                                        const RuleStmt* stmt,
-                                       const StringPiece& after_targets,
+                                       const std::string_view& after_targets,
                                        size_t separator_pos) {
-  StringPiece var_name;
-  StringPiece rhs_string;
+  std::string_view var_name;
+  std::string_view rhs_string;
   AssignOp assign_op;
   ParseAssignStatement(after_targets, separator_pos, &var_name, &rhs_string,
                        &assign_op);
@@ -427,7 +429,8 @@ void Evaluator::EvalRuleSpecificAssign(const vector<Symbol>& targets,
     if (rhs_string.empty()) {
       rhs = stmt->rhs;
     } else if (stmt->rhs) {
-      StringPiece sep(stmt->sep == RuleStmt::SEP_SEMICOLON ? " ; " : " = ");
+      std::string_view sep(stmt->sep == RuleStmt::SEP_SEMICOLON ? " ; "
+                                                                : " = ");
       rhs = Value::NewExpr(loc_, Value::NewLiteral(rhs_string),
                            Value::NewLiteral(sep), stmt->rhs);
     } else {
@@ -439,8 +442,8 @@ void Evaluator::EvalRuleSpecificAssign(const vector<Symbol>& targets,
       MarkVarsReadonly(rhs);
     } else {
       bool needs_assign;
-      Var* rhs_var = EvalRHS(var_sym, rhs, StringPiece("*TODO*"), assign_op,
-                             false, &needs_assign);
+      Var* rhs_var = EvalRHS(var_sym, rhs, std::string_view("*TODO*"),
+                             assign_op, false, &needs_assign);
       if (needs_assign) {
         bool readonly;
         rhs_var->SetAssignOp(assign_op);
@@ -462,17 +465,17 @@ void Evaluator::EvalRule(const RuleStmt* stmt) {
   loc_ = stmt->loc();
   last_rule_ = NULL;
 
-  const string&& before_term = stmt->lhs->Eval(this);
+  const std::string&& before_term = stmt->lhs->Eval(this);
   // See semicolon.mk.
-  if (before_term.find_first_not_of(" \t\n;") == string::npos) {
+  if (before_term.find_first_not_of(" \t\n;") == std::string::npos) {
     if (stmt->sep == RuleStmt::SEP_SEMICOLON)
       Error("*** missing rule before commands.");
     return;
   }
 
-  vector<Symbol> targets;
+  std::vector<Symbol> targets;
   bool is_pattern_rule;
-  StringPiece after_targets =
+  std::string_view after_targets =
       ParseRuleTargets(loc_, before_term, &targets, &is_pattern_rule);
   bool is_double_colon = (after_targets[0] == ':');
   if (is_double_colon) {
@@ -485,9 +488,9 @@ void Evaluator::EvalRule(const RuleStmt* stmt) {
   // first assignment token.
   size_t separator_pos = after_targets.find_first_of("=;");
   char separator = '\0';
-  if (separator_pos != string::npos) {
+  if (separator_pos != std::string::npos) {
     separator = after_targets[separator_pos];
-  } else if (separator_pos == string::npos &&
+  } else if (separator_pos == std::string::npos &&
              (stmt->sep == RuleStmt::SEP_EQ ||
               stmt->sep == RuleStmt::SEP_FINALEQ)) {
     separator_pos = after_targets.size();
@@ -549,7 +552,7 @@ void Evaluator::EvalCommand(const CommandStmt* stmt) {
   loc_ = stmt->loc();
 
   if (!last_rule_) {
-    vector<Stmt*> stmts;
+    std::vector<Stmt*> stmts;
     ParseNotAfterRule(stmt->orig, stmt->loc(), &stmts);
     for (Stmt* a : stmts)
       a->Eval(this);
@@ -569,7 +572,7 @@ void Evaluator::EvalIf(const IfStmt* stmt) {
   switch (stmt->op) {
     case CondOp::IFDEF:
     case CondOp::IFNDEF: {
-      string var_name;
+      std::string var_name;
       stmt->lhs->Eval(this, &var_name);
       Symbol lhs = Intern(TrimRightSpace(var_name));
       if (const auto& s = lhs.str();
@@ -583,8 +586,8 @@ void Evaluator::EvalIf(const IfStmt* stmt) {
     }
     case CondOp::IFEQ:
     case CondOp::IFNEQ: {
-      const string&& lhs = stmt->lhs->Eval(this);
-      const string&& rhs = stmt->rhs->Eval(this);
+      const std::string&& lhs = stmt->lhs->Eval(this);
+      const std::string&& rhs = stmt->rhs->Eval(this);
       is_true = ((lhs == rhs) == (stmt->op == CondOp::IFEQ));
       break;
     }
@@ -593,7 +596,7 @@ void Evaluator::EvalIf(const IfStmt* stmt) {
       abort();
   }
 
-  const vector<Stmt*>* stmts;
+  const std::vector<Stmt*>* stmts;
   if (is_true) {
     stmts = &stmt->true_stmts;
   } else {
@@ -605,7 +608,7 @@ void Evaluator::EvalIf(const IfStmt* stmt) {
   }
 }
 
-void Evaluator::DoInclude(const string& fname) {
+void Evaluator::DoInclude(const std::string& fname) {
   CheckStack();
   COLLECT_STATS_WITH_SLOW_REPORT("included makefiles", fname.c_str());
 
@@ -632,8 +635,8 @@ void Evaluator::EvalInclude(const IncludeStmt* stmt) {
   loc_ = stmt->loc();
   last_rule_ = NULL;
 
-  const string&& pats = stmt->expr->Eval(this);
-  for (StringPiece pat : WordScanner(pats)) {
+  const std::string&& pats = stmt->expr->Eval(this);
+  for (std::string_view pat : WordScanner(pats)) {
     ScopedTerminator st(pat);
     const auto& files = Glob(pat.data());
 
@@ -646,7 +649,7 @@ void Evaluator::EvalInclude(const IncludeStmt* stmt) {
 
     include_stack_.push_back(stmt->loc());
 
-    for (const string& fname : files) {
+    for (const std::string& fname : files) {
       if (!stmt->should_exist && g_flags.ignore_optional_include_pattern &&
           Pattern(g_flags.ignore_optional_include_pattern).Match(fname)) {
         continue;
@@ -665,11 +668,11 @@ void Evaluator::EvalExport(const ExportStmt* stmt) {
   loc_ = stmt->loc();
   last_rule_ = NULL;
 
-  const string&& exports = stmt->expr->Eval(this);
-  for (StringPiece tok : WordScanner(exports)) {
+  const std::string&& exports = stmt->expr->Eval(this);
+  for (std::string_view tok : WordScanner(exports)) {
     size_t equal_index = tok.find('=');
-    StringPiece lhs;
-    if (equal_index == string::npos) {
+    std::string_view lhs;
+    if (equal_index == std::string::npos) {
       lhs = tok;
     } else if (equal_index == 0 ||
                (equal_index == 1 &&
@@ -677,7 +680,7 @@ void Evaluator::EvalExport(const ExportStmt* stmt) {
       // Do not export tokens after an assignment.
       break;
     } else {
-      StringPiece rhs;
+      std::string_view rhs;
       AssignOp op;
       ParseAssignStatement(tok, equal_index, &lhs, &rhs, &op);
     }
@@ -709,35 +712,70 @@ Var* Evaluator::LookupVarGlobal(Symbol name) {
   return v;
 }
 
-void Evaluator::TraceVariableLookup(const char* operation,
-                                    Symbol name,
-                                    Var* var) {
+bool Evaluator::IsTraced(Symbol& name) const {
   if (assignment_tracefile_ == nullptr) {
-    return;
+    return false;
   }
 
-  if (assignment_count_++ == 0) {
-    fprintf(assignment_tracefile_, "\n");
-  } else {
-    fprintf(assignment_tracefile_, ",\n");
+  bool trace_var = g_flags.traced_variables_pattern.size() == 0;
+  // trace every variable unless filtered
+  if (trace_var) {
+    return true;
   }
 
-  bool has_definition_trace = var->Definition() != nullptr;
-  fprintf(assignment_tracefile_, "    {\n");
-  fprintf(assignment_tracefile_, "      \"name\": \"%s\",\n", name.c_str());
-  fprintf(assignment_tracefile_, "      \"operation\": \"%s\",\n", operation);
-  fprintf(assignment_tracefile_, "      \"defined\": %s,\n",
-          var->IsDefined() ? "true" : "false");
+  for (const auto& pat : g_flags.traced_variables_pattern) {
+    if (pat.Match(name.c_str())) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void Evaluator::TraceVariableLookup(const char* operation,
+                                    Symbol& name,
+                                    Var* var) {
+  if (!IsTraced(name)) {
+    return;
+  }
+
+  fputs(assignment_sep_, assignment_tracefile_);
+  assignment_sep_ = ",\n";
+  fprintf(assignment_tracefile_,
+          "    {\n"
+          "      \"name\": \"%s\",\n"
+          "      \"operation\": \"%s\",\n"
+          "      \"defined\": %s,\n",
+          name.c_str(), operation, var->IsDefined() ? "true" : "false");
   fprintf(assignment_tracefile_, "      \"reference_stack\": [\n");
   CurrentFrame()->PrintJSONTrace(assignment_tracefile_, 8);
-  fprintf(assignment_tracefile_, "      ]%s\n",
-          has_definition_trace ? "," : "");
-  if (has_definition_trace) {
-    fprintf(assignment_tracefile_, "      \"value_stack\": [\n");
-    var->Definition()->PrintJSONTrace(assignment_tracefile_, 8);
-    fprintf(assignment_tracefile_, "      ]\n");
+  fprintf(assignment_tracefile_,
+          "      ]\n"
+          "    }");
+}
+
+void Evaluator::TraceVariableAssign(Symbol& name, Var* var) {
+  if (!IsTraced(name)) {
+    return;
   }
-  fprintf(assignment_tracefile_, "    }");
+  fputs(assignment_sep_, assignment_tracefile_);
+  assignment_sep_ = ",\n";
+  fprintf(assignment_tracefile_,
+          "    {\n"
+          "      \"name\": \"%s\",\n"
+          "      \"operation\": \"assign\",\n"
+          "      \"value\": \"%s\"",
+          name.c_str(), var->DebugString().c_str());
+  Frame* definition = var->Definition();
+  if (definition != nullptr) {
+    fprintf(assignment_tracefile_,
+            ",\n"
+            "      \"value_stack\": [\n");
+    definition->PrintJSONTrace(assignment_tracefile_, 8);
+    fprintf(assignment_tracefile_, "      ]");
+  }
+  fprintf(assignment_tracefile_,
+          "\n"
+          "    }");
 }
 
 Var* Evaluator::LookupVarForEval(Symbol name) {
@@ -806,12 +844,12 @@ Var* Evaluator::PeekVarInCurrentScope(Symbol name) {
   return result;
 }
 
-string Evaluator::EvalVar(Symbol name) {
+std::string Evaluator::EvalVar(Symbol name) {
   return LookupVar(name)->Eval(this);
 }
 
 ScopedFrame Evaluator::Enter(FrameType frame_type,
-                             const string& name,
+                             const std::string& name,
                              Loc loc) {
   if (!trace_) {
     return ScopedFrame(this, nullptr);
@@ -821,24 +859,24 @@ ScopedFrame Evaluator::Enter(FrameType frame_type,
   return ScopedFrame(this, frame);
 }
 
-string Evaluator::GetShell() {
+std::string Evaluator::GetShell() {
   return EvalVar(kShellSym);
 }
 
-string Evaluator::GetShellFlag() {
+std::string Evaluator::GetShellFlag() {
   // TODO: Handle $(.SHELLFLAGS)
   return is_posix_ ? "-ec" : "-c";
 }
 
-string Evaluator::GetShellAndFlag() {
-  string shell = GetShell();
+std::string Evaluator::GetShellAndFlag() {
+  std::string shell = GetShell();
   shell += ' ';
   shell += GetShellFlag();
   return shell;
 }
 
 RulesAllowed Evaluator::GetAllowRules() {
-  string val = EvalVar(kAllowRulesSym);
+  std::string val = EvalVar(kAllowRulesSym);
   if (val == "warning") {
     return RULES_WARNING;
   } else if (val == "error") {
@@ -854,7 +892,7 @@ void Evaluator::PrintIncludeStack() {
   }
 }
 
-void Evaluator::Error(const string& msg) {
+void Evaluator::Error(const std::string& msg) {
   PrintIncludeStack();
   ERROR_LOC(loc_, "%s", msg.c_str());
 }
@@ -865,7 +903,7 @@ void Evaluator::DumpStackStats() const {
            LOCF(lowest_loc_));
 }
 
-void Evaluator::DumpIncludeJSON(const string& filename) const {
+void Evaluator::DumpIncludeJSON(const std::string& filename) const {
   IncludeGraph graph;
   graph.MergeTreeNode(stack_.front());
   FILE* jsonfile;
diff --git a/src/eval.h b/src/eval.h
index 75038ef..6c4199f 100644
--- a/src/eval.h
+++ b/src/eval.h
@@ -18,17 +18,15 @@
 #include <map>
 #include <memory>
 #include <set>
+#include <string_view>
 #include <unordered_map>
 #include <unordered_set>
 #include <vector>
 
 #include "loc.h"
 #include "stmt.h"
-#include "string_piece.h"
 #include "symtab.h"
 
-using namespace std;
-
 class Makefile;
 class Rule;
 class Var;
@@ -59,7 +57,7 @@ class Frame {
 
   FrameType Type() const { return type_; }
   Frame* Parent() const { return parent_; }
-  const string& Name() const { return name_; }
+  const std::string& Name() const { return name_; }
   const Loc& Location() const { return location_; }
   const std::vector<std::unique_ptr<Frame>>& Children() const {
     return children_;
@@ -144,17 +142,19 @@ class Evaluator {
   // Equivalent to LookupVar, but doesn't mark as used.
   Var* PeekVar(Symbol name);
 
-  string EvalVar(Symbol name);
+  std::string EvalVar(Symbol name);
 
   const Loc& loc() const { return loc_; }
   void set_loc(const Loc& loc) { loc_ = loc; }
 
-  const vector<const Rule*>& rules() const { return rules_; }
-  const unordered_map<Symbol, Vars*>& rule_vars() const { return rule_vars_; }
-  const unordered_map<Symbol, bool>& exports() const { return exports_; }
+  const std::vector<const Rule*>& rules() const { return rules_; }
+  const std::unordered_map<Symbol, Vars*>& rule_vars() const {
+    return rule_vars_;
+  }
+  const std::unordered_map<Symbol, bool>& exports() const { return exports_; }
 
   void PrintIncludeStack();
-  void Error(const string& msg);
+  void Error(const std::string& msg);
 
   void in_bootstrap();
   void in_command_line();
@@ -165,10 +165,10 @@ class Evaluator {
   bool avoid_io() const { return avoid_io_; }
   void set_avoid_io(bool a) { avoid_io_ = a; }
 
-  const vector<string>& delayed_output_commands() const {
+  const std::vector<std::string>& delayed_output_commands() const {
     return delayed_output_commands_;
   }
-  void add_delayed_output_command(const string& c) {
+  void add_delayed_output_command(const std::string& c) {
     delayed_output_commands_.push_back(c);
   }
   void clear_delayed_output_commands() { delayed_output_commands_.clear(); }
@@ -179,14 +179,14 @@ class Evaluator {
   void IncrementEvalDepth() { eval_depth_++; }
   void DecrementEvalDepth() { eval_depth_--; }
 
-  ScopedFrame Enter(FrameType frame_type, const string& name, Loc loc);
+  ScopedFrame Enter(FrameType frame_type, const std::string& name, Loc loc);
   Frame* CurrentFrame() const {
     return stack_.empty() ? nullptr : stack_.back();
   };
 
-  string GetShell();
-  string GetShellFlag();
-  string GetShellAndFlag();
+  std::string GetShell();
+  std::string GetShellFlag();
+  std::string GetShellAndFlag();
 
   // Parse the current value of .KATI_ALLOW_RULES
   RulesAllowed GetAllowRules();
@@ -200,20 +200,20 @@ class Evaluator {
   }
 
   void DumpStackStats() const;
-  void DumpIncludeJSON(const string& filename) const;
+  void DumpIncludeJSON(const std::string& filename) const;
 
   bool ExportDeprecated() const { return export_message_ && !export_error_; };
   bool ExportObsolete() const { return export_error_; };
-  void SetExportDeprecated(StringPiece msg) {
-    export_message_.reset(new string(msg.as_string()));
+  void SetExportDeprecated(std::string_view msg) {
+    export_message_.reset(new std::string(msg));
   }
-  void SetExportObsolete(StringPiece msg) {
-    export_message_.reset(new string(msg.as_string()));
+  void SetExportObsolete(std::string_view msg) {
+    export_message_.reset(new std::string(msg));
     export_error_ = true;
   }
 
-  void ProfileMakefile(StringPiece mk) {
-    profiled_files_.emplace_back(mk.as_string());
+  void ProfileMakefile(std::string_view mk) {
+    profiled_files_.emplace_back(std::string(mk));
   }
 
   bool IsEvaluatingCommand() const;
@@ -222,13 +222,15 @@ class Evaluator {
  private:
   Var* EvalRHS(Symbol lhs,
                Value* rhs,
-               StringPiece orig_rhs,
+               std::string_view orig_rhs,
                AssignOp op,
                bool is_override,
                bool* needs_assign);
-  void DoInclude(const string& fname);
+  void DoInclude(const std::string& fname);
 
-  void TraceVariableLookup(const char* operation, Symbol name, Var* var);
+  bool IsTraced(Symbol& name) const;
+  void TraceVariableLookup(const char* operation, Symbol& name, Var* var);
+  void TraceVariableAssign(Symbol& name, Var* var);
   Var* LookupVarGlobal(Symbol name);
 
   // Equivalent to LookupVarInCurrentScope, but doesn't mark as used.
@@ -236,14 +238,14 @@ class Evaluator {
 
   void MarkVarsReadonly(Value* var_list);
 
-  void EvalRuleSpecificAssign(const vector<Symbol>& targets,
+  void EvalRuleSpecificAssign(const std::vector<Symbol>& targets,
                               const RuleStmt* stmt,
-                              const StringPiece& lhs_string,
+                              const std::string_view& lhs_string,
                               size_t separator_pos);
 
-  unordered_map<Symbol, Vars*> rule_vars_;
-  vector<const Rule*> rules_;
-  unordered_map<Symbol, bool> exports_;
+  std::unordered_map<Symbol, Vars*> rule_vars_;
+  std::vector<const Rule*> rules_;
+  std::unordered_map<Symbol, bool> exports_;
   std::set<Symbol> symbols_for_eval_;
 
   Rule* last_rule_;
@@ -256,7 +258,7 @@ class Evaluator {
   bool trace_;
   std::vector<Frame*> stack_;
   FILE* assignment_tracefile_;
-  long int assignment_count_;
+  const char* assignment_sep_;
 
   std::vector<Loc> include_stack_;
 
@@ -267,7 +269,7 @@ class Evaluator {
   int eval_depth_;
   // Commands which should run at ninja-time (i.e., info, warning, and
   // error).
-  vector<string> delayed_output_commands_;
+  std::vector<std::string> delayed_output_commands_;
 
   Symbol posix_sym_;
   bool is_posix_;
@@ -277,10 +279,10 @@ class Evaluator {
   void* lowest_stack_;
   Loc lowest_loc_;
 
-  unique_ptr<string> export_message_;
+  std::unique_ptr<std::string> export_message_;
   bool export_error_;
 
-  vector<string> profiled_files_;
+  std::vector<std::string> profiled_files_;
 
   static SymbolSet used_undefined_vars_;
 
diff --git a/src/exec.cc b/src/exec.cc
index 40f37dc..000caa2 100644
--- a/src/exec.cc
+++ b/src/exec.cc
@@ -21,6 +21,7 @@
 #include <sys/wait.h>
 
 #include <memory>
+#include <string_view>
 #include <unordered_map>
 #include <utility>
 #include <vector>
@@ -32,7 +33,6 @@
 #include "fileutil.h"
 #include "flags.h"
 #include "log.h"
-#include "string_piece.h"
 #include "strutil.h"
 #include "symtab.h"
 #include "var.h"
@@ -105,7 +105,7 @@ class Executor {
         fflush(stdout);
       }
       if (!g_flags.is_dry_run) {
-        string out;
+        std::string out;
         int result = RunCommand(shell_, shellflag_, command.cmd.c_str(),
                                 RedirectStderr::STDOUT, &out);
         printf("%s", out.c_str());
@@ -130,15 +130,15 @@ class Executor {
 
  private:
   CommandEvaluator ce_;
-  unordered_map<Symbol, double> done_;
-  string shell_;
-  string shellflag_;
+  std::unordered_map<Symbol, double> done_;
+  std::string shell_;
+  std::string shellflag_;
   uint64_t num_commands_;
 };
 
 }  // namespace
 
-void Exec(const vector<NamedDepNode>& roots, Evaluator* ev) {
+void Exec(const std::vector<NamedDepNode>& roots, Evaluator* ev) {
   Executor executor(ev);
   for (auto const& root : roots) {
     executor.ExecNode(*root.second, nullptr);
diff --git a/src/exec.h b/src/exec.h
index 34fda96..3b74ba4 100644
--- a/src/exec.h
+++ b/src/exec.h
@@ -17,10 +17,9 @@
 
 #include <vector>
 
-using namespace std;
 #include "dep.h"
 class Evaluator;
 
-void Exec(const vector<NamedDepNode>& roots, Evaluator* ev);
+void Exec(const std::vector<NamedDepNode>& roots, Evaluator* ev);
 
 #endif  // EXEC_H_
diff --git a/src/expr.cc b/src/expr.cc
index 40e7b7d..41b60bb 100644
--- a/src/expr.cc
+++ b/src/expr.cc
@@ -29,8 +29,8 @@ Evaluable::Evaluable(const Loc& loc) : loc_(loc) {}
 
 Evaluable::~Evaluable() {}
 
-string Evaluable::Eval(Evaluator* ev) const {
-  string s;
+std::string Evaluable::Eval(Evaluator* ev) const {
+  std::string s;
   Eval(ev, &s);
   return s;
 }
@@ -39,30 +39,30 @@ Value::Value(const Loc& loc) : Evaluable(loc) {}
 
 Value::~Value() {}
 
-string Value::DebugString(const Value* v) {
+std::string Value::DebugString(const Value* v) {
   return v ? NoLineBreak(v->DebugString_()) : "(null)";
 }
 
 class Literal : public Value {
  public:
-  explicit Literal(StringPiece s) : Value(Loc()), s_(s) {}
+  explicit Literal(std::string_view s) : Value(Loc()), s_(s) {}
 
-  StringPiece val() const { return s_; }
+  std::string_view val() const { return s_; }
 
   virtual bool IsFunc(Evaluator*) const override { return false; }
 
-  virtual void Eval(Evaluator* ev, string* s) const override {
+  virtual void Eval(Evaluator* ev, std::string* s) const override {
     ev->CheckStack();
     s->append(s_.begin(), s_.end());
   }
 
   virtual bool IsLiteral() const override { return true; }
-  virtual StringPiece GetLiteralValueUnsafe() const override { return s_; }
+  virtual std::string_view GetLiteralValueUnsafe() const override { return s_; }
 
-  virtual string DebugString_() const override { return s_.as_string(); }
+  virtual std::string DebugString_() const override { return std::string(s_); }
 
  private:
-  StringPiece s_;
+  std::string_view s_;
 };
 
 class ValueList : public Value {
@@ -82,7 +82,7 @@ class ValueList : public Value {
     vals_.push_back(v2);
   }
 
-  ValueList(const Loc& loc, vector<Value*>* values) : ValueList(loc) {
+  ValueList(const Loc& loc, std::vector<Value*>* values) : ValueList(loc) {
     values->shrink_to_fit();
     values->swap(vals_);
   }
@@ -102,15 +102,15 @@ class ValueList : public Value {
     return false;
   }
 
-  virtual void Eval(Evaluator* ev, string* s) const override {
+  virtual void Eval(Evaluator* ev, std::string* s) const override {
     ev->CheckStack();
     for (Value* v : vals_) {
       v->Eval(ev, s);
     }
   }
 
-  virtual string DebugString_() const override {
-    string r;
+  virtual std::string DebugString_() const override {
+    std::string r;
     for (Value* v : vals_) {
       if (r.empty()) {
         r += "ValueList(";
@@ -125,7 +125,7 @@ class ValueList : public Value {
   }
 
  private:
-  vector<Value*> vals_;
+  std::vector<Value*> vals_;
 };
 
 class SymRef : public Value {
@@ -141,7 +141,7 @@ class SymRef : public Value {
     return IsInteger(name_.str());
   }
 
-  virtual void Eval(Evaluator* ev, string* s) const override {
+  virtual void Eval(Evaluator* ev, std::string* s) const override {
     ev->CheckStack();
     Var* v = ev->LookupVarForEval(name_);
     v->Used(ev, name_);
@@ -149,7 +149,7 @@ class SymRef : public Value {
     ev->VarEvalComplete(name_);
   }
 
-  virtual string DebugString_() const override {
+  virtual std::string DebugString_() const override {
     return StringPrintf("SymRef(%s)", name_.c_str());
   }
 
@@ -167,10 +167,10 @@ class VarRef : public Value {
     return true;
   }
 
-  virtual void Eval(Evaluator* ev, string* s) const override {
+  virtual void Eval(Evaluator* ev, std::string* s) const override {
     ev->CheckStack();
     ev->IncrementEvalDepth();
-    const string&& name = name_->Eval(ev);
+    const std::string&& name = name_->Eval(ev);
     ev->DecrementEvalDepth();
     Symbol sym = Intern(name);
     Var* v = ev->LookupVarForEval(sym);
@@ -179,7 +179,7 @@ class VarRef : public Value {
     ev->VarEvalComplete(sym);
   }
 
-  virtual string DebugString_() const override {
+  virtual std::string DebugString_() const override {
     return StringPrintf("VarRef(%s)", Value::DebugString(name_).c_str());
   }
 
@@ -201,26 +201,26 @@ class VarSubst : public Value {
     return name_->IsFunc(ev) || pat_->IsFunc(ev) || subst_->IsFunc(ev);
   }
 
-  virtual void Eval(Evaluator* ev, string* s) const override {
+  virtual void Eval(Evaluator* ev, std::string* s) const override {
     ev->CheckStack();
     ev->IncrementEvalDepth();
-    const string&& name = name_->Eval(ev);
+    const std::string&& name = name_->Eval(ev);
     Symbol sym = Intern(name);
     Var* v = ev->LookupVar(sym);
-    const string&& pat_str = pat_->Eval(ev);
-    const string&& subst = subst_->Eval(ev);
+    const std::string&& pat_str = pat_->Eval(ev);
+    const std::string&& subst = subst_->Eval(ev);
     ev->DecrementEvalDepth();
     v->Used(ev, sym);
-    const string&& value = v->Eval(ev);
+    const std::string&& value = v->Eval(ev);
     WordWriter ww(s);
     Pattern pat(pat_str);
-    for (StringPiece tok : WordScanner(value)) {
+    for (std::string_view tok : WordScanner(value)) {
       ww.MaybeAddWhitespace();
       pat.AppendSubstRef(tok, subst, s);
     }
   }
 
-  virtual string DebugString_() const override {
+  virtual std::string DebugString_() const override {
     return StringPrintf("VarSubst(%s:%s=%s)", Value::DebugString(name_).c_str(),
                         Value::DebugString(pat_).c_str(),
                         Value::DebugString(subst_).c_str());
@@ -243,7 +243,7 @@ class Func : public Value {
 
   virtual bool IsFunc(Evaluator*) const override { return true; }
 
-  virtual void Eval(Evaluator* ev, string* s) const override {
+  virtual void Eval(Evaluator* ev, std::string* s) const override {
     ScopedFrame frame(ev->Enter(FrameType::FUNCALL, fi_->name, Location()));
     ev->CheckStack();
     LOG("Invoke func %s(%s)", name(), JoinValues(args_, ",").c_str());
@@ -252,7 +252,7 @@ class Func : public Value {
     ev->DecrementEvalDepth();
   }
 
-  virtual string DebugString_() const override {
+  virtual std::string DebugString_() const override {
     return StringPrintf("Func(%s %s)", fi_->name,
                         JoinValues(args_, ",").c_str());
   }
@@ -267,7 +267,7 @@ class Func : public Value {
 
  private:
   const FuncInfo* fi_;
-  vector<Value*> args_;
+  std::vector<Value*> args_;
 };
 
 static char CloseParen(char c) {
@@ -280,7 +280,7 @@ static char CloseParen(char c) {
   return 0;
 }
 
-static size_t SkipSpaces(Loc* loc, StringPiece s, const char* terms) {
+static size_t SkipSpaces(Loc* loc, std::string_view s, const char* terms) {
   for (size_t i = 0; i < s.size(); i++) {
     char c = s[i];
     if (strchr(terms, c)) {
@@ -292,7 +292,7 @@ static size_t SkipSpaces(Loc* loc, StringPiece s, const char* terms) {
         return i;
       }
 
-      char n = s.get(i + 1);
+      char n = i + 1 < s.size() ? s[i + 1] : 0;
       if (n != '\r' && n != '\n') {
         return i;
       }
@@ -311,7 +311,7 @@ Value* Value::NewExpr(const Loc& loc, Value* v1, Value* v2, Value* v3) {
   return new ValueList(loc, v1, v2, v3);
 }
 
-Value* Value::NewExpr(const Loc& loc, vector<Value*>* values) {
+Value* Value::NewExpr(const Loc& loc, std::vector<Value*>* values) {
   if (values->size() == 1) {
     Value* v = (*values)[0];
     values->clear();
@@ -320,7 +320,7 @@ Value* Value::NewExpr(const Loc& loc, vector<Value*>* values) {
   return new ValueList(loc, values);
 }
 
-Value* Value::NewLiteral(StringPiece s) {
+Value* Value::NewLiteral(std::string_view s) {
   return new Literal(s);
 }
 
@@ -330,7 +330,7 @@ bool ShouldHandleComments(ParseExprOpt opt) {
 
 void ParseFunc(Loc* loc,
                Func* f,
-               StringPiece s,
+               std::string_view s,
                size_t i,
                char* terms,
                size_t* index_out) {
@@ -356,7 +356,7 @@ void ParseFunc(Loc* loc,
         }
 
         if (s[i] == '\\') {
-          char c = s.get(i + 1);
+          char c = i + 1 < s.size() ? s[i + 1] : 0;
           if (c == '\r' || c == '\n') {
             loc->lineno++;
             continue;
@@ -401,7 +401,7 @@ void ParseFunc(Loc* loc,
   return;
 }
 
-Value* ParseDollar(Loc* loc, StringPiece s, size_t* index_out) {
+Value* ParseDollar(Loc* loc, std::string_view s, size_t* index_out) {
   CHECK(s.size() >= 2);
   CHECK(s[0] == '$');
   CHECK(s[1] != '$');
@@ -427,7 +427,7 @@ Value* ParseDollar(Loc* loc, StringPiece s, size_t* index_out) {
         Symbol sym = Intern(lit->val());
         if (g_flags.enable_kati_warnings) {
           size_t found = sym.str().find_first_of(" ({");
-          if (found != string::npos) {
+          if (found != std::string::npos) {
             KATI_WARN_LOC(start_loc,
                           "*warning*: variable lookup with '%c': %.*s",
                           sym.str()[found], SPF(s));
@@ -489,7 +489,7 @@ Value* ParseDollar(Loc* loc, StringPiece s, size_t* index_out) {
     // GNU make accepts expressions like $((). See unmatched_paren*.mk
     // for detail.
     size_t found = s.find(cp);
-    if (found != string::npos) {
+    if (found != std::string::npos) {
       KATI_WARN_LOC(start_loc, "*warning*: unmatched parentheses: %.*s",
                     SPF(s));
       *index_out = s.size();
@@ -500,21 +500,21 @@ Value* ParseDollar(Loc* loc, StringPiece s, size_t* index_out) {
 }
 
 Value* ParseExprImpl(Loc* loc,
-                     StringPiece s,
+                     std::string_view s,
                      const char* terms,
                      ParseExprOpt opt,
                      size_t* index_out,
                      bool trim_right_space) {
   Loc list_loc = *loc;
 
-  if (s.get(s.size() - 1) == '\r')
+  if (!s.empty() && s.back() == '\r')
     s.remove_suffix(1);
 
   size_t b = 0;
   char save_paren = 0;
   int paren_depth = 0;
   size_t i;
-  vector<Value*> list;
+  std::vector<Value*> list;
   for (i = 0; i < s.size(); i++) {
     Loc item_loc = *loc;
 
@@ -544,14 +544,14 @@ Value* ParseExprImpl(Loc* loc,
         list.push_back(new Literal(s.substr(b, i - b)));
 
       if (s[i + 1] == '$') {
-        list.push_back(new Literal(StringPiece("$")));
+        list.push_back(new Literal(std::string_view("$")));
         i += 1;
         b = i + 1;
         continue;
       }
 
       if (terms && strchr(terms, s[i + 1])) {
-        list.push_back(new Literal(StringPiece("$")));
+        list.push_back(new Literal(std::string_view("$")));
         *index_out = i + 1;
         return Value::NewExpr(item_loc, &list);
       }
@@ -604,15 +604,16 @@ Value* ParseExprImpl(Loc* loc,
         if (i > b) {
           list.push_back(new Literal(TrimRightSpace(s.substr(b, i - b))));
         }
-        list.push_back(new Literal(StringPiece(" ")));
+        list.push_back(new Literal(std::string_view(" ")));
         // Skip the current escaped newline
         i += 2;
-        if (n == '\r' && s.get(i) == '\n') {
+        if (n == '\r' && i < s.size() && s[i] == '\n') {
           i++;
         }
         // Then continue skipping escaped newlines, spaces, and tabs
         for (; i < s.size(); i++) {
-          if (s[i] == '\\' && (s.get(i + 1) == '\r' || s.get(i + 1) == '\n')) {
+          if (s[i] == '\\' && i + 1 < s.size() &&
+              (s[i + 1] == '\r' || s[i + 1] == '\n')) {
             loc->lineno++;
             i++;
             continue;
@@ -628,7 +629,7 @@ Value* ParseExprImpl(Loc* loc,
   }
 
   if (i > b) {
-    StringPiece rest = s.substr(b, i - b);
+    std::string_view rest = s.substr(b, i - b);
     if (trim_right_space)
       rest = TrimRightSpace(rest);
     if (!rest.empty())
@@ -638,13 +639,13 @@ Value* ParseExprImpl(Loc* loc,
   return Value::NewExpr(list_loc, &list);
 }
 
-Value* ParseExpr(Loc* loc, StringPiece s, ParseExprOpt opt) {
+Value* ParseExpr(Loc* loc, std::string_view s, ParseExprOpt opt) {
   size_t n;
   return ParseExprImpl(loc, s, NULL, opt, &n);
 }
 
-string JoinValues(const vector<Value*>& vals, const char* sep) {
-  vector<string> val_strs;
+std::string JoinValues(const std::vector<Value*>& vals, const char* sep) {
+  std::vector<std::string> val_strs;
   val_strs.reserve(vals.size());
   for (Value* v : vals) {
     val_strs.push_back(Value::DebugString(v));
diff --git a/src/expr.h b/src/expr.h
index a731077..b57018f 100644
--- a/src/expr.h
+++ b/src/expr.h
@@ -16,19 +16,17 @@
 #define EXPR_H_
 
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "loc.h"
-#include "string_piece.h"
-
-using namespace std;
 
 class Evaluator;
 
 class Evaluable {
  public:
-  virtual void Eval(Evaluator* ev, string* s) const = 0;
-  string Eval(Evaluator*) const;
+  virtual void Eval(Evaluator* ev, std::string* s) const = 0;
+  std::string Eval(Evaluator*) const;
   const Loc& Location() const { return loc_; }
   // Whether this Evaluable is either knowably a function (e.g. one of the
   // built-ins) or likely to be a function-type macro (i.e. one that has
@@ -55,19 +53,19 @@ class Value : public Evaluable {
   // All NewExpr calls take ownership of the Value instances.
   static Value* NewExpr(const Loc& loc, Value* v1, Value* v2);
   static Value* NewExpr(const Loc& loc, Value* v1, Value* v2, Value* v3);
-  static Value* NewExpr(const Loc& loc, vector<Value*>* values);
+  static Value* NewExpr(const Loc& loc, std::vector<Value*>* values);
 
-  static Value* NewLiteral(StringPiece s);
+  static Value* NewLiteral(std::string_view s);
   virtual ~Value();
   virtual bool IsLiteral() const { return false; }
   // Only safe after IsLiteral() returns true.
-  virtual StringPiece GetLiteralValueUnsafe() const { return ""; }
+  virtual std::string_view GetLiteralValueUnsafe() const { return ""; }
 
-  static string DebugString(const Value*);
+  static std::string DebugString(const Value*);
 
  protected:
   Value(const Loc& loc);
-  virtual string DebugString_() const = 0;
+  virtual std::string DebugString_() const = 0;
 };
 
 enum struct ParseExprOpt {
@@ -78,15 +76,15 @@ enum struct ParseExprOpt {
 };
 
 Value* ParseExprImpl(Loc* loc,
-                     StringPiece s,
+                     std::string_view s,
                      const char* terms,
                      ParseExprOpt opt,
                      size_t* index_out,
                      bool trim_right_space = false);
 Value* ParseExpr(Loc* loc,
-                 StringPiece s,
+                 std::string_view s,
                  ParseExprOpt opt = ParseExprOpt::NORMAL);
 
-string JoinValues(const vector<Value*>& vals, const char* sep);
+std::string JoinValues(const std::vector<Value*>& vals, const char* sep);
 
 #endif  // EXPR_H_
diff --git a/src/file.cc b/src/file.cc
index 9ef6708..43eacbc 100644
--- a/src/file.cc
+++ b/src/file.cc
@@ -26,7 +26,7 @@
 #include "parser.h"
 #include "stmt.h"
 
-Makefile::Makefile(const string& filename)
+Makefile::Makefile(const std::string& filename)
     : mtime_(0), filename_(filename), exists_(false) {
   int fd = open(filename.c_str(), O_RDONLY);
   if (fd < 0) {
diff --git a/src/file.h b/src/file.h
index 6af6696..757d7e7 100644
--- a/src/file.h
+++ b/src/file.h
@@ -20,28 +20,26 @@
 #include <string>
 #include <vector>
 
-using namespace std;
-
 struct Stmt;
 
 class Makefile {
  public:
-  explicit Makefile(const string& filename);
+  explicit Makefile(const std::string& filename);
   ~Makefile();
 
-  const string& buf() const { return buf_; }
-  const string& filename() const { return filename_; }
+  const std::string& buf() const { return buf_; }
+  const std::string& filename() const { return filename_; }
 
-  const vector<Stmt*>& stmts() const { return stmts_; }
-  vector<Stmt*>* mutable_stmts() { return &stmts_; }
+  const std::vector<Stmt*>& stmts() const { return stmts_; }
+  std::vector<Stmt*>* mutable_stmts() { return &stmts_; }
 
   bool Exists() const { return exists_; }
 
  private:
-  string buf_;
+  std::string buf_;
   uint64_t mtime_;
-  string filename_;
-  vector<Stmt*> stmts_;
+  std::string filename_;
+  std::vector<Stmt*> stmts_;
   bool exists_;
 };
 
diff --git a/src/file_cache.cc b/src/file_cache.cc
index eb64a42..d0b4ea5 100644
--- a/src/file_cache.cc
+++ b/src/file_cache.cc
@@ -14,11 +14,10 @@
 
 // +build ignore
 
-#include "file_cache.h"
-
 #include <unordered_map>
 
 #include "file.h"
+#include "file_cache.h"
 
 MakefileCacheManager::MakefileCacheManager() = default;
 
@@ -26,7 +25,7 @@ MakefileCacheManager::~MakefileCacheManager() = default;
 
 class MakefileCacheManagerImpl : public MakefileCacheManager {
  public:
-  virtual const Makefile& ReadMakefile(const string& filename) override {
+  virtual const Makefile& ReadMakefile(const std::string& filename) override {
     auto iter = cache_.find(filename);
     if (iter != cache_.end()) {
       return iter->second;
@@ -34,13 +33,13 @@ class MakefileCacheManagerImpl : public MakefileCacheManager {
     return (cache_.emplace(filename, filename).first)->second;
   }
 
-  virtual void GetAllFilenames(unordered_set<string>* out) override {
+  virtual void GetAllFilenames(std::unordered_set<std::string>* out) override {
     for (const auto& p : cache_)
       out->insert(p.first);
   }
 
  private:
-  unordered_map<string, Makefile> cache_;
+  std::unordered_map<std::string, Makefile> cache_;
 };
 
 MakefileCacheManager& MakefileCacheManager::Get() {
diff --git a/src/file_cache.h b/src/file_cache.h
index 2dca448..ce1cd9c 100644
--- a/src/file_cache.h
+++ b/src/file_cache.h
@@ -18,16 +18,14 @@
 #include <string>
 #include <unordered_set>
 
-using namespace std;
-
 class Makefile;
 
 class MakefileCacheManager {
  public:
   virtual ~MakefileCacheManager();
 
-  virtual const Makefile& ReadMakefile(const string& filename) = 0;
-  virtual void GetAllFilenames(unordered_set<string>* out) = 0;
+  virtual const Makefile& ReadMakefile(const std::string& filename) = 0;
+  virtual void GetAllFilenames(std::unordered_set<std::string>* out) = 0;
 
   static MakefileCacheManager& Get();
 
diff --git a/src/fileutil.cc b/src/fileutil.cc
index 14ee68a..e6518ef 100644
--- a/src/fileutil.cc
+++ b/src/fileutil.cc
@@ -37,10 +37,10 @@
 
 extern char** environ;
 
-bool Exists(StringPiece filename) {
+bool Exists(std::string_view filename) {
   CHECK(filename.size() < PATH_MAX);
   struct stat st;
-  if (stat(filename.as_string().c_str(), &st) < 0) {
+  if (stat(std::string(filename).c_str(), &st) < 0) {
     return false;
   }
   return true;
@@ -54,24 +54,24 @@ double GetTimestampFromStat(const struct stat& st) {
 #endif
 }
 
-double GetTimestamp(StringPiece filename) {
+double GetTimestamp(std::string_view filename) {
   CHECK(filename.size() < PATH_MAX);
   struct stat st;
-  if (stat(filename.as_string().c_str(), &st) < 0) {
+  if (stat(std::string(filename).c_str(), &st) < 0) {
     return -2.0;
   }
   return GetTimestampFromStat(st);
 }
 
-int RunCommand(const string& shell,
-               const string& shellflag,
-               const string& cmd,
+int RunCommand(const std::string& shell,
+               const std::string& shellflag,
+               const std::string& cmd,
                RedirectStderr redirect_stderr,
-               string* s) {
+               std::string* s) {
   const char* argv[] = {NULL, NULL, NULL, NULL};
-  string cmd_with_shell;
-  if (shell[0] != '/' || shell.find_first_of(" $") != string::npos) {
-    string cmd_escaped = cmd;
+  std::string cmd_with_shell;
+  if (shell[0] != '/' || shell.find_first_of(" $") != std::string::npos) {
+    std::string cmd_escaped = cmd;
     EscapeShell(&cmd_escaped);
     cmd_with_shell = shell + " " + shellflag + " \"" + cmd_escaped + "\"";
     argv[0] = "/bin/sh";
diff --git a/src/fileutil.h b/src/fileutil.h
index 1ff4fc1..6f4f067 100644
--- a/src/fileutil.h
+++ b/src/fileutil.h
@@ -19,16 +19,13 @@
 
 #include <memory>
 #include <string>
+#include <string_view>
 #include <unordered_map>
 #include <vector>
 
-#include "string_piece.h"
-
-using namespace std;
-
-bool Exists(StringPiece f);
+bool Exists(std::string_view f);
 double GetTimestampFromStat(const struct stat& st);
-double GetTimestamp(StringPiece f);
+double GetTimestamp(std::string_view f);
 
 enum struct RedirectStderr {
   NONE,
@@ -36,11 +33,11 @@ enum struct RedirectStderr {
   DEV_NULL,
 };
 
-int RunCommand(const string& shell,
-               const string& shellflag,
-               const string& cmd,
+int RunCommand(const std::string& shell,
+               const std::string& shellflag,
+               const std::string& cmd,
                RedirectStderr redirect_stderr,
-               string* out);
+               std::string* out);
 
 std::string GetExecutablePath();
 
diff --git a/src/find.cc b/src/find.cc
index b693449..4e81851 100644
--- a/src/find.cc
+++ b/src/find.cc
@@ -25,6 +25,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <string_view>
 #include <vector>
 
 //#undef NOLOG
@@ -32,7 +33,6 @@
 #include "fileutil.h"
 #include "log.h"
 #include "stats.h"
-#include "string_piece.h"
 #include "strutil.h"
 #include "timeutil.h"
 
@@ -50,7 +50,7 @@ static unsigned int find_emulator_node_cnt = 0;
 class FindCond {
  public:
   virtual ~FindCond() = default;
-  virtual bool IsTrue(const string& path, unsigned char type) const = 0;
+  virtual bool IsTrue(const std::string& path, unsigned char type) const = 0;
   virtual bool Countable() const = 0;
   virtual unsigned Count() const = 0;
 
@@ -62,24 +62,24 @@ namespace {
 
 class NameCond : public FindCond {
  public:
-  explicit NameCond(const string& n) : name_(n) {
-    has_wildcard_ = (n.find_first_of("?*[") != string::npos);
+  explicit NameCond(const std::string& n) : name_(n) {
+    has_wildcard_ = (n.find_first_of("?*[") != std::string::npos);
   }
-  virtual bool IsTrue(const string& path, unsigned char) const override {
+  virtual bool IsTrue(const std::string& path, unsigned char) const override {
     return fnmatch(name_.c_str(), Basename(path).data(), 0) == 0;
   }
   virtual bool Countable() const override { return !has_wildcard_; }
   virtual unsigned Count() const override { return 1; }
 
  private:
-  string name_;
+  std::string name_;
   bool has_wildcard_;
 };
 
 class TypeCond : public FindCond {
  public:
   explicit TypeCond(unsigned char t) : type_(t) {}
-  virtual bool IsTrue(const string&, unsigned char type) const override {
+  virtual bool IsTrue(const std::string&, unsigned char type) const override {
     return type == type_;
   }
   virtual bool Countable() const override { return false; }
@@ -92,20 +92,22 @@ class TypeCond : public FindCond {
 class NotCond : public FindCond {
  public:
   NotCond(FindCond* c) : c_(c) {}
-  virtual bool IsTrue(const string& path, unsigned char type) const override {
+  virtual bool IsTrue(const std::string& path,
+                      unsigned char type) const override {
     return !c_->IsTrue(path, type);
   }
   virtual bool Countable() const override { return false; }
   virtual unsigned Count() const override { return 0; }
 
  private:
-  unique_ptr<FindCond> c_;
+  std::unique_ptr<FindCond> c_;
 };
 
 class AndCond : public FindCond {
  public:
   AndCond(FindCond* c1, FindCond* c2) : c1_(c1), c2_(c2) {}
-  virtual bool IsTrue(const string& path, unsigned char type) const override {
+  virtual bool IsTrue(const std::string& path,
+                      unsigned char type) const override {
     if (c1_->IsTrue(path, type))
       return c2_->IsTrue(path, type);
     return false;
@@ -114,13 +116,14 @@ class AndCond : public FindCond {
   virtual unsigned Count() const override { return 0; }
 
  private:
-  unique_ptr<FindCond> c1_, c2_;
+  std::unique_ptr<FindCond> c1_, c2_;
 };
 
 class OrCond : public FindCond {
  public:
   OrCond(FindCond* c1, FindCond* c2) : c1_(c1), c2_(c2) {}
-  virtual bool IsTrue(const string& path, unsigned char type) const override {
+  virtual bool IsTrue(const std::string& path,
+                      unsigned char type) const override {
     if (!c1_->IsTrue(path, type))
       return c2_->IsTrue(path, type);
     return true;
@@ -134,41 +137,43 @@ class OrCond : public FindCond {
   }
 
  private:
-  unique_ptr<FindCond> c1_, c2_;
+  std::unique_ptr<FindCond> c1_, c2_;
 };
 
 class DirentNode {
  public:
   virtual ~DirentNode() = default;
 
-  virtual const DirentNode* FindDir(StringPiece) const { return NULL; }
-  virtual bool FindNodes(const FindCommand&,
-                         vector<pair<string, const DirentNode*>>&,
-                         string*,
-                         StringPiece) const {
+  virtual const DirentNode* FindDir(std::string_view) const { return NULL; }
+  virtual bool FindNodes(
+      const FindCommand&,
+      std::vector<std::pair<std::string, const DirentNode*>>&,
+      std::string*,
+      std::string_view) const {
     return true;
   }
-  virtual bool RunFind(const FindCommand& fc,
-                       const Loc& loc,
-                       int d,
-                       string* path,
-                       unordered_map<const DirentNode*, string>* cur_read_dirs,
-                       vector<string>& out) const = 0;
+  virtual bool RunFind(
+      const FindCommand& fc,
+      const Loc& loc,
+      int d,
+      std::string* path,
+      std::unordered_map<const DirentNode*, std::string>* cur_read_dirs,
+      std::vector<std::string>& out) const = 0;
 
   virtual bool IsDirectory() const = 0;
 
-  const string& base() const { return base_; }
+  const std::string& base() const { return base_; }
 
  protected:
-  explicit DirentNode(const string& name) {
-    base_ = Basename(name).as_string();
+  explicit DirentNode(const std::string& name) {
+    base_ = std::string(Basename(name));
   }
 
   void PrintIfNecessary(const FindCommand& fc,
-                        const string& path,
+                        const std::string& path,
                         unsigned char type,
                         int d,
-                        vector<string>& out) const {
+                        std::vector<std::string>& out) const {
     if (fc.print_cond && !fc.print_cond->IsTrue(path, type))
       return;
     if (d < fc.mindepth)
@@ -176,20 +181,20 @@ class DirentNode {
     out.push_back(path);
   }
 
-  string base_;
+  std::string base_;
 };
 
 class DirentFileNode : public DirentNode {
  public:
-  DirentFileNode(const string& name, unsigned char type)
+  DirentFileNode(const std::string& name, unsigned char type)
       : DirentNode(name), type_(type) {}
 
   virtual bool RunFind(const FindCommand& fc,
                        const Loc&,
                        int d,
-                       string* path,
-                       unordered_map<const DirentNode*, string>*,
-                       vector<string>& out) const override {
+                       std::string* path,
+                       std::unordered_map<const DirentNode*, std::string>*,
+                       std::vector<std::string>& out) const override {
     PrintIfNecessary(fc, *path, type_, d, out);
     return true;
   }
@@ -202,9 +207,10 @@ class DirentFileNode : public DirentNode {
 
 struct ScopedReadDirTracker {
  public:
-  ScopedReadDirTracker(const DirentNode* n,
-                       const string& path,
-                       unordered_map<const DirentNode*, string>* cur_read_dirs)
+  ScopedReadDirTracker(
+      const DirentNode* n,
+      const std::string& path,
+      std::unordered_map<const DirentNode*, std::string>* cur_read_dirs)
       : n_(NULL), cur_read_dirs_(cur_read_dirs) {
     const auto& p = cur_read_dirs->emplace(n, path);
     if (p.second) {
@@ -220,17 +226,17 @@ struct ScopedReadDirTracker {
   }
 
   bool ok() const { return conflicted_.empty(); }
-  const string& conflicted() const { return conflicted_; }
+  const std::string& conflicted() const { return conflicted_; }
 
  private:
-  string conflicted_;
+  std::string conflicted_;
   const DirentNode* n_;
-  unordered_map<const DirentNode*, string>* cur_read_dirs_;
+  std::unordered_map<const DirentNode*, std::string>* cur_read_dirs_;
 };
 
 class DirentDirNode : public DirentNode {
  public:
-  explicit DirentDirNode(const DirentDirNode* parent, const string& name)
+  explicit DirentDirNode(const DirentDirNode* parent, const std::string& name)
       : DirentNode(name), parent_(parent), name_(name) {}
 
   ~DirentDirNode() {
@@ -239,7 +245,7 @@ class DirentDirNode : public DirentNode {
     }
   }
 
-  virtual const DirentNode* FindDir(StringPiece d) const override {
+  virtual const DirentNode* FindDir(std::string_view d) const override {
     if (!is_initialized_) {
       initialize();
     }
@@ -250,7 +256,7 @@ class DirentDirNode : public DirentNode {
       return parent_;
 
     size_t index = d.find('/');
-    const string& p = d.substr(0, index).as_string();
+    std::string_view p = d.substr(0, index);
     if (p.empty() || p == ".")
       return FindDir(d.substr(index + 1));
     if (p == "..") {
@@ -261,19 +267,20 @@ class DirentDirNode : public DirentNode {
 
     for (auto& child : children_) {
       if (p == child.first) {
-        if (index == string::npos)
+        if (index == std::string::npos)
           return child.second;
-        StringPiece nd = d.substr(index + 1);
+        std::string_view nd = d.substr(index + 1);
         return child.second->FindDir(nd);
       }
     }
     return NULL;
   }
 
-  virtual bool FindNodes(const FindCommand& fc,
-                         vector<pair<string, const DirentNode*>>& results,
-                         string* path,
-                         StringPiece d) const override {
+  virtual bool FindNodes(
+      const FindCommand& fc,
+      std::vector<std::pair<std::string, const DirentNode*>>& results,
+      std::string* path,
+      std::string_view d) const override {
     if (!is_initialized_) {
       initialize();
     }
@@ -284,11 +291,11 @@ class DirentDirNode : public DirentNode {
     size_t orig_path_size = path->size();
 
     size_t index = d.find('/');
-    const string& p = d.substr(0, index).as_string();
+    const std::string p{d.substr(0, index)};
 
     if (p.empty() || p == ".") {
       path->append(p);
-      if (index == string::npos) {
+      if (index == std::string::npos) {
         results.emplace_back(*path, this);
         return true;
       }
@@ -301,14 +308,14 @@ class DirentDirNode : public DirentNode {
         return false;
       }
       path->append(p);
-      if (index == string::npos) {
+      if (index == std::string::npos) {
         results.emplace_back(*path, parent_);
         return true;
       }
       return parent_->FindNodes(fc, results, path, d.substr(index + 1));
     }
 
-    bool is_wild = p.find_first_of("?*[") != string::npos;
+    bool is_wild = p.find_first_of("?*[") != std::string::npos;
     if (is_wild) {
       fc.read_dirs->insert(*path);
     }
@@ -322,7 +329,7 @@ class DirentDirNode : public DirentNode {
       }
       if (matches) {
         path->append(child.first);
-        if (index == string::npos) {
+        if (index == std::string::npos) {
           results.emplace_back(*path, child.second);
         } else {
           if (!child.second->FindNodes(fc, results, path,
@@ -337,12 +344,13 @@ class DirentDirNode : public DirentNode {
     return true;
   }
 
-  virtual bool RunFind(const FindCommand& fc,
-                       const Loc& loc,
-                       int d,
-                       string* path,
-                       unordered_map<const DirentNode*, string>* cur_read_dirs,
-                       vector<string>& out) const override {
+  virtual bool RunFind(
+      const FindCommand& fc,
+      const Loc& loc,
+      int d,
+      std::string* path,
+      std::unordered_map<const DirentNode*, std::string>* cur_read_dirs,
+      std::vector<std::string>& out) const override {
     if (!is_initialized_) {
       initialize();
     }
@@ -450,7 +458,7 @@ class DirentDirNode : public DirentNode {
     }
   }
 
-  static unsigned char GetDtType(const string& path) {
+  static unsigned char GetDtType(const std::string& path) {
     struct stat st;
     if (lstat(path.c_str(), &st)) {
       PERROR("stat for %s", path.c_str());
@@ -462,17 +470,18 @@ class DirentDirNode : public DirentNode {
 
   const DirentDirNode* parent_;
 
-  mutable vector<pair<string, DirentNode*>> children_;
-  mutable string name_;
+  mutable std::vector<std::pair<std::string, DirentNode*>> children_;
+  mutable std::string name_;
   mutable bool is_initialized_ = false;
 };
 
 class DirentSymlinkNode : public DirentNode {
  public:
-  explicit DirentSymlinkNode(const DirentDirNode* parent, const string& name)
+  explicit DirentSymlinkNode(const DirentDirNode* parent,
+                             const std::string& name)
       : DirentNode(name), name_(name), parent_(parent) {}
 
-  virtual const DirentNode* FindDir(StringPiece d) const override {
+  virtual const DirentNode* FindDir(std::string_view d) const override {
     if (!is_initialized_) {
       initialize();
     }
@@ -481,10 +490,11 @@ class DirentSymlinkNode : public DirentNode {
     return NULL;
   }
 
-  virtual bool FindNodes(const FindCommand& fc,
-                         vector<pair<string, const DirentNode*>>& results,
-                         string* path,
-                         StringPiece d) const override {
+  virtual bool FindNodes(
+      const FindCommand& fc,
+      std::vector<std::pair<std::string, const DirentNode*>>& results,
+      std::string* path,
+      std::string_view d) const override {
     if (!is_initialized_) {
       initialize();
     }
@@ -500,12 +510,13 @@ class DirentSymlinkNode : public DirentNode {
     return to_->FindNodes(fc, results, path, d);
   }
 
-  virtual bool RunFind(const FindCommand& fc,
-                       const Loc& loc,
-                       int d,
-                       string* path,
-                       unordered_map<const DirentNode*, string>* cur_read_dirs,
-                       vector<string>& out) const override {
+  virtual bool RunFind(
+      const FindCommand& fc,
+      const Loc& loc,
+      int d,
+      std::string* path,
+      std::unordered_map<const DirentNode*, std::string>* cur_read_dirs,
+      std::vector<std::string>& out) const override {
     unsigned char type = DT_LNK;
     if (fc.follows_symlinks && !is_initialized_) {
       initialize();
@@ -570,7 +581,7 @@ class DirentSymlinkNode : public DirentNode {
     is_initialized_ = true;
   }
 
-  mutable string name_;
+  mutable std::string name_;
   const DirentDirNode* parent_;
 
   mutable const DirentNode* to_ = nullptr;
@@ -598,7 +609,7 @@ void DirentDirNode::initialize() const {
         !strcmp(ent->d_name, ".repo") || !strcmp(ent->d_name, ".git"))
       continue;
 
-    string npath = name_;
+    std::string npath = name_;
     if (!name_.empty())
       npath += '/';
     npath += ent->d_name;
@@ -627,7 +638,7 @@ void DirentDirNode::initialize() const {
 
 class FindCommandParser {
  public:
-  FindCommandParser(StringPiece cmd, FindCommand* fc)
+  FindCommandParser(std::string_view cmd, FindCommand* fc)
       : cmd_(cmd), fc_(fc), has_if_(false) {}
 
   bool Parse() {
@@ -641,10 +652,10 @@ class FindCommandParser {
   }
 
  private:
-  bool GetNextToken(StringPiece* tok) {
+  bool GetNextToken(std::string_view* tok) {
     if (!unget_tok_.empty()) {
       *tok = unget_tok_;
-      unget_tok_.clear();
+      unget_tok_ = std::string_view();
       return true;
     }
 
@@ -656,7 +667,7 @@ class FindCommandParser {
       return true;
     }
     if (cur_[0] == '&') {
-      if (cur_.get(1) != '&') {
+      if (cur_.size() < 2 || cur_[1] != '&') {
         return false;
       }
       *tok = cur_.substr(0, 2);
@@ -673,9 +684,9 @@ class FindCommandParser {
     *tok = cur_.substr(0, i);
     cur_ = cur_.substr(i);
 
-    const char c = tok->get(0);
+    const char c = tok->empty() ? 0 : tok->front();
     if (c == '\'' || c == '"') {
-      if (tok->size() < 2 || (*tok)[tok->size() - 1] != c)
+      if (tok->size() < 2 || tok->back() != c)
         return false;
       *tok = tok->substr(1, tok->size() - 2);
       return true;
@@ -686,7 +697,7 @@ class FindCommandParser {
       }
       // But if there are any others, we can't support it, as unescaping would
       // require allocation
-      if (tok->find("\\") != string::npos) {
+      if (tok->find("\\") != std::string::npos) {
         return false;
       }
     }
@@ -694,7 +705,7 @@ class FindCommandParser {
     return true;
   }
 
-  void UngetToken(StringPiece tok) {
+  void UngetToken(std::string_view tok) {
     CHECK(unget_tok_.empty());
     if (!tok.empty())
       unget_tok_ = tok;
@@ -703,27 +714,27 @@ class FindCommandParser {
   bool ParseTest() {
     if (has_if_ || !fc_->testdir.empty())
       return false;
-    StringPiece tok;
+    std::string_view tok;
     if (!GetNextToken(&tok) || tok != "-d")
       return false;
     if (!GetNextToken(&tok) || tok.empty())
       return false;
-    fc_->testdir = tok.as_string();
+    fc_->testdir = std::string(tok);
     return true;
   }
 
-  FindCond* ParseFact(StringPiece tok) {
+  FindCond* ParseFact(std::string_view tok) {
     if (tok == "-not" || tok == "!") {
       if (!GetNextToken(&tok) || tok.empty())
         return NULL;
-      unique_ptr<FindCond> c(ParseFact(tok));
+      std::unique_ptr<FindCond> c(ParseFact(tok));
       if (!c.get())
         return NULL;
       return new NotCond(c.release());
     } else if (tok == "(") {
       if (!GetNextToken(&tok) || tok.empty())
         return NULL;
-      unique_ptr<FindCond> c(ParseExpr(tok));
+      std::unique_ptr<FindCond> c(ParseExpr(tok));
       if (!GetNextToken(&tok) || tok != ")") {
         return NULL;
       }
@@ -731,7 +742,7 @@ class FindCommandParser {
     } else if (tok == "-name") {
       if (!GetNextToken(&tok) || tok.empty())
         return NULL;
-      return new NameCond(tok.as_string());
+      return new NameCond(std::string(tok));
     } else if (tok == "-type") {
       if (!GetNextToken(&tok) || tok.empty())
         return NULL;
@@ -759,8 +770,8 @@ class FindCommandParser {
     }
   }
 
-  FindCond* ParseTerm(StringPiece tok) {
-    unique_ptr<FindCond> c(ParseFact(tok));
+  FindCond* ParseTerm(std::string_view tok) {
+    std::unique_ptr<FindCond> c(ParseFact(tok));
     if (!c.get())
       return NULL;
     while (true) {
@@ -776,7 +787,7 @@ class FindCommandParser {
           return c.release();
         }
       }
-      unique_ptr<FindCond> r(ParseFact(tok));
+      std::unique_ptr<FindCond> r(ParseFact(tok));
       if (!r.get()) {
         return NULL;
       }
@@ -784,8 +795,8 @@ class FindCommandParser {
     }
   }
 
-  FindCond* ParseExpr(StringPiece tok) {
-    unique_ptr<FindCond> c(ParseTerm(tok));
+  FindCond* ParseExpr(std::string_view tok) {
+    std::unique_ptr<FindCond> c(ParseTerm(tok));
     if (!c.get())
       return NULL;
     while (true) {
@@ -797,7 +808,7 @@ class FindCommandParser {
       }
       if (!GetNextToken(&tok) || tok.empty())
         return NULL;
-      unique_ptr<FindCond> r(ParseTerm(tok));
+      std::unique_ptr<FindCond> r(ParseTerm(tok));
       if (!r.get()) {
         return NULL;
       }
@@ -815,11 +826,11 @@ class FindCommandParser {
   // <name> ::= '-name' NAME
   // <type> ::= '-type' TYPE
   // <maxdepth> ::= '-maxdepth' MAXDEPTH
-  FindCond* ParseFindCond(StringPiece tok) { return ParseExpr(tok); }
+  FindCond* ParseFindCond(std::string_view tok) { return ParseExpr(tok); }
 
   bool ParseFind() {
     fc_->type = FindCommandType::FIND;
-    StringPiece tok;
+    std::string_view tok;
     while (true) {
       if (!GetNextToken(&tok))
         return false;
@@ -841,7 +852,7 @@ class FindCommandParser {
       } else if (tok == "-maxdepth") {
         if (!GetNextToken(&tok) || tok.empty())
           return false;
-        const string& depth_str = tok.as_string();
+        const std::string& depth_str = std::string(tok);
         char* endptr;
         long d = strtol(depth_str.c_str(), &endptr, 10);
         if (endptr != depth_str.data() + depth_str.size() || d < 0 ||
@@ -861,10 +872,10 @@ class FindCommandParser {
           return false;
         }
         fc_->redirect_to_devnull = true;
-      } else if (tok.find_first_of("|;&><'\"") != string::npos) {
+      } else if (tok.find_first_of("|;&><'\"") != std::string::npos) {
         return false;
       } else {
-        fc_->finddirs.push_back(tok.as_string());
+        fc_->finddirs.push_back(std::string(tok));
       }
     }
   }
@@ -872,8 +883,8 @@ class FindCommandParser {
   bool ParseFindLeaves() {
     fc_->type = FindCommandType::FINDLEAVES;
     fc_->follows_symlinks = true;
-    StringPiece tok;
-    vector<string> findfiles;
+    std::string_view tok;
+    std::vector<std::string> findfiles;
     while (true) {
       if (!GetNextToken(&tok))
         return false;
@@ -902,14 +913,14 @@ class FindCommandParser {
 
       if (HasPrefix(tok, "--prune=")) {
         FindCond* cond =
-            new NameCond(tok.substr(strlen("--prune=")).as_string());
+            new NameCond(std::string(tok.substr(strlen("--prune="))));
         if (fc_->prune_cond.get()) {
           cond = new OrCond(fc_->prune_cond.release(), cond);
         }
         CHECK(!fc_->prune_cond.get());
         fc_->prune_cond.reset(cond);
       } else if (HasPrefix(tok, "--mindepth=")) {
-        string mindepth_str = tok.substr(strlen("--mindepth=")).as_string();
+        std::string mindepth_str{tok.substr(strlen("--mindepth="))};
         char* endptr;
         long d = strtol(mindepth_str.c_str(), &endptr, 10);
         if (endptr != mindepth_str.data() + mindepth_str.size() ||
@@ -918,8 +929,8 @@ class FindCommandParser {
         }
         fc_->mindepth = d;
       } else if (HasPrefix(tok, "--dir=")) {
-        StringPiece dir = tok.substr(strlen("--dir="));
-        fc_->finddirs.push_back(dir.as_string());
+        std::string_view dir = tok.substr(strlen("--dir="));
+        fc_->finddirs.emplace_back(dir);
       } else if (HasPrefix(tok, "--")) {
         if (g_flags.werror_find_emulator) {
           ERROR("Unknown flag in findleaves.py: %.*s", SPF(tok));
@@ -928,14 +939,14 @@ class FindCommandParser {
         }
         return false;
       } else {
-        findfiles.push_back(tok.as_string());
+        findfiles.push_back(std::string(tok));
       }
     }
   }
 
   bool ParseImpl() {
     while (true) {
-      StringPiece tok;
+      std::string_view tok;
       if (!GetNextToken(&tok))
         return false;
 
@@ -945,9 +956,9 @@ class FindCommandParser {
       if (tok == "cd") {
         if (!GetNextToken(&tok) || tok.empty() || !fc_->chdir.empty())
           return false;
-        if (tok.find_first_of("?*[") != string::npos)
+        if (tok.find_first_of("?*[") != std::string::npos)
           return false;
-        fc_->chdir = tok.as_string();
+        fc_->chdir = std::string(tok);
         if (!GetNextToken(&tok) || (tok != ";" && tok != "&&"))
           return false;
       } else if (tok == "if") {
@@ -990,11 +1001,11 @@ class FindCommandParser {
     }
   }
 
-  StringPiece cmd_;
-  StringPiece cur_;
+  std::string_view cmd_;
+  std::string_view cur_;
   FindCommand* fc_;
   bool has_if_;
-  StringPiece unget_tok_;
+  std::string_view unget_tok_;
 };
 
 static FindEmulator* g_instance;
@@ -1005,12 +1016,12 @@ class FindEmulatorImpl : public FindEmulator {
 
   virtual ~FindEmulatorImpl() = default;
 
-  bool CanHandle(StringPiece s) const {
+  bool CanHandle(std::string_view s) const {
     return (!HasPrefix(s, "/") && !HasPrefix(s, ".repo") &&
             !HasPrefix(s, ".git"));
   }
 
-  const DirentNode* FindDir(StringPiece d, bool* should_fallback) {
+  const DirentNode* FindDir(std::string_view d, bool* should_fallback) {
     const DirentNode* r = root_->FindDir(d);
     if (!r) {
       *should_fallback = Exists(d);
@@ -1018,10 +1029,10 @@ class FindEmulatorImpl : public FindEmulator {
     return r;
   }
 
-  virtual bool HandleFind(const string& cmd UNUSED,
+  virtual bool HandleFind(const std::string& cmd UNUSED,
                           const FindCommand& fc,
                           const Loc& loc,
-                          string* out) override {
+                          std::string* out) override {
     if (!CanHandle(fc.chdir)) {
       LOG("FindEmulator: Cannot handle chdir (%.*s): %s", SPF(fc.chdir),
           cmd.c_str());
@@ -1063,17 +1074,17 @@ class FindEmulatorImpl : public FindEmulator {
       }
     }
 
-    vector<string> results;
-    for (const string& finddir : fc.finddirs) {
-      string fullpath = ConcatDir(fc.chdir, finddir);
+    std::vector<std::string> results;
+    for (const std::string& finddir : fc.finddirs) {
+      std::string fullpath = ConcatDir(fc.chdir, finddir);
       if (!CanHandle(fullpath)) {
         LOG("FindEmulator: Cannot handle find dir (%s): %s", fullpath.c_str(),
             cmd.c_str());
         return false;
       }
 
-      string findnodestr;
-      vector<pair<string, const DirentNode*>> bases;
+      std::string findnodestr;
+      std::vector<std::pair<std::string, const DirentNode*>> bases;
       if (!root->FindNodes(fc, bases, &findnodestr, finddir)) {
         return false;
       }
@@ -1093,7 +1104,7 @@ class FindEmulatorImpl : public FindEmulator {
       sort(bases.begin(), bases.end());
 
       for (auto [path, base] : bases) {
-        unordered_map<const DirentNode*, string> cur_read_dirs;
+        std::unordered_map<const DirentNode*, std::string> cur_read_dirs;
         if (!base->RunFind(fc, loc, 0, &path, &cur_read_dirs, results)) {
           LOG("FindEmulator: RunFind failed: %s", cmd.c_str());
           return false;
@@ -1104,7 +1115,7 @@ class FindEmulatorImpl : public FindEmulator {
     if (results.size() > 0) {
       // Calculate and reserve necessary space in out
       size_t new_length = 0;
-      for (const string& result : results) {
+      for (const std::string& result : results) {
         new_length += result.size() + 1;
       }
       out->reserve(out->size() + new_length - 1);
@@ -1114,7 +1125,7 @@ class FindEmulatorImpl : public FindEmulator {
       }
 
       WordWriter writer(out);
-      for (const string& result : results) {
+      for (const std::string& result : results) {
         writer.Write(result);
       }
     }
@@ -1134,12 +1145,12 @@ FindCommand::FindCommand()
       depth(INT_MAX),
       mindepth(INT_MIN),
       redirect_to_devnull(false),
-      found_files(new vector<string>()),
-      read_dirs(new unordered_set<string>()) {}
+      found_files(new std::vector<std::string>()),
+      read_dirs(new std::unordered_set<std::string>()) {}
 
 FindCommand::~FindCommand() {}
 
-bool FindCommand::Parse(const string& cmd) {
+bool FindCommand::Parse(const std::string& cmd) {
   FindCommandParser fcp(cmd, this);
   if (!HasWord(cmd, "find") && !HasWord(cmd, "build/tools/findleaves.py") &&
       !HasWord(cmd, "build/make/tools/findleaves.py"))
diff --git a/src/find.h b/src/find.h
index 2a1abe4..4caaef6 100644
--- a/src/find.h
+++ b/src/find.h
@@ -17,13 +17,11 @@
 
 #include <memory>
 #include <string>
+#include <string_view>
 #include <unordered_set>
 #include <vector>
 
 #include "loc.h"
-#include "string_piece.h"
-
-using namespace std;
 
 class FindCond;
 
@@ -37,21 +35,21 @@ struct FindCommand {
   FindCommand();
   ~FindCommand();
 
-  bool Parse(const string& cmd);
+  bool Parse(const std::string& cmd);
 
   FindCommandType type;
-  string chdir;
-  string testdir;
-  vector<string> finddirs;
+  std::string chdir;
+  std::string testdir;
+  std::vector<std::string> finddirs;
   bool follows_symlinks;
-  unique_ptr<FindCond> print_cond;
-  unique_ptr<FindCond> prune_cond;
+  std::unique_ptr<FindCond> print_cond;
+  std::unique_ptr<FindCond> prune_cond;
   int depth;
   int mindepth;
   bool redirect_to_devnull;
 
-  unique_ptr<vector<string>> found_files;
-  unique_ptr<unordered_set<string>> read_dirs;
+  std::unique_ptr<std::vector<std::string>> found_files;
+  std::unique_ptr<std::unordered_set<std::string>> read_dirs;
 
  private:
   FindCommand(const FindCommand&) = delete;
@@ -62,10 +60,10 @@ class FindEmulator {
  public:
   virtual ~FindEmulator() = default;
 
-  virtual bool HandleFind(const string& cmd,
+  virtual bool HandleFind(const std::string& cmd,
                           const FindCommand& fc,
                           const Loc& loc,
-                          string* out) = 0;
+                          std::string* out) = 0;
 
   static FindEmulator* Get();
   static unsigned int GetNodeCount();
diff --git a/src/find_test.cc b/src/find_test.cc
index e8d521c..b901e4e 100644
--- a/src/find_test.cc
+++ b/src/find_test.cc
@@ -22,6 +22,7 @@
 #include <string>
 
 #include "fileutil.h"
+#include "log.h"
 #include "strutil.h"
 
 int FindUnitTests();
@@ -32,7 +33,7 @@ int main(int argc, char* argv[]) {
   }
 
   InitFindEmulator();
-  string cmd;
+  std::string cmd;
   for (int i = 1; i < argc; i++) {
     if (i > 1)
       cmd += ' ';
@@ -43,19 +44,19 @@ int main(int argc, char* argv[]) {
     fprintf(stderr, "Find emulator does not support this command\n");
     return 1;
   }
-  string out;
+  std::string out;
   if (!FindEmulator::Get()->HandleFind(cmd, fc, Loc(), &out)) {
     fprintf(stderr, "Find emulator does not support this command\n");
     return 1;
   }
 
-  for (StringPiece tok : WordScanner(out)) {
+  for (std::string_view tok : WordScanner(out)) {
     printf("%.*s\n", SPF(tok));
   }
 }
 
-string Run(const string& cmd) {
-  string s;
+std::string Run(const std::string& cmd) {
+  std::string s;
   int ret = RunCommand("/bin/sh", "-c", cmd, RedirectStderr::NONE, &s);
 
   if (ret != 0) {
@@ -68,22 +69,22 @@ string Run(const string& cmd) {
 
 static bool unit_test_failed = false;
 
-void CompareFind(const string& cmd) {
-  string native = Run(cmd);
+void CompareFind(const std::string& cmd) {
+  std::string native = Run(cmd);
 
   FindCommand fc;
   if (!fc.Parse(cmd)) {
     fprintf(stderr, "Find emulator cannot parse `%s`\n", cmd.c_str());
     exit(1);
   }
-  string emulated;
+  std::string emulated;
   if (!FindEmulator::Get()->HandleFind(cmd, fc, Loc(), &emulated)) {
     fprintf(stderr, "Find emulator cannot handle `%s`\n", cmd.c_str());
     exit(1);
   }
 
-  vector<StringPiece> nativeWords;
-  vector<StringPiece> emulatedWords;
+  std::vector<std::string_view> nativeWords;
+  std::vector<std::string_view> emulatedWords;
 
   WordScanner(native).Split(&nativeWords);
   WordScanner(emulated).Split(&emulatedWords);
@@ -99,17 +100,17 @@ void CompareFind(const string& cmd) {
       fprintf(stderr, " %-20s %-20s\n",
               (nativeIter == nativeWords.end())
                   ? ""
-                  : (*nativeIter++).as_string().c_str(),
+                  : std::string(*nativeIter++).c_str(),
               (emulatedIter == emulatedWords.end())
                   ? ""
-                  : (*emulatedIter++).as_string().c_str());
+                  : std::string(*emulatedIter++).c_str());
     }
     fprintf(stderr, "------------------------------------------\n");
     unit_test_failed = true;
   }
 }
 
-void ExpectParseFailure(const string& cmd) {
+void ExpectParseFailure(const std::string& cmd) {
   FindCommand fc;
   if (fc.Parse(cmd)) {
     fprintf(stderr, "Expected parse failure for `%s`\n", cmd.c_str());
diff --git a/src/flags.cc b/src/flags.cc
index e21a541..37f08f4 100644
--- a/src/flags.cc
+++ b/src/flags.cc
@@ -24,7 +24,7 @@
 
 Flags g_flags;
 
-static bool ParseCommandLineOptionWithArg(StringPiece option,
+static bool ParseCommandLineOptionWithArg(std::string_view option,
                                           char* argv[],
                                           int* index,
                                           const char** out_arg) {
@@ -53,10 +53,11 @@ void Flags::Parse(int argc, char** argv) {
   num_jobs = num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
   const char* num_jobs_str;
   const char* writable_str;
+  const char* variable_assignment_trace_filter;
 
   if (const char* makeflags = getenv("MAKEFLAGS")) {
-    for (StringPiece tok : WordScanner(makeflags)) {
-      if (!HasPrefix(tok, "-") && tok.find('=') != string::npos)
+    for (std::string_view tok : WordScanner(makeflags)) {
+      if (!HasPrefix(tok, "-") && tok.find('=') != std::string::npos)
         cl_vars.push_back(tok);
     }
   }
@@ -154,6 +155,13 @@ void Flags::Parse(int argc, char** argv) {
     } else if (ParseCommandLineOptionWithArg("--dump_variable_assignment_trace",
                                              argv, &i,
                                              &dump_variable_assignment_trace)) {
+    } else if (ParseCommandLineOptionWithArg(
+                   "--variable_assignment_trace_filter", argv, &i,
+                   &variable_assignment_trace_filter)) {
+      for (std::string_view pat :
+           WordScanner(variable_assignment_trace_filter)) {
+        traced_variables_pattern.push_back(Pattern(pat));
+      }
     } else if (ParseCommandLineOptionWithArg("-j", argv, &i, &num_jobs_str)) {
       num_jobs = strtol(num_jobs_str, NULL, 10);
       if (num_jobs <= 0) {
@@ -202,4 +210,11 @@ void Flags::Parse(int argc, char** argv) {
       }
     }
   }
+
+  if (traced_variables_pattern.size() &&
+      dump_variable_assignment_trace == nullptr) {
+    ERROR(
+        "--variable_assignment_trace_filter is valid only together with "
+        "--dump_variable_assignment_trace");
+  }
 }
diff --git a/src/flags.h b/src/flags.h
index 73410d5..5b36518 100644
--- a/src/flags.h
+++ b/src/flags.h
@@ -16,13 +16,12 @@
 #define FLAGS_H_
 
 #include <string>
+#include <string_view>
 #include <vector>
 
-#include "string_piece.h"
+#include "strutil.h"
 #include "symtab.h"
 
-using namespace std;
-
 struct Flags {
   bool detect_android_echo;
   bool detect_depfiles;
@@ -76,10 +75,11 @@ struct Flags {
   int num_cpus;
   int num_jobs;
   int remote_num_jobs;
-  vector<const char*> subkati_args;
-  vector<Symbol> targets;
-  vector<StringPiece> cl_vars;
-  vector<string> writable;
+  std::vector<const char*> subkati_args;
+  std::vector<Symbol> targets;
+  std::vector<std::string_view> cl_vars;
+  std::vector<std::string> writable;
+  std::vector<Pattern> traced_variables_pattern;
 
   void Parse(int argc, char** argv);
 };
diff --git a/src/func.cc b/src/func.cc
index bd8d78d..2345808 100644
--- a/src/func.cc
+++ b/src/func.cc
@@ -45,11 +45,11 @@ namespace {
 
 // TODO: This code is very similar to
 // NinjaGenerator::TranslateCommand. Factor them out.
-void StripShellComment(string* cmd) {
-  if (cmd->find('#') == string::npos)
+void StripShellComment(std::string* cmd) {
+  if (cmd->find('#') == std::string::npos)
     return;
 
-  string res;
+  std::string res;
   bool prev_backslash = false;
   // Set space as an initial value so the leading comment will be
   // stripped out.
@@ -98,30 +98,32 @@ void StripShellComment(string* cmd) {
   cmd->swap(res);
 }
 
-void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& pat_str = args[0]->Eval(ev);
-  const string&& repl = args[1]->Eval(ev);
-  const string&& str = args[2]->Eval(ev);
+void PatsubstFunc(const std::vector<Value*>& args,
+                  Evaluator* ev,
+                  std::string* s) {
+  const std::string&& pat_str = args[0]->Eval(ev);
+  const std::string&& repl = args[1]->Eval(ev);
+  const std::string&& str = args[2]->Eval(ev);
   WordWriter ww(s);
   Pattern pat(pat_str);
-  for (StringPiece tok : WordScanner(str)) {
+  for (std::string_view tok : WordScanner(str)) {
     ww.MaybeAddWhitespace();
     pat.AppendSubst(tok, repl, s);
   }
 }
 
-void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& str = args[0]->Eval(ev);
+void StripFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
+  const std::string&& str = args[0]->Eval(ev);
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(str)) {
+  for (std::string_view tok : WordScanner(str)) {
     ww.Write(tok);
   }
 }
 
-void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& pat = args[0]->Eval(ev);
-  const string&& repl = args[1]->Eval(ev);
-  const string&& str = args[2]->Eval(ev);
+void SubstFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
+  const std::string&& pat = args[0]->Eval(ev);
+  const std::string&& repl = args[1]->Eval(ev);
+  const std::string&& str = args[2]->Eval(ev);
   if (pat.empty()) {
     *s += str;
     *s += repl;
@@ -130,31 +132,35 @@ void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   size_t index = 0;
   while (index < str.size()) {
     size_t found = str.find(pat, index);
-    if (found == string::npos)
+    if (found == std::string::npos)
       break;
-    AppendString(StringPiece(str).substr(index, found - index), s);
-    AppendString(repl, s);
+    s->append(std::string_view(str).substr(index, found - index));
+    s->append(repl);
     index = found + pat.size();
   }
-  AppendString(StringPiece(str).substr(index), s);
+  s->append(std::string_view(str).substr(index));
 }
 
-void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& find = args[0]->Eval(ev);
-  const string&& in = args[1]->Eval(ev);
-  if (in.find(find) != string::npos)
-    AppendString(find, s);
+void FindstringFunc(const std::vector<Value*>& args,
+                    Evaluator* ev,
+                    std::string* s) {
+  const std::string&& find = args[0]->Eval(ev);
+  const std::string&& in = args[1]->Eval(ev);
+  if (in.find(find) != std::string::npos)
+    s->append(find);
 }
 
-void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& pat_buf = args[0]->Eval(ev);
-  const string&& text = args[1]->Eval(ev);
-  vector<Pattern> pats;
-  for (StringPiece pat : WordScanner(pat_buf)) {
+void FilterFunc(const std::vector<Value*>& args,
+                Evaluator* ev,
+                std::string* s) {
+  const std::string&& pat_buf = args[0]->Eval(ev);
+  const std::string&& text = args[1]->Eval(ev);
+  std::vector<Pattern> pats;
+  for (std::string_view pat : WordScanner(pat_buf)) {
     pats.push_back(Pattern(pat));
   }
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(text)) {
+  for (std::string_view tok : WordScanner(text)) {
     for (const Pattern& pat : pats) {
       if (pat.Match(tok)) {
         ww.Write(tok);
@@ -164,15 +170,17 @@ void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   }
 }
 
-void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& pat_buf = args[0]->Eval(ev);
-  const string&& text = args[1]->Eval(ev);
-  vector<Pattern> pats;
-  for (StringPiece pat : WordScanner(pat_buf)) {
+void FilterOutFunc(const std::vector<Value*>& args,
+                   Evaluator* ev,
+                   std::string* s) {
+  const std::string&& pat_buf = args[0]->Eval(ev);
+  const std::string&& text = args[1]->Eval(ev);
+  std::vector<Pattern> pats;
+  for (std::string_view pat : WordScanner(pat_buf)) {
     pats.push_back(Pattern(pat));
   }
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(text)) {
+  for (std::string_view tok : WordScanner(text)) {
     bool matched = false;
     for (const Pattern& pat : pats) {
       if (pat.Match(tok)) {
@@ -185,18 +193,18 @@ void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   }
 }
 
-void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  string list;
+void SortFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
+  std::string list;
   args[0]->Eval(ev, &list);
   COLLECT_STATS("func sort time");
   // TODO(hamaji): Probably we could use a faster string-specific sort
   // algorithm.
-  vector<StringPiece> toks;
+  std::vector<std::string_view> toks;
   WordScanner(list).Split(&toks);
   stable_sort(toks.begin(), toks.end());
   WordWriter ww(s);
-  StringPiece prev;
-  for (StringPiece tok : toks) {
+  std::string_view prev;
+  for (std::string_view tok : toks) {
     if (prev != tok) {
       ww.Write(tok);
       prev = tok;
@@ -204,8 +212,8 @@ void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   }
 }
 
-static int GetNumericValueForFunc(const string& buf) {
-  StringPiece s = TrimLeftSpace(buf);
+static int GetNumericValueForFunc(const std::string& buf) {
+  std::string_view s = TrimLeftSpace(buf);
   char* end;
   long n = strtol(s.data(), &end, 10);
   if (n < 0 || n == LONG_MAX || s.data() + s.size() != end) {
@@ -214,8 +222,8 @@ static int GetNumericValueForFunc(const string& buf) {
   return n;
 }
 
-void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& n_str = args[0]->Eval(ev);
+void WordFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
+  const std::string&& n_str = args[0]->Eval(ev);
   int n = GetNumericValueForFunc(n_str);
   if (n < 0) {
     ev->Error(
@@ -226,18 +234,20 @@ void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
     ev->Error("*** first argument to `word' function must be greater than 0.");
   }
 
-  const string&& text = args[1]->Eval(ev);
-  for (StringPiece tok : WordScanner(text)) {
+  const std::string&& text = args[1]->Eval(ev);
+  for (std::string_view tok : WordScanner(text)) {
     n--;
     if (n == 0) {
-      AppendString(tok, s);
+      s->append(tok);
       break;
     }
   }
 }
 
-void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& s_str = args[0]->Eval(ev);
+void WordlistFunc(const std::vector<Value*>& args,
+                  Evaluator* ev,
+                  std::string* s) {
+  const std::string&& s_str = args[0]->Eval(ev);
   int si = GetNumericValueForFunc(s_str);
   if (si < 0) {
     ev->Error(StringPrintf(
@@ -250,7 +260,7 @@ void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
                      s_str.c_str()));
   }
 
-  const string&& e_str = args[1]->Eval(ev);
+  const std::string&& e_str = args[1]->Eval(ev);
   int ei = GetNumericValueForFunc(e_str);
   if (ei < 0) {
     ev->Error(StringPrintf(
@@ -258,10 +268,10 @@ void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
         e_str.c_str()));
   }
 
-  const string&& text = args[2]->Eval(ev);
+  const std::string&& text = args[2]->Eval(ev);
   int i = 0;
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(text)) {
+  for (std::string_view tok : WordScanner(text)) {
     i++;
     if (si <= i && i <= ei) {
       ww.Write(tok);
@@ -269,8 +279,8 @@ void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   }
 }
 
-void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& text = args[0]->Eval(ev);
+void WordsFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
+  const std::string&& text = args[0]->Eval(ev);
   WordScanner ws(text);
   int n = 0;
   for (auto iter = ws.begin(); iter != ws.end(); ++iter)
@@ -280,27 +290,31 @@ void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   *s += buf;
 }
 
-void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& text = args[0]->Eval(ev);
+void FirstwordFunc(const std::vector<Value*>& args,
+                   Evaluator* ev,
+                   std::string* s) {
+  const std::string&& text = args[0]->Eval(ev);
   WordScanner ws(text);
   auto begin = ws.begin();
   if (begin != ws.end()) {
-    AppendString(*begin, s);
+    s->append(*begin);
   }
 }
 
-void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& text = args[0]->Eval(ev);
-  StringPiece last;
-  for (StringPiece tok : WordScanner(text)) {
+void LastwordFunc(const std::vector<Value*>& args,
+                  Evaluator* ev,
+                  std::string* s) {
+  const std::string&& text = args[0]->Eval(ev);
+  std::string_view last;
+  for (std::string_view tok : WordScanner(text)) {
     last = tok;
   }
-  AppendString(last, s);
+  s->append(last);
 }
 
-void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& list1 = args[0]->Eval(ev);
-  const string&& list2 = args[1]->Eval(ev);
+void JoinFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
+  const std::string&& list1 = args[0]->Eval(ev);
+  const std::string&& list2 = args[1]->Eval(ev);
   WordScanner ws1(list1);
   WordScanner ws2(list2);
   WordWriter ww(s);
@@ -308,8 +322,8 @@ void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   for (iter1 = ws1.begin(), iter2 = ws2.begin();
        iter1 != ws1.end() && iter2 != ws2.end(); ++iter1, ++iter2) {
     ww.Write(*iter1);
-    // Use |AppendString| not to append extra ' '.
-    AppendString(*iter2, s);
+    // Use append to not append extra ' '.
+    s->append(*iter2);
   }
   for (; iter1 != ws1.end(); ++iter1)
     ww.Write(*iter1);
@@ -317,82 +331,96 @@ void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
     ww.Write(*iter2);
 }
 
-void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& pat = args[0]->Eval(ev);
+void WildcardFunc(const std::vector<Value*>& args,
+                  Evaluator* ev,
+                  std::string* s) {
+  const std::string&& pat = args[0]->Eval(ev);
   COLLECT_STATS("func wildcard time");
   // Note GNU make does not delay the execution of $(wildcard) so we
   // do not need to check avoid_io here.
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(pat)) {
+  for (std::string_view tok : WordScanner(pat)) {
     ScopedTerminator st(tok);
     const auto& files = Glob(tok.data());
-    for (const string& file : files) {
+    for (const std::string& file : files) {
       ww.Write(file);
     }
   }
 }
 
-void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& text = args[0]->Eval(ev);
+void DirFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
+  const std::string&& text = args[0]->Eval(ev);
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(text)) {
+  for (std::string_view tok : WordScanner(text)) {
     ww.Write(Dirname(tok));
     s->push_back('/');
   }
 }
 
-void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& text = args[0]->Eval(ev);
+void NotdirFunc(const std::vector<Value*>& args,
+                Evaluator* ev,
+                std::string* s) {
+  const std::string&& text = args[0]->Eval(ev);
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(text)) {
+  for (std::string_view tok : WordScanner(text)) {
     if (tok == "/") {
-      ww.Write(StringPiece(""));
+      ww.Write(std::string_view(""));
     } else {
       ww.Write(Basename(tok));
     }
   }
 }
 
-void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& text = args[0]->Eval(ev);
+void SuffixFunc(const std::vector<Value*>& args,
+                Evaluator* ev,
+                std::string* s) {
+  const std::string&& text = args[0]->Eval(ev);
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(text)) {
-    StringPiece suf = GetExt(tok);
+  for (std::string_view tok : WordScanner(text)) {
+    std::string_view suf = GetExt(tok);
     if (!suf.empty())
       ww.Write(suf);
   }
 }
 
-void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& text = args[0]->Eval(ev);
+void BasenameFunc(const std::vector<Value*>& args,
+                  Evaluator* ev,
+                  std::string* s) {
+  const std::string&& text = args[0]->Eval(ev);
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(text)) {
+  for (std::string_view tok : WordScanner(text)) {
     ww.Write(StripExt(tok));
   }
 }
 
-void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& suf = args[0]->Eval(ev);
-  const string&& text = args[1]->Eval(ev);
+void AddsuffixFunc(const std::vector<Value*>& args,
+                   Evaluator* ev,
+                   std::string* s) {
+  const std::string&& suf = args[0]->Eval(ev);
+  const std::string&& text = args[1]->Eval(ev);
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(text)) {
+  for (std::string_view tok : WordScanner(text)) {
     ww.Write(tok);
     *s += suf;
   }
 }
 
-void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& pre = args[0]->Eval(ev);
-  const string&& text = args[1]->Eval(ev);
+void AddprefixFunc(const std::vector<Value*>& args,
+                   Evaluator* ev,
+                   std::string* s) {
+  const std::string&& pre = args[0]->Eval(ev);
+  const std::string&& text = args[1]->Eval(ev);
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(text)) {
+  for (std::string_view tok : WordScanner(text)) {
     ww.Write(pre);
-    AppendString(tok, s);
+    s->append(tok);
   }
 }
 
-void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& text = args[0]->Eval(ev);
+void RealpathFunc(const std::vector<Value*>& args,
+                  Evaluator* ev,
+                  std::string* s) {
+  const std::string&& text = args[0]->Eval(ev);
   if (ev->avoid_io()) {
     *s += "$(";
     *s += GetExecutablePath();
@@ -403,7 +431,7 @@ void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   }
 
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(text)) {
+  for (std::string_view tok : WordScanner(text)) {
     ScopedTerminator st(tok);
     char buf[PATH_MAX];
     if (realpath(tok.data(), buf))
@@ -411,18 +439,20 @@ void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   }
 }
 
-void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& text = args[0]->Eval(ev);
+void AbspathFunc(const std::vector<Value*>& args,
+                 Evaluator* ev,
+                 std::string* s) {
+  const std::string&& text = args[0]->Eval(ev);
   WordWriter ww(s);
-  string buf;
-  for (StringPiece tok : WordScanner(text)) {
+  std::string buf;
+  for (std::string_view tok : WordScanner(text)) {
     AbsPath(tok, &buf);
     ww.Write(buf);
   }
 }
 
-void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& cond = args[0]->Eval(ev);
+void IfFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
+  const std::string&& cond = args[0]->Eval(ev);
   if (cond.empty()) {
     if (args.size() > 2)
       args[2]->Eval(ev, s);
@@ -431,8 +461,8 @@ void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   }
 }
 
-void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  string cond;
+void AndFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
+  std::string cond;
   for (Value* a : args) {
     cond = a->Eval(ev);
     if (cond.empty())
@@ -443,9 +473,9 @@ void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   }
 }
 
-void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
+void OrFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
   for (Value* a : args) {
-    const string&& cond = a->Eval(ev);
+    const std::string&& cond = a->Eval(ev);
     if (!cond.empty()) {
       *s += cond;
       return;
@@ -453,24 +483,24 @@ void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   }
 }
 
-void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& var_name = args[0]->Eval(ev);
+void ValueFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
+  const std::string&& var_name = args[0]->Eval(ev);
   Var* var = ev->LookupVar(Intern(var_name));
-  AppendString(var->String().as_string(), s);
+  s->append(std::string(var->String()));
 }
 
-void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) {
+void EvalFunc(const std::vector<Value*>& args, Evaluator* ev, std::string*) {
   // TODO: eval leaks everything... for now.
   // const string text = args[0]->Eval(ev);
   ev->CheckStack();
-  string* text = new string;
+  std::string* text = new std::string;
   args[0]->Eval(ev, text);
   if (ev->avoid_io()) {
     KATI_WARN_LOC(ev->loc(),
                   "*warning*: $(eval) in a recipe is not recommended: %s",
                   text->c_str());
   }
-  vector<Stmt*> stmts;
+  std::vector<Stmt*> stmts;
   Parse(*text, ev->loc(), &stmts);
   for (Stmt* stmt : stmts) {
     LOG("%s", stmt->DebugString().c_str());
@@ -486,7 +516,7 @@ void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) {
 // will be passed to other make functions.
 // TODO: Maybe we should introduce a helper binary which evaluate
 // make expressions at ninja-time.
-static bool HasNoIoInShellScript(const string& cmd) {
+static bool HasNoIoInShellScript(const std::string& cmd) {
   if (cmd.empty())
     return true;
   if (HasPrefix(cmd, "echo $((") && cmd[cmd.size() - 1] == ')')
@@ -494,11 +524,11 @@ static bool HasNoIoInShellScript(const string& cmd) {
   return false;
 }
 
-static int ShellFuncImpl(const string& shell,
-                         const string& shellflag,
-                         const string& cmd,
+static int ShellFuncImpl(const std::string& shell,
+                         const std::string& shellflag,
+                         const std::string& cmd,
                          const Loc& loc,
-                         string* s,
+                         std::string* s,
                          FindCommand** fc) {
   LOG("ShellFunc: %s", cmd.c_str());
 
@@ -542,17 +572,18 @@ static int ShellFuncImpl(const string& shell,
   return 1;
 }
 
-static vector<CommandResult*> g_command_results;
+static std::vector<CommandResult*> g_command_results;
 
-bool ShouldStoreCommandResult(StringPiece cmd) {
+bool ShouldStoreCommandResult(std::string_view cmd) {
   // We really just want to ignore this one, or remove BUILD_DATETIME from
   // Android completely
   if (cmd == "date +%s")
     return false;
 
-  Pattern pat(g_flags.ignore_dirty_pattern);
-  Pattern nopat(g_flags.no_ignore_dirty_pattern);
-  for (StringPiece tok : WordScanner(cmd)) {
+  Pattern pat(g_flags.ignore_dirty_pattern ? g_flags.ignore_dirty_pattern : "");
+  Pattern nopat(
+      g_flags.no_ignore_dirty_pattern ? g_flags.no_ignore_dirty_pattern : "");
+  for (std::string_view tok : WordScanner(cmd)) {
     if (pat.Match(tok) && !nopat.Match(tok)) {
       return false;
     }
@@ -561,8 +592,8 @@ bool ShouldStoreCommandResult(StringPiece cmd) {
   return true;
 }
 
-void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  string cmd = args[0]->Eval(ev);
+void ShellFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
+  std::string cmd = args[0]->Eval(ev);
   if (ev->avoid_io() && !HasNoIoInShellScript(cmd)) {
     if (ev->eval_depth() > 1) {
       ERROR_LOC(ev->loc(),
@@ -577,10 +608,10 @@ void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
     return;
   }
 
-  const string&& shell = ev->GetShell();
-  const string&& shellflag = ev->GetShellFlag();
+  const std::string&& shell = ev->GetShell();
+  const std::string&& shellflag = ev->GetShellFlag();
 
-  string out;
+  std::string out;
   FindCommand* fc = NULL;
   int returnCode = ShellFuncImpl(shell, shellflag, cmd, ev->loc(), &out, &fc);
   if (ShouldStoreCommandResult(cmd)) {
@@ -598,13 +629,13 @@ void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   ShellStatusVar::SetValue(returnCode);
 }
 
-void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
+void CallFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
   static const Symbol tmpvar_names[] = {
       Intern("0"), Intern("1"), Intern("2"), Intern("3"), Intern("4"),
       Intern("5"), Intern("6"), Intern("7"), Intern("8"), Intern("9")};
 
   ev->CheckStack();
-  const string&& func_name_buf = args[0]->Eval(ev);
+  const std::string&& func_name_buf = args[0]->Eval(ev);
   Symbol func_sym = Intern(TrimSpace(func_name_buf));
   Var* func = ev->LookupVar(func_sym);
   func->Used(ev, func_sym);
@@ -612,15 +643,14 @@ void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
     KATI_WARN_LOC(ev->loc(), "*warning*: undefined user function: %s",
                   func_sym.c_str());
   }
-  vector<unique_ptr<SimpleVar>> av;
+  std::vector<std::unique_ptr<SimpleVar>> av;
   for (size_t i = 1; i < args.size(); i++) {
-    unique_ptr<SimpleVar> s(
-        new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC, nullptr, Loc()));
-    av.push_back(move(s));
+    av.emplace_back(std::make_unique<SimpleVar>(
+        args[i]->Eval(ev), VarOrigin::AUTOMATIC, nullptr, Loc()));
   }
-  vector<unique_ptr<ScopedGlobalVar>> sv;
+  std::vector<std::unique_ptr<ScopedGlobalVar>> sv;
   for (size_t i = 1;; i++) {
-    string s;
+    std::string s;
     Symbol tmpvar_name_sym;
     if (i < sizeof(tmpvar_names) / sizeof(tmpvar_names[0])) {
       tmpvar_name_sym = tmpvar_names[i];
@@ -653,14 +683,16 @@ void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   ev->IncrementEvalDepth();
 }
 
-void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& varname = args[0]->Eval(ev);
-  const string&& list = args[1]->Eval(ev);
+void ForeachFunc(const std::vector<Value*>& args,
+                 Evaluator* ev,
+                 std::string* s) {
+  const std::string&& varname = args[0]->Eval(ev);
+  const std::string&& list = args[1]->Eval(ev);
   ev->DecrementEvalDepth();
   WordWriter ww(s);
-  for (StringPiece tok : WordScanner(list)) {
-    unique_ptr<SimpleVar> v(
-        new SimpleVar(tok.as_string(), VarOrigin::AUTOMATIC, nullptr, Loc()));
+  for (std::string_view tok : WordScanner(list)) {
+    std::unique_ptr<SimpleVar> v(
+        new SimpleVar(std::string(tok), VarOrigin::AUTOMATIC, nullptr, Loc()));
     ScopedGlobalVar sv(Intern(varname), v.get());
     ww.MaybeAddWhitespace();
     args[2]->Eval(ev, s);
@@ -668,20 +700,24 @@ void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   ev->IncrementEvalDepth();
 }
 
-void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& var_name = args[0]->Eval(ev);
+void OriginFunc(const std::vector<Value*>& args,
+                Evaluator* ev,
+                std::string* s) {
+  const std::string&& var_name = args[0]->Eval(ev);
   Var* var = ev->LookupVar(Intern(var_name));
   *s += GetOriginStr(var->Origin());
 }
 
-void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
-  const string&& var_name = args[0]->Eval(ev);
+void FlavorFunc(const std::vector<Value*>& args,
+                Evaluator* ev,
+                std::string* s) {
+  const std::string&& var_name = args[0]->Eval(ev);
   Var* var = ev->LookupVar(Intern(var_name));
   *s += var->Flavor();
 }
 
-void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
-  const string&& a = args[0]->Eval(ev);
+void InfoFunc(const std::vector<Value*>& args, Evaluator* ev, std::string*) {
+  const std::string&& a = args[0]->Eval(ev);
   if (ev->avoid_io()) {
     ev->add_delayed_output_command(
         StringPrintf("echo -e \"%s\"", EchoEscape(a).c_str()));
@@ -691,8 +727,8 @@ void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
   fflush(stdout);
 }
 
-void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
-  const string&& a = args[0]->Eval(ev);
+void WarningFunc(const std::vector<Value*>& args, Evaluator* ev, std::string*) {
+  const std::string&& a = args[0]->Eval(ev);
   if (ev->avoid_io()) {
     ev->add_delayed_output_command(StringPrintf(
         "echo -e \"%s:%d: %s\" 2>&1", LOCF(ev->loc()), EchoEscape(a).c_str()));
@@ -701,8 +737,8 @@ void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
   WARN_LOC(ev->loc(), "%s", a.c_str());
 }
 
-void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
-  const string&& a = args[0]->Eval(ev);
+void ErrorFunc(const std::vector<Value*>& args, Evaluator* ev, std::string*) {
+  const std::string&& a = args[0]->Eval(ev);
   if (ev->avoid_io()) {
     ev->add_delayed_output_command(
         StringPrintf("echo -e \"%s:%d: *** %s.\" 2>&1 && false",
@@ -712,7 +748,9 @@ void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
   ev->Error(StringPrintf("*** %s.", a.c_str()));
 }
 
-static void FileReadFunc(Evaluator* ev, const string& filename, string* s) {
+static void FileReadFunc(Evaluator* ev,
+                         const std::string& filename,
+                         std::string* s) {
   int fd = open(filename.c_str(), O_RDONLY);
   if (fd < 0) {
     if (errno == ENOENT) {
@@ -735,7 +773,7 @@ static void FileReadFunc(Evaluator* ev, const string& filename, string* s) {
   }
 
   size_t len = st.st_size;
-  string out;
+  std::string out;
   out.resize(len);
   ssize_t r = HANDLE_EINTR(read(fd, &out[0], len));
   if (r != static_cast<ssize_t>(len)) {
@@ -761,9 +799,9 @@ static void FileReadFunc(Evaluator* ev, const string& filename, string* s) {
 }
 
 static void FileWriteFunc(Evaluator* ev,
-                          const string& filename,
+                          const std::string& filename,
                           bool append,
-                          string text) {
+                          std::string text) {
   FILE* f = fopen(filename.c_str(), append ? "ab" : "wb");
   if (f == NULL) {
     ev->Error("*** fopen failed.");
@@ -787,13 +825,13 @@ static void FileWriteFunc(Evaluator* ev,
   }
 }
 
-void FileFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
+void FileFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
   if (ev->avoid_io()) {
     ev->Error("*** $(file ...) is not supported in rules.");
   }
 
-  string arg = args[0]->Eval(ev);
-  StringPiece filename = TrimSpace(arg);
+  std::string arg = args[0]->Eval(ev);
+  std::string_view filename = TrimSpace(arg);
 
   if (filename.size() <= 1) {
     ev->Error("*** Missing filename");
@@ -808,7 +846,7 @@ void FileFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
       ev->Error("*** invalid argument");
     }
 
-    FileReadFunc(ev, filename.as_string(), s);
+    FileReadFunc(ev, std::string(filename), s);
   } else if (filename[0] == '>') {
     bool append = false;
     if (filename[1] == '>') {
@@ -822,7 +860,7 @@ void FileFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
       ev->Error("*** Missing filename");
     }
 
-    string text;
+    std::string text;
     if (args.size() > 1) {
       text = args[1]->Eval(ev);
       if (text.size() == 0 || text.back() != '\n') {
@@ -830,16 +868,18 @@ void FileFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
       }
     }
 
-    FileWriteFunc(ev, filename.as_string(), append, text);
+    FileWriteFunc(ev, std::string(filename), append, text);
   } else {
     ev->Error(StringPrintf("*** Invalid file operation: %s.  Stop.",
-                           filename.as_string().c_str()));
+                           std::string(filename).c_str()));
   }
 }
 
-void DeprecatedVarFunc(const vector<Value*>& args, Evaluator* ev, string*) {
-  string vars_str = args[0]->Eval(ev);
-  string msg;
+void DeprecatedVarFunc(const std::vector<Value*>& args,
+                       Evaluator* ev,
+                       std::string*) {
+  std::string vars_str = args[0]->Eval(ev);
+  std::string msg;
 
   if (args.size() == 2) {
     msg = ". " + args[1]->Eval(ev);
@@ -849,7 +889,7 @@ void DeprecatedVarFunc(const vector<Value*>& args, Evaluator* ev, string*) {
     ev->Error("*** $(KATI_deprecated_var ...) is not supported in rules.");
   }
 
-  for (StringPiece var : WordScanner(vars_str)) {
+  for (std::string_view var : WordScanner(vars_str)) {
     Symbol sym = Intern(var);
     Var* v = ev->PeekVar(sym);
     if (!v->IsDefined()) {
@@ -873,9 +913,11 @@ void DeprecatedVarFunc(const vector<Value*>& args, Evaluator* ev, string*) {
   }
 }
 
-void ObsoleteVarFunc(const vector<Value*>& args, Evaluator* ev, string*) {
-  string vars_str = args[0]->Eval(ev);
-  string msg;
+void ObsoleteVarFunc(const std::vector<Value*>& args,
+                     Evaluator* ev,
+                     std::string*) {
+  std::string vars_str = args[0]->Eval(ev);
+  std::string msg;
 
   if (args.size() == 2) {
     msg = ". " + args[1]->Eval(ev);
@@ -885,7 +927,7 @@ void ObsoleteVarFunc(const vector<Value*>& args, Evaluator* ev, string*) {
     ev->Error("*** $(KATI_obsolete_var ...) is not supported in rules.");
   }
 
-  for (StringPiece var : WordScanner(vars_str)) {
+  for (std::string_view var : WordScanner(vars_str)) {
     Symbol sym = Intern(var);
     Var* v = ev->PeekVar(sym);
     if (!v->IsDefined()) {
@@ -908,8 +950,10 @@ void ObsoleteVarFunc(const vector<Value*>& args, Evaluator* ev, string*) {
   }
 }
 
-void DeprecateExportFunc(const vector<Value*>& args, Evaluator* ev, string*) {
-  string msg = ". " + args[0]->Eval(ev);
+void DeprecateExportFunc(const std::vector<Value*>& args,
+                         Evaluator* ev,
+                         std::string*) {
+  std::string msg = ". " + args[0]->Eval(ev);
 
   if (ev->avoid_io()) {
     ev->Error("*** $(KATI_deprecate_export) is not supported in rules.");
@@ -924,8 +968,10 @@ void DeprecateExportFunc(const vector<Value*>& args, Evaluator* ev, string*) {
   ev->SetExportDeprecated(msg);
 }
 
-void ObsoleteExportFunc(const vector<Value*>& args, Evaluator* ev, string*) {
-  string msg = ". " + args[0]->Eval(ev);
+void ObsoleteExportFunc(const std::vector<Value*>& args,
+                        Evaluator* ev,
+                        std::string*) {
+  std::string msg = ". " + args[0]->Eval(ev);
 
   if (ev->avoid_io()) {
     ev->Error("*** $(KATI_obsolete_export) is not supported in rules.");
@@ -938,27 +984,27 @@ void ObsoleteExportFunc(const vector<Value*>& args, Evaluator* ev, string*) {
   ev->SetExportObsolete(msg);
 }
 
-void ProfileFunc(const vector<Value*>& args, Evaluator* ev, string*) {
+void ProfileFunc(const std::vector<Value*>& args, Evaluator* ev, std::string*) {
   for (auto arg : args) {
-    string files = arg->Eval(ev);
-    for (StringPiece file : WordScanner(files)) {
+    std::string files = arg->Eval(ev);
+    for (std::string_view file : WordScanner(files)) {
       ev->ProfileMakefile(file);
     }
   }
 }
 
-void VariableLocationFunc(const vector<Value*>& args,
+void VariableLocationFunc(const std::vector<Value*>& args,
                           Evaluator* ev,
-                          string* s) {
-  string arg = args[0]->Eval(ev);
+                          std::string* s) {
+  std::string arg = args[0]->Eval(ev);
   WordWriter ww(s);
-  for (StringPiece var : WordScanner(arg)) {
+  for (std::string_view var : WordScanner(arg)) {
     Symbol sym = Intern(var);
     Var* v = ev->PeekVar(sym);
     const Loc& loc = v->Location();
     ww.Write(loc.filename ? loc.filename : "<unknown>");
-    AppendString(":", s);
-    AppendString(std::to_string(loc.lineno > 0 ? loc.lineno : 0), s);
+    s->append(":");
+    s->append(std::to_string(loc.lineno > 0 ? loc.lineno : 0));
   }
 }
 
@@ -967,7 +1013,7 @@ void VariableLocationFunc(const vector<Value*>& args,
     name, { name, args }     \
   }
 
-static const std::unordered_map<StringPiece, FuncInfo> g_func_info_map = {
+static const std::unordered_map<std::string_view, FuncInfo> g_func_info_map = {
 
     ENTRY("patsubst", &PatsubstFunc, 3, 3, false, false),
     ENTRY("strip", &StripFunc, 1, 1, false, false),
@@ -1024,13 +1070,13 @@ static const std::unordered_map<StringPiece, FuncInfo> g_func_info_map = {
 
 }  // namespace
 
-const FuncInfo* GetFuncInfo(StringPiece name) {
+const FuncInfo* GetFuncInfo(std::string_view name) {
   auto found = g_func_info_map.find(name);
   if (found == g_func_info_map.end())
     return nullptr;
   return &found->second;
 }
 
-const vector<CommandResult*>& GetShellCommandResults() {
+const std::vector<CommandResult*>& GetShellCommandResults() {
   return g_command_results;
 }
diff --git a/src/func.h b/src/func.h
index 206a363..efa5793 100644
--- a/src/func.h
+++ b/src/func.h
@@ -22,11 +22,9 @@
 #include "expr.h"
 #include "loc.h"
 
-using namespace std;
-
 struct FuncInfo {
   const char* name;
-  void (*func)(const vector<Value*>& args, Evaluator* ev, string* s);
+  void (*func)(const std::vector<Value*>& args, Evaluator* ev, std::string* s);
   int arity;
   int min_arity;
   // For all parameters.
@@ -35,7 +33,7 @@ struct FuncInfo {
   bool trim_right_space_1st;
 };
 
-const FuncInfo* GetFuncInfo(StringPiece name);
+const FuncInfo* GetFuncInfo(std::string_view name);
 
 struct FindCommand;
 
@@ -50,14 +48,14 @@ enum struct CommandOp {
 
 struct CommandResult {
   CommandOp op;
-  string shell;
-  string shellflag;
-  string cmd;
-  unique_ptr<FindCommand> find;
-  string result;
+  std::string shell;
+  std::string shellflag;
+  std::string cmd;
+  std::unique_ptr<FindCommand> find;
+  std::string result;
   Loc loc;
 };
 
-const vector<CommandResult*>& GetShellCommandResults();
+const std::vector<CommandResult*>& GetShellCommandResults();
 
 #endif  // FUNC_H_
diff --git a/src/io.cc b/src/io.cc
index 9ae1c5e..d2ee850 100644
--- a/src/io.cc
+++ b/src/io.cc
@@ -23,7 +23,7 @@ void DumpInt(FILE* fp, int v) {
   CHECK(r == 1);
 }
 
-void DumpString(FILE* fp, StringPiece s) {
+void DumpString(FILE* fp, std::string_view s) {
   DumpInt(fp, s.size());
   size_t r = fwrite(s.data(), 1, s.size(), fp);
   CHECK(r == s.size());
@@ -37,7 +37,7 @@ int LoadInt(FILE* fp) {
   return v;
 }
 
-bool LoadString(FILE* fp, string* s) {
+bool LoadString(FILE* fp, std::string* s) {
   int len = LoadInt(fp);
   if (len < 0)
     return false;
diff --git a/src/io.h b/src/io.h
index 28316f4..6f176a3 100644
--- a/src/io.h
+++ b/src/io.h
@@ -18,16 +18,13 @@
 #include <stdio.h>
 
 #include <string>
-
-#include "string_piece.h"
-
-using namespace std;
+#include <string_view>
 
 void DumpInt(FILE* fp, int v);
-void DumpString(FILE* fp, StringPiece s);
+void DumpString(FILE* fp, std::string_view s);
 
 int LoadInt(FILE* fp);
-bool LoadString(FILE* fp, string* s);
+bool LoadString(FILE* fp, std::string* s);
 
 struct ScopedFile {
  public:
diff --git a/src/log.cc b/src/log.cc
index 62f2422..90c17c5 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -31,10 +31,10 @@ void ColorErrorLog(const char* file, int line, const char* msg) {
   }
 
   if (g_flags.color_warnings) {
-    StringPiece filtered = TrimPrefix(msg, "*** ");
+    std::string_view filtered = TrimPrefix(msg, "*** ");
 
     ERROR(BOLD "%s:%d: " RED "error: " RESET BOLD "%s" RESET, file, line,
-          filtered.as_string().c_str());
+          std::string(filtered).c_str());
   } else {
     ERROR("%s:%d: %s", file, line, msg);
   }
@@ -47,16 +47,16 @@ void ColorWarnLog(const char* file, int line, const char* msg) {
   }
 
   if (g_flags.color_warnings) {
-    StringPiece filtered = TrimPrefix(msg, "*warning*: ");
+    std::string_view filtered = TrimPrefix(msg, "*warning*: ");
     filtered = TrimPrefix(filtered, "warning: ");
 
     fprintf(stderr,
             BOLD "%s:%d: " MAGENTA "warning: " RESET BOLD "%s" RESET "\n", file,
-            line, filtered.as_string().c_str());
+            line, std::string(filtered).c_str());
   } else {
     fprintf(stderr, "%s:%d: %s\n", file, line, msg);
   }
 }
 
 bool g_log_no_exit;
-string* g_last_error;
+std::string* g_last_error;
diff --git a/src/log.h b/src/log.h
index ba0bd8b..982f477 100644
--- a/src/log.h
+++ b/src/log.h
@@ -24,10 +24,10 @@
 #include "log.h"
 #include "stringprintf.h"
 
-using namespace std;
-
 extern bool g_log_no_exit;
-extern string* g_last_error;
+extern std::string* g_last_error;
+
+#define SPF(s) static_cast<int>((s).size()), (s).data()
 
 // Useful for logging-only arguments.
 #define UNUSED __attribute__((unused))
@@ -76,7 +76,7 @@ extern string* g_last_error;
       fprintf(stderr, "%s\n", StringPrintf(__VA_ARGS__).c_str()); \
       exit(1);                                                    \
     }                                                             \
-    g_last_error = new string(StringPrintf(__VA_ARGS__));         \
+    g_last_error = new std::string(StringPrintf(__VA_ARGS__));    \
   } while (0)
 
 #define CHECK(c) \
diff --git a/src/main.cc b/src/main.cc
index 417ec2c..a32d013 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -22,6 +22,8 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <string_view>
+
 #include "affinity.h"
 #include "eval.h"
 #include "exec.h"
@@ -37,7 +39,6 @@
 #include "regen.h"
 #include "stats.h"
 #include "stmt.h"
-#include "string_piece.h"
 #include "stringprintf.h"
 #include "strutil.h"
 #include "symtab.h"
@@ -49,9 +50,9 @@ extern "C" const char* __asan_default_options() {
   return "detect_leaks=0:allow_user_segv_handler=1";
 }
 
-static void ReadBootstrapMakefile(const vector<Symbol>& targets,
-                                  vector<Stmt*>* stmts) {
-  string bootstrap =
+static void ReadBootstrapMakefile(const std::vector<Symbol>& targets,
+                                  std::vector<Stmt*>* stmts) {
+  std::string bootstrap =
       ("CC?=cc\n"
 #if defined(__APPLE__)
        "CXX?=c++\n"
@@ -98,14 +99,14 @@ static void ReadBootstrapMakefile(const vector<Symbol>& targets,
   Parse(Intern(bootstrap).str(), Loc("*bootstrap*", 0), stmts);
 }
 
-static void SetVar(StringPiece l,
+static void SetVar(std::string_view l,
                    VarOrigin origin,
                    Frame* definition,
                    Loc loc) {
   size_t found = l.find('=');
-  CHECK(found != string::npos);
+  CHECK(found != std::string::npos);
   Symbol lhs = Intern(l.substr(0, found));
-  StringPiece rhs = l.substr(found + 1);
+  std::string_view rhs = l.substr(found + 1);
   lhs.SetGlobalVar(new RecursiveVar(Value::NewLiteral(rhs.data()), origin,
                                     definition, loc, rhs.data()));
 }
@@ -203,9 +204,9 @@ SegfaultHandler::~SegfaultHandler() {
   global_handler = nullptr;
 }
 
-static int Run(const vector<Symbol>& targets,
-               const vector<StringPiece>& cl_vars,
-               const string& orig_args) {
+static int Run(const std::vector<Symbol>& targets,
+               const std::vector<std::string_view>& cl_vars,
+               const std::string& orig_args) {
   double start_time = GetTime();
 
   if (g_flags.generate_ninja && (g_flags.regen || g_flags.dump_kati_stamp)) {
@@ -236,7 +237,7 @@ static int Run(const vector<Symbol>& targets,
   }
   SegfaultHandler segfault(&ev);
 
-  vector<Stmt*> bootstrap_asts;
+  std::vector<Stmt*> bootstrap_asts;
   ReadBootstrapMakefile(targets, &bootstrap_asts);
 
   {
@@ -251,8 +252,8 @@ static int Run(const vector<Symbol>& targets,
   {
     ScopedFrame frame(ev.Enter(FrameType::PHASE, "*command line*", Loc()));
     ev.in_command_line();
-    for (StringPiece l : cl_vars) {
-      vector<Stmt*> asts;
+    for (std::string_view l : cl_vars) {
+      std::vector<Stmt*> asts;
       Parse(Intern(l).str(), Loc("*bootstrap*", 0), &asts);
       CHECK(asts.size() == 1);
       asts[0]->Eval(&ev);
@@ -282,7 +283,7 @@ static int Run(const vector<Symbol>& targets,
     ev.DumpIncludeJSON(std::string(g_flags.dump_include_graph));
   }
 
-  vector<NamedDepNode> nodes;
+  std::vector<NamedDepNode> nodes;
   {
     ScopedFrame frame(
         ev.Enter(FrameType::PHASE, "*dependency analysis*", Loc()));
@@ -306,7 +307,7 @@ static int Run(const vector<Symbol>& targets,
     const Symbol name = p.first;
     if (p.second) {
       Var* v = ev.LookupVar(name);
-      const string&& value = v->Eval(&ev);
+      const std::string&& value = v->Eval(&ev);
       LOG("setenv(%s, %s)", name.c_str(), value.c_str());
       setenv(name.c_str(), value.c_str(), 1);
     } else {
@@ -357,7 +358,7 @@ int main(int argc, char* argv[]) {
     HandleRealpath(argc - 2, argv + 2);
     return 0;
   }
-  string orig_args;
+  std::string orig_args;
   for (int i = 0; i < argc; i++) {
     if (i)
       orig_args += ' ';
diff --git a/src/ninja.cc b/src/ninja.cc
index ee4a87f..469c89c 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -26,6 +26,7 @@
 #include <ostream>
 #include <sstream>
 #include <string>
+#include <string_view>
 #include <unordered_map>
 #include <unordered_set>
 
@@ -40,27 +41,26 @@
 #include "io.h"
 #include "log.h"
 #include "stats.h"
-#include "string_piece.h"
 #include "stringprintf.h"
 #include "strutil.h"
 #include "timeutil.h"
 #include "var.h"
 #include "version.h"
 
-static size_t FindCommandLineFlag(StringPiece cmd, StringPiece name) {
+static size_t FindCommandLineFlag(std::string_view cmd, std::string_view name) {
   const size_t found = cmd.find(name);
   if (found == std::string::npos || found == 0)
     return std::string::npos;
   return found;
 }
 
-static StringPiece FindCommandLineFlagWithArg(StringPiece cmd,
-                                              StringPiece name) {
+static std::string_view FindCommandLineFlagWithArg(std::string_view cmd,
+                                                   std::string_view name) {
   size_t index = FindCommandLineFlag(cmd, name);
   if (index == std::string::npos)
-    return StringPiece();
+    return std::string_view();
 
-  StringPiece val = TrimLeftSpace(cmd.substr(index + name.size()));
+  std::string_view val = TrimLeftSpace(cmd.substr(index + name.size()));
   index = val.find(name);
   while (index != std::string::npos) {
     val = TrimLeftSpace(val.substr(index + name.size()));
@@ -71,18 +71,18 @@ static StringPiece FindCommandLineFlagWithArg(StringPiece cmd,
   return val.substr(0, index);
 }
 
-static bool StripPrefix(StringPiece p, StringPiece* s) {
+static bool StripPrefix(std::string_view p, std::string_view* s) {
   if (!HasPrefix(*s, p))
     return false;
   *s = s->substr(p.size());
   return true;
 }
 
-size_t GetGomaccPosForAndroidCompileCommand(StringPiece cmdline) {
+size_t GetGomaccPosForAndroidCompileCommand(std::string_view cmdline) {
   size_t index = cmdline.find(' ');
   if (index == std::string::npos)
     return std::string::npos;
-  StringPiece cmd = cmdline.substr(0, index);
+  std::string_view cmd = cmdline.substr(0, index);
   if (HasSuffix(cmd, "ccache")) {
     index++;
     size_t pos = GetGomaccPosForAndroidCompileCommand(cmdline.substr(index));
@@ -97,30 +97,30 @@ size_t GetGomaccPosForAndroidCompileCommand(StringPiece cmdline) {
     return std::string::npos;
   }
 
-  StringPiece rest = cmdline.substr(index);
+  std::string_view rest = cmdline.substr(index);
   return rest.find(" -c ") != std::string::npos ? 0 : std::string::npos;
 }
 
-static bool GetDepfileFromCommandImpl(StringPiece cmd, std::string* out) {
+static bool GetDepfileFromCommandImpl(std::string_view cmd, std::string* out) {
   if ((FindCommandLineFlag(cmd, " -MD") == std::string::npos &&
        FindCommandLineFlag(cmd, " -MMD") == std::string::npos) ||
       FindCommandLineFlag(cmd, " -c") == std::string::npos) {
     return false;
   }
 
-  StringPiece mf = FindCommandLineFlagWithArg(cmd, " -MF");
+  std::string_view mf = FindCommandLineFlagWithArg(cmd, " -MF");
   if (!mf.empty()) {
-    mf.AppendToString(out);
+    out->append(mf);
     return true;
   }
 
-  StringPiece o = FindCommandLineFlagWithArg(cmd, " -o");
+  std::string_view o = FindCommandLineFlagWithArg(cmd, " -o");
   if (o.empty()) {
-    ERROR("Cannot find the depfile in %s", cmd.as_string().c_str());
+    ERROR("Cannot find the depfile in %s", std::string(cmd).c_str());
     return false;
   }
 
-  StripExt(o).AppendToString(out);
+  out->append(StripExt(o));
   *out += ".d";
   return true;
 }
@@ -138,8 +138,7 @@ bool GetDepfileFromCommand(std::string* cmd, std::string* out) {
   // TODO: A hack for Makefiles generated by automake.
 
   // A hack for Android to get .P files instead of .d.
-  std::string p;
-  StripExt(*out).AppendToString(&p);
+  std::string p{StripExt(*out)};
   p += ".P";
   if (cmd->find(p) != std::string::npos) {
     const std::string rm_f = "; rm -f " + *out;
@@ -154,7 +153,7 @@ bool GetDepfileFromCommand(std::string* cmd, std::string* out) {
   // A hack for Android. For .s files, GCC does not use C
   // preprocessor, so it ignores -MF flag.
   std::string as = "/";
-  StripExt(Basename(*out)).AppendToString(&as);
+  as.append(StripExt(Basename(*out)));
   as += ".s";
   if (cmd->find(as) != std::string::npos) {
     return false;
@@ -257,7 +256,7 @@ class NinjaGenerator {
     }
   }
 
-  StringPiece TranslateCommand(const char* in, std::string* cmd_buf) {
+  std::string_view TranslateCommand(const char* in, std::string* cmd_buf) {
     const size_t orig_size = cmd_buf->size();
     bool prev_backslash = false;
     // Set space as an initial value so the leading comment will be
@@ -327,27 +326,27 @@ class NinjaGenerator {
       cmd_buf->resize(cmd_buf->size() - 1);
     }
 
-    return StringPiece(cmd_buf->data() + orig_size,
-                       cmd_buf->size() - orig_size);
+    return std::string_view(cmd_buf->data() + orig_size,
+                            cmd_buf->size() - orig_size);
   }
 
-  bool IsOutputMkdir(const char* name, StringPiece cmd) {
+  bool IsOutputMkdir(const char* name, std::string_view cmd) {
     if (!HasPrefix(cmd, "mkdir -p ")) {
       return false;
     }
     cmd = cmd.substr(9, cmd.size());
-    if (cmd.get(cmd.size() - 1) == '/') {
-      cmd = cmd.substr(0, cmd.size() - 1);
+    if (!cmd.empty() && cmd.back() == '/') {
+      cmd.remove_suffix(1);
     }
 
-    StringPiece dir = Dirname(name);
+    std::string_view dir = Dirname(name);
     if (cmd == dir) {
       return true;
     }
     return false;
   }
 
-  bool GetDescriptionFromCommand(StringPiece cmd, std::string* out) {
+  bool GetDescriptionFromCommand(std::string_view cmd, std::string* out) {
     if (!HasPrefix(cmd, "echo ")) {
       return false;
     }
@@ -358,7 +357,7 @@ class NinjaGenerator {
     std::string out_buf;
 
     // Strip outer quotes, and fail if it is not a single echo command
-    for (StringPiece::iterator in = cmd.begin(); in != cmd.end(); in++) {
+    for (std::string_view::iterator in = cmd.begin(); in != cmd.end(); in++) {
       if (prev_backslash) {
         prev_backslash = false;
         out_buf += *in;
@@ -414,19 +413,20 @@ class NinjaGenerator {
       while (isspace(*in))
         in++;
 
-      bool needs_subshell = (command_count > 1 || c.ignore_error);
+      bool needs_subshell =
+          (command_count > 1 || c.ignore_error) && !c.force_no_subshell;
 
       if (needs_subshell)
         *cmd_buf += '(';
 
       size_t cmd_start = cmd_buf->size();
-      StringPiece translated = TranslateCommand(in, cmd_buf);
+      std::string_view translated = TranslateCommand(in, cmd_buf);
       if (g_flags.detect_android_echo && !got_descritpion && !c.echo &&
           GetDescriptionFromCommand(translated, description)) {
         got_descritpion = true;
-        translated.clear();
+        translated = std::string_view();
       } else if (IsOutputMkdir(name, translated) && !c.echo && cmd_begin == 0) {
-        translated.clear();
+        translated = std::string_view();
       }
       if (translated.empty()) {
         cmd_buf->resize(cmd_begin);
@@ -665,8 +665,8 @@ class NinjaGenerator {
     // PATH changes $(shell).
     used_env_vars.insert(Intern("PATH"));
     for (Symbol e : used_env_vars) {
-      StringPiece val(getenv(e.c_str()));
-      used_envs_.emplace(e.str(), val.as_string());
+      std::string_view val(getenv(e.c_str()));
+      used_envs_.emplace(e.str(), std::string(val));
     }
   }
 
@@ -770,7 +770,7 @@ class NinjaGenerator {
 
       if (cr->op == CommandOp::FIND) {
         std::vector<std::string> missing_dirs;
-        for (StringPiece fd : cr->find->finddirs) {
+        for (std::string_view fd : cr->find->finddirs) {
           const std::string& d = ConcatDir(cr->find->chdir, fd);
           if (!Exists(d))
             missing_dirs.push_back(d);
@@ -781,12 +781,12 @@ class NinjaGenerator {
         }
 
         DumpInt(fp, cr->find->found_files->size());
-        for (StringPiece s : *cr->find->found_files) {
+        for (std::string_view s : *cr->find->found_files) {
           DumpString(fp, ConcatDir(cr->find->chdir, s));
         }
 
         DumpInt(fp, cr->find->read_dirs->size());
-        for (StringPiece s : *cr->find->read_dirs) {
+        for (std::string_view s : *cr->find->read_dirs) {
           DumpString(fp, ConcatDir(cr->find->chdir, s));
         }
       }
@@ -816,15 +816,15 @@ class NinjaGenerator {
   const DepNode* default_target_;
 };
 
-string GetNinjaFilename() {
+std::string GetNinjaFilename() {
   return NinjaGenerator::GetFilename("build%s.ninja");
 }
 
-string GetNinjaShellScriptFilename() {
+std::string GetNinjaShellScriptFilename() {
   return NinjaGenerator::GetFilename("ninja%s.sh");
 }
 
-string GetNinjaStampFilename() {
+std::string GetNinjaStampFilename() {
   return NinjaGenerator::GetFilename(".kati_stamp%s");
 }
 
diff --git a/src/ninja.h b/src/ninja.h
index 281ce2c..521ad4c 100644
--- a/src/ninja.h
+++ b/src/ninja.h
@@ -18,10 +18,10 @@
 #include <time.h>
 
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "dep.h"
-#include "string_piece.h"
 
 class Evaluator;
 
@@ -30,12 +30,12 @@ void GenerateNinja(const std::vector<NamedDepNode>& nodes,
                    const std::string& orig_args,
                    double start_time);
 
-string GetNinjaFilename();
-string GetNinjaShellScriptFilename();
-string GetNinjaStampFilename();
+std::string GetNinjaFilename();
+std::string GetNinjaShellScriptFilename();
+std::string GetNinjaStampFilename();
 
 // Exposed only for test.
 bool GetDepfileFromCommand(std::string* cmd, std::string* out);
-size_t GetGomaccPosForAndroidCompileCommand(StringPiece cmdline);
+size_t GetGomaccPosForAndroidCompileCommand(std::string_view cmdline);
 
 #endif  // NINJA_H_
diff --git a/src/ninja_test.cc b/src/ninja_test.cc
index 15b0693..f46d2bb 100644
--- a/src/ninja_test.cc
+++ b/src/ninja_test.cc
@@ -23,9 +23,9 @@
 
 namespace {
 
-string GetDepfile(string cmd, string* new_cmd) {
+std::string GetDepfile(std::string cmd, std::string* new_cmd) {
   new_cmd->clear();
-  string r;
+  std::string r;
   if (GetDepfileFromCommand(&cmd, &r)) {
     *new_cmd = cmd;
     return r;
@@ -34,7 +34,7 @@ string GetDepfile(string cmd, string* new_cmd) {
 }
 
 void TestGetDepfile() {
-  string new_cmd;
+  std::string new_cmd;
   ASSERT_EQ(GetDepfile("g++ -c fat.cc -MD ", &new_cmd), "");
   assert(g_last_error);
   delete g_last_error;
@@ -74,7 +74,8 @@ static void TestGetGomaccPosForAndroidCompileCommand() {
                 "prebuilts/misc/linux-x86/ccache/ccache "
                 "prebuilts/clang/linux-x86/host/3.6/bin/clang++ -c foo.c"),
             39);
-  ASSERT_EQ(GetGomaccPosForAndroidCompileCommand("echo foo"), string::npos);
+  ASSERT_EQ(GetGomaccPosForAndroidCompileCommand("echo foo"),
+            std::string::npos);
 }
 
 }  // namespace
diff --git a/src/parser.cc b/src/parser.cc
index 9db7ac0..11da3c7 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -17,6 +17,7 @@
 #include "parser.h"
 
 #include <stack>
+#include <string_view>
 #include <unordered_map>
 
 #include "expr.h"
@@ -25,7 +26,6 @@
 #include "log.h"
 #include "stats.h"
 #include "stmt.h"
-#include "string_piece.h"
 #include "strutil.h"
 
 enum struct ParserState {
@@ -41,12 +41,12 @@ class Parser {
     int num_nest;
   };
 
-  typedef void (Parser::*DirectiveHandler)(StringPiece line,
-                                           StringPiece directive);
-  typedef unordered_map<StringPiece, DirectiveHandler> DirectiveMap;
+  typedef void (Parser::*DirectiveHandler)(std::string_view line,
+                                           std::string_view directive);
+  typedef std::unordered_map<std::string_view, DirectiveHandler> DirectiveMap;
 
  public:
-  Parser(StringPiece buf, const char* filename, vector<Stmt*>* stmts)
+  Parser(std::string_view buf, const char* filename, std::vector<Stmt*>* stmts)
       : buf_(buf),
         state_(ParserState::NOT_AFTER_RULE),
         stmts_(stmts),
@@ -56,7 +56,7 @@ class Parser {
         loc_(filename, 0),
         fixed_lineno_(false) {}
 
-  Parser(StringPiece buf, const Loc& loc, vector<Stmt*>* stmts)
+  Parser(std::string_view buf, const Loc& loc, std::vector<Stmt*>* stmts)
       : buf_(buf),
         state_(ParserState::NOT_AFTER_RULE),
         stmts_(stmts),
@@ -73,8 +73,8 @@ class Parser {
       size_t e = FindEndOfLine(&lf_cnt);
       if (!fixed_lineno_)
         loc_.lineno++;
-      StringPiece line(buf_.data() + l_, e - l_);
-      if (line.get(line.size() - 1) == '\r')
+      std::string_view line(buf_.data() + l_, e - l_);
+      if (!line.empty() && line.back() == '\r')
         line.remove_suffix(1);
       orig_line_with_directives_ = line;
       ParseLine(line);
@@ -95,10 +95,10 @@ class Parser {
 
   void set_state(ParserState st) { state_ = st; }
 
-  static vector<ParseErrorStmt*> parse_errors;
+  static std::vector<ParseErrorStmt*> parse_errors;
 
  private:
-  void Error(const string& msg) {
+  void Error(const std::string& msg) {
     ParseErrorStmt* stmt = new ParseErrorStmt();
     stmt->set_loc(loc_);
     stmt->msg = msg;
@@ -111,12 +111,12 @@ class Parser {
   }
 
   Value* ParseExpr(Loc* loc,
-                   StringPiece s,
+                   std::string_view s,
                    ParseExprOpt opt = ParseExprOpt::NORMAL) {
     return ::ParseExpr(loc, s, opt);
   }
 
-  void ParseLine(StringPiece line) {
+  void ParseLine(std::string_view line) {
     if (!define_name_.empty()) {
       ParseInsideDefine(line);
       return;
@@ -150,13 +150,13 @@ class Parser {
     ParseRuleOrAssign(line);
   }
 
-  void ParseRuleOrAssign(StringPiece line) {
+  void ParseRuleOrAssign(std::string_view line) {
     size_t sep = FindThreeOutsideParen(line, ':', '=', ';');
-    if (sep == string::npos || line[sep] == ';') {
-      ParseRule(line, string::npos);
+    if (sep == std::string::npos || line[sep] == ';') {
+      ParseRule(line, std::string::npos);
     } else if (line[sep] == '=') {
       ParseAssign(line, sep);
-    } else if (line.get(sep + 1) == '=') {
+    } else if (sep + 1 < line.size() && line[sep + 1] == '=') {
       ParseAssign(line, sep + 1);
     } else if (line[sep] == ':') {
       ParseRule(line, sep);
@@ -165,11 +165,11 @@ class Parser {
     }
   }
 
-  void ParseRule(StringPiece line, size_t sep) {
+  void ParseRule(std::string_view line, size_t sep) {
     if (current_directive_ != AssignDirective::NONE) {
       if (IsInExport())
         return;
-      if (sep != string::npos) {
+      if (sep != std::string::npos) {
         sep += orig_line_with_directives_.size() - line.size();
       }
       line = orig_line_with_directives_;
@@ -184,13 +184,13 @@ class Parser {
       return;
     }
 
-    const bool is_rule = sep != string::npos && line[sep] == ':';
+    const bool is_rule = sep != std::string::npos && line[sep] == ':';
     RuleStmt* rule_stmt = new RuleStmt();
     rule_stmt->set_loc(loc_);
 
     size_t found = FindTwoOutsideParen(line.substr(sep + 1), '=', ';');
     Loc mutable_loc(loc_);
-    if (found != string::npos) {
+    if (found != std::string::npos) {
       found += sep + 1;
       rule_stmt->lhs =
           ParseExpr(&mutable_loc, TrimSpace(line.substr(0, found)));
@@ -219,13 +219,13 @@ class Parser {
     state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE;
   }
 
-  void ParseAssign(StringPiece line, size_t separator_pos) {
+  void ParseAssign(std::string_view line, size_t separator_pos) {
     if (separator_pos == 0) {
       Error("*** empty variable name ***");
       return;
     }
-    StringPiece lhs;
-    StringPiece rhs;
+    std::string_view lhs;
+    std::string_view rhs;
     AssignOp op;
     ParseAssignStatement(line, separator_pos, &lhs, &rhs, &op);
 
@@ -252,7 +252,7 @@ class Parser {
     state_ = ParserState::NOT_AFTER_RULE;
   }
 
-  void ParseInclude(StringPiece line, StringPiece directive) {
+  void ParseInclude(std::string_view line, std::string_view directive) {
     IncludeStmt* stmt = new IncludeStmt();
     stmt->set_loc(loc_);
     Loc mutable_loc(loc_);
@@ -262,7 +262,7 @@ class Parser {
     state_ = ParserState::NOT_AFTER_RULE;
   }
 
-  void ParseDefine(StringPiece line, StringPiece) {
+  void ParseDefine(std::string_view line, std::string_view) {
     if (line.empty()) {
       Error("*** empty variable name.");
       return;
@@ -274,9 +274,9 @@ class Parser {
     state_ = ParserState::NOT_AFTER_RULE;
   }
 
-  void ParseInsideDefine(StringPiece line) {
+  void ParseInsideDefine(std::string_view line) {
     line = TrimLeftSpace(line);
-    StringPiece directive = GetDirective(line);
+    std::string_view directive = GetDirective(line);
     if (directive == "define")
       num_define_nest_++;
     else if (directive == "endef")
@@ -287,8 +287,8 @@ class Parser {
       return;
     }
 
-    StringPiece rest = TrimRightSpace(
-        RemoveComment(TrimLeftSpace(line.substr(sizeof("endef")))));
+    std::string_view rest = TrimRightSpace(
+        RemoveComment(TrimLeftSpace(line.substr(sizeof("endef") - 1))));
     if (!rest.empty()) {
       WARN_LOC(loc_, "extraneous text after `endef' directive");
     }
@@ -298,7 +298,7 @@ class Parser {
     Loc mutable_loc(stmt->loc());
     stmt->lhs = ParseExpr(&mutable_loc, define_name_);
     mutable_loc.lineno++;
-    StringPiece rhs;
+    std::string_view rhs;
     if (define_start_)
       rhs = buf_.substr(define_start_, l_ - define_start_ - 1);
     stmt->rhs = ParseExpr(&mutable_loc, rhs, ParseExprOpt::DEFINE);
@@ -306,7 +306,7 @@ class Parser {
     stmt->op = AssignOp::EQ;
     stmt->directive = current_directive_;
     out_stmts_->push_back(stmt);
-    define_name_.clear();
+    define_name_ = std::string_view();
   }
 
   void EnterIf(IfStmt* stmt) {
@@ -318,7 +318,7 @@ class Parser {
     out_stmts_ = &stmt->true_stmts;
   }
 
-  void ParseIfdef(StringPiece line, StringPiece directive) {
+  void ParseIfdef(std::string_view line, std::string_view directive) {
     IfStmt* stmt = new IfStmt();
     stmt->set_loc(loc_);
     stmt->op = directive[2] == 'n' ? CondOp::IFNDEF : CondOp::IFDEF;
@@ -329,7 +329,7 @@ class Parser {
     EnterIf(stmt);
   }
 
-  bool ParseIfEqCond(StringPiece s, IfStmt* stmt) {
+  bool ParseIfEqCond(std::string_view s, IfStmt* stmt) {
     if (s.empty()) {
       return false;
     }
@@ -346,7 +346,7 @@ class Parser {
       s = TrimLeftSpace(s.substr(n + 1));
       stmt->rhs =
           ParseExprImpl(&mutable_loc, s, NULL, ParseExprOpt::NORMAL, &n);
-      s = TrimLeftSpace(s.substr(n));
+      s = TrimLeftSpace(s.substr(std::min(n, s.size())));
     } else {
       for (int i = 0; i < 2; i++) {
         if (s.empty())
@@ -355,7 +355,7 @@ class Parser {
         if (quote != '\'' && quote != '"')
           return false;
         size_t end = s.find(quote, 1);
-        if (end == string::npos)
+        if (end == std::string::npos)
           return false;
         Value* v =
             ParseExpr(&mutable_loc, s.substr(1, end - 1), ParseExprOpt::NORMAL);
@@ -373,7 +373,7 @@ class Parser {
     return true;
   }
 
-  void ParseIfeq(StringPiece line, StringPiece directive) {
+  void ParseIfeq(std::string_view line, std::string_view directive) {
     IfStmt* stmt = new IfStmt();
     stmt->set_loc(loc_);
     stmt->op = directive[2] == 'n' ? CondOp::IFNEQ : CondOp::IFEQ;
@@ -387,7 +387,7 @@ class Parser {
     EnterIf(stmt);
   }
 
-  void ParseElse(StringPiece line, StringPiece) {
+  void ParseElse(std::string_view line, std::string_view) {
     if (!CheckIfStack("else"))
       return;
     IfState* st = if_stack_.top();
@@ -398,7 +398,7 @@ class Parser {
     st->is_in_else = true;
     out_stmts_ = &st->stmt->false_stmts;
 
-    StringPiece next_if = TrimLeftSpace(line);
+    std::string_view next_if = TrimLeftSpace(line);
     if (next_if.empty())
       return;
 
@@ -409,7 +409,7 @@ class Parser {
     num_if_nest_ = 0;
   }
 
-  void ParseEndif(StringPiece line, StringPiece) {
+  void ParseEndif(std::string_view line, std::string_view) {
     if (!CheckIfStack("endif"))
       return;
     if (!line.empty()) {
@@ -437,7 +437,7 @@ class Parser {
             static_cast<int>(AssignDirective::EXPORT));
   }
 
-  void CreateExport(StringPiece line, bool is_export) {
+  void CreateExport(std::string_view line, bool is_export) {
     ExportStmt* stmt = new ExportStmt;
     stmt->set_loc(loc_);
     Loc mutable_loc(loc_);
@@ -446,7 +446,7 @@ class Parser {
     out_stmts_->push_back(stmt);
   }
 
-  void ParseOverride(StringPiece line, StringPiece) {
+  void ParseOverride(std::string_view line, std::string_view) {
     current_directive_ = static_cast<AssignDirective>(
         (static_cast<int>(current_directive_) |
          static_cast<int>(AssignDirective::OVERRIDE)));
@@ -458,7 +458,7 @@ class Parser {
     ParseRuleOrAssign(line);
   }
 
-  void ParseExport(StringPiece line, StringPiece) {
+  void ParseExport(std::string_view line, std::string_view) {
     current_directive_ = static_cast<AssignDirective>(
         (static_cast<int>(current_directive_) |
          static_cast<int>(AssignDirective::EXPORT)));
@@ -468,7 +468,7 @@ class Parser {
     ParseRuleOrAssign(line);
   }
 
-  void ParseUnexport(StringPiece line, StringPiece) {
+  void ParseUnexport(std::string_view line, std::string_view) {
     CreateExport(line, false);
   }
   bool CheckIfStack(const char* keyword) {
@@ -479,50 +479,51 @@ class Parser {
     return true;
   }
 
-  StringPiece RemoveComment(StringPiece line) {
+  std::string_view RemoveComment(std::string_view line) {
     size_t i = FindOutsideParen(line, '#');
-    if (i == string::npos)
+    if (i == std::string::npos)
       return line;
     return line.substr(0, i);
   }
 
-  StringPiece GetDirective(StringPiece line) {
+  std::string_view GetDirective(std::string_view line) {
     if (line.size() < shortest_directive_len_)
-      return StringPiece();
-    StringPiece prefix = line.substr(0, longest_directive_len_ + 1);
+      return std::string_view();
+    std::string_view prefix = line.substr(0, longest_directive_len_ + 1);
     size_t space_index = prefix.find_first_of(" \t#");
     return prefix.substr(0, space_index);
   }
 
-  bool HandleDirective(StringPiece line, const DirectiveMap& directive_map) {
-    StringPiece directive = GetDirective(line);
+  bool HandleDirective(std::string_view line,
+                       const DirectiveMap& directive_map) {
+    std::string_view directive = GetDirective(line);
     auto found = directive_map.find(directive);
     if (found == directive_map.end())
       return false;
 
-    StringPiece rest = TrimRightSpace(
+    std::string_view rest = TrimRightSpace(
         RemoveComment(TrimLeftSpace(line.substr(directive.size()))));
     (this->*found->second)(rest, directive);
     return true;
   }
 
-  StringPiece buf_;
+  std::string_view buf_;
   size_t l_;
   ParserState state_;
 
-  vector<Stmt*>* stmts_;
-  vector<Stmt*>* out_stmts_;
+  std::vector<Stmt*>* stmts_;
+  std::vector<Stmt*>* out_stmts_;
 
-  StringPiece define_name_;
+  std::string_view define_name_;
   int num_define_nest_;
   size_t define_start_;
   int define_start_line_;
 
-  StringPiece orig_line_with_directives_;
+  std::string_view orig_line_with_directives_;
   AssignDirective current_directive_;
 
   int num_if_nest_;
-  stack<IfState*> if_stack_;
+  std::stack<IfState*> if_stack_;
 
   Loc loc_;
   bool fixed_lineno_;
@@ -536,20 +537,22 @@ class Parser {
 
 void Parse(Makefile* mk) {
   COLLECT_STATS("parse file time");
-  Parser parser(StringPiece(mk->buf()), mk->filename().c_str(),
+  Parser parser(std::string_view(mk->buf()), mk->filename().c_str(),
                 mk->mutable_stmts());
   parser.Parse();
 }
 
-void Parse(StringPiece buf, const Loc& loc, vector<Stmt*>* out_stmts) {
+void Parse(std::string_view buf,
+           const Loc& loc,
+           std::vector<Stmt*>* out_stmts) {
   COLLECT_STATS("parse eval time");
   Parser parser(buf, loc, out_stmts);
   parser.Parse();
 }
 
-void ParseNotAfterRule(StringPiece buf,
+void ParseNotAfterRule(std::string_view buf,
                        const Loc& loc,
-                       vector<Stmt*>* out_stmts) {
+                       std::vector<Stmt*>* out_stmts) {
   Parser parser(buf, loc, out_stmts);
   parser.set_state(ParserState::NOT_AFTER_RULE);
   parser.Parse();
@@ -595,12 +598,12 @@ const size_t Parser::longest_directive_len_ = []() {
   return result;
 }();
 
-vector<ParseErrorStmt*> Parser::parse_errors;
+std::vector<ParseErrorStmt*> Parser::parse_errors;
 
-void ParseAssignStatement(StringPiece line,
+void ParseAssignStatement(std::string_view line,
                           size_t sep,
-                          StringPiece* lhs,
-                          StringPiece* rhs,
+                          std::string_view* lhs,
+                          std::string_view* rhs,
                           AssignOp* op) {
   CHECK(sep != 0);
   *op = AssignOp::EQ;
@@ -620,9 +623,9 @@ void ParseAssignStatement(StringPiece line,
       break;
   }
   *lhs = TrimSpace(line.substr(0, lhs_end));
-  *rhs = TrimLeftSpace(line.substr(sep + 1));
+  *rhs = TrimLeftSpace(line.substr(std::min(sep + 1, line.size())));
 }
 
-const vector<ParseErrorStmt*>& GetParseErrors() {
+const std::vector<ParseErrorStmt*>& GetParseErrors() {
   return Parser::parse_errors;
 }
diff --git a/src/parser.h b/src/parser.h
index e42ef5b..d0457d2 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -15,28 +15,26 @@
 #ifndef PARSER_H_
 #define PARSER_H_
 
+#include <string_view>
 #include <vector>
 
 #include "loc.h"
 #include "stmt.h"
-#include "string_piece.h"
-
-using namespace std;
 
 class Makefile;
 
 void Parse(Makefile* mk);
-void Parse(StringPiece buf, const Loc& loc, vector<Stmt*>* out_asts);
-void ParseNotAfterRule(StringPiece buf,
+void Parse(std::string_view buf, const Loc& loc, std::vector<Stmt*>* out_asts);
+void ParseNotAfterRule(std::string_view buf,
                        const Loc& loc,
-                       vector<Stmt*>* out_asts);
+                       std::vector<Stmt*>* out_asts);
 
-void ParseAssignStatement(StringPiece line,
+void ParseAssignStatement(std::string_view line,
                           size_t sep,
-                          StringPiece* lhs,
-                          StringPiece* rhs,
+                          std::string_view* lhs,
+                          std::string_view* rhs,
                           AssignOp* op);
 
-const vector<ParseErrorStmt*>& GetParseErrors();
+const std::vector<ParseErrorStmt*>& GetParseErrors();
 
 #endif  // PARSER_H_
diff --git a/src/regen.cc b/src/regen.cc
index ee2559f..458c4cd 100644
--- a/src/regen.cc
+++ b/src/regen.cc
@@ -44,27 +44,28 @@ namespace {
       return true;               \
   } while (0)
 
-bool ShouldIgnoreDirty(StringPiece s) {
-  Pattern pat(g_flags.ignore_dirty_pattern);
-  Pattern nopat(g_flags.no_ignore_dirty_pattern);
+bool ShouldIgnoreDirty(std::string_view s) {
+  Pattern pat(g_flags.ignore_dirty_pattern ? g_flags.ignore_dirty_pattern : "");
+  Pattern nopat(
+      g_flags.no_ignore_dirty_pattern ? g_flags.no_ignore_dirty_pattern : "");
   return pat.Match(s) && !nopat.Match(s);
 }
 
 class StampChecker {
   struct GlobResult {
-    string pat;
-    vector<string> result;
+    std::string pat;
+    std::vector<std::string> result;
   };
 
   struct ShellResult {
     CommandOp op;
-    string shell;
-    string shellflag;
-    string cmd;
-    string result;
-    vector<string> missing_dirs;
-    vector<string> files;
-    vector<string> read_dirs;
+    std::string shell;
+    std::string shellflag;
+    std::string cmd;
+    std::string result;
+    std::vector<std::string> missing_dirs;
+    std::vector<std::string> files;
+    std::vector<std::string> read_dirs;
   };
 
  public:
@@ -79,7 +80,7 @@ class StampChecker {
     }
   }
 
-  bool NeedsRegen(double start_time, const string& orig_args) {
+  bool NeedsRegen(double start_time, const std::string& orig_args) {
     if (IsMissingOutputs())
       RETURN_TRUE;
 
@@ -117,7 +118,7 @@ class StampChecker {
     return false;
   }
 
-  bool CheckStep1(const string& orig_args) {
+  bool CheckStep1(const std::string& orig_args) {
 #define LOAD_INT(fp)                                               \
   ({                                                               \
     int v = LoadInt(fp);                                           \
@@ -136,7 +137,7 @@ class StampChecker {
     }                                                              \
   })
 
-    const string& stamp_filename = GetNinjaStampFilename();
+    const std::string& stamp_filename = GetNinjaStampFilename();
     FILE* fp = fopen(stamp_filename.c_str(), "rb");
     if (!fp) {
       if (g_flags.regen_debug)
@@ -155,7 +156,7 @@ class StampChecker {
     if (g_flags.regen_debug)
       printf("Generated time: %f\n", gen_time);
 
-    string s, s2;
+    std::string s, s2;
     int num_files = LOAD_INT(fp);
     for (int i = 0; i < num_files; i++) {
       LOAD_STRING(fp, &s);
@@ -201,7 +202,8 @@ class StampChecker {
     int num_envs = LOAD_INT(fp);
     for (int i = 0; i < num_envs; i++) {
       LOAD_STRING(fp, &s);
-      StringPiece val(getenv(s.c_str()));
+      const char* val_c_str = getenv(s.c_str());
+      std::string_view val(val_c_str ? val_c_str : "");
       LOAD_STRING(fp, &s2);
       if (val != s2) {
         if (g_flags.dump_kati_stamp) {
@@ -220,7 +222,7 @@ class StampChecker {
     }
 
     int num_globs = LOAD_INT(fp);
-    string pat;
+    std::string pat;
     for (int i = 0; i < num_globs; i++) {
       GlobResult* gr = new GlobResult;
       globs_.push_back(gr);
@@ -243,7 +245,7 @@ class StampChecker {
       LOAD_STRING(fp, &sr->cmd);
       LOAD_STRING(fp, &sr->result);
 
-      string file;
+      std::string file;
       // Ignore debug info
       LOAD_STRING(fp, &file);
       LOAD_INT(fp);
@@ -276,7 +278,7 @@ class StampChecker {
     return needs_regen_;
   }
 
-  bool CheckGlobResult(const GlobResult* gr, string* err) {
+  bool CheckGlobResult(const GlobResult* gr, std::string* err) {
     COLLECT_STATS("glob time (regen)");
     const auto& files = Glob(gr->pat.c_str());
     bool needs_regen = files.size() != gr->result.size();
@@ -312,15 +314,15 @@ class StampChecker {
       return true;
 
     COLLECT_STATS("stat time (regen)");
-    for (const string& dir : sr->missing_dirs) {
+    for (const std::string& dir : sr->missing_dirs) {
       if (Exists(dir))
         return true;
     }
-    for (const string& file : sr->files) {
+    for (const std::string& file : sr->files) {
       if (!Exists(file))
         return true;
     }
-    for (const string& dir : sr->read_dirs) {
+    for (const std::string& dir : sr->read_dirs) {
       // We assume we rarely do a significant change for the top
       // directory which affects the results of find command.
       if (dir == "" || dir == "." || ShouldIgnoreDirty(dir))
@@ -343,7 +345,7 @@ class StampChecker {
     return false;
   }
 
-  bool CheckShellResult(const ShellResult* sr, string* err) {
+  bool CheckShellResult(const ShellResult* sr, std::string* err) {
     if (sr->op == CommandOp::READ_MISSING) {
       if (Exists(sr->cmd)) {
         if (g_flags.dump_kati_stamp)
@@ -407,7 +409,7 @@ class StampChecker {
     }
 
     COLLECT_STATS_WITH_SLOW_REPORT("shell time (regen)", sr->cmd.c_str());
-    string result;
+    std::string result;
     RunCommand(sr->shell, sr->shellflag, sr->cmd, RedirectStderr::DEV_NULL,
                &result);
     FormatForCommandSubstitution(&result);
@@ -428,12 +430,12 @@ class StampChecker {
 
   bool CheckStep2() {
     auto glob_future = std::async([this]() {
-      string err;
+      std::string err;
       // TODO: Make glob cache thread safe and create a task for each glob.
       SetAffinityForSingleThread();
       for (GlobResult* gr : globs_) {
         if (CheckGlobResult(gr, &err)) {
-          unique_lock<mutex> lock(mu_);
+          std::unique_lock<std::mutex> lock(mu_);
           if (!needs_regen_) {
             needs_regen_ = true;
             msg_ = err;
@@ -446,9 +448,9 @@ class StampChecker {
     auto shell_future = std::async([this]() {
       SetAffinityForSingleThread();
       for (ShellResult* sr : commands_) {
-        string err;
+        std::string err;
         if (CheckShellResult(sr, &err)) {
-          unique_lock<mutex> lock(mu_);
+          std::unique_lock<std::mutex> lock(mu_);
           if (!needs_regen_) {
             needs_regen_ = true;
             msg_ = err;
@@ -467,15 +469,15 @@ class StampChecker {
 
  private:
   double gen_time_;
-  vector<GlobResult*> globs_;
-  vector<ShellResult*> commands_;
-  mutex mu_;
+  std::vector<GlobResult*> globs_;
+  std::vector<ShellResult*> commands_;
+  std::mutex mu_;
   bool needs_regen_;
-  string msg_;
+  std::string msg_;
 };
 
 }  // namespace
 
-bool NeedsRegen(double start_time, const string& orig_args) {
+bool NeedsRegen(double start_time, const std::string& orig_args) {
   return StampChecker().NeedsRegen(start_time, orig_args);
 }
diff --git a/src/regen.h b/src/regen.h
index 3d43d70..91f67f1 100644
--- a/src/regen.h
+++ b/src/regen.h
@@ -17,8 +17,6 @@
 
 #include <string>
 
-using namespace std;
-
-bool NeedsRegen(double start_time, const string& orig_args);
+bool NeedsRegen(double start_time, const std::string& orig_args);
 
 #endif  // REGEN_H_
diff --git a/src/regen_dump.cc b/src/regen_dump.cc
index 13ab8be..70034dc 100644
--- a/src/regen_dump.cc
+++ b/src/regen_dump.cc
@@ -29,12 +29,14 @@
 #include "log.h"
 #include "strutil.h"
 
-vector<string> LoadVecString(FILE* fp) {
+using namespace std;
+
+vector<std::string> LoadVecString(FILE* fp) {
   int count = LoadInt(fp);
   if (count < 0) {
     ERROR("Incomplete stamp file");
   }
-  vector<string> ret(count);
+  std::vector<std::string> ret(count);
   for (int i = 0; i < count; i++) {
     if (!LoadString(fp, &ret[i])) {
       ERROR("Incomplete stamp file");
diff --git a/src/rule.cc b/src/rule.cc
index 867a7e3..01692d1 100644
--- a/src/rule.cc
+++ b/src/rule.cc
@@ -25,7 +25,7 @@
 
 Rule::Rule() : is_double_colon(false), is_suffix_rule(false), cmd_lineno(0) {}
 
-void Rule::ParseInputs(const StringPiece& inputs_str) {
+void Rule::ParseInputs(const std::string_view& inputs_str) {
   bool is_order_only = false;
   for (auto const& input : WordScanner(inputs_str)) {
     if (input == "|") {
@@ -37,7 +37,7 @@ void Rule::ParseInputs(const StringPiece& inputs_str) {
   }
 }
 
-void Rule::ParsePrerequisites(const StringPiece& line,
+void Rule::ParsePrerequisites(const std::string_view& line,
                               size_t separator_pos,
                               const RuleStmt* rule_stmt) {
   // line is either
@@ -46,8 +46,8 @@ void Rule::ParsePrerequisites(const StringPiece& line,
   //    target-prerequisites : prereq-patterns [ ; command ]
   // First, separate command. At this point separator_pos should point to ';'
   // unless null.
-  StringPiece prereq_string = line;
-  if (separator_pos != string::npos &&
+  std::string_view prereq_string = line;
+  if (separator_pos != std::string::npos &&
       rule_stmt->sep != RuleStmt::SEP_SEMICOLON) {
     CHECK(line[separator_pos] == ';');
     // TODO: Maybe better to avoid Intern here?
@@ -56,7 +56,7 @@ void Rule::ParsePrerequisites(const StringPiece& line,
     prereq_string = line.substr(0, separator_pos);
   }
 
-  if ((separator_pos = prereq_string.find(':')) == string::npos) {
+  if ((separator_pos = prereq_string.find(':')) == std::string::npos) {
     // Simple prerequisites
     ParseInputs(prereq_string);
     return;
@@ -73,10 +73,10 @@ void Rule::ParsePrerequisites(const StringPiece& line,
     return;
   }
 
-  StringPiece target_prereq = prereq_string.substr(0, separator_pos);
-  StringPiece prereq_patterns = prereq_string.substr(separator_pos + 1);
+  std::string_view target_prereq = prereq_string.substr(0, separator_pos);
+  std::string_view prereq_patterns = prereq_string.substr(separator_pos + 1);
 
-  for (StringPiece target_pattern : WordScanner(target_prereq)) {
+  for (std::string_view target_pattern : WordScanner(target_prereq)) {
     target_pattern = TrimLeadingCurdir(target_pattern);
     for (Symbol target : outputs) {
       if (!Pattern(target_pattern).Match(target.str())) {
@@ -99,8 +99,8 @@ void Rule::ParsePrerequisites(const StringPiece& line,
   ParseInputs(prereq_patterns);
 }
 
-string Rule::DebugString() const {
-  vector<string> v;
+std::string Rule::DebugString() const {
+  std::vector<std::string> v;
   v.push_back(StringPrintf("outputs=[%s]", JoinSymbols(outputs, ",").c_str()));
   v.push_back(StringPrintf("inputs=[%s]", JoinSymbols(inputs, ",").c_str()));
   if (!order_only_inputs.empty()) {
diff --git a/src/rule.h b/src/rule.h
index 237eb02..59f6de6 100644
--- a/src/rule.h
+++ b/src/rule.h
@@ -17,16 +17,14 @@
 
 #include <functional>
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "loc.h"
 #include "log.h"
 #include "stmt.h"
-#include "string_piece.h"
 #include "symtab.h"
 
-using namespace std;
-
 class Value;
 
 class Rule {
@@ -35,31 +33,31 @@ class Rule {
 
   Loc cmd_loc() const { return Loc(loc.filename, cmd_lineno); }
 
-  string DebugString() const;
+  std::string DebugString() const;
 
-  void ParseInputs(const StringPiece& inputs_string);
+  void ParseInputs(const std::string_view& inputs_string);
 
-  void ParsePrerequisites(const StringPiece& line,
+  void ParsePrerequisites(const std::string_view& line,
                           size_t pos,
                           const RuleStmt* rule_stmt);
 
-  static bool IsPatternRule(const StringPiece& target_string) {
-    return target_string.find('%') != string::npos;
+  static bool IsPatternRule(const std::string_view& target_string) {
+    return target_string.find('%') != std::string::npos;
   }
 
-  vector<Symbol> outputs;
-  vector<Symbol> inputs;
-  vector<Symbol> order_only_inputs;
-  vector<Symbol> output_patterns;
-  vector<Symbol> validations;
+  std::vector<Symbol> outputs;
+  std::vector<Symbol> inputs;
+  std::vector<Symbol> order_only_inputs;
+  std::vector<Symbol> output_patterns;
+  std::vector<Symbol> validations;
   bool is_double_colon;
   bool is_suffix_rule;
-  vector<Value*> cmds;
+  std::vector<Value*> cmds;
   Loc loc;
   int cmd_lineno;
 
  private:
-  void Error(const string& msg) { ERROR_LOC(loc, "%s", msg.c_str()); }
+  void Error(const std::string& msg) { ERROR_LOC(loc, "%s", msg.c_str()); }
 };
 
 #endif  // RULE_H_
diff --git a/src/stats.cc b/src/stats.cc
index be03774..6dccf7d 100644
--- a/src/stats.cc
+++ b/src/stats.cc
@@ -28,31 +28,31 @@
 
 namespace {
 
-mutex g_mu;
-vector<Stats*>* g_stats;
+std::mutex g_mu;
+std::vector<Stats*>* g_stats;
 
 }  // namespace
 
 Stats::Stats(const char* name) : name_(name), elapsed_(0), cnt_(0) {
-  unique_lock<mutex> lock(g_mu);
+  std::unique_lock<std::mutex> lock(g_mu);
   if (g_stats == NULL)
-    g_stats = new vector<Stats*>;
+    g_stats = new std::vector<Stats*>;
   g_stats->push_back(this);
 }
 
 void Stats::DumpTop() const {
-  unique_lock<mutex> lock(mu_);
+  std::unique_lock<std::mutex> lock(mu_);
   if (detailed_.size() > 0) {
-    vector<pair<string, StatsDetails>> details(detailed_.begin(),
-                                               detailed_.end());
+    std::vector<std::pair<std::string, StatsDetails>> details(detailed_.begin(),
+                                                              detailed_.end());
     sort(details.begin(), details.end(),
-         [](const pair<string, StatsDetails> a,
-            const pair<string, StatsDetails> b) -> bool {
+         [](const std::pair<std::string, StatsDetails> a,
+            const std::pair<std::string, StatsDetails> b) -> bool {
            return a.second.elapsed_ > b.second.elapsed_;
          });
 
     // Only print the top 10
-    details.resize(min(details.size(), static_cast<size_t>(10)));
+    details.resize(std::min(details.size(), static_cast<size_t>(10)));
 
     if (!interesting_.empty()) {
       // No need to print anything out twice
@@ -73,8 +73,8 @@ void Stats::DumpTop() const {
 
     int max_cnt_len = 1;
     for (auto& [name, detail] : details) {
-      max_cnt_len =
-          max(max_cnt_len, static_cast<int>(to_string(detail.cnt_).length()));
+      max_cnt_len = std::max(
+          max_cnt_len, static_cast<int>(std::to_string(detail.cnt_).length()));
     }
 
     for (auto& [name, detail] : details) {
@@ -84,8 +84,8 @@ void Stats::DumpTop() const {
   }
 }
 
-string Stats::String() const {
-  unique_lock<mutex> lock(mu_);
+std::string Stats::String() const {
+  std::unique_lock<std::mutex> lock(mu_);
   if (!detailed_.empty())
     return StringPrintf("%s: %f / %d (%d unique)", name_, elapsed_, cnt_,
                         detailed_.size());
@@ -94,25 +94,25 @@ string Stats::String() const {
 
 double Stats::Start() {
   double start = GetTime();
-  unique_lock<mutex> lock(mu_);
+  std::unique_lock<std::mutex> lock(mu_);
   cnt_++;
   return start;
 }
 
 double Stats::End(double start, const char* msg) {
   double e = GetTime() - start;
-  unique_lock<mutex> lock(mu_);
+  std::unique_lock<std::mutex> lock(mu_);
   elapsed_ += e;
   if (msg != 0) {
-    StatsDetails& details = detailed_[string(msg)];
+    StatsDetails& details = detailed_[std::string(msg)];
     details.elapsed_ += e;
     details.cnt_++;
   }
   return e;
 }
 
-void Stats::MarkInteresting(const string& msg) {
-  unique_lock<mutex> lock(mu_);
+void Stats::MarkInteresting(const std::string& msg) {
+  std::unique_lock<std::mutex> lock(mu_);
   interesting_.emplace(msg);
 }
 
diff --git a/src/stats.h b/src/stats.h
index 4501353..2c311f0 100644
--- a/src/stats.h
+++ b/src/stats.h
@@ -20,8 +20,6 @@
 #include <unordered_map>
 #include <unordered_set>
 
-using namespace std;
-
 struct StatsDetails {
   int cnt_ = 0;
   double elapsed_ = 0;
@@ -32,9 +30,9 @@ class Stats {
   explicit Stats(const char* name);
 
   void DumpTop() const;
-  string String() const;
+  std::string String() const;
 
-  void MarkInteresting(const string& msg);
+  void MarkInteresting(const std::string& msg);
 
  private:
   double Start();
@@ -45,9 +43,9 @@ class Stats {
   const char* name_;
   double elapsed_;
   int cnt_;
-  mutable mutex mu_;
-  unordered_map<string, StatsDetails> detailed_;
-  unordered_set<string> interesting_;
+  mutable std::mutex mu_;
+  std::unordered_map<std::string, StatsDetails> detailed_;
+  std::unordered_set<std::string> interesting_;
 };
 
 class ScopedStatsRecorder {
diff --git a/src/stmt.cc b/src/stmt.cc
index 7315dc1..7c7d4f4 100644
--- a/src/stmt.cc
+++ b/src/stmt.cc
@@ -30,13 +30,13 @@ void Stmt::Eval(Evaluator* ev) const {
   EvalStatement(ev);
 }
 
-string RuleStmt::DebugString() const {
+std::string RuleStmt::DebugString() const {
   return StringPrintf("RuleStmt(lhs=%s sep=%d rhs=%s loc=%s:%d)",
                       Value::DebugString(lhs).c_str(), sep,
                       Value::DebugString(rhs).c_str(), LOCF(loc()));
 }
 
-string AssignStmt::DebugString() const {
+std::string AssignStmt::DebugString() const {
   const char* opstr = "???";
   switch (op) {
     case AssignOp::EQ:
@@ -68,12 +68,12 @@ string AssignStmt::DebugString() const {
       "AssignStmt(lhs=%s rhs=%s (%s) "
       "opstr=%s dir=%s loc=%s:%d)",
       Value::DebugString(lhs).c_str(), Value::DebugString(rhs).c_str(),
-      NoLineBreak(orig_rhs.as_string()).c_str(), opstr, dirstr, LOCF(loc()));
+      NoLineBreak(std::string(orig_rhs)).c_str(), opstr, dirstr, LOCF(loc()));
 }
 
 Symbol AssignStmt::GetLhsSymbol(Evaluator* ev) const {
   if (!lhs->IsLiteral()) {
-    string buf;
+    std::string buf;
     lhs->Eval(ev, &buf);
     return Intern(buf);
   }
@@ -84,12 +84,12 @@ Symbol AssignStmt::GetLhsSymbol(Evaluator* ev) const {
   return lhs_sym_cache_;
 }
 
-string CommandStmt::DebugString() const {
+std::string CommandStmt::DebugString() const {
   return StringPrintf("CommandStmt(%s, loc=%s:%d)",
                       Value::DebugString(expr).c_str(), LOCF(loc()));
 }
 
-string IfStmt::DebugString() const {
+std::string IfStmt::DebugString() const {
   const char* opstr = "???";
   switch (op) {
     case CondOp::IFEQ:
@@ -111,17 +111,17 @@ string IfStmt::DebugString() const {
                       false_stmts.size(), LOCF(loc()));
 }
 
-string IncludeStmt::DebugString() const {
+std::string IncludeStmt::DebugString() const {
   return StringPrintf("IncludeStmt(%s, loc=%s:%d)",
                       Value::DebugString(expr).c_str(), LOCF(loc()));
 }
 
-string ExportStmt::DebugString() const {
+std::string ExportStmt::DebugString() const {
   return StringPrintf("ExportStmt(%s, %d, loc=%s:%d)",
                       Value::DebugString(expr).c_str(), is_export, LOCF(loc()));
 }
 
-string ParseErrorStmt::DebugString() const {
+std::string ParseErrorStmt::DebugString() const {
   return StringPrintf("ParseErrorStmt(%s, loc=%s:%d)", msg.c_str(),
                       LOCF(loc()));
 }
diff --git a/src/stmt.h b/src/stmt.h
index d0ef79b..1173f1b 100644
--- a/src/stmt.h
+++ b/src/stmt.h
@@ -16,14 +16,12 @@
 #define STMT_H_
 
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "loc.h"
-#include "string_piece.h"
 #include "symtab.h"
 
-using namespace std;
-
 class Evaluator;
 class Value;
 
@@ -53,19 +51,19 @@ struct Stmt {
 
   Loc loc() const { return loc_; }
   void set_loc(Loc loc) { loc_ = loc; }
-  StringPiece orig() const { return orig_; }
+  std::string_view orig() const { return orig_; }
 
   void Eval(Evaluator*) const;
   virtual void EvalStatement(Evaluator* ev) const = 0;
 
-  virtual string DebugString() const = 0;
+  virtual std::string DebugString() const = 0;
 
  protected:
   Stmt();
 
  private:
   Loc loc_;
-  StringPiece orig_;
+  std::string_view orig_;
 };
 
 /* Parsed "rule statement" before evaluation is kept as
@@ -84,13 +82,13 @@ struct RuleStmt : public Stmt {
 
   virtual void EvalStatement(Evaluator* ev) const;
 
-  virtual string DebugString() const;
+  virtual std::string DebugString() const;
 };
 
 struct AssignStmt : public Stmt {
   Value* lhs;
   Value* rhs;
-  StringPiece orig_rhs;
+  std::string_view orig_rhs;
   AssignOp op;
   AssignDirective directive;
   bool is_final;
@@ -100,7 +98,7 @@ struct AssignStmt : public Stmt {
 
   virtual void EvalStatement(Evaluator* ev) const;
 
-  virtual string DebugString() const;
+  virtual std::string DebugString() const;
 
   Symbol GetLhsSymbol(Evaluator* ev) const;
 
@@ -110,27 +108,27 @@ struct AssignStmt : public Stmt {
 
 struct CommandStmt : public Stmt {
   Value* expr;
-  StringPiece orig;
+  std::string_view orig;
 
   virtual ~CommandStmt();
 
   virtual void EvalStatement(Evaluator* ev) const;
 
-  virtual string DebugString() const;
+  virtual std::string DebugString() const;
 };
 
 struct IfStmt : public Stmt {
   CondOp op;
   Value* lhs;
   Value* rhs;
-  vector<Stmt*> true_stmts;
-  vector<Stmt*> false_stmts;
+  std::vector<Stmt*> true_stmts;
+  std::vector<Stmt*> false_stmts;
 
   virtual ~IfStmt();
 
   virtual void EvalStatement(Evaluator* ev) const;
 
-  virtual string DebugString() const;
+  virtual std::string DebugString() const;
 };
 
 struct IncludeStmt : public Stmt {
@@ -141,7 +139,7 @@ struct IncludeStmt : public Stmt {
 
   virtual void EvalStatement(Evaluator* ev) const;
 
-  virtual string DebugString() const;
+  virtual std::string DebugString() const;
 };
 
 struct ExportStmt : public Stmt {
@@ -152,17 +150,17 @@ struct ExportStmt : public Stmt {
 
   virtual void EvalStatement(Evaluator* ev) const;
 
-  virtual string DebugString() const;
+  virtual std::string DebugString() const;
 };
 
 struct ParseErrorStmt : public Stmt {
-  string msg;
+  std::string msg;
 
   virtual ~ParseErrorStmt();
 
   virtual void EvalStatement(Evaluator* ev) const;
 
-  virtual string DebugString() const;
+  virtual std::string DebugString() const;
 };
 
 #endif  // STMT_H_
diff --git a/src/string_piece.cc b/src/string_piece.cc
deleted file mode 100644
index 32a7be0..0000000
--- a/src/string_piece.cc
+++ /dev/null
@@ -1,239 +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.
-
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-// Copied from strings/stringpiece.cc with modifications
-
-// +build ignore
-
-#include "string_piece.h"
-
-#include <ctype.h>
-#include <limits.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <ostream>
-
-typedef StringPiece::size_type size_type;
-
-bool operator==(const StringPiece& x, const StringPiece& y) {
-  if (x.size() != y.size())
-    return false;
-  size_t len = x.size();
-  if (len >= sizeof(uint64_t)) {
-    len -= sizeof(uint64_t);
-    uint64_t xt = *reinterpret_cast<const uint64_t*>(x.data() + len);
-    uint64_t yt = *reinterpret_cast<const uint64_t*>(y.data() + len);
-    if (xt != yt)
-      return false;
-  }
-  return StringPiece::wordmemcmp(x.data(), y.data(), len) == 0;
-}
-
-void StringPiece::CopyToString(std::string* target) const {
-  target->assign(!empty() ? data() : "", size());
-}
-
-void StringPiece::AppendToString(std::string* target) const {
-  if (!empty())
-    target->append(data(), size());
-}
-
-size_type StringPiece::copy(char* buf, size_type n, size_type pos) const {
-  size_type ret = std::min(length_ - pos, n);
-  memcpy(buf, ptr_ + pos, ret);
-  return ret;
-}
-
-size_type StringPiece::find(const StringPiece& s, size_type pos) const {
-  if (pos > length_)
-    return npos;
-
-  const char* result =
-      std::search(ptr_ + pos, ptr_ + length_, s.ptr_, s.ptr_ + s.length_);
-  const size_type xpos = result - ptr_;
-  return xpos + s.length_ <= length_ ? xpos : npos;
-}
-
-size_type StringPiece::find(char c, size_type pos) const {
-  if (pos >= length_)
-    return npos;
-
-  const char* result = std::find(ptr_ + pos, ptr_ + length_, c);
-  return result != ptr_ + length_ ? static_cast<size_t>(result - ptr_) : npos;
-}
-
-size_type StringPiece::rfind(const StringPiece& s, size_type pos) const {
-  if (length_ < s.length_)
-    return npos;
-
-  if (s.empty())
-    return std::min(length_, pos);
-
-  const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_;
-  const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
-  return result != last ? static_cast<size_t>(result - ptr_) : npos;
-}
-
-size_type StringPiece::rfind(char c, size_type pos) const {
-  if (length_ == 0)
-    return npos;
-
-  for (size_type i = std::min(pos, length_ - 1);; --i) {
-    if (ptr_[i] == c)
-      return i;
-    if (i == 0)
-      break;
-  }
-  return npos;
-}
-
-// For each character in characters_wanted, sets the index corresponding
-// to the ASCII code of that character to 1 in table.  This is used by
-// the find_.*_of methods below to tell whether or not a character is in
-// the lookup table in constant time.
-// The argument `table' must be an array that is large enough to hold all
-// the possible values of an unsigned char.  Thus it should be be declared
-// as follows:
-//   bool table[UCHAR_MAX + 1]
-static inline void BuildLookupTable(const StringPiece& characters_wanted,
-                                    bool* table) {
-  const size_type length = characters_wanted.length();
-  const char* const data = characters_wanted.data();
-  for (size_type i = 0; i < length; ++i) {
-    table[static_cast<unsigned char>(data[i])] = true;
-  }
-}
-
-size_type StringPiece::find_first_of(const StringPiece& s,
-                                     size_type pos) const {
-  if (length_ == 0 || s.length_ == 0)
-    return npos;
-
-  // Avoid the cost of BuildLookupTable() for a single-character search.
-  if (s.length_ == 1)
-    return find_first_of(s.ptr_[0], pos);
-
-  bool lookup[UCHAR_MAX + 1] = {false};
-  BuildLookupTable(s, lookup);
-  for (size_type i = pos; i < length_; ++i) {
-    if (lookup[static_cast<unsigned char>(ptr_[i])]) {
-      return i;
-    }
-  }
-  return npos;
-}
-
-size_type StringPiece::find_first_not_of(const StringPiece& s,
-                                         size_type pos) const {
-  if (length_ == 0)
-    return npos;
-
-  if (s.length_ == 0)
-    return 0;
-
-  // Avoid the cost of BuildLookupTable() for a single-character search.
-  if (s.length_ == 1)
-    return find_first_not_of(s.ptr_[0], pos);
-
-  bool lookup[UCHAR_MAX + 1] = {false};
-  BuildLookupTable(s, lookup);
-  for (size_type i = pos; i < length_; ++i) {
-    if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
-      return i;
-    }
-  }
-  return npos;
-}
-
-size_type StringPiece::find_first_not_of(char c, size_type pos) const {
-  if (length_ == 0)
-    return npos;
-
-  for (; pos < length_; ++pos) {
-    if (ptr_[pos] != c) {
-      return pos;
-    }
-  }
-  return npos;
-}
-
-size_type StringPiece::find_last_of(const StringPiece& s, size_type pos) const {
-  if (length_ == 0 || s.length_ == 0)
-    return npos;
-
-  // Avoid the cost of BuildLookupTable() for a single-character search.
-  if (s.length_ == 1)
-    return find_last_of(s.ptr_[0], pos);
-
-  bool lookup[UCHAR_MAX + 1] = {false};
-  BuildLookupTable(s, lookup);
-  for (size_type i = std::min(pos, length_ - 1);; --i) {
-    if (lookup[static_cast<unsigned char>(ptr_[i])])
-      return i;
-    if (i == 0)
-      break;
-  }
-  return npos;
-}
-
-size_type StringPiece::find_last_not_of(const StringPiece& s,
-                                        size_type pos) const {
-  if (length_ == 0)
-    return npos;
-
-  size_type i = std::min(pos, length_ - 1);
-  if (s.length_ == 0)
-    return i;
-
-  // Avoid the cost of BuildLookupTable() for a single-character search.
-  if (s.length_ == 1)
-    return find_last_not_of(s.ptr_[0], pos);
-
-  bool lookup[UCHAR_MAX + 1] = {false};
-  BuildLookupTable(s, lookup);
-  for (;; --i) {
-    if (!lookup[static_cast<unsigned char>(ptr_[i])])
-      return i;
-    if (i == 0)
-      break;
-  }
-  return npos;
-}
-
-size_type StringPiece::find_last_not_of(char c, size_type pos) const {
-  if (length_ == 0)
-    return npos;
-
-  for (size_type i = std::min(pos, length_ - 1);; --i) {
-    if (ptr_[i] != c)
-      return i;
-    if (i == 0)
-      break;
-  }
-  return npos;
-}
-
-StringPiece StringPiece::substr(size_type pos, size_type n) const {
-  if (pos > length_)
-    pos = length_;
-  if (n > length_ - pos)
-    n = length_ - pos;
-  return StringPiece(ptr_ + pos, n);
-}
-
-const StringPiece::size_type StringPiece::npos = size_type(-1);
diff --git a/src/string_piece.h b/src/string_piece.h
deleted file mode 100644
index df3562f..0000000
--- a/src/string_piece.h
+++ /dev/null
@@ -1,224 +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.
-
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-// Copied from strings/stringpiece.h with modifications
-//
-// A string-like object that points to a sized piece of memory.
-//
-// Functions or methods may use const StringPiece& parameters to accept either
-// a "const char*" or a "string" value that will be implicitly converted to
-// a StringPiece.  The implicit conversion means that it is often appropriate
-// to include this .h file in other files rather than forward-declaring
-// StringPiece as would be appropriate for most other Google classes.
-//
-// Systematic usage of StringPiece is encouraged as it will reduce unnecessary
-// conversions from "const char*" to "string" and back again.
-//
-
-#ifndef BASE_STRING_PIECE_H_
-#define BASE_STRING_PIECE_H_
-#pragma once
-
-#include <stddef.h>
-#include <string.h>
-
-#include <string>
-
-//#include "base/base_api.h"
-//#include "base/basictypes.h"
-
-class StringPiece {
- public:
-  // standard STL container boilerplate
-  typedef size_t size_type;
-  typedef char value_type;
-  typedef const char* pointer;
-  typedef const char& reference;
-  typedef const char& const_reference;
-  typedef ptrdiff_t difference_type;
-  typedef const char* const_iterator;
-  typedef const char* iterator;
-  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-  typedef std::reverse_iterator<iterator> reverse_iterator;
-
-  static const size_type npos;
-
- public:
-  // We provide non-explicit singleton constructors so users can pass
-  // in a "const char*" or a "string" wherever a "StringPiece" is
-  // expected.
-  StringPiece() : ptr_(NULL), length_(0) {}
-  StringPiece(const char* str)
-      : ptr_(str), length_((str == NULL) ? 0 : strlen(str)) {}
-  StringPiece(const std::string& str) : ptr_(str.data()), length_(str.size()) {}
-  StringPiece(const std::string&& str)
-      : ptr_(str.data()), length_(str.size()) {}
-  StringPiece(const char* offset, size_type len) : ptr_(offset), length_(len) {}
-
-  // data() may return a pointer to a buffer with embedded NULs, and the
-  // returned buffer may or may not be null terminated.  Therefore it is
-  // typically a mistake to pass data() to a routine that expects a NUL
-  // terminated string.
-  const char* data() const { return ptr_; }
-  size_type size() const { return length_; }
-  size_type length() const { return length_; }
-  bool empty() const { return length_ == 0; }
-
-  void clear() {
-    ptr_ = NULL;
-    length_ = 0;
-  }
-  void set(const char* data, size_type len) {
-    ptr_ = data;
-    length_ = len;
-  }
-  void set(const char* str) {
-    ptr_ = str;
-    length_ = str ? strlen(str) : 0;
-  }
-  void set(const void* data, size_type len) {
-    ptr_ = reinterpret_cast<const char*>(data);
-    length_ = len;
-  }
-
-  char operator[](size_type i) const { return ptr_[i]; }
-
-  void remove_prefix(size_type n) {
-    ptr_ += n;
-    length_ -= n;
-  }
-
-  void remove_suffix(size_type n) { length_ -= n; }
-
-  int compare(const StringPiece& x) const {
-    int r =
-        wordmemcmp(ptr_, x.ptr_, (length_ < x.length_ ? length_ : x.length_));
-    if (r == 0) {
-      if (length_ < x.length_)
-        r = -1;
-      else if (length_ > x.length_)
-        r = +1;
-    }
-    return r;
-  }
-
-  std::string as_string() const {
-    // std::string doesn't like to take a NULL pointer even with a 0 size.
-    return std::string(!empty() ? data() : "", size());
-  }
-
-  void CopyToString(std::string* target) const;
-  void AppendToString(std::string* target) const;
-
-  // Does "this" start with "x"
-  bool starts_with(const StringPiece& x) const {
-    return ((length_ >= x.length_) &&
-            (wordmemcmp(ptr_, x.ptr_, x.length_) == 0));
-  }
-
-  // Does "this" end with "x"
-  bool ends_with(const StringPiece& x) const {
-    return ((length_ >= x.length_) &&
-            (wordmemcmp(ptr_ + (length_ - x.length_), x.ptr_, x.length_) == 0));
-  }
-
-  iterator begin() const { return ptr_; }
-  iterator end() const { return ptr_ + length_; }
-  const_reverse_iterator rbegin() const {
-    return const_reverse_iterator(ptr_ + length_);
-  }
-  const_reverse_iterator rend() const { return const_reverse_iterator(ptr_); }
-
-  size_type max_size() const { return length_; }
-  size_type capacity() const { return length_; }
-
-  size_type copy(char* buf, size_type n, size_type pos = 0) const;
-
-  size_type find(const StringPiece& s, size_type pos = 0) const;
-  size_type find(char c, size_type pos = 0) const;
-  size_type rfind(const StringPiece& s, size_type pos = npos) const;
-  size_type rfind(char c, size_type pos = npos) const;
-
-  size_type find_first_of(const StringPiece& s, size_type pos = 0) const;
-  size_type find_first_of(char c, size_type pos = 0) const {
-    return find(c, pos);
-  }
-  size_type find_first_not_of(const StringPiece& s, size_type pos = 0) const;
-  size_type find_first_not_of(char c, size_type pos = 0) const;
-  size_type find_last_of(const StringPiece& s, size_type pos = npos) const;
-  size_type find_last_of(char c, size_type pos = npos) const {
-    return rfind(c, pos);
-  }
-  size_type find_last_not_of(const StringPiece& s, size_type pos = npos) const;
-  size_type find_last_not_of(char c, size_type pos = npos) const;
-
-  StringPiece substr(size_type pos, size_type n = npos) const;
-
-  static int wordmemcmp(const char* p, const char* p2, size_type N) {
-    return memcmp(p, p2, N);
-  }
-
-  // kati specific functions will follow.
-
-  char get(size_type i) const { return i < length_ ? ptr_[i] : 0; }
-
- private:
-  const char* ptr_;
-  size_type length_;
-};
-
-bool operator==(const StringPiece& x, const StringPiece& y);
-
-inline bool operator!=(const StringPiece& x, const StringPiece& y) {
-  return !(x == y);
-}
-
-inline bool operator<(const StringPiece& x, const StringPiece& y) {
-  const int r = StringPiece::wordmemcmp(
-      x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size()));
-  return ((r < 0) || ((r == 0) && (x.size() < y.size())));
-}
-
-inline bool operator>(const StringPiece& x, const StringPiece& y) {
-  return y < x;
-}
-
-inline bool operator<=(const StringPiece& x, const StringPiece& y) {
-  return !(x > y);
-}
-
-inline bool operator>=(const StringPiece& x, const StringPiece& y) {
-  return !(x < y);
-}
-
-namespace std {
-template <>
-struct hash<StringPiece> {
-  size_t operator()(const StringPiece& s) const {
-    size_t result = 0;
-    for (char c : s) {
-      result = (result * 131) + c;
-    }
-    return result;
-  }
-};
-
-}  // namespace std
-
-#define SPF(s) static_cast<int>((s).size()), (s).data()
-
-#endif  // BASE_STRING_PIECE_H_
diff --git a/src/string_piece_test.cc b/src/string_piece_test.cc
deleted file mode 100644
index 0434cbe..0000000
--- a/src/string_piece_test.cc
+++ /dev/null
@@ -1,37 +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.
-
-// +build ignore
-
-#include "string_piece.h"
-
-#include <assert.h>
-
-#include <unordered_set>
-
-using namespace std;
-
-int main() {
-  unordered_set<StringPiece> sps;
-  sps.insert(StringPiece("foo"));
-  sps.insert(StringPiece("foo"));
-  sps.insert(StringPiece("bar"));
-  assert(sps.size() == 2);
-  assert(sps.count(StringPiece("foo")) == 1);
-  assert(sps.count(StringPiece("bar")) == 1);
-
-  assert(StringPiece("hogefugahige") == StringPiece("hogefugahige"));
-  assert(StringPiece("hogefugahoge") != StringPiece("hogefugahige"));
-  assert(StringPiece("hogefugahige") != StringPiece("higefugahige"));
-}
diff --git a/src/stringprintf.cc b/src/stringprintf.cc
index b0d4b4a..c16ca18 100644
--- a/src/stringprintf.cc
+++ b/src/stringprintf.cc
@@ -19,8 +19,8 @@
 #include <assert.h>
 #include <stdarg.h>
 
-string StringPrintf(const char* format, ...) {
-  string str;
+std::string StringPrintf(const char* format, ...) {
+  std::string str;
   str.resize(128);
   for (int i = 0; i < 2; i++) {
     va_list args;
diff --git a/src/stringprintf.h b/src/stringprintf.h
index 8b67e6c..d7e10a9 100644
--- a/src/stringprintf.h
+++ b/src/stringprintf.h
@@ -17,8 +17,6 @@
 
 #include <string>
 
-using namespace std;
-
-string StringPrintf(const char* fmt, ...);
+std::string StringPrintf(const char* fmt, ...);
 
 #endif  // STRINGPRINTF_H_
diff --git a/src/strutil.cc b/src/strutil.cc
index 8c4bdc0..0a222ad 100644
--- a/src/strutil.cc
+++ b/src/strutil.cc
@@ -53,11 +53,11 @@ WordScanner::Iterator& WordScanner::Iterator::operator++() {
   return *this;
 }
 
-StringPiece WordScanner::Iterator::operator*() const {
+std::string_view WordScanner::Iterator::operator*() const {
   return in->substr(s, i - s);
 }
 
-WordScanner::WordScanner(StringPiece in) : in_(in) {}
+WordScanner::WordScanner(std::string_view in) : in_(in) {}
 
 WordScanner::Iterator WordScanner::begin() const {
   Iterator iter;
@@ -76,12 +76,12 @@ WordScanner::Iterator WordScanner::end() const {
   return iter;
 }
 
-void WordScanner::Split(vector<StringPiece>* o) {
-  for (StringPiece t : *this)
+void WordScanner::Split(std::vector<std::string_view>* o) {
+  for (std::string_view t : *this)
     o->push_back(t);
 }
 
-WordWriter::WordWriter(string* o) : out_(o), needs_space_(false) {}
+WordWriter::WordWriter(std::string* o) : out_(o), needs_space_(false) {}
 
 void WordWriter::MaybeAddWhitespace() {
   if (needs_space_) {
@@ -91,12 +91,13 @@ void WordWriter::MaybeAddWhitespace() {
   }
 }
 
-void WordWriter::Write(StringPiece s) {
+void WordWriter::Write(std::string_view s) {
   MaybeAddWhitespace();
-  AppendString(s, out_);
+  out_->append(s);
 }
 
-ScopedTerminator::ScopedTerminator(StringPiece s) : s_(s), c_(s[s.size()]) {
+ScopedTerminator::ScopedTerminator(std::string_view s)
+    : s_(s), c_(s[s.size()]) {
   const_cast<char*>(s_.data())[s_.size()] = '\0';
 }
 
@@ -104,23 +105,19 @@ ScopedTerminator::~ScopedTerminator() {
   const_cast<char*>(s_.data())[s_.size()] = c_;
 }
 
-void AppendString(StringPiece str, string* out) {
-  out->append(str.begin(), str.end());
-}
-
-bool HasPrefix(StringPiece str, StringPiece prefix) {
+bool HasPrefix(std::string_view str, std::string_view prefix) {
   ssize_t size_diff = str.size() - prefix.size();
   return size_diff >= 0 && str.substr(0, prefix.size()) == prefix;
 }
 
-bool HasSuffix(StringPiece str, StringPiece suffix) {
+bool HasSuffix(std::string_view str, std::string_view suffix) {
   ssize_t size_diff = str.size() - suffix.size();
   return size_diff >= 0 && str.substr(size_diff) == suffix;
 }
 
-bool HasWord(StringPiece str, StringPiece w) {
+bool HasWord(std::string_view str, std::string_view w) {
   size_t found = str.find(w);
-  if (found == string::npos)
+  if (found == std::string::npos)
     return false;
   if (found != 0 && !isSpace(str[found - 1]))
     return false;
@@ -130,99 +127,99 @@ bool HasWord(StringPiece str, StringPiece w) {
   return true;
 }
 
-StringPiece TrimPrefix(StringPiece str, StringPiece prefix) {
+std::string_view TrimPrefix(std::string_view str, std::string_view prefix) {
   ssize_t size_diff = str.size() - prefix.size();
   if (size_diff < 0 || str.substr(0, prefix.size()) != prefix)
     return str;
   return str.substr(prefix.size());
 }
 
-StringPiece TrimSuffix(StringPiece str, StringPiece suffix) {
+std::string_view TrimSuffix(std::string_view str, std::string_view suffix) {
   ssize_t size_diff = str.size() - suffix.size();
   if (size_diff < 0 || str.substr(size_diff) != suffix)
     return str;
   return str.substr(0, size_diff);
 }
 
-Pattern::Pattern(StringPiece pat) : pat_(pat), percent_index_(pat.find('%')) {}
+Pattern::Pattern(std::string_view pat)
+    : pat_(pat), percent_index_(pat.find('%')) {}
 
-bool Pattern::Match(StringPiece str) const {
-  if (percent_index_ == string::npos)
+bool Pattern::Match(std::string_view str) const {
+  if (percent_index_ == std::string::npos)
     return str == pat_;
   return MatchImpl(str);
 }
 
-bool Pattern::MatchImpl(StringPiece str) const {
+bool Pattern::MatchImpl(std::string_view str) const {
   return (HasPrefix(str, pat_.substr(0, percent_index_)) &&
           HasSuffix(str, pat_.substr(percent_index_ + 1)));
 }
 
-StringPiece Pattern::Stem(StringPiece str) const {
+std::string_view Pattern::Stem(std::string_view str) const {
   if (!Match(str))
     return "";
-  return str.substr(percent_index_,
-                    str.size() - pat_.size() + 1);
+  return str.substr(percent_index_, str.size() - pat_.size() + 1);
 }
 
-void Pattern::AppendSubst(StringPiece str,
-                          StringPiece subst,
-                          string* out) const {
-  if (percent_index_ == string::npos) {
+void Pattern::AppendSubst(std::string_view str,
+                          std::string_view subst,
+                          std::string* out) const {
+  if (percent_index_ == std::string::npos) {
     if (str == pat_) {
-      AppendString(subst, out);
+      out->append(subst);
       return;
     } else {
-      AppendString(str, out);
+      out->append(str);
       return;
     }
   }
 
   if (MatchImpl(str)) {
     size_t subst_percent_index = subst.find('%');
-    if (subst_percent_index == string::npos) {
-      AppendString(subst, out);
+    if (subst_percent_index == std::string::npos) {
+      out->append(subst);
       return;
     } else {
-      AppendString(subst.substr(0, subst_percent_index), out);
-      AppendString(str.substr(percent_index_, str.size() - pat_.size() + 1),
-                   out);
-      AppendString(subst.substr(subst_percent_index + 1), out);
+      out->append(subst.substr(0, subst_percent_index));
+      out->append(str.substr(percent_index_, str.size() - pat_.size() + 1));
+      out->append(subst.substr(subst_percent_index + 1));
       return;
     }
   }
-  AppendString(str, out);
+  out->append(str);
 }
 
-void Pattern::AppendSubstRef(StringPiece str,
-                             StringPiece subst,
-                             string* out) const {
-  if (percent_index_ != string::npos && subst.find('%') != string::npos) {
+void Pattern::AppendSubstRef(std::string_view str,
+                             std::string_view subst,
+                             std::string* out) const {
+  if (percent_index_ != std::string::npos &&
+      subst.find('%') != std::string::npos) {
     AppendSubst(str, subst, out);
     return;
   }
-  StringPiece s = TrimSuffix(str, pat_);
+  std::string_view s = TrimSuffix(str, pat_);
   out->append(s.begin(), s.end());
   out->append(subst.begin(), subst.end());
 }
 
-string NoLineBreak(const string& s) {
+std::string NoLineBreak(const std::string& s) {
   size_t index = s.find('\n');
-  if (index == string::npos)
+  if (index == std::string::npos)
     return s;
-  string r = s;
-  while (index != string::npos) {
+  std::string r = s;
+  while (index != std::string::npos) {
     r = r.substr(0, index) + "\\n" + r.substr(index + 1);
     index = r.find('\n', index + 2);
   }
   return r;
 }
 
-StringPiece TrimLeftSpace(StringPiece s) {
+std::string_view TrimLeftSpace(std::string_view s) {
   size_t i = 0;
   for (; i < s.size(); i++) {
     if (isSpace(s[i]))
       continue;
-    char n = s.get(i + 1);
+    char n = i + 1 < s.size() ? s[i + 1] : 0;
     if (s[i] == '\\' && (n == '\r' || n == '\n')) {
       i++;
       continue;
@@ -232,12 +229,13 @@ StringPiece TrimLeftSpace(StringPiece s) {
   return s.substr(i, s.size() - i);
 }
 
-StringPiece TrimRightSpace(StringPiece s) {
+std::string_view TrimRightSpace(std::string_view s) {
   size_t i = 0;
   for (; i < s.size(); i++) {
     char c = s[s.size() - 1 - i];
     if (isSpace(c)) {
-      if ((c == '\r' || c == '\n') && s.get(s.size() - 2 - i) == '\\')
+      if ((c == '\r' || c == '\n') && s.size() >= i + 2 &&
+          s[s.size() - 2 - i] == '\\')
         i++;
       continue;
     }
@@ -246,43 +244,43 @@ StringPiece TrimRightSpace(StringPiece s) {
   return s.substr(0, s.size() - i);
 }
 
-StringPiece TrimSpace(StringPiece s) {
+std::string_view TrimSpace(std::string_view s) {
   return TrimRightSpace(TrimLeftSpace(s));
 }
 
-StringPiece Dirname(StringPiece s) {
+std::string_view Dirname(std::string_view s) {
   size_t found = s.rfind('/');
-  if (found == string::npos)
-    return StringPiece(".");
+  if (found == std::string::npos)
+    return std::string_view(".");
   if (found == 0)
-    return StringPiece("");
+    return std::string_view("");
   return s.substr(0, found);
 }
 
-StringPiece Basename(StringPiece s) {
+std::string_view Basename(std::string_view s) {
   size_t found = s.rfind('/');
-  if (found == string::npos || found == 0)
+  if (found == std::string::npos || found == 0)
     return s;
   return s.substr(found + 1);
 }
 
-StringPiece GetExt(StringPiece s) {
+std::string_view GetExt(std::string_view s) {
   size_t found = s.rfind('.');
-  if (found == string::npos)
-    return StringPiece("");
+  if (found == std::string::npos)
+    return std::string_view("");
   return s.substr(found);
 }
 
-StringPiece StripExt(StringPiece s) {
+std::string_view StripExt(std::string_view s) {
   size_t slash_index = s.rfind('/');
   size_t found = s.rfind('.');
-  if (found == string::npos ||
-      (slash_index != string::npos && found < slash_index))
+  if (found == std::string::npos ||
+      (slash_index != std::string::npos && found < slash_index))
     return s;
   return s.substr(0, found);
 }
 
-void NormalizePath(string* o) {
+void NormalizePath(std::string* o) {
   if (o->empty())
     return;
   size_t start_index = 0;
@@ -298,7 +296,8 @@ void NormalizePath(string* o) {
       continue;
     }
 
-    StringPiece prev_dir = StringPiece(o->data() + prev_start, j - prev_start);
+    std::string_view prev_dir =
+        std::string_view(o->data() + prev_start, j - prev_start);
     if (prev_dir == ".") {
       j--;
     } else if (prev_dir == ".." && j != 2 /* .. */) {
@@ -309,12 +308,12 @@ void NormalizePath(string* o) {
         size_t orig_j = j;
         j -= 4;
         j = o->rfind('/', j);
-        if (j == string::npos) {
+        if (j == std::string::npos) {
           j = start_index;
         } else {
           j++;
         }
-        if (StringPiece(o->data() + j, 3) == "../") {
+        if (std::string_view(o->data() + j, 3) == "../") {
           j = orig_j;
           (*o)[j] = c;
           j++;
@@ -333,8 +332,8 @@ void NormalizePath(string* o) {
   o->resize(j);
 }
 
-void AbsPath(StringPiece s, string* o) {
-  if (s.get(0) == '/') {
+void AbsPath(std::string_view s, std::string* o) {
+  if (!s.empty() && s.front() == '/') {
     o->clear();
   } else {
     char buf[PATH_MAX];
@@ -347,14 +346,14 @@ void AbsPath(StringPiece s, string* o) {
     *o = buf;
     *o += '/';
   }
-  AppendString(s, o);
+  o->append(s);
   NormalizePath(o);
 }
 
 template <typename Cond>
-size_t FindOutsideParenImpl(StringPiece s, Cond cond) {
+size_t FindOutsideParenImpl(std::string_view s, Cond cond) {
   bool prev_backslash = false;
-  stack<char> paren_stack;
+  std::stack<char> paren_stack;
   for (size_t i = 0; i < s.size(); i++) {
     char c = s[i];
     if (cond(c) && paren_stack.empty() && !prev_backslash) {
@@ -377,24 +376,24 @@ size_t FindOutsideParenImpl(StringPiece s, Cond cond) {
     }
     prev_backslash = c == '\\' && !prev_backslash;
   }
-  return string::npos;
+  return std::string::npos;
 }
 
-size_t FindOutsideParen(StringPiece s, char c) {
+size_t FindOutsideParen(std::string_view s, char c) {
   return FindOutsideParenImpl(s, [&c](char d) { return c == d; });
 }
 
-size_t FindTwoOutsideParen(StringPiece s, char c1, char c2) {
+size_t FindTwoOutsideParen(std::string_view s, char c1, char c2) {
   return FindOutsideParenImpl(
       s, [&c1, &c2](char d) { return d == c1 || d == c2; });
 }
 
-size_t FindThreeOutsideParen(StringPiece s, char c1, char c2, char c3) {
+size_t FindThreeOutsideParen(std::string_view s, char c1, char c2, char c3) {
   return FindOutsideParenImpl(
       s, [&c1, &c2, &c3](char d) { return d == c1 || d == c2 || d == c3; });
 }
 
-size_t FindEndOfLine(StringPiece s, size_t e, size_t* lf_cnt) {
+size_t FindEndOfLine(std::string_view s, size_t e, size_t* lf_cnt) {
   while (e < s.size()) {
     e += SkipUntil(s.data() + e, s.size() - e, "\n\\");  // skip to line end
     if (e >= s.size()) {
@@ -424,13 +423,13 @@ size_t FindEndOfLine(StringPiece s, size_t e, size_t* lf_cnt) {
   return e;
 }
 
-StringPiece TrimLeadingCurdir(StringPiece s) {
+std::string_view TrimLeadingCurdir(std::string_view s) {
   while (s.substr(0, 2) == "./")
     s = s.substr(2);
   return s;
 }
 
-void FormatForCommandSubstitution(string* s) {
+void FormatForCommandSubstitution(std::string* s) {
   while ((*s)[s->size() - 1] == '\n')
     s->pop_back();
   for (size_t i = 0; i < s->size(); i++) {
@@ -439,29 +438,29 @@ void FormatForCommandSubstitution(string* s) {
   }
 }
 
-string SortWordsInString(StringPiece s) {
-  vector<string> toks;
-  for (StringPiece tok : WordScanner(s)) {
-    toks.push_back(tok.as_string());
+std::string SortWordsInString(std::string_view s) {
+  std::vector<std::string> toks;
+  for (std::string_view tok : WordScanner(s)) {
+    toks.push_back(std::string(tok));
   }
   sort(toks.begin(), toks.end());
   return JoinStrings(toks, " ");
 }
 
-string ConcatDir(StringPiece b, StringPiece n) {
-  string r;
+std::string ConcatDir(std::string_view b, std::string_view n) {
+  std::string r;
   if (!b.empty() && (n.empty() || n[0] != '/')) {
-    b.AppendToString(&r);
+    r.append(b);
     r += '/';
   }
-  n.AppendToString(&r);
+  r.append(n);
   NormalizePath(&r);
   return r;
 }
 
-string EchoEscape(const string& str) {
+std::string EchoEscape(const std::string& str) {
   const char* in = str.c_str();
-  string buf;
+  std::string buf;
   for (; *in; in++) {
     switch (*in) {
       case '\\':
@@ -480,16 +479,16 @@ string EchoEscape(const string& str) {
   return buf;
 }
 
-void EscapeShell(string* s) {
+void EscapeShell(std::string* s) {
   static const char delimiters[] = "\"$\\`";
   size_t prev = 0;
   size_t i = SkipUntil(s->c_str(), s->size(), delimiters);
   if (i == s->size())
     return;
 
-  string r;
+  std::string r;
   for (; i < s->size();) {
-    StringPiece(*s).substr(prev, i - prev).AppendToString(&r);
+    r.append(std::string_view(*s).substr(prev, i - prev));
     char c = (*s)[i];
     r += '\\';
     if (c == '$') {
@@ -503,11 +502,11 @@ void EscapeShell(string* s) {
     prev = i;
     i += SkipUntil(s->c_str() + i, s->size() - i, delimiters);
   }
-  StringPiece(*s).substr(prev).AppendToString(&r);
+  r.append(std::string_view(*s).substr(prev));
   s->swap(r);
 }
 
-bool IsInteger(StringPiece s) {
+bool IsInteger(std::string_view s) {
   if (s.size() == 0) {
     return false;
   }
diff --git a/src/strutil.h b/src/strutil.h
index d573b79..e199e14 100644
--- a/src/strutil.h
+++ b/src/strutil.h
@@ -16,63 +16,60 @@
 #define STRUTIL_H_
 
 #include <string>
+#include <string_view>
 #include <vector>
 
-#include "string_piece.h"
-
-using namespace std;
-
 class WordScanner {
  public:
   struct Iterator {
     Iterator& operator++();
-    StringPiece operator*() const;
+    std::string_view operator*() const;
     bool operator!=(const Iterator& r) const {
       return in != r.in || s != r.s || i != r.i;
     }
 
-    const StringPiece* in;
+    const std::string_view* in;
     int s;
     int i;
   };
 
-  explicit WordScanner(StringPiece in);
+  explicit WordScanner(std::string_view in);
 
   Iterator begin() const;
   Iterator end() const;
 
-  void Split(vector<StringPiece>* o);
+  void Split(std::vector<std::string_view>* o);
 
  private:
-  StringPiece in_;
+  std::string_view in_;
 };
 
 class WordWriter {
  public:
-  explicit WordWriter(string* o);
+  explicit WordWriter(std::string* o);
   void MaybeAddWhitespace();
-  void Write(StringPiece s);
+  void Write(std::string_view s);
 
  private:
-  string* out_;
+  std::string* out_;
   bool needs_space_;
 };
 
 // Temporary modifies s[s.size()] to '\0'.
 class ScopedTerminator {
  public:
-  explicit ScopedTerminator(StringPiece s);
+  explicit ScopedTerminator(std::string_view s);
   ~ScopedTerminator();
 
  private:
-  StringPiece s_;
+  std::string_view s_;
   char c_;
 };
 
 template <class String>
-inline string JoinStrings(vector<String> v, const char* sep) {
-  string r;
-  for (StringPiece s : v) {
+inline std::string JoinStrings(std::vector<String> v, const char* sep) {
+  std::string r;
+  for (std::string_view s : v) {
     if (!r.empty()) {
       r += sep;
     }
@@ -81,71 +78,73 @@ inline string JoinStrings(vector<String> v, const char* sep) {
   return r;
 }
 
-void AppendString(StringPiece str, string* out);
-
-bool HasPrefix(StringPiece str, StringPiece prefix);
+bool HasPrefix(std::string_view str, std::string_view prefix);
 
-bool HasSuffix(StringPiece str, StringPiece suffix);
+bool HasSuffix(std::string_view str, std::string_view suffix);
 
-bool HasWord(StringPiece str, StringPiece w);
+bool HasWord(std::string_view str, std::string_view w);
 
-StringPiece TrimPrefix(StringPiece str, StringPiece suffix);
+std::string_view TrimPrefix(std::string_view str, std::string_view prefix);
 
-StringPiece TrimSuffix(StringPiece str, StringPiece suffix);
+std::string_view TrimSuffix(std::string_view str, std::string_view suffix);
 
 class Pattern {
  public:
-  explicit Pattern(StringPiece pat);
+  explicit Pattern(std::string_view pat);
 
-  bool Match(StringPiece str) const;
+  bool Match(std::string_view str) const;
 
-  StringPiece Stem(StringPiece str) const;
+  std::string_view Stem(std::string_view str) const;
 
-  void AppendSubst(StringPiece str, StringPiece subst, string* out) const;
+  void AppendSubst(std::string_view str,
+                   std::string_view subst,
+                   std::string* out) const;
 
-  void AppendSubstRef(StringPiece str, StringPiece subst, string* out) const;
+  void AppendSubstRef(std::string_view str,
+                      std::string_view subst,
+                      std::string* out) const;
 
  private:
-  bool MatchImpl(StringPiece str) const;
+  bool MatchImpl(std::string_view str) const;
 
-  StringPiece pat_;
+  std::string_view pat_;
   size_t percent_index_;
 };
 
-string NoLineBreak(const string& s);
+std::string NoLineBreak(const std::string& s);
 
-StringPiece TrimLeftSpace(StringPiece s);
-StringPiece TrimRightSpace(StringPiece s);
-StringPiece TrimSpace(StringPiece s);
+std::string_view TrimLeftSpace(std::string_view s);
+std::string_view TrimRightSpace(std::string_view s);
+std::string_view TrimSpace(std::string_view s);
 
-StringPiece Dirname(StringPiece s);
-StringPiece Basename(StringPiece s);
-StringPiece GetExt(StringPiece s);
-StringPiece StripExt(StringPiece s);
-void NormalizePath(string* o);
-void AbsPath(StringPiece s, string* o);
+std::string_view Dirname(std::string_view s);
+std::string_view Basename(std::string_view s);
+std::string_view GetExt(std::string_view s);
+std::string_view StripExt(std::string_view s);
+void NormalizePath(std::string* o);
+void AbsPath(std::string_view s, std::string* o);
 
-size_t FindOutsideParen(StringPiece s, char c);
-size_t FindTwoOutsideParen(StringPiece s, char c1, char c2);
-size_t FindThreeOutsideParen(StringPiece s, char c1, char c2, char c3);
+size_t FindOutsideParen(std::string_view s, char c);
+size_t FindTwoOutsideParen(std::string_view s, char c1, char c2);
+size_t FindThreeOutsideParen(std::string_view s, char c1, char c2, char c3);
 
-size_t FindEndOfLine(StringPiece s, size_t e, size_t* lf_cnt);
+size_t FindEndOfLine(std::string_view s, size_t e, size_t* lf_cnt);
 
 // Strip leading sequences of './' from file names, so that ./file
 // and file are considered to be the same file.
 // From http://www.gnu.org/software/make/manual/make.html#Features
-StringPiece TrimLeadingCurdir(StringPiece s);
+std::string_view TrimLeadingCurdir(std::string_view s);
 
-void FormatForCommandSubstitution(string* s);
+void FormatForCommandSubstitution(std::string* s);
 
-string SortWordsInString(StringPiece s);
+std::string SortWordsInString(std::string_view s);
 
-string ConcatDir(StringPiece b, StringPiece n);
+std::string ConcatDir(std::string_view b, std::string_view n);
 
-string EchoEscape(const string& str);
+std::string EchoEscape(const std::string& str);
 
-void EscapeShell(string* s);
+void EscapeShell(std::string* s);
 
-bool IsInteger(StringPiece s);
+bool IsInteger(std::string_view s);
 
 #endif  // STRUTIL_H_
diff --git a/src/strutil_bench.cc b/src/strutil_bench.cc
index d3b2e6c..1d80b75 100644
--- a/src/strutil_bench.cc
+++ b/src/strutil_bench.cc
@@ -15,18 +15,16 @@
 // +build ignore
 
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "flags.h"
-#include "string_piece.h"
 #include "strutil.h"
 #include "timeutil.h"
 
-using namespace std;
-
 int main() {
   g_flags.enable_stat_logs = true;
-  string s;
+  std::string s;
   while (s.size() < 400000) {
     if (!s.empty())
       s += ' ';
@@ -36,7 +34,7 @@ int main() {
   ScopedTimeReporter tr("WordScanner");
   static const int N = 1000;
   for (int i = 0; i < N; i++) {
-    vector<StringPiece> toks;
+    std::vector<std::string_view> toks;
     WordScanner(s).Split(&toks);
   }
 }
diff --git a/src/strutil_test.cc b/src/strutil_test.cc
index d95d351..27d3b77 100644
--- a/src/strutil_test.cc
+++ b/src/strutil_test.cc
@@ -21,18 +21,16 @@
 #include <unistd.h>
 
 #include <string>
+#include <string_view>
 #include <vector>
 
-#include "string_piece.h"
 #include "testutil.h"
 
-using namespace std;
-
 namespace {
 
 void TestWordScanner() {
-  vector<StringPiece> ss;
-  for (StringPiece tok : WordScanner("foo bar baz hogeeeeeeeeeeeeeeee")) {
+  std::vector<std::string_view> ss;
+  for (std::string_view tok : WordScanner("foo bar baz hogeeeeeeeeeeeeeeee")) {
     ss.push_back(tok);
   }
   assert(ss.size() == 4LU);
@@ -70,8 +68,10 @@ void TestTrimSuffix() {
   ASSERT_EQ(TrimSuffix("bar", "bbar"), "bar");
 }
 
-string SubstPattern(StringPiece str, StringPiece pat, StringPiece subst) {
-  string r;
+std::string SubstPattern(std::string_view str,
+                         std::string_view pat,
+                         std::string_view subst) {
+  std::string r;
   Pattern(pat).AppendSubst(str, subst, &r);
   return r;
 }
@@ -104,7 +104,7 @@ void TestHasWord() {
   assert(!HasWord("foo bar baz", "fo"));
 }
 
-static string NormalizePath(string s) {
+static std::string NormalizePath(std::string s) {
   ::NormalizePath(&s);
   return s;
 }
@@ -132,7 +132,7 @@ void TestNormalizePath() {
   ASSERT_EQ(NormalizePath("./../../a/b"), "../../a/b");
 }
 
-string EscapeShell(string s) {
+std::string EscapeShell(std::string s) {
   ::EscapeShell(&s);
   return s;
 }
@@ -150,8 +150,8 @@ void TestFindEndOfLine() {
   size_t lf_cnt = 0;
   ASSERT_EQ(FindEndOfLine("foo", 0, &lf_cnt), 3);
   char buf[10] = {'f', 'o', '\\', '\0', 'x', 'y'};
-  ASSERT_EQ(FindEndOfLine(StringPiece(buf, 6), 0, &lf_cnt), 3);
-  ASSERT_EQ(FindEndOfLine(StringPiece(buf, 2), 0, &lf_cnt), 2);
+  ASSERT_EQ(FindEndOfLine(std::string_view(buf, 6), 0, &lf_cnt), 3);
+  ASSERT_EQ(FindEndOfLine(std::string_view(buf, 2), 0, &lf_cnt), 2);
 }
 
 // Take a string, and copy it into an allocated buffer where
@@ -184,8 +184,9 @@ const char* CreateProtectedString(const char* str) {
 }
 
 void TestWordScannerInvalidAccess() {
-  vector<StringPiece> ss;
-  for (StringPiece tok : WordScanner(CreateProtectedString("0123 456789"))) {
+  std::vector<std::string_view> ss;
+  for (std::string_view tok :
+       WordScanner(CreateProtectedString("0123 456789"))) {
     ss.push_back(tok);
   }
   assert(ss.size() == 2LU);
diff --git a/src/symtab.cc b/src/symtab.cc
index 69895f7..0ba1213 100644
--- a/src/symtab.cc
+++ b/src/symtab.cc
@@ -35,8 +35,8 @@ struct SymbolData {
   Var* gv;
 };
 
-vector<string*>* g_symbols;
-static vector<SymbolData> g_symbol_data;
+std::vector<std::string*>* g_symbols;
+static std::vector<SymbolData> g_symbol_data;
 
 Symbol kEmptySym;
 Symbol kShellSym;
@@ -143,23 +143,23 @@ class Symtab {
 
   ~Symtab() {
     LOG_STAT("%zu symbols", symbols_.size());
-    for (string* s : symbols_)
+    for (std::string* s : symbols_)
       delete s;
   }
 
-  Symbol InternImpl(StringPiece s) {
+  Symbol InternImpl(std::string_view s) {
     auto found = symtab_.find(s);
     if (found != symtab_.end()) {
       return found->second;
     }
-    symbols_.push_back(new string(s.data(), s.size()));
+    symbols_.push_back(new std::string(s.data(), s.size()));
     Symbol sym = Symbol(symtab_.size());
     bool ok = symtab_.emplace(*symbols_.back(), sym).second;
     CHECK(ok);
     return sym;
   }
 
-  Symbol Intern(StringPiece s) {
+  Symbol Intern(std::string_view s) {
 #ifdef ENABLE_TID_CHECK
     if (tid_ != pthread_self())
       abort();
@@ -171,8 +171,9 @@ class Symtab {
     return InternImpl(s);
   }
 
-  vector<StringPiece> GetSymbolNames(std::function<bool(Var*)> const& filter) {
-    vector<StringPiece> result;
+  std::vector<std::string_view> GetSymbolNames(
+      std::function<bool(Var*)> const& filter) {
+    std::vector<std::string_view> result;
     for (auto entry : symtab_) {
       Var* var = entry.second.PeekGlobalVar();
       // The symbol table contains all interned strings, not just variables
@@ -188,8 +189,8 @@ class Symtab {
   }
 
  private:
-  unordered_map<StringPiece, Symbol> symtab_;
-  vector<string*> symbols_;
+  std::unordered_map<std::string_view, Symbol> symtab_;
+  std::vector<std::string*> symbols_;
 #ifdef ENABLE_TID_CHECK
   pthread_t tid_;
 #endif
@@ -197,12 +198,12 @@ class Symtab {
 
 static Symtab g_symtab;
 
-Symbol Intern(StringPiece s) {
+Symbol Intern(std::string_view s) {
   return g_symtab.Intern(s);
 }
 
-string JoinSymbols(const vector<Symbol>& syms, const char* sep) {
-  vector<string> strs;
+std::string JoinSymbols(const std::vector<Symbol>& syms, const char* sep) {
+  std::vector<std::string> strs;
   strs.reserve(syms.size());
   for (Symbol s : syms) {
     strs.push_back(s.str());
@@ -210,6 +211,7 @@ string JoinSymbols(const vector<Symbol>& syms, const char* sep) {
   return JoinStrings(strs, sep);
 }
 
-vector<StringPiece> GetSymbolNames(std::function<bool(Var*)> const& filter) {
+std::vector<std::string_view> GetSymbolNames(
+    std::function<bool(Var*)> const& filter) {
   return g_symtab.GetSymbolNames(filter);
 }
diff --git a/src/symtab.h b/src/symtab.h
index f3524ca..641f416 100644
--- a/src/symtab.h
+++ b/src/symtab.h
@@ -18,13 +18,10 @@
 #include <bitset>
 #include <functional>
 #include <string>
+#include <string_view>
 #include <vector>
 
-#include "string_piece.h"
-
-using namespace std;
-
-extern vector<string*>* g_symbols;
+extern std::vector<std::string*>* g_symbols;
 
 class Symtab;
 class Var;
@@ -33,7 +30,7 @@ class Symbol {
  public:
   explicit Symbol() : v_(-1) {}
 
-  const string& str() const { return *((*g_symbols)[v_]); }
+  const std::string& str() const { return *((*g_symbols)[v_]); }
 
   const char* c_str() const { return str().c_str(); }
 
@@ -42,7 +39,7 @@ class Symbol {
   int val() const { return v_; }
 
   char get(size_t i) const {
-    const string& s = str();
+    const std::string& s = str();
     if (i >= s.size())
       return 0;
     return s[i];
@@ -221,11 +218,12 @@ extern Symbol kShellSym;
 extern Symbol kAllowRulesSym;
 extern Symbol kKatiReadonlySym;
 
-Symbol Intern(StringPiece s);
+Symbol Intern(std::string_view s);
 
-string JoinSymbols(const vector<Symbol>& syms, const char* sep);
+std::string JoinSymbols(const std::vector<Symbol>& syms, const char* sep);
 
 // Get all symbol names for which filter returns true.
-vector<StringPiece> GetSymbolNames(std::function<bool(Var*)> const& filter);
+std::vector<std::string_view> GetSymbolNames(
+    std::function<bool(Var*)> const& filter);
 
 #endif  // SYMTAB_H_
diff --git a/src/testutil.h b/src/testutil.h
index 8de3666..e94c8fd 100644
--- a/src/testutil.h
+++ b/src/testutil.h
@@ -13,8 +13,9 @@
 // limitations under the License.
 
 #include <assert.h>
+#include <string_view>
 
-#include "string_piece.h"
+#include "log.h"
 
 bool g_failed;
 
@@ -38,10 +39,10 @@ bool g_failed;
     }                                                                       \
   } while (0)
 
-StringPiece GetStringPiece(StringPiece s) {
+std::string_view GetStringPiece(std::string_view s) {
   return s;
 }
-StringPiece GetStringPiece(size_t v) {
+std::string_view GetStringPiece(size_t v) {
   static char buf[64];
   sprintf(buf, "%zd", v);
   return buf;
diff --git a/src/var.cc b/src/var.cc
index e51aa6b..0f1cb05 100644
--- a/src/var.cc
+++ b/src/var.cc
@@ -21,7 +21,7 @@
 #include "log.h"
 #include "strutil.h"
 
-unordered_map<const Var*, string> Var::diagnostic_messages_;
+std::unordered_map<const Var*, std::string> Var::diagnostic_messages_;
 
 const char* GetOriginStr(VarOrigin origin) {
   switch (origin) {
@@ -65,14 +65,14 @@ void Var::AppendVar(Evaluator*, Value*) {
   CHECK(false);
 }
 
-void Var::SetDeprecated(const StringPiece& msg) {
+void Var::SetDeprecated(const std::string_view& msg) {
   deprecated_ = true;
-  diagnostic_messages_[this] = msg.as_string();
+  diagnostic_messages_[this] = std::string(msg);
 }
 
-void Var::SetObsolete(const StringPiece& msg) {
+void Var::SetObsolete(const std::string_view& msg) {
   obsolete_ = true;
-  diagnostic_messages_[this] = msg.as_string();
+  diagnostic_messages_[this] = std::string(msg);
 }
 
 void Var::Used(Evaluator* ev, const Symbol& sym) const {
@@ -90,8 +90,8 @@ const char* Var::diagnostic_message_text() const {
   return it == diagnostic_messages_.end() ? "" : it->second.c_str();
 }
 
-const string& Var::DeprecatedMessage() const {
-  static const string empty_string;
+const std::string& Var::DeprecatedMessage() const {
+  static const std::string empty_string;
   auto it = diagnostic_messages_.find(this);
   return it == diagnostic_messages_.end() ? empty_string : it->second;
 }
@@ -107,7 +107,7 @@ Var* Var::Undefined() {
 SimpleVar::SimpleVar(VarOrigin origin, Frame* definition, Loc loc)
     : Var(origin, definition, loc) {}
 
-SimpleVar::SimpleVar(const string& v,
+SimpleVar::SimpleVar(const std::string& v,
                      VarOrigin origin,
                      Frame* definition,
                      Loc loc)
@@ -126,24 +126,24 @@ bool SimpleVar::IsFunc(Evaluator*) const {
   return false;
 }
 
-void SimpleVar::Eval(Evaluator* ev, string* s) const {
+void SimpleVar::Eval(Evaluator* ev, std::string* s) const {
   ev->CheckStack();
   *s += v_;
 }
 
 void SimpleVar::AppendVar(Evaluator* ev, Value* v) {
-  string buf;
+  std::string buf;
   v->Eval(ev, &buf);
   v_.push_back(' ');
   v_ += buf;
   definition_ = ev->CurrentFrame();
 }
 
-StringPiece SimpleVar::String() const {
+std::string_view SimpleVar::String() const {
   return v_;
 }
 
-string SimpleVar::DebugString() const {
+std::string SimpleVar::DebugString() const {
   return v_;
 }
 
@@ -151,14 +151,14 @@ RecursiveVar::RecursiveVar(Value* v,
                            VarOrigin origin,
                            Frame* definition,
                            Loc loc,
-                           StringPiece orig)
+                           std::string_view orig)
     : Var(origin, definition, loc), v_(v), orig_(orig) {}
 
 bool RecursiveVar::IsFunc(Evaluator* ev) const {
   return v_->IsFunc(ev);
 }
 
-void RecursiveVar::Eval(Evaluator* ev, string* s) const {
+void RecursiveVar::Eval(Evaluator* ev, std::string* s) const {
   ev->CheckStack();
   v_->Eval(ev, s);
 }
@@ -182,11 +182,11 @@ void RecursiveVar::Used(Evaluator* ev, const Symbol& sym) const {
   Var::Used(ev, sym);
 }
 
-StringPiece RecursiveVar::String() const {
+std::string_view RecursiveVar::String() const {
   return orig_;
 }
 
-string RecursiveVar::DebugString() const {
+std::string RecursiveVar::DebugString() const {
   return Value::DebugString(v_);
 }
 
@@ -196,19 +196,19 @@ bool UndefinedVar::IsFunc(Evaluator*) const {
   return false;
 }
 
-void UndefinedVar::Eval(Evaluator*, string*) const {
+void UndefinedVar::Eval(Evaluator*, std::string*) const {
   // Nothing to do.
 }
 
-StringPiece UndefinedVar::String() const {
-  return StringPiece("");
+std::string_view UndefinedVar::String() const {
+  return std::string_view("");
 }
 
-string UndefinedVar::DebugString() const {
+std::string UndefinedVar::DebugString() const {
   return "*undefined*";
 }
 
-VariableNamesVar::VariableNamesVar(StringPiece name, bool all)
+VariableNamesVar::VariableNamesVar(std::string_view name, bool all)
     : name_(name), all_(all) {
   SetReadOnly();
   SetAssignOp(AssignOp::COLON_EQ);
@@ -218,38 +218,41 @@ bool VariableNamesVar::IsFunc(Evaluator*) const {
   return false;
 }
 
-void VariableNamesVar::Eval(Evaluator* ev, string* s) const {
+void VariableNamesVar::Eval(Evaluator* ev, std::string* s) const {
   ConcatVariableNames(ev, s);
 }
 
-StringPiece VariableNamesVar::String() const {
+std::string_view VariableNamesVar::String() const {
   return name_;
 }
 
-void VariableNamesVar::ConcatVariableNames(Evaluator* ev, string* s) const {
+void VariableNamesVar::ConcatVariableNames(Evaluator* ev,
+                                           std::string* s) const {
   WordWriter ww(s);
-  vector<StringPiece>&& symbols = GetSymbolNames([=](Var* var) -> bool {
-    if (var->Obsolete()) {
-      return false;
-    }
-    if (!all_) {
-      if (var->IsFunc(ev)) {
-        return false;
-      }
-    }
-    return true;
-  });
+  std::vector<std::string_view>&& symbols =
+      GetSymbolNames([=](Var* var) -> bool {
+        if (var->Obsolete()) {
+          return false;
+        }
+        if (!all_) {
+          if (var->IsFunc(ev)) {
+            return false;
+          }
+        }
+        return true;
+      });
   for (auto entry : symbols) {
     ww.Write(entry);
   }
 }
 
-string VariableNamesVar::DebugString() const {
+std::string VariableNamesVar::DebugString() const {
   return "*VariableNamesVar*";
 }
 
 bool ShellStatusVar::is_set_ = false;
 int ShellStatusVar::shell_status_ = 0;
+std::string ShellStatusVar::shell_status_string_;
 
 ShellStatusVar::ShellStatusVar() {
   SetReadOnly();
@@ -257,8 +260,11 @@ ShellStatusVar::ShellStatusVar() {
 }
 
 void ShellStatusVar::SetValue(int newShellStatus) {
-  shell_status_ = newShellStatus;
-  is_set_ = true;
+  if (!is_set_ || shell_status_ != newShellStatus) {
+    shell_status_ = newShellStatus;
+    is_set_ = true;
+    shell_status_string_.clear();
+  }
 }
 
 bool ShellStatusVar::IsDefined() const {
@@ -269,7 +275,7 @@ bool ShellStatusVar::IsFunc(Evaluator*) const {
   return false;
 }
 
-void ShellStatusVar::Eval(Evaluator* ev, string* s) const {
+void ShellStatusVar::Eval(Evaluator* ev, std::string* s) const {
   if (ev->IsEvaluatingCommand()) {
     ev->Error("Kati does not support using .SHELLSTATUS inside of a rule");
   }
@@ -278,18 +284,22 @@ void ShellStatusVar::Eval(Evaluator* ev, string* s) const {
     return;
   }
 
-  *s += std::to_string(shell_status_);
+  *s += String();
 }
 
-StringPiece ShellStatusVar::String() const {
+std::string_view ShellStatusVar::String() const {
   if (!is_set_) {
     return "";
   }
 
-  return std::to_string(shell_status_);
+  if (shell_status_string_.empty()) {
+    shell_status_string_ = std::to_string(shell_status_);
+  }
+
+  return shell_status_string_;
 }
 
-string ShellStatusVar::DebugString() const {
+std::string ShellStatusVar::DebugString() const {
   return "*ShellStatusVar*";
 }
 
diff --git a/src/var.h b/src/var.h
index 67b26f6..0e0972f 100644
--- a/src/var.h
+++ b/src/var.h
@@ -17,6 +17,7 @@
 
 #include <memory>
 #include <string>
+#include <string_view>
 #include <unordered_map>
 #include <unordered_set>
 
@@ -25,11 +26,8 @@
 #include "loc.h"
 #include "log.h"
 #include "stmt.h"
-#include "string_piece.h"
 #include "symtab.h"
 
-using namespace std;
-
 class Evaluator;
 class Value;
 
@@ -59,23 +57,23 @@ class Var : public Evaluable {
 
   virtual void AppendVar(Evaluator* ev, Value* v);
 
-  virtual StringPiece String() const = 0;
+  virtual std::string_view String() const = 0;
 
-  virtual string DebugString() const = 0;
+  virtual std::string DebugString() const = 0;
 
   bool ReadOnly() const { return readonly_; }
   void SetReadOnly() { readonly_ = true; }
 
   bool Deprecated() const { return deprecated_; }
-  void SetDeprecated(const StringPiece& msg);
+  void SetDeprecated(const std::string_view& msg);
 
   bool Obsolete() const { return obsolete_; }
-  void SetObsolete(const StringPiece& msg);
+  void SetObsolete(const std::string_view& msg);
 
   bool SelfReferential() const { return self_referential_; }
   void SetSelfReferential() { self_referential_ = true; }
 
-  const string& DeprecatedMessage() const;
+  const std::string& DeprecatedMessage() const;
 
   // This variable was used (either written or read from)
   virtual void Used(Evaluator* ev, const Symbol& sym) const;
@@ -102,13 +100,13 @@ class Var : public Evaluable {
 
   const char* diagnostic_message_text() const;
 
-  static unordered_map<const Var*, string> diagnostic_messages_;
+  static std::unordered_map<const Var*, std::string> diagnostic_messages_;
 };
 
 class SimpleVar : public Var {
  public:
   explicit SimpleVar(VarOrigin origin, Frame* definition, Loc loc);
-  SimpleVar(const string& v, VarOrigin origin, Frame* definition, Loc loc);
+  SimpleVar(const std::string& v, VarOrigin origin, Frame* definition, Loc loc);
   SimpleVar(VarOrigin origin,
             Frame* definition,
             Loc loc,
@@ -119,15 +117,15 @@ class SimpleVar : public Var {
 
   virtual bool IsFunc(Evaluator* ev) const override;
 
-  virtual void Eval(Evaluator* ev, string* s) const override;
+  virtual void Eval(Evaluator* ev, std::string* s) const override;
 
   virtual void AppendVar(Evaluator* ev, Value* v) override;
 
-  virtual StringPiece String() const override;
+  virtual std::string_view String() const override;
 
-  virtual string DebugString() const override;
+  virtual std::string DebugString() const override;
 
-  string v_;
+  std::string v_;
 };
 
 class RecursiveVar : public Var {
@@ -136,24 +134,24 @@ class RecursiveVar : public Var {
                VarOrigin origin,
                Frame* definition,
                Loc loc,
-               StringPiece orig);
+               std::string_view orig);
 
   virtual const char* Flavor() const override { return "recursive"; }
 
   virtual bool IsFunc(Evaluator* ev) const override;
 
-  virtual void Eval(Evaluator* ev, string* s) const override;
+  virtual void Eval(Evaluator* ev, std::string* s) const override;
 
   virtual void AppendVar(Evaluator* ev, Value* v) override;
 
-  virtual StringPiece String() const override;
+  virtual std::string_view String() const override;
 
-  virtual string DebugString() const override;
+  virtual std::string DebugString() const override;
 
   virtual void Used(Evaluator* ev, const Symbol& sym) const override;
 
   Value* v_;
-  StringPiece orig_;
+  std::string_view orig_;
 };
 
 class UndefinedVar : public Var {
@@ -165,34 +163,34 @@ class UndefinedVar : public Var {
 
   virtual bool IsFunc(Evaluator* ev) const override;
 
-  virtual void Eval(Evaluator* ev, string* s) const override;
+  virtual void Eval(Evaluator* ev, std::string* s) const override;
 
-  virtual StringPiece String() const override;
+  virtual std::string_view String() const override;
 
-  virtual string DebugString() const override;
+  virtual std::string DebugString() const override;
 };
 
 // The built-in VARIABLES and KATI_SYMBOLS variables
 class VariableNamesVar : public Var {
  public:
-  VariableNamesVar(StringPiece name, bool all);
+  VariableNamesVar(std::string_view name, bool all);
 
   virtual const char* Flavor() const override { return "kati_variable_names"; }
   virtual bool IsDefined() const override { return true; }
 
   virtual bool IsFunc(Evaluator* ev) const override;
 
-  virtual void Eval(Evaluator* ev, string* s) const override;
+  virtual void Eval(Evaluator* ev, std::string* s) const override;
 
-  virtual StringPiece String() const override;
+  virtual std::string_view String() const override;
 
-  virtual string DebugString() const override;
+  virtual std::string DebugString() const override;
 
  private:
-  StringPiece name_;
+  std::string_view name_;
   bool all_;
 
-  void ConcatVariableNames(Evaluator* ev, string* s) const;
+  void ConcatVariableNames(Evaluator* ev, std::string* s) const;
 };
 
 // The built-in .SHELLSTATUS variable
@@ -207,18 +205,19 @@ class ShellStatusVar : public Var {
 
   virtual bool IsFunc(Evaluator* ev) const override;
 
-  virtual void Eval(Evaluator* ev, string* s) const override;
+  virtual void Eval(Evaluator* ev, std::string* s) const override;
 
-  virtual StringPiece String() const override;
+  virtual std::string_view String() const override;
 
-  virtual string DebugString() const override;
+  virtual std::string DebugString() const override;
 
  private:
   static bool is_set_;
   static int shell_status_;
+  static std::string shell_status_string_;
 };
 
-class Vars : public unordered_map<Symbol, Var*> {
+class Vars : public std::unordered_map<Symbol, Var*> {
  public:
   ~Vars();
 
diff --git a/testcase/ninja_question.sh b/testcase/ninja_question.sh
new file mode 100755
index 0000000..d177fb7
--- /dev/null
+++ b/testcase/ninja_question.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# Copyright 2022 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
+
+mk="$@"
+
+cat <<EOF > Makefile
+
+all: d
+
+a:
+	echo a > a
+
+b:
+	echo b > b
+
+c:
+	echo c > c
+
+d: a b c
+	echo \$? > d
+
+EOF
+
+${mk}
+if [ -e ninja.sh ]; then ./ninja.sh -j1; fi
+cat d
+sleep 0.1
+touch b
+if [ -e ninja.sh ]; then ./ninja.sh -j1; else ${mk}; fi
+cat d
+
diff --git a/testcase/question.sh b/testcase/question.sh
new file mode 100755
index 0000000..0d3c7c4
--- /dev/null
+++ b/testcase/question.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+#
+# Copyright 2022 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
+
+mk="$@"
+
+cat <<EOF > Makefile
+
+all: d
+
+a:
+	echo a > a
+
+b:
+	echo b > b
+
+c:
+	echo c > c
+
+d: a b c
+	echo \$? > d
+
+EOF
+
+${mk}
+cat d
+sleep 0.1
+touch b
+${mk}
+cat d
+
diff --git a/testcase/stem_middle.mk b/testcase/stem_middle.mk
index cce73ae..6127c24 100644
--- a/testcase/stem_middle.mk
+++ b/testcase/stem_middle.mk
@@ -1,11 +1,16 @@
 
 test: a/a.a b.b c/c
 
+# ninja always makes the folders leading up to the outputs,
+# so add mkdirs to match that functionality in make
+
 a/%.a:
+	@mkdir -p a
 	@echo $*
 
 %.b:
 	@echo $*
 
 c/%:
+	@mkdir -p c
 	@echo $*

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/lib/debug/.build-id/f2/859d7d369f6aeaa104118a6f6f5884b9495a8c.debug

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/lib/debug/.build-id/b5/c1688bae274e89cc198b93cff3c411788dfbf6.debug

No differences were encountered between the control files of package ckati

Control files of package ckati-dbgsym: lines which differ (wdiff format)

  • Build-Ids: b5c1688bae274e89cc198b93cff3c411788dfbf6 f2859d7d369f6aeaa104118a6f6f5884b9495a8c

More details

Full run details