Auto merge of #17287 - Veykril:sysroot-encode-empty, r=Veykril

Allow sysroots to only consist of the source root dir

Fixes https://github.com/rust-lang/rust-analyzer/issues/17159

This PR encodes the `None` case of an optional sysroot into `Sysroot` itself. This simplifies a lot of things and allows us to have sysroots that consist of nothing, only standard library sources, everything but the standard library sources or everything. This makes things a lot more flexible. Additionally, this removes the workspace status bar info again, as it turns out that that can be too much information for the status bar to handle (this is better rendered somewhere else, like in the status view).
This commit is contained in:
bors 2024-05-23 18:13:47 +00:00
commit f6fc109fcb
18 changed files with 277 additions and 361 deletions

View file

@ -1,7 +1,7 @@
use chalk_ir::{AdtId, TyKind}; use chalk_ir::{AdtId, TyKind};
use either::Either; use either::Either;
use hir_def::db::DefDatabase; use hir_def::db::DefDatabase;
use project_model::target_data_layout::RustcDataLayoutConfig; use project_model::{target_data_layout::RustcDataLayoutConfig, Sysroot};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use test_fixture::WithFixture; use test_fixture::WithFixture;
use triomphe::Arc; use triomphe::Arc;
@ -17,7 +17,7 @@ mod closure;
fn current_machine_data_layout() -> String { fn current_machine_data_layout() -> String {
project_model::target_data_layout::get( project_model::target_data_layout::get(
RustcDataLayoutConfig::Rustc(None), RustcDataLayoutConfig::Rustc(&Sysroot::empty()),
None, None,
&FxHashMap::default(), &FxHashMap::default(),
) )

View file

@ -65,7 +65,7 @@ impl WorkspaceBuildScripts {
allowed_features: &FxHashSet<String>, allowed_features: &FxHashSet<String>,
manifest_path: &ManifestPath, manifest_path: &ManifestPath,
toolchain: Option<&Version>, toolchain: Option<&Version>,
sysroot: Option<&Sysroot>, sysroot: &Sysroot,
) -> io::Result<Command> { ) -> io::Result<Command> {
const RUST_1_75: Version = Version::new(1, 75, 0); const RUST_1_75: Version = Version::new(1, 75, 0);
let mut cmd = match config.run_build_script_command.as_deref() { let mut cmd = match config.run_build_script_command.as_deref() {
@ -75,7 +75,7 @@ impl WorkspaceBuildScripts {
cmd cmd
} }
_ => { _ => {
let mut cmd = Sysroot::tool(sysroot, Tool::Cargo); let mut cmd = sysroot.tool(Tool::Cargo);
cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]); cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]);
cmd.args(&config.extra_args); cmd.args(&config.extra_args);
@ -149,7 +149,7 @@ impl WorkspaceBuildScripts {
workspace: &CargoWorkspace, workspace: &CargoWorkspace,
progress: &dyn Fn(String), progress: &dyn Fn(String),
toolchain: Option<&Version>, toolchain: Option<&Version>,
sysroot: Option<&Sysroot>, sysroot: &Sysroot,
) -> io::Result<WorkspaceBuildScripts> { ) -> io::Result<WorkspaceBuildScripts> {
let current_dir = match &config.invocation_location { let current_dir = match &config.invocation_location {
InvocationLocation::Root(root) if config.run_build_script_command.is_some() => { InvocationLocation::Root(root) if config.run_build_script_command.is_some() => {
@ -195,7 +195,7 @@ impl WorkspaceBuildScripts {
// This is not gonna be used anyways, so just construct a dummy here // This is not gonna be used anyways, so just construct a dummy here
&ManifestPath::try_from(workspace_root.clone()).unwrap(), &ManifestPath::try_from(workspace_root.clone()).unwrap(),
None, None,
None, &Sysroot::empty(),
)?; )?;
// NB: Cargo.toml could have been modified between `cargo metadata` and // NB: Cargo.toml could have been modified between `cargo metadata` and
// `cargo check`. We shouldn't assume that package ids we see here are // `cargo check`. We shouldn't assume that package ids we see here are
@ -412,7 +412,7 @@ impl WorkspaceBuildScripts {
rustc: &CargoWorkspace, rustc: &CargoWorkspace,
current_dir: &AbsPath, current_dir: &AbsPath,
extra_env: &FxHashMap<String, String>, extra_env: &FxHashMap<String, String>,
sysroot: Option<&Sysroot>, sysroot: &Sysroot,
) -> Self { ) -> Self {
let mut bs = WorkspaceBuildScripts::default(); let mut bs = WorkspaceBuildScripts::default();
for p in rustc.packages() { for p in rustc.packages() {
@ -420,7 +420,7 @@ impl WorkspaceBuildScripts {
} }
let res = (|| { let res = (|| {
let target_libdir = (|| { let target_libdir = (|| {
let mut cargo_config = Sysroot::tool(sysroot, Tool::Cargo); let mut cargo_config = sysroot.tool(Tool::Cargo);
cargo_config.envs(extra_env); cargo_config.envs(extra_env);
cargo_config cargo_config
.current_dir(current_dir) .current_dir(current_dir)
@ -429,7 +429,7 @@ impl WorkspaceBuildScripts {
if let Ok(it) = utf8_stdout(cargo_config) { if let Ok(it) = utf8_stdout(cargo_config) {
return Ok(it); return Ok(it);
} }
let mut cmd = Sysroot::tool(sysroot, Tool::Rustc); let mut cmd = sysroot.tool(Tool::Rustc);
cmd.envs(extra_env); cmd.envs(extra_env);
cmd.args(["--print", "target-libdir"]); cmd.args(["--print", "target-libdir"]);
utf8_stdout(cmd) utf8_stdout(cmd)

View file

@ -258,12 +258,12 @@ impl CargoWorkspace {
cargo_toml: &ManifestPath, cargo_toml: &ManifestPath,
current_dir: &AbsPath, current_dir: &AbsPath,
config: &CargoConfig, config: &CargoConfig,
sysroot: Option<&Sysroot>, sysroot: &Sysroot,
progress: &dyn Fn(String), progress: &dyn Fn(String),
) -> anyhow::Result<cargo_metadata::Metadata> { ) -> anyhow::Result<cargo_metadata::Metadata> {
let targets = find_list_of_build_targets(config, cargo_toml, sysroot); let targets = find_list_of_build_targets(config, cargo_toml, sysroot);
let cargo = Sysroot::tool(sysroot, Tool::Cargo); let cargo = sysroot.tool(Tool::Cargo);
let mut meta = MetadataCommand::new(); let mut meta = MetadataCommand::new();
meta.cargo_path(cargo.get_program()); meta.cargo_path(cargo.get_program());
cargo.get_envs().for_each(|(var, val)| _ = meta.env(var, val.unwrap_or_default())); cargo.get_envs().for_each(|(var, val)| _ = meta.env(var, val.unwrap_or_default()));
@ -536,7 +536,7 @@ impl CargoWorkspace {
fn find_list_of_build_targets( fn find_list_of_build_targets(
config: &CargoConfig, config: &CargoConfig,
cargo_toml: &ManifestPath, cargo_toml: &ManifestPath,
sysroot: Option<&Sysroot>, sysroot: &Sysroot,
) -> Vec<String> { ) -> Vec<String> {
if let Some(target) = &config.target { if let Some(target) = &config.target {
return [target.into()].to_vec(); return [target.into()].to_vec();
@ -553,9 +553,9 @@ fn find_list_of_build_targets(
fn rustc_discover_host_triple( fn rustc_discover_host_triple(
cargo_toml: &ManifestPath, cargo_toml: &ManifestPath,
extra_env: &FxHashMap<String, String>, extra_env: &FxHashMap<String, String>,
sysroot: Option<&Sysroot>, sysroot: &Sysroot,
) -> Option<String> { ) -> Option<String> {
let mut rustc = Sysroot::tool(sysroot, Tool::Rustc); let mut rustc = sysroot.tool(Tool::Rustc);
rustc.envs(extra_env); rustc.envs(extra_env);
rustc.current_dir(cargo_toml.parent()).arg("-vV"); rustc.current_dir(cargo_toml.parent()).arg("-vV");
tracing::debug!("Discovering host platform by {:?}", rustc); tracing::debug!("Discovering host platform by {:?}", rustc);
@ -581,9 +581,9 @@ fn rustc_discover_host_triple(
fn cargo_config_build_target( fn cargo_config_build_target(
cargo_toml: &ManifestPath, cargo_toml: &ManifestPath,
extra_env: &FxHashMap<String, String>, extra_env: &FxHashMap<String, String>,
sysroot: Option<&Sysroot>, sysroot: &Sysroot,
) -> Vec<String> { ) -> Vec<String> {
let mut cargo_config = Sysroot::tool(sysroot, Tool::Cargo); let mut cargo_config = sysroot.tool(Tool::Cargo);
cargo_config.envs(extra_env); cargo_config.envs(extra_env);
cargo_config cargo_config
.current_dir(cargo_toml.parent()) .current_dir(cargo_toml.parent())

View file

@ -62,9 +62,9 @@ pub(crate) fn inject_rustc_tool_env(env: &mut Env, cargo_name: &str, kind: Targe
pub(crate) fn cargo_config_env( pub(crate) fn cargo_config_env(
manifest: &ManifestPath, manifest: &ManifestPath,
extra_env: &FxHashMap<String, String>, extra_env: &FxHashMap<String, String>,
sysroot: Option<&Sysroot>, sysroot: &Sysroot,
) -> FxHashMap<String, String> { ) -> FxHashMap<String, String> {
let mut cargo_config = Sysroot::tool(sysroot, Tool::Cargo); let mut cargo_config = sysroot.tool(Tool::Cargo);
cargo_config.envs(extra_env); cargo_config.envs(extra_env);
cargo_config cargo_config
.current_dir(manifest.parent()) .current_dir(manifest.parent())

View file

@ -10,10 +10,10 @@ use crate::{cfg::CfgFlag, utf8_stdout, ManifestPath, Sysroot};
pub(crate) enum RustcCfgConfig<'a> { pub(crate) enum RustcCfgConfig<'a> {
/// Use `rustc --print cfg`, either from with the binary from the sysroot or by discovering via /// Use `rustc --print cfg`, either from with the binary from the sysroot or by discovering via
/// [`toolchain::rustc`]. /// [`toolchain::rustc`].
Rustc(Option<&'a Sysroot>), Rustc(&'a Sysroot),
/// Use `cargo --print cfg`, either from with the binary from the sysroot or by discovering via /// Use `cargo --print cfg`, either from with the binary from the sysroot or by discovering via
/// [`toolchain::cargo`]. /// [`toolchain::cargo`].
Cargo(Option<&'a Sysroot>, &'a ManifestPath), Cargo(&'a Sysroot, &'a ManifestPath),
} }
pub(crate) fn get( pub(crate) fn get(
@ -65,7 +65,7 @@ fn get_rust_cfgs(
) -> anyhow::Result<String> { ) -> anyhow::Result<String> {
let sysroot = match config { let sysroot = match config {
RustcCfgConfig::Cargo(sysroot, cargo_toml) => { RustcCfgConfig::Cargo(sysroot, cargo_toml) => {
let mut cmd = Sysroot::tool(sysroot, Tool::Cargo); let mut cmd = sysroot.tool(Tool::Cargo);
cmd.envs(extra_env); cmd.envs(extra_env);
cmd.current_dir(cargo_toml.parent()) cmd.current_dir(cargo_toml.parent())
@ -86,7 +86,7 @@ fn get_rust_cfgs(
RustcCfgConfig::Rustc(sysroot) => sysroot, RustcCfgConfig::Rustc(sysroot) => sysroot,
}; };
let mut cmd = Sysroot::tool(sysroot, Tool::Rustc); let mut cmd = sysroot.tool(Tool::Rustc);
cmd.envs(extra_env); cmd.envs(extra_env);
cmd.args(["--print", "cfg", "-O"]); cmd.args(["--print", "cfg", "-O"]);
if let Some(target) = target { if let Some(target) = target {

View file

@ -4,7 +4,7 @@
//! but we can't process `.rlib` and need source code instead. The source code //! but we can't process `.rlib` and need source code instead. The source code
//! is typically installed with `rustup component add rust-src` command. //! is typically installed with `rustup component add rust-src` command.
use std::{env, fs, ops, process::Command, sync::Arc}; use std::{env, fs, ops, process::Command};
use anyhow::{format_err, Result}; use anyhow::{format_err, Result};
use base_db::CrateName; use base_db::CrateName;
@ -16,30 +16,19 @@ use toolchain::{probe_for_binary, Tool};
use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath}; use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath};
#[derive(Debug, Clone)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Sysroot { pub struct Sysroot {
root: AbsPathBuf, root: Option<AbsPathBuf>,
src_root: Option<Result<AbsPathBuf, Arc<anyhow::Error>>>, src_root: Option<AbsPathBuf>,
mode: SysrootMode, mode: SysrootMode,
} error: Option<String>,
impl Eq for Sysroot {}
impl PartialEq for Sysroot {
fn eq(&self, other: &Self) -> bool {
self.root == other.root
&& self.mode == other.mode
&& match (&self.src_root, &other.src_root) {
(Some(Ok(this)), Some(Ok(other))) => this == other,
(None, None) | (Some(Err(_)), Some(Err(_))) => true,
_ => false,
}
}
} }
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) enum SysrootMode { pub(crate) enum SysrootMode {
Workspace(CargoWorkspace), Workspace(CargoWorkspace),
Stitched(Stitched), Stitched(Stitched),
Empty,
} }
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
@ -89,70 +78,40 @@ pub(crate) struct SysrootCrateData {
} }
impl Sysroot { impl Sysroot {
pub const fn empty() -> Sysroot {
Sysroot { root: None, src_root: None, mode: SysrootMode::Empty, error: None }
}
/// Returns sysroot "root" directory, where `bin/`, `etc/`, `lib/`, `libexec/` /// Returns sysroot "root" directory, where `bin/`, `etc/`, `lib/`, `libexec/`
/// subfolder live, like: /// subfolder live, like:
/// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu` /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu`
pub fn root(&self) -> &AbsPath { pub fn root(&self) -> Option<&AbsPath> {
&self.root self.root.as_deref()
} }
/// Returns the sysroot "source" directory, where stdlib sources are located, like: /// Returns the sysroot "source" directory, where stdlib sources are located, like:
/// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library` /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library`
pub fn src_root(&self) -> Option<&AbsPath> { pub fn src_root(&self) -> Option<&AbsPath> {
self.src_root.as_ref()?.as_deref().ok() self.src_root.as_deref()
} }
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
match &self.mode { match &self.mode {
SysrootMode::Workspace(ws) => ws.packages().next().is_none(), SysrootMode::Workspace(ws) => ws.packages().next().is_none(),
SysrootMode::Stitched(stitched) => stitched.crates.is_empty(), SysrootMode::Stitched(stitched) => stitched.crates.is_empty(),
SysrootMode::Empty => true,
} }
} }
pub fn loading_warning(&self) -> Option<String> { pub fn error(&self) -> Option<&str> {
let src_root = match &self.src_root { self.error.as_deref()
None => return Some(format!("sysroot at `{}` has no library sources", self.root)),
Some(Ok(src_root)) => src_root,
Some(Err(e)) => return Some(e.to_string()),
};
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() {
" (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
} else {
" try running `rustup component add rust-src` to possible fix this"
};
Some(format!("could not find libcore in loaded sysroot at `{}`{var_note}", src_root,))
} else {
None
}
}
pub fn check_has_core(&self) -> Result<(), String> {
let Some(Ok(src_root)) = &self.src_root else { return Ok(()) };
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() {
" (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
} else {
" try running `rustup component add rust-src` to possible fix this"
};
Err(format!("could not find libcore in loaded sysroot at `{}`{var_note}", src_root,))
} else {
Ok(())
}
} }
pub fn num_packages(&self) -> usize { pub fn num_packages(&self) -> usize {
match &self.mode { match &self.mode {
SysrootMode::Workspace(ws) => ws.packages().count(), SysrootMode::Workspace(ws) => ws.packages().count(),
SysrootMode::Stitched(c) => c.crates().count(), SysrootMode::Stitched(c) => c.crates().count(),
SysrootMode::Empty => 0,
} }
} }
@ -168,63 +127,50 @@ impl Sysroot {
dir: &AbsPath, dir: &AbsPath,
extra_env: &FxHashMap<String, String>, extra_env: &FxHashMap<String, String>,
metadata: bool, metadata: bool,
) -> Result<Sysroot> { ) -> Sysroot {
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 = sysroot_dir.as_ref().ok().map(|sysroot_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, Some(sysroot_src_dir), metadata)) Sysroot::load_core_check(Some(sysroot_dir), sysroot_src_dir, metadata)
}
pub fn discover_no_source(
dir: &AbsPath,
extra_env: &FxHashMap<String, String>,
) -> Result<Sysroot> {
tracing::debug!("discovering sysroot for {dir}");
let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
let sysroot_src_dir =
discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env);
Ok(Sysroot::load(sysroot_dir, Some(sysroot_src_dir), false))
} }
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, sysroot_src_dir: AbsPathBuf,
metadata: bool, metadata: bool,
) -> Result<Sysroot> { ) -> Sysroot {
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)?; Sysroot::load_core_check(Some(sysroot_dir), Some(Ok(sysroot_src_dir)), metadata)
Ok(Sysroot::load(sysroot_dir, Some(Ok(src)), metadata)) }
pub fn discover_sysroot_src_dir(sysroot_dir: AbsPathBuf, metadata: bool) -> Sysroot {
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir)
.ok_or_else(|| format_err!("can't find standard library sources in {sysroot_dir}"));
Sysroot::load_core_check(Some(Ok(sysroot_dir)), Some(sysroot_src_dir), metadata)
} }
pub fn discover_rustc_src(&self) -> Option<ManifestPath> { pub fn discover_rustc_src(&self) -> Option<ManifestPath> {
get_rustc_src(&self.root) get_rustc_src(self.root()?)
}
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(|| {
format_err!("can't load standard library from sysroot path {sysroot_dir}")
});
Ok(Sysroot::load(sysroot_dir, Some(sysroot_src_dir), metadata))
} }
/// Returns a command to run a tool preferring the cargo proxies if the sysroot exists. /// Returns a command to run a tool preferring the cargo proxies if the sysroot exists.
pub fn tool(sysroot: Option<&Self>, tool: Tool) -> Command { pub fn tool(&self, tool: Tool) -> Command {
match sysroot { match self.root() {
Some(sysroot) => { Some(root) => {
// special case rustc, we can look that up directly in the sysroot's bin folder // special case rustc, we can look that up directly in the sysroot's bin folder
// as it should never invoke another cargo binary // as it should never invoke another cargo binary
if let Tool::Rustc = tool { if let Tool::Rustc = tool {
if let Some(path) = if let Some(path) =
probe_for_binary(sysroot.root.join("bin").join(Tool::Rustc.name()).into()) probe_for_binary(root.join("bin").join(Tool::Rustc.name()).into())
{ {
return Command::new(path); return Command::new(path);
} }
} }
let mut cmd = Command::new(tool.prefer_proxy()); let mut cmd = Command::new(tool.prefer_proxy());
cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(&sysroot.root)); cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(root));
cmd cmd
} }
_ => Command::new(tool.path()), _ => Command::new(tool.path()),
@ -232,35 +178,89 @@ impl Sysroot {
} }
pub fn discover_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> { pub fn discover_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
let Some(root) = self.root() else {
return Err(anyhow::format_err!("no sysroot",));
};
["libexec", "lib"] ["libexec", "lib"]
.into_iter() .into_iter()
.map(|segment| self.root().join(segment).join("rust-analyzer-proc-macro-srv")) .map(|segment| root.join(segment).join("rust-analyzer-proc-macro-srv"))
.find_map(|server_path| probe_for_binary(server_path.into())) .find_map(|server_path| probe_for_binary(server_path.into()))
.map(AbsPathBuf::assert) .map(AbsPathBuf::assert)
.ok_or_else(|| { .ok_or_else(|| {
anyhow::format_err!("cannot find proc-macro server in sysroot `{}`", self.root()) anyhow::format_err!("cannot find proc-macro server in sysroot `{}`", root)
}) })
} }
pub fn load( pub fn load(
sysroot_dir: AbsPathBuf, sysroot_dir: Option<AbsPathBuf>,
sysroot_src_dir: Option<AbsPathBuf>,
metadata: bool,
) -> Sysroot {
Self::load_core_check(sysroot_dir.map(Ok), sysroot_src_dir.map(Ok), metadata)
}
fn load_core_check(
sysroot_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>, sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
metadata: bool, metadata: bool,
) -> Sysroot { ) -> Sysroot {
let mut sysroot = Self::load_(sysroot_dir, sysroot_src_dir, metadata);
if sysroot.error.is_none() {
if let Some(src_root) = &sysroot.src_root {
let has_core = match &sysroot.mode {
SysrootMode::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
SysrootMode::Stitched(stitched) => stitched.by_name("core").is_some(),
SysrootMode::Empty => true,
};
if !has_core {
let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
" (env var `RUST_SRC_PATH` is set and may be incorrect, try unsetting it)"
} else {
", try running `rustup component add rust-src` to possibly fix this"
};
sysroot.error = Some(format!(
"sysroot at `{}` is missing a `core` library{var_note}",
src_root,
));
}
}
}
sysroot
}
fn load_(
sysroot_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
metadata: bool,
) -> Sysroot {
let sysroot_dir = match sysroot_dir {
Some(Ok(sysroot_dir)) => Some(sysroot_dir),
Some(Err(e)) => {
return Sysroot {
root: None,
src_root: None,
mode: SysrootMode::Empty,
error: Some(e.to_string()),
}
}
None => None,
};
let sysroot_src_dir = match sysroot_src_dir { let sysroot_src_dir = match sysroot_src_dir {
Some(Ok(sysroot_src_dir)) => sysroot_src_dir, Some(Ok(sysroot_src_dir)) => sysroot_src_dir,
Some(Err(e)) => { Some(Err(e)) => {
return Sysroot { return Sysroot {
root: sysroot_dir, root: sysroot_dir,
src_root: Some(Err(Arc::new(e))), src_root: None,
mode: SysrootMode::Stitched(Stitched { crates: Arena::default() }), mode: SysrootMode::Empty,
error: Some(e.to_string()),
} }
} }
None => { None => {
return Sysroot { return Sysroot {
root: sysroot_dir, root: sysroot_dir,
src_root: None, src_root: None,
mode: SysrootMode::Stitched(Stitched { crates: Arena::default() }), mode: SysrootMode::Empty,
error: None,
} }
} }
}; };
@ -284,7 +284,7 @@ impl Sysroot {
&sysroot_cargo_toml, &sysroot_cargo_toml,
&current_dir, &current_dir,
&cargo_config, &cargo_config,
None, &Sysroot::empty(),
&|_| (), &|_| (),
) )
.map_err(|e| { .map_err(|e| {
@ -368,8 +368,9 @@ impl Sysroot {
let cargo_workspace = CargoWorkspace::new(res, sysroot_cargo_toml); let cargo_workspace = CargoWorkspace::new(res, sysroot_cargo_toml);
Some(Sysroot { Some(Sysroot {
root: sysroot_dir.clone(), root: sysroot_dir.clone(),
src_root: Some(Ok(sysroot_src_dir.clone())), src_root: Some(sysroot_src_dir.clone()),
mode: SysrootMode::Workspace(cargo_workspace), mode: SysrootMode::Workspace(cargo_workspace),
error: None,
}) })
})(); })();
if let Some(sysroot) = sysroot { if let Some(sysroot) = sysroot {
@ -420,8 +421,9 @@ impl Sysroot {
} }
Sysroot { Sysroot {
root: sysroot_dir, root: sysroot_dir,
src_root: Some(Ok(sysroot_src_dir)), src_root: Some(sysroot_src_dir),
mode: SysrootMode::Stitched(stitched), mode: SysrootMode::Stitched(stitched),
error: None,
} }
} }
} }

View file

@ -9,10 +9,10 @@ use crate::{utf8_stdout, ManifestPath, Sysroot};
pub enum RustcDataLayoutConfig<'a> { pub enum RustcDataLayoutConfig<'a> {
/// Use `rustc --print target-spec-json`, either from with the binary from the sysroot or by discovering via /// Use `rustc --print target-spec-json`, either from with the binary from the sysroot or by discovering via
/// [`toolchain::rustc`]. /// [`toolchain::rustc`].
Rustc(Option<&'a Sysroot>), Rustc(&'a Sysroot),
/// Use `cargo --print target-spec-json`, either from with the binary from the sysroot or by discovering via /// Use `cargo --print target-spec-json`, either from with the binary from the sysroot or by discovering via
/// [`toolchain::cargo`]. /// [`toolchain::cargo`].
Cargo(Option<&'a Sysroot>, &'a ManifestPath), Cargo(&'a Sysroot, &'a ManifestPath),
} }
pub fn get( pub fn get(
@ -28,7 +28,7 @@ pub fn get(
}; };
let sysroot = match config { let sysroot = match config {
RustcDataLayoutConfig::Cargo(sysroot, cargo_toml) => { RustcDataLayoutConfig::Cargo(sysroot, cargo_toml) => {
let mut cmd = Sysroot::tool(sysroot, Tool::Cargo); let mut cmd = sysroot.tool(Tool::Cargo);
cmd.envs(extra_env); cmd.envs(extra_env);
cmd.current_dir(cargo_toml.parent()) cmd.current_dir(cargo_toml.parent())
.args([ .args([

View file

@ -34,7 +34,7 @@ fn load_cargo_with_overrides(
cargo_config_extra_env: Default::default(), cargo_config_extra_env: Default::default(),
}, },
cfg_overrides, cfg_overrides,
sysroot: Err(None), sysroot: Sysroot::empty(),
rustc_cfg: Vec::new(), rustc_cfg: Vec::new(),
toolchain: None, toolchain: None,
target_layout: Err("target_data_layout not loaded".into()), target_layout: Err("target_data_layout not loaded".into()),
@ -57,7 +57,7 @@ fn load_cargo_with_fake_sysroot(
rustc: Err(None), rustc: Err(None),
cargo_config_extra_env: Default::default(), cargo_config_extra_env: Default::default(),
}, },
sysroot: Ok(get_fake_sysroot()), sysroot: get_fake_sysroot(),
rustc_cfg: Vec::new(), rustc_cfg: Vec::new(),
cfg_overrides: Default::default(), cfg_overrides: Default::default(),
toolchain: None, toolchain: None,
@ -77,7 +77,7 @@ fn load_cargo_with_fake_sysroot(
fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) { fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) {
let data = get_test_json_file(file); let data = get_test_json_file(file);
let project = rooted_project_json(data); let project = rooted_project_json(data);
let sysroot = Ok(get_fake_sysroot()); let sysroot = get_fake_sysroot();
let project_workspace = ProjectWorkspace { let project_workspace = ProjectWorkspace {
kind: ProjectWorkspaceKind::Json(project), kind: ProjectWorkspaceKind::Json(project),
sysroot, sysroot,
@ -144,7 +144,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, Some(Ok(sysroot_src_dir)), false) Sysroot::load(Some(sysroot_dir), Some(sysroot_src_dir), false)
} }
fn rooted_project_json(data: ProjectJsonData) -> ProjectJson { fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
@ -281,12 +281,11 @@ fn smoke_test_real_sysroot_cargo() {
let manifest_path = let manifest_path =
ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap(); ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap();
let cargo_workspace = CargoWorkspace::new(meta, manifest_path); let cargo_workspace = CargoWorkspace::new(meta, manifest_path);
let sysroot = Ok(Sysroot::discover( let sysroot = Sysroot::discover(
AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))), AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))),
&Default::default(), &Default::default(),
true, true,
) );
.unwrap());
let project_workspace = ProjectWorkspace { let project_workspace = ProjectWorkspace {
kind: ProjectWorkspaceKind::Cargo { kind: ProjectWorkspaceKind::Cargo {

View file

@ -48,7 +48,7 @@ pub struct PackageRoot {
pub struct ProjectWorkspace { pub struct ProjectWorkspace {
pub kind: ProjectWorkspaceKind, pub kind: ProjectWorkspaceKind,
/// The sysroot loaded for this workspace. /// The sysroot loaded for this workspace.
pub sysroot: Result<Sysroot, Option<String>>, pub sysroot: Sysroot,
/// Holds cfg flags for the current target. We get those by running /// Holds cfg flags for the current target. We get those by running
/// `rustc --print cfg`. /// `rustc --print cfg`.
// FIXME: make this a per-crate map, as, eg, build.rs might have a // FIXME: make this a per-crate map, as, eg, build.rs might have a
@ -112,7 +112,7 @@ impl fmt::Debug for ProjectWorkspace {
.debug_struct("Cargo") .debug_struct("Cargo")
.field("root", &cargo.workspace_root().file_name()) .field("root", &cargo.workspace_root().file_name())
.field("n_packages", &cargo.packages().len()) .field("n_packages", &cargo.packages().len())
.field("sysroot", &sysroot.is_ok()) .field("n_sysroot_crates", &sysroot.num_packages())
.field( .field(
"n_rustc_compiler_crates", "n_rustc_compiler_crates",
&rustc.as_ref().map(|a| a.as_ref()).map_or(0, |(rc, _)| rc.packages().len()), &rustc.as_ref().map(|a| a.as_ref()).map_or(0, |(rc, _)| rc.packages().len()),
@ -125,11 +125,9 @@ impl fmt::Debug for ProjectWorkspace {
.finish(), .finish(),
ProjectWorkspaceKind::Json(project) => { ProjectWorkspaceKind::Json(project) => {
let mut debug_struct = f.debug_struct("Json"); let mut debug_struct = f.debug_struct("Json");
debug_struct.field("n_crates", &project.n_crates());
if let Ok(sysroot) = sysroot {
debug_struct.field("n_sysroot_crates", &sysroot.num_packages());
}
debug_struct debug_struct
.field("n_crates", &project.n_crates())
.field("n_sysroot_crates", &sysroot.num_packages())
.field("n_rustc_cfg", &rustc_cfg.len()) .field("n_rustc_cfg", &rustc_cfg.len())
.field("toolchain", &toolchain) .field("toolchain", &toolchain)
.field("data_layout", &target_layout) .field("data_layout", &target_layout)
@ -144,7 +142,7 @@ impl fmt::Debug for ProjectWorkspace {
.debug_struct("DetachedFiles") .debug_struct("DetachedFiles")
.field("file", &file) .field("file", &file)
.field("cargo_script", &cargo_script.is_some()) .field("cargo_script", &cargo_script.is_some())
.field("sysroot", &sysroot.is_ok()) .field("n_sysroot_crates", &sysroot.num_packages())
.field("cargo_script", &cargo_script.is_some()) .field("cargo_script", &cargo_script.is_some())
.field("n_rustc_cfg", &rustc_cfg.len()) .field("n_rustc_cfg", &rustc_cfg.len())
.field("toolchain", &toolchain) .field("toolchain", &toolchain)
@ -158,7 +156,7 @@ impl fmt::Debug for ProjectWorkspace {
fn get_toolchain_version( fn get_toolchain_version(
current_dir: &AbsPath, current_dir: &AbsPath,
sysroot: Option<&Sysroot>, sysroot: &Sysroot,
tool: Tool, tool: Tool,
extra_env: &FxHashMap<String, String>, extra_env: &FxHashMap<String, String>,
prefix: &str, prefix: &str,
@ -213,41 +211,37 @@ impl ProjectWorkspace {
} }
ProjectManifest::CargoToml(cargo_toml) => { ProjectManifest::CargoToml(cargo_toml) => {
let sysroot = match (&config.sysroot, &config.sysroot_src) { let sysroot = match (&config.sysroot, &config.sysroot_src) {
(Some(RustLibSource::Path(path)), None) => { (Some(RustLibSource::Discover), None) => Sysroot::discover(
Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata).map_err(|e| { cargo_toml.parent(),
Some(format!("Failed to find sysroot at {path}:{e}")) &config.extra_env,
}) config.sysroot_query_metadata,
} ),
(Some(RustLibSource::Discover), None) => {
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(RustLibSource::Path(sysroot)), Some(sysroot_src)) => {
Ok(Sysroot::load(sysroot.clone(), Some(Ok(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(), config.sysroot_query_metadata, sysroot_src.clone(),
).map_err(|e| { config.sysroot_query_metadata,
Some(format!("Failed to find sysroot for Cargo.toml file {cargo_toml}. Is rust-src installed? {e}")) )
})
} }
(None, _) => Err(None), (Some(RustLibSource::Path(path)), None) => Sysroot::discover_sysroot_src_dir(
path.clone(),
config.sysroot_query_metadata,
),
(Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => Sysroot::load(
Some(sysroot.clone()),
Some(sysroot_src.clone()),
config.sysroot_query_metadata,
),
(None, _) => Sysroot::empty(),
}; };
let sysroot_ref = sysroot.as_ref().ok(); tracing::info!(workspace = %cargo_toml, src_root = ?sysroot.src_root(), root = ?sysroot.root(), "Using sysroot");
if let Ok(sysroot) = &sysroot {
tracing::info!(workspace = %cargo_toml, src_root = ?sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
}
let rustc_dir = match &config.rustc_source { let rustc_dir = match &config.rustc_source {
Some(RustLibSource::Path(path)) => ManifestPath::try_from(path.clone()) Some(RustLibSource::Path(path)) => ManifestPath::try_from(path.clone())
.map_err(|p| Some(format!("rustc source path is not absolute: {p}"))), .map_err(|p| Some(format!("rustc source path is not absolute: {p}"))),
Some(RustLibSource::Discover) => { Some(RustLibSource::Discover) => {
sysroot_ref.and_then(Sysroot::discover_rustc_src).ok_or_else(|| { sysroot.discover_rustc_src().ok_or_else(|| {
Some("Failed to discover rustc source for sysroot.".to_owned()) Some("Failed to discover rustc source for sysroot.".to_owned())
}) })
} }
@ -263,7 +257,7 @@ impl ProjectWorkspace {
features: crate::CargoFeatures::default(), features: crate::CargoFeatures::default(),
..config.clone() ..config.clone()
}, },
sysroot_ref, &sysroot,
progress, progress,
) { ) {
Ok(meta) => { Ok(meta) => {
@ -272,7 +266,7 @@ impl ProjectWorkspace {
&workspace, &workspace,
cargo_toml.parent(), cargo_toml.parent(),
&config.extra_env, &config.extra_env,
sysroot_ref &sysroot
); );
Ok(Box::new((workspace, buildscripts))) Ok(Box::new((workspace, buildscripts)))
} }
@ -290,7 +284,7 @@ impl ProjectWorkspace {
let toolchain = get_toolchain_version( let toolchain = get_toolchain_version(
cargo_toml.parent(), cargo_toml.parent(),
sysroot_ref, &sysroot,
Tool::Cargo, Tool::Cargo,
&config.extra_env, &config.extra_env,
"cargo ", "cargo ",
@ -298,12 +292,12 @@ impl ProjectWorkspace {
let rustc_cfg = rustc_cfg::get( let rustc_cfg = rustc_cfg::get(
config.target.as_deref(), config.target.as_deref(),
&config.extra_env, &config.extra_env,
RustcCfgConfig::Cargo(sysroot_ref, cargo_toml), RustcCfgConfig::Cargo(&sysroot, cargo_toml),
); );
let cfg_overrides = config.cfg_overrides.clone(); let cfg_overrides = config.cfg_overrides.clone();
let data_layout = target_data_layout::get( let data_layout = target_data_layout::get(
RustcDataLayoutConfig::Cargo(sysroot_ref, cargo_toml), RustcDataLayoutConfig::Cargo(&sysroot, cargo_toml),
config.target.as_deref(), config.target.as_deref(),
&config.extra_env, &config.extra_env,
); );
@ -315,7 +309,7 @@ impl ProjectWorkspace {
cargo_toml, cargo_toml,
cargo_toml.parent(), cargo_toml.parent(),
config, config,
sysroot_ref, &sysroot,
progress, progress,
) )
.with_context(|| { .with_context(|| {
@ -326,7 +320,7 @@ impl ProjectWorkspace {
let cargo = CargoWorkspace::new(meta, cargo_toml.clone()); let cargo = CargoWorkspace::new(meta, cargo_toml.clone());
let cargo_config_extra_env = let cargo_config_extra_env =
cargo_config_env(cargo_toml, &config.extra_env, sysroot_ref); cargo_config_env(cargo_toml, &config.extra_env, &sysroot);
ProjectWorkspace { ProjectWorkspace {
kind: ProjectWorkspaceKind::Cargo { kind: ProjectWorkspaceKind::Cargo {
cargo, cargo,
@ -354,32 +348,13 @@ impl ProjectWorkspace {
extra_env: &FxHashMap<String, String>, extra_env: &FxHashMap<String, String>,
cfg_overrides: &CfgOverrides, cfg_overrides: &CfgOverrides,
) -> ProjectWorkspace { ) -> ProjectWorkspace {
let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) { let sysroot =
(Some(sysroot), Some(sysroot_src)) => { Sysroot::load(project_json.sysroot.clone(), project_json.sysroot_src.clone(), false);
Ok(Sysroot::load(sysroot, Some(Ok(sysroot_src)), false)) let cfg_config = RustcCfgConfig::Rustc(&sysroot);
} let data_layout_config = RustcDataLayoutConfig::Rustc(&sysroot);
(Some(sysroot), None) => {
// assume sysroot is structured like rustup's and guess `sysroot_src`
let sysroot_src =
sysroot.join("lib").join("rustlib").join("src").join("rust").join("library");
Ok(Sysroot::load(sysroot, Some(Ok(sysroot_src)), false))
}
(None, Some(sysroot_src)) => {
// assume sysroot is structured like rustup's and guess `sysroot`
let mut sysroot = sysroot_src.clone();
for _ in 0..5 {
sysroot.pop();
}
Ok(Sysroot::load(sysroot, Some(Ok(sysroot_src)), false))
}
(None, None) => Err(None),
};
let sysroot_ref = sysroot.as_ref().ok();
let cfg_config = RustcCfgConfig::Rustc(sysroot_ref);
let data_layout_config = RustcDataLayoutConfig::Rustc(sysroot_ref);
let toolchain = match get_toolchain_version( let toolchain = match get_toolchain_version(
project_json.path(), project_json.path(),
sysroot_ref, &sysroot,
Tool::Rustc, Tool::Rustc,
extra_env, extra_env,
"rustc ", "rustc ",
@ -410,24 +385,16 @@ impl ProjectWorkspace {
let dir = detached_file.parent(); let dir = detached_file.parent();
let sysroot = match &config.sysroot { let sysroot = match &config.sysroot {
Some(RustLibSource::Path(path)) => { Some(RustLibSource::Path(path)) => {
Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata) Sysroot::discover_sysroot_src_dir(path.clone(), config.sysroot_query_metadata)
.map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}")))
} }
Some(RustLibSource::Discover) => Sysroot::discover( Some(RustLibSource::Discover) => {
dir, Sysroot::discover(dir, &config.extra_env, config.sysroot_query_metadata)
&config.extra_env, }
config.sysroot_query_metadata, None => Sysroot::empty(),
)
.map_err(|e| {
Some(format!("Failed to find sysroot for {dir}. Is rust-src installed? {e}"))
}),
None => Err(None),
}; };
let sysroot_ref = sysroot.as_ref().ok();
let toolchain = let toolchain =
match get_toolchain_version(dir, sysroot_ref, Tool::Rustc, &config.extra_env, "rustc ") match get_toolchain_version(dir, &sysroot, Tool::Rustc, &config.extra_env, "rustc ") {
{
Ok(it) => it, Ok(it) => it,
Err(e) => { Err(e) => {
tracing::error!("{e}"); tracing::error!("{e}");
@ -435,25 +402,24 @@ impl ProjectWorkspace {
} }
}; };
let rustc_cfg = rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(sysroot_ref)); let rustc_cfg = rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(&sysroot));
let data_layout = target_data_layout::get( let data_layout = target_data_layout::get(
RustcDataLayoutConfig::Rustc(sysroot_ref), RustcDataLayoutConfig::Rustc(&sysroot),
None, None,
&config.extra_env, &config.extra_env,
); );
let cargo_script = let cargo_script =
CargoWorkspace::fetch_metadata(detached_file, dir, config, sysroot_ref, &|_| ()) CargoWorkspace::fetch_metadata(detached_file, dir, config, &sysroot, &|_| ()).ok().map(
.ok() |ws| {
.map(|ws| {
( (
CargoWorkspace::new(ws, detached_file.clone()), CargoWorkspace::new(ws, detached_file.clone()),
WorkspaceBuildScripts::default(), WorkspaceBuildScripts::default(),
) )
}); },
);
let cargo_config_extra_env = let cargo_config_extra_env = cargo_config_env(detached_file, &config.extra_env, &sysroot);
cargo_config_env(detached_file, &config.extra_env, sysroot_ref);
Ok(ProjectWorkspace { Ok(ProjectWorkspace {
kind: ProjectWorkspaceKind::DetachedFile { kind: ProjectWorkspaceKind::DetachedFile {
file: detached_file.to_owned(), file: detached_file.to_owned(),
@ -489,7 +455,7 @@ impl ProjectWorkspace {
cargo, cargo,
progress, progress,
self.toolchain.as_ref(), self.toolchain.as_ref(),
self.sysroot.as_ref().ok(), &self.sysroot,
) )
.with_context(|| { .with_context(|| {
format!("Failed to run build scripts for {}", cargo.workspace_root()) format!("Failed to run build scripts for {}", cargo.workspace_root())
@ -562,17 +528,7 @@ impl ProjectWorkspace {
} }
pub fn find_sysroot_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> { pub fn find_sysroot_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
match &self.sysroot { self.sysroot.discover_proc_macro_srv()
Ok(sysroot) => sysroot.discover_proc_macro_srv(),
Err(None) => Err(anyhow::format_err!(
"cannot find proc-macro server, the workspace `{}` is missing a sysroot",
self.manifest_or_root()
)),
Err(Some(e)) => Err(anyhow::format_err!(
"cannot find proc-macro server, the workspace `{}` is missing a sysroot: {e}",
self.manifest_or_root()
)),
}
} }
/// Returns the roots for the current `ProjectWorkspace` /// Returns the roots for the current `ProjectWorkspace`
@ -580,39 +536,37 @@ impl ProjectWorkspace {
/// 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 = || { let mk_sysroot = || {
self.sysroot.as_ref().into_iter().flat_map(move |sysroot: &Sysroot| { let mut r = match self.sysroot.mode() {
let mut r = match sysroot.mode() { SysrootMode::Workspace(ws) => ws
SysrootMode::Workspace(ws) => ws .packages()
.packages() .filter_map(|pkg| {
.filter_map(|pkg| { if ws[pkg].is_local {
if ws[pkg].is_local { // the local ones are included in the main `PackageRoot`` below
// the local ones are included in the main `PackageRoot`` below return None;
return None; }
} let pkg_root = ws[pkg].manifest.parent().to_path_buf();
let pkg_root = ws[pkg].manifest.parent().to_path_buf();
let include = vec![pkg_root.clone()]; let include = vec![pkg_root.clone()];
let exclude = vec![ let exclude = vec![
pkg_root.join(".git"), pkg_root.join(".git"),
pkg_root.join("target"), pkg_root.join("target"),
pkg_root.join("tests"), pkg_root.join("tests"),
pkg_root.join("examples"), pkg_root.join("examples"),
pkg_root.join("benches"), pkg_root.join("benches"),
]; ];
Some(PackageRoot { is_local: false, include, exclude }) Some(PackageRoot { is_local: false, include, exclude })
}) })
.collect(), .collect(),
SysrootMode::Stitched(_) => vec![], SysrootMode::Stitched(_) | SysrootMode::Empty => vec![],
}; };
r.push(PackageRoot { r.push(PackageRoot {
is_local: false, is_local: false,
include: sysroot.src_root().map(|it| it.to_path_buf()).into_iter().collect(), include: self.sysroot.src_root().map(|it| it.to_path_buf()).into_iter().collect(),
exclude: Vec::new(), exclude: Vec::new(),
}); });
r r
})
}; };
match &self.kind { match &self.kind {
ProjectWorkspaceKind::Json(project) => project ProjectWorkspaceKind::Json(project) => project
@ -731,19 +685,15 @@ impl ProjectWorkspace {
} }
pub fn n_packages(&self) -> usize { pub fn n_packages(&self) -> usize {
let sysroot_package_len = self.sysroot.num_packages();
match &self.kind { match &self.kind {
ProjectWorkspaceKind::Json(project) => { ProjectWorkspaceKind::Json(project) => sysroot_package_len + project.n_crates(),
let sysroot_package_len = self.sysroot.as_ref().map_or(0, |it| it.num_packages());
sysroot_package_len + project.n_crates()
}
ProjectWorkspaceKind::Cargo { cargo, rustc, .. } => { ProjectWorkspaceKind::Cargo { cargo, rustc, .. } => {
let rustc_package_len = let rustc_package_len =
rustc.as_ref().map(|a| a.as_ref()).map_or(0, |(it, _)| it.packages().len()); rustc.as_ref().map(|a| a.as_ref()).map_or(0, |(it, _)| it.packages().len());
let sysroot_package_len = self.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
} }
ProjectWorkspaceKind::DetachedFile { cargo: cargo_script, .. } => { ProjectWorkspaceKind::DetachedFile { cargo: cargo_script, .. } => {
let sysroot_package_len = self.sysroot.as_ref().map_or(0, |it| it.num_packages());
sysroot_package_len sysroot_package_len
+ cargo_script.as_ref().map_or(1, |(cargo, _)| cargo.packages().len()) + cargo_script.as_ref().map_or(1, |(cargo, _)| cargo.packages().len())
} }
@ -764,7 +714,7 @@ impl ProjectWorkspace {
rustc_cfg.clone(), rustc_cfg.clone(),
load, load,
project, project,
sysroot.as_ref().ok(), sysroot,
extra_env, extra_env,
cfg_overrides, cfg_overrides,
), ),
@ -780,7 +730,7 @@ impl ProjectWorkspace {
load, load,
rustc.as_ref().map(|a| a.as_ref()).ok(), rustc.as_ref().map(|a| a.as_ref()).ok(),
cargo, cargo,
sysroot.as_ref().ok(), sysroot,
rustc_cfg.clone(), rustc_cfg.clone(),
cfg_overrides, cfg_overrides,
build_scripts, build_scripts,
@ -793,7 +743,7 @@ impl ProjectWorkspace {
&mut |path| load(path), &mut |path| load(path),
None, None,
cargo, cargo,
sysroot.as_ref().ok(), sysroot,
rustc_cfg.clone(), rustc_cfg.clone(),
cfg_overrides, cfg_overrides,
build_scripts, build_scripts,
@ -803,7 +753,7 @@ impl ProjectWorkspace {
rustc_cfg.clone(), rustc_cfg.clone(),
load, load,
file, file,
sysroot.as_ref().ok(), sysroot,
cfg_overrides, cfg_overrides,
) )
}, },
@ -811,9 +761,7 @@ impl ProjectWorkspace {
), ),
}; };
if matches!(sysroot.as_ref().map(|it| it.mode()), Ok(SysrootMode::Stitched(_))) if matches!(sysroot.mode(), SysrootMode::Stitched(_)) && crate_graph.patch_cfg_if() {
&& crate_graph.patch_cfg_if()
{
tracing::debug!("Patched std to depend on cfg-if") tracing::debug!("Patched std to depend on cfg-if")
} else { } else {
tracing::debug!("Did not patch std to depend on cfg-if") tracing::debug!("Did not patch std to depend on cfg-if")
@ -892,15 +840,14 @@ fn project_json_to_crate_graph(
rustc_cfg: Vec<CfgFlag>, rustc_cfg: Vec<CfgFlag>,
load: FileLoader<'_>, load: FileLoader<'_>,
project: &ProjectJson, project: &ProjectJson,
sysroot: Option<&Sysroot>, sysroot: &Sysroot,
extra_env: &FxHashMap<String, String>, extra_env: &FxHashMap<String, String>,
override_cfg: &CfgOverrides, override_cfg: &CfgOverrides,
) -> (CrateGraph, ProcMacroPaths) { ) -> (CrateGraph, ProcMacroPaths) {
let mut res = (CrateGraph::default(), ProcMacroPaths::default()); let mut res = (CrateGraph::default(), ProcMacroPaths::default());
let (crate_graph, proc_macros) = &mut res; let (crate_graph, proc_macros) = &mut res;
let sysroot_deps = sysroot let (public_deps, libproc_macro) =
.as_ref() sysroot_to_crate_graph(crate_graph, sysroot, rustc_cfg.clone(), load);
.map(|sysroot| sysroot_to_crate_graph(crate_graph, sysroot, rustc_cfg.clone(), load));
let r_a_cfg_flag = CfgFlag::Atom("rust_analyzer".to_owned()); let r_a_cfg_flag = CfgFlag::Atom("rust_analyzer".to_owned());
let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default(); let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
@ -978,11 +925,9 @@ fn project_json_to_crate_graph(
for (from_idx, krate) in project.crates() { for (from_idx, krate) in project.crates() {
if let Some(&from) = idx_to_crate_id.get(&from_idx) { if let Some(&from) = idx_to_crate_id.get(&from_idx) {
if let Some((public_deps, libproc_macro)) = &sysroot_deps { public_deps.add_to_crate_graph(crate_graph, from);
public_deps.add_to_crate_graph(crate_graph, from); if let Some(proc_macro) = libproc_macro {
if let Some(proc_macro) = libproc_macro { add_proc_macro_dep(crate_graph, from, proc_macro, krate.is_proc_macro);
add_proc_macro_dep(crate_graph, from, *proc_macro, krate.is_proc_macro);
}
} }
for dep in &krate.deps { for dep in &krate.deps {
@ -999,7 +944,7 @@ fn cargo_to_crate_graph(
load: FileLoader<'_>, load: FileLoader<'_>,
rustc: Option<&(CargoWorkspace, WorkspaceBuildScripts)>, rustc: Option<&(CargoWorkspace, WorkspaceBuildScripts)>,
cargo: &CargoWorkspace, cargo: &CargoWorkspace,
sysroot: Option<&Sysroot>, sysroot: &Sysroot,
rustc_cfg: Vec<CfgFlag>, rustc_cfg: Vec<CfgFlag>,
override_cfg: &CfgOverrides, override_cfg: &CfgOverrides,
build_scripts: &WorkspaceBuildScripts, build_scripts: &WorkspaceBuildScripts,
@ -1008,10 +953,8 @@ fn cargo_to_crate_graph(
let mut res = (CrateGraph::default(), ProcMacroPaths::default()); let mut res = (CrateGraph::default(), ProcMacroPaths::default());
let crate_graph = &mut res.0; let crate_graph = &mut res.0;
let proc_macros = &mut res.1; let proc_macros = &mut res.1;
let (public_deps, libproc_macro) = match sysroot { let (public_deps, libproc_macro) =
Some(sysroot) => sysroot_to_crate_graph(crate_graph, sysroot, rustc_cfg.clone(), load), sysroot_to_crate_graph(crate_graph, sysroot, rustc_cfg.clone(), load);
None => (SysrootPublicDeps::default(), None),
};
let cfg_options = CfgOptions::from_iter(rustc_cfg); let cfg_options = CfgOptions::from_iter(rustc_cfg);
@ -1188,15 +1131,13 @@ fn detached_file_to_crate_graph(
rustc_cfg: Vec<CfgFlag>, rustc_cfg: Vec<CfgFlag>,
load: FileLoader<'_>, load: FileLoader<'_>,
detached_file: &ManifestPath, detached_file: &ManifestPath,
sysroot: Option<&Sysroot>, sysroot: &Sysroot,
override_cfg: &CfgOverrides, override_cfg: &CfgOverrides,
) -> (CrateGraph, ProcMacroPaths) { ) -> (CrateGraph, ProcMacroPaths) {
let _p = tracing::span!(tracing::Level::INFO, "detached_file_to_crate_graph").entered(); let _p = tracing::span!(tracing::Level::INFO, "detached_file_to_crate_graph").entered();
let mut crate_graph = CrateGraph::default(); let mut crate_graph = CrateGraph::default();
let (public_deps, _libproc_macro) = match sysroot { let (public_deps, _libproc_macro) =
Some(sysroot) => sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load), sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load);
None => (SysrootPublicDeps::default(), None),
};
let mut cfg_options = CfgOptions::from_iter(rustc_cfg); let mut cfg_options = CfgOptions::from_iter(rustc_cfg);
cfg_options.insert_atom("test".into()); cfg_options.insert_atom("test".into());
@ -1431,7 +1372,7 @@ fn sysroot_to_crate_graph(
load, load,
None, None,
cargo, cargo,
None, &Sysroot::empty(),
rustc_cfg, rustc_cfg,
&CfgOverrides { &CfgOverrides {
global: CfgDiff::new( global: CfgDiff::new(
@ -1554,6 +1495,7 @@ fn sysroot_to_crate_graph(
stitched.proc_macro().and_then(|it| sysroot_crates.get(&it).copied()); stitched.proc_macro().and_then(|it| sysroot_crates.get(&it).copied());
(public_deps, libproc_macro) (public_deps, libproc_macro)
} }
SysrootMode::Empty => (SysrootPublicDeps { deps: vec![] }, None),
} }
} }

View file

@ -69,11 +69,9 @@ impl Tester {
let cargo_config = let cargo_config =
CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() }; CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() };
let sysroot = let sysroot = Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env, false);
Ok(Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env, false)
.unwrap());
let data_layout = target_data_layout::get( let data_layout = target_data_layout::get(
RustcDataLayoutConfig::Rustc(sysroot.as_ref().ok()), RustcDataLayoutConfig::Rustc(&sysroot),
None, None,
&cargo_config.extra_env, &cargo_config.extra_env,
); );

View file

@ -1783,18 +1783,18 @@ pub(crate) fn handle_open_docs(
let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match &ws.kind { let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match &ws.kind {
ProjectWorkspaceKind::Cargo { cargo, .. } ProjectWorkspaceKind::Cargo { cargo, .. }
| ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. } => { | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. } => {
Some((cargo, ws.sysroot.as_ref().ok())) Some((cargo, &ws.sysroot))
} }
ProjectWorkspaceKind::Json { .. } => None, ProjectWorkspaceKind::Json { .. } => None,
ProjectWorkspaceKind::DetachedFile { .. } => None, ProjectWorkspaceKind::DetachedFile { .. } => None,
}); });
let (cargo, sysroot) = match ws_and_sysroot { let (cargo, sysroot) = match ws_and_sysroot {
Some((ws, sysroot)) => (Some(ws), sysroot), Some((ws, sysroot)) => (Some(ws), Some(sysroot)),
_ => (None, None), _ => (None, None),
}; };
let sysroot = sysroot.map(|p| p.root().as_str()); let sysroot = sysroot.and_then(|p| p.root()).map(|it| it.as_str());
let target_dir = cargo.map(|cargo| cargo.target_directory()).map(|p| p.as_str()); let target_dir = cargo.map(|cargo| cargo.target_directory()).map(|p| p.as_str());
let Ok(remote_urls) = snap.analysis.external_docs(position, target_dir, sysroot) else { let Ok(remote_urls) = snap.analysis.external_docs(position, target_dir, sysroot) else {

View file

@ -500,7 +500,6 @@ pub struct ServerStatusParams {
pub health: Health, pub health: Health,
pub quiescent: bool, pub quiescent: bool,
pub message: Option<String>, pub message: Option<String>,
pub workspace_info: Option<String>,
} }
#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] #[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]

View file

@ -103,7 +103,6 @@ impl GlobalState {
health: lsp_ext::Health::Ok, health: lsp_ext::Health::Ok,
quiescent: self.is_quiescent(), quiescent: self.is_quiescent(),
message: None, message: None,
workspace_info: None,
}; };
let mut message = String::new(); let mut message = String::new();
@ -164,53 +163,37 @@ impl GlobalState {
let proc_macro_clients = let proc_macro_clients =
self.proc_macro_clients.iter().map(Some).chain(iter::repeat_with(|| None)); self.proc_macro_clients.iter().map(Some).chain(iter::repeat_with(|| None));
let mut workspace_info = "Loaded workspaces:\n".to_owned();
for (ws, proc_macro_client) in self.workspaces.iter().zip(proc_macro_clients) { for (ws, proc_macro_client) in self.workspaces.iter().zip(proc_macro_clients) {
format_to!(workspace_info, "- `{}`\n", ws.manifest_or_root()); if let Some(err) = ws.sysroot.error() {
format_to!(workspace_info, " - sysroot:");
match ws.sysroot.as_ref() {
Err(None) => format_to!(workspace_info, " None"),
Err(Some(e)) => {
status.health |= lsp_ext::Health::Warning;
format_to!(workspace_info, " {e}");
}
Ok(s) => {
format_to!(workspace_info, " `{}`", s.root().to_string());
if let Some(err) = s
.check_has_core()
.err()
.inspect(|_| status.health |= lsp_ext::Health::Warning)
{
format_to!(workspace_info, " ({err})");
}
if let Some(src_root) = s.src_root() {
format_to!(
workspace_info,
"\n - sysroot source: `{}`",
src_root
);
}
format_to!(workspace_info, "\n");
}
}
if let ProjectWorkspaceKind::Cargo { rustc: Err(Some(e)), .. } = &ws.kind {
status.health |= lsp_ext::Health::Warning; status.health |= lsp_ext::Health::Warning;
format_to!(workspace_info, " - rustc workspace: {e}\n"); format_to!(
message,
"Workspace `{}` has sysroot errors: ",
ws.manifest_or_root()
);
message.push_str(err);
message.push_str("\n\n");
}
if let ProjectWorkspaceKind::Cargo { rustc: Err(Some(err)), .. } = &ws.kind {
status.health |= lsp_ext::Health::Warning;
format_to!(
message,
"Failed loading rustc_private crates for workspace `{}`: ",
ws.manifest_or_root()
);
message.push_str(err);
message.push_str("\n\n");
}; };
if let Some(proc_macro_client) = proc_macro_client { if let Some(Err(err)) = proc_macro_client {
format_to!(workspace_info, " - proc-macro server: "); status.health |= lsp_ext::Health::Warning;
match proc_macro_client { format_to!(
Ok(it) => format_to!(workspace_info, "`{}`\n", it.path()), message,
Err(e) => { "Failed spawning proc-macro server for workspace `{}`: {err}",
status.health |= lsp_ext::Health::Warning; ws.manifest_or_root()
format_to!(workspace_info, "{e}\n") );
} message.push_str("\n\n");
}
} }
} }
status.workspace_info = Some(workspace_info);
} }
if !message.is_empty() { if !message.is_empty() {
@ -534,8 +517,8 @@ impl GlobalState {
.map(|(a, b)| (a.clone(), b.clone())) .map(|(a, b)| (a.clone(), b.clone()))
.chain( .chain(
ws.sysroot ws.sysroot
.as_ref() .root()
.map(|it| ("RUSTUP_TOOLCHAIN".to_owned(), it.root().to_string())), .map(|it| ("RUSTUP_TOOLCHAIN".to_owned(), it.to_string())),
) )
.collect(), .collect(),
@ -719,7 +702,7 @@ impl GlobalState {
} }
ProjectWorkspaceKind::DetachedFile { .. } => return None, ProjectWorkspaceKind::DetachedFile { .. } => return None,
}, },
ws.sysroot.as_ref().ok().map(|sysroot| sysroot.root().to_owned()), ws.sysroot.root().map(ToOwned::to_owned),
)) ))
}) })
.map(|(id, (root, manifest_path), sysroot_root)| { .map(|(id, (root, manifest_path), sysroot_root)| {

View file

@ -21,7 +21,7 @@ fn load_cargo_with_fake_sysroot(file: &str) -> ProjectWorkspace {
rustc: Err(None), rustc: Err(None),
cargo_config_extra_env: Default::default(), cargo_config_extra_env: Default::default(),
}, },
sysroot: Ok(get_fake_sysroot()), sysroot: get_fake_sysroot(),
rustc_cfg: Vec::new(), rustc_cfg: Vec::new(),
cfg_overrides: Default::default(), cfg_overrides: Default::default(),
toolchain: None, toolchain: None,
@ -69,7 +69,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_utf8(sysroot_path); let sysroot_dir = AbsPathBuf::assert_utf8(sysroot_path);
let sysroot_src_dir = sysroot_dir.clone(); let sysroot_src_dir = sysroot_dir.clone();
Sysroot::load(sysroot_dir, Some(Ok(sysroot_src_dir)), false) Sysroot::load(Some(sysroot_dir), Some(sysroot_src_dir), false)
} }
#[test] #[test]

View file

@ -1059,11 +1059,11 @@ fn resolve_proc_macro() {
return; return;
} }
let sysroot = project_model::Sysroot::discover_no_source( let sysroot = project_model::Sysroot::discover(
&AbsPathBuf::assert_utf8(std::env::current_dir().unwrap()), &AbsPathBuf::assert_utf8(std::env::current_dir().unwrap()),
&Default::default(), &Default::default(),
) false,
.unwrap(); );
let proc_macro_server_path = sysroot.discover_proc_macro_srv().unwrap(); let proc_macro_server_path = sysroot.discover_proc_macro_srv().unwrap();

View file

@ -1,5 +1,5 @@
<!--- <!---
lsp/ext.rs hash: a39009c351009d16 lsp/ext.rs hash: 422dcc22c2e56166
If you need to change the above hash to make the test pass, please check if you If you need to change the above hash to make the test pass, please check if you
need to adjust this doc as well and ping this issue: need to adjust this doc as well and ping this issue:

View file

@ -472,12 +472,6 @@ export class Ctx implements RustAnalyzerExtensionApi {
if (status.message) { if (status.message) {
statusBar.tooltip.appendText(status.message); statusBar.tooltip.appendText(status.message);
} }
if (status.workspaceInfo) {
if (statusBar.tooltip.value) {
statusBar.tooltip.appendMarkdown("\n\n---\n\n");
}
statusBar.tooltip.appendMarkdown(status.workspaceInfo);
}
if (statusBar.tooltip.value) { if (statusBar.tooltip.value) {
statusBar.tooltip.appendMarkdown("\n\n---\n\n"); statusBar.tooltip.appendMarkdown("\n\n---\n\n");
} }

View file

@ -241,7 +241,6 @@ export type ServerStatusParams = {
health: "ok" | "warning" | "error"; health: "ok" | "warning" | "error";
quiescent: boolean; quiescent: boolean;
message?: string; message?: string;
workspaceInfo?: string;
}; };
export type SsrParams = { export type SsrParams = {
query: string; query: string;