Add `--filter-with-data` flag for `gn gen --ide=json`
Change-Id: Id043d19973cdc26622faf510e571c5383a2e5b26
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/18660
Reviewed-by: David Turner <digit@google.com>
Commit-Queue: David Turner <digit@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
diff --git a/docs/reference.md b/docs/reference.md
index f8c43a3..91521b7 100644
--- a/docs/reference.md
+++ b/docs/reference.md
@@ -919,6 +919,10 @@
--json-ide-script-args=<argument>
Optional second argument that will be passed to executed script.
+
+ --filter-with-data
+ Additionally follows data deps when filtering. Without this flag, only
+ public and private linked deps will be followed. Only used with --filters.
```
#### **Ninja Outputs**
diff --git a/src/gn/command_gen.cc b/src/gn/command_gen.cc
index d3de0ba..3edee43 100644
--- a/src/gn/command_gen.cc
+++ b/src/gn/command_gen.cc
@@ -76,6 +76,7 @@
const char kSwitchJsonIdeScriptArgs[] = "json-ide-script-args";
const char kSwitchExportCompileCommands[] = "export-compile-commands";
const char kSwitchExportRustProject[] = "export-rust-project";
+const char kSwitchFilterWithData[] = "filter-with-data";
// A map type used to implement --ide=ninja_outputs
using NinjaOutputsMap = NinjaOutputsWriter::MapType;
@@ -359,10 +360,11 @@
std::string exec_script_extra_args =
command_line->GetSwitchValueString(kSwitchJsonIdeScriptArgs);
std::string filters = command_line->GetSwitchValueString(kSwitchFilters);
+ bool filter_with_data = command_line->HasSwitch(kSwitchFilterWithData);
bool res = JSONProjectWriter::RunAndWriteFiles(
build_settings, builder, file_name, exec_script, exec_script_extra_args,
- filters, quiet, err);
+ filters, filter_with_data, quiet, err);
if (res && !quiet) {
OutputString("Generating JSON projects took " +
base::Int64ToString(timer.Elapsed().InMilliseconds()) +
@@ -677,6 +679,10 @@
--json-ide-script-args=<argument>
Optional second argument that will be passed to executed script.
+ --filter-with-data
+ Additionally follows data deps when filtering. Without this flag, only
+ public and private linked deps will be followed. Only used with --filters.
+
Ninja Outputs
The --ninja-outputs-file=<FILE> option dumps a JSON file that maps GN labels
diff --git a/src/gn/json_project_writer.cc b/src/gn/json_project_writer.cc
index 1ea06ff..c69f480 100644
--- a/src/gn/json_project_writer.cc
+++ b/src/gn/json_project_writer.cc
@@ -40,21 +40,26 @@
namespace {
-void AddTargetDependencies(const Target* target, TargetSet* deps) {
- for (const auto& pair : target->GetDeps(Target::DEPS_LINKED)) {
+void AddTargetDependencies(const Target* target, TargetSet* deps,
+ Target::DepsIterationType iteration_type) {
+ for (const auto& pair : target->GetDeps(iteration_type)) {
if (deps->add(pair.ptr)) {
- AddTargetDependencies(pair.ptr, deps);
+ AddTargetDependencies(pair.ptr, deps, iteration_type);
}
}
}
+} // namespace
+
// Filters targets according to filter string; Will also recursively
// add dependent targets.
-bool FilterTargets(const BuildSettings* build_settings,
- std::vector<const Target*>& all_targets,
- std::vector<const Target*>* targets,
- const std::string& dir_filter_string,
- Err* err) {
+bool JSONProjectWriter::FilterTargets(
+ const BuildSettings* build_settings,
+ std::vector<const Target*>& all_targets,
+ std::vector<const Target*>* targets,
+ const std::string& dir_filter_string,
+ bool filter_with_data_deps,
+ Err* err) {
if (dir_filter_string.empty()) {
*targets = all_targets;
} else {
@@ -67,8 +72,10 @@
commands::FilterTargetsByPatterns(all_targets, filters, targets);
TargetSet target_set(targets->begin(), targets->end());
+ Target::DepsIterationType iteration_type =
+ filter_with_data_deps ? Target::DEPS_ALL : Target::DEPS_LINKED;
for (const auto* target : *targets)
- AddTargetDependencies(target, &target_set);
+ AddTargetDependencies(target, &target_set, iteration_type);
targets->assign(target_set.begin(), target_set.end());
}
@@ -83,8 +90,6 @@
return true;
}
-} // namespace
-
bool JSONProjectWriter::RunAndWriteFiles(
const BuildSettings* build_settings,
const Builder& builder,
@@ -92,6 +97,7 @@
const std::string& exec_script,
const std::string& exec_script_extra_args,
const std::string& dir_filter_string,
+ bool filter_with_data_deps,
bool quiet,
Err* err) {
SourceFile output_file = build_settings->build_dir().ResolveRelativeFile(
@@ -104,8 +110,8 @@
std::vector<const Target*> all_targets = builder.GetAllResolvedTargets();
std::vector<const Target*> targets;
- if (!FilterTargets(build_settings, all_targets, &targets, dir_filter_string,
- err)) {
+ if (!JSONProjectWriter::FilterTargets(build_settings, all_targets, &targets, dir_filter_string,
+ filter_with_data_deps, err)) {
return false;
}
diff --git a/src/gn/json_project_writer.h b/src/gn/json_project_writer.h
index 74293a4..0557689 100644
--- a/src/gn/json_project_writer.h
+++ b/src/gn/json_project_writer.h
@@ -20,6 +20,7 @@
const std::string& exec_script,
const std::string& exec_script_extra_args,
const std::string& dir_filter_string,
+ bool filter_with_data_deps,
bool quiet,
Err* err);
@@ -27,6 +28,14 @@
FRIEND_TEST_ALL_PREFIXES(JSONWriter, ActionWithResponseFile);
FRIEND_TEST_ALL_PREFIXES(JSONWriter, ForEachWithResponseFile);
FRIEND_TEST_ALL_PREFIXES(JSONWriter, RustTarget);
+ FRIEND_TEST_ALL_PREFIXES(JSONWriter, FilterTargetsWithDataDeps);
+
+ static bool FilterTargets(const BuildSettings* build_settings,
+ std::vector<const Target*>& all_targets,
+ std::vector<const Target*>* targets,
+ const std::string& dir_filter_string,
+ bool filter_with_data_deps,
+ Err* err);
static StringOutputBuffer GenerateJSON(
const BuildSettings* build_settings,
diff --git a/src/gn/json_project_writer_unittest.cc b/src/gn/json_project_writer_unittest.cc
index 0481d1a..be0d05d 100644
--- a/src/gn/json_project_writer_unittest.cc
+++ b/src/gn/json_project_writer_unittest.cc
@@ -780,3 +780,58 @@
)_";
EXPECT_EQ(expected_json, out) << out;
}
+
+TEST_F(JSONWriter, FilterTargetsWithDataDeps) {
+ Err err;
+ TestWithScope setup;
+
+ // Create targets :a, :b, :c
+ Target target_a(setup.settings(), Label(SourceDir("//foo/"), "a"));
+ target_a.set_output_type(Target::STATIC_LIBRARY);
+ target_a.visibility().SetPublic();
+
+ Target target_b(setup.settings(), Label(SourceDir("//foo/"), "b"));
+ target_b.set_output_type(Target::STATIC_LIBRARY);
+ target_b.visibility().SetPublic();
+
+ Target target_c(setup.settings(), Label(SourceDir("//foo/"), "c"));
+ target_c.set_output_type(Target::STATIC_LIBRARY);
+ target_c.visibility().SetPublic();
+
+ // :a depends on :b, and data_depends on :c
+ target_a.private_deps().push_back(LabelTargetPair(&target_b));
+ target_a.data_deps().push_back(LabelTargetPair(&target_c));
+
+ target_a.SetToolchain(setup.toolchain());
+ target_b.SetToolchain(setup.toolchain());
+ target_c.SetToolchain(setup.toolchain());
+
+ ASSERT_TRUE(target_a.OnResolved(&err));
+ ASSERT_TRUE(target_b.OnResolved(&err));
+ ASSERT_TRUE(target_c.OnResolved(&err));
+
+ std::vector<const Target*> all_targets = {&target_a, &target_b, &target_c};
+ std::vector<const Target*> filtered;
+
+ // Only DEPS_LINKED (should include :a and :b, but not :c)
+ ASSERT_TRUE(JSONProjectWriter::FilterTargets(
+ setup.build_settings(), all_targets, &filtered,
+ "//foo:a", /*filter_with_data_deps=*/false, &err));
+ std::set<Label> labels_linked;
+ for (const Target* t : filtered)
+ labels_linked.insert(t->label());
+ EXPECT_GT(labels_linked.count(Label(SourceDir("//foo/"), "a")), 0u);
+ EXPECT_GT(labels_linked.count(Label(SourceDir("//foo/"), "b")), 0u);
+ EXPECT_EQ(labels_linked.count(Label(SourceDir("//foo/"), "c")), 0u);
+
+ // DEPS_ALL (should include :a, :b, :c)
+ ASSERT_TRUE(JSONProjectWriter::FilterTargets(
+ setup.build_settings(), all_targets, &filtered,
+ "//foo:a", /*filter_with_data_deps=*/true, &err));
+ std::set<Label> labels_all;
+ for (const Target* t : filtered)
+ labels_all.insert(t->label());
+ EXPECT_GT(labels_all.count(Label(SourceDir("//foo/"), "a")), 0u);
+ EXPECT_GT(labels_all.count(Label(SourceDir("//foo/"), "b")), 0u);
+ EXPECT_GT(labels_all.count(Label(SourceDir("//foo/"), "c")), 0u);
+}