[rust-project] Only list direct dependencies, not transitive deps For each target in the file, only list that target's direct dependencies and not the transitive dependencies. Add a "label" field to each crate entry to specifiy which GN target the rust crate corresponds to (debugging aid). Change-Id: I59074ef7af647a7095db6cec6579aa8f2530c354 Reviewed-on: https://gn-review.googlesource.com/c/gn/+/8440 Reviewed-by: Benjamin Brittain <bwb@google.com> Commit-Queue: Benjamin Brittain <bwb@google.com>
diff --git a/src/gn/rust_project_writer.cc b/src/gn/rust_project_writer.cc index 19eb426..0c238ce 100644 --- a/src/gn/rust_project_writer.cc +++ b/src/gn/rust_project_writer.cc
@@ -10,6 +10,7 @@ #include "base/json/string_escape.h" #include "gn/builder.h" +#include "gn/deps_iterator.h" #include "gn/filesystem_utils.h" #include "gn/ninja_target_command_util.h" #include "gn/rust_tool.h" @@ -75,6 +76,30 @@ using SysrootIdxMap = std::unordered_map<std::string_view, std::unordered_map<std::string_view, uint32_t>>; +using TargetsVec = UniqueVector<const Target*>; + +// Get the Rust deps for a target, recursively expanding OutputType::GROUPS +// that are present in the GN structure. This will return a flattened list of +// deps from the groups, but will not expand a Rust lib dependency to find any +// transitive Rust dependencies. +void GetRustDeps(const Target* target, TargetsVec* rust_deps) { + for (const auto& pair : target->GetDeps(Target::DEPS_LINKED)) { + const Target* dep = pair.ptr; + + if (dep->source_types_used().RustSourceUsed()) { + // Include any Rust dep. + rust_deps->push_back(dep); + } else if (dep->output_type() == Target::OutputType::GROUP) { + // Inspect (recursively) any group to see if it contains Rust deps. + GetRustDeps(dep, rust_deps); + } + } +} +TargetsVec GetRustDeps(const Target* target) { + TargetsVec deps; + GetRustDeps(target, &deps); + return deps; +} void WriteDeps(const Target* target, TargetIdxMap& lookup, @@ -102,7 +127,7 @@ } } - for (const auto& dep : target->rust_values().transitive_libs().GetOrdered()) { + for (const auto& dep : GetRustDeps(target)) { auto idx = lookup[dep]; if (!first) rust_project << ","; @@ -228,11 +253,12 @@ } } - // Add each dependency first before we write any of the parent target. - for (const auto& dep : target->rust_values().transitive_libs().GetOrdered()) { - AddTarget(dep, count, lookup, sysroot_lookup, build_settings, rust_project, - first); - first = false; + for (const auto& dep : GetRustDeps(target)) { + if (dep->source_types_used().RustSourceUsed()) { + AddTarget(dep, count, lookup, sysroot_lookup, build_settings, + rust_project, first); + first = false; + } } if (!first) { @@ -253,6 +279,8 @@ rust_project << " \"root_module\": \"" << FilePathToUTF8(crate_root) << "\"," NEWLINE; + rust_project << " \"label\": \"" + << target->label().GetUserVisibleName(false) << "\"," NEWLINE; WriteDeps(target, lookup, sysroot_lookup, rust_project);
diff --git a/src/gn/rust_project_writer_unittest.cc b/src/gn/rust_project_writer_unittest.cc index 1d8d153..e43641d 100644 --- a/src/gn/rust_project_writer_unittest.cc +++ b/src/gn/rust_project_writer_unittest.cc
@@ -43,6 +43,7 @@ " {\n" " \"crate_id\": 0,\n" " \"root_module\": \"foo/lib.rs\",\n" + " \"label\": \"//foo:bar\",\n" " \"deps\": [\n" " ],\n" " \"edition\": \"2015\",\n" @@ -98,6 +99,7 @@ " {\n" " \"crate_id\": 0,\n" " \"root_module\": \"tortoise/lib.rs\",\n" + " \"label\": \"//tortoise:bar\",\n" " \"deps\": [\n" " ],\n" " \"edition\": \"2015\",\n" @@ -109,6 +111,7 @@ " {\n" " \"crate_id\": 1,\n" " \"root_module\": \"hare/lib.rs\",\n" + " \"label\": \"//hare:bar\",\n" " \"deps\": [\n" " {\n" " \"crate\": 0,\n" @@ -179,6 +182,7 @@ " {\n" " \"crate_id\": 0,\n" " \"root_module\": \"tortoise/lib.rs\",\n" + " \"label\": \"//tortoise:bar\",\n" " \"deps\": [\n" " ],\n" " \"edition\": \"2015\",\n" @@ -190,6 +194,7 @@ " {\n" " \"crate_id\": 1,\n" " \"root_module\": \"achilles/lib.rs\",\n" + " \"label\": \"//achilles:bar\",\n" " \"deps\": [\n" " ],\n" " \"edition\": \"2015\",\n" @@ -201,6 +206,7 @@ " {\n" " \"crate_id\": 2,\n" " \"root_module\": \"hare/lib.rs\",\n" + " \"label\": \"//hare:bar\",\n" " \"deps\": [\n" " {\n" " \"crate\": 0,\n" @@ -221,3 +227,117 @@ "}\n"; EXPECT_EQ(expected_json, out); } + +// Test that when outputting dependencies, only Rust deps are returned, +// and that any groups are inspected to see if they include Rust deps. +TEST_F(RustProjectJSONWriter, RustTargetGetDepRustOnly) { + Err err; + TestWithScope setup; + + Target dep(setup.settings(), Label(SourceDir("//tortoise/"), "bar")); + dep.set_output_type(Target::RUST_LIBRARY); + dep.visibility().SetPublic(); + SourceFile tlib("//tortoise/lib.rs"); + dep.sources().push_back(tlib); + dep.source_types_used().Set(SourceFile::SOURCE_RS); + dep.rust_values().set_crate_root(tlib); + dep.rust_values().crate_name() = "tortoise"; + dep.SetToolchain(setup.toolchain()); + + Target dep2(setup.settings(), Label(SourceDir("//achilles/"), "bar")); + dep2.set_output_type(Target::STATIC_LIBRARY); + dep2.visibility().SetPublic(); + SourceFile alib("//achilles/lib.o"); + dep2.SetToolchain(setup.toolchain()); + + Target dep3(setup.settings(), Label(SourceDir("//achilles/"), "group")); + dep3.set_output_type(Target::GROUP); + dep3.visibility().SetPublic(); + dep3.public_deps().push_back(LabelTargetPair(&dep)); + dep3.SetToolchain(setup.toolchain()); + + Target dep4(setup.settings(), Label(SourceDir("//tortoise/"), "macro")); + dep4.set_output_type(Target::RUST_PROC_MACRO); + dep4.visibility().SetPublic(); + SourceFile tmlib("//tortoise/macro/lib.rs"); + dep4.sources().push_back(tmlib); + dep4.source_types_used().Set(SourceFile::SOURCE_RS); + dep4.rust_values().set_crate_root(tmlib); + dep4.rust_values().crate_name() = "tortoise_macro"; + dep4.SetToolchain(setup.toolchain()); + + Target target(setup.settings(), Label(SourceDir("//hare/"), "bar")); + target.set_output_type(Target::RUST_LIBRARY); + target.visibility().SetPublic(); + SourceFile harelib("//hare/lib.rs"); + target.sources().push_back(harelib); + target.source_types_used().Set(SourceFile::SOURCE_RS); + target.rust_values().set_crate_root(harelib); + target.rust_values().crate_name() = "hare"; + target.public_deps().push_back(LabelTargetPair(&dep)); + target.public_deps().push_back(LabelTargetPair(&dep3)); + target.public_deps().push_back(LabelTargetPair(&dep4)); + target.SetToolchain(setup.toolchain()); + ASSERT_TRUE(target.OnResolved(&err)); + + std::ostringstream stream; + std::vector<const Target*> targets; + targets.push_back(&target); + RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream); + std::string out = stream.str(); +#if defined(OS_WIN) + base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n"); +#endif + const char expected_json[] = + "{\n" + " \"roots\": [],\n" + " \"crates\": [\n" + " {\n" + " \"crate_id\": 0,\n" + " \"root_module\": \"tortoise/lib.rs\",\n" + " \"label\": \"//tortoise:bar\",\n" + " \"deps\": [\n" + " ],\n" + " \"edition\": \"2015\",\n" + " \"atom_cfgs\": [\n" + " ],\n" + " \"key_value_cfgs\": {\n" + " }\n" + " },\n" + " {\n" + " \"crate_id\": 1,\n" + " \"root_module\": \"tortoise/macro/lib.rs\",\n" + " \"label\": \"//tortoise:macro\",\n" + " \"deps\": [\n" + " ],\n" + " \"edition\": \"2015\",\n" + " \"atom_cfgs\": [\n" + " ],\n" + " \"key_value_cfgs\": {\n" + " }\n" + " },\n" + " {\n" + " \"crate_id\": 2,\n" + " \"root_module\": \"hare/lib.rs\",\n" + " \"label\": \"//hare:bar\",\n" + " \"deps\": [\n" + " {\n" + " \"crate\": 0,\n" + " \"name\": \"tortoise\"\n" + " },\n" + " {\n" + " \"crate\": 1,\n" + " \"name\": \"tortoise_macro\"\n" + " }\n" + " ],\n" + " \"edition\": \"2015\",\n" + " \"atom_cfgs\": [\n" + " ],\n" + " \"key_value_cfgs\": {\n" + " }\n" + " }\n" + " ]\n" + "}\n"; + + EXPECT_EQ(expected_json, out); +}