set 'no_stamp_files' by default

This sets 'no_stamp_files' by default and update test expectations
to use phony rule instead of stamp.

Bug: 42440099
Change-Id: I14c7463fcdf680c643d55e4329d884f77131cecc
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/17620
Reviewed-by: David Turner <digit@google.com>
Commit-Queue: Takuto Ikuta <tikuta@google.com>
diff --git a/src/gn/build_settings.h b/src/gn/build_settings.h
index dd3bd9c..3d1dbf2 100644
--- a/src/gn/build_settings.h
+++ b/src/gn/build_settings.h
@@ -152,7 +152,7 @@
 
   // See 40045b9 for the reason behind using 1.7.2 as the default version.
   Version ninja_required_version_{1, 7, 2};
-  bool no_stamp_files_ = false;
+  bool no_stamp_files_ = true;
 
   SourceFile build_config_file_;
   SourceFile arg_file_template_path_;
diff --git a/src/gn/ninja_action_target_writer_unittest.cc b/src/gn/ninja_action_target_writer_unittest.cc
index 3f41d97..9b7c76f 100644
--- a/src/gn/ninja_action_target_writer_unittest.cc
+++ b/src/gn/ninja_action_target_writer_unittest.cc
@@ -68,7 +68,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();
 }
@@ -113,7 +113,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());
 }
@@ -154,7 +154,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());
 }
 
@@ -209,10 +209,10 @@
       "  restat = 1\n"
       "\n"
       "build foo.out: __foo_bar___rule | ../../foo/script.py "
-      "../../foo/included.txt ../../foo/source.txt obj/foo/dep.stamp || "
-      "obj/foo/datadep.stamp\n"
+      "../../foo/included.txt ../../foo/source.txt phony/foo/dep || "
+      "phony/foo/datadep\n"
       "\n"
-      "build obj/foo/bar.stamp: stamp foo.out\n";
+      "build phony/foo/bar: phony foo.out\n";
 
   EXPECT_EQ(expected, out.str());
 }
@@ -284,20 +284,20 @@
 #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 || obj/foo/bundle_data_dep.stamp "
-      "obj/foo/datadep.stamp\n"
+      "phony/foo/bar.inputdeps || phony/foo/bundle_data_dep "
+      "phony/foo/datadep\n"
       "  source_name_part = input1\n"
       "build input2.out: __foo_bar___rule ../../foo/input2.txt | "
-      "obj/foo/bar.inputdeps.stamp || obj/foo/bundle_data_dep.stamp "
-      "obj/foo/datadep.stamp\n"
+      "phony/foo/bar.inputdeps || phony/foo/bundle_data_dep "
+      "phony/foo/datadep\n"
       "  source_name_part = input2\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();
 #if defined(OS_WIN)
@@ -351,21 +351,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());
 }
 
@@ -419,7 +419,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());
 }
 
@@ -470,7 +470,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());
 }
 
@@ -511,9 +511,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());
   }
 
@@ -541,9 +541,9 @@
         "\n"
         // Do not have obj/foo/dep.stamp 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());
   }
 }
@@ -602,7 +602,7 @@
         "  include_dirs = -I../../my_inc_dir\n"
         "  cflags = -isysroot=baz\n"
         "\n"
-        "build obj/foo/foo.stamp: stamp foo.out\n";
+        "build phony/foo/foo: phony foo.out\n";
     std::string out_str = out.str();
     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
   }
@@ -649,7 +649,7 @@
 
 build foo.out: __foo_bar___rule | ../../foo/my$ script.py ../../foo/input$ file.txt
 
-build obj/foo/bar.stamp: stamp foo.out
+build phony/foo/bar: phony foo.out
 )";
   EXPECT_EQ(expected, out.str()) << expected << "--" << out.str();
 }
diff --git a/src/gn/ninja_binary_target_writer_unittest.cc b/src/gn/ninja_binary_target_writer_unittest.cc
index f390e88..29dfd33 100644
--- a/src/gn/ninja_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_binary_target_writer_unittest.cc
@@ -49,7 +49,7 @@
       "  source_file_part = input2.cc\n"
       "  source_name_part = input2\n"
       "\n"
-      "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
+      "build phony/foo/bar: phony obj/foo/bar.input1.o "
       "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj\n";
   std::string out_str = out.str();
   EXPECT_EQ(expected, out_str);
