Skip to content

Commit

Permalink
[rust-project] Remove the emitting of sysroot crates
Browse files Browse the repository at this point in the history
Now that rust-analyzer is able to automatically add the sysroot
crates, if a 'sysroot' value is specified in the file, remove
the addition of the sysroot crates, and let rust-analyzer find
the crates from within the sysroot path specified.

This is more maintainable over time (doesn't duplicate the logic
of finding the sysroot crates), and removes the current double-
addition of the sysroot crates which is breaking rust-analyzer's
ability to locate the implementations of items like Deref<>.

Change-Id: I84db1591525e8b7a5c46952a9d076990eb9c3540
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/14800
Reviewed-by: Dan Johnson <[email protected]>
Reviewed-by: Brett Wilson <[email protected]>
Commit-Queue: Aaron Wood <[email protected]>
  • Loading branch information
woody77 authored and GN LUCI committed Oct 28, 2022
1 parent 11dc0b1 commit a4d67be
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 331 deletions.
148 changes: 22 additions & 126 deletions src/gn/rust_project_writer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
// Current structure of rust-project.json output file
//
// {
// "sysroot": "path/to/rust/sysroot", // if there is only one sysroot found
// "sysroot": "path/to/rust/sysroot",
// "crates": [
// {
// "deps": [
Expand All @@ -45,7 +45,7 @@
// ],
// "exclude_dirs": []
// },
// "edition": "2018", // edition of crate
// "edition": "2021", // edition of crate
// "cfg": [
// "unix", // "atomic" value config options
// "rust_panic=\"abort\""", // key="value" config options
Expand Down Expand Up @@ -162,99 +162,9 @@ std::vector<std::string> FindAllArgValuesAfterPrefix(
return values;
}

// TODO(bwb) Parse sysroot structure from toml files. This is fragile and
// might break if upstream changes the dependency structure.
const std::string_view sysroot_crates[] = {"std",
"core",
"alloc",
"panic_unwind",
"proc_macro",
"test",
"panic_abort",
"unwind"};

// Multiple sysroot crates have dependenices on each other. This provides a
// mechanism for specifying 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 BuildSettings* build_settings,
std::string_view crate,
std::string_view current_sysroot,
SysrootCrateIndexMap& sysroot_crate_lookup,
CrateList& crate_list) {
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(build_settings, dep, current_sysroot,
sysroot_crate_lookup, crate_list);
}
}

size_t crate_index = crate_list.size();
sysroot_crate_lookup.insert(std::make_pair(crate, crate_index));

base::FilePath rebased_out_dir =
build_settings->GetFullPath(build_settings->build_dir());
auto crate_path =
FilePathToUTF8(rebased_out_dir) + std::string(current_sysroot) +
"/lib/rustlib/src/rust/library/" + std::string(crate) + "/src/lib.rs";

Crate sysroot_crate = Crate(SourceFile(crate_path), std::nullopt, crate_index,
std::string(crate), "2018");

sysroot_crate.AddConfigItem("debug_assertions");

if (deps_lookup != sysroot_deps_map.end()) {
auto deps = (*deps_lookup).second;
for (auto dep : deps) {
auto idx = sysroot_crate_lookup[dep];
sysroot_crate.AddDependency(idx, std::string(dep));
}
}

crate_list.push_back(sysroot_crate);
}

// Add the given sysroot to the project, if it hasn't already been added.
void AddSysroot(const BuildSettings* build_settings,
std::string_view sysroot,
SysrootIndexMap& sysroot_lookup,
CrateList& crate_list) {
// 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(build_settings, crate, sysroot, sysroot_lookup[sysroot],
crate_list);
}
}

void AddSysrootDependencyToCrate(Crate* crate,
const SysrootCrateIndexMap& sysroot,
std::string_view crate_name) {
if (const auto crate_idx = sysroot.find(crate_name);
crate_idx != sysroot.end()) {
crate->AddDependency(crate_idx->second, std::string(crate_name));
}
}

