about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/load-cargo/src/lib.rs4
-rw-r--r--crates/proc-macro-api/src/lib.rs8
-rw-r--r--crates/proc-macro-api/src/process.rs25
-rw-r--r--crates/project-model/src/tests.rs3
-rw-r--r--crates/project-model/src/workspace.rs43
-rw-r--r--crates/rust-analyzer/src/reload.rs13
6 files changed, 83 insertions, 13 deletions
diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs
index a52cc19650f..6958a4be17b 100644
--- a/crates/load-cargo/src/lib.rs
+++ b/crates/load-cargo/src/lib.rs
@@ -67,9 +67,9 @@ pub fn load_workspace(
     let proc_macro_server = match &load_config.with_proc_macro_server {
         ProcMacroServerChoice::Sysroot => ws
             .find_sysroot_proc_macro_srv()
-            .and_then(|it| ProcMacroServer::spawn(it).map_err(Into::into)),
+            .and_then(|it| ProcMacroServer::spawn(it, extra_env).map_err(Into::into)),
         ProcMacroServerChoice::Explicit(path) => {
-            ProcMacroServer::spawn(path.clone()).map_err(Into::into)
+            ProcMacroServer::spawn(path.clone(), extra_env).map_err(Into::into)
         }
         ProcMacroServerChoice::None => Err(anyhow::format_err!("proc macro server disabled")),
     };
diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs
index 1dadfc40ac4..6b16711a8d8 100644
--- a/crates/proc-macro-api/src/lib.rs
+++ b/crates/proc-macro-api/src/lib.rs
@@ -13,6 +13,7 @@ mod version;
 
 use indexmap::IndexSet;
 use paths::AbsPathBuf;
+use rustc_hash::FxHashMap;
 use span::Span;
 use std::{
     fmt, io,
@@ -107,8 +108,11 @@ pub struct MacroPanic {
 
 impl ProcMacroServer {
     /// Spawns an external process as the proc macro server and returns a client connected to it.
-    pub fn spawn(process_path: AbsPathBuf) -> io::Result<ProcMacroServer> {
-        let process = ProcMacroProcessSrv::run(process_path)?;
+    pub fn spawn(
+        process_path: AbsPathBuf,
+        env: &FxHashMap<String, String>,
+    ) -> io::Result<ProcMacroServer> {
+        let process = ProcMacroProcessSrv::run(process_path, env)?;
         Ok(ProcMacroServer { process: Arc::new(Mutex::new(process)) })
     }
 
diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs
index 96f97bf5e20..12eafcea442 100644
--- a/crates/proc-macro-api/src/process.rs
+++ b/crates/proc-macro-api/src/process.rs
@@ -7,6 +7,7 @@ use std::{
 };
 
 use paths::{AbsPath, AbsPathBuf};
+use rustc_hash::FxHashMap;
 use stdx::JodChild;
 
 use crate::{
@@ -26,9 +27,12 @@ pub(crate) struct ProcMacroProcessSrv {
 }
 
 impl ProcMacroProcessSrv {
-    pub(crate) fn run(process_path: AbsPathBuf) -> io::Result<ProcMacroProcessSrv> {
+    pub(crate) fn run(
+        process_path: AbsPathBuf,
+        env: &FxHashMap<String, String>,
+    ) -> io::Result<ProcMacroProcessSrv> {
         let create_srv = |null_stderr| {
-            let mut process = Process::run(process_path.clone(), null_stderr)?;
+            let mut process = Process::run(process_path.clone(), env, null_stderr)?;
             let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
 
             io::Result::Ok(ProcMacroProcessSrv {
@@ -147,8 +151,12 @@ struct Process {
 }
 
 impl Process {
-    fn run(path: AbsPathBuf, null_stderr: bool) -> io::Result<Process> {
-        let child = JodChild(mk_child(&path, null_stderr)?);
+    fn run(
+        path: AbsPathBuf,
+        env: &FxHashMap<String, String>,
+        null_stderr: bool,
+    ) -> io::Result<Process> {
+        let child = JodChild(mk_child(&path, env, null_stderr)?);
         Ok(Process { child })
     }
 
@@ -161,9 +169,14 @@ impl Process {
     }
 }
 
-fn mk_child(path: &AbsPath, null_stderr: bool) -> io::Result<Child> {
+fn mk_child(
+    path: &AbsPath,
+    env: &FxHashMap<String, String>,
+    null_stderr: bool,
+) -> io::Result<Child> {
     let mut cmd = Command::new(path.as_os_str());
-    cmd.env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
+    cmd.envs(env)
+        .env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
         .stdin(Stdio::piped())
         .stdout(Stdio::piped())
         .stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() });
diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs
index 75d48004b64..b50750c6149 100644
--- a/crates/project-model/src/tests.rs
+++ b/crates/project-model/src/tests.rs
@@ -34,6 +34,7 @@ fn load_cargo_with_overrides(
         cfg_overrides,
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
+        cargo_config_extra_env: Default::default(),
     };
     to_crate_graph(project_workspace)
 }
@@ -53,6 +54,7 @@ fn load_cargo_with_fake_sysroot(
         cfg_overrides: Default::default(),
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
+        cargo_config_extra_env: Default::default(),
     };
     project_workspace.to_crate_graph(
         &mut {
@@ -332,6 +334,7 @@ fn smoke_test_real_sysroot_cargo() {
         cfg_overrides: Default::default(),
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
+        cargo_config_extra_env: Default::default(),
     };
     project_workspace.to_crate_graph(
         &mut {
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 80093925283..cacd506d1b2 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -73,6 +73,7 @@ pub enum ProjectWorkspace {
         cfg_overrides: CfgOverrides,
         toolchain: Option<Version>,
         target_layout: Result<String, String>,
+        cargo_config_extra_env: FxHashMap<String, String>,
     },
     /// Project workspace was manually specified using a `rust-project.json` file.
     Json {
@@ -115,7 +116,8 @@ impl fmt::Debug for ProjectWorkspace {
                 rustc_cfg,
                 cfg_overrides,
                 toolchain,
-                target_layout: data_layout,
+                target_layout,
+                cargo_config_extra_env,
             } => f
                 .debug_struct("Cargo")
                 .field("root", &cargo.workspace_root().file_name())
@@ -128,7 +130,8 @@ impl fmt::Debug for ProjectWorkspace {
                 .field("n_rustc_cfg", &rustc_cfg.len())
                 .field("n_cfg_overrides", &cfg_overrides.len())
                 .field("toolchain", &toolchain)
-                .field("data_layout", &data_layout)
+                .field("data_layout", &target_layout)
+                .field("cargo_config_extra_env", &cargo_config_extra_env)
                 .finish(),
             ProjectWorkspace::Json {
                 project,
@@ -320,6 +323,8 @@ impl ProjectWorkspace {
                 })?;
                 let cargo = CargoWorkspace::new(meta);
 
+                let cargo_config_extra_env =
+                    cargo_config_env(cargo_toml, &config.extra_env, sysroot_ref);
                 ProjectWorkspace::Cargo {
                     cargo,
                     build_scripts: WorkspaceBuildScripts::default(),
@@ -329,6 +334,7 @@ impl ProjectWorkspace {
                     cfg_overrides,
                     toolchain,
                     target_layout: data_layout.map_err(|it| it.to_string()),
+                    cargo_config_extra_env,
                 }
             }
         };
@@ -589,6 +595,7 @@ impl ProjectWorkspace {
                 build_scripts,
                 toolchain: _,
                 target_layout: _,
+                cargo_config_extra_env: _,
             } => {
                 cargo
                     .packages()
@@ -700,6 +707,7 @@ impl ProjectWorkspace {
                 build_scripts,
                 toolchain,
                 target_layout,
+                cargo_config_extra_env: _,
             } => cargo_to_crate_graph(
                 load,
                 rustc.as_ref().map(|a| a.as_ref()).ok(),
@@ -742,6 +750,7 @@ impl ProjectWorkspace {
                     rustc_cfg,
                     cfg_overrides,
                     toolchain,
+                    cargo_config_extra_env,
                     build_scripts: _,
                     target_layout: _,
                 },
@@ -752,6 +761,7 @@ impl ProjectWorkspace {
                     rustc_cfg: o_rustc_cfg,
                     cfg_overrides: o_cfg_overrides,
                     toolchain: o_toolchain,
+                    cargo_config_extra_env: o_cargo_config_extra_env,
                     build_scripts: _,
                     target_layout: _,
                 },
@@ -762,6 +772,7 @@ impl ProjectWorkspace {
                     && cfg_overrides == o_cfg_overrides
                     && toolchain == o_toolchain
                     && sysroot == o_sysroot
+                    && cargo_config_extra_env == o_cargo_config_extra_env
             }
             (
                 Self::Json { project, sysroot, rustc_cfg, toolchain, target_layout: _ },
@@ -1598,3 +1609,31 @@ fn create_cfg_options(rustc_cfg: Vec<CfgFlag>) -> CfgOptions {
     cfg_options.insert_atom("debug_assertions".into());
     cfg_options
 }
+
+fn cargo_config_env(
+    cargo_toml: &ManifestPath,
+    extra_env: &FxHashMap<String, String>,
+    sysroot: Option<&Sysroot>,
+) -> FxHashMap<String, String> {
+    let Ok(program) = Sysroot::discover_tool(sysroot, toolchain::Tool::Cargo) else {
+        return Default::default();
+    };
+    let mut cargo_config = Command::new(program);
+    cargo_config.envs(extra_env);
+    cargo_config
+        .current_dir(cargo_toml.parent())
+        .args(["-Z", "unstable-options", "config", "get", "env"])
+        .env("RUSTC_BOOTSTRAP", "1");
+    // if successful we receive `env.key.value = "value" per entry
+    tracing::debug!("Discovering cargo config env by {:?}", cargo_config);
+    utf8_stdout(cargo_config).map(parse_output_cargo_config_env).unwrap_or_default()
+}
+
+fn parse_output_cargo_config_env(stdout: String) -> FxHashMap<String, String> {
+    stdout
+        .lines()
+        .filter_map(|l| l.strip_prefix("env."))
+        .filter_map(|l| l.split_once(".value = "))
+        .map(|(key, value)| (key.to_owned(), value.trim_matches('"').to_owned()))
+        .collect()
+}
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 3c2ba2f115a..93b6a53908f 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -468,8 +468,19 @@ impl GlobalState {
                     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(),
+                };
                 tracing::info!("Using proc-macro server at {path}");
-                ProcMacroServer::spawn(path.clone()).map_err(|err| {
+
+                ProcMacroServer::spawn(path.clone(), &env).map_err(|err| {
                     tracing::error!(
                         "Failed to run proc-macro server from path {path}, error: {err:?}",
                     );