@@ -77,10 +77,9 @@
       "target_out_dir = obj/foo\n"
       "target_output_name = bar\n"
       "\n"
-      "\n"
-      "build obj/foo/bar.stamp: stamp\n";
+      "\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str);
+  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
 }
 
 TEST_F(NinjaBinaryTargetWriterTest, NoSourcesStaticLib) {
@@ -148,7 +147,7 @@
         "  source_file_part = source1.cc\n"
         "  source_name_part = source1\n"
         "\n"
-        "build obj/foo/bar.stamp: stamp obj/foo/bar.source1.o\n";
+        "build phony/foo/bar: phony obj/foo/bar.source1.o\n";
     std::string out_str = out.str();
     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
   }
@@ -179,18 +178,18 @@
         "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"
         "  source_file_part = source1.cc\n"
         "  source_name_part = source1\n"
         "build obj/foo/bar.source2.o: cxx ../../foo/source2.cc | "
-        "obj/foo/bar.inputs.stamp\n"
+        "phony/foo/bar.inputs\n"
         "  source_file_part = source2.cc\n"
         "  source_name_part = source2\n"
         "\n"
-        "build obj/foo/bar.stamp: stamp obj/foo/bar.source1.o "
+        "build phony/foo/bar: phony obj/foo/bar.source1.o "
         "obj/foo/bar.source2.o\n";
     std::string out_str = out.str();
     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
diff --git a/src/gn/ninja_build_writer_unittest.cc b/src/gn/ninja_build_writer_unittest.cc
index f46cd5f..493ba40 100644
--- a/src/gn/ninja_build_writer_unittest.cc
+++ b/src/gn/ninja_build_writer_unittest.cc
@@ -158,16 +158,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_unittest.cc b/src/gn/ninja_bundle_data_target_writer_unittest.cc
index 6fa4fe1..9f90245 100644
--- a/src/gn/ninja_bundle_data_target_writer_unittest.cc
+++ b/src/gn/ninja_bundle_data_target_writer_unittest.cc
@@ -46,7 +46,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_unittest.cc b/src/gn/ninja_c_binary_target_writer_unittest.cc
index 0316eb3..8d2a388 100644
--- a/src/gn/ninja_c_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_c_binary_target_writer_unittest.cc
@@ -61,7 +61,7 @@
         "  source_file_part = input2.cc\n"
         "  source_name_part = input2\n"
         "\n"
-        "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
+        "build phony/foo/bar: phony obj/foo/bar.input1.o "
         "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj\n";
     std::string out_str = out.str();
     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
@@ -93,7 +93,7 @@
         // order.
         "build ./libshlib.so: solink obj/foo/bar.input1.o "
         "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj "
-        "|| obj/foo/bar.stamp\n"
+        "|| phony/foo/bar\n"
         "  ldflags =\n"
         "  libs =\n"
         "  frameworks =\n"
@@ -127,7 +127,7 @@
         "\n"
         // There are no sources so there are no params to alink. (In practice
         // this will probably fail in the archive tool.)
-        "build obj/foo/libstlib.a: alink || obj/foo/bar.stamp\n"
+        "build obj/foo/libstlib.a: alink || phony/foo/bar\n"
         "  arflags =\n"
         "  output_extension =\n"
         "  output_dir =\n";
@@ -156,7 +156,7 @@
         // order.
         "build obj/foo/libstlib.a: alink obj/foo/bar.input1.o "
         "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj "
-        "|| obj/foo/bar.stamp\n"
+        "|| phony/foo/bar\n"
         "  arflags =\n"
         "  output_extension =\n"
         "  output_dir =\n";
@@ -348,11 +348,11 @@
       "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"
       "  source_file_part = input1.cc\n"
       "  source_name_part = input1\n"
       "build obj/foo/libshlib.input2.o: cxx ../../foo/input2.cc"
-      " || obj/foo/action.stamp\n"
+      " || phony/foo/action\n"
       "  source_file_part = input2.cc\n"
       "  source_name_part = input2\n"
       "\n"
@@ -360,7 +360,7 @@
       // 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"
@@ -416,14 +416,14 @@
       "target_output_name = gen_obj\n"
       "\n"
       "build obj/BUILD_DIR/gen_obj.generated.o: cxx generated.cc"
-      " || obj/foo/generate.stamp\n"
+      " || phony/foo/generate\n"
       "  source_file_part = generated.cc\n"
       "  source_name_part = generated\n"
       "\n"
