Switch remaining stamp targets to phony targets

GN uses stamp files for a variety of output types as a mechanism for
completing a group of dependencies. Ninja's phony targets can be used in
a similar manner.

The GN 'group', 'generated_file', 'bundle_data', 'copy', 'action',
'action_for_each' and 'create_bundle' output types each generate a stamp
file as an output for other targets to depend on. This CL replaces those
stamp targets with a phony alias target.

For a few target types, GN optionally creates a "<target>.inputdeps"
and/or "<target>.input" stamp files to represent a group of input
dependencies or inputs, respectively. This is useful for limiting the
size of ninja files because the dependencies only have to be listed
once. As with the stamp files generated for the aforementioned output
types, this CL also replaces those stamp targets with a phony alias
target.

Finally, there are several intermediate stamp files that are created for
certain outputs, such as the code signing stamp for `create_bundle`
targets. Where possible, these are also replaced with phony alias
targets.

Bug: 186, 188, 191, 194
Change-Id: I5b257147affc55bb8b093a3f39c7e9a5b56b6f6c
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/10100
Commit-Queue: Brett Wilson <brettw@chromium.org>
Reviewed-by: Brett Wilson <brettw@chromium.org>
diff --git a/src/gn/function_get_target_outputs.cc b/src/gn/function_get_target_outputs.cc
index ca37d9a..6c5041e 100644
--- a/src/gn/function_get_target_outputs.cc
+++ b/src/gn/function_get_target_outputs.cc
@@ -46,8 +46,8 @@
   process_file_template").
 
   source sets and groups: this will return a list containing the path of the
-  phony target or the "stamp" file that Ninja will produce once all outputs are
-  generated. This probably isn't very useful.
+  phony target that Ninja completes once all outputs are generated. This
+  probably isn't very useful.
 
 Example
 
diff --git a/src/gn/ninja_action_target_writer.cc b/src/gn/ninja_action_target_writer.cc
index 0b49066..c8a8437 100644
--- a/src/gn/ninja_action_target_writer.cc
+++ b/src/gn/ninja_action_target_writer.cc
@@ -39,12 +39,12 @@
     extra_hard_deps.push_back(pair.ptr);
 
   // For ACTIONs, the input deps appear only once in the generated ninja
-  // file, so WriteInputDepsStampAndGetDep() won't create a stamp file
+  // file, so WriteInputDepsPhonyAndGetDep() won't create a phony rule
   // and the action will just depend on all the input deps directly.
-  size_t num_stamp_uses =
+  size_t num_output_uses =
       target_->output_type() == Target::ACTION ? 1u : target_->sources().size();
   std::vector<OutputFile> input_deps =
-      WriteInputDepsStampAndGetDep(extra_hard_deps, num_stamp_uses);
+      WriteInputDepsPhonyAndGetDep(extra_hard_deps, num_output_uses);
   out_ << std::endl;
 
   // Collects all output files for writing below.
@@ -83,17 +83,17 @@
   }
   out_ << std::endl;
 
-  // Write the stamp, which also depends on all data deps. These are needed at
+  // Write the phony, which also depends on all data deps. These are needed at
   // runtime and should be compiled when the action is, but don't need to be
   // done before we run the action.
   // TODO(thakis): If the action has just a single output, make things depend
-  // on that output directly without writing a stamp file.
+  // on that output directly without writing a phony target.
   std::vector<OutputFile> data_outs;
   for (const auto& dep : target_->data_deps()) {
     if (dep.ptr->dependency_output_file_or_phony())
       data_outs.push_back(*dep.ptr->dependency_output_file_or_phony());
   }
-  WriteStampForTarget(output_files, data_outs);
+  WritePhonyForTarget(output_files, data_outs);
 }
 
 std::string NinjaActionTargetWriter::WriteRuleDefinition() {
diff --git a/src/gn/ninja_action_target_writer_unittest.cc b/src/gn/ninja_action_target_writer_unittest.cc
index eb03df1..74f7f90 100644
--- a/src/gn/ninja_action_target_writer_unittest.cc
+++ b/src/gn/ninja_action_target_writer_unittest.cc
@@ -67,7 +67,7 @@
 
 build foo.out: __foo_bar___rule | ../../foo/script.py ../../foo/included.txt
 
-build obj/foo/bar.stamp: stamp foo.out
+build phony/foo/bar: phony foo.out
 )";
   EXPECT_EQ(expected, out.str()) << expected << "--" << out.str();
 }
@@ -112,7 +112,7 @@
 build foo.out: __foo_bar___rule | ../../foo/script.py ../../foo/included.txt
   pool = console
 
-build obj/foo/bar.stamp: stamp foo.out
+build phony/foo/bar: phony foo.out
 )";
   EXPECT_EQ(expected, out.str());
 }
@@ -153,7 +153,7 @@
       "build foo.out: __foo_bar___rule | ../../foo/script.py "
       "../../foo/included.txt ../../foo/source.txt\n"
       "\n"
-      "build obj/foo/bar.stamp: stamp foo.out\n";
+      "build phony/foo/bar: phony foo.out\n";
   EXPECT_EQ(expected_linux, out.str());
 }
 
@@ -162,9 +162,9 @@
   TestWithScope setup;
 
   // Some dependencies that the action can depend on. Use actions for these
-  // so they have a nice platform-independent stamp file that can appear in the
-  // output (rather than having to worry about how the current platform names
-  // binaries).
+  // so they have a nice platform-independent phony target that can appear in
+  // the output (rather than having to worry about how the current platform
+  // names binaries).
   Target dep(setup.settings(), Label(SourceDir("//foo/"), "dep"));
   dep.set_output_type(Target::ACTION);
   dep.visibility().SetPublic();
@@ -215,18 +215,18 @@
 #endif
       "  description = ACTION //foo:bar()\n"
       "  restat = 1\n"
-      "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
-      "../../foo/included.txt obj/foo/dep.stamp\n"
+      "build phony/foo/bar.inputdeps: phony ../../foo/script.py "
+      "../../foo/included.txt phony/foo/dep\n"
       "\n"
       "build input1.out: __foo_bar___rule ../../foo/input1.txt | "
-      "obj/foo/bar.inputdeps.stamp\n"
+      "phony/foo/bar.inputdeps\n"
       "  source_name_part = input1\n"
       "build input2.out: __foo_bar___rule ../../foo/input2.txt | "
-      "obj/foo/bar.inputdeps.stamp\n"
+      "phony/foo/bar.inputdeps\n"
       "  source_name_part = input2\n"
       "\n"
-      "build obj/foo/bar.stamp: "
-      "stamp input1.out input2.out || obj/foo/datadep.stamp\n";
+      "build phony/foo/bar: "
+      "phony input1.out input2.out || phony/foo/datadep\n";
 
   std::string out_str = out.str();
 #if defined(OS_WIN)
@@ -280,21 +280,21 @@
 #endif
       "  description = ACTION //foo:bar()\n"
       "  restat = 1\n"
-      "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
+      "build phony/foo/bar.inputdeps: phony ../../foo/script.py "
       "../../foo/included.txt\n"
       "\n"
       "build input1.out: __foo_bar___rule ../../foo/input1.txt"
-      " | obj/foo/bar.inputdeps.stamp\n"
+      " | phony/foo/bar.inputdeps\n"
       "  source_name_part = input1\n"
       "  depfile = gen/input1.d\n"
       "  deps = gcc\n"
       "build input2.out: __foo_bar___rule ../../foo/input2.txt"
-      " | obj/foo/bar.inputdeps.stamp\n"
+      " | phony/foo/bar.inputdeps\n"
       "  source_name_part = input2\n"
       "  depfile = gen/input2.d\n"
       "  deps = gcc\n"
       "\n"
-      "build obj/foo/bar.stamp: stamp input1.out input2.out\n";
+      "build phony/foo/bar: phony input1.out input2.out\n";
   EXPECT_EQ(expected_linux, out.str());
 }
 
@@ -348,7 +348,7 @@
       // Substitution for the rspfile contents.
       "  source_name_part = input1\n"
       "\n"
-      "build obj/foo/bar.stamp: stamp input1.out\n";
+      "build phony/foo/bar: phony input1.out\n";
   EXPECT_EQ(expected_linux, out.str());
 }
 
@@ -399,7 +399,7 @@
       "  source_file_part = input1.txt\n"
       "  pool = foo_pool\n"
       "\n"
-      "build obj/foo/bar.stamp: stamp input1.out\n";
+      "build phony/foo/bar: phony input1.out\n";
   EXPECT_EQ(expected_linux, out.str());
 }
 
@@ -440,9 +440,9 @@
         "  restat = 1\n"
         "\n"
         "build foo.out: __foo_foo___rule | ../../foo/script.py"
-        " ../../foo/input1.txt obj/foo/dep.stamp\n"
+        " ../../foo/input1.txt phony/foo/dep\n"
         "\n"
-        "build obj/foo/foo.stamp: stamp foo.out\n";
+        "build phony/foo/foo: phony foo.out\n";
     EXPECT_EQ(expected_linux, out.str());
   }
 
@@ -468,11 +468,11 @@
         "  description = ACTION //bar:bar()\n"
         "  restat = 1\n"
         "\n"
-        // Do not have obj/foo/dep.stamp as dependency.
+        // Do not have phony/foo/dep as dependency.
         "build bar.out: __bar_bar___rule | ../../bar/script.py"
-        " ../../bar/input1.txt obj/foo/foo.stamp\n"
+        " ../../bar/input1.txt phony/foo/foo\n"
         "\n"
