Specify deps format for actions

Setting deps format is necessary for Ninja to store the depfile in its
internal dependency database. This can significantly speed up loading
for large dependency files, which can be the case for custom language
support, e.g. Go or Dart in Fuchsia, where we emit large depfiles from
actions. This also enables the use of `ninja -t deps` tool for custom
actions.

We hardcode the format to gcc since the documentation for depfile
already explicitly specifies that "format is that of a Makefile".

Change-Id: I67dfdfe4ede8fe8d4a2a1fa3ee2cecb7c185aafd
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/8722
Commit-Queue: Petr Hosek <phosek@google.com>
Reviewed-by: Brett Wilson <brettw@chromium.org>
diff --git a/src/gn/ninja_action_target_writer.cc b/src/gn/ninja_action_target_writer.cc
index bb78254..28f28c7 100644
--- a/src/gn/ninja_action_target_writer.cc
+++ b/src/gn/ninja_action_target_writer.cc
@@ -72,9 +72,7 @@
     }
     out_ << std::endl;
     if (target_->action_values().has_depfile()) {
-      out_ << "  depfile = ";
       WriteDepfile(SourceFile());
-      out_ << std::endl;
     }
     if (target_->action_values().pool().ptr) {
       out_ << "  pool = ";
@@ -203,9 +201,7 @@
         args_escape_options, out_);
 
     if (target_->action_values().has_depfile()) {
-      out_ << "  depfile = ";
       WriteDepfile(sources[i]);
-      out_ << std::endl;
     }
     if (target_->action_values().pool().ptr) {
       out_ << "  pool = ";
@@ -232,8 +228,18 @@
 }
 
 void NinjaActionTargetWriter::WriteDepfile(const SourceFile& source) {
+  out_ << "  depfile = ";
   path_output_.WriteFile(
       out_,
       SubstitutionWriter::ApplyPatternToSourceAsOutputFile(
           target_, settings_, target_->action_values().depfile(), source));
+  out_ << std::endl;
+  // Using "deps = gcc" allows Ninja to read and store the depfile content in
+  // its internal database which improves performance, especially for large
+  // depfiles. The use of this feature with depfiles that contain multiple
+  // outputs require Ninja version 1.9.0 or newer.
+  if (settings_->build_settings()->ninja_required_version() >=
+      Version{1, 9, 0}) {
+    out_ << "  deps = gcc" << std::endl;
+  }
 }
diff --git a/src/gn/ninja_action_target_writer_unittest.cc b/src/gn/ninja_action_target_writer_unittest.cc
index d217ab2..eb03df1 100644
--- a/src/gn/ninja_action_target_writer_unittest.cc
+++ b/src/gn/ninja_action_target_writer_unittest.cc
@@ -264,6 +264,7 @@
 
   setup.build_settings()->set_python_path(
       base::FilePath(FILE_PATH_LITERAL("/usr/bin/python")));
+  setup.build_settings()->set_ninja_required_version(Version{1, 9, 0});
 
   std::ostringstream out;
   NinjaActionTargetWriter writer(&target, out);
@@ -286,10 +287,12 @@
       " | obj/foo/bar.inputdeps.stamp\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"
       "  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";
   EXPECT_EQ(expected_linux, out.str());