GN: Add optional default_args variable to .gn.

Allows a project to specify default overrides for declared arguments.
This is useful for subprojects which might declare arguments with default values
that need to be changed for this project.

BUG=588513

Review-Url: https://codereview.chromium.org/2581193003
Cr-Original-Commit-Position: refs/heads/master@{#445259}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: adbf15668dc1beadf9ee73fe1d7784a5aba207c3
diff --git a/tools/gn/args.cc b/tools/gn/args.cc
index f81ffbe..ceeb46b 100644
--- a/tools/gn/args.cc
+++ b/tools/gn/args.cc
@@ -26,6 +26,9 @@
    - target_cpu
    - target_os
 
+  Next, project-specific overrides are applied. These are specified inside
+  the default_args variable of //.gn. See "gn help dotfile" for more.
+
   If specified, arguments from the --args command line flag are used. If that
   flag is not specified, args from previous builds in the build directory will
   be used (this is in the file args.gn in the build directory).
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index 06062e9..5c4e984 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -106,6 +106,15 @@
 
       The secondary source root must be inside the main source tree.
 
+  default_args [optional]
+      Scope containing the default overrides for declared arguments. These
+      overrides take precedence over the default values specified in the
+      declare_args() block, but can be overriden using --args or the
+      args.gn file.
+
+      This is intended to be used when subprojects declare arguments with
+      default values that need to be changed for whatever reason.
+
 Example .gn file contents
 
   buildconfig = "//build/config/BUILDCONFIG.gn"
@@ -118,6 +127,12 @@
   root = "//:root"
 
   secondary_source = "//build/config/temporary_buildfiles/"
+
+  default_args = {
+    # Default to release builds for this project.
+    is_debug = false
+    is_component_build = false
+  }
 )";
 
 namespace {
@@ -273,6 +288,7 @@
       check_public_headers_(false),
       dotfile_settings_(&build_settings_, std::string()),
       dotfile_scope_(&dotfile_settings_),
+      default_args_(nullptr),
       fill_arguments_(true) {
   dotfile_settings_.set_toolchain_label(Label());
 
@@ -316,6 +332,14 @@
     return false;
   }
 
+  // Apply project-specific default (if specified).
+  // Must happen before FillArguments().
+  if (default_args_) {
+    Scope::KeyValueMap overrides;
+    default_args_->GetCurrentScopeValues(&overrides);
+    build_settings_.build_args().AddArgOverrides(overrides);
+  }
+
   if (fill_arguments_) {
     if (!FillArguments(*cmdline))
       return false;
@@ -754,5 +778,17 @@
     build_settings_.set_exec_script_whitelist(std::move(whitelist));
   }
 
+  // Fill optional default_args.
+  const Value* default_args_value =
+      dotfile_scope_.GetValue("default_args", true);
+  if (default_args_value) {
+    if (!default_args_value->VerifyTypeIs(Value::SCOPE, &err)) {
+      err.PrintToStdout();
+      return false;
+    }
+
+    default_args_ = default_args_value->scope_value();
+  }
+
   return true;
 }
diff --git a/tools/gn/setup.h b/tools/gn/setup.h
index 45335bf..d9a77d0 100644
--- a/tools/gn/setup.h
+++ b/tools/gn/setup.h
@@ -150,6 +150,10 @@
   std::vector<Token> dotfile_tokens_;
   std::unique_ptr<ParseNode> dotfile_root_;
 
+  // Default overrides, specified in the dotfile.
+  // Owned by the Value (if it exists) in the dotfile_scope_.
+  const Scope* default_args_;
+
   // Set to true when we should populate the build arguments from the command
   // line or build argument file. See setter above.
   bool fill_arguments_;