-        "build obj/bar/bar.stamp: stamp bar.out\n";
+        "build phony/bar/bar: phony bar.out\n";
     EXPECT_EQ(expected_linux, out.str());
   }
 }
diff --git a/src/gn/ninja_binary_target_writer.cc b/src/gn/ninja_binary_target_writer.cc
index e06700a..08df4c1 100644
--- a/src/gn/ninja_binary_target_writer.cc
+++ b/src/gn/ninja_binary_target_writer.cc
@@ -7,10 +7,10 @@
 #include <sstream>
 
 #include "base/strings/string_util.h"
+#include "gn/builtin_tool.h"
 #include "gn/config_values_extractors.h"
 #include "gn/deps_iterator.h"
 #include "gn/filesystem_utils.h"
-#include "gn/general_tool.h"
 #include "gn/ninja_c_binary_target_writer.h"
 #include "gn/ninja_rust_binary_target_writer.h"
 #include "gn/ninja_target_command_util.h"
@@ -50,8 +50,8 @@
   writer.Run();
 }
 
-std::vector<OutputFile> NinjaBinaryTargetWriter::WriteInputsStampAndGetDep(
-    size_t num_stamp_uses) const {
+std::vector<OutputFile> NinjaBinaryTargetWriter::WriteInputsPhonyAndGetDep(
+    size_t num_output_uses) const {
   CHECK(target_->toolchain()) << "Toolchain not set on target "
                               << target_->label().GetUserVisibleName(true);
 
@@ -65,8 +65,8 @@
   if (inputs.size() == 0)
     return std::vector<OutputFile>();  // No inputs
 
-  // If we only have one input, return it directly instead of writing a stamp
-  // file for it.
+  // If we only have one input, return it directly instead of writing a phony
+  // target for it.
   if (inputs.size() == 1) {
     return std::vector<OutputFile>{
       OutputFile(settings_->build_settings(), *inputs[0])};
@@ -76,21 +76,22 @@
   for (const SourceFile* source : inputs)
     outs.push_back(OutputFile(settings_->build_settings(), *source));
 
-  // If there are multiple inputs, but the stamp file would be referenced only
+  // If there are multiple inputs, but the phony target would be referenced only
   // once, don't write it but depend on the inputs directly.
-  if (num_stamp_uses == 1u)
+  if (num_output_uses == 1u)
     return outs;
 
-  // Make a stamp file.
-  OutputFile stamp_file =
-      GetBuildDirForTargetAsOutputFile(target_, BuildDirType::OBJ);
-  stamp_file.value().append(target_->label().name());
-  stamp_file.value().append(".inputs.stamp");
+  // Make a phony target. We don't need to worry about an empty phony target, as
+  // those would have been peeled off already.
+  CHECK(!inputs.empty());
+  OutputFile phony_file =
+      GetBuildDirForTargetAsOutputFile(target_, BuildDirType::PHONY);
+  phony_file.value().append(target_->label().name());
+  phony_file.value().append(".inputs");
 
   out_ << "build ";
-  path_output_.WriteFile(out_, stamp_file);
-  out_ << ": " << GetNinjaRulePrefixForToolchain(settings_)
-       << GeneralTool::kGeneralToolStamp;
+  path_output_.WriteFile(out_, phony_file);
+  out_ << ": " << BuiltinTool::kBuiltinToolPhony;
 
   // File inputs.
   for (const auto* input : inputs) {
@@ -99,7 +100,7 @@
   }
 
   out_ << std::endl;
-  return {stamp_file};
+  return {phony_file};
 }
 
 void NinjaBinaryTargetWriter::WriteSourceSetPhony(
diff --git a/src/gn/ninja_binary_target_writer.h b/src/gn/ninja_binary_target_writer.h
index eb75c89..fcf90bf 100644
--- a/src/gn/ninja_binary_target_writer.h
+++ b/src/gn/ninja_binary_target_writer.h
@@ -33,15 +33,15 @@
     UniqueVector<const Target*> swiftmodule_deps;
   };
 
-  // Writes to the output stream a stamp rule for inputs, and
-  // returns the file to be appended to source rules that encodes the
+  // Writes to the output stream a phony rule for inputs, and
+  // returns the target to be appended to source rules that encodes the
   // implicit dependencies for the current target.
-  // If num_stamp_uses is small, this might return all input dependencies
-  // directly, without writing a stamp file.
+  // If num_output_uses is small, this might return all input dependencies
+  // directly, without writing a phony rule.
   // If there are no implicit dependencies and no extra target dependencies
   // are passed in, this returns an empty vector.
-  std::vector<OutputFile> WriteInputsStampAndGetDep(
-      size_t num_stamp_uses) const;
+  std::vector<OutputFile> WriteInputsPhonyAndGetDep(
+      size_t num_phony_uses) const;
 
   // Writes the phony line for a source set. These are not linked.
   void WriteSourceSetPhony(const std::vector<OutputFile>& object_files);
diff --git a/src/gn/ninja_binary_target_writer_unittest.cc b/src/gn/ninja_binary_target_writer_unittest.cc
index 9e4037c..afcc4d6 100644
--- a/src/gn/ninja_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_binary_target_writer_unittest.cc
@@ -167,12 +167,12 @@
         "target_out_dir = obj/foo\n"
         "target_output_name = bar\n"
         "\n"
-        "build obj/foo/bar.inputs.stamp: stamp "
+        "build phony/foo/bar.inputs: phony "
         "../../foo/input1 ../../foo/input2\n"
         "build obj/foo/bar.source1.o: cxx ../../foo/source1.cc | "
-        "obj/foo/bar.inputs.stamp\n"
+        "phony/foo/bar.inputs\n"
         "build obj/foo/bar.source2.o: cxx ../../foo/source2.cc | "
-        "obj/foo/bar.inputs.stamp\n"
+        "phony/foo/bar.inputs\n"
         "\n"
         "build phony/foo/bar: phony obj/foo/bar.source1.o "
         "obj/foo/bar.source2.o\n";
diff --git a/src/gn/ninja_build_writer_unittest.cc b/src/gn/ninja_build_writer_unittest.cc
index 8bc6839..f98787c 100644
--- a/src/gn/ninja_build_writer_unittest.cc
+++ b/src/gn/ninja_build_writer_unittest.cc
@@ -155,16 +155,16 @@
       "  depth = 42\n";
   const char expected_toolchain[] = "subninja toolchain.ninja\n";
   const char expected_targets[] =
-      "build bar: phony obj/bar/bar.stamp\n"
-      "build baz: phony obj/baz/baz.stamp\n"
-      "build foo$:bar: phony obj/foo/bar.stamp\n"
-      "build bar$:bar: phony obj/bar/bar.stamp\n"
-      "build baz$:baz: phony obj/baz/baz.stamp\n";
+      "build bar: phony phony/bar/bar\n"
+      "build baz: phony phony/baz/baz\n"
+      "build foo$:bar: phony phony/foo/bar\n"
+      "build bar$:bar: phony phony/bar/bar\n"
+      "build baz$:baz: phony phony/baz/baz\n";
   const char expected_root_target[] =
       "build all: phony $\n"
-      "    obj/foo/bar.stamp $\n"
-      "    obj/bar/bar.stamp $\n"
-      "    obj/baz/baz.stamp\n";
+      "    phony/foo/bar $\n"
+      "    phony/bar/bar $\n"
+      "    phony/baz/baz\n";
   const char expected_default[] = "default all\n";
   std::string out_str = ninja_out.str();
 #define EXPECT_SNIPPET(expected)                       \
diff --git a/src/gn/ninja_bundle_data_target_writer.cc b/src/gn/ninja_bundle_data_target_writer.cc
index 239c0c2..2281978 100644
--- a/src/gn/ninja_bundle_data_target_writer.cc
+++ b/src/gn/ninja_bundle_data_target_writer.cc
@@ -21,8 +21,8 @@
         OutputFile(settings_->build_settings(), source_file));
   }
 
-  std::vector<OutputFile> input_deps = WriteInputDepsStampAndGetDep(
-      std::vector<const Target*>(), /*num_stamp_uses=*/1);
+  std::vector<OutputFile> input_deps = WriteInputDepsPhonyAndGetDep(
+      std::vector<const Target*>(), /*num_output_uses=*/1);
   output_files.insert(output_files.end(), input_deps.begin(), input_deps.end());
 
   std::vector<OutputFile> order_only_deps;
@@ -31,5 +31,5 @@
       order_only_deps.push_back(*pair.ptr->dependency_output_file_or_phony());
   }
 
-  WriteStampForTarget(output_files, order_only_deps);
+  WritePhonyForTarget(output_files, order_only_deps);
 }
diff --git a/src/gn/ninja_bundle_data_target_writer_unittest.cc b/src/gn/ninja_bundle_data_target_writer_unittest.cc
index 06b5eb2..ebf0f89 100644
--- a/src/gn/ninja_bundle_data_target_writer_unittest.cc
+++ b/src/gn/ninja_bundle_data_target_writer_unittest.cc
@@ -42,7 +42,7 @@
   writer.Run();
 
   const char expected[] =
-      "build obj/foo/data.stamp: stamp "
+      "build phony/foo/data: phony "
       "../../foo/input1.txt "
       "../../foo/input2.txt "
       "../../foo/Foo.xcassets/Contents.json "
diff --git a/src/gn/ninja_c_binary_target_writer.cc b/src/gn/ninja_c_binary_target_writer.cc
index 2e7e613..f0d43a3 100644
--- a/src/gn/ninja_c_binary_target_writer.cc
+++ b/src/gn/ninja_c_binary_target_writer.cc
@@ -132,10 +132,10 @@
 
   WriteCompilerVars(module_dep_info);
 