-      "build obj/foo/gen_obj.stamp: stamp obj/BUILD_DIR/gen_obj.generated.o"
+      "build phony/foo/gen_obj: phony obj/BUILD_DIR/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(std::string(obj_expected), obj_str);
@@ -457,7 +457,7 @@
       // The order-only dependency here is strictly unnecessary since
       // obj/out/Debug/gen_obj.generated.o has dependency to
       // obj/foo/gen_obj.stamp
-      " || obj/foo/gen_obj.stamp\n"
+      " || phony/foo/gen_obj\n"
       "  ldflags =\n"
       "  libs =\n"
       "  frameworks =\n"
@@ -563,6 +563,13 @@
   Err err;
   TestWithScope setup;
 
+  // An action for our library to depend on.
+  Target action(setup.settings(), Label(SourceDir("//foo/"), "action"));
+  action.set_output_type(Target::ACTION_FOREACH);
+  action.visibility().SetPublic();
+  action.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(action.OnResolved(&err));
+
   // A config that force linking with the framework.
   Config framework_config(setup.settings(),
                           Label(SourceDir("//bar"), "framework_config"));
@@ -577,6 +584,7 @@
   framework.set_output_type(Target::CREATE_BUNDLE);
   framework.bundle_data().product_type() = "com.apple.product-type.framework";
   framework.public_configs().push_back(LabelConfigPair(&framework_config));
+  framework.private_deps().push_back(LabelTargetPair(&action));
   framework.SetToolchain(setup.toolchain());
   framework.visibility().SetPublic();
   ASSERT_TRUE(framework.OnResolved(&err));
@@ -603,7 +611,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 "
@@ -711,7 +719,7 @@
       "  source_file_part = inter.cc\n"
       "  source_name_part = inter\n"
       "\n"
-      "build obj/foo/inter.stamp: stamp obj/foo/inter.inter.o || "
+      "build phony/foo/inter: phony obj/foo/inter.inter.o || "
       "./data_target\n";
   EXPECT_EQ(inter_expected, inter_out.str());
 
@@ -748,7 +756,7 @@
       "  source_name_part = final\n"
       "\n"
       "build ./exe: link obj/foo/exe.final.o obj/foo/inter.inter.o || "
-      "obj/foo/inter.stamp\n"
+      "phony/foo/inter\n"
       "  ldflags =\n"
       "  libs =\n"
       "  frameworks =\n"
@@ -950,8 +958,8 @@
         "  source_file_part = input2.c\n"
         "  source_name_part = input2\n"
         "\n"
-        "build withpch/obj/foo/no_pch_target.stamp: "
-        "withpch_stamp withpch/obj/foo/no_pch_target.input1.o "
+        "build withpch/phony/foo/no_pch_target: "
+        "phony withpch/obj/foo/no_pch_target.input1.o "
         "withpch/obj/foo/no_pch_target.input2.o\n";
     EXPECT_EQ(no_pch_expected, out.str());
   }
@@ -1012,7 +1020,7 @@
         "  source_file_part = input2.c\n"
         "  source_name_part = input2\n"
         "\n"
-        "build withpch/obj/foo/pch_target.stamp: withpch_stamp "
+        "build withpch/phony/foo/pch_target: phony "
         "withpch/obj/foo/pch_target.input1.o "
         "withpch/obj/foo/pch_target.input2.o "
         // The precompiled object files were added to the outputs.
@@ -1096,8 +1104,8 @@
         "  source_file_part = input2.c\n"
         "  source_name_part = input2\n"
         "\n"
-        "build withpch/obj/foo/no_pch_target.stamp: "
-        "withpch_stamp withpch/obj/foo/no_pch_target.input1.o "
+        "build withpch/phony/foo/no_pch_target: "
+        "phony withpch/obj/foo/no_pch_target.input1.o "
         "withpch/obj/foo/no_pch_target.input2.o\n";
     EXPECT_EQ(no_pch_expected, out.str());
   }
@@ -1156,10 +1164,11 @@
         "  source_file_part = input2.c\n"
         "  source_name_part = input2\n"
         "\n"
-        "build withpch/obj/foo/pch_target.stamp: "
-        "withpch_stamp withpch/obj/foo/pch_target.input1.o "
+        "build withpch/phony/foo/pch_target: "
+        "phony withpch/obj/foo/pch_target.input1.o "
         "withpch/obj/foo/pch_target.input2.o\n";
