[rust-project] Correct sysroot dependencies
liballoc also has a dependency on libcore, which prompted a change
to use a more extensible map of deps, and the separate short-
circuiting of adding a sysroot as well as each crate within it.
Change-Id: I818b3373f4ec6330e2976194b76c81ffbef07c9d
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/8442
Commit-Queue: Petr Hosek <phosek@google.com>
Reviewed-by: Benjamin Brittain <bwb@google.com>
Reviewed-by: Tyler Mandry <tmandry@google.com>
Reviewed-by: Petr Hosek <phosek@google.com>
diff --git a/build/gen.py b/build/gen.py
index 99e06f7..34f349c 100755
--- a/build/gen.py
+++ b/build/gen.py
@@ -652,6 +652,7 @@
'src/gn/input_conversion_unittest.cc',
'src/gn/json_project_writer_unittest.cc',
'src/gn/rust_project_writer_unittest.cc',
+ 'src/gn/rust_project_writer_helpers_unittest.cc',
'src/gn/label_pattern_unittest.cc',
'src/gn/label_unittest.cc',
'src/gn/loader_unittest.cc',
diff --git a/src/gn/rust_project_writer.cc b/src/gn/rust_project_writer.cc
index 8452dae..f78ca2d 100644
--- a/src/gn/rust_project_writer.cc
+++ b/src/gn/rust_project_writer.cc
@@ -13,6 +13,7 @@
#include "gn/deps_iterator.h"
#include "gn/filesystem_utils.h"
#include "gn/ninja_target_command_util.h"
+#include "gn/rust_project_writer_helpers.h"
#include "gn/rust_tool.h"
#include "gn/source_file.h"
#include "gn/string_output_buffer.h"
@@ -72,10 +73,11 @@
return out_buffer.WriteToFile(output_path, err);
}
+// Map of Targets to their index in the crates list (for linking dependencies to
+// their indexes).
using TargetIdxMap = std::unordered_map<const Target*, uint32_t>;
-using SysrootIdxMap =
- std::unordered_map<std::string_view,
- std::unordered_map<std::string_view, uint32_t>>;
+
+// A collection of Targets.
using TargetsVec = UniqueVector<const Target*>;
// Get the Rust deps for a target, recursively expanding OutputType::GROUPS
@@ -105,7 +107,7 @@
TargetIdxMap& lookup,
SysrootIdxMap& sysroot_lookup,
std::ostream& rust_project) {
- bool first = true;
+ bool first_dep = true;
rust_project << " \"deps\": [";
@@ -117,26 +119,26 @@
// TODO(bwb) If this library doesn't depend on std, use core instead
auto std_idx = sysroot_lookup[current_sysroot].find("std");
if (std_idx != sysroot_lookup[current_sysroot].end()) {
- if (!first)
+ if (!first_dep)
rust_project << ",";
rust_project << NEWLINE << " {" NEWLINE
<< " \"crate\": " << std::to_string(std_idx->second)
<< "," NEWLINE << " \"name\": \"std\"" NEWLINE
<< " }";
- first = false;
+ first_dep = false;
}
}
for (const auto& dep : GetRustDeps(target)) {
auto idx = lookup[dep];
- if (!first)
+ if (!first_dep)
rust_project << ",";
rust_project << NEWLINE << " {" NEWLINE
<< " \"crate\": " << std::to_string(idx)
<< "," NEWLINE << " \"name\": \""
<< dep->rust_values().crate_name() << "\"" NEWLINE
<< " }";
- first = false;
+ first_dep = false;
}
rust_project << NEWLINE " ]," NEWLINE;
}
@@ -167,31 +169,40 @@
"rustc_tsan",
"syntax"};
-const std::string_view std_deps[] = {
- "alloc",
- "core",
- "panic_abort",
- "unwind",
-};
+// Multiple sysroot crates have dependenices on each other. This provides a
+// mechanism for specifiying that in an extendible manner.
+const std::unordered_map<std::string_view, std::vector<std::string_view>>
+ sysroot_deps_map = {{"alloc", {"core"}},
+ {"std", {"alloc", "core", "panic_abort", "unwind"}}};
+// Add each of the crates a sysroot has, including their dependencies.
void AddSysrootCrate(const std::string_view crate,
const std::string_view current_sysroot,
uint32_t* count,
- SysrootIdxMap& sysroot_lookup,
+ SysrootCrateIdxMap& sysroot_crate_lookup,
std::ostream& rust_project,
const BuildSettings* build_settings,
- bool first) {
- if (crate == "std") {
- for (auto dep : std_deps) {
- AddSysrootCrate(dep, current_sysroot, count, sysroot_lookup, rust_project,
- build_settings, first);
- first = false;
+ bool first_crate) {
+ if (sysroot_crate_lookup.find(crate) != sysroot_crate_lookup.end()) {
+ // If this sysroot crate is already in the lookup, we don't add it again.
+ return;
+ }
+
+ // Add any crates that this sysroot crate depends on.
+ auto deps_lookup = sysroot_deps_map.find(crate);
+ if (deps_lookup != sysroot_deps_map.end()) {
+ auto deps = (*deps_lookup).second;
+ for (auto dep : deps) {
+ AddSysrootCrate(dep, current_sysroot, count, sysroot_crate_lookup,
+ rust_project, build_settings, first_crate);
+ first_crate = false;
}
}
- if (!first)
+ if (!first_crate)
rust_project << "," NEWLINE;
- sysroot_lookup[current_sysroot].insert(std::make_pair(crate, *count));
+ first_crate = false;
+ sysroot_crate_lookup.insert(std::make_pair(crate, *count));
base::FilePath rebased_out_dir =
build_settings->GetFullPath(build_settings->build_dir());
@@ -208,14 +219,14 @@
rust_project << " \"edition\": \"2018\"," NEWLINE;
rust_project << " \"deps\": [";
(*count)++;
- if (crate == "std") {
- first = true;
- for (auto dep : std_deps) {
- auto idx = sysroot_lookup[current_sysroot][dep];
- if (!first) {
+ if (deps_lookup != sysroot_deps_map.end()) {
+ auto deps = (*deps_lookup).second;
+ bool first_dep = true;
+ for (auto dep : deps) {
+ auto idx = sysroot_crate_lookup[dep];
+ if (!first_dep)
rust_project << ",";
- }
- first = false;
+ first_dep = false;
rust_project << NEWLINE " {" NEWLINE
<< " \"crate\": " << std::to_string(idx)
<< "," NEWLINE " \"name\": \"" << dep
@@ -229,13 +240,33 @@
rust_project << " }";
}
+// Add the given sysroot to the project, if it hasn't already been added.
+void AddSysroot(const std::string_view sysroot,
+ uint32_t* count,
+ SysrootIdxMap& sysroot_lookup,
+ std::ostream& rust_project,
+ const BuildSettings* build_settings,
+ bool first_crate) {
+ // If this sysroot is already in the lookup, we don't add it again.
+ if (sysroot_lookup.find(sysroot) != sysroot_lookup.end()) {
+ return;
+ }
+
+ // Otherwise, add all of its crates
+ for (auto crate : sysroot_crates) {
+ AddSysrootCrate(crate, sysroot, count, sysroot_lookup[sysroot],
+ rust_project, build_settings, first_crate);
+ first_crate = false;
+ }
+}
+
void AddTarget(const Target* target,
uint32_t* count,
TargetIdxMap& lookup,
SysrootIdxMap& sysroot_lookup,
const BuildSettings* build_settings,
std::ostream& rust_project,
- bool first) {
+ bool first_crate) {
if (lookup.find(target) != lookup.end()) {
// If target is already in the lookup, we don't add it again.
return;
@@ -246,24 +277,19 @@
target->toolchain()->GetToolForSourceTypeAsRust(SourceFile::SOURCE_RS);
auto current_sysroot = rust_tool->GetSysroot();
if (current_sysroot != "" && sysroot_lookup.count(current_sysroot) == 0) {
- for (const auto& crate : sysroot_crates) {
- AddSysrootCrate(crate, current_sysroot, count, sysroot_lookup,
- rust_project, build_settings, first);
- first = false;
- }
+ AddSysroot(current_sysroot, count, sysroot_lookup, rust_project,
+ build_settings, first_crate);
+ first_crate = 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;
- }
+ AddTarget(dep, count, lookup, sysroot_lookup, build_settings, rust_project,
+ first_crate);
+ first_crate = false;
}
- if (!first) {
+ if (!first_crate)
rust_project << "," NEWLINE;
- }
// Construct the crate info.
rust_project << " {" NEWLINE;
@@ -306,15 +332,14 @@
}
}
-if (!edition_set)
+ if (!edition_set)
rust_project << " \"edition\": \"2015\"," NEWLINE;
rust_project << " \"cfg\": [";
bool first_cfg = true;
for (const auto& cfg : cfgs) {
- if (!first_cfg) {
+ if (!first_cfg)
rust_project << ",";
- }
first_cfg = false;
rust_project << NEWLINE;
rust_project << " \"" << cfg << "\"";
diff --git a/src/gn/rust_project_writer_helpers.h b/src/gn/rust_project_writer_helpers.h
new file mode 100644
index 0000000..a70b280
--- /dev/null
+++ b/src/gn/rust_project_writer_helpers.h
@@ -0,0 +1,43 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_GN_RUST_PROJECT_WRITER_HELPERS_H_
+#define TOOLS_GN_RUST_PROJECT_WRITER_HELPERS_H_
+
+#include <fstream>
+#include <sstream>
+#include <unordered_map>
+
+#include "build_settings.h"
+#include "gn/target.h"
+
+// These are internal types and helper functions for RustProjectWriter that have
+// been extracted for easier testability.
+
+// Mapping of a sysroot crate (path) to it's index in the crates list.
+using SysrootCrateIdxMap = std::unordered_map<std::string_view, uint32_t>;
+
+// Mapping of a sysroot (path) to the mapping of each of the sysroot crates to
+// their index in the crates list.
+using SysrootIdxMap = std::unordered_map<std::string_view, SysrootCrateIdxMap>;
+
+// Add all of the crates for a sysroot (path) to the rust_project ostream.
+void AddSysroot(const std::string_view sysroot,
+ uint32_t* count,
+ SysrootIdxMap& sysroot_lookup,
+ std::ostream& rust_project,
+ const BuildSettings* build_settings,
+ bool first_crate);
+
+// Add a sysroot crate to the rust_project ostream, first recursively adding its
+// sysroot crate depedencies.
+void AddSysrootCrate(const std::string_view crate,
+ const std::string_view current_sysroot,
+ uint32_t* count,
+ SysrootCrateIdxMap& sysroot_crate_lookup,
+ std::ostream& rust_project,
+ const BuildSettings* build_settings,
+ bool first_crate);
+
+#endif // TOOLS_GN_RUST_PROJECT_WRITER_HELPERS_H_
\ No newline at end of file
diff --git a/src/gn/rust_project_writer_helpers_unittest.cc b/src/gn/rust_project_writer_helpers_unittest.cc
new file mode 100644
index 0000000..bb932ad
--- /dev/null
+++ b/src/gn/rust_project_writer_helpers_unittest.cc
@@ -0,0 +1,231 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gn/rust_project_writer_helpers.h"
+
+#include "base/strings/string_util.h"
+#include "gn/string_output_buffer.h"
+#include "gn/test_with_scheduler.h"
+#include "gn/test_with_scope.h"
+#include "util/build_config.h"
+#include "util/test/test.h"
+
+using RustProjectWriterHelper = TestWithScheduler;
+
+TEST_F(RustProjectWriterHelper, SysrootDepsAreCorrect) {
+ TestWithScope setup;
+
+ SysrootIdxMap sysroot_lookup;
+ uint32_t current_crate_count = 2;
+
+ std::ostringstream stream;
+
+ AddSysroot("path", ¤t_crate_count, sysroot_lookup, stream, setup.build_settings(),
+ false);
+
+ std::string out = stream.str();
+#if defined(OS_WIN)
+ base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
+#endif
+
+const char expected_json[] = ",\n"
+ " {\n"
+ " \"crate_id\": 2,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/libcore/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 3,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/liballoc/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " {\n"
+ " \"crate\": 2,\n"
+ " \"name\": \"core\"\n"
+ " }\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 4,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/libpanic_abort/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 5,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/libunwind/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 6,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/libstd/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " {\n"
+ " \"crate\": 3,\n"
+ " \"name\": \"alloc\"\n"
+ " },\n"
+ " {\n"
+ " \"crate\": 2,\n"
+ " \"name\": \"core\"\n"
+ " },\n"
+ " {\n"
+ " \"crate\": 4,\n"
+ " \"name\": \"panic_abort\"\n"
+ " },\n"
+ " {\n"
+ " \"crate\": 5,\n"
+ " \"name\": \"unwind\"\n"
+ " }\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 7,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/libcollections/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 8,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/liblibc/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 9,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/libpanic_unwind/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 10,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/libproc_macro/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 11,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/librustc_unicode/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 12,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/libstd_unicode/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 13,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/libtest/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 14,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/liballoc_jemalloc/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 15,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/liballoc_system/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 16,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/libcompiler_builtins/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 17,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/libgetopts/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 18,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/libbuild_helper/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 19,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/librustc_asan/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 20,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/librustc_lsan/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 21,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/librustc_msan/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 22,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/librustc_tsan/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " },\n"
+ " {\n"
+ " \"crate_id\": 23,\n"
+ " \"root_module\": \"out/Debug/path/lib/rustlib/src/rust/src/libsyntax/lib.rs\",\n"
+ " \"edition\": \"2018\",\n"
+ " \"deps\": [\n"
+ " ],\n"
+ " \"cfg\": []\n"
+ " }"
+;
+ EXPECT_EQ(expected_json, out);
+}