-  size_t num_stamp_uses = target_->sources().size();
+  size_t num_output_uses = target_->sources().size();
 
-  std::vector<OutputFile> input_deps = WriteInputsStampAndGetDep(
-      num_stamp_uses);
+  std::vector<OutputFile> input_deps =
+      WriteInputsPhonyAndGetDep(num_output_uses);
 
   // The input dependencies will be an order-only dependency. This will cause
   // Ninja to make sure the inputs are up to date before compiling this source,
@@ -164,11 +164,11 @@
   // The order only deps are referenced by each source file compile,
   // but also by PCH compiles.  The latter are annoying to count, so omit
   // them here.  This means that binary targets with a single source file
-  // that also use PCH files won't have a stamp file even though having
+  // that also use PCH files won't have a phony target even though having
   // one would make output ninja file size a bit lower. That's ok, binary
   // targets with a single source are rare.
-  std::vector<OutputFile> order_only_deps = WriteInputDepsStampAndGetDep(
-      std::vector<const Target*>(), num_stamp_uses);
+  std::vector<OutputFile> order_only_deps = WriteInputDepsPhonyAndGetDep(
+      std::vector<const Target*>(), num_output_uses);
 
   // For GCC builds, the .gch files are not object files, but still need to be
   // added as explicit dependencies below. The .gch output files are placed in
@@ -813,11 +813,11 @@
   // this target.
   //
   // The action dependencies are not strictly necessary in this case. They
-  // should also have been collected via the input deps stamp that each source
-  // file has for an order-only dependency, and since this target depends on
-  // the sources, there is already an implicit order-only dependency. However,
-  // it's extra work to separate these out and there's no disadvantage to
-  // listing them again.
+  // should also have been collected via the input deps phony alias that each
+  // source file has for an order-only dependency, and since this target depends
+  // on the sources, there is already an implicit order-only dependency.
+  // However, it's extra work to separate these out and there's no disadvantage
+  // to listing them again.
   WriteOrderOnlyDependencies(classified_deps.non_linkable_deps);
 
   // End of the link "build" line.
diff --git a/src/gn/ninja_c_binary_target_writer.h b/src/gn/ninja_c_binary_target_writer.h
index bbc71c5..ae0b09d 100644
--- a/src/gn/ninja_c_binary_target_writer.h
+++ b/src/gn/ninja_c_binary_target_writer.h
@@ -40,7 +40,7 @@
   // non-object files (for instance, .gch files from a GCC toolchain, are
   // appended to |other_files|).
   //
-  // input_deps is the stamp file collecting the dependencies required before
+  // input_deps is the phony target collecting the dependencies required before
   // compiling this target. It will be empty if there are no input deps.
   void WritePCHCommands(const std::vector<OutputFile>& input_deps,
                         const std::vector<OutputFile>& order_only_deps,
diff --git a/src/gn/ninja_c_binary_target_writer_unittest.cc b/src/gn/ninja_c_binary_target_writer_unittest.cc
index df6e8b5..c4941fa 100644
--- a/src/gn/ninja_c_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_c_binary_target_writer_unittest.cc
@@ -329,15 +329,15 @@
       "target_output_name = libshlib\n"
       "\n"
       "build obj/foo/libshlib.input1.o: cxx ../../foo/input1.cc"
-      " || obj/foo/action.stamp\n"
+      " || phony/foo/action\n"
       "build obj/foo/libshlib.input2.o: cxx ../../foo/input2.cc"
-      " || obj/foo/action.stamp\n"
+      " || phony/foo/action\n"
       "\n"
       "build ./libshlib.so.6: solink obj/foo/libshlib.input1.o "
       // The order-only dependency here is stricly unnecessary since the
       // sources list this as an order-only dep. See discussion in the code
       // that writes this.
-      "obj/foo/libshlib.input2.o || obj/foo/action.stamp\n"
+      "obj/foo/libshlib.input2.o || phony/foo/action\n"
       "  ldflags =\n"
       "  libs =\n"
       "  frameworks =\n"
@@ -392,12 +392,12 @@
       "target_output_name = gen_obj\n"
       "\n"
       "build obj/out/Debug/gen_obj.generated.o: cxx generated.cc"
-      " || obj/foo/generate.stamp\n"
+      " || phony/foo/generate\n"
       "\n"
       "build phony/foo/gen_obj: phony obj/out/Debug/gen_obj.generated.o"
       // The order-only dependency here is strictly unnecessary since the
       // sources list this as an order-only dep.
-      " || obj/foo/generate.stamp\n";
+      " || phony/foo/generate\n";
 
   std::string obj_str = obj_out.str();
   EXPECT_EQ(obj_expected, obj_str);
@@ -537,6 +537,8 @@
   Target framework(setup.settings(), Label(SourceDir("//bar"), "framework"));
   framework.set_output_type(Target::CREATE_BUNDLE);
   framework.bundle_data().product_type() = "com.apple.product-type.framework";
+  framework.bundle_data().set_partial_info_plist(
+      SourceFile("//out/Debug/bar/framework/framework_partial_info.plist"));
   framework.public_configs().push_back(LabelConfigPair(&framework_config));
   framework.SetToolchain(setup.toolchain());
   framework.visibility().SetPublic();
@@ -563,7 +565,7 @@
       "target_output_name = libshlib\n"
       "\n"
       "\n"
-      "build ./libshlib.so: solink | obj/bar/framework.stamp\n"
+      "build ./libshlib.so: solink | phony/bar/framework\n"
       "  ldflags = -F.\n"
       "  libs =\n"
       "  frameworks = -framework System -framework Bar "
@@ -1202,12 +1204,12 @@
         "target_out_dir = obj/foo\n"
         "target_output_name = bar\n"
         "\n"
-        "build obj/foo/bar.inputs.stamp: stamp"
+        "build phony/foo/bar.inputs: phony"
         " ../../foo/input1.data ../../foo/input2.data\n"
         "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc"
-        " | obj/foo/bar.inputs.stamp\n"
+        " | phony/foo/bar.inputs\n"
         "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc"
-        " | obj/foo/bar.inputs.stamp\n"
+        " | phony/foo/bar.inputs\n"
         "\n"
         "build phony/foo/bar: phony obj/foo/bar.input1.o "
         "obj/foo/bar.input2.o\n";
@@ -1252,12 +1254,12 @@
         "target_out_dir = obj/foo\n"
         "target_output_name = bar\n"
         "\n"
-        "build obj/foo/bar.inputs.stamp: stamp"
+        "build phony/foo/bar.inputs: phony"
         " ../../foo/input1.data ../../foo/input2.data ../../foo/input3.data\n"
         "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc"
-        " | obj/foo/bar.inputs.stamp\n"
+        " | phony/foo/bar.inputs\n"
         "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc"
-        " | obj/foo/bar.inputs.stamp\n"
+        " | phony/foo/bar.inputs\n"
         "\n"
         "build phony/foo/bar: phony obj/foo/bar.input1.o "
         "obj/foo/bar.input2.o\n";
@@ -1656,7 +1658,7 @@
         " || phony/foo/foo\n"
         "\n"
         "build phony/bar/bar: phony obj/bar/bar.o "
-        "|| obj/bar/group.stamp phony/foo/foo\n";
+        "|| phony/bar/group phony/foo/foo\n";
 
     const std::string out_str = out.str();
     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
diff --git a/src/gn/ninja_copy_target_writer.cc b/src/gn/ninja_copy_target_writer.cc
index c1a94ee..646ec44 100644
--- a/src/gn/ninja_copy_target_writer.cc
+++ b/src/gn/ninja_copy_target_writer.cc
@@ -33,28 +33,13 @@
     return;
   }
 
-  const Tool* stamp_tool = target_->toolchain()->GetTool(GeneralTool::kGeneralToolStamp);
-  if (!stamp_tool) {
-    g_scheduler->FailWithError(Err(
-        nullptr, "Copy tool not defined",
-        "The toolchain " +
-            target_->toolchain()->label().GetUserVisibleName(false) +
-            "\n used by target " + target_->label().GetUserVisibleName(false) +
-            "\n doesn't define a \"stamp\" tool."));
-    return;
-  }
-
-  // Figure out the substitutions used by the copy and stamp tools.
-  SubstitutionBits required_bits = copy_tool->substitution_bits();
-  required_bits.MergeFrom(stamp_tool->substitution_bits());
-
-  // General target-related substitutions needed by both tools.
-  WriteSharedVars(required_bits);
+  // General target-related substitutions needed by the copy tool.
+  WriteSharedVars(copy_tool->substitution_bits());
 
   std::vector<OutputFile> output_files;
   WriteCopyRules(&output_files);
   out_ << std::endl;
