[gn] Always create "args.gn" file when running gn gen.

After this patch, when running `gn gen out-dir` with no --args,
gn will create an empty args.gn file if it does not exists.

Bug: crbug.com/gn/53
Change-Id: I84ee860180c642899bfd4adcbe39e9019609b4bd
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/4380
Commit-Queue: Haowei Wu <haowei@google.com>
Reviewed-by: Scott Graham <scottmg@chromium.org>
diff --git a/tools/gn/command_gen.cc b/tools/gn/command_gen.cc
index a8033ab..46d8b89 100644
--- a/tools/gn/command_gen.cc
+++ b/tools/gn/command_gen.cc
@@ -441,6 +441,10 @@
 
   // Deliberately leaked to avoid expensive process teardown.
   Setup* setup = new Setup();
+  // Generate an empty args.gn file if it does not exists
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kArgs)) {
+    setup->set_gen_empty_args(true);
+  }
   if (!setup->DoSetup(args[0], true))
     return 1;
 
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index 7b336a6..e461e26 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -149,6 +149,7 @@
 namespace {
 
 const base::FilePath::CharType kGnFile[] = FILE_PATH_LITERAL(".gn");
+const char kDefaultArgsGn[] = "# Set build arguments here. See `gn buildargs`.";
 
 base::FilePath FindDotFile(const base::FilePath& current_dir) {
   base::FilePath try_this_file = current_dir.Append(kGnFile);
@@ -300,7 +301,8 @@
       dotfile_settings_(&build_settings_, std::string()),
       dotfile_scope_(&dotfile_settings_),
       default_args_(nullptr),
-      fill_arguments_(true) {
+      fill_arguments_(true),
+      gen_empty_args_(false) {
   dotfile_settings_.set_toolchain_label(Label());
 
   build_settings_.set_item_defined_callback(
@@ -435,9 +437,18 @@
 bool Setup::FillArguments(const base::CommandLine& cmdline) {
   // Use the args on the command line if specified, and save them. Do this even
   // if the list is empty (this means clear any defaults).
-  if (cmdline.HasSwitch(switches::kArgs)) {
-    if (!FillArgsFromCommandLine(cmdline.GetSwitchValueASCII(switches::kArgs)))
+  // If --args is not set, args.gn file does not exist and gen_empty_args
+  // is set, generate an empty args.gn file with default comments.
+
+  base::FilePath build_arg_file =
+      build_settings_.GetFullPath(GetBuildArgFile());
+  auto switch_value = cmdline.GetSwitchValueASCII(switches::kArgs);
+  if (cmdline.HasSwitch(switches::kArgs) ||
+      (gen_empty_args_ && !PathExists(build_arg_file))) {
+    if (!FillArgsFromCommandLine(switch_value.empty() ? kDefaultArgsGn
+                                                    : switch_value)) {
       return false;
+    }
     SaveArgsToFile();
     return true;
   }
diff --git a/tools/gn/setup.h b/tools/gn/setup.h
index cca30ab..cf0136a 100644
--- a/tools/gn/setup.h
+++ b/tools/gn/setup.h
@@ -84,6 +84,10 @@
   // headers to be checked. Defaults to false.
   void set_check_public_headers(bool s) { check_public_headers_ = s; }
 
+  // Before DoSetup, setting this will generate an empty args.gn if
+  // it does not exist and set up correct dependencies for it.
+  void set_gen_empty_args(bool ge) { gen_empty_args_ = ge; }
+
   // Read from the .gn file, these are the targets to check. If the .gn file
   // does not specify anything, this will be null. If the .gn file specifies
   // the empty list, this will be non-null but empty.
@@ -170,6 +174,9 @@
   // line or build argument file. See setter above.
   bool fill_arguments_;
 
+  // Generate an empty args.gn file if it does not exists.
+  bool gen_empty_args_;
+
   // State for invoking the command line args. We specifically want to keep
   // this around for the entire run so that Values can blame to the command
   // line when we issue errors about them.