-    EXPECT_EQ(pch_gcc_expected, out.str());
+    EXPECT_EQ(pch_gcc_expected, out.str()) << pch_gcc_expected << "\n"
+                                           << out.str();
   }
 }
 
@@ -1227,7 +1236,7 @@
         "  source_file_part = input2.cc\n"
         "  source_name_part = input2\n"
         "\n"
-        "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
+        "build phony/foo/bar: phony obj/foo/bar.input1.o "
         "obj/foo/bar.input2.o\n";
 
     EXPECT_EQ(expected, out.str());
@@ -1293,18 +1302,18 @@
         "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"
         "  source_file_part = input1.cc\n"
         "  source_name_part = input1\n"
         "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc"
-        " | obj/foo/bar.inputs.stamp\n"
+        " | phony/foo/bar.inputs\n"
         "  source_file_part = input2.cc\n"
         "  source_name_part = input2\n"
         "\n"
-        "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
+        "build phony/foo/bar: phony obj/foo/bar.input1.o "
         "obj/foo/bar.input2.o\n";
 
     EXPECT_EQ(expected, out.str());
@@ -1348,18 +1357,18 @@
         "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"
         "  source_file_part = input1.cc\n"
         "  source_name_part = input1\n"
         "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc"
-        " | obj/foo/bar.inputs.stamp\n"
+        " | phony/foo/bar.inputs\n"
         "  source_file_part = input2.cc\n"
         "  source_name_part = input2\n"
         "\n"
-        "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
+        "build phony/foo/bar: phony obj/foo/bar.input1.o "
         "obj/foo/bar.input2.o\n";
 
     EXPECT_EQ(expected, out.str());
@@ -1593,8 +1602,8 @@
       "obj/dylib/libdylib.so | "
       "obj/pub_in_staticlib/libpub_in_staticlib.rlib "
       "obj/priv_in_staticlib/libpriv_in_staticlib.rlib || "
-      "obj/pub_sset_in_staticlib/pub_sset_in_staticlib.stamp "
-      "obj/priv_sset_in_staticlib/priv_sset_in_staticlib.stamp\n"
+      "phony/pub_sset_in_staticlib/pub_sset_in_staticlib "
+      "phony/priv_sset_in_staticlib/priv_sset_in_staticlib\n"
       "  ldflags =\n"
       "  libs =\n"
       "  frameworks =\n"
@@ -2335,7 +2344,7 @@
         "obj/foo/file2.o: swift ../../foo/file1.swift ../../foo/file2.swift\n"
         "  restat = 1\n"
         "\n"
-        "build obj/foo/foo.stamp: stamp"
+        "build phony/foo/foo: phony"
         " gen/foo/foo.h obj/foo/Foo.swiftmodule"
         " obj/foo/file1.o obj/foo/file2.o\n";
 
@@ -2370,12 +2379,12 @@
         "target_output_name = bar\n"
         "\n"
         "build gen/bar/bar.h obj/bar/Bar.swiftmodule obj/bar/bar.o: swift "
-        "../../bar/bar.swift || obj/foo/foo.stamp\n"
+        "../../bar/bar.swift || phony/foo/foo\n"
         "  restat = 1\n"
         "\n"
-        "build obj/bar/bar.stamp: stamp"
+        "build phony/bar/bar: phony"
         " gen/bar/bar.h obj/bar/Bar.swiftmodule obj/bar/bar.o "
-        "|| obj/foo/foo.stamp\n";
+        "|| phony/foo/foo\n";
 
     const std::string out_str = out.str();
     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
@@ -2416,12 +2425,12 @@
         "target_output_name = bar\n"
         "\n"
         "build gen/bar/bar.h obj/bar/Bar.swiftmodule obj/bar/bar.o: swift "
-        "../../bar/bar.swift || obj/bar/group.stamp obj/foo/foo.stamp\n"
+        "../../bar/bar.swift || phony/bar/group phony/foo/foo\n"
         "  restat = 1\n"
         "\n"
-        "build obj/bar/bar.stamp: stamp"
+        "build phony/bar/bar: phony"
         " gen/bar/bar.h obj/bar/Bar.swiftmodule obj/bar/bar.o "