-  WriteStampForTarget(output_files, std::vector<OutputFile>());
+  WritePhonyForTarget(output_files, std::vector<OutputFile>());
 }
 
 void NinjaCopyTargetWriter::WriteCopyRules(
@@ -69,9 +54,9 @@
   std::string tool_name = GetNinjaRulePrefixForToolchain(settings_) +
                           GeneralTool::kGeneralToolCopy;
 
-  size_t num_stamp_uses = target_->sources().size();
-  std::vector<OutputFile> input_deps = WriteInputDepsStampAndGetDep(
-      std::vector<const Target*>(), num_stamp_uses);
+  size_t num_output_uses = target_->sources().size();
+  std::vector<OutputFile> input_deps = WriteInputDepsPhonyAndGetDep(
+      std::vector<const Target*>(), num_output_uses);
 
   std::vector<OutputFile> data_outs;
   for (const auto& dep : target_->data_deps()) {
diff --git a/src/gn/ninja_copy_target_writer_unittest.cc b/src/gn/ninja_copy_target_writer_unittest.cc
index f641ffa..1b5077a 100644
--- a/src/gn/ninja_copy_target_writer_unittest.cc
+++ b/src/gn/ninja_copy_target_writer_unittest.cc
@@ -35,7 +35,7 @@
       "build input1.out: copy ../../foo/input1.txt\n"
       "build input2.out: copy ../../foo/input2.txt\n"
       "\n"
-      "build obj/foo/bar.stamp: stamp input1.out input2.out\n";
+      "build phony/foo/bar: phony input1.out input2.out\n";
   std::string out_str = out.str();
   EXPECT_EQ(expected_linux, out_str);
 }
@@ -63,7 +63,7 @@
   const char expected_linux[] =
       "build output.out: copy ../../foo/input1.txt\n"
       "\n"
-      "build obj/foo/bar.stamp: stamp output.out\n";
+      "build phony/foo/bar: phony output.out\n";
   std::string out_str = out.str();
   EXPECT_EQ(expected_linux, out_str);
 }
@@ -88,7 +88,7 @@
   const char expected_linux[] =
       "build input1.out: copy ../../foo/input1.txt || ../../foo/script.py\n"
       "\n"
-      "build obj/foo/bar.stamp: stamp input1.out\n";
+      "build phony/foo/bar: phony input1.out\n";
   std::string out_str = out.str();
   EXPECT_EQ(expected_linux, out_str);
 }
@@ -118,9 +118,9 @@
   writer.Run();
 
   const char expected_linux[] =
-      "build input1.out: copy ../../foo/input1.txt || obj/foo/datadep.stamp\n"
+      "build input1.out: copy ../../foo/input1.txt || phony/foo/datadep\n"
       "\n"
-      "build obj/foo/bar.stamp: stamp input1.out\n";
+      "build phony/foo/bar: phony input1.out\n";
   std::string out_str = out.str();
   EXPECT_EQ(expected_linux, out_str);
 }
diff --git a/src/gn/ninja_create_bundle_target_writer.cc b/src/gn/ninja_create_bundle_target_writer.cc
index 9623e32..002c042 100644
--- a/src/gn/ninja_create_bundle_target_writer.cc
+++ b/src/gn/ninja_create_bundle_target_writer.cc
@@ -77,11 +77,11 @@
   if (!EnsureAllToolsAvailable(target_))
     return;
 
-  // Stamp users are CopyBundleData, CompileAssetsCatalog, CodeSigning and
-  // StampForTarget.
-  size_t num_stamp_uses = 4;
-  std::vector<OutputFile> order_only_deps = WriteInputDepsStampAndGetDep(
-      std::vector<const Target*>(), num_stamp_uses);
+  // Output users are CopyBundleData, CompileAssetsCatalog, CodeSigning and
+  // PhonyForTarget.
+  size_t num_output_uses = 4;
+  std::vector<OutputFile> order_only_deps = WriteInputDepsPhonyAndGetDep(
+      std::vector<const Target*>(), num_output_uses);
 
   std::string code_signing_rule_name = WriteCodeSigningRuleDefinition();
 
@@ -94,7 +94,13 @@
     if (pair.ptr->dependency_output_file_or_phony())
       order_only_deps.push_back(*pair.ptr->dependency_output_file_or_phony());
   }
-  WriteStampForTarget(output_files, order_only_deps);
+
+  // If the target does not have a phony target to write, then we have nothing
+  // left to do.
+  if (!target_->dependency_output_file_or_phony())
+    return;
+
+  WritePhonyForTarget(output_files, order_only_deps);
 
   // Write a phony target for the outer bundle directory. This allows other
   // targets to treat the entire bundle as a single unit, even though it is
@@ -104,7 +110,6 @@
       out_,
       OutputFile(settings_->build_settings(),
                  target_->bundle_data().GetBundleRootDirOutput(settings_)));
-  CHECK(target_->dependency_output_file_or_phony());
   out_ << ": " << BuiltinTool::kBuiltinToolPhony << " ";
   out_ << target_->dependency_output_file_or_phony()->value();
   out_ << std::endl;
@@ -222,7 +227,7 @@
     return;
   }
 
-  OutputFile input_dep = WriteCompileAssetsCatalogInputDepsStamp(
+  OutputFile input_dep = WriteCompileAssetsCatalogInputDepsPhony(
       target_->bundle_data().assets_catalog_deps());
   DCHECK(!input_dep.value().empty());
 
@@ -282,7 +287,7 @@
 }
 
 OutputFile
-NinjaCreateBundleTargetWriter::WriteCompileAssetsCatalogInputDepsStamp(
+NinjaCreateBundleTargetWriter::WriteCompileAssetsCatalogInputDepsPhony(
     const std::vector<const Target*>& dependencies) {
   DCHECK(!dependencies.empty());
   if (dependencies.size() == 1) {
@@ -291,15 +296,14 @@
                : OutputFile{};
   }
 
-  OutputFile xcassets_input_stamp_file =
-      GetBuildDirForTargetAsOutputFile(target_, BuildDirType::OBJ);
-  xcassets_input_stamp_file.value().append(target_->label().name());
-  xcassets_input_stamp_file.value().append(".xcassets.inputdeps.stamp");
+  OutputFile xcassets_input_phony =
+      GetBuildDirForTargetAsOutputFile(target_, BuildDirType::PHONY);
+  xcassets_input_phony.value().append(target_->label().name());
+  xcassets_input_phony.value().append(".xcassets.inputdeps");
 
   out_ << "build ";
-  path_output_.WriteFile(out_, xcassets_input_stamp_file);
-  out_ << ": " << GetNinjaRulePrefixForToolchain(settings_)
-       << GeneralTool::kGeneralToolStamp;
+  path_output_.WriteFile(out_, xcassets_input_phony);
+  out_ << ": " << BuiltinTool::kBuiltinToolPhony;
 
   for (const Target* target : dependencies) {
     if (target->dependency_output_file_or_phony()) {
@@ -308,7 +312,7 @@
     }
   }
   out_ << std::endl;
-  return xcassets_input_stamp_file;
+  return xcassets_input_phony;
 }
 
 void NinjaCreateBundleTargetWriter::WriteCodeSigningStep(
@@ -318,9 +322,9 @@
   if (code_signing_rule_name.empty())
     return;
 
-  OutputFile code_signing_input_stamp_file =
-      WriteCodeSigningInputDepsStamp(order_only_deps, output_files);
-  DCHECK(!code_signing_input_stamp_file.value().empty());
+  OutputFile code_signing_input_phony =
+      WriteCodeSigningInputDepsPhony(order_only_deps, output_files);
+  DCHECK(!code_signing_input_phony.value().empty());
 
   out_ << "build";
   std::vector<OutputFile> code_signing_output_files;
@@ -330,17 +334,17 @@
   path_output_.WriteFiles(out_, code_signing_output_files);
 
   // Since the code signature step depends on all the files from the bundle,
-  // the create_bundle stamp can just depends on the output of the signature
+  // the create_bundle phony can just depends on the output of the signature
   // script (dependencies are transitive).
   *output_files = std::move(code_signing_output_files);
 
   out_ << ": " << code_signing_rule_name;
   out_ << " | ";
-  path_output_.WriteFile(out_, code_signing_input_stamp_file);
+  path_output_.WriteFile(out_, code_signing_input_phony);
   out_ << std::endl;
 }
 
-OutputFile NinjaCreateBundleTargetWriter::WriteCodeSigningInputDepsStamp(
+OutputFile NinjaCreateBundleTargetWriter::WriteCodeSigningInputDepsPhony(
     const std::vector<OutputFile>& order_only_deps,
     std::vector<OutputFile>* output_files) {
   std::vector<SourceFile> code_signing_input_files;
@@ -359,15 +363,14 @@
   if (code_signing_input_files.size() == 1 && order_only_deps.empty())
     return OutputFile(settings_->build_settings(), code_signing_input_files[0]);
 
-  OutputFile code_signing_input_stamp_file =
-      GetBuildDirForTargetAsOutputFile(target_, BuildDirType::OBJ);
-  code_signing_input_stamp_file.value().append(target_->label().name());
-  code_signing_input_stamp_file.value().append(".codesigning.inputdeps.stamp");
+  OutputFile code_signing_input_phony =
+      GetBuildDirForTargetAsOutputFile(target_, BuildDirType::PHONY);
+  code_signing_input_phony.value().append(target_->label().name());
+  code_signing_input_phony.value().append(".codesigning.inputdeps");
 
   out_ << "build ";
-  path_output_.WriteFile(out_, code_signing_input_stamp_file);
-  out_ << ": " << GetNinjaRulePrefixForToolchain(settings_)
-       << GeneralTool::kGeneralToolStamp;
+  path_output_.WriteFile(out_, code_signing_input_phony);
+  out_ << ": " << BuiltinTool::kBuiltinToolPhony;
 
   for (const SourceFile& source : code_signing_input_files) {
     out_ << " ";
@@ -378,5 +381,5 @@
     path_output_.WriteFiles(out_, order_only_deps);
   }
   out_ << std::endl;
-  return code_signing_input_stamp_file;
+  return code_signing_input_phony;
 }
diff --git a/src/gn/ninja_create_bundle_target_writer.h b/src/gn/ninja_create_bundle_target_writer.h
index 6d4e224..189a524 100644
--- a/src/gn/ninja_create_bundle_target_writer.h
+++ b/src/gn/ninja_create_bundle_target_writer.h
@@ -46,9 +46,9 @@
       const std::vector<OutputFile>& order_only_deps,
       std::vector<OutputFile>* output_files);
 
-  // Writes the stamp file for the assets catalog compilation input
+  // Writes the phony target for the assets catalog compilation input
   // dependencies.
-  OutputFile WriteCompileAssetsCatalogInputDepsStamp(
+  OutputFile WriteCompileAssetsCatalogInputDepsPhony(
       const std::vector<const Target*>& dependencies);
 
   // Writes the code signing step (if a script is defined).
@@ -60,8 +60,8 @@
                             const std::vector<OutputFile>& order_only_deps,
                             std::vector<OutputFile>* output_files);
 
-  // Writes the stamp file for the code signing input dependencies.
-  OutputFile WriteCodeSigningInputDepsStamp(
+  // Writes the phony target for the code signing input dependencies.
+  OutputFile WriteCodeSigningInputDepsPhony(
       const std::vector<OutputFile>& order_only_deps,
       std::vector<OutputFile>* output_files);
 
diff --git a/src/gn/ninja_create_bundle_target_writer_unittest.cc b/src/gn/ninja_create_bundle_target_writer_unittest.cc
index d2c5c24..77598c8 100644
--- a/src/gn/ninja_create_bundle_target_writer_unittest.cc
+++ b/src/gn/ninja_create_bundle_target_writer_unittest.cc
@@ -75,17 +75,17 @@
   writer.Run();
 
   const char expected[] =
-      "build obj/baz/bar.inputdeps.stamp: stamp obj/foo/bar.stamp "
-      "obj/foo/data.stamp\n"
+      "build phony/baz/bar.inputdeps: phony phony/foo/bar "
+      "phony/foo/data\n"
       "build bar.bundle/Contents/Resources/input1.txt: copy_bundle_data "
-      "../../foo/input1.txt || obj/baz/bar.inputdeps.stamp\n"
+      "../../foo/input1.txt || phony/baz/bar.inputdeps\n"
       "build bar.bundle/Contents/Resources/input2.txt: copy_bundle_data "
-      "../../foo/input2.txt || obj/baz/bar.inputdeps.stamp\n"
-      "build obj/baz/bar.stamp: stamp "
+      "../../foo/input2.txt || phony/baz/bar.inputdeps\n"
+      "build phony/baz/bar: phony "
       "bar.bundle/Contents/Resources/input1.txt "
       "bar.bundle/Contents/Resources/input2.txt"
-      " || obj/baz/bar.inputdeps.stamp\n"
-      "build bar.bundle: phony obj/baz/bar.stamp\n";
+      " || phony/baz/bar.inputdeps\n"
+      "build bar.bundle: phony phony/baz/bar\n";
   std::string out_str = out.str();
   EXPECT_EQ(expected, out_str);
 }
@@ -124,17 +124,17 @@
   writer.Run();
 
   const char expected[] =
-      "build obj/baz/bar.inputdeps.stamp: stamp obj/foo/bar.stamp "
-      "obj/foo/data.stamp\n"
+      "build phony/baz/bar.inputdeps: phony phony/foo/bar "
+      "phony/foo/data\n"
       "build gen/bar.bundle/Contents/Resources/input1.txt: copy_bundle_data "
-      "../../foo/input1.txt || obj/baz/bar.inputdeps.stamp\n"
+      "../../foo/input1.txt || phony/baz/bar.inputdeps\n"
       "build gen/bar.bundle/Contents/Resources/input2.txt: copy_bundle_data "
-      "../../foo/input2.txt || obj/baz/bar.inputdeps.stamp\n"
-      "build obj/baz/bar.stamp: stamp "
+      "../../foo/input2.txt || phony/baz/bar.inputdeps\n"
+      "build phony/baz/bar: phony "
       "gen/bar.bundle/Contents/Resources/input1.txt "
       "gen/bar.bundle/Contents/Resources/input2.txt || "
-      "obj/baz/bar.inputdeps.stamp\n"
-      "build gen/bar.bundle: phony obj/baz/bar.stamp\n";
+      "phony/baz/bar.inputdeps\n"
+      "build gen/bar.bundle: phony phony/baz/bar\n";
   std::string out_str = out.str();
   EXPECT_EQ(expected, out_str);
 }
