List .gn file in build.ninja.d. This way, gn reruns when the .gn file is touched. Bug: 24 Change-Id: Iabc21ee5f4b82106c7d8004f8372b3d83471b515 Reviewed-on: https://gn-review.googlesource.com/c/3321 Commit-Queue: Brett Wilson <brettw@chromium.org> Reviewed-by: Brett Wilson <brettw@chromium.org>
diff --git a/build/gen.py b/build/gen.py index 9f5eaf2..56a6566 100755 --- a/build/gen.py +++ b/build/gen.py
@@ -586,6 +586,7 @@ 'tools/gn/runtime_deps_unittest.cc', 'tools/gn/scope_per_file_provider_unittest.cc', 'tools/gn/scope_unittest.cc', + 'tools/gn/setup_unittest.cc', 'tools/gn/source_dir_unittest.cc', 'tools/gn/source_file_unittest.cc', 'tools/gn/string_utils_unittest.cc',
diff --git a/tools/gn/command_analyze.cc b/tools/gn/command_analyze.cc index 9aa698b..d3b24bf 100644 --- a/tools/gn/command_analyze.cc +++ b/tools/gn/command_analyze.cc
@@ -106,6 +106,7 @@ return 1; } + // Deliberately leaked to avoid expensive process teardown. Setup* setup = new Setup; if (!setup->DoSetup(args[0], false) || !setup->Run()) return 1;
diff --git a/tools/gn/command_args.cc b/tools/gn/command_args.cc index 9980333..fac8683 100644 --- a/tools/gn/command_args.cc +++ b/tools/gn/command_args.cc
@@ -205,6 +205,7 @@ } int ListArgs(const std::string& build_dir) { + // Deliberately leaked to avoid expensive process teardown. Setup* setup = new Setup; if (!setup->DoSetup(build_dir, false) || !setup->Run()) return 1;
diff --git a/tools/gn/command_clean.cc b/tools/gn/command_clean.cc index b138864..b354039 100644 --- a/tools/gn/command_clean.cc +++ b/tools/gn/command_clean.cc
@@ -63,6 +63,7 @@ return 1; } + // Deliberately leaked to avoid expensive process teardown. Setup* setup = new Setup; if (!setup->DoSetup(args[0], false)) return 1;
diff --git a/tools/gn/command_ls.cc b/tools/gn/command_ls.cc index 65ec1a9..2609499 100644 --- a/tools/gn/command_ls.cc +++ b/tools/gn/command_ls.cc
@@ -68,6 +68,7 @@ return 1; } + // Deliberately leaked to avoid expensive process teardown. Setup* setup = new Setup; if (!setup->DoSetup(args[0], false) || !setup->Run()) return 1;
diff --git a/tools/gn/command_path.cc b/tools/gn/command_path.cc index 333a78e..503ba6d 100644 --- a/tools/gn/command_path.cc +++ b/tools/gn/command_path.cc
@@ -319,6 +319,7 @@ return 1; } + // Deliberately leaked to avoid expensive process teardown. Setup* setup = new Setup; if (!setup->DoSetup(args[0], false)) return 1;
diff --git a/tools/gn/command_refs.cc b/tools/gn/command_refs.cc index 92ecf10..1ca63ec 100644 --- a/tools/gn/command_refs.cc +++ b/tools/gn/command_refs.cc
@@ -407,6 +407,7 @@ bool all = cmdline->HasSwitch("all"); bool all_toolchains = cmdline->HasSwitch(switches::kAllToolchains); + // Deliberately leaked to avoid expensive process teardown. Setup* setup = new Setup; if (!setup->DoSetup(args[0], false) || !setup->Run()) return 1;
diff --git a/tools/gn/exec_process_unittest.cc b/tools/gn/exec_process_unittest.cc index 323a070..647bf42 100644 --- a/tools/gn/exec_process_unittest.cc +++ b/tools/gn/exec_process_unittest.cc
@@ -67,7 +67,6 @@ // byte buffer and, if stdout is non-blocking, python will throw an IOError when // a write exceeds the buffer size. TEST(ExecProcessTest, TestLargeOutput) { - base::ScopedTempDir temp_dir; std::string std_out, std_err; int exit_code; @@ -78,7 +77,6 @@ } TEST(ExecProcessTest, TestStdoutAndStderrOutput) { - base::ScopedTempDir temp_dir; std::string std_out, std_err; int exit_code;
diff --git a/tools/gn/ninja_build_writer_unittest.cc b/tools/gn/ninja_build_writer_unittest.cc index 55ffcc9..50530b1 100644 --- a/tools/gn/ninja_build_writer_unittest.cc +++ b/tools/gn/ninja_build_writer_unittest.cc
@@ -113,7 +113,8 @@ target_baz.action_values().outputs() = SubstitutionList::MakeForTest( "//out/Debug/out5.out", "//out/Debug/out6.out"); target_baz.SetToolchain(&other_toolchain); - target_baz.action_values().set_pool(LabelPtrPair<Pool>(&another_regular_pool)); + target_baz.action_values().set_pool( + LabelPtrPair<Pool>(&another_regular_pool)); ASSERT_TRUE(target_baz.OnResolved(&err)); // The console pool must be in the default toolchain.
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc index 27c6475..6720f65 100644 --- a/tools/gn/setup.cc +++ b/tools/gn/setup.cc
@@ -315,20 +315,25 @@ Setup::~Setup() = default; bool Setup::DoSetup(const std::string& build_dir, bool force_create) { - base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); + return DoSetup(build_dir, force_create, + *base::CommandLine::ForCurrentProcess()); +} - scheduler_.set_verbose_logging(cmdline->HasSwitch(switches::kVerbose)); - if (cmdline->HasSwitch(switches::kTime) || - cmdline->HasSwitch(switches::kTracelog)) +bool Setup::DoSetup(const std::string& build_dir, + bool force_create, + const base::CommandLine& cmdline) { + scheduler_.set_verbose_logging(cmdline.HasSwitch(switches::kVerbose)); + if (cmdline.HasSwitch(switches::kTime) || + cmdline.HasSwitch(switches::kTracelog)) EnableTracing(); ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "DoSetup"); - if (!FillSourceDir(*cmdline)) + if (!FillSourceDir(cmdline)) return false; if (!RunConfigFile()) return false; - if (!FillOtherConfig(*cmdline)) + if (!FillOtherConfig(cmdline)) return false; // Must be after FillSourceDir to resolve. @@ -344,10 +349,10 @@ } if (fill_arguments_) { - if (!FillArguments(*cmdline)) + if (!FillArguments(cmdline)) return false; } - if (!FillPythonPath(*cmdline)) + if (!FillPythonPath(cmdline)) return false; // Check for unused variables in the .gn file. @@ -361,10 +366,14 @@ } bool Setup::Run() { + return Run(*base::CommandLine::ForCurrentProcess()); +} + +bool Setup::Run(const base::CommandLine& cmdline) { RunPreMessageLoop(); if (!scheduler_.Run()) return false; - return RunPostMessageLoop(); + return RunPostMessageLoop(cmdline); } SourceFile Setup::GetBuildArgFile() const { @@ -379,7 +388,7 @@ loader_->Load(root_build_file_, LocationRange(), Label()); } -bool Setup::RunPostMessageLoop() { +bool Setup::RunPostMessageLoop(const base::CommandLine& cmdline) { Err err; if (!builder_.CheckForBadItems(&err)) { err.PrintToStdout(); @@ -387,8 +396,7 @@ } if (!build_settings_.build_args().VerifyAllOverridesUsed(&err)) { - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kFailOnUnusedArgs)) { + if (cmdline.HasSwitch(switches::kFailOnUnusedArgs)) { err.PrintToStdout(); return false; } @@ -416,11 +424,10 @@ } // Write out tracing and timing if requested. - const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); - if (cmdline->HasSwitch(switches::kTime)) + if (cmdline.HasSwitch(switches::kTime)) PrintLongHelp(SummarizeTraces()); - if (cmdline->HasSwitch(switches::kTracelog)) - SaveTraces(cmdline->GetSwitchValuePath(switches::kTracelog)); + if (cmdline.HasSwitch(switches::kTracelog)) + SaveTraces(cmdline.GetSwitchValuePath(switches::kTracelog)); return true; } @@ -715,6 +722,12 @@ return false; } + // Add a dependency on the build arguments file. If this changes, we want + // to re-generate the build. This causes the dotfile to make it into + // build.ninja.d. + g_scheduler->AddGenDependency(dotfile_name_); + + // Also add a build dependency to the scope, which is used by `gn analyze`. dotfile_scope_.AddBuildDependencyFile(SourceFile("//.gn")); dotfile_root_->Execute(&dotfile_scope_, &err); if (err.has_error()) {
diff --git a/tools/gn/setup.h b/tools/gn/setup.h index 13d0da5..cca30ab 100644 --- a/tools/gn/setup.h +++ b/tools/gn/setup.h
@@ -29,7 +29,7 @@ extern const char kDotfile_Help[]; -// Helper class to setup the build settings and environment for the various +// Helper class to set up the build settings and environment for the various // commands to run. class Setup { public: @@ -49,12 +49,24 @@ // generation should set this to true to create it, but querying commands // should set it to false to prevent creating oddly-named directories in case // the user omits the build directory argument (which is easy to do). + // + // cmdline is the gn invocation command, with flags like --root and --dotfile. + // If no explicit cmdline is passed, base::CommandLine::ForCurrentProcess() + // is used. bool DoSetup(const std::string& build_dir, bool force_create); + bool DoSetup(const std::string& build_dir, + bool force_create, + const base::CommandLine& cmdline); // Runs the load, returning true on success. On failure, prints the error // and returns false. This includes both RunPreMessageLoop() and // RunPostMessageLoop(). + // + // cmdline is the gn invocation command, with flags like --root and --dotfile. + // If no explicit cmdline is passed, base::CommandLine::ForCurrentProcess() + // is used. bool Run(); + bool Run(const base::CommandLine& cmdline); Scheduler& scheduler() { return scheduler_; } @@ -93,7 +105,7 @@ // Performs the two sets of operations to run the generation before and after // the message loop is run. void RunPreMessageLoop(); - bool RunPostMessageLoop(); + bool RunPostMessageLoop(const base::CommandLine& cmdline); // Fills build arguments. Returns true on success. bool FillArguments(const base::CommandLine& cmdline);
diff --git a/tools/gn/setup_unittest.cc b/tools/gn/setup_unittest.cc new file mode 100644 index 0000000..ab94ce1 --- /dev/null +++ b/tools/gn/setup_unittest.cc
@@ -0,0 +1,44 @@ +// Copyright 2018 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/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "tools/gn/filesystem_utils.h" +#include "tools/gn/switches.h" +#include "tools/gn/test_with_scheduler.h" + +using SetupTest = TestWithScheduler; + +static void WriteFile(const base::FilePath& file, const std::string& data) { + CHECK(data.size() == base::WriteFile(file, data.data(), data.size())); +} + +TEST_F(SetupTest, DotGNFileIsGenDep) { + base::CommandLine cmdline(base::CommandLine::NO_PROGRAM); + + // Create a temp directory containing a .gn file and a BUILDCONFIG.gn file, + // pass it as --root. + base::ScopedTempDir in_temp_dir; + ASSERT_TRUE(in_temp_dir.CreateUniqueTempDir()); + base::FilePath in_path = in_temp_dir.GetPath(); + base::FilePath dot_gn_name = in_path.Append(FILE_PATH_LITERAL(".gn")); + WriteFile(dot_gn_name, "buildconfig = \"//BUILDCONFIG.gn\"\n"); + WriteFile(in_path.Append(FILE_PATH_LITERAL("BUILDCONFIG.gn")), ""); + cmdline.AppendSwitchASCII(switches::kRoot, FilePathToUTF8(in_path)); + + // Create another temp dir for writing the generated files to. + base::ScopedTempDir build_temp_dir; + ASSERT_TRUE(build_temp_dir.CreateUniqueTempDir()); + + // Run setup and check that the .gn file is in the scheduler's gen deps. + Setup setup; + EXPECT_TRUE( + setup.DoSetup(FilePathToUTF8(build_temp_dir.GetPath()), true, cmdline)); + std::vector<base::FilePath> gen_deps = g_scheduler->GetGenDependencies(); + ASSERT_EQ(1u, gen_deps.size()); + EXPECT_EQ(gen_deps[0], base::MakeAbsoluteFilePath(dot_gn_name)); +}