void AddTarget(const BuildSettings* build_settings,
const Target* target,
TargetIndexMap& lookup,
SysrootIndexMap& sysroot_lookup,
CrateList& crate_list) {
if (lookup.find(target) != lookup.end()) {
// If target is already in the lookup, we don't add it again.
Expand All @@ -263,21 +173,11 @@ void AddTarget(const BuildSettings* build_settings,

auto compiler_args = ExtractCompilerArgs(target);
auto compiler_target = FindArgValue("--target", compiler_args);

// Check what sysroot this target needs. Add it to the crate list if it
// hasn't already been added.
auto rust_tool =
target->toolchain()->GetToolForTargetFinalOutputAsRust(target);
auto current_sysroot = rust_tool->GetSysroot();
if (current_sysroot != "" && sysroot_lookup.count(current_sysroot) == 0) {
AddSysroot(build_settings, current_sysroot, sysroot_lookup, crate_list);
}

auto crate_deps = GetRustDeps(target);

// Add all dependencies of this crate, before this crate.
for (const auto& dep : crate_deps) {
AddTarget(build_settings, dep, lookup, sysroot_lookup, crate_list);
AddTarget(build_settings, dep, lookup, crate_list);
}

// The index of a crate is its position (0-based) in the list of crates.
Expand Down Expand Up @@ -314,21 +214,9 @@ void AddTarget(const BuildSettings* build_settings,
crate.AddConfigItem(cfg);
}

// Add the sysroot dependencies, if there is one.
if (current_sysroot != "") {
const auto& sysroot = sysroot_lookup[current_sysroot];
AddSysrootDependencyToCrate(&crate, sysroot, "core");
AddSysrootDependencyToCrate(&crate, sysroot, "alloc");
AddSysrootDependencyToCrate(&crate, sysroot, "std");

// Proc macros have the proc_macro crate as a direct dependency
if (std::string_view(rust_tool->name()) ==
std::string_view(RustTool::kRsToolMacro)) {
AddSysrootDependencyToCrate(&crate, sysroot, "proc_macro");
}
}

// If it's a proc macro, record its output location so IDEs can invoke it.
auto rust_tool =
target->toolchain()->GetToolForTargetFinalOutputAsRust(target);
if (std::string_view(rust_tool->name()) ==
std::string_view(RustTool::kRsToolMacro)) {
auto outputs = target->computed_outputs();
Expand Down Expand Up @@ -359,19 +247,18 @@ void AddTarget(const BuildSettings* build_settings,

void WriteCrates(const BuildSettings* build_settings,
CrateList& crate_list,
SysrootIndexMap& sysroots,
std::optional<std::string>& sysroot,
std::ostream& rust_project) {
rust_project << "{" NEWLINE;

// If there is one, and only one, sysroot found, then that can be used to tell
// rust-analyzer where to find the sysroot (and associated tools like the
// If a sysroot was found, then that can be used to tell rust-analyzer where
// to find the sysroot (and associated tools like the
// 'rust-analyzer-proc-macro-srv` proc-macro server that matches the abi used
// by 'rustc'
if (sysroots.size() == 1) {
auto sysroot = sysroots.begin()->first;
if (sysroot.has_value()) {
base::FilePath rebased_out_dir =
build_settings->GetFullPath(build_settings->build_dir());
auto sysroot_path = FilePathToUTF8(rebased_out_dir) + std::string(sysroot);
auto sysroot_path = FilePathToUTF8(rebased_out_dir) + sysroot.value();
rust_project << " \"sysroot\": \"" << sysroot_path << "\"," NEWLINE;
}

Expand Down Expand Up @@ -503,16 +390,25 @@ void RustProjectWriter::RenderJSON(const BuildSettings* build_settings,
std::vector<const Target*>& all_targets,
std::ostream& rust_project) {
TargetIndexMap lookup;
SysrootIndexMap sysroot_lookup;
CrateList crate_list;
std::optional<std::string> rust_sysroot;

// All the crates defined in the project.
for (const auto* target : all_targets) {
if (!target->IsBinary() || !target->source_types_used().RustSourceUsed())
continue;

AddTarget(build_settings, target, lookup, sysroot_lookup, crate_list);
AddTarget(build_settings, target, lookup, crate_list);

// If a sysroot hasn't been found, see if we can find one using this target.
if (!rust_sysroot.has_value()) {
auto rust_tool =
target->toolchain()->GetToolForTargetFinalOutputAsRust(target);
auto sysroot = rust_tool->GetSysroot();
if (sysroot != "")
rust_sysroot = sysroot;
}
}

WriteCrates(build_settings, crate_list, sysroot_lookup, rust_project);
WriteCrates(build_settings, crate_list, rust_sysroot, rust_project);
}
17 changes: 1 addition & 16 deletions src/gn/rust_project_writer_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,26 +125,11 @@ class Crate {

using CrateList = std::vector<Crate>;

// Mapping of a sysroot crate (path) to it's index in the crates list.
using SysrootCrateIndexMap = std::unordered_map<std::string_view, CrateIndex>;

// Mapping of a sysroot (path) to the mapping of each of the sysroot crates to
// their index in the crates list.
using SysrootIndexMap =
std::unordered_map<std::string_view, SysrootCrateIndexMap>;

// Add all of the crates for a sysroot (path) to the rust_project ostream.
// Add the given sysroot to the project, if it hasn't already been added.
void AddSysroot(const BuildSettings* build_settings,
std::string_view sysroot,
SysrootIndexMap& sysroot_lookup,
CrateList& crate_list);

// Write the entire rust-project.json file contents into the given stream, based
// on the the given crates list.
void WriteCrates(const BuildSettings* build_settings,
CrateList& crate_list,
SysrootIndexMap& sysroot_lookup,
std::optional<std::string>& sysroot,
std::ostream& rust_project);

// Assemble the compiler arguments for the given GN Target.
Expand Down
Loading

0 comments on commit a4d67be

Please sign in to comment.