@@ -165,10 +165,10 @@
   writer.Run();
 
   const char expected[] =
-      "build baz/bar/bar_partial_info.plist: stamp || obj/foo/bar.stamp\n"
-      "build obj/baz/bar.stamp: stamp "
-      "baz/bar/bar_partial_info.plist || obj/foo/bar.stamp\n"
-      "build bar.bundle: phony obj/baz/bar.stamp\n";
+      "build baz/bar/bar_partial_info.plist: stamp || phony/foo/bar\n"
+      "build phony/baz/bar: phony "
+      "baz/bar/bar_partial_info.plist || phony/foo/bar\n"
+      "build bar.bundle: phony phony/baz/bar\n";
   std::string out_str = out.str();
   EXPECT_EQ(expected, out_str);
 }
@@ -225,17 +225,17 @@
   writer.Run();
 
   const char expected[] =
-      "build obj/baz/bar.inputdeps.stamp: stamp obj/foo/bar.stamp "
-      "obj/foo/data.stamp\n"
+      "build phony/baz/bar.inputdeps: phony phony/foo/bar "
+      "phony/foo/data\n"
       "build bar.bundle/Contents/Resources/Assets.car: compile_xcassets "
-      "../../foo/Foo.xcassets | obj/foo/data.stamp || "
-      "obj/baz/bar.inputdeps.stamp\n"
+      "../../foo/Foo.xcassets | phony/foo/data || "
+      "phony/baz/bar.inputdeps\n"
       "  product_type = com.apple.product-type\n"
       "  xcasset_compiler_flags = --app-icon foo\n"
-      "build obj/baz/bar.stamp: stamp "
+      "build phony/baz/bar: phony "
       "bar.bundle/Contents/Resources/Assets.car || "
-      "obj/baz/bar.inputdeps.stamp\n"
-      "build bar.bundle: phony obj/baz/bar.stamp\n";
+      "phony/baz/bar.inputdeps\n"
+      "build bar.bundle: phony phony/baz/bar\n";
   std::string out_str = out.str();
   EXPECT_EQ(expected, out_str);
 }
@@ -253,6 +253,8 @@
   SetupBundleDataDir(&create_bundle.bundle_data(), "//out/Debug");
   create_bundle.set_output_type(Target::CREATE_BUNDLE);
   create_bundle.SetToolchain(setup.toolchain());
+  create_bundle.bundle_data().set_partial_info_plist(
+      SourceFile("//out/Debug/baz/bar/bar_partial_info.plist"));
   ASSERT_TRUE(create_bundle.OnResolved(&err));
 
   std::ostringstream out;
@@ -260,10 +262,11 @@
   writer.Run();
 
   const char expected[] =
-      "build obj/baz/bar.stamp: stamp\n"
-      "build bar.bundle: phony obj/baz/bar.stamp\n";
+      "build baz/bar/bar_partial_info.plist: stamp\n"
+      "build phony/baz/bar: phony baz/bar/bar_partial_info.plist\n"
+      "build bar.bundle: phony phony/baz/bar\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str);
+  EXPECT_EQ(expected, out_str) << out_str;
 }
 
 // Tests complex target with multiple bundle_data sources, including
@@ -376,32 +379,32 @@
   writer.Run();
 
   const char expected[] =
-      "build obj/baz/bar.inputdeps.stamp: stamp obj/biz/assets.stamp "
-      "obj/foo/assets.stamp obj/foo/bar.stamp obj/foo/data.stamp "
-      "obj/qux/info_plist.stamp obj/quz/assets.stamp\n"
+      "build phony/baz/bar.inputdeps: phony phony/biz/assets "
+      "phony/foo/assets phony/foo/bar phony/foo/data "
+      "phony/qux/info_plist phony/quz/assets\n"
       "build bar.bundle/Contents/Info.plist: copy_bundle_data "
-      "../../qux/qux-Info.plist || obj/baz/bar.inputdeps.stamp\n"
+      "../../qux/qux-Info.plist || phony/baz/bar.inputdeps\n"
       "build bar.bundle/Contents/Resources/input1.txt: copy_bundle_data "
-      "../../foo/input1.txt || obj/baz/bar.inputdeps.stamp\n"
+      "../../foo/input1.txt || phony/baz/bar.inputdeps\n"
       "build bar.bundle/Contents/Resources/input2.txt: copy_bundle_data "
-      "../../foo/input2.txt || obj/baz/bar.inputdeps.stamp\n"
-      "build obj/baz/bar.xcassets.inputdeps.stamp: stamp "
-      "obj/foo/assets.stamp "
-      "obj/quz/assets.stamp obj/biz/assets.stamp\n"
+      "../../foo/input2.txt || phony/baz/bar.inputdeps\n"
+      "build phony/baz/bar.xcassets.inputdeps: phony "
+      "phony/foo/assets "
+      "phony/quz/assets phony/biz/assets\n"
       "build bar.bundle/Contents/Resources/Assets.car | "
       "baz/bar/bar_partial_info.plist: compile_xcassets "
       "../../foo/Foo.xcassets ../../quz/Quz.xcassets "
-      "../../biz/Biz.xcassets | obj/baz/bar.xcassets.inputdeps.stamp || "
-      "obj/baz/bar.inputdeps.stamp\n"
+      "../../biz/Biz.xcassets | phony/baz/bar.xcassets.inputdeps || "
+      "phony/baz/bar.inputdeps\n"
       "  product_type = com.apple.product-type\n"
       "  partial_info_plist = baz/bar/bar_partial_info.plist\n"
