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