-        "|| obj/bar/group.stamp obj/foo/foo.stamp\n";
+        "|| phony/bar/group phony/foo/foo\n";
 
     const std::string out_str = out.str();
     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
@@ -2451,7 +2460,7 @@
         "\n"
         "build ./bar: link obj/foo/file1.o obj/foo/file2.o "
         "| obj/foo/Foo.swiftmodule "
-        "|| obj/foo/foo.stamp\n"
+        "|| phony/foo/foo\n"
         "  ldflags =\n"
         "  libs =\n"
         "  frameworks =\n"
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_unittest.cc b/src/gn/ninja_create_bundle_target_writer_unittest.cc
index 8540671..d79b719 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,12 +165,12 @@
   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);
+  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
 }
 
 // Tests multiple files from asset catalog.
@@ -229,17 +229,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);
 }
@@ -250,13 +250,22 @@
   Err err;
   TestWithScope setup;
 
+  // An action for our library to depend on.
+  Target action(setup.settings(), Label(SourceDir("//foo/"), "action"));
+  action.set_output_type(Target::ACTION_FOREACH);
+  action.visibility().SetPublic();
+  action.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(action.OnResolved(&err));
+
   Target create_bundle(
       setup.settings(),
       Label(SourceDir("//baz/"), "bar", setup.toolchain()->label().dir(),
             setup.toolchain()->label().name()));
   SetupBundleDataDir(&create_bundle.bundle_data(), "//out/Debug");
   create_bundle.set_output_type(Target::CREATE_BUNDLE);
+  create_bundle.private_deps().push_back(LabelTargetPair(&action));
   create_bundle.SetToolchain(setup.toolchain());
+
   ASSERT_TRUE(create_bundle.OnResolved(&err));
 
   std::ostringstream out;
@@ -264,10 +273,10 @@
   writer.Run();
 
   const char expected[] =
-      "build obj/baz/bar.stamp: stamp\n"
-      "build bar.bundle: phony obj/baz/bar.stamp\n";
+      "build phony/baz/bar: phony || phony/foo/action\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) << expected << "\n" << out_str;
 }
 
 // Tests complex target with multiple bundle_data sources, including
@@ -384,34 +393,34 @@
   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);
+  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
 }
 
 // Tests post-processing step.
@@ -466,32 +475,32 @@
   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__post_processing_rule\n"
       "  command =  ../../build/codesign.py -b=quz bar.bundle\n"
       "  description = POST PROCESSING //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.postprocessing.inputdeps.stamp: stamp "
+      "../../foo/input2.txt || phony/baz/bar.inputdeps\n"
+      "build phony/baz/bar.postprocessing.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__post_processing_rule "
-      "| obj/baz/bar.postprocessing.inputdeps.stamp\n"
-      "build obj/baz/bar.stamp: stamp "
+      "| phony/baz/bar.postprocessing.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);
+  EXPECT_EQ(expected, out_str) << out_str << "\n" << expected;
 }
 
 TEST(NinjaCreateBundleTargetWriter, PostProcessingNoStampFilesCustomToolchain) {
diff --git a/src/gn/ninja_generated_file_target_writer_unittest.cc b/src/gn/ninja_generated_file_target_writer_unittest.cc
index f883102..481db80 100644
--- a/src/gn/ninja_generated_file_target_writer_unittest.cc
+++ b/src/gn/ninja_generated_file_target_writer_unittest.cc
@@ -63,8 +63,8 @@
   writer.Run();
 
   const char expected[] =
-      "build obj/foo/bar.stamp: stamp foo.json obj/foo/dep.stamp "
-      "obj/foo/dep2.stamp || "
-      "obj/foo/bundle_data_dep.stamp obj/foo/datadep.stamp\n";
+      "build phony/foo/bar: phony foo.json phony/foo/dep "
+      "phony/foo/dep2 || "
+      "phony/foo/bundle_data_dep phony/foo/datadep\n";
   EXPECT_EQ(expected, out.str());
 }
diff --git a/src/gn/ninja_group_target_writer_unittest.cc b/src/gn/ninja_group_target_writer_unittest.cc
index 1fe51ca..ec9f72d 100644
--- a/src/gn/ninja_group_target_writer_unittest.cc
+++ b/src/gn/ninja_group_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/bundle_data_dep.stamp obj/foo/datadep.stamp\n";
+      "build phony/foo/bar: phony phony/foo/dep phony/foo/dep2 || "
+      "phony/foo/bundle_data_dep phony/foo/datadep\n";
   EXPECT_EQ(expected, out.str());
 }
