OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/gn/setup.h" | 5 #include "tools/gn/setup.h" |
6 | 6 |
7 #include <stdlib.h> | 7 #include <stdlib.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <sstream> |
10 | 11 |
11 #include "base/bind.h" | 12 #include "base/bind.h" |
12 #include "base/command_line.h" | 13 #include "base/command_line.h" |
13 #include "base/file_util.h" | 14 #include "base/file_util.h" |
14 #include "base/files/file_path.h" | 15 #include "base/files/file_path.h" |
15 #include "base/process/launch.h" | 16 #include "base/process/launch.h" |
16 #include "base/strings/string_split.h" | 17 #include "base/strings/string_split.h" |
17 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
18 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
19 #include "build/build_config.h" | 20 #include "build/build_config.h" |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 } | 127 } |
127 | 128 |
128 void DecrementWorkCount() { | 129 void DecrementWorkCount() { |
129 g_scheduler->DecrementWorkCount(); | 130 g_scheduler->DecrementWorkCount(); |
130 } | 131 } |
131 | 132 |
132 } // namespace | 133 } // namespace |
133 | 134 |
134 // CommonSetup ----------------------------------------------------------------- | 135 // CommonSetup ----------------------------------------------------------------- |
135 | 136 |
| 137 const char CommonSetup::kBuildArgFileName[] = "gn.args"; |
| 138 |
136 CommonSetup::CommonSetup() | 139 CommonSetup::CommonSetup() |
137 : build_settings_(), | 140 : build_settings_(), |
138 loader_(new LoaderImpl(&build_settings_)), | 141 loader_(new LoaderImpl(&build_settings_)), |
139 builder_(new Builder(loader_.get())), | 142 builder_(new Builder(loader_.get())), |
140 root_build_file_("//BUILD.gn"), | 143 root_build_file_("//BUILD.gn"), |
141 check_for_bad_items_(true), | 144 check_for_bad_items_(true), |
142 check_for_unused_overrides_(true), | 145 check_for_unused_overrides_(true), |
143 check_public_headers_(false) { | 146 check_public_headers_(false) { |
144 loader_->set_complete_callback(base::Bind(&DecrementWorkCount)); | 147 loader_->set_complete_callback(base::Bind(&DecrementWorkCount)); |
145 } | 148 } |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 SaveTraces(cmdline->GetSwitchValuePath(kTracelogSwitch)); | 211 SaveTraces(cmdline->GetSwitchValuePath(kTracelogSwitch)); |
209 | 212 |
210 return true; | 213 return true; |
211 } | 214 } |
212 | 215 |
213 // Setup ----------------------------------------------------------------------- | 216 // Setup ----------------------------------------------------------------------- |
214 | 217 |
215 Setup::Setup() | 218 Setup::Setup() |
216 : CommonSetup(), | 219 : CommonSetup(), |
217 empty_settings_(&empty_build_settings_, std::string()), | 220 empty_settings_(&empty_build_settings_, std::string()), |
218 dotfile_scope_(&empty_settings_) { | 221 dotfile_scope_(&empty_settings_), |
| 222 fill_arguments_(true) { |
219 empty_settings_.set_toolchain_label(Label()); | 223 empty_settings_.set_toolchain_label(Label()); |
220 build_settings_.set_item_defined_callback( | 224 build_settings_.set_item_defined_callback( |
221 base::Bind(&ItemDefinedCallback, scheduler_.main_loop(), builder_)); | 225 base::Bind(&ItemDefinedCallback, scheduler_.main_loop(), builder_)); |
222 | 226 |
223 // The scheduler's main loop wasn't created when the Loader was created, so | 227 // The scheduler's main loop wasn't created when the Loader was created, so |
224 // we need to set it now. | 228 // we need to set it now. |
225 loader_->set_main_loop(scheduler_.main_loop()); | 229 loader_->set_main_loop(scheduler_.main_loop()); |
226 } | 230 } |
227 | 231 |
228 Setup::~Setup() { | 232 Setup::~Setup() { |
229 } | 233 } |
230 | 234 |
231 bool Setup::DoSetup(const std::string& build_dir) { | 235 bool Setup::DoSetup(const std::string& build_dir) { |
232 CommandLine* cmdline = CommandLine::ForCurrentProcess(); | 236 CommandLine* cmdline = CommandLine::ForCurrentProcess(); |
233 | 237 |
234 scheduler_.set_verbose_logging(cmdline->HasSwitch(kSwitchVerbose)); | 238 scheduler_.set_verbose_logging(cmdline->HasSwitch(kSwitchVerbose)); |
235 if (cmdline->HasSwitch(kTimeSwitch) || | 239 if (cmdline->HasSwitch(kTimeSwitch) || |
236 cmdline->HasSwitch(kTracelogSwitch)) | 240 cmdline->HasSwitch(kTracelogSwitch)) |
237 EnableTracing(); | 241 EnableTracing(); |
238 | 242 |
239 if (!FillArguments(*cmdline)) | 243 ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "DoSetup"); |
240 return false; | 244 |
241 if (!FillSourceDir(*cmdline)) | 245 if (!FillSourceDir(*cmdline)) |
242 return false; | 246 return false; |
243 if (!RunConfigFile()) | 247 if (!RunConfigFile()) |
244 return false; | 248 return false; |
245 if (!FillOtherConfig(*cmdline)) | 249 if (!FillOtherConfig(*cmdline)) |
246 return false; | 250 return false; |
247 if (!FillBuildDir(build_dir)) // Must be after FillSourceDir to resolve. | 251 if (!FillBuildDir(build_dir)) // Must be after FillSourceDir to resolve. |
248 return false; | 252 return false; |
| 253 if (fill_arguments_) { |
| 254 if (!FillArguments(*cmdline)) |
| 255 return false; |
| 256 } |
249 FillPythonPath(); | 257 FillPythonPath(); |
250 | 258 |
251 return true; | 259 return true; |
252 } | 260 } |
253 | 261 |
254 bool Setup::Run() { | 262 bool Setup::Run() { |
255 RunPreMessageLoop(); | 263 RunPreMessageLoop(); |
256 if (!scheduler_.Run()) | 264 if (!scheduler_.Run()) |
257 return false; | 265 return false; |
258 return RunPostMessageLoop(); | 266 return RunPostMessageLoop(); |
259 } | 267 } |
260 | 268 |
261 Scheduler* Setup::GetScheduler() { | 269 Scheduler* Setup::GetScheduler() { |
262 return &scheduler_; | 270 return &scheduler_; |
263 } | 271 } |
264 | 272 |
| 273 SourceFile Setup::GetBuildArgFile() const { |
| 274 return SourceFile(build_settings_.build_dir().value() + kBuildArgFileName); |
| 275 } |
| 276 |
265 bool Setup::FillArguments(const CommandLine& cmdline) { | 277 bool Setup::FillArguments(const CommandLine& cmdline) { |
266 std::string args = cmdline.GetSwitchValueASCII(kSwitchArgs); | 278 // Add a dependency on the build arguments file. If this changes, we want |
267 if (args.empty()) | 279 // to re-generated the build. |
268 return true; // Nothing to set. | 280 g_scheduler->AddGenDependency(build_settings_.GetFullPath(GetBuildArgFile())); |
269 | 281 |
| 282 // Use the args on the command line if specified, and save them. Do this even |
| 283 // if the list is empty (this means clear any defaults). |
| 284 if (cmdline.HasSwitch(kSwitchArgs)) { |
| 285 if (!FillArgsFromCommandLine(cmdline.GetSwitchValueASCII(kSwitchArgs))) |
| 286 return false; |
| 287 SaveArgsToFile(); |
| 288 return true; |
| 289 } |
| 290 |
| 291 // No command line args given, use the arguments from the build dir (if any). |
| 292 return FillArgsFromFile(); |
| 293 } |
| 294 |
| 295 bool Setup::FillArgsFromCommandLine(const std::string& args) { |
270 args_input_file_.reset(new InputFile(SourceFile())); | 296 args_input_file_.reset(new InputFile(SourceFile())); |
271 args_input_file_->SetContents(args); | 297 args_input_file_->SetContents(args); |
272 args_input_file_->set_friendly_name("the command-line \"--args\" settings"); | 298 args_input_file_->set_friendly_name("the command-line \"--args\""); |
| 299 return FillArgsFromArgsInputFile(); |
| 300 } |
| 301 |
| 302 bool Setup::FillArgsFromFile() { |
| 303 ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "Load args file"); |
| 304 |
| 305 SourceFile build_arg_source_file = GetBuildArgFile(); |
| 306 base::FilePath build_arg_file = |
| 307 build_settings_.GetFullPath(build_arg_source_file); |
| 308 |
| 309 std::string contents; |
| 310 if (!base::ReadFileToString(build_arg_file, &contents)) |
| 311 return true; // File doesn't exist, continue with default args. |
| 312 if (contents.empty()) |
| 313 return true; // Empty file, do nothing. |
| 314 |
| 315 args_input_file_.reset(new InputFile(build_arg_source_file)); |
| 316 args_input_file_->SetContents(contents); |
| 317 args_input_file_->set_friendly_name( |
| 318 "build arg file (use \"gn args <out_dir>\" to edit)"); |
| 319 |
| 320 setup_trace.Done(); // Only want to count the load as part of the trace. |
| 321 return FillArgsFromArgsInputFile(); |
| 322 } |
| 323 |
| 324 bool Setup::FillArgsFromArgsInputFile() { |
| 325 ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "Parse args"); |
273 | 326 |
274 Err err; | 327 Err err; |
275 args_tokens_ = Tokenizer::Tokenize(args_input_file_.get(), &err); | 328 args_tokens_ = Tokenizer::Tokenize(args_input_file_.get(), &err); |
276 if (err.has_error()) { | 329 if (err.has_error()) { |
277 err.PrintToStdout(); | 330 err.PrintToStdout(); |
278 return false; | 331 return false; |
279 } | 332 } |
280 | 333 |
281 args_root_ = Parser::Parse(args_tokens_, &err); | 334 args_root_ = Parser::Parse(args_tokens_, &err); |
282 if (err.has_error()) { | 335 if (err.has_error()) { |
283 err.PrintToStdout(); | 336 err.PrintToStdout(); |
284 return false; | 337 return false; |
285 } | 338 } |
286 | 339 |
287 Scope arg_scope(&empty_settings_); | 340 Scope arg_scope(&empty_settings_); |
288 args_root_->AsBlock()->ExecuteBlockInScope(&arg_scope, &err); | 341 args_root_->AsBlock()->ExecuteBlockInScope(&arg_scope, &err); |
289 if (err.has_error()) { | 342 if (err.has_error()) { |
290 err.PrintToStdout(); | 343 err.PrintToStdout(); |
291 return false; | 344 return false; |
292 } | 345 } |
293 | 346 |
294 // Save the result of the command args. | 347 // Save the result of the command args. |
295 Scope::KeyValueMap overrides; | 348 Scope::KeyValueMap overrides; |
296 arg_scope.GetCurrentScopeValues(&overrides); | 349 arg_scope.GetCurrentScopeValues(&overrides); |
297 build_settings_.build_args().AddArgOverrides(overrides); | 350 build_settings_.build_args().AddArgOverrides(overrides); |
298 return true; | 351 return true; |
299 } | 352 } |
300 | 353 |
| 354 bool Setup::SaveArgsToFile() { |
| 355 ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "Save args file"); |
| 356 |
| 357 Scope::KeyValueMap args = build_settings_.build_args().GetAllOverrides(); |
| 358 |
| 359 std::ostringstream stream; |
| 360 for (Scope::KeyValueMap::const_iterator i = args.begin(); |
| 361 i != args.end(); ++i) { |
| 362 stream << i->first.as_string() << " = " << i->second.ToString(true); |
| 363 stream << std::endl; |
| 364 } |
| 365 |
| 366 // For the first run, the build output dir might not be created yet, so do |
| 367 // that so we can write a file into it. Ignore errors, we'll catch the error |
| 368 // when we try to write a file to it below. |
| 369 base::FilePath build_arg_file = |
| 370 build_settings_.GetFullPath(GetBuildArgFile()); |
| 371 base::CreateDirectory(build_arg_file.DirName()); |
| 372 |
| 373 std::string contents = stream.str(); |
| 374 #if defined(OS_WIN) |
| 375 // Use Windows lineendings for this file since it will often open in |
| 376 // Notepad which can't handle Unix ones. |
| 377 ReplaceSubstringsAfterOffset(&contents, 0, "\n", "\r\n"); |
| 378 #endif |
| 379 if (base::WriteFile(build_arg_file, contents.c_str(), contents.size()) == |
| 380 -1) { |
| 381 Err(Location(), "Args file could not be written.", |
| 382 "The file is \"" + FilePathToUTF8(build_arg_file) + |
| 383 "\"").PrintToStdout(); |
| 384 return false; |
| 385 } |
| 386 |
| 387 return true; |
| 388 } |
| 389 |
301 bool Setup::FillSourceDir(const CommandLine& cmdline) { | 390 bool Setup::FillSourceDir(const CommandLine& cmdline) { |
302 // Find the .gn file. | 391 // Find the .gn file. |
303 base::FilePath root_path; | 392 base::FilePath root_path; |
304 | 393 |
305 // Prefer the command line args to the config file. | 394 // Prefer the command line args to the config file. |
306 base::FilePath relative_root_path = cmdline.GetSwitchValuePath(kSwitchRoot); | 395 base::FilePath relative_root_path = cmdline.GetSwitchValuePath(kSwitchRoot); |
307 if (!relative_root_path.empty()) { | 396 if (!relative_root_path.empty()) { |
308 root_path = base::MakeAbsoluteFilePath(relative_root_path); | 397 root_path = base::MakeAbsoluteFilePath(relative_root_path); |
309 if (root_path.empty()) { | 398 if (root_path.empty()) { |
310 Err(Location(), "Root source path not found.", | 399 Err(Location(), "Root source path not found.", |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
362 return false; | 451 return false; |
363 } | 452 } |
364 | 453 |
365 if (scheduler_.verbose_logging()) | 454 if (scheduler_.verbose_logging()) |
366 scheduler_.Log("Using build dir", resolved.value()); | 455 scheduler_.Log("Using build dir", resolved.value()); |
367 build_settings_.SetBuildDir(resolved); | 456 build_settings_.SetBuildDir(resolved); |
368 return true; | 457 return true; |
369 } | 458 } |
370 | 459 |
371 void Setup::FillPythonPath() { | 460 void Setup::FillPythonPath() { |
| 461 // Trace this since it tends to be a bit slow on Windows. |
| 462 ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "Fill Python Path"); |
372 #if defined(OS_WIN) | 463 #if defined(OS_WIN) |
373 // Find Python on the path so we can use the absolute path in the build. | 464 // Find Python on the path so we can use the absolute path in the build. |
374 const base::char16 kGetPython[] = | 465 const base::char16 kGetPython[] = |
375 L"cmd.exe /c python -c \"import sys; print sys.executable\""; | 466 L"cmd.exe /c python -c \"import sys; print sys.executable\""; |
376 std::string python_path; | 467 std::string python_path; |
377 if (base::GetAppOutput(kGetPython, &python_path)) { | 468 if (base::GetAppOutput(kGetPython, &python_path)) { |
378 base::TrimWhitespaceASCII(python_path, base::TRIM_ALL, &python_path); | 469 base::TrimWhitespaceASCII(python_path, base::TRIM_ALL, &python_path); |
379 if (scheduler_.verbose_logging()) | 470 if (scheduler_.verbose_logging()) |
380 scheduler_.Log("Found python", python_path); | 471 scheduler_.Log("Found python", python_path); |
381 } else { | 472 } else { |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 } | 591 } |
501 | 592 |
502 void DependentSetup::RunPreMessageLoop() { | 593 void DependentSetup::RunPreMessageLoop() { |
503 CommonSetup::RunPreMessageLoop(); | 594 CommonSetup::RunPreMessageLoop(); |
504 } | 595 } |
505 | 596 |
506 bool DependentSetup::RunPostMessageLoop() { | 597 bool DependentSetup::RunPostMessageLoop() { |
507 return CommonSetup::RunPostMessageLoop(); | 598 return CommonSetup::RunPostMessageLoop(); |
508 } | 599 } |
509 | 600 |
OLD | NEW |