Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / tools / gn / setup.cc
blob5ba87b934bbe9da8d978b75da325623c9fd7f1be
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
3 // found in the LICENSE file.
5 #include "tools/gn/setup.h"
7 #include <stdlib.h>
9 #include <algorithm>
10 #include <sstream>
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/files/file_path.h"
15 #include "base/files/file_util.h"
16 #include "base/process/launch.h"
17 #include "base/strings/string_split.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "build/build_config.h"
21 #include "tools/gn/commands.h"
22 #include "tools/gn/filesystem_utils.h"
23 #include "tools/gn/input_file.h"
24 #include "tools/gn/parse_tree.h"
25 #include "tools/gn/parser.h"
26 #include "tools/gn/source_dir.h"
27 #include "tools/gn/source_file.h"
28 #include "tools/gn/standard_out.h"
29 #include "tools/gn/tokenizer.h"
30 #include "tools/gn/trace.h"
31 #include "tools/gn/value.h"
33 #if defined(OS_WIN)
34 #include <windows.h>
35 #endif
37 extern const char kDotfile_Help[] =
38 ".gn file\n"
39 "\n"
40 " When gn starts, it will search the current directory and parent\n"
41 " directories for a file called \".gn\". This indicates the source root.\n"
42 " You can override this detection by using the --root command-line\n"
43 " argument\n"
44 "\n"
45 " The .gn file in the source root will be executed. The syntax is the\n"
46 " same as a buildfile, but with very limited build setup-specific\n"
47 " meaning.\n"
48 "\n"
49 " If you specify --root, by default GN will look for the file .gn in\n"
50 " that directory. If you want to specify a different file, you can\n"
51 " additionally pass --dotfile:\n"
52 "\n"
53 " gn gen out/Debug --root=/home/build --dotfile=/home/my_gn_file.gn\n"
54 "\n"
55 "Variables\n"
56 "\n"
57 " buildconfig [required]\n"
58 " Label of the build config file. This file will be used to set up\n"
59 " the build file execution environment for each toolchain.\n"
60 "\n"
61 " root [optional]\n"
62 " Label of the root build target. The GN build will start by loading\n"
63 " the build file containing this target name. This defaults to\n"
64 " \"//:\" which will cause the file //BUILD.gn to be loaded.\n"
65 "\n"
66 " secondary_source [optional]\n"
67 " Label of an alternate directory tree to find input files. When\n"
68 " searching for a BUILD.gn file (or the build config file discussed\n"
69 " above), the file will first be looked for in the source root.\n"
70 " If it's not found, the secondary source root will be checked\n"
71 " (which would contain a parallel directory hierarchy).\n"
72 "\n"
73 " This behavior is intended to be used when BUILD.gn files can't be\n"
74 " checked in to certain source directories for whatever reason.\n"
75 "\n"
76 " The secondary source root must be inside the main source tree.\n"
77 "\n"
78 "Example .gn file contents\n"
79 "\n"
80 " buildconfig = \"//build/config/BUILDCONFIG.gn\"\n"
81 "\n"
82 " root = \"//:root\"\n"
83 "\n"
84 " secondary_source = \"//build/config/temporary_buildfiles/\"\n";
86 namespace {
88 // More logging.
89 const char kSwitchVerbose[] = "v";
91 // Set build args.
92 const char kSwitchArgs[] = "args";
94 // Set root dir.
95 const char kSwitchRoot[] = "root";
97 // Set dotfile name.
98 const char kSwitchDotfile[] = "dotfile";
100 // Enable timing.
101 const char kTimeSwitch[] = "time";
103 const char kTracelogSwitch[] = "tracelog";
105 const base::FilePath::CharType kGnFile[] = FILE_PATH_LITERAL(".gn");
107 base::FilePath FindDotFile(const base::FilePath& current_dir) {
108 base::FilePath try_this_file = current_dir.Append(kGnFile);
109 if (base::PathExists(try_this_file))
110 return try_this_file;
112 base::FilePath with_no_slash = current_dir.StripTrailingSeparators();
113 base::FilePath up_one_dir = with_no_slash.DirName();
114 if (up_one_dir == current_dir)
115 return base::FilePath(); // Got to the top.
117 return FindDotFile(up_one_dir);
120 // Called on any thread. Post the item to the builder on the main thread.
121 void ItemDefinedCallback(base::MessageLoop* main_loop,
122 scoped_refptr<Builder> builder,
123 scoped_ptr<Item> item) {
124 DCHECK(item);
125 main_loop->PostTask(FROM_HERE, base::Bind(&Builder::ItemDefined, builder,
126 base::Passed(&item)));
129 void DecrementWorkCount() {
130 g_scheduler->DecrementWorkCount();
133 } // namespace
135 // CommonSetup -----------------------------------------------------------------
137 const char CommonSetup::kBuildArgFileName[] = "args.gn";
139 CommonSetup::CommonSetup()
140 : build_settings_(),
141 loader_(new LoaderImpl(&build_settings_)),
142 builder_(new Builder(loader_.get())),
143 root_build_file_("//BUILD.gn"),
144 check_for_bad_items_(true),
145 check_for_unused_overrides_(true),
146 check_public_headers_(false) {
147 loader_->set_complete_callback(base::Bind(&DecrementWorkCount));
150 CommonSetup::CommonSetup(const CommonSetup& other)
151 : build_settings_(other.build_settings_),
152 loader_(new LoaderImpl(&build_settings_)),
153 builder_(new Builder(loader_.get())),
154 root_build_file_(other.root_build_file_),
155 check_for_bad_items_(other.check_for_bad_items_),
156 check_for_unused_overrides_(other.check_for_unused_overrides_),
157 check_public_headers_(other.check_public_headers_) {
158 loader_->set_complete_callback(base::Bind(&DecrementWorkCount));
161 CommonSetup::~CommonSetup() {
164 void CommonSetup::RunPreMessageLoop() {
165 // Load the root build file.
166 loader_->Load(root_build_file_, LocationRange(), Label());
168 // Will be decremented with the loader is drained.
169 g_scheduler->IncrementWorkCount();
172 bool CommonSetup::RunPostMessageLoop() {
173 Err err;
174 if (check_for_bad_items_) {
175 if (!builder_->CheckForBadItems(&err)) {
176 err.PrintToStdout();
177 return false;
181 if (check_for_unused_overrides_) {
182 if (!build_settings_.build_args().VerifyAllOverridesUsed(&err)) {
183 // TODO(brettw) implement a system of warnings. Until we have a better
184 // system, print the error but don't return failure.
185 err.PrintToStdout();
186 return true;
190 if (check_public_headers_) {
191 if (!commands::CheckPublicHeaders(&build_settings_,
192 builder_->GetAllResolvedTargets(),
193 std::vector<const Target*>(),
194 false)) {
195 return false;
199 // Write out tracing and timing if requested.
200 const CommandLine* cmdline = CommandLine::ForCurrentProcess();
201 if (cmdline->HasSwitch(kTimeSwitch))
202 PrintLongHelp(SummarizeTraces());
203 if (cmdline->HasSwitch(kTracelogSwitch))
204 SaveTraces(cmdline->GetSwitchValuePath(kTracelogSwitch));
206 return true;
209 // Setup -----------------------------------------------------------------------
211 Setup::Setup()
212 : CommonSetup(),
213 empty_settings_(&empty_build_settings_, std::string()),
214 dotfile_scope_(&empty_settings_),
215 fill_arguments_(true) {
216 empty_settings_.set_toolchain_label(Label());
217 build_settings_.set_item_defined_callback(
218 base::Bind(&ItemDefinedCallback, scheduler_.main_loop(), builder_));
220 // The scheduler's main loop wasn't created when the Loader was created, so
221 // we need to set it now.
222 loader_->set_main_loop(scheduler_.main_loop());
225 Setup::~Setup() {
228 bool Setup::DoSetup(const std::string& build_dir, bool force_create) {
229 CommandLine* cmdline = CommandLine::ForCurrentProcess();
231 scheduler_.set_verbose_logging(cmdline->HasSwitch(kSwitchVerbose));
232 if (cmdline->HasSwitch(kTimeSwitch) ||
233 cmdline->HasSwitch(kTracelogSwitch))
234 EnableTracing();
236 ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "DoSetup");
238 if (!FillSourceDir(*cmdline))
239 return false;
240 if (!RunConfigFile())
241 return false;
242 if (!FillOtherConfig(*cmdline))
243 return false;
245 // Must be after FillSourceDir to resolve.
246 if (!FillBuildDir(build_dir, !force_create))
247 return false;
249 if (fill_arguments_) {
250 if (!FillArguments(*cmdline))
251 return false;
253 FillPythonPath();
255 return true;
258 bool Setup::Run() {
259 RunPreMessageLoop();
260 if (!scheduler_.Run())
261 return false;
262 return RunPostMessageLoop();
265 Scheduler* Setup::GetScheduler() {
266 return &scheduler_;
269 SourceFile Setup::GetBuildArgFile() const {
270 return SourceFile(build_settings_.build_dir().value() + kBuildArgFileName);
273 bool Setup::FillArguments(const CommandLine& cmdline) {
274 // Use the args on the command line if specified, and save them. Do this even
275 // if the list is empty (this means clear any defaults).
276 if (cmdline.HasSwitch(kSwitchArgs)) {
277 if (!FillArgsFromCommandLine(cmdline.GetSwitchValueASCII(kSwitchArgs)))
278 return false;
279 SaveArgsToFile();
280 return true;
283 // No command line args given, use the arguments from the build dir (if any).
284 return FillArgsFromFile();
287 bool Setup::FillArgsFromCommandLine(const std::string& args) {
288 args_input_file_.reset(new InputFile(SourceFile()));
289 args_input_file_->SetContents(args);
290 args_input_file_->set_friendly_name("the command-line \"--args\"");
291 return FillArgsFromArgsInputFile();
294 bool Setup::FillArgsFromFile() {
295 ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "Load args file");
297 SourceFile build_arg_source_file = GetBuildArgFile();
298 base::FilePath build_arg_file =
299 build_settings_.GetFullPath(build_arg_source_file);
301 std::string contents;
302 if (!base::ReadFileToString(build_arg_file, &contents))
303 return true; // File doesn't exist, continue with default args.
305 // Add a dependency on the build arguments file. If this changes, we want
306 // to re-generate the build.
307 g_scheduler->AddGenDependency(build_arg_file);
309 if (contents.empty())
310 return true; // Empty file, do nothing.
312 args_input_file_.reset(new InputFile(build_arg_source_file));
313 args_input_file_->SetContents(contents);
314 args_input_file_->set_friendly_name(
315 "build arg file (use \"gn args <out_dir>\" to edit)");
317 setup_trace.Done(); // Only want to count the load as part of the trace.
318 return FillArgsFromArgsInputFile();
321 bool Setup::FillArgsFromArgsInputFile() {
322 ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "Parse args");
324 Err err;
325 args_tokens_ = Tokenizer::Tokenize(args_input_file_.get(), &err);
326 if (err.has_error()) {
327 err.PrintToStdout();
328 return false;
331 args_root_ = Parser::Parse(args_tokens_, &err);
332 if (err.has_error()) {
333 err.PrintToStdout();
334 return false;
337 Scope arg_scope(&empty_settings_);
338 args_root_->AsBlock()->ExecuteBlockInScope(&arg_scope, &err);
339 if (err.has_error()) {
340 err.PrintToStdout();
341 return false;
344 // Save the result of the command args.
345 Scope::KeyValueMap overrides;
346 arg_scope.GetCurrentScopeValues(&overrides);
347 build_settings_.build_args().AddArgOverrides(overrides);
348 return true;
351 bool Setup::SaveArgsToFile() {
352 ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "Save args file");
354 std::ostringstream stream;
355 for (const auto& pair : build_settings_.build_args().GetAllOverrides()) {
356 stream << pair.first.as_string() << " = " << pair.second.ToString(true);
357 stream << std::endl;
360 // For the first run, the build output dir might not be created yet, so do
361 // that so we can write a file into it. Ignore errors, we'll catch the error
362 // when we try to write a file to it below.
363 base::FilePath build_arg_file =
364 build_settings_.GetFullPath(GetBuildArgFile());
365 base::CreateDirectory(build_arg_file.DirName());
367 std::string contents = stream.str();
368 #if defined(OS_WIN)
369 // Use Windows lineendings for this file since it will often open in
370 // Notepad which can't handle Unix ones.
371 ReplaceSubstringsAfterOffset(&contents, 0, "\n", "\r\n");
372 #endif
373 if (base::WriteFile(build_arg_file, contents.c_str(),
374 static_cast<int>(contents.size())) == -1) {
375 Err(Location(), "Args file could not be written.",
376 "The file is \"" + FilePathToUTF8(build_arg_file) +
377 "\"").PrintToStdout();
378 return false;
381 // Add a dependency on the build arguments file. If this changes, we want
382 // to re-generate the build.
383 g_scheduler->AddGenDependency(build_arg_file);
385 return true;
388 bool Setup::FillSourceDir(const CommandLine& cmdline) {
389 // Find the .gn file.
390 base::FilePath root_path;
392 // Prefer the command line args to the config file.
393 base::FilePath relative_root_path = cmdline.GetSwitchValuePath(kSwitchRoot);
394 if (!relative_root_path.empty()) {
395 root_path = base::MakeAbsoluteFilePath(relative_root_path);
396 if (root_path.empty()) {
397 Err(Location(), "Root source path not found.",
398 "The path \"" + FilePathToUTF8(relative_root_path) +
399 "\" doesn't exist.").PrintToStdout();
400 return false;
403 // When --root is specified, an alternate --dotfile can also be set.
404 // --dotfile should be a real file path and not a "//foo" source-relative
405 // path.
406 base::FilePath dot_file_path = cmdline.GetSwitchValuePath(kSwitchDotfile);
407 if (dot_file_path.empty()) {
408 dotfile_name_ = root_path.Append(kGnFile);
409 } else {
410 dotfile_name_ = base::MakeAbsoluteFilePath(dot_file_path);
411 if (dotfile_name_.empty()) {
412 Err(Location(), "Could not load dotfile.",
413 "The file \"" + FilePathToUTF8(dot_file_path) +
414 "\" cound't be loaded.").PrintToStdout();
415 return false;
418 } else {
419 // In the default case, look for a dotfile and that also tells us where the
420 // source root is.
421 base::FilePath cur_dir;
422 base::GetCurrentDirectory(&cur_dir);
423 dotfile_name_ = FindDotFile(cur_dir);
424 if (dotfile_name_.empty()) {
425 Err(Location(), "Can't find source root.",
426 "I could not find a \".gn\" file in the current directory or any "
427 "parent,\nand the --root command-line argument was not specified.")
428 .PrintToStdout();
429 return false;
431 root_path = dotfile_name_.DirName();
434 if (scheduler_.verbose_logging())
435 scheduler_.Log("Using source root", FilePathToUTF8(root_path));
436 build_settings_.SetRootPath(root_path);
438 return true;
441 bool Setup::FillBuildDir(const std::string& build_dir, bool require_exists) {
442 SourceDir resolved =
443 SourceDirForCurrentDirectory(build_settings_.root_path()).
444 ResolveRelativeDir(build_dir, build_settings_.root_path_utf8());
445 if (resolved.is_null()) {
446 Err(Location(), "Couldn't resolve build directory.",
447 "The build directory supplied (\"" + build_dir + "\") was not valid.").
448 PrintToStdout();
449 return false;
452 if (scheduler_.verbose_logging())
453 scheduler_.Log("Using build dir", resolved.value());
455 if (require_exists) {
456 base::FilePath build_dir_path = build_settings_.GetFullPath(resolved);
457 if (!base::PathExists(build_dir_path.Append(
458 FILE_PATH_LITERAL("build.ninja")))) {
459 Err(Location(), "Not a build directory.",
460 "This command requires an existing build directory. I interpreted "
461 "your input\n\"" + build_dir + "\" as:\n " +
462 FilePathToUTF8(build_dir_path) +
463 "\nwhich doesn't seem to contain a previously-generated build.")
464 .PrintToStdout();
465 return false;
469 build_settings_.SetBuildDir(resolved);
470 return true;
473 void Setup::FillPythonPath() {
474 // Trace this since it tends to be a bit slow on Windows.
475 ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "Fill Python Path");
476 #if defined(OS_WIN)
477 // Find Python on the path so we can use the absolute path in the build.
478 const base::char16 kGetPython[] =
479 L"cmd.exe /c python -c \"import sys; print sys.executable\"";
480 std::string python_path;
481 if (base::GetAppOutput(kGetPython, &python_path)) {
482 base::TrimWhitespaceASCII(python_path, base::TRIM_ALL, &python_path);
483 if (scheduler_.verbose_logging())
484 scheduler_.Log("Found python", python_path);
485 } else {
486 scheduler_.Log("WARNING", "Could not find python on path, using "
487 "just \"python.exe\"");
488 python_path = "python.exe";
490 build_settings_.set_python_path(base::FilePath(base::UTF8ToUTF16(python_path))
491 .NormalizePathSeparatorsTo('/'));
492 #else
493 build_settings_.set_python_path(base::FilePath("python"));
494 #endif
497 bool Setup::RunConfigFile() {
498 if (scheduler_.verbose_logging())
499 scheduler_.Log("Got dotfile", FilePathToUTF8(dotfile_name_));
501 dotfile_input_file_.reset(new InputFile(SourceFile("//.gn")));
502 if (!dotfile_input_file_->Load(dotfile_name_)) {
503 Err(Location(), "Could not load dotfile.",
504 "The file \"" + FilePathToUTF8(dotfile_name_) + "\" cound't be loaded")
505 .PrintToStdout();
506 return false;
509 Err err;
510 dotfile_tokens_ = Tokenizer::Tokenize(dotfile_input_file_.get(), &err);
511 if (err.has_error()) {
512 err.PrintToStdout();
513 return false;
516 dotfile_root_ = Parser::Parse(dotfile_tokens_, &err);
517 if (err.has_error()) {
518 err.PrintToStdout();
519 return false;
522 dotfile_root_->AsBlock()->ExecuteBlockInScope(&dotfile_scope_, &err);
523 if (err.has_error()) {
524 err.PrintToStdout();
525 return false;
528 return true;
531 bool Setup::FillOtherConfig(const CommandLine& cmdline) {
532 Err err;
534 // Secondary source path, read from the config file if present.
535 // Read from the config file if present.
536 const Value* secondary_value =
537 dotfile_scope_.GetValue("secondary_source", true);
538 if (secondary_value) {
539 if (!secondary_value->VerifyTypeIs(Value::STRING, &err)) {
540 err.PrintToStdout();
541 return false;
543 build_settings_.SetSecondarySourcePath(
544 SourceDir(secondary_value->string_value()));
547 // Root build file.
548 const Value* root_value = dotfile_scope_.GetValue("root", true);
549 if (root_value) {
550 if (!root_value->VerifyTypeIs(Value::STRING, &err)) {
551 err.PrintToStdout();
552 return false;
555 Label root_target_label =
556 Label::Resolve(SourceDir("//"), Label(), *root_value, &err);
557 if (err.has_error()) {
558 err.PrintToStdout();
559 return false;
562 root_build_file_ = Loader::BuildFileForLabel(root_target_label);
565 // Build config file.
566 const Value* build_config_value =
567 dotfile_scope_.GetValue("buildconfig", true);
568 if (!build_config_value) {
569 Err(Location(), "No build config file.",
570 "Your .gn file (\"" + FilePathToUTF8(dotfile_name_) + "\")\n"
571 "didn't specify a \"buildconfig\" value.").PrintToStdout();
572 return false;
573 } else if (!build_config_value->VerifyTypeIs(Value::STRING, &err)) {
574 err.PrintToStdout();
575 return false;
577 build_settings_.set_build_config_file(
578 SourceFile(build_config_value->string_value()));
580 return true;
583 // DependentSetup --------------------------------------------------------------
585 DependentSetup::DependentSetup(Setup* derive_from)
586 : CommonSetup(*derive_from),
587 scheduler_(derive_from->GetScheduler()) {
588 build_settings_.set_item_defined_callback(
589 base::Bind(&ItemDefinedCallback, scheduler_->main_loop(), builder_));
592 DependentSetup::DependentSetup(DependentSetup* derive_from)
593 : CommonSetup(*derive_from),
594 scheduler_(derive_from->GetScheduler()) {
595 build_settings_.set_item_defined_callback(
596 base::Bind(&ItemDefinedCallback, scheduler_->main_loop(), builder_));
599 DependentSetup::~DependentSetup() {
602 Scheduler* DependentSetup::GetScheduler() {
603 return scheduler_;
606 void DependentSetup::RunPreMessageLoop() {
607 CommonSetup::RunPreMessageLoop();
610 bool DependentSetup::RunPostMessageLoop() {
611 return CommonSetup::RunPostMessageLoop();