mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-19 18:34:08 +00:00
Auto merge of #16537 - Veykril:sysroot-tools, r=Veykril
internal: tool discovery prefers sysroot tools Fixes https://github.com/rust-lang/rust-analyzer/issues/15927, Fixes https://github.com/rust-lang/rust-analyzer/issues/16523 After this PR we will look for `cargo` and `rustc` in the sysroot if it was succesfully loaded instead of using the current lookup scheme. This should be more correct than the current approach as that relies on the working directory of the server binary or loade workspace, meaning it can behave a bit odd wrt overrides. Additionally, rust-project.json projects now get the target data layout set so there should be better const eval support now.
This commit is contained in:
commit
5e1b09bb76
@ -89,9 +89,10 @@ impl FlycheckHandle {
|
|||||||
id: usize,
|
id: usize,
|
||||||
sender: Box<dyn Fn(Message) + Send>,
|
sender: Box<dyn Fn(Message) + Send>,
|
||||||
config: FlycheckConfig,
|
config: FlycheckConfig,
|
||||||
|
cargo: PathBuf,
|
||||||
workspace_root: AbsPathBuf,
|
workspace_root: AbsPathBuf,
|
||||||
) -> FlycheckHandle {
|
) -> FlycheckHandle {
|
||||||
let actor = FlycheckActor::new(id, sender, config, workspace_root);
|
let actor = FlycheckActor::new(id, sender, config, cargo, workspace_root);
|
||||||
let (sender, receiver) = unbounded::<StateChange>();
|
let (sender, receiver) = unbounded::<StateChange>();
|
||||||
let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker)
|
let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker)
|
||||||
.name("Flycheck".to_owned())
|
.name("Flycheck".to_owned())
|
||||||
@ -171,6 +172,7 @@ struct FlycheckActor {
|
|||||||
/// Either the workspace root of the workspace we are flychecking,
|
/// Either the workspace root of the workspace we are flychecking,
|
||||||
/// or the project root of the project.
|
/// or the project root of the project.
|
||||||
root: AbsPathBuf,
|
root: AbsPathBuf,
|
||||||
|
cargo: PathBuf,
|
||||||
/// CargoHandle exists to wrap around the communication needed to be able to
|
/// CargoHandle exists to wrap around the communication needed to be able to
|
||||||
/// run `cargo check` without blocking. Currently the Rust standard library
|
/// run `cargo check` without blocking. Currently the Rust standard library
|
||||||
/// doesn't provide a way to read sub-process output without blocking, so we
|
/// doesn't provide a way to read sub-process output without blocking, so we
|
||||||
@ -189,10 +191,11 @@ impl FlycheckActor {
|
|||||||
id: usize,
|
id: usize,
|
||||||
sender: Box<dyn Fn(Message) + Send>,
|
sender: Box<dyn Fn(Message) + Send>,
|
||||||
config: FlycheckConfig,
|
config: FlycheckConfig,
|
||||||
|
cargo: PathBuf,
|
||||||
workspace_root: AbsPathBuf,
|
workspace_root: AbsPathBuf,
|
||||||
) -> FlycheckActor {
|
) -> FlycheckActor {
|
||||||
tracing::info!(%id, ?workspace_root, "Spawning flycheck");
|
tracing::info!(%id, ?workspace_root, "Spawning flycheck");
|
||||||
FlycheckActor { id, sender, config, root: workspace_root, command_handle: None }
|
FlycheckActor { id, sender, config, cargo, root: workspace_root, command_handle: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_progress(&self, progress: Progress) {
|
fn report_progress(&self, progress: Progress) {
|
||||||
@ -316,7 +319,7 @@ impl FlycheckActor {
|
|||||||
ansi_color_output,
|
ansi_color_output,
|
||||||
target_dir,
|
target_dir,
|
||||||
} => {
|
} => {
|
||||||
let mut cmd = Command::new(toolchain::cargo());
|
let mut cmd = Command::new(&self.cargo);
|
||||||
cmd.arg(command);
|
cmd.arg(command);
|
||||||
cmd.current_dir(&self.root);
|
cmd.current_dir(&self.root);
|
||||||
|
|
||||||
|
@ -1,6 +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 rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use test_fixture::WithFixture;
|
use test_fixture::WithFixture;
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
@ -15,7 +16,12 @@ use crate::{
|
|||||||
mod closure;
|
mod closure;
|
||||||
|
|
||||||
fn current_machine_data_layout() -> String {
|
fn current_machine_data_layout() -> String {
|
||||||
project_model::target_data_layout::get(None, None, &FxHashMap::default()).unwrap()
|
project_model::target_data_layout::get(
|
||||||
|
RustcDataLayoutConfig::Rustc(None),
|
||||||
|
None,
|
||||||
|
&FxHashMap::default(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutError> {
|
fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutError> {
|
||||||
|
@ -20,10 +20,11 @@ use paths::{AbsPath, AbsPathBuf};
|
|||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use toolchain::Tool;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cfg_flag::CfgFlag, utf8_stdout, CargoConfig, CargoFeatures, CargoWorkspace, InvocationLocation,
|
cfg_flag::CfgFlag, utf8_stdout, CargoConfig, CargoFeatures, CargoWorkspace, InvocationLocation,
|
||||||
InvocationStrategy, Package,
|
InvocationStrategy, Package, Sysroot,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||||
@ -61,6 +62,7 @@ impl WorkspaceBuildScripts {
|
|||||||
config: &CargoConfig,
|
config: &CargoConfig,
|
||||||
allowed_features: &FxHashSet<String>,
|
allowed_features: &FxHashSet<String>,
|
||||||
workspace_root: &AbsPathBuf,
|
workspace_root: &AbsPathBuf,
|
||||||
|
sysroot: Option<&Sysroot>,
|
||||||
) -> io::Result<Command> {
|
) -> io::Result<Command> {
|
||||||
let mut cmd = match config.run_build_script_command.as_deref() {
|
let mut cmd = match config.run_build_script_command.as_deref() {
|
||||||
Some([program, args @ ..]) => {
|
Some([program, args @ ..]) => {
|
||||||
@ -69,7 +71,10 @@ impl WorkspaceBuildScripts {
|
|||||||
cmd
|
cmd
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut cmd = Command::new(toolchain::cargo());
|
let mut cmd = Command::new(
|
||||||
|
Sysroot::discover_tool(sysroot, Tool::Cargo)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::NotFound, e))?,
|
||||||
|
);
|
||||||
|
|
||||||
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);
|
||||||
@ -133,6 +138,7 @@ impl WorkspaceBuildScripts {
|
|||||||
workspace: &CargoWorkspace,
|
workspace: &CargoWorkspace,
|
||||||
progress: &dyn Fn(String),
|
progress: &dyn Fn(String),
|
||||||
toolchain: &Option<Version>,
|
toolchain: &Option<Version>,
|
||||||
|
sysroot: Option<&Sysroot>,
|
||||||
) -> io::Result<WorkspaceBuildScripts> {
|
) -> io::Result<WorkspaceBuildScripts> {
|
||||||
const RUST_1_62: Version = Version::new(1, 62, 0);
|
const RUST_1_62: Version = Version::new(1, 62, 0);
|
||||||
|
|
||||||
@ -151,6 +157,7 @@ impl WorkspaceBuildScripts {
|
|||||||
config,
|
config,
|
||||||
&allowed_features,
|
&allowed_features,
|
||||||
&workspace.workspace_root().to_path_buf(),
|
&workspace.workspace_root().to_path_buf(),
|
||||||
|
sysroot,
|
||||||
)?,
|
)?,
|
||||||
workspace,
|
workspace,
|
||||||
current_dir,
|
current_dir,
|
||||||
@ -165,6 +172,7 @@ impl WorkspaceBuildScripts {
|
|||||||
config,
|
config,
|
||||||
&allowed_features,
|
&allowed_features,
|
||||||
&workspace.workspace_root().to_path_buf(),
|
&workspace.workspace_root().to_path_buf(),
|
||||||
|
sysroot,
|
||||||
)?;
|
)?;
|
||||||
cmd.args(["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
|
cmd.args(["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
|
||||||
let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?;
|
let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?;
|
||||||
@ -194,7 +202,7 @@ impl WorkspaceBuildScripts {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let cmd = Self::build_command(config, &Default::default(), workspace_root)?;
|
let cmd = Self::build_command(config, &Default::default(), workspace_root, None)?;
|
||||||
// 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
|
||||||
// exactly those from `config`.
|
// exactly those from `config`.
|
||||||
@ -415,6 +423,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>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut bs = WorkspaceBuildScripts::default();
|
let mut bs = WorkspaceBuildScripts::default();
|
||||||
for p in rustc.packages() {
|
for p in rustc.packages() {
|
||||||
@ -422,7 +431,7 @@ impl WorkspaceBuildScripts {
|
|||||||
}
|
}
|
||||||
let res = (|| {
|
let res = (|| {
|
||||||
let target_libdir = (|| {
|
let target_libdir = (|| {
|
||||||
let mut cargo_config = Command::new(toolchain::cargo());
|
let mut cargo_config = Command::new(Sysroot::discover_tool(sysroot, Tool::Cargo)?);
|
||||||
cargo_config.envs(extra_env);
|
cargo_config.envs(extra_env);
|
||||||
cargo_config
|
cargo_config
|
||||||
.current_dir(current_dir)
|
.current_dir(current_dir)
|
||||||
@ -431,7 +440,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 = Command::new(toolchain::rustc());
|
let mut cmd = Command::new(Sysroot::discover_tool(sysroot, 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)
|
||||||
|
@ -12,8 +12,9 @@ use paths::{AbsPath, AbsPathBuf};
|
|||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::from_value;
|
use serde_json::from_value;
|
||||||
|
use toolchain::Tool;
|
||||||
|
|
||||||
use crate::{utf8_stdout, InvocationLocation, ManifestPath};
|
use crate::{utf8_stdout, InvocationLocation, ManifestPath, Sysroot};
|
||||||
use crate::{CfgOverrides, InvocationStrategy};
|
use crate::{CfgOverrides, InvocationStrategy};
|
||||||
|
|
||||||
/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
|
/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
|
||||||
@ -236,12 +237,13 @@ impl CargoWorkspace {
|
|||||||
cargo_toml: &ManifestPath,
|
cargo_toml: &ManifestPath,
|
||||||
current_dir: &AbsPath,
|
current_dir: &AbsPath,
|
||||||
config: &CargoConfig,
|
config: &CargoConfig,
|
||||||
|
sysroot: Option<&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);
|
let targets = find_list_of_build_targets(config, cargo_toml, sysroot);
|
||||||
|
|
||||||
let mut meta = MetadataCommand::new();
|
let mut meta = MetadataCommand::new();
|
||||||
meta.cargo_path(toolchain::cargo());
|
meta.cargo_path(Sysroot::discover_tool(sysroot, Tool::Cargo)?);
|
||||||
meta.manifest_path(cargo_toml.to_path_buf());
|
meta.manifest_path(cargo_toml.to_path_buf());
|
||||||
match &config.features {
|
match &config.features {
|
||||||
CargoFeatures::All => {
|
CargoFeatures::All => {
|
||||||
@ -476,24 +478,29 @@ impl CargoWorkspace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_list_of_build_targets(config: &CargoConfig, cargo_toml: &ManifestPath) -> Vec<String> {
|
fn find_list_of_build_targets(
|
||||||
|
config: &CargoConfig,
|
||||||
|
cargo_toml: &ManifestPath,
|
||||||
|
sysroot: Option<&Sysroot>,
|
||||||
|
) -> Vec<String> {
|
||||||
if let Some(target) = &config.target {
|
if let Some(target) = &config.target {
|
||||||
return [target.into()].to_vec();
|
return [target.into()].to_vec();
|
||||||
}
|
}
|
||||||
|
|
||||||
let build_targets = cargo_config_build_target(cargo_toml, &config.extra_env);
|
let build_targets = cargo_config_build_target(cargo_toml, &config.extra_env, sysroot);
|
||||||
if !build_targets.is_empty() {
|
if !build_targets.is_empty() {
|
||||||
return build_targets;
|
return build_targets;
|
||||||
}
|
}
|
||||||
|
|
||||||
rustc_discover_host_triple(cargo_toml, &config.extra_env).into_iter().collect()
|
rustc_discover_host_triple(cargo_toml, &config.extra_env, sysroot).into_iter().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
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>,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let mut rustc = Command::new(toolchain::rustc());
|
let mut rustc = Command::new(Sysroot::discover_tool(sysroot, Tool::Rustc).ok()?);
|
||||||
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);
|
||||||
@ -519,8 +526,10 @@ 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>,
|
||||||
) -> Vec<String> {
|
) -> Vec<String> {
|
||||||
let mut cargo_config = Command::new(toolchain::cargo());
|
let Ok(program) = Sysroot::discover_tool(sysroot, Tool::Cargo) else { return vec![] };
|
||||||
|
let mut cargo_config = Command::new(program);
|
||||||
cargo_config.envs(extra_env);
|
cargo_config.envs(extra_env);
|
||||||
cargo_config
|
cargo_config
|
||||||
.current_dir(cargo_toml.parent())
|
.current_dir(cargo_toml.parent())
|
||||||
|
@ -8,17 +8,13 @@ use rustc_hash::FxHashMap;
|
|||||||
use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath, Sysroot};
|
use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath, Sysroot};
|
||||||
|
|
||||||
/// Determines how `rustc --print cfg` is discovered and invoked.
|
/// Determines how `rustc --print cfg` is discovered and invoked.
|
||||||
///
|
|
||||||
/// There options are supported:
|
|
||||||
/// - [`RustcCfgConfig::Cargo`], which relies on `cargo rustc --print cfg`
|
|
||||||
/// and `RUSTC_BOOTSTRAP`.
|
|
||||||
/// - [`RustcCfgConfig::Explicit`], which uses an explicit path to the `rustc`
|
|
||||||
/// binary in the sysroot.
|
|
||||||
/// - [`RustcCfgConfig::Discover`], which uses [`toolchain::rustc`].
|
|
||||||
pub(crate) enum RustcCfgConfig<'a> {
|
pub(crate) enum RustcCfgConfig<'a> {
|
||||||
Cargo(&'a ManifestPath),
|
/// Use `rustc --print cfg`, either from with the binary from the sysroot or by discovering via
|
||||||
Explicit(&'a Sysroot),
|
/// [`toolchain::rustc`].
|
||||||
Discover,
|
Rustc(Option<&'a Sysroot>),
|
||||||
|
/// Use `cargo --print cfg`, either from with the binary from the sysroot or by discovering via
|
||||||
|
/// [`toolchain::cargo`].
|
||||||
|
Cargo(Option<&'a Sysroot>, &'a ManifestPath),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get(
|
pub(crate) fn get(
|
||||||
@ -71,36 +67,31 @@ fn get_rust_cfgs(
|
|||||||
extra_env: &FxHashMap<String, String>,
|
extra_env: &FxHashMap<String, String>,
|
||||||
config: RustcCfgConfig<'_>,
|
config: RustcCfgConfig<'_>,
|
||||||
) -> anyhow::Result<String> {
|
) -> anyhow::Result<String> {
|
||||||
let mut cmd = match config {
|
match config {
|
||||||
RustcCfgConfig::Cargo(cargo_toml) => {
|
RustcCfgConfig::Cargo(sysroot, cargo_oml) => {
|
||||||
let mut cmd = Command::new(toolchain::cargo());
|
let cargo = Sysroot::discover_tool(sysroot, toolchain::Tool::Cargo)?;
|
||||||
|
let mut cmd = Command::new(cargo);
|
||||||
cmd.envs(extra_env);
|
cmd.envs(extra_env);
|
||||||
cmd.current_dir(cargo_toml.parent())
|
cmd.current_dir(cargo_oml.parent())
|
||||||
.args(["rustc", "-Z", "unstable-options", "--print", "cfg"])
|
.args(["rustc", "-Z", "unstable-options", "--print", "cfg"])
|
||||||
.env("RUSTC_BOOTSTRAP", "1");
|
.env("RUSTC_BOOTSTRAP", "1");
|
||||||
if let Some(target) = target {
|
if let Some(target) = target {
|
||||||
cmd.args(["--target", target]);
|
cmd.args(["--target", target]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return utf8_stdout(cmd).context("Unable to run `cargo rustc`");
|
utf8_stdout(cmd).context("Unable to run `cargo rustc`")
|
||||||
}
|
}
|
||||||
RustcCfgConfig::Explicit(sysroot) => {
|
RustcCfgConfig::Rustc(sysroot) => {
|
||||||
let rustc: std::path::PathBuf = sysroot.discover_rustc()?.into();
|
let rustc = Sysroot::discover_tool(sysroot, toolchain::Tool::Rustc)?;
|
||||||
tracing::debug!(?rustc, "using explicit rustc from sysroot");
|
tracing::debug!(?rustc, "using explicit rustc from sysroot");
|
||||||
Command::new(rustc)
|
let mut cmd = Command::new(rustc);
|
||||||
}
|
cmd.envs(extra_env);
|
||||||
RustcCfgConfig::Discover => {
|
cmd.args(["--print", "cfg", "-O"]);
|
||||||
let rustc = toolchain::rustc();
|
if let Some(target) = target {
|
||||||
tracing::debug!(?rustc, "using rustc from env");
|
cmd.args(["--target", target]);
|
||||||
Command::new(rustc)
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
cmd.envs(extra_env);
|
utf8_stdout(cmd).context("Unable to run `rustc`")
|
||||||
cmd.args(["--print", "cfg", "-O"]);
|
}
|
||||||
if let Some(target) = target {
|
|
||||||
cmd.args(["--target", target]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
utf8_stdout(cmd).context("Unable to run `rustc`")
|
|
||||||
}
|
}
|
||||||
|
@ -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, iter, ops, path::PathBuf, process::Command};
|
use std::{env, fs, iter, ops, path::PathBuf, process::Command, sync::Arc};
|
||||||
|
|
||||||
use anyhow::{format_err, Context, Result};
|
use anyhow::{format_err, Context, Result};
|
||||||
use base_db::CrateName;
|
use base_db::CrateName;
|
||||||
@ -12,16 +12,30 @@ 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;
|
||||||
|
use toolchain::{probe_for_binary, Tool};
|
||||||
|
|
||||||
use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath};
|
use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Sysroot {
|
pub struct Sysroot {
|
||||||
root: AbsPathBuf,
|
root: AbsPathBuf,
|
||||||
src_root: AbsPathBuf,
|
src_root: Option<Result<AbsPathBuf, Arc<anyhow::Error>>>,
|
||||||
mode: SysrootMode,
|
mode: SysrootMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
@ -86,8 +100,8 @@ impl Sysroot {
|
|||||||
|
|
||||||
/// 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) -> &AbsPath {
|
pub fn src_root(&self) -> Option<&AbsPath> {
|
||||||
&self.src_root
|
self.src_root.as_ref()?.as_deref().ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
@ -98,6 +112,11 @@ impl Sysroot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn loading_warning(&self) -> Option<String> {
|
pub fn loading_warning(&self) -> Option<String> {
|
||||||
|
let src_root = match &self.src_root {
|
||||||
|
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 {
|
let has_core = match &self.mode {
|
||||||
SysrootMode::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
|
SysrootMode::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
|
||||||
SysrootMode::Stitched(stitched) => stitched.by_name("core").is_some(),
|
SysrootMode::Stitched(stitched) => stitched.by_name("core").is_some(),
|
||||||
@ -108,10 +127,7 @@ impl Sysroot {
|
|||||||
} else {
|
} else {
|
||||||
" try running `rustup component add rust-src` to possible fix this"
|
" try running `rustup component add rust-src` to possible fix this"
|
||||||
};
|
};
|
||||||
Some(format!(
|
Some(format!("could not find libcore in loaded sysroot at `{}`{var_note}", src_root,))
|
||||||
"could not find libcore in loaded sysroot at `{}`{var_note}",
|
|
||||||
self.src_root.as_path(),
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -140,8 +156,19 @@ impl 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, metadata))
|
Ok(Sysroot::load(sysroot_dir, Some(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(
|
||||||
@ -152,33 +179,73 @@ impl Sysroot {
|
|||||||
) -> 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, metadata))
|
Ok(Sysroot::load(sysroot_dir, Some(Ok(src)), 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 discover_rustc(&self) -> anyhow::Result<AbsPathBuf> {
|
|
||||||
let rustc = self.root.join("bin/rustc");
|
|
||||||
tracing::debug!(?rustc, "checking for rustc binary at location");
|
|
||||||
match fs::metadata(&rustc) {
|
|
||||||
Ok(_) => Ok(rustc),
|
|
||||||
Err(e) => Err(e).context(format!(
|
|
||||||
"failed to discover rustc in sysroot: {:?}",
|
|
||||||
AsRef::<std::path::Path>::as_ref(&self.root)
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf, metadata: bool) -> 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, metadata))
|
Ok(Sysroot::load(sysroot_dir, Some(sysroot_src_dir), metadata))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf, metadata: bool) -> Sysroot {
|
pub fn discover_binary(&self, binary: &str) -> anyhow::Result<AbsPathBuf> {
|
||||||
|
toolchain::probe_for_binary(self.root.join("bin").join(binary).into())
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("no rustc binary found in {}", self.root.join("bin")))
|
||||||
|
.and_then(|rustc| {
|
||||||
|
fs::metadata(&rustc).map(|_| AbsPathBuf::assert(rustc)).with_context(|| {
|
||||||
|
format!(
|
||||||
|
"failed to discover rustc in sysroot: {:?}",
|
||||||
|
AsRef::<std::path::Path>::as_ref(&self.root)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn discover_tool(sysroot: Option<&Self>, tool: Tool) -> anyhow::Result<PathBuf> {
|
||||||
|
match sysroot {
|
||||||
|
Some(sysroot) => sysroot.discover_binary(tool.name()).map(Into::into),
|
||||||
|
None => Ok(tool.path()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn discover_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
|
||||||
|
["libexec", "lib"]
|
||||||
|
.into_iter()
|
||||||
|
.map(|segment| self.root().join(segment).join("rust-analyzer-proc-macro-srv"))
|
||||||
|
.find_map(|server_path| probe_for_binary(server_path.into()))
|
||||||
|
.map(AbsPathBuf::assert)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
anyhow::format_err!("cannot find proc-macro server in sysroot `{}`", self.root())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(
|
||||||
|
sysroot_dir: AbsPathBuf,
|
||||||
|
sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
|
||||||
|
metadata: bool,
|
||||||
|
) -> Sysroot {
|
||||||
|
let sysroot_src_dir = match sysroot_src_dir {
|
||||||
|
Some(Ok(sysroot_src_dir)) => sysroot_src_dir,
|
||||||
|
Some(Err(e)) => {
|
||||||
|
return Sysroot {
|
||||||
|
root: sysroot_dir,
|
||||||
|
src_root: Some(Err(Arc::new(e))),
|
||||||
|
mode: SysrootMode::Stitched(Stitched { crates: Arena::default() }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Sysroot {
|
||||||
|
root: sysroot_dir,
|
||||||
|
src_root: None,
|
||||||
|
mode: SysrootMode::Stitched(Stitched { crates: Arena::default() }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
if metadata {
|
if metadata {
|
||||||
let sysroot: Option<_> = (|| {
|
let sysroot: Option<_> = (|| {
|
||||||
let sysroot_cargo_toml = ManifestPath::try_from(
|
let sysroot_cargo_toml = ManifestPath::try_from(
|
||||||
@ -191,6 +258,7 @@ impl Sysroot {
|
|||||||
&sysroot_cargo_toml,
|
&sysroot_cargo_toml,
|
||||||
¤t_dir,
|
¤t_dir,
|
||||||
&CargoConfig::default(),
|
&CargoConfig::default(),
|
||||||
|
None,
|
||||||
&|_| (),
|
&|_| (),
|
||||||
)
|
)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
@ -274,7 +342,7 @@ impl Sysroot {
|
|||||||
let cargo_workspace = CargoWorkspace::new(res);
|
let cargo_workspace = CargoWorkspace::new(res);
|
||||||
Some(Sysroot {
|
Some(Sysroot {
|
||||||
root: sysroot_dir.clone(),
|
root: sysroot_dir.clone(),
|
||||||
src_root: sysroot_src_dir.clone(),
|
src_root: Some(Ok(sysroot_src_dir.clone())),
|
||||||
mode: SysrootMode::Workspace(cargo_workspace),
|
mode: SysrootMode::Workspace(cargo_workspace),
|
||||||
})
|
})
|
||||||
})();
|
})();
|
||||||
@ -326,7 +394,7 @@ impl Sysroot {
|
|||||||
}
|
}
|
||||||
Sysroot {
|
Sysroot {
|
||||||
root: sysroot_dir,
|
root: sysroot_dir,
|
||||||
src_root: sysroot_src_dir,
|
src_root: Some(Ok(sysroot_src_dir)),
|
||||||
mode: SysrootMode::Stitched(stitched),
|
mode: SysrootMode::Stitched(stitched),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,27 @@ use std::process::Command;
|
|||||||
|
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::{utf8_stdout, ManifestPath};
|
use crate::{utf8_stdout, ManifestPath, Sysroot};
|
||||||
|
|
||||||
|
/// Determines how `rustc --print target-spec-json` is discovered and invoked.
|
||||||
|
pub enum RustcDataLayoutConfig<'a> {
|
||||||
|
/// Use `rustc --print target-spec-json`, either from with the binary from the sysroot or by discovering via
|
||||||
|
/// [`toolchain::rustc`].
|
||||||
|
Rustc(Option<&'a Sysroot>),
|
||||||
|
/// Use `cargo --print target-spec-json`, either from with the binary from the sysroot or by discovering via
|
||||||
|
/// [`toolchain::cargo`].
|
||||||
|
Cargo(Option<&'a Sysroot>, &'a ManifestPath),
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get(
|
pub fn get(
|
||||||
cargo_toml: Option<&ManifestPath>,
|
config: RustcDataLayoutConfig<'_>,
|
||||||
target: Option<&str>,
|
target: Option<&str>,
|
||||||
extra_env: &FxHashMap<String, String>,
|
extra_env: &FxHashMap<String, String>,
|
||||||
) -> anyhow::Result<String> {
|
) -> anyhow::Result<String> {
|
||||||
let output = (|| {
|
let output = match config {
|
||||||
if let Some(cargo_toml) = cargo_toml {
|
RustcDataLayoutConfig::Cargo(sysroot, cargo_toml) => {
|
||||||
let mut cmd = Command::new(toolchain::rustc());
|
let cargo = Sysroot::discover_tool(sysroot, toolchain::Tool::Cargo)?;
|
||||||
|
let mut cmd = Command::new(cargo);
|
||||||
cmd.envs(extra_env);
|
cmd.envs(extra_env);
|
||||||
cmd.current_dir(cargo_toml.parent())
|
cmd.current_dir(cargo_toml.parent())
|
||||||
.args(["-Z", "unstable-options", "--print", "target-spec-json"])
|
.args(["-Z", "unstable-options", "--print", "target-spec-json"])
|
||||||
@ -20,21 +31,20 @@ pub fn get(
|
|||||||
if let Some(target) = target {
|
if let Some(target) = target {
|
||||||
cmd.args(["--target", target]);
|
cmd.args(["--target", target]);
|
||||||
}
|
}
|
||||||
match utf8_stdout(cmd) {
|
utf8_stdout(cmd)
|
||||||
Ok(it) => return Ok(it),
|
}
|
||||||
Err(e) => tracing::debug!("{e:?}: falling back to querying rustc for cfgs"),
|
RustcDataLayoutConfig::Rustc(sysroot) => {
|
||||||
|
let rustc = Sysroot::discover_tool(sysroot, toolchain::Tool::Rustc)?;
|
||||||
|
let mut cmd = Command::new(rustc);
|
||||||
|
cmd.envs(extra_env)
|
||||||
|
.args(["-Z", "unstable-options", "--print", "target-spec-json"])
|
||||||
|
.env("RUSTC_BOOTSTRAP", "1");
|
||||||
|
if let Some(target) = target {
|
||||||
|
cmd.args(["--target", target]);
|
||||||
}
|
}
|
||||||
|
utf8_stdout(cmd)
|
||||||
}
|
}
|
||||||
// using unstable cargo features failed, fall back to using plain rustc
|
}?;
|
||||||
let mut cmd = Command::new(toolchain::rustc());
|
|
||||||
cmd.envs(extra_env)
|
|
||||||
.args(["-Z", "unstable-options", "--print", "target-spec-json"])
|
|
||||||
.env("RUSTC_BOOTSTRAP", "1");
|
|
||||||
if let Some(target) = target {
|
|
||||||
cmd.args(["--target", target]);
|
|
||||||
}
|
|
||||||
utf8_stdout(cmd)
|
|
||||||
})()?;
|
|
||||||
(|| Some(output.split_once(r#""data-layout": ""#)?.1.split_once('"')?.0.to_owned()))()
|
(|| Some(output.split_once(r#""data-layout": ""#)?.1.split_once('"')?.0.to_owned()))()
|
||||||
.ok_or_else(|| anyhow::format_err!("could not fetch target-spec-json from command output"))
|
.ok_or_else(|| anyhow::format_err!("could not fetch target-spec-json from command output"))
|
||||||
}
|
}
|
||||||
|
@ -69,8 +69,13 @@ 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 = Ok(get_fake_sysroot());
|
||||||
let project_workspace =
|
let project_workspace = ProjectWorkspace::Json {
|
||||||
ProjectWorkspace::Json { project, sysroot, rustc_cfg: Vec::new(), toolchain: None };
|
project,
|
||||||
|
sysroot,
|
||||||
|
rustc_cfg: Vec::new(),
|
||||||
|
toolchain: None,
|
||||||
|
target_layout: Err("test has no data layout".to_owned()),
|
||||||
|
};
|
||||||
to_crate_graph(project_workspace)
|
to_crate_graph(project_workspace)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +130,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, false)
|
Sysroot::load(sysroot_dir, Some(Ok(sysroot_src_dir)), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
|
fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
//! metadata` or `rust-project.json`) into representation stored in the salsa
|
//! metadata` or `rust-project.json`) into representation stored in the salsa
|
||||||
//! database -- `CrateGraph`.
|
//! database -- `CrateGraph`.
|
||||||
|
|
||||||
use std::{collections::VecDeque, fmt, fs, iter, process::Command, str::FromStr, sync};
|
use std::{
|
||||||
|
collections::VecDeque, fmt, fs, iter, path::PathBuf, process::Command, str::FromStr, sync,
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::{format_err, Context};
|
use anyhow::{format_err, Context};
|
||||||
use base_db::{
|
use base_db::{
|
||||||
@ -23,8 +25,9 @@ use crate::{
|
|||||||
project_json::Crate,
|
project_json::Crate,
|
||||||
rustc_cfg::{self, RustcCfgConfig},
|
rustc_cfg::{self, RustcCfgConfig},
|
||||||
sysroot::{SysrootCrate, SysrootMode},
|
sysroot::{SysrootCrate, SysrootMode},
|
||||||
target_data_layout, utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath,
|
target_data_layout::{self, RustcDataLayoutConfig},
|
||||||
Package, ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
|
utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath, Package,
|
||||||
|
ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A set of cfg-overrides per crate.
|
/// A set of cfg-overrides per crate.
|
||||||
@ -79,6 +82,7 @@ pub enum ProjectWorkspace {
|
|||||||
/// `rustc --print cfg`.
|
/// `rustc --print cfg`.
|
||||||
rustc_cfg: Vec<CfgFlag>,
|
rustc_cfg: Vec<CfgFlag>,
|
||||||
toolchain: Option<Version>,
|
toolchain: Option<Version>,
|
||||||
|
target_layout: Result<String, String>,
|
||||||
},
|
},
|
||||||
// FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
|
// FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
|
||||||
// That's not the end user experience we should strive for.
|
// That's not the end user experience we should strive for.
|
||||||
@ -126,14 +130,22 @@ impl fmt::Debug for ProjectWorkspace {
|
|||||||
.field("toolchain", &toolchain)
|
.field("toolchain", &toolchain)
|
||||||
.field("data_layout", &data_layout)
|
.field("data_layout", &data_layout)
|
||||||
.finish(),
|
.finish(),
|
||||||
ProjectWorkspace::Json { project, sysroot, rustc_cfg, toolchain } => {
|
ProjectWorkspace::Json {
|
||||||
|
project,
|
||||||
|
sysroot,
|
||||||
|
rustc_cfg,
|
||||||
|
toolchain,
|
||||||
|
target_layout: data_layout,
|
||||||
|
} => {
|
||||||
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.num_packages());
|
debug_struct.field("n_sysroot_crates", &sysroot.num_packages());
|
||||||
}
|
}
|
||||||
debug_struct.field("toolchain", &toolchain);
|
debug_struct
|
||||||
debug_struct.field("n_rustc_cfg", &rustc_cfg.len());
|
.field("toolchain", &toolchain)
|
||||||
|
.field("n_rustc_cfg", &rustc_cfg.len())
|
||||||
|
.field("data_layout", &data_layout);
|
||||||
debug_struct.finish()
|
debug_struct.finish()
|
||||||
}
|
}
|
||||||
ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f
|
ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f
|
||||||
@ -146,6 +158,26 @@ impl fmt::Debug for ProjectWorkspace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_toolchain_version(
|
||||||
|
current_dir: &AbsPath,
|
||||||
|
cmd_path: Result<PathBuf, anyhow::Error>,
|
||||||
|
extra_env: &FxHashMap<String, String>,
|
||||||
|
prefix: &str,
|
||||||
|
) -> Result<Option<Version>, anyhow::Error> {
|
||||||
|
let cargo_version = utf8_stdout({
|
||||||
|
let mut cmd = Command::new(cmd_path?);
|
||||||
|
cmd.envs(extra_env);
|
||||||
|
cmd.arg("--version").current_dir(current_dir);
|
||||||
|
cmd
|
||||||
|
})
|
||||||
|
.with_context(|| format!("Failed to query rust toolchain version at {current_dir}, is your toolchain setup correctly?"))?;
|
||||||
|
anyhow::Ok(
|
||||||
|
cargo_version
|
||||||
|
.get(prefix.len()..)
|
||||||
|
.and_then(|it| Version::parse(it.split_whitespace().next()?).ok()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
impl ProjectWorkspace {
|
impl ProjectWorkspace {
|
||||||
pub fn load(
|
pub fn load(
|
||||||
manifest: ProjectManifest,
|
manifest: ProjectManifest,
|
||||||
@ -161,20 +193,6 @@ impl ProjectWorkspace {
|
|||||||
config: &CargoConfig,
|
config: &CargoConfig,
|
||||||
progress: &dyn Fn(String),
|
progress: &dyn Fn(String),
|
||||||
) -> anyhow::Result<ProjectWorkspace> {
|
) -> anyhow::Result<ProjectWorkspace> {
|
||||||
let version = |current_dir, cmd_path, prefix: &str| {
|
|
||||||
let cargo_version = utf8_stdout({
|
|
||||||
let mut cmd = Command::new(cmd_path);
|
|
||||||
cmd.envs(&config.extra_env);
|
|
||||||
cmd.arg("--version").current_dir(current_dir);
|
|
||||||
cmd
|
|
||||||
})
|
|
||||||
.with_context(|| format!("Failed to query rust toolchain version at {current_dir}, is your toolchain setup correctly?"))?;
|
|
||||||
anyhow::Ok(
|
|
||||||
cargo_version
|
|
||||||
.get(prefix.len()..)
|
|
||||||
.and_then(|it| Version::parse(it.split_whitespace().next()?).ok()),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let res = match manifest {
|
let res = match manifest {
|
||||||
ProjectManifest::ProjectJson(project_json) => {
|
ProjectManifest::ProjectJson(project_json) => {
|
||||||
let file = fs::read_to_string(project_json)
|
let file = fs::read_to_string(project_json)
|
||||||
@ -182,30 +200,14 @@ impl ProjectWorkspace {
|
|||||||
let data = serde_json::from_str(&file)
|
let data = serde_json::from_str(&file)
|
||||||
.with_context(|| format!("Failed to deserialize json file {project_json}"))?;
|
.with_context(|| format!("Failed to deserialize json file {project_json}"))?;
|
||||||
let project_location = project_json.parent().to_path_buf();
|
let project_location = project_json.parent().to_path_buf();
|
||||||
let toolchain = version(&*project_location, toolchain::rustc(), "rustc ")?;
|
let project_json: ProjectJson = ProjectJson::new(&project_location, data);
|
||||||
let project_json = ProjectJson::new(&project_location, data);
|
|
||||||
ProjectWorkspace::load_inline(
|
ProjectWorkspace::load_inline(
|
||||||
project_json,
|
project_json,
|
||||||
config.target.as_deref(),
|
config.target.as_deref(),
|
||||||
&config.extra_env,
|
&config.extra_env,
|
||||||
toolchain,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ProjectManifest::CargoToml(cargo_toml) => {
|
ProjectManifest::CargoToml(cargo_toml) => {
|
||||||
let toolchain = version(cargo_toml.parent(), toolchain::cargo(), "cargo ")?;
|
|
||||||
let meta = CargoWorkspace::fetch_metadata(
|
|
||||||
cargo_toml,
|
|
||||||
cargo_toml.parent(),
|
|
||||||
config,
|
|
||||||
progress,
|
|
||||||
)
|
|
||||||
.with_context(|| {
|
|
||||||
format!(
|
|
||||||
"Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}",
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
let cargo = CargoWorkspace::new(meta);
|
|
||||||
|
|
||||||
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(), config.sysroot_query_metadata).map_err(|e| {
|
Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata).map_err(|e| {
|
||||||
@ -218,7 +220,7 @@ impl ProjectWorkspace {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
(Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => {
|
(Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => {
|
||||||
Ok(Sysroot::load(sysroot.clone(), sysroot_src.clone(), config.sysroot_query_metadata))
|
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(
|
||||||
@ -231,18 +233,19 @@ impl ProjectWorkspace {
|
|||||||
}
|
}
|
||||||
(None, _) => Err(None),
|
(None, _) => Err(None),
|
||||||
};
|
};
|
||||||
|
let sysroot_ref = sysroot.as_ref().ok();
|
||||||
|
|
||||||
if let Ok(sysroot) = &sysroot {
|
if let Ok(sysroot) = &sysroot {
|
||||||
tracing::info!(workspace = %cargo_toml, src_root = %sysroot.src_root(), root = %sysroot.root(), "Using 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.as_ref().ok().and_then(Sysroot::discover_rustc_src).ok_or_else(
|
sysroot_ref.and_then(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())
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
None => Err(None),
|
None => Err(None),
|
||||||
};
|
};
|
||||||
@ -256,6 +259,7 @@ impl ProjectWorkspace {
|
|||||||
features: crate::CargoFeatures::default(),
|
features: crate::CargoFeatures::default(),
|
||||||
..config.clone()
|
..config.clone()
|
||||||
},
|
},
|
||||||
|
sysroot_ref,
|
||||||
progress,
|
progress,
|
||||||
) {
|
) {
|
||||||
Ok(meta) => {
|
Ok(meta) => {
|
||||||
@ -264,6 +268,7 @@ impl ProjectWorkspace {
|
|||||||
&workspace,
|
&workspace,
|
||||||
cargo_toml.parent(),
|
cargo_toml.parent(),
|
||||||
&config.extra_env,
|
&config.extra_env,
|
||||||
|
sysroot_ref
|
||||||
);
|
);
|
||||||
Ok(Box::new((workspace, buildscripts)))
|
Ok(Box::new((workspace, buildscripts)))
|
||||||
}
|
}
|
||||||
@ -279,21 +284,42 @@ impl ProjectWorkspace {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let toolchain = get_toolchain_version(
|
||||||
|
cargo_toml.parent(),
|
||||||
|
Sysroot::discover_tool(sysroot_ref, toolchain::Tool::Cargo),
|
||||||
|
&config.extra_env,
|
||||||
|
"cargo ",
|
||||||
|
)?;
|
||||||
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(cargo_toml),
|
RustcCfgConfig::Cargo(sysroot_ref, 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(
|
||||||
Some(cargo_toml),
|
RustcDataLayoutConfig::Cargo(sysroot_ref, cargo_toml),
|
||||||
config.target.as_deref(),
|
config.target.as_deref(),
|
||||||
&config.extra_env,
|
&config.extra_env,
|
||||||
);
|
);
|
||||||
if let Err(e) = &data_layout {
|
if let Err(e) = &data_layout {
|
||||||
tracing::error!(%e, "failed fetching data layout for {cargo_toml:?} workspace");
|
tracing::error!(%e, "failed fetching data layout for {cargo_toml:?} workspace");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let meta = CargoWorkspace::fetch_metadata(
|
||||||
|
cargo_toml,
|
||||||
|
cargo_toml.parent(),
|
||||||
|
config,
|
||||||
|
sysroot_ref,
|
||||||
|
progress,
|
||||||
|
)
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let cargo = CargoWorkspace::new(meta);
|
||||||
|
|
||||||
ProjectWorkspace::Cargo {
|
ProjectWorkspace::Cargo {
|
||||||
cargo,
|
cargo,
|
||||||
build_scripts: WorkspaceBuildScripts::default(),
|
build_scripts: WorkspaceBuildScripts::default(),
|
||||||
@ -314,15 +340,16 @@ impl ProjectWorkspace {
|
|||||||
project_json: ProjectJson,
|
project_json: ProjectJson,
|
||||||
target: Option<&str>,
|
target: Option<&str>,
|
||||||
extra_env: &FxHashMap<String, String>,
|
extra_env: &FxHashMap<String, String>,
|
||||||
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, false)),
|
(Some(sysroot), Some(sysroot_src)) => {
|
||||||
|
Ok(Sysroot::load(sysroot, Some(Ok(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, false))
|
Ok(Sysroot::load(sysroot, Some(Ok(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,23 +357,32 @@ impl ProjectWorkspace {
|
|||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
sysroot.pop();
|
sysroot.pop();
|
||||||
}
|
}
|
||||||
Ok(Sysroot::load(sysroot, sysroot_src, false))
|
Ok(Sysroot::load(sysroot, Some(Ok(sysroot_src)), false))
|
||||||
}
|
}
|
||||||
(None, None) => Err(None),
|
(None, None) => Err(None),
|
||||||
};
|
};
|
||||||
let config = match &sysroot {
|
let sysroot_ref = sysroot.as_ref().ok();
|
||||||
Ok(sysroot) => {
|
let cfg_config = RustcCfgConfig::Rustc(sysroot_ref);
|
||||||
tracing::debug!(src_root = %sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
|
let data_layout_config = RustcDataLayoutConfig::Rustc(sysroot_ref);
|
||||||
RustcCfgConfig::Explicit(sysroot)
|
let rustc = Sysroot::discover_tool(sysroot_ref, toolchain::Tool::Rustc).map(Into::into);
|
||||||
}
|
let toolchain = match get_toolchain_version(project_json.path(), rustc, extra_env, "rustc ")
|
||||||
Err(_) => {
|
{
|
||||||
tracing::debug!("discovering sysroot");
|
Ok(it) => it,
|
||||||
RustcCfgConfig::Discover
|
Err(e) => {
|
||||||
|
tracing::error!("{e}");
|
||||||
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let rustc_cfg = rustc_cfg::get(target, extra_env, config);
|
let rustc_cfg = rustc_cfg::get(target, extra_env, cfg_config);
|
||||||
ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg, toolchain }
|
let data_layout = target_data_layout::get(data_layout_config, target, extra_env);
|
||||||
|
ProjectWorkspace::Json {
|
||||||
|
project: project_json,
|
||||||
|
sysroot,
|
||||||
|
rustc_cfg,
|
||||||
|
toolchain,
|
||||||
|
target_layout: data_layout.map_err(|it| it.to_string()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_detached_files(
|
pub fn load_detached_files(
|
||||||
@ -373,18 +409,11 @@ impl ProjectWorkspace {
|
|||||||
}
|
}
|
||||||
None => Err(None),
|
None => Err(None),
|
||||||
};
|
};
|
||||||
let rustc_config = match &sysroot {
|
let rustc_cfg = rustc_cfg::get(
|
||||||
Ok(sysroot) => {
|
None,
|
||||||
tracing::info!(src_root = %sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
|
&FxHashMap::default(),
|
||||||
RustcCfgConfig::Explicit(sysroot)
|
RustcCfgConfig::Rustc(sysroot.as_ref().ok()),
|
||||||
}
|
);
|
||||||
Err(_) => {
|
|
||||||
tracing::info!("discovering sysroot");
|
|
||||||
RustcCfgConfig::Discover
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let rustc_cfg = rustc_cfg::get(None, &FxHashMap::default(), rustc_config);
|
|
||||||
Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
|
Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,11 +424,17 @@ impl ProjectWorkspace {
|
|||||||
progress: &dyn Fn(String),
|
progress: &dyn Fn(String),
|
||||||
) -> anyhow::Result<WorkspaceBuildScripts> {
|
) -> anyhow::Result<WorkspaceBuildScripts> {
|
||||||
match self {
|
match self {
|
||||||
ProjectWorkspace::Cargo { cargo, toolchain, .. } => {
|
ProjectWorkspace::Cargo { cargo, toolchain, sysroot, .. } => {
|
||||||
WorkspaceBuildScripts::run_for_workspace(config, cargo, progress, toolchain)
|
WorkspaceBuildScripts::run_for_workspace(
|
||||||
.with_context(|| {
|
config,
|
||||||
format!("Failed to run build scripts for {}", cargo.workspace_root())
|
cargo,
|
||||||
})
|
progress,
|
||||||
|
toolchain,
|
||||||
|
sysroot.as_ref().ok(),
|
||||||
|
)
|
||||||
|
.with_context(|| {
|
||||||
|
format!("Failed to run build scripts for {}", cargo.workspace_root())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => {
|
ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => {
|
||||||
Ok(WorkspaceBuildScripts::default())
|
Ok(WorkspaceBuildScripts::default())
|
||||||
@ -472,18 +507,7 @@ impl ProjectWorkspace {
|
|||||||
ProjectWorkspace::Cargo { sysroot: Ok(sysroot), .. }
|
ProjectWorkspace::Cargo { sysroot: Ok(sysroot), .. }
|
||||||
| ProjectWorkspace::Json { sysroot: Ok(sysroot), .. }
|
| ProjectWorkspace::Json { sysroot: Ok(sysroot), .. }
|
||||||
| ProjectWorkspace::DetachedFiles { sysroot: Ok(sysroot), .. } => {
|
| ProjectWorkspace::DetachedFiles { sysroot: Ok(sysroot), .. } => {
|
||||||
let standalone_server_name =
|
sysroot.discover_proc_macro_srv()
|
||||||
format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
|
|
||||||
["libexec", "lib"]
|
|
||||||
.into_iter()
|
|
||||||
.map(|segment| sysroot.root().join(segment).join(&standalone_server_name))
|
|
||||||
.find(|server_path| std::fs::metadata(server_path).is_ok())
|
|
||||||
.ok_or_else(|| {
|
|
||||||
anyhow::format_err!(
|
|
||||||
"cannot find proc-macro server in sysroot `{}`",
|
|
||||||
sysroot.root()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
ProjectWorkspace::DetachedFiles { .. } => {
|
ProjectWorkspace::DetachedFiles { .. } => {
|
||||||
Err(anyhow::format_err!("cannot find proc-macro server, no sysroot was found"))
|
Err(anyhow::format_err!("cannot find proc-macro server, no sysroot was found"))
|
||||||
@ -503,8 +527,7 @@ 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<_, _>, project_root: Option<&AbsPath>| {
|
let mk_sysroot = |sysroot: Result<_, _>| {
|
||||||
let project_root = project_root.map(ToOwned::to_owned);
|
|
||||||
sysroot.into_iter().flat_map(move |sysroot: &Sysroot| {
|
sysroot.into_iter().flat_map(move |sysroot: &Sysroot| {
|
||||||
let mut r = match sysroot.mode() {
|
let mut r = match sysroot.mode() {
|
||||||
SysrootMode::Workspace(ws) => ws
|
SysrootMode::Workspace(ws) => ws
|
||||||
@ -532,18 +555,21 @@ impl ProjectWorkspace {
|
|||||||
};
|
};
|
||||||
|
|
||||||
r.push(PackageRoot {
|
r.push(PackageRoot {
|
||||||
// mark the sysroot as mutable if it is located inside of the project
|
is_local: false,
|
||||||
is_local: project_root
|
include: sysroot.src_root().map(|it| it.to_path_buf()).into_iter().collect(),
|
||||||
.as_ref()
|
|
||||||
.map_or(false, |project_root| sysroot.src_root().starts_with(project_root)),
|
|
||||||
include: vec![sysroot.src_root().to_path_buf()],
|
|
||||||
exclude: Vec::new(),
|
exclude: Vec::new(),
|
||||||
});
|
});
|
||||||
r
|
r
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
match self {
|
match self {
|
||||||
ProjectWorkspace::Json { project, sysroot, rustc_cfg: _, toolchain: _ } => project
|
ProjectWorkspace::Json {
|
||||||
|
project,
|
||||||
|
sysroot,
|
||||||
|
rustc_cfg: _,
|
||||||
|
toolchain: _,
|
||||||
|
target_layout: _,
|
||||||
|
} => project
|
||||||
.crates()
|
.crates()
|
||||||
.map(|(_, krate)| PackageRoot {
|
.map(|(_, krate)| PackageRoot {
|
||||||
is_local: krate.is_workspace_member,
|
is_local: krate.is_workspace_member,
|
||||||
@ -552,7 +578,7 @@ impl ProjectWorkspace {
|
|||||||
})
|
})
|
||||||
.collect::<FxHashSet<_>>()
|
.collect::<FxHashSet<_>>()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(mk_sysroot(sysroot.as_ref(), Some(project.path())))
|
.chain(mk_sysroot(sysroot.as_ref()))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
ProjectWorkspace::Cargo {
|
ProjectWorkspace::Cargo {
|
||||||
cargo,
|
cargo,
|
||||||
@ -602,7 +628,7 @@ impl ProjectWorkspace {
|
|||||||
}
|
}
|
||||||
PackageRoot { is_local, include, exclude }
|
PackageRoot { is_local, include, exclude }
|
||||||
})
|
})
|
||||||
.chain(mk_sysroot(sysroot.as_ref(), Some(cargo.workspace_root())))
|
.chain(mk_sysroot(sysroot.as_ref()))
|
||||||
.chain(rustc.iter().map(|a| a.as_ref()).flat_map(|(rustc, _)| {
|
.chain(rustc.iter().map(|a| a.as_ref()).flat_map(|(rustc, _)| {
|
||||||
rustc.packages().map(move |krate| PackageRoot {
|
rustc.packages().map(move |krate| PackageRoot {
|
||||||
is_local: false,
|
is_local: false,
|
||||||
@ -619,7 +645,7 @@ impl ProjectWorkspace {
|
|||||||
include: vec![detached_file.clone()],
|
include: vec![detached_file.clone()],
|
||||||
exclude: Vec::new(),
|
exclude: Vec::new(),
|
||||||
})
|
})
|
||||||
.chain(mk_sysroot(sysroot.as_ref(), None))
|
.chain(mk_sysroot(sysroot.as_ref()))
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -651,14 +677,17 @@ impl ProjectWorkspace {
|
|||||||
let _p = tracing::span!(tracing::Level::INFO, "ProjectWorkspace::to_crate_graph").entered();
|
let _p = tracing::span!(tracing::Level::INFO, "ProjectWorkspace::to_crate_graph").entered();
|
||||||
|
|
||||||
let (mut crate_graph, proc_macros) = match self {
|
let (mut crate_graph, proc_macros) = match self {
|
||||||
ProjectWorkspace::Json { project, sysroot, rustc_cfg, toolchain } => {
|
ProjectWorkspace::Json { project, sysroot, rustc_cfg, toolchain, target_layout } => {
|
||||||
project_json_to_crate_graph(
|
project_json_to_crate_graph(
|
||||||
rustc_cfg.clone(),
|
rustc_cfg.clone(),
|
||||||
load,
|
load,
|
||||||
project,
|
project,
|
||||||
sysroot.as_ref().ok(),
|
sysroot.as_ref().ok(),
|
||||||
extra_env,
|
extra_env,
|
||||||
Err("rust-project.json projects have no target layout set".into()),
|
match target_layout.as_ref() {
|
||||||
|
Ok(it) => Ok(Arc::from(it.as_str())),
|
||||||
|
Err(it) => Err(Arc::from(it.as_str())),
|
||||||
|
},
|
||||||
toolchain.clone(),
|
toolchain.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -735,12 +764,13 @@ impl ProjectWorkspace {
|
|||||||
&& sysroot == o_sysroot
|
&& sysroot == o_sysroot
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
Self::Json { project, sysroot, rustc_cfg, toolchain },
|
Self::Json { project, sysroot, rustc_cfg, toolchain, target_layout: _ },
|
||||||
Self::Json {
|
Self::Json {
|
||||||
project: o_project,
|
project: o_project,
|
||||||
sysroot: o_sysroot,
|
sysroot: o_sysroot,
|
||||||
rustc_cfg: o_rustc_cfg,
|
rustc_cfg: o_rustc_cfg,
|
||||||
toolchain: o_toolchain,
|
toolchain: o_toolchain,
|
||||||
|
target_layout: _,
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
project == o_project
|
project == o_project
|
||||||
@ -813,12 +843,7 @@ fn project_json_to_crate_graph(
|
|||||||
|
|
||||||
let target_cfgs = match target.as_deref() {
|
let target_cfgs = match target.as_deref() {
|
||||||
Some(target) => cfg_cache.entry(target).or_insert_with(|| {
|
Some(target) => cfg_cache.entry(target).or_insert_with(|| {
|
||||||
let rustc_cfg = match sysroot {
|
rustc_cfg::get(Some(target), extra_env, RustcCfgConfig::Rustc(sysroot))
|
||||||
Some(sysroot) => RustcCfgConfig::Explicit(sysroot),
|
|
||||||
None => RustcCfgConfig::Discover,
|
|
||||||
};
|
|
||||||
|
|
||||||
rustc_cfg::get(Some(target), extra_env, rustc_cfg)
|
|
||||||
}),
|
}),
|
||||||
None => &rustc_cfg,
|
None => &rustc_cfg,
|
||||||
};
|
};
|
||||||
@ -959,21 +984,6 @@ fn cargo_to_crate_graph(
|
|||||||
}
|
}
|
||||||
let &TargetData { ref name, kind, is_proc_macro, ref root, .. } = &cargo[tgt];
|
let &TargetData { ref name, kind, is_proc_macro, ref root, .. } = &cargo[tgt];
|
||||||
|
|
||||||
if kind == TargetKind::Lib
|
|
||||||
&& sysroot.map_or(false, |sysroot| root.starts_with(sysroot.src_root()))
|
|
||||||
{
|
|
||||||
if let Some(&(_, crate_id, _)) =
|
|
||||||
public_deps.deps.iter().find(|(dep_name, ..)| dep_name.as_smol_str() == name)
|
|
||||||
{
|
|
||||||
pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, kind));
|
|
||||||
|
|
||||||
lib_tgt = Some((crate_id, name.clone()));
|
|
||||||
pkg_to_lib_crate.insert(pkg, crate_id);
|
|
||||||
// sysroot is inside the workspace, prevent the sysroot crates from being duplicated here
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(file_id) = load(root) else { continue };
|
let Some(file_id) = load(root) else { continue };
|
||||||
|
|
||||||
let crate_id = add_target_crate_root(
|
let crate_id = add_target_crate_root(
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
),
|
),
|
||||||
is_proc_macro: false,
|
is_proc_macro: false,
|
||||||
target_layout: Err(
|
target_layout: Err(
|
||||||
"rust-project.json projects have no target layout set",
|
"test has no data layout",
|
||||||
),
|
),
|
||||||
toolchain: None,
|
toolchain: None,
|
||||||
},
|
},
|
||||||
@ -70,7 +70,7 @@
|
|||||||
),
|
),
|
||||||
is_proc_macro: false,
|
is_proc_macro: false,
|
||||||
target_layout: Err(
|
target_layout: Err(
|
||||||
"rust-project.json projects have no target layout set",
|
"test has no data layout",
|
||||||
),
|
),
|
||||||
toolchain: None,
|
toolchain: None,
|
||||||
},
|
},
|
||||||
@ -103,7 +103,7 @@
|
|||||||
),
|
),
|
||||||
is_proc_macro: false,
|
is_proc_macro: false,
|
||||||
target_layout: Err(
|
target_layout: Err(
|
||||||
"rust-project.json projects have no target layout set",
|
"test has no data layout",
|
||||||
),
|
),
|
||||||
toolchain: None,
|
toolchain: None,
|
||||||
},
|
},
|
||||||
@ -136,7 +136,7 @@
|
|||||||
),
|
),
|
||||||
is_proc_macro: false,
|
is_proc_macro: false,
|
||||||
target_layout: Err(
|
target_layout: Err(
|
||||||
"rust-project.json projects have no target layout set",
|
"test has no data layout",
|
||||||
),
|
),
|
||||||
toolchain: None,
|
toolchain: None,
|
||||||
},
|
},
|
||||||
@ -186,7 +186,7 @@
|
|||||||
),
|
),
|
||||||
is_proc_macro: false,
|
is_proc_macro: false,
|
||||||
target_layout: Err(
|
target_layout: Err(
|
||||||
"rust-project.json projects have no target layout set",
|
"test has no data layout",
|
||||||
),
|
),
|
||||||
toolchain: None,
|
toolchain: None,
|
||||||
},
|
},
|
||||||
@ -219,7 +219,7 @@
|
|||||||
),
|
),
|
||||||
is_proc_macro: false,
|
is_proc_macro: false,
|
||||||
target_layout: Err(
|
target_layout: Err(
|
||||||
"rust-project.json projects have no target layout set",
|
"test has no data layout",
|
||||||
),
|
),
|
||||||
toolchain: None,
|
toolchain: None,
|
||||||
},
|
},
|
||||||
@ -317,7 +317,7 @@
|
|||||||
),
|
),
|
||||||
is_proc_macro: false,
|
is_proc_macro: false,
|
||||||
target_layout: Err(
|
target_layout: Err(
|
||||||
"rust-project.json projects have no target layout set",
|
"test has no data layout",
|
||||||
),
|
),
|
||||||
toolchain: None,
|
toolchain: None,
|
||||||
},
|
},
|
||||||
@ -350,7 +350,7 @@
|
|||||||
),
|
),
|
||||||
is_proc_macro: false,
|
is_proc_macro: false,
|
||||||
target_layout: Err(
|
target_layout: Err(
|
||||||
"rust-project.json projects have no target layout set",
|
"test has no data layout",
|
||||||
),
|
),
|
||||||
toolchain: None,
|
toolchain: None,
|
||||||
},
|
},
|
||||||
@ -383,7 +383,7 @@
|
|||||||
),
|
),
|
||||||
is_proc_macro: false,
|
is_proc_macro: false,
|
||||||
target_layout: Err(
|
target_layout: Err(
|
||||||
"rust-project.json projects have no target layout set",
|
"test has no data layout",
|
||||||
),
|
),
|
||||||
toolchain: None,
|
toolchain: None,
|
||||||
},
|
},
|
||||||
@ -416,7 +416,7 @@
|
|||||||
),
|
),
|
||||||
is_proc_macro: false,
|
is_proc_macro: false,
|
||||||
target_layout: Err(
|
target_layout: Err(
|
||||||
"rust-project.json projects have no target layout set",
|
"test has no data layout",
|
||||||
),
|
),
|
||||||
toolchain: None,
|
toolchain: None,
|
||||||
},
|
},
|
||||||
@ -493,7 +493,7 @@
|
|||||||
},
|
},
|
||||||
is_proc_macro: false,
|
is_proc_macro: false,
|
||||||
target_layout: Err(
|
target_layout: Err(
|
||||||
"rust-project.json projects have no target layout set",
|
"test has no data layout",
|
||||||
),
|
),
|
||||||
toolchain: None,
|
toolchain: None,
|
||||||
},
|
},
|
||||||
|
@ -1937,6 +1937,7 @@ fn run_rustfmt(
|
|||||||
|
|
||||||
let mut command = match snap.config.rustfmt() {
|
let mut command = match snap.config.rustfmt() {
|
||||||
RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
|
RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
|
||||||
|
// FIXME: This should use the sysroot's rustfmt if its loaded
|
||||||
let mut cmd = process::Command::new(toolchain::rustfmt());
|
let mut cmd = process::Command::new(toolchain::rustfmt());
|
||||||
cmd.envs(snap.config.extra_env());
|
cmd.envs(snap.config.extra_env());
|
||||||
cmd.args(extra_args);
|
cmd.args(extra_args);
|
||||||
|
@ -24,7 +24,7 @@ use ide_db::{
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use load_cargo::{load_proc_macro, ProjectFolders};
|
use load_cargo::{load_proc_macro, ProjectFolders};
|
||||||
use proc_macro_api::ProcMacroServer;
|
use proc_macro_api::ProcMacroServer;
|
||||||
use project_model::{ProjectWorkspace, WorkspaceBuildScripts};
|
use project_model::{ProjectWorkspace, Sysroot, WorkspaceBuildScripts};
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use stdx::{format_to, thread::ThreadIntent};
|
use stdx::{format_to, thread::ThreadIntent};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
@ -234,7 +234,6 @@ impl GlobalState {
|
|||||||
it.clone(),
|
it.clone(),
|
||||||
cargo_config.target.as_deref(),
|
cargo_config.target.as_deref(),
|
||||||
&cargo_config.extra_env,
|
&cargo_config.extra_env,
|
||||||
None,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -605,6 +604,7 @@ impl GlobalState {
|
|||||||
0,
|
0,
|
||||||
Box::new(move |msg| sender.send(msg).unwrap()),
|
Box::new(move |msg| sender.send(msg).unwrap()),
|
||||||
config,
|
config,
|
||||||
|
toolchain::cargo(),
|
||||||
self.config.root_path().clone(),
|
self.config.root_path().clone(),
|
||||||
)],
|
)],
|
||||||
flycheck::InvocationStrategy::PerWorkspace => {
|
flycheck::InvocationStrategy::PerWorkspace => {
|
||||||
@ -612,23 +612,35 @@ impl GlobalState {
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(id, w)| match w {
|
.filter_map(|(id, w)| match w {
|
||||||
ProjectWorkspace::Cargo { cargo, .. } => Some((id, cargo.workspace_root())),
|
ProjectWorkspace::Cargo { cargo, sysroot, .. } => Some((
|
||||||
ProjectWorkspace::Json { project, .. } => {
|
id,
|
||||||
|
cargo.workspace_root(),
|
||||||
|
Sysroot::discover_tool(sysroot.as_ref().ok(), toolchain::Tool::Cargo),
|
||||||
|
)),
|
||||||
|
ProjectWorkspace::Json { project, sysroot, .. } => {
|
||||||
// Enable flychecks for json projects if a custom flycheck command was supplied
|
// Enable flychecks for json projects if a custom flycheck command was supplied
|
||||||
// in the workspace configuration.
|
// in the workspace configuration.
|
||||||
match config {
|
match config {
|
||||||
FlycheckConfig::CustomCommand { .. } => Some((id, project.path())),
|
FlycheckConfig::CustomCommand { .. } => Some((
|
||||||
|
id,
|
||||||
|
project.path(),
|
||||||
|
Sysroot::discover_tool(
|
||||||
|
sysroot.as_ref().ok(),
|
||||||
|
toolchain::Tool::Cargo,
|
||||||
|
),
|
||||||
|
)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ProjectWorkspace::DetachedFiles { .. } => None,
|
ProjectWorkspace::DetachedFiles { .. } => None,
|
||||||
})
|
})
|
||||||
.map(|(id, root)| {
|
.map(|(id, root, cargo)| {
|
||||||
let sender = sender.clone();
|
let sender = sender.clone();
|
||||||
FlycheckHandle::spawn(
|
FlycheckHandle::spawn(
|
||||||
id,
|
id,
|
||||||
Box::new(move |msg| sender.send(msg).unwrap()),
|
Box::new(move |msg| sender.send(msg).unwrap()),
|
||||||
config.clone(),
|
config.clone(),
|
||||||
|
cargo.unwrap_or_else(|_| toolchain::cargo()),
|
||||||
root.to_path_buf(),
|
root.to_path_buf(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -911,20 +911,18 @@ fn root_contains_symlink_out_dirs_check() {
|
|||||||
#[cfg(any(feature = "sysroot-abi", rust_analyzer))]
|
#[cfg(any(feature = "sysroot-abi", rust_analyzer))]
|
||||||
fn resolve_proc_macro() {
|
fn resolve_proc_macro() {
|
||||||
use expect_test::expect;
|
use expect_test::expect;
|
||||||
|
use vfs::AbsPathBuf;
|
||||||
if skip_slow_tests() {
|
if skip_slow_tests() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip using the sysroot config as to prevent us from loading the sysroot sources
|
let sysroot = project_model::Sysroot::discover_no_source(
|
||||||
let mut rustc = std::process::Command::new(toolchain::rustc());
|
&AbsPathBuf::assert(std::env::current_dir().unwrap()),
|
||||||
rustc.args(["--print", "sysroot"]);
|
&Default::default(),
|
||||||
let output = rustc.output().unwrap();
|
)
|
||||||
let sysroot =
|
.unwrap();
|
||||||
vfs::AbsPathBuf::try_from(std::str::from_utf8(&output.stdout).unwrap().trim()).unwrap();
|
|
||||||
|
|
||||||
let standalone_server_name =
|
let proc_macro_server_path = sysroot.discover_proc_macro_srv().unwrap();
|
||||||
format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
|
|
||||||
let proc_macro_server_path = sysroot.join("libexec").join(&standalone_server_name);
|
|
||||||
|
|
||||||
let server = Project::with_fixture(
|
let server = Project::with_fixture(
|
||||||
r###"
|
r###"
|
||||||
|
@ -2,7 +2,41 @@
|
|||||||
|
|
||||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||||
|
|
||||||
use std::{env, iter, path::PathBuf};
|
use std::{
|
||||||
|
env, iter,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum Tool {
|
||||||
|
Cargo,
|
||||||
|
Rustc,
|
||||||
|
Rustup,
|
||||||
|
Rustfmt,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tool {
|
||||||
|
pub fn path(self) -> PathBuf {
|
||||||
|
get_path_for_executable(self.name())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_in(self, path: &Path) -> Option<PathBuf> {
|
||||||
|
probe_for_binary(path.join(self.name()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_in_or_discover(self, path: &Path) -> PathBuf {
|
||||||
|
probe_for_binary(path.join(self.name())).unwrap_or_else(|| self.path())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Tool::Cargo => "cargo",
|
||||||
|
Tool::Rustc => "rustc",
|
||||||
|
Tool::Rustup => "rustup",
|
||||||
|
Tool::Rustfmt => "rustfmt",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cargo() -> PathBuf {
|
pub fn cargo() -> PathBuf {
|
||||||
get_path_for_executable("cargo")
|
get_path_for_executable("cargo")
|
||||||
@ -47,7 +81,7 @@ fn get_path_for_executable(executable_name: &'static str) -> PathBuf {
|
|||||||
if let Some(mut path) = get_cargo_home() {
|
if let Some(mut path) = get_cargo_home() {
|
||||||
path.push("bin");
|
path.push("bin");
|
||||||
path.push(executable_name);
|
path.push(executable_name);
|
||||||
if let Some(path) = probe(path) {
|
if let Some(path) = probe_for_binary(path) {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,7 +91,7 @@ fn get_path_for_executable(executable_name: &'static str) -> PathBuf {
|
|||||||
|
|
||||||
fn lookup_in_path(exec: &str) -> bool {
|
fn lookup_in_path(exec: &str) -> bool {
|
||||||
let paths = env::var_os("PATH").unwrap_or_default();
|
let paths = env::var_os("PATH").unwrap_or_default();
|
||||||
env::split_paths(&paths).map(|path| path.join(exec)).find_map(probe).is_some()
|
env::split_paths(&paths).map(|path| path.join(exec)).find_map(probe_for_binary).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_cargo_home() -> Option<PathBuf> {
|
fn get_cargo_home() -> Option<PathBuf> {
|
||||||
@ -73,7 +107,7 @@ fn get_cargo_home() -> Option<PathBuf> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn probe(path: PathBuf) -> Option<PathBuf> {
|
pub fn probe_for_binary(path: PathBuf) -> Option<PathBuf> {
|
||||||
let with_extension = match env::consts::EXE_EXTENSION {
|
let with_extension = match env::consts::EXE_EXTENSION {
|
||||||
"" => None,
|
"" => None,
|
||||||
it => Some(path.with_extension(it)),
|
it => Some(path.with_extension(it)),
|
||||||
|
Loading…
Reference in New Issue
Block a user