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); +}