-      "build obj/baz/bar.stamp: stamp "
+      "build phony/baz/bar: phony "
       "bar.bundle/Contents/Info.plist "
       "bar.bundle/Contents/Resources/input1.txt "
       "bar.bundle/Contents/Resources/input2.txt "
       "bar.bundle/Contents/Resources/Assets.car "
-      "baz/bar/bar_partial_info.plist || obj/baz/bar.inputdeps.stamp\n"
-      "build bar.bundle: phony obj/baz/bar.stamp\n";
+      "baz/bar/bar_partial_info.plist || phony/baz/bar.inputdeps\n"
+      "build bar.bundle: phony phony/baz/bar\n";
   std::string out_str = out.str();
   EXPECT_EQ(expected, out_str);
 }
@@ -458,30 +461,30 @@
   writer.Run();
 
   const char expected[] =
-      "build obj/baz/bar.inputdeps.stamp: stamp ./quz obj/foo/bar.stamp "
-      "obj/foo/data.stamp\n"
+      "build phony/baz/bar.inputdeps: phony ./quz phony/foo/bar "
+      "phony/foo/data\n"
       "rule __baz_bar___toolchain_default__code_signing_rule\n"
       "  command =  ../../build/codesign.py -b=quz bar.bundle\n"
       "  description = CODE SIGNING //baz:bar(//toolchain:default)\n"
       "  restat = 1\n"
       "\n"
       "build bar.bundle/Contents/Resources/input1.txt: copy_bundle_data "
-      "../../foo/input1.txt || obj/baz/bar.inputdeps.stamp\n"
+      "../../foo/input1.txt || phony/baz/bar.inputdeps\n"
       "build bar.bundle/Contents/Resources/input2.txt: copy_bundle_data "
-      "../../foo/input2.txt || obj/baz/bar.inputdeps.stamp\n"
-      "build obj/baz/bar.codesigning.inputdeps.stamp: stamp "
+      "../../foo/input2.txt || phony/baz/bar.inputdeps\n"
+      "build phony/baz/bar.codesigning.inputdeps: phony "
       "../../build/codesign.py "
       "quz "
       "bar.bundle/Contents/Resources/input1.txt "
       "bar.bundle/Contents/Resources/input2.txt || "
-      "obj/baz/bar.inputdeps.stamp\n"
+      "phony/baz/bar.inputdeps\n"
       "build bar.bundle/Contents/quz bar.bundle/_CodeSignature/CodeResources: "
       "__baz_bar___toolchain_default__code_signing_rule "
-      "| obj/baz/bar.codesigning.inputdeps.stamp\n"
-      "build obj/baz/bar.stamp: stamp "
+      "| phony/baz/bar.codesigning.inputdeps\n"
+      "build phony/baz/bar: phony "
       "bar.bundle/Contents/quz "
-      "bar.bundle/_CodeSignature/CodeResources || obj/baz/bar.inputdeps.stamp\n"
-      "build bar.bundle: phony obj/baz/bar.stamp\n";
+      "bar.bundle/_CodeSignature/CodeResources || phony/baz/bar.inputdeps\n"
+      "build bar.bundle: phony phony/baz/bar\n";
   std::string out_str = out.str();
   EXPECT_EQ(expected, out_str);
 }
diff --git a/src/gn/ninja_generated_file_target_writer.cc b/src/gn/ninja_generated_file_target_writer.cc
index 16fcf96..f4508a5 100644
--- a/src/gn/ninja_generated_file_target_writer.cc
+++ b/src/gn/ninja_generated_file_target_writer.cc
@@ -26,7 +26,7 @@
   // Write the file.
   GenerateFile();
 
-  // A generated_file target should generate a stamp file with dependencies
+  // A generated_file target should generate a phony target with dependencies
   // on each of the deps and data_deps in the target. The actual collection is
   // done at gen time, and so ninja doesn't need to know about it.
   std::vector<OutputFile> output_files;
@@ -42,7 +42,7 @@
       data_output_files.push_back(*pair.ptr->dependency_output_file_or_phony());
   }
 
-  WriteStampForTarget(output_files, data_output_files);
+  WritePhonyForTarget(output_files, data_output_files);
 }
 
 void NinjaGeneratedFileTargetWriter::GenerateFile() {
diff --git a/src/gn/ninja_generated_file_target_writer_unittest.cc b/src/gn/ninja_generated_file_target_writer_unittest.cc
index e88ad49..c7eab68 100644
--- a/src/gn/ninja_generated_file_target_writer_unittest.cc
+++ b/src/gn/ninja_generated_file_target_writer_unittest.cc
@@ -54,7 +54,7 @@
   writer.Run();
 
   const char expected[] =
-      "build obj/foo/bar.stamp: stamp obj/foo/dep.stamp obj/foo/dep2.stamp || "
-      "obj/foo/datadep.stamp\n";
+      "build phony/foo/bar: phony phony/foo/dep phony/foo/dep2 || "
+      "phony/foo/datadep\n";
   EXPECT_EQ(expected, out.str());
 }
diff --git a/src/gn/ninja_group_target_writer.cc b/src/gn/ninja_group_target_writer.cc
index 1ba6d1c..5ba4ba6 100644
--- a/src/gn/ninja_group_target_writer.cc
+++ b/src/gn/ninja_group_target_writer.cc
@@ -17,7 +17,7 @@
 NinjaGroupTargetWriter::~NinjaGroupTargetWriter() = default;
 
 void NinjaGroupTargetWriter::Run() {
-  // A group rule just generates a stamp file with dependencies on each of
+  // A group rule just generates a phony target with dependencies on each of
   // the deps and data_deps in the group.
   std::vector<OutputFile> output_files;
   for (const auto& pair : target_->GetDeps(Target::DEPS_LINKED)) {
@@ -32,5 +32,5 @@
       data_output_files.push_back(*pair.ptr->dependency_output_file_or_phony());
   }
 
-  WriteStampForTarget(output_files, data_output_files);
+  WritePhonyForTarget(output_files, data_output_files);
 }
diff --git a/src/gn/ninja_group_target_writer_unittest.cc b/src/gn/ninja_group_target_writer_unittest.cc
index 2280bb0..2408992 100644
--- a/src/gn/ninja_group_target_writer_unittest.cc
+++ b/src/gn/ninja_group_target_writer_unittest.cc
@@ -45,7 +45,7 @@
   writer.Run();
 
   const char expected[] =
-      "build obj/foo/bar.stamp: stamp obj/foo/dep.stamp obj/foo/dep2.stamp || "
-      "obj/foo/datadep.stamp\n";
+      "build phony/foo/bar: phony phony/foo/dep phony/foo/dep2 || "
+      "phony/foo/datadep\n";
   EXPECT_EQ(expected, out.str());
 }
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc
index a8aecaf..66e2804 100644
--- a/src/gn/ninja_rust_binary_target_writer.cc
+++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -110,10 +110,10 @@
 void NinjaRustBinaryTargetWriter::Run() {
   DCHECK(target_->output_type() != Target::SOURCE_SET);
 
-  size_t num_stamp_uses = target_->sources().size();
+  size_t num_output_uses = target_->sources().size();
 
-  std::vector<OutputFile> input_deps = WriteInputsStampAndGetDep(
-      num_stamp_uses);
+  std::vector<OutputFile> input_deps =
+      WriteInputsPhonyAndGetDep(num_output_uses);
 
   WriteCompilerVars();
 
@@ -124,8 +124,8 @@
   // Ninja to make sure the inputs are up to date before compiling this source,
   // but changes in the inputs deps won't cause the file to be recompiled. See
   // the comment on NinjaCBinaryTargetWriter::Run for more detailed explanation.
-  std::vector<OutputFile> order_only_deps = WriteInputDepsStampAndGetDep(
-      std::vector<const Target*>(), num_stamp_uses);
+  std::vector<OutputFile> order_only_deps = WriteInputDepsPhonyAndGetDep(
+      std::vector<const Target*>(), num_output_uses);
   std::copy(input_deps.begin(), input_deps.end(),
             std::back_inserter(order_only_deps));
 
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc
index a440a6f..d2446ac 100644
--- a/src/gn/ninja_rust_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -244,7 +244,7 @@
         "\n"
         "build obj/bar/libmylib.rlib: rust_rlib ../../bar/lib.rs | "
         "../../bar/mylib.rs ../../bar/lib.rs obj/bar/libmymacro.so || "
-        "obj/baz/group.stamp\n"
+        "phony/baz/group\n"
         "  externs = --extern mymacro=obj/bar/libmymacro.so\n"
         "  rustdeps = -Ldependency=obj/bar\n"
         "  sources = ../../bar/mylib.rs ../../bar/lib.rs\n";
@@ -748,7 +748,7 @@
         "target_output_name = bar\n"
         "\n"
         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
-        "../../foo/main.rs obj/bar/libmylib.rlib || obj/baz/group.stamp\n"
+        "../../foo/main.rs obj/bar/libmylib.rlib || phony/baz/group\n"
         "  externs = --extern mylib=obj/bar/libmylib.rlib\n"
         "  rustdeps = -Ldependency=obj/bar\n"
         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
@@ -828,7 +828,7 @@
     writer.Run();
 
     const char expected[] =
-        "build obj/foo/bar.inputs.stamp: stamp ../../foo/config.json ../../foo/template.h\n"
+        "build phony/foo/bar.inputs: phony ../../foo/config.json ../../foo/template.h\n"
         "crate_name = foo_bar\n"
         "crate_type = bin\n"
         "output_extension = \n"
@@ -841,7 +841,7 @@
         "\n"
         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
         "../../foo/main.rs ../../foo/config.json ../../foo/template.h "
-        "|| obj/foo/bar.inputs.stamp\n"
+        "|| phony/foo/bar.inputs\n"
         "  externs =\n"
         "  rustdeps =\n"
         "  sources = ../../foo/source.rs ../../foo/main.rs "
diff --git a/src/gn/ninja_target_writer.cc b/src/gn/ninja_target_writer.cc
index 5b443f1..802852c 100644
--- a/src/gn/ninja_target_writer.cc
+++ b/src/gn/ninja_target_writer.cc
@@ -188,16 +188,16 @@
     out_ << std::endl;
 }
 
