[GN] Implement tracking build dependency files for Items.
This CL implements tracking build dependency files for targets,
configs, toolchains and pools and write corresponding unit tests
to verify the behaviors.
Bug: 795913
Change-Id: I3f7a9302db0725ef8167160838448e7eb39c4eee
Reviewed-on: https://chromium-review.googlesource.com/838220
Commit-Queue: Yuke Liao <liaoyuke@chromium.org>
Reviewed-by: Dirk Pranke <dpranke@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#526037}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 3cf32744d21a6f64e491c167cb995e72fe0d67bcdiff --git a/tools/gn/config.cc b/tools/gn/config.cc
index 953e677..e021fe4 100644
--- a/tools/gn/config.cc
+++ b/tools/gn/config.cc
@@ -8,8 +8,10 @@
#include "tools/gn/input_file_manager.h"
#include "tools/gn/scheduler.h"
-Config::Config(const Settings* settings, const Label& label)
- : Item(settings, label), resolved_(false) {}
+Config::Config(const Settings* settings,
+ const Label& label,
+ const std::set<SourceFile>& build_dependency_files)
+ : Item(settings, label, build_dependency_files), resolved_(false) {}
Config::~Config() = default;
diff --git a/tools/gn/config.h b/tools/gn/config.h
index 20cfe7e..ad04973 100644
--- a/tools/gn/config.h
+++ b/tools/gn/config.h
@@ -5,6 +5,8 @@
#ifndef TOOLS_GN_CONFIG_H_
#define TOOLS_GN_CONFIG_H_
+#include <set>
+
#include "base/logging.h"
#include "base/macros.h"
#include "tools/gn/config_values.h"
@@ -21,7 +23,11 @@
// flags.
class Config : public Item {
public:
- Config(const Settings* settings, const Label& label);
+ // We track the set of build files that may affect this config, please refer
+ // to Scope for how this is determined.
+ Config(const Settings* settings,
+ const Label& label,
+ const std::set<SourceFile>& build_dependency_files = {});
~Config() override;
// Item implementation.
diff --git a/tools/gn/function_toolchain.cc b/tools/gn/function_toolchain.cc
index 9fcf1f6..230f77f 100644
--- a/tools/gn/function_toolchain.cc
+++ b/tools/gn/function_toolchain.cc
@@ -454,8 +454,8 @@
// This object will actually be copied into the one owned by the toolchain
// manager, but that has to be done in the lock.
- std::unique_ptr<Toolchain> toolchain =
- std::make_unique<Toolchain>(scope->settings(), label);
+ std::unique_ptr<Toolchain> toolchain = std::make_unique<Toolchain>(
+ scope->settings(), label, scope->build_dependency_files());
toolchain->set_defined_from(function);
toolchain->visibility().SetPublic();
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc
index 60a6eb7..38b3020 100644
--- a/tools/gn/functions.cc
+++ b/tools/gn/functions.cc
@@ -338,8 +338,8 @@
g_scheduler->Log("Defining config", label.GetUserVisibleName(true));
// Create the new config.
- std::unique_ptr<Config> config =
- std::make_unique<Config>(scope->settings(), label);
+ std::unique_ptr<Config> config = std::make_unique<Config>(
+ scope->settings(), label, scope->build_dependency_files());
config->set_defined_from(function);
if (!Visibility::FillItemVisibility(config.get(), scope, err))
return Value();
@@ -633,6 +633,7 @@
SourceFile import_file =
input_dir.ResolveRelativeFile(args[0], err,
scope->settings()->build_settings()->root_path_utf8());
+ scope->AddBuildDependencyFile(import_file);
if (!err->has_error()) {
scope->settings()->import_manager().DoImport(import_file, function,
scope, err);
@@ -910,7 +911,8 @@
}
// Create the new pool.
- std::unique_ptr<Pool> pool = std::make_unique<Pool>(scope->settings(), label);
+ std::unique_ptr<Pool> pool = std::make_unique<Pool>(
+ scope->settings(), label, scope->build_dependency_files());
pool->set_depth(depth->int_value());
// Save the generated item.
diff --git a/tools/gn/item.cc b/tools/gn/item.cc
index 31abcdb..f36ff02 100644
--- a/tools/gn/item.cc
+++ b/tools/gn/item.cc
@@ -7,8 +7,13 @@
#include "base/logging.h"
#include "tools/gn/settings.h"
-Item::Item(const Settings* settings, const Label& label)
- : settings_(settings), label_(label), defined_from_(nullptr) {}
+Item::Item(const Settings* settings,
+ const Label& label,
+ const std::set<SourceFile>& build_dependency_files)
+ : settings_(settings),
+ label_(label),
+ build_dependency_files_(build_dependency_files),
+ defined_from_(nullptr) {}
Item::~Item() = default;
diff --git a/tools/gn/item.h b/tools/gn/item.h
index 3ec482a..9195b5e 100644
--- a/tools/gn/item.h
+++ b/tools/gn/item.h
@@ -5,15 +5,18 @@
#ifndef TOOLS_GN_ITEM_H_
#define TOOLS_GN_ITEM_H_
+#include <set>
#include <string>
#include "tools/gn/label.h"
+#include "tools/gn/source_file.h"
#include "tools/gn/visibility.h"
class Config;
class ParseNode;
class Pool;
class Settings;
+class SourceFile;
class Target;
class Toolchain;
@@ -21,7 +24,9 @@
// graph.
class Item {
public:
- Item(const Settings* settings, const Label& label);
+ Item(const Settings* settings,
+ const Label& label,
+ const std::set<SourceFile>& build_dependency_files = {});
virtual ~Item();
const Settings* settings() const { return settings_; }
@@ -50,6 +55,12 @@
// be used in logging and error messages.
std::string GetItemTypeName() const;
+ // Returns the set of build files that may affect this item, please refer to
+ // Scope for how this is determined.
+ const std::set<SourceFile>& build_dependency_files() const {
+ return build_dependency_files_;
+ }
+
// Called when this item is resolved, meaning it and all of its dependents
// have no unresolved deps. Returns true on success. Sets the error and
// returns false on failure.
@@ -58,6 +69,7 @@
private:
const Settings* settings_;
Label label_;
+ const std::set<SourceFile> build_dependency_files_;
const ParseNode* defined_from_;
Visibility visibility_;
diff --git a/tools/gn/loader.cc b/tools/gn/loader.cc
index 616a224..2e10c9a 100644
--- a/tools/gn/loader.cc
+++ b/tools/gn/loader.cc
@@ -24,9 +24,7 @@
struct SourceFileAndOrigin {
SourceFileAndOrigin(const SourceFile& f, const LocationRange& o)
- : file(f),
- origin(o) {
- }
+ : file(f), origin(o) {}
SourceFile file;
LocationRange origin;
@@ -39,9 +37,7 @@
struct LoaderImpl::LoadID {
LoadID() = default;
LoadID(const SourceFile& f, const Label& tc_name)
- : file(f),
- toolchain_name(tc_name) {
- }
+ : file(f), toolchain_name(tc_name) {}
bool operator<(const LoadID& other) const {
if (file.value() == other.file.value())
@@ -61,9 +57,10 @@
ToolchainRecord(const BuildSettings* build_settings,
const Label& toolchain_label,
const Label& default_toolchain_label)
- : settings(build_settings,
- GetOutputSubdirName(toolchain_label,
- toolchain_label == default_toolchain_label)),
+ : settings(
+ build_settings,
+ GetOutputSubdirName(toolchain_label,
+ toolchain_label == default_toolchain_label)),
is_toolchain_loaded(false),
is_config_loaded(false) {
settings.set_default_toolchain_label(default_toolchain_label);
@@ -111,7 +108,8 @@
const LocationRange& origin,
const Label& in_toolchain_name) {
const Label& toolchain_name = in_toolchain_name.is_null()
- ? default_toolchain_label_ : in_toolchain_name;
+ ? default_toolchain_label_
+ : in_toolchain_name;
LoadID load_id(file, toolchain_name);
if (!invocations_.insert(load_id).second)
return; // Already in set, so this file was already loaded or schedulerd.
@@ -253,6 +251,7 @@
Scope our_scope(settings->base_config());
ScopePerFileProvider per_file_provider(&our_scope, true);
our_scope.set_source_dir(file_name.GetDir());
+ our_scope.AddBuildDependencyFile(file_name);
// Targets, etc. generated as part of running this file will end up here.
Scope::ItemVector collected_items;
@@ -294,9 +293,11 @@
Scope* base_config = settings->base_config();
base_config->set_source_dir(SourceDir("//"));
+ base_config->AddBuildDependencyFile(
+ settings->build_settings()->build_config_file());
- settings->build_settings()->build_args().SetupRootScope(
- base_config, toolchain_overrides);
+ settings->build_settings()->build_args().SetupRootScope(base_config,
+ toolchain_overrides);
base_config->SetProcessingBuildConfig();
@@ -306,7 +307,7 @@
base_config->SetProperty(kDefaultToolchainKey, &default_toolchain_label);
ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE,
- settings->build_settings()->build_config_file().value());
+ settings->build_settings()->build_config_file().value());
trace.SetToolchain(settings->toolchain_label());
Err err;
@@ -327,7 +328,8 @@
// The default toolchain must have been set in the default build config
// file.
if (default_toolchain_label.is_null()) {
- g_scheduler->FailWithError(Err(Location(),
+ g_scheduler->FailWithError(Err(
+ Location(),
"The default build config file did not call set_default_toolchain()",
"If you don't call this, I can't figure out what toolchain to use\n"
"for all of this code."));
@@ -423,6 +425,5 @@
return g_scheduler->input_file_manager()->AsyncLoadFile(
origin, build_settings, file_name, callback, err);
}
- return async_load_file_.Run(
- origin, build_settings, file_name, callback, err);
+ return async_load_file_.Run(origin, build_settings, file_name, callback, err);
}
diff --git a/tools/gn/loader_unittest.cc b/tools/gn/loader_unittest.cc
index 8f51a42..4b240c3 100644
--- a/tools/gn/loader_unittest.cc
+++ b/tools/gn/loader_unittest.cc
@@ -20,6 +20,35 @@
namespace {
+bool ItemContainsBuildDependencyFile(const Item* item,
+ const SourceFile& source_file) {
+ const auto& build_dependency_files = item->build_dependency_files();
+ return build_dependency_files.end() !=
+ build_dependency_files.find(source_file);
+}
+
+class MockBuilder {
+ public:
+ void OnItemDefined(std::unique_ptr<Item> item);
+ std::vector<const Item*> GetAllItems() const;
+
+ private:
+ std::vector<std::unique_ptr<Item>> items_;
+};
+
+void MockBuilder::OnItemDefined(std::unique_ptr<Item> item) {
+ items_.push_back(std::move(item));
+}
+
+std::vector<const Item*> MockBuilder::GetAllItems() const {
+ std::vector<const Item*> result;
+ for (const auto& item : items_) {
+ result.push_back(item.get());
+ }
+
+ return result;
+}
+
class MockInputFileManager {
public:
typedef base::Callback<void(const ParseNode*)> Callback;
@@ -119,6 +148,7 @@
protected:
Scheduler scheduler_;
BuildSettings build_settings_;
+ MockBuilder mock_builder_;
MockInputFileManager mock_ifm_;
};
@@ -184,3 +214,51 @@
EXPECT_FALSE(scheduler_.is_failed());
}
+
+TEST_F(LoaderTest, BuildDependencyFilesAreCollected) {
+ SourceFile build_config("//build/config/BUILDCONFIG.gn");
+ SourceFile root_build("//BUILD.gn");
+ build_settings_.set_build_config_file(build_config);
+ build_settings_.set_item_defined_callback(base::Bind(
+ &MockBuilder::OnItemDefined, base::Unretained(&mock_builder_)));
+
+ scoped_refptr<LoaderImpl> loader(new LoaderImpl(&build_settings_));
+ mock_ifm_.AddCannedResponse(build_config,
+ "set_default_toolchain(\"//tc:tc\")");
+ mock_ifm_.AddCannedResponse(SourceFile("//test.gni"), "concurrent_jobs = 1");
+ std::string root_build_content =
+ "executable(\"a\") { sources = [ \"a.cc\" ] }\n"
+ "config(\"b\") { configs = [\"//t:t\"] }\n"
+ "toolchain(\"c\") {}\n"
+ "pool(\"d\") { depth = 1 }";
+ mock_ifm_.AddCannedResponse(root_build, root_build_content);
+
+ loader->set_async_load_file(mock_ifm_.GetCallback());
+
+ // Request the root build file be loaded. This should kick off the default
+ // build config loading.
+ loader->Load(root_build, LocationRange(), Label());
+ EXPECT_TRUE(mock_ifm_.HasOnePending(build_config));
+
+ // Completing the build config load should kick off the root build file load.
+ mock_ifm_.IssueAllPending();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(mock_ifm_.HasOnePending(root_build));
+
+ // Completing the root build file should define a target which must have
+ // set of source files hashes.
+ mock_ifm_.IssueAllPending();
+ base::RunLoop().RunUntilIdle();
+
+ std::vector<const Item*> items = mock_builder_.GetAllItems();
+ EXPECT_TRUE(items[0]->AsTarget());
+ EXPECT_TRUE(ItemContainsBuildDependencyFile(items[0], root_build));
+ EXPECT_TRUE(items[1]->AsConfig());
+ EXPECT_TRUE(ItemContainsBuildDependencyFile(items[1], root_build));
+ EXPECT_TRUE(items[2]->AsToolchain());
+ EXPECT_TRUE(ItemContainsBuildDependencyFile(items[2], root_build));
+ EXPECT_TRUE(items[3]->AsPool());
+ EXPECT_TRUE(ItemContainsBuildDependencyFile(items[3], root_build));
+
+ EXPECT_FALSE(scheduler_.is_failed());
+}
diff --git a/tools/gn/scope.cc b/tools/gn/scope.cc
index 444ce53..145d6ad 100644
--- a/tools/gn/scope.cc
+++ b/tools/gn/scope.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "tools/gn/parse_tree.h"
+#include "tools/gn/source_file.h"
#include "tools/gn/template.h"
namespace {
@@ -30,8 +31,7 @@
Scope::MergeOptions::MergeOptions()
: clobber_existing(false),
skip_private_vars(false),
- mark_dest_used(false) {
-}
+ mark_dest_used(false) {}
Scope::MergeOptions::~MergeOptions() = default;
@@ -51,14 +51,16 @@
mutable_containing_(parent),
settings_(parent->settings()),
mode_flags_(0),
- item_collector_(nullptr) {}
+ item_collector_(nullptr),
+ build_dependency_files_(parent->build_dependency_files_) {}
Scope::Scope(const Scope* parent)
: const_containing_(parent),
mutable_containing_(nullptr),
settings_(parent->settings()),
mode_flags_(0),
- item_collector_(nullptr) {}
+ item_collector_(nullptr),
+ build_dependency_files_(parent->build_dependency_files_) {}
Scope::~Scope() = default;
@@ -121,8 +123,8 @@
// Search in the parent mutable scope if requested, but not const one.
if (search_mode == SEARCH_NESTED && mutable_containing_) {
- return mutable_containing_->GetMutableValue(
- ident, Scope::SEARCH_NESTED, counts_as_used);
+ return mutable_containing_->GetMutableValue(ident, Scope::SEARCH_NESTED,
+ counts_as_used);
}
return nullptr;
}
@@ -247,7 +249,8 @@
bool Scope::CheckForUnusedVars(Err* err) const {
for (const auto& pair : values_) {
if (!pair.second.used) {
- std::string help = "You set the variable \"" + pair.first.as_string() +
+ std::string help =
+ "You set the variable \"" + pair.first.as_string() +
"\" here and it was unused before it went\nout of scope.";
const BinaryOpNode* binary = pair.second.value.origin()->AsBinaryOp();
@@ -294,13 +297,16 @@
// Value present in both the source and the dest.
std::string desc_string(desc_for_err);
*err = Err(node_for_err, "Value collision.",
- "This " + desc_string + " contains \"" + current_name.as_string() +
- "\"");
- err->AppendSubErr(Err(pair.second.value, "defined here.",
- "Which would clobber the one in your current scope"));
- err->AppendSubErr(Err(*existing_value, "defined here.",
- "Executing " + desc_string + " should not conflict with anything "
- "in the current\nscope unless the values are identical."));
+ "This " + desc_string + " contains \"" +
+ current_name.as_string() + "\"");
+ err->AppendSubErr(
+ Err(pair.second.value, "defined here.",
+ "Which would clobber the one in your current scope"));
+ err->AppendSubErr(
+ Err(*existing_value, "defined here.",
+ "Executing " + desc_string +
+ " should not conflict with anything "
+ "in the current\nscope unless the values are identical."));
return false;
}
}
@@ -333,12 +339,18 @@
// target defaults.
std::string desc_string(desc_for_err);
*err = Err(node_for_err, "Target defaults collision.",
- "This " + desc_string + " contains target defaults for\n"
- "\"" + current_name + "\" which would clobber one for the\n"
- "same target type in your current scope. It's unfortunate that "
- "I'm too stupid\nto tell you the location of where the target "
- "defaults were set. Usually\nthis happens in the BUILDCONFIG.gn "
- "file or in a related .gni file.\n");
+ "This " + desc_string +
+ " contains target defaults for\n"
+ "\"" +
+ current_name +
+ "\" which would clobber one for the\n"
+ "same target type in your current scope. It's "
+ "unfortunate that "
+ "I'm too stupid\nto tell you the location of where "
+ "the target "
+ "defaults were set. Usually\nthis happens in the "
+ "BUILDCONFIG.gn "
+ "file or in a related .gni file.\n");
return false;
}
}
@@ -357,8 +369,9 @@
// Sources assignment filter present in both the source and the dest.
std::string desc_string(desc_for_err);
*err = Err(node_for_err, "Assignment filter collision.",
- "The " + desc_string + " contains a sources_assignment_filter "
- "which\nwould clobber the one in your current scope.");
+ "The " + desc_string +
+ " contains a sources_assignment_filter "
+ "which\nwould clobber the one in your current scope.");
return false;
}
}
@@ -386,15 +399,16 @@
// same one.
std::string desc_string(desc_for_err);
*err = Err(node_for_err, "Template collision.",
- "This " + desc_string + " contains a template \"" +
- current_name + "\"");
- err->AppendSubErr(Err(pair.second->GetDefinitionRange(),
- "defined here.",
- "Which would clobber the one in your current scope"));
+ "This " + desc_string + " contains a template \"" +
+ current_name + "\"");
+ err->AppendSubErr(
+ Err(pair.second->GetDefinitionRange(), "defined here.",
+ "Which would clobber the one in your current scope"));
err->AppendSubErr(Err(existing_template->GetDefinitionRange(),
- "defined here.",
- "Executing " + desc_string + " should not conflict with anything "
- "in the current\nscope."));
+ "defined here.",
+ "Executing " + desc_string +
+ " should not conflict with anything "
+ "in the current\nscope."));
return false;
}
}
@@ -403,6 +417,10 @@
dest->templates_[current_name] = pair.second;
}
+ // Propogate build dependency files,
+ dest->build_dependency_files_.insert(build_dependency_files_.begin(),
+ build_dependency_files_.end());
+
return true;
}
@@ -501,6 +519,10 @@
return source_dir_;
}
+void Scope::AddBuildDependencyFile(const SourceFile& build_dependency_file) {
+ build_dependency_files_.insert(build_dependency_file);
+}
+
Scope::ItemVector* Scope::GetItemCollector() {
if (item_collector_)
return item_collector_;
diff --git a/tools/gn/scope.h b/tools/gn/scope.h
index 8ad14ed..9e683d2 100644
--- a/tools/gn/scope.h
+++ b/tools/gn/scope.h
@@ -22,6 +22,7 @@
class Item;
class ParseNode;
class Settings;
+class SourceFile;
class Template;
// Scope for the script execution.
@@ -284,6 +285,15 @@
const SourceDir& GetSourceDir() const;
void set_source_dir(const SourceDir& d) { source_dir_ = d; }
+ // Set of files that may affect the execution of this scope. Note that this
+ // set is constructed conservatively, meanining that every file that can
+ // potentially affect this scope is included, but not necessarily every change
+ // to these files will affect this scope.
+ const std::set<SourceFile>& build_dependency_files() const {
+ return build_dependency_files_;
+ }
+ void AddBuildDependencyFile(const SourceFile& build_dependency_file);
+
// The item collector is where Items (Targets, Configs, etc.) go that have
// been defined. If a scope can generate items, this non-owning pointer will
// point to the storage for such items. The creator of this scope will be
@@ -379,6 +389,8 @@
SourceDir source_dir_;
+ std::set<SourceFile> build_dependency_files_;
+
DISALLOW_COPY_AND_ASSIGN(Scope);
};
diff --git a/tools/gn/scope_unittest.cc b/tools/gn/scope_unittest.cc
index a90d725..ce3fe0b 100644
--- a/tools/gn/scope_unittest.cc
+++ b/tools/gn/scope_unittest.cc
@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "tools/gn/scope.h"
+
#include "testing/gtest/include/gtest/gtest.h"
#include "tools/gn/input_file.h"
#include "tools/gn/parse_tree.h"
-#include "tools/gn/scope.h"
+#include "tools/gn/source_file.h"
#include "tools/gn/template.h"
#include "tools/gn/test_with_scope.h"
@@ -22,8 +24,25 @@
return value->string_value() == expected_value;
}
+bool ContainsBuildDependencyFile(const Scope* scope,
+ const SourceFile& source_file) {
+ const auto& build_dependency_files = scope->build_dependency_files();
+ return build_dependency_files.end() !=
+ build_dependency_files.find(source_file);
+}
+
} // namespace
+TEST(Scope, InheritBuildDependencyFilesFromParent) {
+ TestWithScope setup;
+ SourceFile source_file = SourceFile("//a/BUILD.gn");
+ setup.scope()->AddBuildDependencyFile(source_file);
+
+ Scope new_scope(setup.scope());
+ EXPECT_EQ(1U, new_scope.build_dependency_files().size());
+ EXPECT_TRUE(ContainsBuildDependencyFile(&new_scope, source_file));
+}
+
TEST(Scope, NonRecursiveMergeTo) {
TestWithScope setup;
@@ -192,6 +211,24 @@
EXPECT_TRUE(new_scope.CheckForUnusedVars(&err));
EXPECT_FALSE(err.has_error());
}
+
+ // Build dependency files are merged.
+ {
+ Scope from_scope(setup.settings());
+ SourceFile source_file = SourceFile("//a/BUILD.gn");
+ from_scope.AddBuildDependencyFile(source_file);
+
+ Scope to_scope(setup.settings());
+ EXPECT_FALSE(ContainsBuildDependencyFile(&to_scope, source_file));
+
+ Scope::MergeOptions options;
+ Err err;
+ EXPECT_TRUE(from_scope.NonRecursiveMergeTo(&to_scope, options, &assignment,
+ "error", &err));
+ EXPECT_FALSE(err.has_error());
+ EXPECT_EQ(1U, to_scope.build_dependency_files().size());
+ EXPECT_TRUE(ContainsBuildDependencyFile(&to_scope, source_file));
+ }
}
TEST(Scope, MakeClosure) {
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index dea3eae..9bb0b71 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -690,6 +690,7 @@
return false;
}
+ dotfile_scope_.AddBuildDependencyFile(SourceFile("//.gn"));
dotfile_root_->Execute(&dotfile_scope_, &err);
if (err.has_error()) {
err.PrintToStdout();
diff --git a/tools/gn/target.cc b/tools/gn/target.cc
index d65e265..5c5ff5c 100644
--- a/tools/gn/target.cc
+++ b/tools/gn/target.cc
@@ -273,8 +273,10 @@
future, do not rely on this behavior.
)";
-Target::Target(const Settings* settings, const Label& label)
- : Item(settings, label),
+Target::Target(const Settings* settings,
+ const Label& label,
+ const std::set<SourceFile>& build_dependency_files)
+ : Item(settings, label, build_dependency_files),
output_type_(UNKNOWN),
output_prefix_override_(false),
output_extension_set_(false),
diff --git a/tools/gn/target.h b/tools/gn/target.h
index 1890a53..2c9dc35 100644
--- a/tools/gn/target.h
+++ b/tools/gn/target.h
@@ -55,7 +55,11 @@
typedef std::vector<SourceFile> FileList;
typedef std::vector<std::string> StringVector;
- Target(const Settings* settings, const Label& label);
+ // We track the set of build files that may affect this target, please refer
+ // to Scope for how this is determined.
+ Target(const Settings* settings,
+ const Label& label,
+ const std::set<SourceFile>& build_dependency_files = {});
~Target() override;
// Returns a string naming the output type.
diff --git a/tools/gn/target_generator.cc b/tools/gn/target_generator.cc
index 114bca7..c441f04 100644
--- a/tools/gn/target_generator.cc
+++ b/tools/gn/target_generator.cc
@@ -90,8 +90,8 @@
if (g_scheduler->verbose_logging())
g_scheduler->Log("Defining target", label.GetUserVisibleName(true));
- std::unique_ptr<Target> target =
- std::make_unique<Target>(scope->settings(), label);
+ std::unique_ptr<Target> target = std::make_unique<Target>(
+ scope->settings(), label, scope->build_dependency_files());
target->set_defined_from(function_call);
// Create and call out to the proper generator.
diff --git a/tools/gn/toolchain.cc b/tools/gn/toolchain.cc
index ec02b3e..879acd9 100644
--- a/tools/gn/toolchain.cc
+++ b/tools/gn/toolchain.cc
@@ -28,8 +28,10 @@
const char* Toolchain::kToolCompileXCAssets = "compile_xcassets";
const char* Toolchain::kToolAction = "action";
-Toolchain::Toolchain(const Settings* settings, const Label& label)
- : Item(settings, label), setup_complete_(false) {}
+Toolchain::Toolchain(const Settings* settings,
+ const Label& label,
+ const std::set<SourceFile>& build_dependency_files)
+ : Item(settings, label, build_dependency_files), setup_complete_(false) {}
Toolchain::~Toolchain() = default;
diff --git a/tools/gn/toolchain.h b/tools/gn/toolchain.h
index 368c2db..1e9bc2e 100644
--- a/tools/gn/toolchain.h
+++ b/tools/gn/toolchain.h
@@ -77,7 +77,12 @@
// Loader::GetToolchainSettings(). Many toolchain objects may be created in a
// given build, but only a few might be used, and the Loader is in charge of
// this process.
- Toolchain(const Settings* settings, const Label& label);
+ //
+ // We also track the set of build files that may affect this target, please
+ // refer to Scope for how this is determined.
+ Toolchain(const Settings* settings,
+ const Label& label,
+ const std::set<SourceFile>& build_dependency_files = {});
~Toolchain() override;
// Item overrides.