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