mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Auto merge of #16356 - Veykril:sysroot-metadata, r=Veykril
internal: Add unstable config for loading the sysroot sources via `cargo metadata` cc https://github.com/rust-lang/rust-analyzer/issues/7637 This takes the approach of having `cargo metadata` generate a lock file that we then delete again, hence why this is behind a flag. If people need this for their workflow they can just enable it, if not, they are probably better off keeping it disabled. [example](https://dreampuf.github.io/GraphvizOnline/#digraph%20rust_analyzer_crate_graph%20%7B%0A%20%20%20%20_0%5Blabel%3D%22core%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_17%5Blabel%3D%22ra_playground%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_14%5Blabel%3D%22getopts%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_11%5Blabel%3D%22std_detect%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_8%5Blabel%3D%22unwind%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_5%5Blabel%3D%22hashbrown%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_2%5Blabel%3D%22alloc%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_16%5Blabel%3D%22test%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_13%5Blabel%3D%22unicode_width%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_10%5Blabel%3D%22rustc_demangle%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_7%5Blabel%3D%22panic_abort%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_4%5Blabel%3D%22cfg_if%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_1%5Blabel%3D%22compiler_builtins%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_18%5Blabel%3D%22build_script_build%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_15%5Blabel%3D%22proc_macro%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_12%5Blabel%3D%22std%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_9%5Blabel%3D%22panic_unwind%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_6%5Blabel%3D%22libc%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_3%5Blabel%3D%22allocator_api2%22%5D%5Bshape%3D%22box%22%5D%3B%0A%20%20%20%20_17%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_17%20-%3E%20_2%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_17%20-%3E%20_12%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_17%20-%3E%20_15%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_17%20-%3E%20_16%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_14%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_14%20-%3E%20_12%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_14%20-%3E%20_13%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_11%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_11%20-%3E%20_1%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_11%20-%3E%20_2%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_11%20-%3E%20_4%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_11%20-%3E%20_6%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_8%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_8%20-%3E%20_1%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_8%20-%3E%20_4%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_8%20-%3E%20_6%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_5%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_5%20-%3E%20_1%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_5%20-%3E%20_2%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_5%20-%3E%20_3%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_2%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_2%20-%3E%20_1%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_16%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_16%20-%3E%20_7%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_16%20-%3E%20_9%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_16%20-%3E%20_12%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_16%20-%3E%20_14%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_13%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_13%20-%3E%20_1%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_13%20-%3E%20_12%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_10%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_10%20-%3E%20_1%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_7%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_7%20-%3E%20_1%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_7%20-%3E%20_2%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_7%20-%3E%20_4%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_7%20-%3E%20_6%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_1%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_18%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_18%20-%3E%20_2%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_18%20-%3E%20_12%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_18%20-%3E%20_15%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_18%20-%3E%20_16%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_15%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_15%20-%3E%20_12%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_12%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_12%20-%3E%20_1%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_12%20-%3E%20_2%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_12%20-%3E%20_4%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_12%20-%3E%20_4%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_12%20-%3E%20_5%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_12%20-%3E%20_6%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_12%20-%3E%20_7%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_12%20-%3E%20_8%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_12%20-%3E%20_9%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_12%20-%3E%20_10%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_12%20-%3E%20_11%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_9%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_9%20-%3E%20_1%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_9%20-%3E%20_2%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_9%20-%3E%20_4%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_9%20-%3E%20_6%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_9%20-%3E%20_8%5Blabel%3D%22%22%5D%3B%0A%20%20%20%20_6%20-%3E%20_0%5Blabel%3D%22%22%5D%3B%0A%7D%0A) ![image](https://github.com/rust-lang/rust-analyzer/assets/3757771/7709bb38-d948-4106-82c2-9b76677620bd) hashbrown resolves as a dependency now
This commit is contained in:
commit
a616c4d117
11 changed files with 507 additions and 249 deletions
|
@ -9,7 +9,7 @@
|
||||||
use std::{fmt, mem, ops, str::FromStr};
|
use std::{fmt, mem, ops, str::FromStr};
|
||||||
|
|
||||||
use cfg::CfgOptions;
|
use cfg::CfgOptions;
|
||||||
use la_arena::{Arena, Idx};
|
use la_arena::{Arena, Idx, RawIdx};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
|
@ -157,6 +157,10 @@ impl CrateOrigin {
|
||||||
pub fn is_lib(&self) -> bool {
|
pub fn is_lib(&self) -> bool {
|
||||||
matches!(self, CrateOrigin::Library { .. })
|
matches!(self, CrateOrigin::Library { .. })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_lang(&self) -> bool {
|
||||||
|
matches!(self, CrateOrigin::Lang { .. })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
@ -174,7 +178,7 @@ impl From<&str> for LangCrateOrigin {
|
||||||
match s {
|
match s {
|
||||||
"alloc" => LangCrateOrigin::Alloc,
|
"alloc" => LangCrateOrigin::Alloc,
|
||||||
"core" => LangCrateOrigin::Core,
|
"core" => LangCrateOrigin::Core,
|
||||||
"proc-macro" => LangCrateOrigin::ProcMacro,
|
"proc-macro" | "proc_macro" => LangCrateOrigin::ProcMacro,
|
||||||
"std" => LangCrateOrigin::Std,
|
"std" => LangCrateOrigin::Std,
|
||||||
"test" => LangCrateOrigin::Test,
|
"test" => LangCrateOrigin::Test,
|
||||||
_ => LangCrateOrigin::Other,
|
_ => LangCrateOrigin::Other,
|
||||||
|
@ -522,7 +526,7 @@ impl CrateGraph {
|
||||||
self.arena.iter().map(|(idx, _)| idx)
|
self.arena.iter().map(|(idx, _)| idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: used for `handle_hack_cargo_workspace`, should be removed later
|
// FIXME: used for fixing up the toolchain sysroot, should be removed and done differently
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = (CrateId, &mut CrateData)> + '_ {
|
pub fn iter_mut(&mut self) -> impl Iterator<Item = (CrateId, &mut CrateData)> + '_ {
|
||||||
self.arena.iter_mut()
|
self.arena.iter_mut()
|
||||||
|
@ -619,7 +623,12 @@ impl CrateGraph {
|
||||||
/// This will deduplicate the crates of the graph where possible.
|
/// This will deduplicate the crates of the graph where possible.
|
||||||
/// Note that for deduplication to fully work, `self`'s crate dependencies must be sorted by crate id.
|
/// Note that for deduplication to fully work, `self`'s crate dependencies must be sorted by crate id.
|
||||||
/// If the crate dependencies were sorted, the resulting graph from this `extend` call will also have the crate dependencies sorted.
|
/// If the crate dependencies were sorted, the resulting graph from this `extend` call will also have the crate dependencies sorted.
|
||||||
pub fn extend(&mut self, mut other: CrateGraph, proc_macros: &mut ProcMacroPaths) {
|
pub fn extend(
|
||||||
|
&mut self,
|
||||||
|
mut other: CrateGraph,
|
||||||
|
proc_macros: &mut ProcMacroPaths,
|
||||||
|
on_finished: impl FnOnce(&FxHashMap<CrateId, CrateId>),
|
||||||
|
) {
|
||||||
let topo = other.crates_in_topological_order();
|
let topo = other.crates_in_topological_order();
|
||||||
let mut id_map: FxHashMap<CrateId, CrateId> = FxHashMap::default();
|
let mut id_map: FxHashMap<CrateId, CrateId> = FxHashMap::default();
|
||||||
for topo in topo {
|
for topo in topo {
|
||||||
|
@ -670,6 +679,8 @@ impl CrateGraph {
|
||||||
|
|
||||||
*proc_macros =
|
*proc_macros =
|
||||||
mem::take(proc_macros).into_iter().map(|(id, macros)| (id_map[&id], macros)).collect();
|
mem::take(proc_macros).into_iter().map(|(id, macros)| (id_map[&id], macros)).collect();
|
||||||
|
|
||||||
|
on_finished(&id_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_path(
|
fn find_path(
|
||||||
|
@ -721,6 +732,29 @@ impl CrateGraph {
|
||||||
fn hacky_find_crate<'a>(&'a self, display_name: &'a str) -> impl Iterator<Item = CrateId> + 'a {
|
fn hacky_find_crate<'a>(&'a self, display_name: &'a str) -> impl Iterator<Item = CrateId> + 'a {
|
||||||
self.iter().filter(move |it| self[*it].display_name.as_deref() == Some(display_name))
|
self.iter().filter(move |it| self[*it].display_name.as_deref() == Some(display_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes all crates from this crate graph except for the ones in `to_keep` and fixes up the dependencies.
|
||||||
|
/// Returns a mapping from old crate ids to new crate ids.
|
||||||
|
pub fn remove_crates_except(&mut self, to_keep: &[CrateId]) -> Vec<Option<CrateId>> {
|
||||||
|
let mut id_map = vec![None; self.arena.len()];
|
||||||
|
self.arena = std::mem::take(&mut self.arena)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(id, data)| if to_keep.contains(&id) { Some((id, data)) } else { None })
|
||||||
|
.enumerate()
|
||||||
|
.map(|(new_id, (id, data))| {
|
||||||
|
id_map[id.into_raw().into_u32() as usize] =
|
||||||
|
Some(CrateId::from_raw(RawIdx::from_u32(new_id as u32)));
|
||||||
|
data
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
for (_, data) in self.arena.iter_mut() {
|
||||||
|
data.dependencies.iter_mut().for_each(|dep| {
|
||||||
|
dep.crate_id =
|
||||||
|
id_map[dep.crate_id.into_raw().into_u32() as usize].expect("crate was filtered")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
id_map
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Index<CrateId> for CrateGraph {
|
impl ops::Index<CrateId> for CrateGraph {
|
||||||
|
|
|
@ -82,6 +82,8 @@ pub struct CargoConfig {
|
||||||
pub target: Option<String>,
|
pub target: Option<String>,
|
||||||
/// Sysroot loading behavior
|
/// Sysroot loading behavior
|
||||||
pub sysroot: Option<RustLibSource>,
|
pub sysroot: Option<RustLibSource>,
|
||||||
|
/// Whether to invoke `cargo metadata` on the sysroot crate.
|
||||||
|
pub sysroot_query_metadata: bool,
|
||||||
pub sysroot_src: Option<AbsPathBuf>,
|
pub sysroot_src: Option<AbsPathBuf>,
|
||||||
/// rustc private crate source
|
/// rustc private crate source
|
||||||
pub rustc_source: Option<RustLibSource>,
|
pub rustc_source: Option<RustLibSource>,
|
||||||
|
|
|
@ -8,6 +8,7 @@ use std::{env, fs, iter, ops, path::PathBuf, process::Command};
|
||||||
|
|
||||||
use anyhow::{format_err, Context, Result};
|
use anyhow::{format_err, Context, Result};
|
||||||
use base_db::CrateName;
|
use base_db::CrateName;
|
||||||
|
use itertools::Itertools;
|
||||||
use la_arena::{Arena, Idx};
|
use la_arena::{Arena, Idx};
|
||||||
use paths::{AbsPath, AbsPathBuf};
|
use paths::{AbsPath, AbsPathBuf};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
@ -18,25 +19,61 @@ use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath};
|
||||||
pub struct Sysroot {
|
pub struct Sysroot {
|
||||||
root: AbsPathBuf,
|
root: AbsPathBuf,
|
||||||
src_root: AbsPathBuf,
|
src_root: AbsPathBuf,
|
||||||
|
mode: SysrootMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub(crate) enum SysrootMode {
|
||||||
|
Workspace(CargoWorkspace),
|
||||||
|
Stitched(Stitched),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub(crate) struct Stitched {
|
||||||
crates: Arena<SysrootCrateData>,
|
crates: Arena<SysrootCrateData>,
|
||||||
/// Stores the result of `cargo metadata` of the `RA_UNSTABLE_SYSROOT_HACK` workspace.
|
}
|
||||||
pub hack_cargo_workspace: Option<CargoWorkspace>,
|
|
||||||
|
impl ops::Index<SysrootCrate> for Stitched {
|
||||||
|
type Output = SysrootCrateData;
|
||||||
|
fn index(&self, index: SysrootCrate) -> &SysrootCrateData {
|
||||||
|
&self.crates[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stitched {
|
||||||
|
pub(crate) fn public_deps(&self) -> impl Iterator<Item = (CrateName, SysrootCrate, bool)> + '_ {
|
||||||
|
// core is added as a dependency before std in order to
|
||||||
|
// mimic rustcs dependency order
|
||||||
|
["core", "alloc", "std"]
|
||||||
|
.into_iter()
|
||||||
|
.zip(iter::repeat(true))
|
||||||
|
.chain(iter::once(("test", false)))
|
||||||
|
.filter_map(move |(name, prelude)| {
|
||||||
|
Some((CrateName::new(name).unwrap(), self.by_name(name)?, prelude))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn proc_macro(&self) -> Option<SysrootCrate> {
|
||||||
|
self.by_name("proc_macro")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn crates(&self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + '_ {
|
||||||
|
self.crates.iter().map(|(id, _data)| id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn by_name(&self, name: &str) -> Option<SysrootCrate> {
|
||||||
|
let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?;
|
||||||
|
Some(id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type SysrootCrate = Idx<SysrootCrateData>;
|
pub(crate) type SysrootCrate = Idx<SysrootCrateData>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct SysrootCrateData {
|
pub(crate) struct SysrootCrateData {
|
||||||
pub name: String,
|
pub(crate) name: String,
|
||||||
pub root: ManifestPath,
|
pub(crate) root: ManifestPath,
|
||||||
pub deps: Vec<SysrootCrate>,
|
pub(crate) deps: Vec<SysrootCrate>,
|
||||||
}
|
|
||||||
|
|
||||||
impl ops::Index<SysrootCrate> for Sysroot {
|
|
||||||
type Output = SysrootCrateData;
|
|
||||||
fn index(&self, index: SysrootCrate) -> &SysrootCrateData {
|
|
||||||
&self.crates[index]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sysroot {
|
impl Sysroot {
|
||||||
|
@ -53,32 +90,19 @@ impl Sysroot {
|
||||||
&self.src_root
|
&self.src_root
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn public_deps(&self) -> impl Iterator<Item = (CrateName, SysrootCrate, bool)> + '_ {
|
|
||||||
// core is added as a dependency before std in order to
|
|
||||||
// mimic rustcs dependency order
|
|
||||||
["core", "alloc", "std"]
|
|
||||||
.into_iter()
|
|
||||||
.zip(iter::repeat(true))
|
|
||||||
.chain(iter::once(("test", false)))
|
|
||||||
.filter_map(move |(name, prelude)| {
|
|
||||||
Some((CrateName::new(name).unwrap(), self.by_name(name)?, prelude))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn proc_macro(&self) -> Option<SysrootCrate> {
|
|
||||||
self.by_name("proc_macro")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn crates(&self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + '_ {
|
|
||||||
self.crates.iter().map(|(id, _data)| id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.crates.is_empty()
|
match &self.mode {
|
||||||
|
SysrootMode::Workspace(ws) => ws.packages().next().is_none(),
|
||||||
|
SysrootMode::Stitched(stitched) => stitched.crates.is_empty(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn loading_warning(&self) -> Option<String> {
|
pub fn loading_warning(&self) -> Option<String> {
|
||||||
if self.by_name("core").is_none() {
|
let has_core = match &self.mode {
|
||||||
|
SysrootMode::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
|
||||||
|
SysrootMode::Stitched(stitched) => stitched.by_name("core").is_some(),
|
||||||
|
};
|
||||||
|
if !has_core {
|
||||||
let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
|
let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
|
||||||
" (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
|
" (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
|
||||||
} else {
|
} else {
|
||||||
|
@ -92,27 +116,43 @@ impl Sysroot {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn num_packages(&self) -> usize {
|
||||||
|
match &self.mode {
|
||||||
|
SysrootMode::Workspace(ws) => ws.packages().count(),
|
||||||
|
SysrootMode::Stitched(c) => c.crates().count(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mode(&self) -> &SysrootMode {
|
||||||
|
&self.mode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Expose a builder api as loading the sysroot got way too modular and complicated.
|
// FIXME: Expose a builder api as loading the sysroot got way too modular and complicated.
|
||||||
impl Sysroot {
|
impl Sysroot {
|
||||||
/// Attempts to discover the toolchain's sysroot from the given `dir`.
|
/// Attempts to discover the toolchain's sysroot from the given `dir`.
|
||||||
pub fn discover(dir: &AbsPath, extra_env: &FxHashMap<String, String>) -> Result<Sysroot> {
|
pub fn discover(
|
||||||
|
dir: &AbsPath,
|
||||||
|
extra_env: &FxHashMap<String, String>,
|
||||||
|
metadata: bool,
|
||||||
|
) -> Result<Sysroot> {
|
||||||
tracing::debug!("discovering sysroot for {dir}");
|
tracing::debug!("discovering sysroot for {dir}");
|
||||||
let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
|
let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
|
||||||
let sysroot_src_dir =
|
let sysroot_src_dir =
|
||||||
discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?;
|
discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?;
|
||||||
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
|
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir, metadata))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn discover_with_src_override(
|
pub fn discover_with_src_override(
|
||||||
current_dir: &AbsPath,
|
current_dir: &AbsPath,
|
||||||
extra_env: &FxHashMap<String, String>,
|
extra_env: &FxHashMap<String, String>,
|
||||||
src: AbsPathBuf,
|
src: AbsPathBuf,
|
||||||
|
metadata: bool,
|
||||||
) -> Result<Sysroot> {
|
) -> Result<Sysroot> {
|
||||||
tracing::debug!("discovering sysroot for {current_dir}");
|
tracing::debug!("discovering sysroot for {current_dir}");
|
||||||
let sysroot_dir = discover_sysroot_dir(current_dir, extra_env)?;
|
let sysroot_dir = discover_sysroot_dir(current_dir, extra_env)?;
|
||||||
Ok(Sysroot::load(sysroot_dir, src))
|
Ok(Sysroot::load(sysroot_dir, src, metadata))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn discover_rustc_src(&self) -> Option<ManifestPath> {
|
pub fn discover_rustc_src(&self) -> Option<ManifestPath> {
|
||||||
|
@ -131,49 +171,132 @@ impl Sysroot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf) -> Result<Sysroot> {
|
pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf, metadata: bool) -> Result<Sysroot> {
|
||||||
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
|
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
|
||||||
format_err!("can't load standard library from sysroot path {sysroot_dir}")
|
format_err!("can't load standard library from sysroot path {sysroot_dir}")
|
||||||
})?;
|
})?;
|
||||||
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
|
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir, metadata))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(sysroot_dir: AbsPathBuf, mut sysroot_src_dir: AbsPathBuf) -> Sysroot {
|
pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf, metadata: bool) -> Sysroot {
|
||||||
// FIXME: Remove this `hack_cargo_workspace` field completely once we support sysroot dependencies
|
if metadata {
|
||||||
let hack_cargo_workspace = if let Ok(path) = std::env::var("RA_UNSTABLE_SYSROOT_HACK") {
|
let sysroot: Option<_> = (|| {
|
||||||
let cargo_toml = ManifestPath::try_from(
|
let sysroot_cargo_toml = ManifestPath::try_from(
|
||||||
AbsPathBuf::try_from(&*format!("{path}/Cargo.toml")).unwrap(),
|
AbsPathBuf::try_from(&*format!("{sysroot_src_dir}/sysroot/Cargo.toml")).ok()?,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.ok()?;
|
||||||
sysroot_src_dir = AbsPathBuf::try_from(&*path).unwrap().join("library");
|
let current_dir =
|
||||||
CargoWorkspace::fetch_metadata(
|
AbsPathBuf::try_from(&*format!("{sysroot_src_dir}/sysroot")).ok()?;
|
||||||
&cargo_toml,
|
let res = CargoWorkspace::fetch_metadata(
|
||||||
&AbsPathBuf::try_from("/").unwrap(),
|
&sysroot_cargo_toml,
|
||||||
|
¤t_dir,
|
||||||
&CargoConfig::default(),
|
&CargoConfig::default(),
|
||||||
&|_| (),
|
&|_| (),
|
||||||
)
|
)
|
||||||
.map(CargoWorkspace::new)
|
.map_err(|e| {
|
||||||
.ok()
|
tracing::error!(
|
||||||
} else {
|
"failed to load sysroot `{sysroot_src_dir}/sysroot/Cargo.toml`: {}",
|
||||||
None
|
e
|
||||||
};
|
);
|
||||||
let mut sysroot = Sysroot {
|
e
|
||||||
root: sysroot_dir,
|
});
|
||||||
src_root: sysroot_src_dir,
|
if let Err(e) =
|
||||||
crates: Arena::default(),
|
std::fs::remove_file(&format!("{sysroot_src_dir}/sysroot/Cargo.lock"))
|
||||||
hack_cargo_workspace,
|
{
|
||||||
};
|
tracing::error!(
|
||||||
|
"failed to remove sysroot `{sysroot_src_dir}/sysroot/Cargo.lock`: {}",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
}
|
||||||
|
let mut res = res.ok()?;
|
||||||
|
|
||||||
|
// Patch out `rustc-std-workspace-*` crates to point to the real crates.
|
||||||
|
// This is done prior to `CrateGraph` construction to avoid having duplicate `std` targets.
|
||||||
|
|
||||||
|
let mut fake_core = None;
|
||||||
|
let mut fake_alloc = None;
|
||||||
|
let mut fake_std = None;
|
||||||
|
let mut real_core = None;
|
||||||
|
let mut real_alloc = None;
|
||||||
|
let mut real_std = None;
|
||||||
|
res.packages.iter().enumerate().for_each(|(idx, package)| {
|
||||||
|
match package.name.strip_prefix("rustc-std-workspace-") {
|
||||||
|
Some("core") => fake_core = Some((idx, package.id.clone())),
|
||||||
|
Some("alloc") => fake_alloc = Some((idx, package.id.clone())),
|
||||||
|
Some("std") => fake_std = Some((idx, package.id.clone())),
|
||||||
|
Some(_) => {
|
||||||
|
tracing::warn!("unknown rustc-std-workspace-* crate: {}", package.name)
|
||||||
|
}
|
||||||
|
None => match &*package.name {
|
||||||
|
"core" => real_core = Some(package.id.clone()),
|
||||||
|
"alloc" => real_alloc = Some(package.id.clone()),
|
||||||
|
"std" => real_std = Some(package.id.clone()),
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let patches =
|
||||||
|
[fake_core.zip(real_core), fake_alloc.zip(real_alloc), fake_std.zip(real_std)]
|
||||||
|
.into_iter()
|
||||||
|
.flatten();
|
||||||
|
|
||||||
|
let resolve = res.resolve.as_mut().expect("metadata executed with deps");
|
||||||
|
let mut remove_nodes = vec![];
|
||||||
|
for (idx, node) in resolve.nodes.iter_mut().enumerate() {
|
||||||
|
// Replace them in the dependency list
|
||||||
|
node.deps.iter_mut().for_each(|dep| {
|
||||||
|
if let Some((_, real)) =
|
||||||
|
patches.clone().find(|((_, fake_id), _)| *fake_id == dep.pkg)
|
||||||
|
{
|
||||||
|
dep.pkg = real;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if patches.clone().any(|((_, fake), _)| fake == node.id) {
|
||||||
|
remove_nodes.push(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remove the fake ones from the resolve data
|
||||||
|
remove_nodes.into_iter().rev().for_each(|r| {
|
||||||
|
resolve.nodes.remove(r);
|
||||||
|
});
|
||||||
|
// Remove the fake ones from the packages
|
||||||
|
patches.map(|((r, _), _)| r).sorted().rev().for_each(|r| {
|
||||||
|
res.packages.remove(r);
|
||||||
|
});
|
||||||
|
|
||||||
|
res.workspace_members = res
|
||||||
|
.packages
|
||||||
|
.iter()
|
||||||
|
.filter_map(|package| {
|
||||||
|
RELEVANT_SYSROOT_CRATES
|
||||||
|
.contains(&&*package.name)
|
||||||
|
.then(|| package.id.clone())
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let cargo_workspace = CargoWorkspace::new(res);
|
||||||
|
Some(Sysroot {
|
||||||
|
root: sysroot_dir.clone(),
|
||||||
|
src_root: sysroot_src_dir.clone(),
|
||||||
|
mode: SysrootMode::Workspace(cargo_workspace),
|
||||||
|
})
|
||||||
|
})();
|
||||||
|
if let Some(sysroot) = sysroot {
|
||||||
|
return sysroot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut stitched = Stitched { crates: Arena::default() };
|
||||||
|
|
||||||
for path in SYSROOT_CRATES.trim().lines() {
|
for path in SYSROOT_CRATES.trim().lines() {
|
||||||
let name = path.split('/').last().unwrap();
|
let name = path.split('/').last().unwrap();
|
||||||
let root = [format!("{path}/src/lib.rs"), format!("lib{path}/lib.rs")]
|
let root = [format!("{path}/src/lib.rs"), format!("lib{path}/lib.rs")]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|it| sysroot.src_root.join(it))
|
.map(|it| sysroot_src_dir.join(it))
|
||||||
.filter_map(|it| ManifestPath::try_from(it).ok())
|
.filter_map(|it| ManifestPath::try_from(it).ok())
|
||||||
.find(|it| fs::metadata(it).is_ok());
|
.find(|it| fs::metadata(it).is_ok());
|
||||||
|
|
||||||
if let Some(root) = root {
|
if let Some(root) = root {
|
||||||
sysroot.crates.alloc(SysrootCrateData {
|
stitched.crates.alloc(SysrootCrateData {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
root,
|
root,
|
||||||
deps: Vec::new(),
|
deps: Vec::new(),
|
||||||
|
@ -181,36 +304,34 @@ impl Sysroot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(std) = sysroot.by_name("std") {
|
if let Some(std) = stitched.by_name("std") {
|
||||||
for dep in STD_DEPS.trim().lines() {
|
for dep in STD_DEPS.trim().lines() {
|
||||||
if let Some(dep) = sysroot.by_name(dep) {
|
if let Some(dep) = stitched.by_name(dep) {
|
||||||
sysroot.crates[std].deps.push(dep)
|
stitched.crates[std].deps.push(dep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(alloc) = sysroot.by_name("alloc") {
|
if let Some(alloc) = stitched.by_name("alloc") {
|
||||||
for dep in ALLOC_DEPS.trim().lines() {
|
for dep in ALLOC_DEPS.trim().lines() {
|
||||||
if let Some(dep) = sysroot.by_name(dep) {
|
if let Some(dep) = stitched.by_name(dep) {
|
||||||
sysroot.crates[alloc].deps.push(dep)
|
stitched.crates[alloc].deps.push(dep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(proc_macro) = sysroot.by_name("proc_macro") {
|
if let Some(proc_macro) = stitched.by_name("proc_macro") {
|
||||||
for dep in PROC_MACRO_DEPS.trim().lines() {
|
for dep in PROC_MACRO_DEPS.trim().lines() {
|
||||||
if let Some(dep) = sysroot.by_name(dep) {
|
if let Some(dep) = stitched.by_name(dep) {
|
||||||
sysroot.crates[proc_macro].deps.push(dep)
|
stitched.crates[proc_macro].deps.push(dep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Sysroot {
|
||||||
sysroot
|
root: sysroot_dir,
|
||||||
|
src_root: sysroot_src_dir,
|
||||||
|
mode: SysrootMode::Stitched(stitched),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn by_name(&self, name: &str) -> Option<SysrootCrate> {
|
|
||||||
let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?;
|
|
||||||
Some(id)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,3 +439,5 @@ test";
|
||||||
const PROC_MACRO_DEPS: &str = "
|
const PROC_MACRO_DEPS: &str = "
|
||||||
std
|
std
|
||||||
core";
|
core";
|
||||||
|
|
||||||
|
const RELEVANT_SYSROOT_CRATES: &[&str] = &["core", "alloc", "std", "test", "proc_macro"];
|
||||||
|
|
|
@ -38,7 +38,7 @@ fn load_cargo_with_overrides(
|
||||||
to_crate_graph(project_workspace)
|
to_crate_graph(project_workspace)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_cargo_with_sysroot(
|
fn load_cargo_with_fake_sysroot(
|
||||||
file_map: &mut FxHashMap<AbsPathBuf, FileId>,
|
file_map: &mut FxHashMap<AbsPathBuf, FileId>,
|
||||||
file: &str,
|
file: &str,
|
||||||
) -> (CrateGraph, ProcMacroPaths) {
|
) -> (CrateGraph, ProcMacroPaths) {
|
||||||
|
@ -125,7 +125,7 @@ fn get_fake_sysroot() -> Sysroot {
|
||||||
// fake sysroot, so we give them both the same path:
|
// fake sysroot, so we give them both the same path:
|
||||||
let sysroot_dir = AbsPathBuf::assert(sysroot_path);
|
let sysroot_dir = AbsPathBuf::assert(sysroot_path);
|
||||||
let sysroot_src_dir = sysroot_dir.clone();
|
let sysroot_src_dir = sysroot_dir.clone();
|
||||||
Sysroot::load(sysroot_dir, sysroot_src_dir)
|
Sysroot::load(sysroot_dir, sysroot_src_dir, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
|
fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
|
||||||
|
@ -225,12 +225,12 @@ fn rust_project_is_proc_macro_has_proc_macro_dep() {
|
||||||
#[test]
|
#[test]
|
||||||
fn crate_graph_dedup_identical() {
|
fn crate_graph_dedup_identical() {
|
||||||
let (mut crate_graph, proc_macros) =
|
let (mut crate_graph, proc_macros) =
|
||||||
load_cargo_with_sysroot(&mut Default::default(), "regex-metadata.json");
|
load_cargo_with_fake_sysroot(&mut Default::default(), "regex-metadata.json");
|
||||||
crate_graph.sort_deps();
|
crate_graph.sort_deps();
|
||||||
|
|
||||||
let (d_crate_graph, mut d_proc_macros) = (crate_graph.clone(), proc_macros.clone());
|
let (d_crate_graph, mut d_proc_macros) = (crate_graph.clone(), proc_macros.clone());
|
||||||
|
|
||||||
crate_graph.extend(d_crate_graph.clone(), &mut d_proc_macros);
|
crate_graph.extend(d_crate_graph.clone(), &mut d_proc_macros, |_| ());
|
||||||
assert!(crate_graph.iter().eq(d_crate_graph.iter()));
|
assert!(crate_graph.iter().eq(d_crate_graph.iter()));
|
||||||
assert_eq!(proc_macros, d_proc_macros);
|
assert_eq!(proc_macros, d_proc_macros);
|
||||||
}
|
}
|
||||||
|
@ -239,14 +239,14 @@ fn crate_graph_dedup_identical() {
|
||||||
fn crate_graph_dedup() {
|
fn crate_graph_dedup() {
|
||||||
let path_map = &mut Default::default();
|
let path_map = &mut Default::default();
|
||||||
let (mut crate_graph, _proc_macros) =
|
let (mut crate_graph, _proc_macros) =
|
||||||
load_cargo_with_sysroot(path_map, "ripgrep-metadata.json");
|
load_cargo_with_fake_sysroot(path_map, "ripgrep-metadata.json");
|
||||||
assert_eq!(crate_graph.iter().count(), 81);
|
assert_eq!(crate_graph.iter().count(), 81);
|
||||||
crate_graph.sort_deps();
|
crate_graph.sort_deps();
|
||||||
let (regex_crate_graph, mut regex_proc_macros) =
|
let (regex_crate_graph, mut regex_proc_macros) =
|
||||||
load_cargo_with_sysroot(path_map, "regex-metadata.json");
|
load_cargo_with_fake_sysroot(path_map, "regex-metadata.json");
|
||||||
assert_eq!(regex_crate_graph.iter().count(), 60);
|
assert_eq!(regex_crate_graph.iter().count(), 60);
|
||||||
|
|
||||||
crate_graph.extend(regex_crate_graph, &mut regex_proc_macros);
|
crate_graph.extend(regex_crate_graph, &mut regex_proc_macros, |_| ());
|
||||||
assert_eq!(crate_graph.iter().count(), 118);
|
assert_eq!(crate_graph.iter().count(), 118);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,12 +254,12 @@ fn crate_graph_dedup() {
|
||||||
fn test_deduplicate_origin_dev() {
|
fn test_deduplicate_origin_dev() {
|
||||||
let path_map = &mut Default::default();
|
let path_map = &mut Default::default();
|
||||||
let (mut crate_graph, _proc_macros) =
|
let (mut crate_graph, _proc_macros) =
|
||||||
load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json");
|
load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_A.json");
|
||||||
crate_graph.sort_deps();
|
crate_graph.sort_deps();
|
||||||
let (crate_graph_1, mut _proc_macros_2) =
|
let (crate_graph_1, mut _proc_macros_2) =
|
||||||
load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json");
|
load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_B.json");
|
||||||
|
|
||||||
crate_graph.extend(crate_graph_1, &mut _proc_macros_2);
|
crate_graph.extend(crate_graph_1, &mut _proc_macros_2, |_| ());
|
||||||
|
|
||||||
let mut crates_named_p2 = vec![];
|
let mut crates_named_p2 = vec![];
|
||||||
for id in crate_graph.iter() {
|
for id in crate_graph.iter() {
|
||||||
|
@ -280,12 +280,12 @@ fn test_deduplicate_origin_dev() {
|
||||||
fn test_deduplicate_origin_dev_rev() {
|
fn test_deduplicate_origin_dev_rev() {
|
||||||
let path_map = &mut Default::default();
|
let path_map = &mut Default::default();
|
||||||
let (mut crate_graph, _proc_macros) =
|
let (mut crate_graph, _proc_macros) =
|
||||||
load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json");
|
load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_B.json");
|
||||||
crate_graph.sort_deps();
|
crate_graph.sort_deps();
|
||||||
let (crate_graph_1, mut _proc_macros_2) =
|
let (crate_graph_1, mut _proc_macros_2) =
|
||||||
load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json");
|
load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_A.json");
|
||||||
|
|
||||||
crate_graph.extend(crate_graph_1, &mut _proc_macros_2);
|
crate_graph.extend(crate_graph_1, &mut _proc_macros_2, |_| ());
|
||||||
|
|
||||||
let mut crates_named_p2 = vec![];
|
let mut crates_named_p2 = vec![];
|
||||||
for id in crate_graph.iter() {
|
for id in crate_graph.iter() {
|
||||||
|
@ -301,3 +301,40 @@ fn test_deduplicate_origin_dev_rev() {
|
||||||
let p2 = crates_named_p2[0];
|
let p2 = crates_named_p2[0];
|
||||||
assert!(p2.origin.is_local());
|
assert!(p2.origin.is_local());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke_test_real_sysroot_cargo() {
|
||||||
|
if std::env::var("SYSROOT_CARGO_METADATA").is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let file_map = &mut FxHashMap::<AbsPathBuf, FileId>::default();
|
||||||
|
let meta = get_test_json_file("hello-world-metadata.json");
|
||||||
|
|
||||||
|
let cargo_workspace = CargoWorkspace::new(meta);
|
||||||
|
let sysroot = Ok(Sysroot::discover(
|
||||||
|
AbsPath::assert(Path::new(env!("CARGO_MANIFEST_DIR"))),
|
||||||
|
&Default::default(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.unwrap());
|
||||||
|
|
||||||
|
let project_workspace = ProjectWorkspace::Cargo {
|
||||||
|
cargo: cargo_workspace,
|
||||||
|
build_scripts: WorkspaceBuildScripts::default(),
|
||||||
|
sysroot,
|
||||||
|
rustc: Err(None),
|
||||||
|
rustc_cfg: Vec::new(),
|
||||||
|
cfg_overrides: Default::default(),
|
||||||
|
toolchain: None,
|
||||||
|
target_layout: Err("target_data_layout not loaded".into()),
|
||||||
|
};
|
||||||
|
project_workspace.to_crate_graph(
|
||||||
|
&mut {
|
||||||
|
|path| {
|
||||||
|
let len = file_map.len();
|
||||||
|
Some(*file_map.entry(path.to_path_buf()).or_insert(FileId::from_raw(len as u32)))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&Default::default(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use base_db::{
|
||||||
CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, DependencyKind,
|
CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, DependencyKind,
|
||||||
Edition, Env, FileId, LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult,
|
Edition, Env, FileId, LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult,
|
||||||
};
|
};
|
||||||
use cfg::{CfgDiff, CfgOptions};
|
use cfg::{CfgAtom, CfgDiff, CfgOptions};
|
||||||
use paths::{AbsPath, AbsPathBuf};
|
use paths::{AbsPath, AbsPathBuf};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
|
@ -22,7 +22,7 @@ use crate::{
|
||||||
cfg_flag::CfgFlag,
|
cfg_flag::CfgFlag,
|
||||||
project_json::Crate,
|
project_json::Crate,
|
||||||
rustc_cfg::{self, RustcCfgConfig},
|
rustc_cfg::{self, RustcCfgConfig},
|
||||||
sysroot::SysrootCrate,
|
sysroot::{SysrootCrate, SysrootMode},
|
||||||
target_data_layout, utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath,
|
target_data_layout, utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath,
|
||||||
Package, ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
|
Package, ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
|
||||||
};
|
};
|
||||||
|
@ -130,7 +130,7 @@ impl fmt::Debug for ProjectWorkspace {
|
||||||
let mut debug_struct = f.debug_struct("Json");
|
let mut debug_struct = f.debug_struct("Json");
|
||||||
debug_struct.field("n_crates", &project.n_crates());
|
debug_struct.field("n_crates", &project.n_crates());
|
||||||
if let Ok(sysroot) = sysroot {
|
if let Ok(sysroot) = sysroot {
|
||||||
debug_struct.field("n_sysroot_crates", &sysroot.crates().len());
|
debug_struct.field("n_sysroot_crates", &sysroot.num_packages());
|
||||||
}
|
}
|
||||||
debug_struct.field("toolchain", &toolchain);
|
debug_struct.field("toolchain", &toolchain);
|
||||||
debug_struct.field("n_rustc_cfg", &rustc_cfg.len());
|
debug_struct.field("n_rustc_cfg", &rustc_cfg.len());
|
||||||
|
@ -208,23 +208,23 @@ impl ProjectWorkspace {
|
||||||
|
|
||||||
let sysroot = match (&config.sysroot, &config.sysroot_src) {
|
let sysroot = match (&config.sysroot, &config.sysroot_src) {
|
||||||
(Some(RustLibSource::Path(path)), None) => {
|
(Some(RustLibSource::Path(path)), None) => {
|
||||||
Sysroot::with_sysroot_dir(path.clone()).map_err(|e| {
|
Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata).map_err(|e| {
|
||||||
Some(format!("Failed to find sysroot at {path}:{e}"))
|
Some(format!("Failed to find sysroot at {path}:{e}"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
(Some(RustLibSource::Discover), None) => {
|
(Some(RustLibSource::Discover), None) => {
|
||||||
Sysroot::discover(cargo_toml.parent(), &config.extra_env).map_err(|e| {
|
Sysroot::discover(cargo_toml.parent(), &config.extra_env, config.sysroot_query_metadata).map_err(|e| {
|
||||||
Some(format!("Failed to find sysroot for Cargo.toml file {cargo_toml}. Is rust-src installed? {e}"))
|
Some(format!("Failed to find sysroot for Cargo.toml file {cargo_toml}. Is rust-src installed? {e}"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
(Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => {
|
(Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => {
|
||||||
Ok(Sysroot::load(sysroot.clone(), sysroot_src.clone()))
|
Ok(Sysroot::load(sysroot.clone(), sysroot_src.clone(), config.sysroot_query_metadata))
|
||||||
}
|
}
|
||||||
(Some(RustLibSource::Discover), Some(sysroot_src)) => {
|
(Some(RustLibSource::Discover), Some(sysroot_src)) => {
|
||||||
Sysroot::discover_with_src_override(
|
Sysroot::discover_with_src_override(
|
||||||
cargo_toml.parent(),
|
cargo_toml.parent(),
|
||||||
&config.extra_env,
|
&config.extra_env,
|
||||||
sysroot_src.clone(),
|
sysroot_src.clone(), config.sysroot_query_metadata,
|
||||||
).map_err(|e| {
|
).map_err(|e| {
|
||||||
Some(format!("Failed to find sysroot for Cargo.toml file {cargo_toml}. Is rust-src installed? {e}"))
|
Some(format!("Failed to find sysroot for Cargo.toml file {cargo_toml}. Is rust-src installed? {e}"))
|
||||||
})
|
})
|
||||||
|
@ -317,12 +317,12 @@ impl ProjectWorkspace {
|
||||||
toolchain: Option<Version>,
|
toolchain: Option<Version>,
|
||||||
) -> ProjectWorkspace {
|
) -> ProjectWorkspace {
|
||||||
let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
|
let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
|
||||||
(Some(sysroot), Some(sysroot_src)) => Ok(Sysroot::load(sysroot, sysroot_src)),
|
(Some(sysroot), Some(sysroot_src)) => Ok(Sysroot::load(sysroot, sysroot_src, false)),
|
||||||
(Some(sysroot), None) => {
|
(Some(sysroot), None) => {
|
||||||
// assume sysroot is structured like rustup's and guess `sysroot_src`
|
// assume sysroot is structured like rustup's and guess `sysroot_src`
|
||||||
let sysroot_src =
|
let sysroot_src =
|
||||||
sysroot.join("lib").join("rustlib").join("src").join("rust").join("library");
|
sysroot.join("lib").join("rustlib").join("src").join("rust").join("library");
|
||||||
Ok(Sysroot::load(sysroot, sysroot_src))
|
Ok(Sysroot::load(sysroot, sysroot_src, false))
|
||||||
}
|
}
|
||||||
(None, Some(sysroot_src)) => {
|
(None, Some(sysroot_src)) => {
|
||||||
// assume sysroot is structured like rustup's and guess `sysroot`
|
// assume sysroot is structured like rustup's and guess `sysroot`
|
||||||
|
@ -330,7 +330,7 @@ impl ProjectWorkspace {
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
sysroot.pop();
|
sysroot.pop();
|
||||||
}
|
}
|
||||||
Ok(Sysroot::load(sysroot, sysroot_src))
|
Ok(Sysroot::load(sysroot, sysroot_src, false))
|
||||||
}
|
}
|
||||||
(None, None) => Err(None),
|
(None, None) => Err(None),
|
||||||
};
|
};
|
||||||
|
@ -354,16 +354,22 @@ impl ProjectWorkspace {
|
||||||
config: &CargoConfig,
|
config: &CargoConfig,
|
||||||
) -> anyhow::Result<ProjectWorkspace> {
|
) -> anyhow::Result<ProjectWorkspace> {
|
||||||
let sysroot = match &config.sysroot {
|
let sysroot = match &config.sysroot {
|
||||||
Some(RustLibSource::Path(path)) => Sysroot::with_sysroot_dir(path.clone())
|
Some(RustLibSource::Path(path)) => {
|
||||||
.map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}"))),
|
Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata)
|
||||||
|
.map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}")))
|
||||||
|
}
|
||||||
Some(RustLibSource::Discover) => {
|
Some(RustLibSource::Discover) => {
|
||||||
let dir = &detached_files
|
let dir = &detached_files
|
||||||
.first()
|
.first()
|
||||||
.and_then(|it| it.parent())
|
.and_then(|it| it.parent())
|
||||||
.ok_or_else(|| format_err!("No detached files to load"))?;
|
.ok_or_else(|| format_err!("No detached files to load"))?;
|
||||||
Sysroot::discover(dir, &config.extra_env).map_err(|e| {
|
Sysroot::discover(dir, &config.extra_env, config.sysroot_query_metadata).map_err(
|
||||||
Some(format!("Failed to find sysroot for {dir}. Is rust-src installed? {e}"))
|
|e| {
|
||||||
})
|
Some(format!(
|
||||||
|
"Failed to find sysroot for {dir}. Is rust-src installed? {e}"
|
||||||
|
))
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
None => Err(None),
|
None => Err(None),
|
||||||
};
|
};
|
||||||
|
@ -494,13 +500,43 @@ impl ProjectWorkspace {
|
||||||
/// The return type contains the path and whether or not
|
/// The return type contains the path and whether or not
|
||||||
/// the root is a member of the current workspace
|
/// the root is a member of the current workspace
|
||||||
pub fn to_roots(&self) -> Vec<PackageRoot> {
|
pub fn to_roots(&self) -> Vec<PackageRoot> {
|
||||||
let mk_sysroot = |sysroot: Result<&Sysroot, _>, project_root: Option<&AbsPath>| {
|
let mk_sysroot = |sysroot: Result<_, _>, project_root: Option<&AbsPath>| {
|
||||||
sysroot.map(|sysroot| PackageRoot {
|
let project_root = project_root.map(ToOwned::to_owned);
|
||||||
|
sysroot.into_iter().flat_map(move |sysroot: &Sysroot| {
|
||||||
|
let mut r = match sysroot.mode() {
|
||||||
|
SysrootMode::Workspace(ws) => ws
|
||||||
|
.packages()
|
||||||
|
.filter_map(|pkg| {
|
||||||
|
if ws[pkg].is_local {
|
||||||
|
// the local ones are included in the main `PackageRoot`` below
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let pkg_root = ws[pkg].manifest.parent().to_path_buf();
|
||||||
|
|
||||||
|
let include = vec![pkg_root.clone()];
|
||||||
|
|
||||||
|
let exclude = vec![
|
||||||
|
pkg_root.join(".git"),
|
||||||
|
pkg_root.join("target"),
|
||||||
|
pkg_root.join("tests"),
|
||||||
|
pkg_root.join("examples"),
|
||||||
|
pkg_root.join("benches"),
|
||||||
|
];
|
||||||
|
Some(PackageRoot { is_local: false, include, exclude })
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
SysrootMode::Stitched(_) => vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
r.push(PackageRoot {
|
||||||
// mark the sysroot as mutable if it is located inside of the project
|
// mark the sysroot as mutable if it is located inside of the project
|
||||||
is_local: project_root
|
is_local: project_root
|
||||||
|
.as_ref()
|
||||||
.map_or(false, |project_root| sysroot.src_root().starts_with(project_root)),
|
.map_or(false, |project_root| sysroot.src_root().starts_with(project_root)),
|
||||||
include: vec![sysroot.src_root().to_path_buf()],
|
include: vec![sysroot.src_root().to_path_buf()],
|
||||||
exclude: Vec::new(),
|
exclude: Vec::new(),
|
||||||
|
});
|
||||||
|
r
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
match self {
|
match self {
|
||||||
|
@ -588,16 +624,16 @@ impl ProjectWorkspace {
|
||||||
pub fn n_packages(&self) -> usize {
|
pub fn n_packages(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
ProjectWorkspace::Json { project, sysroot, .. } => {
|
ProjectWorkspace::Json { project, sysroot, .. } => {
|
||||||
let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len());
|
let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
|
||||||
sysroot_package_len + project.n_crates()
|
sysroot_package_len + project.n_crates()
|
||||||
}
|
}
|
||||||
ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => {
|
ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => {
|
||||||
let rustc_package_len = rustc.as_ref().map_or(0, |(it, _)| it.packages().len());
|
let rustc_package_len = rustc.as_ref().map_or(0, |(it, _)| it.packages().len());
|
||||||
let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len());
|
let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
|
||||||
cargo.packages().len() + sysroot_package_len + rustc_package_len
|
cargo.packages().len() + sysroot_package_len + rustc_package_len
|
||||||
}
|
}
|
||||||
ProjectWorkspace::DetachedFiles { sysroot, files, .. } => {
|
ProjectWorkspace::DetachedFiles { sysroot, files, .. } => {
|
||||||
let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len());
|
let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
|
||||||
sysroot_package_len + files.len()
|
sysroot_package_len + files.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -638,7 +674,6 @@ impl ProjectWorkspace {
|
||||||
sysroot.as_ref().ok(),
|
sysroot.as_ref().ok(),
|
||||||
rustc_cfg.clone(),
|
rustc_cfg.clone(),
|
||||||
cfg_overrides,
|
cfg_overrides,
|
||||||
None,
|
|
||||||
build_scripts,
|
build_scripts,
|
||||||
match target_layout.as_ref() {
|
match target_layout.as_ref() {
|
||||||
Ok(it) => Ok(Arc::from(it.as_str())),
|
Ok(it) => Ok(Arc::from(it.as_str())),
|
||||||
|
@ -849,8 +884,6 @@ fn cargo_to_crate_graph(
|
||||||
sysroot: Option<&Sysroot>,
|
sysroot: Option<&Sysroot>,
|
||||||
rustc_cfg: Vec<CfgFlag>,
|
rustc_cfg: Vec<CfgFlag>,
|
||||||
override_cfg: &CfgOverrides,
|
override_cfg: &CfgOverrides,
|
||||||
// Don't compute cfg and use this if present, only used for the sysroot experiment hack
|
|
||||||
forced_cfg: Option<CfgOptions>,
|
|
||||||
build_scripts: &WorkspaceBuildScripts,
|
build_scripts: &WorkspaceBuildScripts,
|
||||||
target_layout: TargetLayoutLoadResult,
|
target_layout: TargetLayoutLoadResult,
|
||||||
toolchain: Option<&Version>,
|
toolchain: Option<&Version>,
|
||||||
|
@ -883,7 +916,7 @@ fn cargo_to_crate_graph(
|
||||||
for pkg in cargo.packages() {
|
for pkg in cargo.packages() {
|
||||||
has_private |= cargo[pkg].metadata.rustc_private;
|
has_private |= cargo[pkg].metadata.rustc_private;
|
||||||
|
|
||||||
let cfg_options = forced_cfg.clone().unwrap_or_else(|| {
|
let cfg_options = {
|
||||||
let mut cfg_options = cfg_options.clone();
|
let mut cfg_options = cfg_options.clone();
|
||||||
|
|
||||||
// Add test cfg for local crates
|
// Add test cfg for local crates
|
||||||
|
@ -908,7 +941,7 @@ fn cargo_to_crate_graph(
|
||||||
cfg_options.apply_diff(diff.clone());
|
cfg_options.apply_diff(diff.clone());
|
||||||
};
|
};
|
||||||
cfg_options
|
cfg_options
|
||||||
});
|
};
|
||||||
|
|
||||||
let mut lib_tgt = None;
|
let mut lib_tgt = None;
|
||||||
for &tgt in cargo[pkg].targets.iter() {
|
for &tgt in cargo[pkg].targets.iter() {
|
||||||
|
@ -1349,26 +1382,84 @@ fn sysroot_to_crate_graph(
|
||||||
toolchain: Option<&Version>,
|
toolchain: Option<&Version>,
|
||||||
) -> (SysrootPublicDeps, Option<CrateId>) {
|
) -> (SysrootPublicDeps, Option<CrateId>) {
|
||||||
let _p = profile::span("sysroot_to_crate_graph");
|
let _p = profile::span("sysroot_to_crate_graph");
|
||||||
let cfg_options = create_cfg_options(rustc_cfg.clone());
|
match sysroot.mode() {
|
||||||
let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = match &sysroot.hack_cargo_workspace {
|
SysrootMode::Workspace(cargo) => {
|
||||||
Some(cargo) => handle_hack_cargo_workspace(
|
let (mut cg, mut pm) = cargo_to_crate_graph(
|
||||||
load,
|
load,
|
||||||
|
None,
|
||||||
cargo,
|
cargo,
|
||||||
|
None,
|
||||||
rustc_cfg,
|
rustc_cfg,
|
||||||
cfg_options,
|
&CfgOverrides::default(),
|
||||||
|
&WorkspaceBuildScripts::default(),
|
||||||
target_layout,
|
target_layout,
|
||||||
toolchain,
|
toolchain,
|
||||||
crate_graph,
|
);
|
||||||
sysroot,
|
|
||||||
),
|
let mut pub_deps = vec![];
|
||||||
None => sysroot
|
let mut libproc_macro = None;
|
||||||
|
let diff = CfgDiff::new(vec![], vec![CfgAtom::Flag("test".into())]).unwrap();
|
||||||
|
for (cid, c) in cg.iter_mut() {
|
||||||
|
// uninject `test` flag so `core` keeps working.
|
||||||
|
c.cfg_options.apply_diff(diff.clone());
|
||||||
|
// patch the origin
|
||||||
|
if c.origin.is_local() {
|
||||||
|
let lang_crate = LangCrateOrigin::from(
|
||||||
|
c.display_name.as_ref().map_or("", |it| it.canonical_name()),
|
||||||
|
);
|
||||||
|
c.origin = CrateOrigin::Lang(lang_crate);
|
||||||
|
match lang_crate {
|
||||||
|
LangCrateOrigin::Test
|
||||||
|
| LangCrateOrigin::Alloc
|
||||||
|
| LangCrateOrigin::Core
|
||||||
|
| LangCrateOrigin::Std => pub_deps.push((
|
||||||
|
CrateName::normalize_dashes(&lang_crate.to_string()),
|
||||||
|
cid,
|
||||||
|
!matches!(lang_crate, LangCrateOrigin::Test),
|
||||||
|
)),
|
||||||
|
LangCrateOrigin::ProcMacro => libproc_macro = Some(cid),
|
||||||
|
LangCrateOrigin::Other => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut marker_set = vec![];
|
||||||
|
for &(_, cid, _) in pub_deps.iter() {
|
||||||
|
marker_set.extend(cg.transitive_deps(cid));
|
||||||
|
}
|
||||||
|
if let Some(cid) = libproc_macro {
|
||||||
|
marker_set.extend(cg.transitive_deps(cid));
|
||||||
|
}
|
||||||
|
|
||||||
|
marker_set.sort();
|
||||||
|
marker_set.dedup();
|
||||||
|
|
||||||
|
// Remove all crates except the ones we are interested in to keep the sysroot graph small.
|
||||||
|
let removed_mapping = cg.remove_crates_except(&marker_set);
|
||||||
|
|
||||||
|
crate_graph.extend(cg, &mut pm, |mapping| {
|
||||||
|
// Map the id through the removal mapping first, then through the crate graph extension mapping.
|
||||||
|
pub_deps.iter_mut().for_each(|(_, cid, _)| {
|
||||||
|
*cid = mapping[&removed_mapping[cid.into_raw().into_u32() as usize].unwrap()]
|
||||||
|
});
|
||||||
|
if let Some(libproc_macro) = &mut libproc_macro {
|
||||||
|
*libproc_macro = mapping
|
||||||
|
[&removed_mapping[libproc_macro.into_raw().into_u32() as usize].unwrap()];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
(SysrootPublicDeps { deps: pub_deps }, libproc_macro)
|
||||||
|
}
|
||||||
|
SysrootMode::Stitched(stitched) => {
|
||||||
|
let cfg_options = create_cfg_options(rustc_cfg.clone());
|
||||||
|
let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = stitched
|
||||||
.crates()
|
.crates()
|
||||||
.filter_map(|krate| {
|
.filter_map(|krate| {
|
||||||
let file_id = load(&sysroot[krate].root)?;
|
let file_id = load(&stitched[krate].root)?;
|
||||||
|
|
||||||
let env = Env::default();
|
let env = Env::default();
|
||||||
let display_name =
|
let display_name =
|
||||||
CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
|
CrateDisplayName::from_canonical_name(stitched[krate].name.clone());
|
||||||
let crate_id = crate_graph.add_crate_root(
|
let crate_id = crate_graph.add_crate_root(
|
||||||
file_id,
|
file_id,
|
||||||
Edition::CURRENT,
|
Edition::CURRENT,
|
||||||
|
@ -1378,95 +1469,39 @@ fn sysroot_to_crate_graph(
|
||||||
None,
|
None,
|
||||||
env,
|
env,
|
||||||
false,
|
false,
|
||||||
CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)),
|
CrateOrigin::Lang(LangCrateOrigin::from(&*stitched[krate].name)),
|
||||||
target_layout.clone(),
|
target_layout.clone(),
|
||||||
toolchain.cloned(),
|
toolchain.cloned(),
|
||||||
);
|
);
|
||||||
Some((krate, crate_id))
|
Some((krate, crate_id))
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect();
|
||||||
};
|
|
||||||
for from in sysroot.crates() {
|
for from in stitched.crates() {
|
||||||
for &to in sysroot[from].deps.iter() {
|
for &to in stitched[from].deps.iter() {
|
||||||
let name = CrateName::new(&sysroot[to].name).unwrap();
|
let name = CrateName::new(&stitched[to].name).unwrap();
|
||||||
if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) {
|
if let (Some(&from), Some(&to)) =
|
||||||
|
(sysroot_crates.get(&from), sysroot_crates.get(&to))
|
||||||
|
{
|
||||||
add_dep(crate_graph, from, name, to, DependencyKind::Normal);
|
add_dep(crate_graph, from, name, to, DependencyKind::Normal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let public_deps = SysrootPublicDeps {
|
let public_deps = SysrootPublicDeps {
|
||||||
deps: sysroot
|
deps: stitched
|
||||||
.public_deps()
|
.public_deps()
|
||||||
.filter_map(|(name, idx, prelude)| Some((name, *sysroot_crates.get(&idx)?, prelude)))
|
.filter_map(|(name, idx, prelude)| {
|
||||||
|
Some((name, *sysroot_crates.get(&idx)?, prelude))
|
||||||
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let libproc_macro = sysroot.proc_macro().and_then(|it| sysroot_crates.get(&it).copied());
|
let libproc_macro =
|
||||||
|
stitched.proc_macro().and_then(|it| sysroot_crates.get(&it).copied());
|
||||||
(public_deps, libproc_macro)
|
(public_deps, libproc_macro)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_hack_cargo_workspace(
|
|
||||||
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
|
||||||
cargo: &CargoWorkspace,
|
|
||||||
rustc_cfg: Vec<CfgFlag>,
|
|
||||||
cfg_options: CfgOptions,
|
|
||||||
target_layout: Result<Arc<str>, Arc<str>>,
|
|
||||||
toolchain: Option<&Version>,
|
|
||||||
crate_graph: &mut CrateGraph,
|
|
||||||
sysroot: &Sysroot,
|
|
||||||
) -> FxHashMap<SysrootCrate, CrateId> {
|
|
||||||
let (cg, mut pm) = cargo_to_crate_graph(
|
|
||||||
load,
|
|
||||||
None,
|
|
||||||
cargo,
|
|
||||||
None,
|
|
||||||
rustc_cfg,
|
|
||||||
&CfgOverrides::default(),
|
|
||||||
Some(cfg_options),
|
|
||||||
&WorkspaceBuildScripts::default(),
|
|
||||||
target_layout,
|
|
||||||
toolchain,
|
|
||||||
);
|
|
||||||
crate_graph.extend(cg, &mut pm);
|
|
||||||
for crate_name in ["std", "alloc", "core"] {
|
|
||||||
let original = crate_graph
|
|
||||||
.iter()
|
|
||||||
.find(|x| {
|
|
||||||
crate_graph[*x]
|
|
||||||
.display_name
|
|
||||||
.as_ref()
|
|
||||||
.map(|x| x.canonical_name() == crate_name)
|
|
||||||
.unwrap_or(false)
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
let fake_crate_name = format!("rustc-std-workspace-{}", crate_name);
|
|
||||||
let fake = crate_graph
|
|
||||||
.iter()
|
|
||||||
.find(|x| {
|
|
||||||
crate_graph[*x]
|
|
||||||
.display_name
|
|
||||||
.as_ref()
|
|
||||||
.map(|x| x.canonical_name() == fake_crate_name)
|
|
||||||
.unwrap_or(false)
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
crate_graph.remove_and_replace(fake, original).unwrap();
|
|
||||||
}
|
}
|
||||||
for (_, c) in crate_graph.iter_mut() {
|
|
||||||
if c.origin.is_local() {
|
|
||||||
// LangCrateOrigin::Other is good enough for a hack.
|
|
||||||
c.origin = CrateOrigin::Lang(LangCrateOrigin::Other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sysroot
|
|
||||||
.crates()
|
|
||||||
.filter_map(|krate| {
|
|
||||||
let file_id = load(&sysroot[krate].root)?;
|
|
||||||
let crate_id = crate_graph.crate_id_for_crate_root(file_id)?;
|
|
||||||
Some((krate, crate_id))
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_dep(
|
fn add_dep(
|
||||||
|
|
|
@ -182,7 +182,7 @@
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
origin: Lang(
|
origin: Lang(
|
||||||
Other,
|
ProcMacro,
|
||||||
),
|
),
|
||||||
is_proc_macro: false,
|
is_proc_macro: false,
|
||||||
target_layout: Err(
|
target_layout: Err(
|
||||||
|
|
|
@ -61,9 +61,12 @@ impl Tester {
|
||||||
cargo_config.sysroot = Some(RustLibSource::Discover);
|
cargo_config.sysroot = Some(RustLibSource::Discover);
|
||||||
let workspace = ProjectWorkspace::DetachedFiles {
|
let workspace = ProjectWorkspace::DetachedFiles {
|
||||||
files: vec![tmp_file.clone()],
|
files: vec![tmp_file.clone()],
|
||||||
sysroot: Ok(
|
sysroot: Ok(Sysroot::discover(
|
||||||
Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env).unwrap()
|
tmp_file.parent().unwrap(),
|
||||||
),
|
&cargo_config.extra_env,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap()),
|
||||||
rustc_cfg: vec![],
|
rustc_cfg: vec![],
|
||||||
};
|
};
|
||||||
let load_cargo_config = LoadCargoConfig {
|
let load_cargo_config = LoadCargoConfig {
|
||||||
|
|
|
@ -135,6 +135,13 @@ config_data! {
|
||||||
///
|
///
|
||||||
/// This option does not take effect until rust-analyzer is restarted.
|
/// This option does not take effect until rust-analyzer is restarted.
|
||||||
cargo_sysroot: Option<String> = "\"discover\"",
|
cargo_sysroot: Option<String> = "\"discover\"",
|
||||||
|
/// Whether to run cargo metadata on the sysroot library allowing rust-analyzer to analyze
|
||||||
|
/// third-party dependencies of the standard libraries.
|
||||||
|
///
|
||||||
|
/// This will cause `cargo` to create a lockfile in your sysroot directory. rust-analyzer
|
||||||
|
/// will attempt to clean up afterwards, but nevertheless requires the location to be
|
||||||
|
/// writable to.
|
||||||
|
cargo_sysrootQueryMetadata: bool = "false",
|
||||||
/// Relative path to the sysroot library sources. If left unset, this will default to
|
/// Relative path to the sysroot library sources. If left unset, this will default to
|
||||||
/// `{cargo.sysroot}/lib/rustlib/src/rust/library`.
|
/// `{cargo.sysroot}/lib/rustlib/src/rust/library`.
|
||||||
///
|
///
|
||||||
|
@ -1233,6 +1240,7 @@ impl Config {
|
||||||
});
|
});
|
||||||
let sysroot_src =
|
let sysroot_src =
|
||||||
self.data.cargo_sysrootSrc.as_ref().map(|sysroot| self.root_path.join(sysroot));
|
self.data.cargo_sysrootSrc.as_ref().map(|sysroot| self.root_path.join(sysroot));
|
||||||
|
let sysroot_query_metadata = self.data.cargo_sysrootQueryMetadata;
|
||||||
|
|
||||||
CargoConfig {
|
CargoConfig {
|
||||||
features: match &self.data.cargo_features {
|
features: match &self.data.cargo_features {
|
||||||
|
@ -1244,6 +1252,7 @@ impl Config {
|
||||||
},
|
},
|
||||||
target: self.data.cargo_target.clone(),
|
target: self.data.cargo_target.clone(),
|
||||||
sysroot,
|
sysroot,
|
||||||
|
sysroot_query_metadata,
|
||||||
sysroot_src,
|
sysroot_src,
|
||||||
rustc_source,
|
rustc_source,
|
||||||
cfg_overrides: project_model::CfgOverrides {
|
cfg_overrides: project_model::CfgOverrides {
|
||||||
|
|
|
@ -516,7 +516,7 @@ impl GlobalState {
|
||||||
for ws in &**self.workspaces {
|
for ws in &**self.workspaces {
|
||||||
let (other, mut crate_proc_macros) =
|
let (other, mut crate_proc_macros) =
|
||||||
ws.to_crate_graph(&mut load, &self.config.extra_env());
|
ws.to_crate_graph(&mut load, &self.config.extra_env());
|
||||||
crate_graph.extend(other, &mut crate_proc_macros);
|
crate_graph.extend(other, &mut crate_proc_macros, |_| {});
|
||||||
proc_macros.push(crate_proc_macros);
|
proc_macros.push(crate_proc_macros);
|
||||||
}
|
}
|
||||||
(crate_graph, proc_macros, crate_graph_file_dependencies)
|
(crate_graph, proc_macros, crate_graph_file_dependencies)
|
||||||
|
|
|
@ -121,6 +121,16 @@ Unsetting this disables sysroot loading.
|
||||||
|
|
||||||
This option does not take effect until rust-analyzer is restarted.
|
This option does not take effect until rust-analyzer is restarted.
|
||||||
--
|
--
|
||||||
|
[[rust-analyzer.cargo.sysrootQueryMetadata]]rust-analyzer.cargo.sysrootQueryMetadata (default: `false`)::
|
||||||
|
+
|
||||||
|
--
|
||||||
|
Whether to run cargo metadata on the sysroot library allowing rust-analyzer to analyze
|
||||||
|
third-party dependencies of the standard libraries.
|
||||||
|
|
||||||
|
This will cause `cargo` to create a lockfile in your sysroot directory. rust-analyzer
|
||||||
|
will attempt to clean up afterwards, but nevertheless requires the location to be
|
||||||
|
writable to.
|
||||||
|
--
|
||||||
[[rust-analyzer.cargo.sysrootSrc]]rust-analyzer.cargo.sysrootSrc (default: `null`)::
|
[[rust-analyzer.cargo.sysrootSrc]]rust-analyzer.cargo.sysrootSrc (default: `null`)::
|
||||||
+
|
+
|
||||||
--
|
--
|
||||||
|
|
|
@ -648,6 +648,11 @@
|
||||||
"string"
|
"string"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"rust-analyzer.cargo.sysrootQueryMetadata": {
|
||||||
|
"markdownDescription": "Whether to run cargo metadata on the sysroot library allowing rust-analyzer to analyze\nthird-party dependencies of the standard libraries.\n\nThis will cause `cargo` to create a lockfile in your sysroot directory. rust-analyzer\nwill attempt to clean up afterwards, but nevertheless requires the location to be\nwritable to.",
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"rust-analyzer.cargo.sysrootSrc": {
|
"rust-analyzer.cargo.sysrootSrc": {
|
||||||
"markdownDescription": "Relative path to the sysroot library sources. If left unset, this will default to\n`{cargo.sysroot}/lib/rustlib/src/rust/library`.\n\nThis option does not take effect until rust-analyzer is restarted.",
|
"markdownDescription": "Relative path to the sysroot library sources. If left unset, this will default to\n`{cargo.sysroot}/lib/rustlib/src/rust/library`.\n\nThis option does not take effect until rust-analyzer is restarted.",
|
||||||
"default": null,
|
"default": null,
|
||||||
|
|
Loading…
Reference in a new issue