-std::vector<OutputFile> NinjaTargetWriter::WriteInputDepsStampAndGetDep(
+std::vector<OutputFile> NinjaTargetWriter::WriteInputDepsPhonyAndGetDep(
     const std::vector<const Target*>& extra_hard_deps,
-    size_t num_stamp_uses) const {
+    size_t num_output_uses) const {
   CHECK(target_->toolchain()) << "Toolchain not set on target "
                               << target_->label().GetUserVisibleName(true);
 
   // ----------
   // Collect all input files that are input deps of this target. Knowing the
   // number before writing allows us to either skip writing the input deps
-  // stamp or optimize it. Use pointers to avoid copies here.
+  // phony or optimize it. Use pointers to avoid copies here.
   std::vector<const SourceFile*> input_deps_sources;
   input_deps_sources.reserve(32);
 
@@ -246,7 +246,7 @@
   // Toolchain dependencies. These must be resolved before doing anything.
   // This just writes all toolchain deps for simplicity. If we find that
   // toolchains often have more than one dependency, we could consider writing
-  // a toolchain-specific stamp file and only include the stamp here.
+  // a toolchain-specific phony target and only include the phony here.
   // Note that these are usually empty/small.
   const LabelTargetVector& toolchain_deps = target_->toolchain()->deps();
   for (const auto& toolchain_dep : toolchain_deps) {
@@ -263,7 +263,7 @@
     return std::vector<OutputFile>();  // No input dependencies.
 
   // If we're only generating one input dependency, return it directly instead
-  // of writing a stamp file for it.
+  // of writing a phony target for it.
   if (input_deps_sources.size() == 1 && input_deps_targets.size() == 0)
     return std::vector<OutputFile>{
         OutputFile(settings_->build_settings(), *input_deps_sources[0])};
@@ -290,52 +290,26 @@
       outs.push_back(*dep->dependency_output_file_or_phony());
   }
 
-  // If there are multiple inputs, but the stamp file would be referenced only
+  // If there are multiple inputs, but the phony target would be referenced only
   // once, don't write it but depend on the inputs directly.
-  if (num_stamp_uses == 1u)
+  if (num_output_uses == 1u)
     return outs;
 
-  // Make a stamp file.
-  OutputFile input_stamp_file =
-      GetBuildDirForTargetAsOutputFile(target_, BuildDirType::OBJ);
-  input_stamp_file.value().append(target_->label().name());
-  input_stamp_file.value().append(".inputdeps.stamp");
+  // Make a phony target. We don't need to worry about an empty phony target, as
+  // we would return early if there were no inputs.
+  CHECK(!outs.empty());
+  OutputFile input_phony_file =
+      GetBuildDirForTargetAsOutputFile(target_, BuildDirType::PHONY);
+  input_phony_file.value().append(target_->label().name());
+  input_phony_file.value().append(".inputdeps");
 
   out_ << "build ";
-  path_output_.WriteFile(out_, input_stamp_file);
-  out_ << ": " << GetNinjaRulePrefixForToolchain(settings_)
-       << GeneralTool::kGeneralToolStamp;
+  path_output_.WriteFile(out_, input_phony_file);
+  out_ << ": " << BuiltinTool::kBuiltinToolPhony;
   path_output_.WriteFiles(out_, outs);
 
   out_ << "\n";
-  return std::vector<OutputFile>{input_stamp_file};
-}
-
-void NinjaTargetWriter::WriteStampForTarget(
-    const std::vector<OutputFile>& files,
-    const std::vector<OutputFile>& order_only_deps) {
-  CHECK(target_->dependency_output_file());
-  const OutputFile& stamp_file = *target_->dependency_output_file();
-
-  // First validate that the target's dependency is a stamp file. Otherwise,
-  // we shouldn't have gotten here!
-  CHECK(base::EndsWith(stamp_file.value(), ".stamp",
-                       base::CompareCase::INSENSITIVE_ASCII))
-      << "Output should end in \".stamp\" for stamp file output. Instead got: "
-      << "\"" << stamp_file.value() << "\"";
-
-  out_ << "build ";
-  path_output_.WriteFile(out_, stamp_file);
-
-  out_ << ": " << GetNinjaRulePrefixForToolchain(settings_)
-       << GeneralTool::kGeneralToolStamp;
-  path_output_.WriteFiles(out_, files);
-
-  if (!order_only_deps.empty()) {
-    out_ << " ||";
-    path_output_.WriteFiles(out_, order_only_deps);
-  }
-  out_ << std::endl;
+  return std::vector<OutputFile>{input_phony_file};
 }
 
 void NinjaTargetWriter::WritePhonyForTarget(
diff --git a/src/gn/ninja_target_writer.h b/src/gn/ninja_target_writer.h
index f6c4e04..c9c8841 100644
--- a/src/gn/ninja_target_writer.h
+++ b/src/gn/ninja_target_writer.h
@@ -40,22 +40,16 @@
   // identified by the given bits will be written.
   void WriteSharedVars(const SubstitutionBits& bits);
 
-  // Writes to the output stream a stamp rule for input dependencies, and
+  // Writes to the output stream a phony rule for input dependencies, and
   // returns the file to be appended to source rules that encodes the
   // order-only dependencies for the current target.
-  // If num_stamp_uses is small, this might return all input dependencies
-  // directly, without writing a stamp file.
+  // If num_output_uses is small, this might return all input dependencies
+  // directly, without writing a phony rule.
   // If there are no implicit dependencies and no extra target dependencies
   // are passed in, this returns an empty vector.
-  std::vector<OutputFile> WriteInputDepsStampAndGetDep(
+  std::vector<OutputFile> WriteInputDepsPhonyAndGetDep(
       const std::vector<const Target*>& extra_hard_deps,
-      size_t num_stamp_uses) const;
-
-  // Writes to the output file a final stamp rule for the target that stamps
-  // the given list of files. This function assumes the stamp is for the target
-  // as a whole so the stamp file is set as the target's dependency output.
-  void WriteStampForTarget(const std::vector<OutputFile>& deps,
-                           const std::vector<OutputFile>& order_only_deps);
+      size_t num_output_uses) const;
 
   // Writes to the output file a final phony rule for the target that aliases
   // the given list of files.
diff --git a/src/gn/ninja_target_writer_unittest.cc b/src/gn/ninja_target_writer_unittest.cc
index 1b19159..300dbdd 100644
--- a/src/gn/ninja_target_writer_unittest.cc
+++ b/src/gn/ninja_target_writer_unittest.cc
@@ -22,17 +22,17 @@
   void Run() override {}
 
   // Make this public so the test can call it.
-  std::vector<OutputFile> WriteInputDepsStampAndGetDep(
+  std::vector<OutputFile> WriteInputDepsPhonyAndGetDep(
       const std::vector<const Target*>& extra_hard_deps,
-      size_t num_stamp_uses) {
-    return NinjaTargetWriter::WriteInputDepsStampAndGetDep(extra_hard_deps,
-                                                           num_stamp_uses);
+      size_t num_output_uses) {
+    return NinjaTargetWriter::WriteInputDepsPhonyAndGetDep(extra_hard_deps,
+                                                           num_output_uses);
   }
 };
 
 }  // namespace
 
-TEST(NinjaTargetWriter, WriteInputDepsStampAndGetDep) {
+TEST(NinjaTargetWriter, WriteInputDepsPhonyAndGetDep) {
   TestWithScope setup;
   Err err;
 
@@ -72,7 +72,7 @@
     std::ostringstream stream;
     TestingNinjaTargetWriter writer(&base_target, setup.toolchain(), stream);
     std::vector<OutputFile> dep =
-        writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>(), 10u);
+        writer.WriteInputDepsPhonyAndGetDep(std::vector<const Target*>(), 10u);
 
     // Since there is only one dependency, it should just be returned and
     // nothing written to the stream.
@@ -86,12 +86,12 @@
     std::ostringstream stream;
     TestingNinjaTargetWriter writer(&target, setup.toolchain(), stream);
     std::vector<OutputFile> dep =
-        writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>(), 10u);
+        writer.WriteInputDepsPhonyAndGetDep(std::vector<const Target*>(), 10u);
 
-    // Since there is only one dependency, a stamp file will be returned
+    // Since there is only one dependency, a phony target will be returned
     // directly without writing any additional rules.
     ASSERT_EQ(1u, dep.size());
-    EXPECT_EQ("obj/foo/base.stamp", dep[0].value());
+    EXPECT_EQ("phony/foo/base", dep[0].value());
   }
 
   {
@@ -107,7 +107,7 @@
         "build: __foo_action___rule | ../../foo/script.py"
         " ../../foo/action_source.txt ./target\n"
         "\n"
-        "build obj/foo/action.stamp: stamp\n",
+        "build phony/foo/action: phony\n",
         stream.str());
   }
 
