Commit da71ef39 authored by Yuke Liao's avatar Yuke Liao Committed by Commit Bot

[GN] Implements analyzing dependencies between items.

The goal of this CL is to teach GN analyzer to handle build files.

Previous CL:
https://chromium-review.googlesource.com/c/chromium/src/+/838220
implemented tracking build dependency files for each item that
participates in the build dependency tree.

This CL implements analyzing the dependencies between items so as
to recursively decide the set of items/targets that are either
directly or indirectly affected by a list of modified source files
(including build files).

This CL also writes unit tests to verify the new behaviors.

Bug: 795913
Change-Id: I5c123180183246f719248415cdc496a154b5e754
Reviewed-on: https://chromium-review.googlesource.com/851080
Commit-Queue: Yuke Liao <liaoyuke@chromium.org>
Reviewed-by: default avatarDirk Pranke <dpranke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#527646}
parent 889c7e61
This diff is collapsed.
...@@ -10,9 +10,9 @@ ...@@ -10,9 +10,9 @@
#include <vector> #include <vector>
#include "tools/gn/builder.h" #include "tools/gn/builder.h"
#include "tools/gn/item.h"
#include "tools/gn/label.h" #include "tools/gn/label.h"
#include "tools/gn/source_file.h" #include "tools/gn/source_file.h"
#include "tools/gn/target.h"
// An Analyzer can answer questions about a build graph. It is used // An Analyzer can answer questions about a build graph. It is used
// to answer queries for the `refs` and `analyze` commands, where we // to answer queries for the `refs` and `analyze` commands, where we
...@@ -20,11 +20,10 @@ ...@@ -20,11 +20,10 @@
// from just a single Target. // from just a single Target.
class Analyzer { class Analyzer {
public: public:
using LabelSet = std::set<Label>; Analyzer(const Builder& builder,
using SourceFileSet = std::set<const SourceFile*>; const SourceFile& build_config_file,
using TargetSet = std::set<const Target*>; const SourceFile& dot_file,
const std::set<SourceFile>& build_args_dependency_files);
explicit Analyzer(const Builder& builder);
~Analyzer(); ~Analyzer();
// Figures out from a Buider and a JSON-formatted string containing lists // Figures out from a Buider and a JSON-formatted string containing lists
...@@ -35,20 +34,17 @@ class Analyzer { ...@@ -35,20 +34,17 @@ class Analyzer {
std::string Analyze(const std::string& input, Err* err) const; std::string Analyze(const std::string& input, Err* err) const;
private: private:
// Returns the roots of the build graph: the set of targets that // Returns the set of all items that might be affected, directly or
// no other target depends on.
TargetSet& roots() { return roots_; };
// Returns the set of all targets that might be affected, directly or
// indirectly, by modifications to the given source files. // indirectly, by modifications to the given source files.
TargetSet AllAffectedTargets(const SourceFileSet& source_files) const; std::set<const Item*> GetAllAffectedItems(
const std::set<const SourceFile*>& source_files) const;
// Returns the set of labels that do not refer to objects in the graph. // Returns the set of labels that do not refer to objects in the graph.
LabelSet InvalidLabels(const LabelSet& labels) const; std::set<Label> InvalidLabels(const std::set<Label>& labels) const;
// Returns the set of all targets that have a label in the given set. // Returns the set of all targets that have a label in the given set.
// Invalid (or missing) labels will be ignored. // Invalid (or missing) labels will be ignored.
TargetSet TargetsFor(const LabelSet& labels) const; std::set<const Target*> TargetsFor(const std::set<Label>& labels) const;
// Returns a filtered set of the given targets, meaning that for each of the // Returns a filtered set of the given targets, meaning that for each of the
// given targets, // given targets,
...@@ -70,26 +66,39 @@ class Analyzer { ...@@ -70,26 +66,39 @@ class Analyzer {
// ones). // ones).
// //
// This filtering behavior is also known as "pruning" the list of targets. // This filtering behavior is also known as "pruning" the list of targets.
TargetSet Filter(const TargetSet& targets) const; std::set<const Target*> Filter(const std::set<const Target*>& targets) const;
// Filter an individual target and adds the results to filtered // Filter an individual target and adds the results to filtered
// (see Filter(), above). // (see Filter(), above).
void FilterTarget(const Target*, TargetSet* seen, TargetSet* filtered) const; void FilterTarget(const Target*,
std::set<const Target*>* seen,
std::set<const Target*>* filtered) const;
bool TargetRefersToFile(const Target* target, const SourceFile* file) const; bool ItemRefersToFile(const Item* item, const SourceFile* file) const;
void AddTargetsDirectlyReferringToFileTo(const SourceFile* file, void AddItemsDirectlyReferringToFile(
TargetSet* matches) const; const SourceFile* file,
std::set<const Item*>* affected_items) const;
void AddAllRefsTo(const Target* target, TargetSet* matches) const; void AddAllItemsReferringToItem(const Item* item,
std::set<const Item*>* affected_items) const;
std::vector<const Target*> all_targets_; // Main GN files stand for files whose context are used globally to execute
std::map<const Label, const Target*> labels_to_targets_; // every other build files, this list includes dot file, build config file,
// build args files etc.
bool WereMainGNFilesModified(
const std::set<const SourceFile*>& modified_files) const;
std::vector<const Item*> all_items_;
std::map<Label, const Item*> labels_to_items_;
Label default_toolchain_; Label default_toolchain_;
std::set<const Target*> roots_;
// Maps targets to the list of targets that depend on them. // Maps items to the list of items that depend on them.
std::multimap<const Target*, const Target*> dep_map_; std::multimap<const Item*, const Item*> dep_map_;
const SourceFile build_config_file_;
const SourceFile dot_file_;
const std::set<SourceFile> build_args_dependency_files_;
}; };
#endif // TOOLS_GN_ANALYZER_H_ #endif // TOOLS_GN_ANALYZER_H_
This diff is collapsed.
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/sys_info.h" #include "base/sys_info.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "tools/gn/source_file.h"
#include "tools/gn/string_utils.h" #include "tools/gn/string_utils.h"
#include "tools/gn/variables.h" #include "tools/gn/variables.h"
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define TOOLS_GN_ARGS_H_ #define TOOLS_GN_ARGS_H_
#include <map> #include <map>
#include <set>
#include "base/containers/hash_tables.h" #include "base/containers/hash_tables.h"
#include "base/macros.h" #include "base/macros.h"
...@@ -13,6 +14,7 @@ ...@@ -13,6 +14,7 @@
#include "tools/gn/scope.h" #include "tools/gn/scope.h"
class Err; class Err;
class SourceFile;
extern const char kBuildArgs_Help[]; extern const char kBuildArgs_Help[];
...@@ -82,6 +84,17 @@ class Args { ...@@ -82,6 +84,17 @@ class Args {
// map instead of a hash map so the arguements are sorted alphabetically. // map instead of a hash map so the arguements are sorted alphabetically.
ValueWithOverrideMap GetAllArguments() const; ValueWithOverrideMap GetAllArguments() const;
// Returns the set of build files that may affect the build arguments, please
// refer to Scope for how this is determined.
const std::set<SourceFile>& build_args_dependency_files() const {
return build_args_dependency_files_;
}
void set_build_args_dependency_files(
const std::set<SourceFile>& build_args_dependency_files) {
build_args_dependency_files_ = build_args_dependency_files;
}
private: private:
using ArgumentsPerToolchain = using ArgumentsPerToolchain =
base::hash_map<const Settings*, Scope::KeyValueMap>; base::hash_map<const Settings*, Scope::KeyValueMap>;
...@@ -126,6 +139,8 @@ class Args { ...@@ -126,6 +139,8 @@ class Args {
// we see an argument declaration. // we see an argument declaration.
mutable ArgumentsPerToolchain toolchain_overrides_; mutable ArgumentsPerToolchain toolchain_overrides_;
std::set<SourceFile> build_args_dependency_files_;
DISALLOW_ASSIGN(Args); DISALLOW_ASSIGN(Args);
}; };
......
...@@ -138,6 +138,19 @@ std::vector<const BuilderRecord*> Builder::GetAllRecords() const { ...@@ -138,6 +138,19 @@ std::vector<const BuilderRecord*> Builder::GetAllRecords() const {
return result; return result;
} }
std::vector<const Item*> Builder::GetAllResolvedItems() const {
std::vector<const Item*> result;
result.reserve(records_.size());
for (const auto& record : records_) {
if (record.second->type() != BuilderRecord::ITEM_UNKNOWN &&
record.second->should_generate() && record.second->item()) {
result.push_back(record.second->item());
}
}
return result;
}
std::vector<const Target*> Builder::GetAllResolvedTargets() const { std::vector<const Target*> Builder::GetAllResolvedTargets() const {
std::vector<const Target*> result; std::vector<const Target*> result;
result.reserve(records_.size()); result.reserve(records_.size());
......
...@@ -45,6 +45,9 @@ class Builder { ...@@ -45,6 +45,9 @@ class Builder {
std::vector<const BuilderRecord*> GetAllRecords() const; std::vector<const BuilderRecord*> GetAllRecords() const;
// Returns items which should be generated and which are defined.
std::vector<const Item*> GetAllResolvedItems() const;
// Returns targets which should be generated and which are defined. // Returns targets which should be generated and which are defined.
std::vector<const Target*> GetAllResolvedTargets() const; std::vector<const Target*> GetAllResolvedTargets() const;
......
...@@ -110,10 +110,12 @@ int RunAnalyze(const std::vector<std::string>& args) { ...@@ -110,10 +110,12 @@ int RunAnalyze(const std::vector<std::string>& args) {
if (!setup->DoSetup(args[0], false) || !setup->Run()) if (!setup->DoSetup(args[0], false) || !setup->Run())
return 1; return 1;
Analyzer analyzer(setup->builder());
Err err; Err err;
std::string output = Analyzer(setup->builder()).Analyze(input, &err); Analyzer analyzer(
setup->builder(), setup->build_settings().build_config_file(),
setup->GetDotFile(),
setup->build_settings().build_args().build_args_dependency_files());
std::string output = analyzer.Analyze(input, &err);
if (err.has_error()) { if (err.has_error()) {
err.PrintToStdout(); err.PrintToStdout();
return 1; return 1;
......
...@@ -61,6 +61,10 @@ class Item { ...@@ -61,6 +61,10 @@ class Item {
return build_dependency_files_; return build_dependency_files_;
} }
std::set<SourceFile>& build_dependency_files() {
return build_dependency_files_;
}
// Called when this item is resolved, meaning it and all of its dependents // 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 // have no unresolved deps. Returns true on success. Sets the error and
// returns false on failure. // returns false on failure.
...@@ -69,7 +73,7 @@ class Item { ...@@ -69,7 +73,7 @@ class Item {
private: private:
const Settings* settings_; const Settings* settings_;
Label label_; Label label_;
const std::set<SourceFile> build_dependency_files_; std::set<SourceFile> build_dependency_files_;
const ParseNode* defined_from_; const ParseNode* defined_from_;
Visibility visibility_; Visibility visibility_;
......
...@@ -488,6 +488,8 @@ bool Setup::FillArgsFromArgsInputFile() { ...@@ -488,6 +488,8 @@ bool Setup::FillArgsFromArgsInputFile() {
Scope::KeyValueMap overrides; Scope::KeyValueMap overrides;
arg_scope.GetCurrentScopeValues(&overrides); arg_scope.GetCurrentScopeValues(&overrides);
build_settings_.build_args().AddArgOverrides(overrides); build_settings_.build_args().AddArgOverrides(overrides);
build_settings_.build_args().set_build_args_dependency_files(
arg_scope.build_dependency_files());
return true; return true;
} }
......
...@@ -85,6 +85,8 @@ class Setup { ...@@ -85,6 +85,8 @@ class Setup {
Builder& builder() { return builder_; } Builder& builder() { return builder_; }
LoaderImpl* loader() { return loader_.get(); } LoaderImpl* loader() { return loader_.get(); }
const SourceFile& GetDotFile() const { return dotfile_input_file_->name(); }
// Name of the file in the root build directory that contains the build // Name of the file in the root build directory that contains the build
// arguements. // arguements.
static const char kBuildArgFileName[]; static const char kBuildArgFileName[];
......
...@@ -27,6 +27,7 @@ class SourceFile { ...@@ -27,6 +27,7 @@ class SourceFile {
// Takes a known absolute source file. Always begins in a slash. // Takes a known absolute source file. Always begins in a slash.
explicit SourceFile(const base::StringPiece& p); explicit SourceFile(const base::StringPiece& p);
SourceFile(const SourceFile& other) = default;
// Constructs from the given string by swapping in the contents of the given // Constructs from the given string by swapping in the contents of the given
// value. The value will be the empty string after this call. // value. The value will be the empty string after this call.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment