diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 71882b6f0dc..ee39a2790bc 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -23,6 +23,7 @@ Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion, }; +use toolchain::Tool; #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub enum InvocationStrategy { @@ -89,10 +90,10 @@ pub fn spawn( id: usize, sender: Box, config: FlycheckConfig, - cargo: PathBuf, + sysroot_root: Option, workspace_root: AbsPathBuf, ) -> FlycheckHandle { - let actor = FlycheckActor::new(id, sender, config, cargo, workspace_root); + let actor = FlycheckActor::new(id, sender, config, sysroot_root, workspace_root); let (sender, receiver) = unbounded::(); let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) .name("Flycheck".to_owned()) @@ -174,7 +175,7 @@ struct FlycheckActor { /// Either the workspace root of the workspace we are flychecking, /// or the project root of the project. root: AbsPathBuf, - cargo: PathBuf, + sysroot_root: Option, /// CargoHandle exists to wrap around the communication needed to be able to /// run `cargo check` without blocking. Currently the Rust standard library /// doesn't provide a way to read sub-process output without blocking, so we @@ -195,11 +196,18 @@ fn new( id: usize, sender: Box, config: FlycheckConfig, - cargo: PathBuf, + sysroot_root: Option, workspace_root: AbsPathBuf, ) -> FlycheckActor { tracing::info!(%id, ?workspace_root, "Spawning flycheck"); - FlycheckActor { id, sender, config, cargo, root: workspace_root, command_handle: None } + FlycheckActor { + id, + sender, + config, + sysroot_root, + root: workspace_root, + command_handle: None, + } } fn report_progress(&self, progress: Progress) { @@ -334,7 +342,10 @@ fn check_command( ansi_color_output, target_dir, } => { - let mut cmd = Command::new(&self.cargo); + let mut cmd = Command::new(Tool::Cargo.path()); + if let Some(sysroot_root) = &self.sysroot_root { + cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(sysroot_root)); + } cmd.arg(command); cmd.current_dir(&self.root); diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs index 51b9c8f5769..98060e876ac 100644 --- a/crates/project-model/src/build_scripts.rs +++ b/crates/project-model/src/build_scripts.rs @@ -71,10 +71,8 @@ fn build_command( cmd } _ => { - let mut cmd = Command::new( - Sysroot::discover_tool(sysroot, Tool::Cargo) - .map_err(|e| io::Error::new(io::ErrorKind::NotFound, e))?, - ); + let mut cmd = Command::new(Tool::Cargo.path()); + Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot); cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]); cmd.args(&config.extra_args); @@ -431,7 +429,8 @@ pub(crate) fn rustc_crates( } let res = (|| { let target_libdir = (|| { - let mut cargo_config = Command::new(Sysroot::discover_tool(sysroot, Tool::Cargo)?); + let mut cargo_config = Command::new(Tool::Cargo.path()); + Sysroot::set_rustup_toolchain_env(&mut cargo_config, sysroot); cargo_config.envs(extra_env); cargo_config .current_dir(current_dir) @@ -440,7 +439,8 @@ pub(crate) fn rustc_crates( if let Ok(it) = utf8_stdout(cargo_config) { return Ok(it); } - let mut cmd = Command::new(Sysroot::discover_tool(sysroot, Tool::Rustc)?); + let mut cmd = Command::new(Tool::Rustc.path()); + Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot); cmd.envs(extra_env); cmd.args(["--print", "target-libdir"]); utf8_stdout(cmd) diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index dae03afde22..8136dc221f2 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -243,7 +243,7 @@ pub fn fetch_metadata( let targets = find_list_of_build_targets(config, cargo_toml, sysroot); let mut meta = MetadataCommand::new(); - meta.cargo_path(Sysroot::discover_tool(sysroot, Tool::Cargo)?); + meta.cargo_path(Tool::Cargo.path()); meta.manifest_path(cargo_toml.to_path_buf()); match &config.features { CargoFeatures::All => { @@ -291,6 +291,7 @@ pub fn fetch_metadata( (|| -> Result { let mut command = meta.cargo_command(); + Sysroot::set_rustup_toolchain_env(&mut command, sysroot); command.envs(&config.extra_env); let output = command.output()?; if !output.status.success() { @@ -500,7 +501,8 @@ fn rustc_discover_host_triple( extra_env: &FxHashMap, sysroot: Option<&Sysroot>, ) -> Option { - let mut rustc = Command::new(Sysroot::discover_tool(sysroot, Tool::Rustc).ok()?); + let mut rustc = Command::new(Tool::Rustc.path()); + Sysroot::set_rustup_toolchain_env(&mut rustc, sysroot); rustc.envs(extra_env); rustc.current_dir(cargo_toml.parent()).arg("-vV"); tracing::debug!("Discovering host platform by {:?}", rustc); @@ -528,8 +530,8 @@ fn cargo_config_build_target( extra_env: &FxHashMap, sysroot: Option<&Sysroot>, ) -> Vec { - let Ok(program) = Sysroot::discover_tool(sysroot, Tool::Cargo) else { return vec![] }; - let mut cargo_config = Command::new(program); + let mut cargo_config = Command::new(Tool::Cargo.path()); + Sysroot::set_rustup_toolchain_env(&mut cargo_config, sysroot); cargo_config.envs(extra_env); cargo_config .current_dir(cargo_toml.parent()) diff --git a/crates/project-model/src/rustc_cfg.rs b/crates/project-model/src/rustc_cfg.rs index 1d07e4a8a65..1ad6e7255bf 100644 --- a/crates/project-model/src/rustc_cfg.rs +++ b/crates/project-model/src/rustc_cfg.rs @@ -68,11 +68,11 @@ fn get_rust_cfgs( config: RustcCfgConfig<'_>, ) -> anyhow::Result { let sysroot = match config { - RustcCfgConfig::Cargo(sysroot, cargo_oml) => { - let cargo = Sysroot::discover_tool(sysroot, toolchain::Tool::Cargo)?; - let mut cmd = Command::new(cargo); + RustcCfgConfig::Cargo(sysroot, cargo_toml) => { + let mut cmd = Command::new(toolchain::Tool::Cargo.path()); + Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot); cmd.envs(extra_env); - cmd.current_dir(cargo_oml.parent()) + cmd.current_dir(cargo_toml.parent()) .args(["rustc", "-Z", "unstable-options", "--print", "cfg"]) .env("RUSTC_BOOTSTRAP", "1"); if let Some(target) = target { @@ -90,9 +90,8 @@ fn get_rust_cfgs( RustcCfgConfig::Rustc(sysroot) => sysroot, }; - let rustc = Sysroot::discover_tool(sysroot, toolchain::Tool::Rustc)?; - tracing::debug!(?rustc, "using explicit rustc from sysroot"); - let mut cmd = Command::new(rustc); + let mut cmd = Command::new(toolchain::Tool::Rustc.path()); + Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot); cmd.envs(extra_env); cmd.args(["--print", "cfg", "-O"]); if let Some(target) = target { diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index 24c2edd2c4f..07cfaba2d2c 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -6,13 +6,13 @@ use std::{env, fs, iter, ops, path::PathBuf, process::Command, sync::Arc}; -use anyhow::{format_err, Context, Result}; +use anyhow::{format_err, Result}; use base_db::CrateName; use itertools::Itertools; use la_arena::{Arena, Idx}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; -use toolchain::{probe_for_binary, Tool}; +use toolchain::probe_for_binary; use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath}; @@ -193,23 +193,9 @@ pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf, metadata: bool) -> Result anyhow::Result { - 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::::as_ref(&self.root) - ) - }) - }) - } - - pub fn discover_tool(sysroot: Option<&Self>, tool: Tool) -> anyhow::Result { - match sysroot { - Some(sysroot) => sysroot.discover_binary(tool.name()).map(Into::into), - None => Ok(tool.path()), + pub fn set_rustup_toolchain_env(cmd: &mut Command, sysroot: Option<&Self>) { + if let Some(sysroot) = sysroot { + cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(&sysroot.root)); } } diff --git a/crates/project-model/src/target_data_layout.rs b/crates/project-model/src/target_data_layout.rs index 4c5200cee81..af635dda578 100644 --- a/crates/project-model/src/target_data_layout.rs +++ b/crates/project-model/src/target_data_layout.rs @@ -28,8 +28,8 @@ pub fn get( }; let sysroot = match config { RustcDataLayoutConfig::Cargo(sysroot, cargo_toml) => { - let cargo = Sysroot::discover_tool(sysroot, toolchain::Tool::Cargo)?; - let mut cmd = Command::new(cargo); + let mut cmd = Command::new(toolchain::Tool::Cargo.path()); + Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot); cmd.envs(extra_env); cmd.current_dir(cargo_toml.parent()) .args(["rustc", "--", "-Z", "unstable-options", "--print", "target-spec-json"]) @@ -48,8 +48,8 @@ pub fn get( RustcDataLayoutConfig::Rustc(sysroot) => sysroot, }; - let rustc = Sysroot::discover_tool(sysroot, toolchain::Tool::Rustc)?; - let mut cmd = Command::new(rustc); + let mut cmd = Command::new(toolchain::Tool::Rustc.path()); + Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot); cmd.envs(extra_env) .args(["-Z", "unstable-options", "--print", "target-spec-json"]) .env("RUSTC_BOOTSTRAP", "1"); diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index cacd506d1b2..6a53fd00aeb 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -2,9 +2,7 @@ //! metadata` or `rust-project.json`) into representation stored in the salsa //! database -- `CrateGraph`. -use std::{ - collections::VecDeque, fmt, fs, iter, path::PathBuf, process::Command, str::FromStr, sync, -}; +use std::{collections::VecDeque, fmt, fs, iter, process::Command, str::FromStr, sync}; use anyhow::{format_err, Context}; use base_db::{ @@ -16,6 +14,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; use stdx::always; +use toolchain::Tool; use triomphe::Arc; use crate::{ @@ -163,12 +162,14 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn get_toolchain_version( current_dir: &AbsPath, - cmd_path: Result, + sysroot: Option<&Sysroot>, + tool: Tool, extra_env: &FxHashMap, prefix: &str, ) -> Result, anyhow::Error> { let cargo_version = utf8_stdout({ - let mut cmd = Command::new(cmd_path?); + let mut cmd = Command::new(tool.path()); + Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot); cmd.envs(extra_env); cmd.arg("--version").current_dir(current_dir); cmd @@ -289,7 +290,8 @@ fn load_inner( let toolchain = get_toolchain_version( cargo_toml.parent(), - Sysroot::discover_tool(sysroot_ref, toolchain::Tool::Cargo), + sysroot_ref, + toolchain::Tool::Cargo, &config.extra_env, "cargo ", )?; @@ -370,9 +372,13 @@ pub fn load_inline( let sysroot_ref = sysroot.as_ref().ok(); let cfg_config = RustcCfgConfig::Rustc(sysroot_ref); let data_layout_config = RustcDataLayoutConfig::Rustc(sysroot_ref); - 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 ") - { + let toolchain = match get_toolchain_version( + project_json.path(), + sysroot_ref, + toolchain::Tool::Rustc, + extra_env, + "rustc ", + ) { Ok(it) => it, Err(e) => { tracing::error!("{e}"); @@ -1615,10 +1621,8 @@ fn cargo_config_env( extra_env: &FxHashMap, sysroot: Option<&Sysroot>, ) -> FxHashMap { - let Ok(program) = Sysroot::discover_tool(sysroot, toolchain::Tool::Cargo) else { - return Default::default(); - }; - let mut cargo_config = Command::new(program); + let mut cargo_config = Command::new(Tool::Cargo.path()); + Sysroot::set_rustup_toolchain_env(&mut cargo_config, sysroot); cargo_config.envs(extra_env); cargo_config .current_dir(cargo_toml.parent()) diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index b175dbc895c..1eb840afe5e 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -1937,7 +1937,7 @@ fn run_rustfmt( let mut command = match snap.config.rustfmt() { RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => { - // FIXME: This should use the sysroot's rustfmt if its loaded + // FIXME: Set RUSTUP_TOOLCHAIN let mut cmd = process::Command::new(toolchain::rustfmt()); cmd.envs(snap.config.extra_env()); cmd.args(extra_args); diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 93b6a53908f..f223bb40c4a 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -24,7 +24,7 @@ use itertools::Itertools; use load_cargo::{load_proc_macro, ProjectFolders}; use proc_macro_api::ProcMacroServer; -use project_model::{ProjectWorkspace, Sysroot, WorkspaceBuildScripts}; +use project_model::{ProjectWorkspace, WorkspaceBuildScripts}; use rustc_hash::FxHashSet; use stdx::{format_to, thread::ThreadIntent}; use triomphe::Arc; @@ -468,16 +468,20 @@ pub(crate) fn switch_workspaces(&mut self, cause: Cause) { None => ws.find_sysroot_proc_macro_srv()?, }; - let env = match ws { - ProjectWorkspace::Cargo { cargo_config_extra_env, .. } => { - cargo_config_extra_env - .iter() - .chain(self.config.extra_env()) - .map(|(a, b)| (a.clone(), b.clone())) - .collect() - } - _ => Default::default(), - }; + let env = + match ws { + ProjectWorkspace::Cargo { cargo_config_extra_env, sysroot, .. } => { + cargo_config_extra_env + .iter() + .chain(self.config.extra_env()) + .map(|(a, b)| (a.clone(), b.clone())) + .chain(sysroot.as_ref().map(|it| { + ("RUSTUP_TOOLCHAIN".to_owned(), it.root().to_string()) + })) + .collect() + } + _ => Default::default(), + }; tracing::info!("Using proc-macro server at {path}"); ProcMacroServer::spawn(path.clone(), &env).map_err(|err| { @@ -620,7 +624,7 @@ fn reload_flycheck(&mut self) { 0, Box::new(move |msg| sender.send(msg).unwrap()), config, - toolchain::cargo(), + None, self.config.root_path().clone(), )], flycheck::InvocationStrategy::PerWorkspace => { @@ -631,7 +635,7 @@ fn reload_flycheck(&mut self) { ProjectWorkspace::Cargo { cargo, sysroot, .. } => Some(( id, cargo.workspace_root(), - Sysroot::discover_tool(sysroot.as_ref().ok(), toolchain::Tool::Cargo), + sysroot.as_ref().ok().map(|sysroot| sysroot.root().to_owned()), )), ProjectWorkspace::Json { project, sysroot, .. } => { // Enable flychecks for json projects if a custom flycheck command was supplied @@ -640,23 +644,20 @@ fn reload_flycheck(&mut self) { FlycheckConfig::CustomCommand { .. } => Some(( id, project.path(), - Sysroot::discover_tool( - sysroot.as_ref().ok(), - toolchain::Tool::Cargo, - ), + sysroot.as_ref().ok().map(|sysroot| sysroot.root().to_owned()), )), _ => None, } } ProjectWorkspace::DetachedFiles { .. } => None, }) - .map(|(id, root, cargo)| { + .map(|(id, root, sysroot_root)| { let sender = sender.clone(); FlycheckHandle::spawn( id, Box::new(move |msg| sender.send(msg).unwrap()), config.clone(), - cargo.unwrap_or_else(|_| toolchain::cargo()), + sysroot_root, root.to_path_buf(), ) })