@@ -117,19 +117,19 @@
     std::ostringstream stream;
     TestingNinjaTargetWriter writer(&action, setup.toolchain(), stream);
     std::vector<OutputFile> dep =
-        writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>(), 10u);
+        writer.WriteInputDepsPhonyAndGetDep(std::vector<const Target*>(), 10u);
 
     ASSERT_EQ(1u, dep.size());
-    EXPECT_EQ("obj/foo/action.inputdeps.stamp", dep[0].value());
+    EXPECT_EQ("phony/foo/action.inputdeps", dep[0].value());
     EXPECT_EQ(
-        "build obj/foo/action.inputdeps.stamp: stamp ../../foo/script.py "
+        "build phony/foo/action.inputdeps: phony ../../foo/script.py "
         "../../foo/action_source.txt ./target\n",
         stream.str());
   }
 }
 
-// Tests WriteInputDepsStampAndGetDep when toolchain deps are present.
-TEST(NinjaTargetWriter, WriteInputDepsStampAndGetDepWithToolchainDeps) {
+// Tests WriteInputDepsPhonyAndGetDep when toolchain deps are present.
+TEST(NinjaTargetWriter, WriteInputDepsPhonyAndGetDepWithToolchainDeps) {
   TestWithScope setup;
   Err err;
 
@@ -153,11 +153,11 @@
   std::ostringstream stream;
   TestingNinjaTargetWriter writer(&target, setup.toolchain(), stream);
   std::vector<OutputFile> dep =
-      writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>(), 10u);
+      writer.WriteInputDepsPhonyAndGetDep(std::vector<const Target*>(), 10u);
 
-  // Since there is more than one dependency, a stamp file will be returned
-  // and the rule for the stamp file will be written to the stream.
+  // Since there is more than one dependency, a phony target will be returned
+  // and the rule for the phony target will be written to the stream.
   ASSERT_EQ(1u, dep.size());
-  EXPECT_EQ("obj/foo/setup.stamp", dep[0].value());
+  EXPECT_EQ("phony/foo/setup", dep[0].value());
   EXPECT_EQ("", stream.str());
 }
diff --git a/src/gn/switches.cc b/src/gn/switches.cc
index cbeaa26..abbc0e4 100644
--- a/src/gn/switches.cc
+++ b/src/gn/switches.cc
@@ -199,8 +199,8 @@
   build directory.
 
   If a source set, action, copy, or group is listed, the runtime deps file will
-  correspond to the .stamp file or phony rule corresponding to that target. This
-  is probably not useful; the use-case for this feature is generally executable
+  correspond to the phony alias rule corresponding to that target. This is
+  probably not useful; the use-case for this feature is generally executable
   targets.
 
   The runtime dependency file will list one file per line, with no escaping.
diff --git a/src/gn/target.cc b/src/gn/target.cc
index a0e6629..c4662e0 100644
--- a/src/gn/target.cc
+++ b/src/gn/target.cc
@@ -542,9 +542,9 @@
           output_file.AsSourceFile(settings()->build_settings()));
     }
   } else {
-    // Everything else (like a group or bundle_data) has a stamp or phony
-    // output. The dependency output file should have computed what this is.
-    // This won't be valid unless the build is complete.
+    // Everything else (like a group or bundle_data) has a phony output. The
+    // dependency output phony should have computed what this is. This won't be
+    // valid unless the build is complete.
     if (!build_complete) {
       *err = Err(loc_for_error, kBuildIncompleteMsg);
       return false;
@@ -790,10 +790,12 @@
   // This check is only necessary if this target will result in a phony target.
   // Phony targets with no real inputs are treated as always dirty.
 
-  // TODO(bug 194): This method is currently just checking the relevant inputs
-  // for the current list of output types that result in phony targets. As the
-  // list of phony targets expands, this method should be updated to properly
-  // account for which inputs matter for the given output type.
+  // Actions always have at least one input file: the script used to execute
+  // the action. As such, they will never have an input-less phony target. We
+  // check this first to elide the common checks.
+  if (output_type() == ACTION || output_type() == ACTION_FOREACH) {
+    return true;
+  }
 
   // If any of this target's dependencies is non-phony target or a phony target
   // with real inputs, then this target should be considered to have inputs.
@@ -803,6 +805,19 @@
     }
   }
 
+  if (output_type() == BUNDLE_DATA) {
+    return !sources().empty();
+  }
+  if (output_type() == CREATE_BUNDLE) {
+    // CREATE_BUNDLE targets pick up most of their inputs in the form of
+    // dependencies on bundle_data targets, which were checked above when
+    // looping through GetDeps. This code handles the remaining possible
+    // CREATE_BUNDLE inputs.
+    return !bundle_data().assets_catalog_sources().empty() ||
+           !bundle_data().partial_info_plist().is_null() ||
+           !bundle_data().code_signing_script().is_null();
+  }
+
   // If any of this target's sources will result in output files, then this
   // target should be considered to have real inputs.
   std::vector<OutputFile> tool_outputs;
@@ -817,6 +832,13 @@
   const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this);
   bool check_tool_outputs = false;
   switch (output_type_) {
+    case ACTION:
+    case ACTION_FOREACH:
+    case BUNDLE_DATA:
+    case COPY_FILES:
+    case CREATE_BUNDLE:
+    case GENERATED_FILE:
+    case GROUP:
     case SOURCE_SET: {
       if (HasRealInputs()) {
         dependency_output_phony_ =
@@ -825,22 +847,6 @@
       }
       break;
     }
-    case GROUP:
-    case BUNDLE_DATA:
-    case CREATE_BUNDLE:
-    case COPY_FILES:
-    case ACTION:
-    case ACTION_FOREACH:
-    case GENERATED_FILE: {
-      // These don't get linked to and use stamps which should be the first
-      // entry in the outputs. These stamps are named
-      // "<target_out_dir>/<targetname>.stamp".
-      dependency_output_file_ =
-          GetBuildDirForTargetAsOutputFile(this, BuildDirType::OBJ);
-      dependency_output_file_->value().append(GetComputedOutputName());
-      dependency_output_file_->value().append(".stamp");
-      break;
-    }
     case EXECUTABLE:
     case LOADABLE_MODULE:
       // Executables and loadable modules don't get linked to, but the first
diff --git a/src/gn/target.h b/src/gn/target.h
index dcbaf2c..1d26301 100644
--- a/src/gn/target.h
+++ b/src/gn/target.h
@@ -320,7 +320,7 @@
   // action or a copy step, and the output library or executable file(s) from
   // binary targets.
   //
-  // It will NOT include stamp files, phony targets or object files.
+  // It will NOT include phony targets or object files.
   const std::vector<OutputFile>& computed_outputs() const {
     return computed_outputs_;
   }
@@ -333,7 +333,7 @@
   // a dependency on this one. It could be the same as the link output file
   // (this will be the case for static libraries). For shared libraries it
   // could be the same or different than the link output file, depending on the
-  // system. For actions this will be the stamp file.
+  // system.
   //
   // The dependency output phony is only set when the target does not have an
   // output file and is using a phony alias to represent it. The exception to
diff --git a/src/gn/tool.cc b/src/gn/tool.cc
index 9708e44..9297ce4 100644
--- a/src/gn/tool.cc
+++ b/src/gn/tool.cc
@@ -350,7 +350,7 @@
 
 // static
 const char* Tool::GetToolTypeForTargetFinalOutput(const Target* target) {
-  // The contents of this list might be suprising (i.e. stamp tool for copy
+  // The contents of this list might be suprising (i.e. phony tool for copy
   // rules). See the header for why.
   // TODO(crbug.com/gn/39): Don't emit stamp files for single-output targets.
   if (target->source_types_used().RustSourceUsed()) {
@@ -389,8 +389,6 @@
     }
   }
   switch (target->output_type()) {
-    case Target::GROUP:
-      return GeneralTool::kGeneralToolStamp;
     case Target::EXECUTABLE:
       return CTool::kCToolLink;
     case Target::SHARED_LIBRARY:
@@ -399,15 +397,15 @@
       return CTool::kCToolSolinkModule;
     case Target::STATIC_LIBRARY:
       return CTool::kCToolAlink;
-    case Target::SOURCE_SET:
-      return BuiltinTool::kBuiltinToolPhony;
     case Target::ACTION:
     case Target::ACTION_FOREACH:
     case Target::BUNDLE_DATA:
-    case Target::CREATE_BUNDLE:
     case Target::COPY_FILES:
+    case Target::CREATE_BUNDLE:
     case Target::GENERATED_FILE:
-      return GeneralTool::kGeneralToolStamp;
+    case Target::GROUP:
+    case Target::SOURCE_SET:
+      return BuiltinTool::kBuiltinToolPhony;
     default:
       NOTREACHED();
       return kToolNone;
diff --git a/src/gn/toolchain.h b/src/gn/toolchain.h
index 3f2b83a..e4215ea 100644
--- a/src/gn/toolchain.h
+++ b/src/gn/toolchain.h
@@ -100,8 +100,8 @@
 
   // Returns the tool that produces the final output for the given target type.
   // This isn't necessarily the tool you would expect. For copy target, this
-  // will return the stamp tool instead since the final output of a copy
-  // target is to stamp the set of copies done so there is one output.
+  // will return the phony tool instead since the final output of a copy
+  // target is a phony alias to the set of copies done so there is one output.
   const Tool* GetToolForTargetFinalOutput(const Target* target) const;
   const CTool* GetToolForTargetFinalOutputAsC(const Target* target) const;
   const GeneralTool* GetToolForTargetFinalOutputAsGeneral(