diff --git a/src/gn/ninja_outputs_writer_unittest.cc b/src/gn/ninja_outputs_writer_unittest.cc
index 52354c6..a5f8a67 100644
--- a/src/gn/ninja_outputs_writer_unittest.cc
+++ b/src/gn/ninja_outputs_writer_unittest.cc
@@ -36,8 +36,6 @@
   std::string rule = NinjaTargetWriter::RunAndWriteFile(target, nullptr,
                                                         &target_ninja_outputs);
 
-  DCHECK(!rule.empty());
-
   std::lock_guard<std::mutex> lock(write_info->lock);
   write_info->ninja_outputs_map.emplace(target,
                                         std::move(target_ninja_outputs));
@@ -142,18 +140,16 @@
   std::string expected = R"##({
   "//:bar": [
     "bar.output",
-    "obj/bar.stamp"
+    "phony/bar"
   ],
   "//:foo": [
-    "obj/foo.stamp"
+    "phony/foo"
   ],
   "//:zoo": [
-    "obj/zoo.stamp"
   ],
   "//:zoo(//toolchain:secondary)": [
-    "secondary/obj/zoo.stamp"
   ]
 })##";
 
-  EXPECT_EQ(generated, expected);
+  EXPECT_EQ(generated, expected) << generated << "\n" << expected;
 }
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc
index 65be062..461cbd8 100644
--- a/src/gn/ninja_rust_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -5,6 +5,7 @@
 #include "gn/ninja_rust_binary_target_writer.h"
 
 #include "gn/config.h"
+#include "gn/label_ptr.h"
 #include "gn/pool.h"
 #include "gn/rust_values.h"
 #include "gn/scheduler.h"
@@ -584,7 +585,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"
         "  source_file_part = lib.rs\n"
         "  source_name_part = lib\n"
         "  externs = --extern mymacro=obj/bar/libmymacro.so\n"
@@ -824,7 +825,7 @@
         "../../foo/main.rs obj/baz/sourceset.csourceset.o "
         "obj/bar/libmylib.rlib "
         "obj/foo/libstatic.a ./libshared.so ./libshared_with_toc.so.TOC "
-        "|| obj/baz/sourceset.stamp\n"
+        "|| phony/baz/sourceset\n"
         "  source_file_part = main.rs\n"
         "  source_name_part = main\n"
         "  externs = --extern mylib=obj/bar/libmylib.rlib\n"
@@ -1089,8 +1090,8 @@
       "obj/pub_in_staticlib/libpub_in_staticlib.rlib "
       "obj/priv_in_staticlib/libpriv_in_staticlib.rlib "
       "obj/pub_in_dylib/libpub_in_dylib.rlib || "
-      "obj/pub_sset_in_staticlib/pub_sset_in_staticlib.stamp "
-      "obj/priv_sset_in_staticlib/priv_sset_in_staticlib.stamp\n"
+      "phony/pub_sset_in_staticlib/pub_sset_in_staticlib "
+      "phony/priv_sset_in_staticlib/priv_sset_in_staticlib\n"
       "  source_file_part = main.rs\n"
       "  source_name_part = main\n"
       "  externs = "
@@ -1541,7 +1542,7 @@
         "\n"
         "build ./foo_bar: rust_bin ../../foo/main.rs | "
         "../../foo/source.rs ../../foo/main.rs obj/bar/libmylib.rlib || "
-        "obj/baz/group.stamp\n"
+        "phony/baz/group\n"
         "  source_file_part = main.rs\n"
         "  source_name_part = main\n"
         "  externs = --extern mylib=obj/bar/libmylib.rlib\n"
@@ -1632,7 +1633,7 @@
     writer.Run();
 
     const char expected[] =
-        "build obj/foo/bar.inputs.stamp: stamp ../../foo/config.json "
+        "build phony/foo/bar.inputs: phony ../../foo/config.json "
         "../../foo/template.h\n"
         "crate_name = foo_bar\n"
         "crate_type = bin\n"
@@ -1647,7 +1648,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"
         "  source_file_part = main.rs\n"
         "  source_name_part = main\n"
         "  externs =\n"
