Index: tools/gn/setup.cc |
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc |
index d956c0f94ac0339c45941fa0dce63a40dbdfaf96..cb1effaaab1ea3d883c688daaed9f3881af24a76 100644 |
--- a/tools/gn/setup.cc |
+++ b/tools/gn/setup.cc |
@@ -7,6 +7,7 @@ |
#include <stdlib.h> |
#include <algorithm> |
+#include <sstream> |
#include "base/bind.h" |
#include "base/command_line.h" |
@@ -133,6 +134,8 @@ void DecrementWorkCount() { |
// CommonSetup ----------------------------------------------------------------- |
+const char CommonSetup::kBuildArgFileName[] = "args.gn"; |
+ |
CommonSetup::CommonSetup() |
: build_settings_(), |
loader_(new LoaderImpl(&build_settings_)), |
@@ -215,7 +218,8 @@ bool CommonSetup::RunPostMessageLoop() { |
Setup::Setup() |
: CommonSetup(), |
empty_settings_(&empty_build_settings_, std::string()), |
- dotfile_scope_(&empty_settings_) { |
+ dotfile_scope_(&empty_settings_), |
+ fill_arguments_(true) { |
empty_settings_.set_toolchain_label(Label()); |
build_settings_.set_item_defined_callback( |
base::Bind(&ItemDefinedCallback, scheduler_.main_loop(), builder_)); |
@@ -236,8 +240,8 @@ bool Setup::DoSetup(const std::string& build_dir) { |
cmdline->HasSwitch(kTracelogSwitch)) |
EnableTracing(); |
- if (!FillArguments(*cmdline)) |
- return false; |
+ ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "DoSetup"); |
+ |
if (!FillSourceDir(*cmdline)) |
return false; |
if (!RunConfigFile()) |
@@ -246,6 +250,10 @@ bool Setup::DoSetup(const std::string& build_dir) { |
return false; |
if (!FillBuildDir(build_dir)) // Must be after FillSourceDir to resolve. |
return false; |
+ if (fill_arguments_) { |
+ if (!FillArguments(*cmdline)) |
+ return false; |
+ } |
FillPythonPath(); |
return true; |
@@ -262,14 +270,59 @@ Scheduler* Setup::GetScheduler() { |
return &scheduler_; |
} |
+SourceFile Setup::GetBuildArgFile() const { |
+ return SourceFile(build_settings_.build_dir().value() + kBuildArgFileName); |
+} |
+ |
bool Setup::FillArguments(const CommandLine& cmdline) { |
- std::string args = cmdline.GetSwitchValueASCII(kSwitchArgs); |
- if (args.empty()) |
- return true; // Nothing to set. |
+ // Add a dependency on the build arguments file. If this changes, we want |
+ // to re-generated the build. |
+ g_scheduler->AddGenDependency(build_settings_.GetFullPath(GetBuildArgFile())); |
+ |
+ // 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(kSwitchArgs)) { |
+ if (!FillArgsFromCommandLine(cmdline.GetSwitchValueASCII(kSwitchArgs))) |
+ return false; |
+ SaveArgsToFile(); |
+ return true; |
+ } |
+ |
+ // No command line args given, use the arguments from the build dir (if any). |
+ return FillArgsFromFile(); |
+} |
+bool Setup::FillArgsFromCommandLine(const std::string& args) { |
args_input_file_.reset(new InputFile(SourceFile())); |
args_input_file_->SetContents(args); |
- args_input_file_->set_friendly_name("the command-line \"--args\" settings"); |
+ args_input_file_->set_friendly_name("the command-line \"--args\""); |
+ return FillArgsFromArgsInputFile(); |
+} |
+ |
+bool Setup::FillArgsFromFile() { |
+ ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "Load args file"); |
+ |
+ SourceFile build_arg_source_file = GetBuildArgFile(); |
+ base::FilePath build_arg_file = |
+ build_settings_.GetFullPath(build_arg_source_file); |
+ |
+ std::string contents; |
+ if (!base::ReadFileToString(build_arg_file, &contents)) |
+ return true; // File doesn't exist, continue with default args. |
+ if (contents.empty()) |
+ return true; // Empty file, do nothing. |
+ |
+ args_input_file_.reset(new InputFile(build_arg_source_file)); |
+ args_input_file_->SetContents(contents); |
+ args_input_file_->set_friendly_name( |
+ "build arg file (use \"gn args <out_dir>\" to edit)"); |
+ |
+ setup_trace.Done(); // Only want to count the load as part of the trace. |
+ return FillArgsFromArgsInputFile(); |
+} |
+ |
+bool Setup::FillArgsFromArgsInputFile() { |
+ ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "Parse args"); |
Err err; |
args_tokens_ = Tokenizer::Tokenize(args_input_file_.get(), &err); |
@@ -298,6 +351,42 @@ bool Setup::FillArguments(const CommandLine& cmdline) { |
return true; |
} |
+bool Setup::SaveArgsToFile() { |
+ ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "Save args file"); |
+ |
+ Scope::KeyValueMap args = build_settings_.build_args().GetAllOverrides(); |
+ |
+ std::ostringstream stream; |
+ for (Scope::KeyValueMap::const_iterator i = args.begin(); |
+ i != args.end(); ++i) { |
+ stream << i->first.as_string() << " = " << i->second.ToString(true); |
+ stream << std::endl; |
+ } |
+ |
+ // For the first run, the build output dir might not be created yet, so do |
+ // that so we can write a file into it. Ignore errors, we'll catch the error |
+ // when we try to write a file to it below. |
+ base::FilePath build_arg_file = |
+ build_settings_.GetFullPath(GetBuildArgFile()); |
+ base::CreateDirectory(build_arg_file.DirName()); |
+ |
+ std::string contents = stream.str(); |
+#if defined(OS_WIN) |
+ // Use Windows lineendings for this file since it will often open in |
+ // Notepad which can't handle Unix ones. |
+ ReplaceSubstringsAfterOffset(&contents, 0, "\n", "\r\n"); |
+#endif |
+ if (base::WriteFile(build_arg_file, contents.c_str(), contents.size()) == |
+ -1) { |
+ Err(Location(), "Args file could not be written.", |
+ "The file is \"" + FilePathToUTF8(build_arg_file) + |
+ "\"").PrintToStdout(); |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
bool Setup::FillSourceDir(const CommandLine& cmdline) { |
// Find the .gn file. |
base::FilePath root_path; |
@@ -369,6 +458,8 @@ bool Setup::FillBuildDir(const std::string& build_dir) { |
} |
void Setup::FillPythonPath() { |
+ // Trace this since it tends to be a bit slow on Windows. |
+ ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "Fill Python Path"); |
#if defined(OS_WIN) |
// Find Python on the path so we can use the absolute path in the build. |
const base::char16 kGetPython[] = |