| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "tools/gn/setup.h" |
| |
| #include "base/command_line.h" |
| #include "base/file_util.h" |
| #include "base/files/file_path.h" |
| #include "tools/gn/filesystem_utils.h" |
| #include "tools/gn/input_file.h" |
| #include "tools/gn/parse_tree.h" |
| #include "tools/gn/parser.h" |
| #include "tools/gn/source_dir.h" |
| #include "tools/gn/source_file.h" |
| #include "tools/gn/tokenizer.h" |
| #include "tools/gn/value.h" |
| |
| namespace { |
| |
| // More logging. |
| const char kSwitchVerbose[] = "v"; |
| |
| const char kSwitchRoot[] = "root"; |
| const char kSecondarySource[] = "secondary"; |
| |
| const base::FilePath::CharType kGnFile[] = FILE_PATH_LITERAL(".gn"); |
| |
| base::FilePath FindDotFile(const base::FilePath& current_dir) { |
| base::FilePath try_this_file = current_dir.Append(kGnFile); |
| if (base::PathExists(try_this_file)) |
| return try_this_file; |
| |
| base::FilePath with_no_slash = current_dir.StripTrailingSeparators(); |
| base::FilePath up_one_dir = with_no_slash.DirName(); |
| if (up_one_dir == current_dir) |
| return base::FilePath(); // Got to the top. |
| |
| return FindDotFile(up_one_dir); |
| } |
| |
| } // namespace |
| |
| Setup::Setup() |
| : dotfile_toolchain_(Label()), |
| dotfile_settings_(&dotfile_build_settings_, &dotfile_toolchain_, |
| std::string()), |
| dotfile_scope_(&dotfile_settings_) { |
| } |
| |
| Setup::~Setup() { |
| } |
| |
| bool Setup::DoSetup() { |
| CommandLine* cmdline = CommandLine::ForCurrentProcess(); |
| |
| scheduler_.set_verbose_logging(cmdline->HasSwitch(kSwitchVerbose)); |
| |
| if (!FillSourceDir(*cmdline)) |
| return false; |
| if (!RunConfigFile()) |
| return false; |
| if (!FillOtherConfig(*cmdline)) |
| return false; |
| |
| // FIXME(brettw) get python path! |
| /*#if defined(OS_WIN) |
| build_settings_.set_python_path(base::FilePath( |
| //L"P:\\depot_tools\\python_bin\\python.exe")); |
| L"C:\\apps\\depot_tools\\python_bin\\python.exe")); |
| #else*/ |
| build_settings_.set_python_path(base::FilePath("python")); |
| //#endif |
| |
| build_settings_.SetBuildDir(SourceDir("//out/gn/")); |
| |
| return true; |
| } |
| |
| bool Setup::Run() { |
| // Load the root build file and start runnung. |
| build_settings_.toolchain_manager().StartLoadingUnlocked( |
| SourceFile("//BUILD.gn")); |
| if (!scheduler_.Run()) |
| return false; |
| |
| Err err = build_settings_.item_tree().CheckForBadItems(); |
| if (err.has_error()) { |
| err.PrintToStdout(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool Setup::FillSourceDir(const CommandLine& cmdline) { |
| // Find the .gn file. |
| base::FilePath root_path; |
| |
| // Prefer the command line args to the config file. |
| base::FilePath relative_root_path = cmdline.GetSwitchValuePath(kSwitchRoot); |
| if (!relative_root_path.empty()) { |
| root_path = base::MakeAbsoluteFilePath(relative_root_path); |
| dotfile_name_ = root_path.Append(kGnFile); |
| } else { |
| base::FilePath cur_dir; |
| file_util::GetCurrentDirectory(&cur_dir); |
| dotfile_name_ = FindDotFile(cur_dir); |
| if (dotfile_name_.empty()) { |
| Err(Location(), "Can't find source root.", |
| "I could not find a \".gn\" file in the current directory or any " |
| "parent,\nand the --root command-line argument was not specified.") |
| .PrintToStdout(); |
| return false; |
| } |
| root_path = dotfile_name_.DirName(); |
| } |
| |
| if (scheduler_.verbose_logging()) |
| scheduler_.Log("Using source root", FilePathToUTF8(root_path)); |
| build_settings_.set_root_path(root_path); |
| |
| return true; |
| } |
| |
| bool Setup::RunConfigFile() { |
| if (scheduler_.verbose_logging()) |
| scheduler_.Log("Got dotfile", FilePathToUTF8(dotfile_name_)); |
| |
| dotfile_input_file_.reset(new InputFile(SourceFile("//.gn"))); |
| if (!dotfile_input_file_->Load(dotfile_name_)) { |
| Err(Location(), "Could not load dotfile.", |
| "The file \"" + FilePathToUTF8(dotfile_name_) + "\" cound't be loaded") |
| .PrintToStdout(); |
| return false; |
| } |
| |
| Err err; |
| dotfile_tokens_ = Tokenizer::Tokenize(dotfile_input_file_.get(), &err); |
| if (err.has_error()) { |
| err.PrintToStdout(); |
| return false; |
| } |
| |
| dotfile_root_ = Parser::Parse(dotfile_tokens_, &err); |
| if (err.has_error()) { |
| err.PrintToStdout(); |
| return false; |
| } |
| |
| dotfile_root_->AsBlock()->ExecuteBlockInScope(&dotfile_scope_, &err); |
| if (err.has_error()) { |
| err.PrintToStdout(); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool Setup::FillOtherConfig(const CommandLine& cmdline) { |
| Err err; |
| |
| // Secondary source path. |
| SourceDir secondary_source; |
| if (cmdline.HasSwitch(kSecondarySource)) { |
| // Prefer the command line over the config file. |
| secondary_source = |
| SourceDir(cmdline.GetSwitchValueASCII(kSecondarySource)); |
| } else { |
| // Read from the config file if present. |
| const Value* secondary_value = |
| dotfile_scope_.GetValue("secondary_source", true); |
| if (secondary_value) { |
| if (!secondary_value->VerifyTypeIs(Value::STRING, &err)) { |
| err.PrintToStdout(); |
| return false; |
| } |
| build_settings_.SetSecondarySourcePath( |
| SourceDir(secondary_value->string_value())); |
| } |
| } |
| |
| // Build config dir. |
| const Value* build_config_value = |
| dotfile_scope_.GetValue("buildconfig", true); |
| if (!build_config_value) { |
| Err(Location(), "No build config file.", |
| "Your .gn file (\"" + FilePathToUTF8(dotfile_name_) + "\")\n" |
| "didn't specify a \"buildconfig\" value.").PrintToStdout(); |
| return false; |
| } |
| build_settings_.set_build_config_file( |
| SourceFile("//build/config/BUILDCONFIG.gn")); |
| |
| return true; |
| } |