@@ -1895,7 +1896,7 @@
         "\n"
         "build ./exe: rust_bin ../../linked/exe.rs | ../../linked/exe.rs "
         "obj/sset/bar.input1.o obj/public/libbehind_sourceset_public.rlib "
-        "obj/private/libbehind_sourceset_private.rlib || obj/sset/bar.stamp\n"
+        "obj/private/libbehind_sourceset_private.rlib || phony/sset/bar\n"
         "  source_file_part = exe.rs\n"
         "  source_name_part = exe\n"
         "  externs = --extern "
@@ -1964,6 +1965,13 @@
   Err err;
   TestWithScope setup;
 
+  // An action for our library to depend on.
+  Target action(setup.settings(), Label(SourceDir("//bar"), "action"));
+  action.set_output_type(Target::ACTION_FOREACH);
+  action.visibility().SetPublic();
+  action.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(action.OnResolved(&err));
+
   // A config that force linking with the framework.
   Config framework_config(setup.settings(),
                           Label(SourceDir("//bar"), "framework_config"));
@@ -1978,6 +1986,7 @@
   framework.set_output_type(Target::CREATE_BUNDLE);
   framework.bundle_data().product_type() = "com.apple.product-type.framework";
   framework.public_configs().push_back(LabelConfigPair(&framework_config));
+  framework.private_deps().push_back(LabelTargetPair(&action));
   framework.SetToolchain(setup.toolchain());
   framework.visibility().SetPublic();
   ASSERT_TRUE(framework.OnResolved(&err));
@@ -2013,7 +2022,7 @@
       "target_output_name = exe\n"
       "\n"
       "build ./exe: rust_bin ../../linked/exe.rs | ../../linked/exe.rs || "
-      "obj/bar/framework.stamp obj/bar/framework.stamp\n"
+      "phony/bar/framework\n"
       "  source_file_part = exe.rs\n"
       "  source_name_part = exe\n"
       "  externs =\n"
@@ -2072,7 +2081,7 @@
       "\n"
       "build ./exe: rust_bin ../../linked/exe.rs | ../../linked/exe.rs "
       "obj/foo/file1.o obj/foo/file2.o || "
-      "obj/foo/foo.stamp obj/foo/Foo.swiftmodule obj/foo/foo.stamp\n"
+      "phony/foo/foo obj/foo/Foo.swiftmodule phony/foo/foo\n"
       "  source_file_part = exe.rs\n"
       "  source_name_part = exe\n"
       "  externs =\n"
diff --git a/src/gn/ninja_target_writer_unittest.cc b/src/gn/ninja_target_writer_unittest.cc
index 6b88674..ae691d7 100644
--- a/src/gn/ninja_target_writer_unittest.cc
+++ b/src/gn/ninja_target_writer_unittest.cc
@@ -133,6 +133,103 @@
     // Since there is only one dependency, a stamp file will be returned
     // directly without writing any additional rules.
     ASSERT_EQ(1u, dep.size());
+    EXPECT_EQ("phony/foo/base", dep[0].value());
+  }
+
+  {
+    std::ostringstream stream;
+    NinjaActionTargetWriter writer(&action, stream);
+    writer.Run();
+    EXPECT_EQ(
+        "rule __foo_action___rule\n"
+        "  command =  ../../foo/script.py\n"
+        "  description = ACTION //foo:action()\n"
+        "  restat = 1\n"
+        "\n"
+        "build: __foo_action___rule | ../../foo/script.py"
+        " ../../foo/action_source.txt ./target\n"
+        "\n"
+        "build phony/foo/action: phony\n",
+        stream.str());
+  }
+
+  // Input deps for action which should depend on the base since its a hard dep
+  // that is a (indirect) dependency, as well as the the action source.
+  {
+    std::ostringstream stream;
+    TestingNinjaTargetWriter writer(&action, setup.toolchain(), stream);
+    std::vector<OutputFile> dep = writer.WriteInputDepsStampOrPhonyAndGetDep(
+        std::vector<const Target*>(), 10u);
+
+    ASSERT_EQ(1u, dep.size());
+    EXPECT_EQ("phony/foo/action.inputdeps", dep[0].value());
+    EXPECT_EQ(
+        "build phony/foo/action.inputdeps: phony ../../foo/script.py "
+        "../../foo/action_source.txt ./target\n",
+        stream.str());
+  }
+}
+
+TEST(NinjaTargetWriter, WriteInputDepsStampOrPhonyAndGetDepUseStampFiles) {
+  TestWithScope setup;
+  Err err;
+  setup.build_settings()->set_no_stamp_files(false);
+
+  // Make a base target that's a hard dep (action).
+  Target base_target(setup.settings(), Label(SourceDir("//foo/"), "base"));
+  base_target.set_output_type(Target::ACTION);
+  base_target.visibility().SetPublic();
+  base_target.SetToolchain(setup.toolchain());
+  base_target.action_values().set_script(SourceFile("//foo/script.py"));
+
+  // Dependent target that also includes a source prerequisite (should get
+  // included) and a source (should not be included).
+  Target target(setup.settings(), Label(SourceDir("//foo/"), "target"));
+  target.set_output_type(Target::EXECUTABLE);
+  target.visibility().SetPublic();
+  target.SetToolchain(setup.toolchain());
+  target.config_values().inputs().push_back(SourceFile("//foo/input.txt"));
+  target.sources().push_back(SourceFile("//foo/source.txt"));
+  target.public_deps().push_back(LabelTargetPair(&base_target));
+
+  // Dependent action to test that action sources will be treated the same as
+  // inputs.
+  Target action(setup.settings(), Label(SourceDir("//foo/"), "action"));
+  action.set_output_type(Target::ACTION);
+  action.visibility().SetPublic();
+  action.SetToolchain(setup.toolchain());
+  action.action_values().set_script(SourceFile("//foo/script.py"));
+  action.sources().push_back(SourceFile("//foo/action_source.txt"));
+  action.public_deps().push_back(LabelTargetPair(&target));
+
+  ASSERT_TRUE(base_target.OnResolved(&err));
+  ASSERT_TRUE(target.OnResolved(&err));
+  ASSERT_TRUE(action.OnResolved(&err));
+
+  // Input deps for the base (should be only the script itself).
+  {
+    std::ostringstream stream;
+    TestingNinjaTargetWriter writer(&base_target, setup.toolchain(), stream);
+    std::vector<OutputFile> dep = writer.WriteInputDepsStampOrPhonyAndGetDep(
+        std::vector<const Target*>(), 10u);
+
+    // Since there is only one dependency, it should just be returned and
+    // nothing written to the stream.
+    ASSERT_EQ(1u, dep.size());
+    EXPECT_EQ("../../foo/script.py", dep[0].value());
+    EXPECT_EQ("", stream.str());
+  }
+
+  // Input deps for the target (should depend on the base).
+  {
+    std::ostringstream stream;
+    TestingNinjaTargetWriter writer(&target, setup.toolchain(), stream);
+    std::vector<OutputFile> dep = writer.WriteInputDepsStampOrPhonyAndGetDep(
+        std::vector<const Target*>(), 10u);
+
+    // Since there is only one dependency, a stamp file will be returned
+    // directly without writing any additional rules.
+    ASSERT_EQ(1u, dep.size());
     EXPECT_EQ("obj/foo/base.stamp", dep[0].value());
   }
 
@@ -200,6 +297,6 @@
   // 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.
   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/target_unittest.cc b/src/gn/target_unittest.cc
index cac3670..ebe40be 100644
--- a/src/gn/target_unittest.cc
+++ b/src/gn/target_unittest.cc
@@ -742,7 +742,7 @@
   EXPECT_TRUE(target.GetOutputsAsSourceFiles(LocationRange(), true,
                                              &computed_outputs, &err));
   ASSERT_EQ(1u, computed_outputs.size());
-  EXPECT_EQ("//out/Debug/obj/a/a.stamp", computed_outputs[0].value());
+  EXPECT_EQ("//out/Debug/phony/a/a", computed_outputs[0].value());
 }
 
 TEST_F(TargetTest, CheckStampFileName) {
@@ -770,9 +770,7 @@
   std::vector<SourceFile> computed_outputs;
   EXPECT_TRUE(target.GetOutputsAsSourceFiles(LocationRange(), true,
                                              &computed_outputs, &err));
-  ASSERT_EQ(1u, computed_outputs.size());
-  EXPECT_EQ("//out/Debug/obj/a/a.stamp", computed_outputs[0].value())
-      << "was instead: " << computed_outputs[0].value();
+  ASSERT_EQ(0u, computed_outputs.size()) << computed_outputs.size();
 }
 
 // Tests Target::GetOutputFilesForSource for action_foreach targets (these, like