fix: Pass .cargo/config.toml env vars to proc-macro server

This commit is contained in:
Lukas Wirth 2024-02-13 19:42:03 +01:00
parent 2c05da15a9
commit a981db53fa
6 changed files with 83 additions and 13 deletions

View file

@ -67,9 +67,9 @@ pub fn load_workspace(
let proc_macro_server = match &load_config.with_proc_macro_server { let proc_macro_server = match &load_config.with_proc_macro_server {
ProcMacroServerChoice::Sysroot => ws ProcMacroServerChoice::Sysroot => ws
.find_sysroot_proc_macro_srv() .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) => { 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")), ProcMacroServerChoice::None => Err(anyhow::format_err!("proc macro server disabled")),
}; };

View file

@ -13,6 +13,7 @@ mod version;
use indexmap::IndexSet; use indexmap::IndexSet;
use paths::AbsPathBuf; use paths::AbsPathBuf;
use rustc_hash::FxHashMap;
use span::Span; use span::Span;
use std::{ use std::{
fmt, io, fmt, io,
@ -107,8 +108,11 @@ pub struct MacroPanic {
impl ProcMacroServer { impl ProcMacroServer {
/// Spawns an external process as the proc macro server and returns a client connected to it. /// 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> { pub fn spawn(
let process = ProcMacroProcessSrv::run(process_path)?; 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)) }) Ok(ProcMacroServer { process: Arc::new(Mutex::new(process)) })
} }

View file

@ -7,6 +7,7 @@ use std::{
}; };
use paths::{AbsPath, AbsPathBuf}; use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap;
use stdx::JodChild; use stdx::JodChild;
use crate::{ use crate::{
@ -26,9 +27,12 @@ pub(crate) struct ProcMacroProcessSrv {
} }
impl 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 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"); let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
io::Result::Ok(ProcMacroProcessSrv { io::Result::Ok(ProcMacroProcessSrv {
@ -147,8 +151,12 @@ struct Process {
} }
impl Process { impl Process {
fn run(path: AbsPathBuf, null_stderr: bool) -> io::Result<Process> { fn run(
let child = JodChild(mk_child(&path, null_stderr)?); path: AbsPathBuf,
env: &FxHashMap<String, String>,
null_stderr: bool,
) -> io::Result<Process> {
let child = JodChild(mk_child(&path, env, null_stderr)?);
Ok(Process { child }) 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()); 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()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() }); .stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() });

View file

@ -34,6 +34,7 @@ fn load_cargo_with_overrides(
cfg_overrides, cfg_overrides,
toolchain: None, toolchain: None,
target_layout: Err("target_data_layout not loaded".into()), target_layout: Err("target_data_layout not loaded".into()),
cargo_config_extra_env: Default::default(),
}; };
to_crate_graph(project_workspace) to_crate_graph(project_workspace)
} }
@ -53,6 +54,7 @@ fn load_cargo_with_fake_sysroot(
cfg_overrides: Default::default(), cfg_overrides: Default::default(),
toolchain: None, toolchain: None,
target_layout: Err("target_data_layout not loaded".into()), target_layout: Err("target_data_layout not loaded".into()),
cargo_config_extra_env: Default::default(),
}; };
project_workspace.to_crate_graph( project_workspace.to_crate_graph(
&mut { &mut {
@ -332,6 +334,7 @@ fn smoke_test_real_sysroot_cargo() {
cfg_overrides: Default::default(), cfg_overrides: Default::default(),
toolchain: None, toolchain: None,
target_layout: Err("target_data_layout not loaded".into()), target_layout: Err("target_data_layout not loaded".into()),
cargo_config_extra_env: Default::default(),
}; };
project_workspace.to_crate_graph( project_workspace.to_crate_graph(
&mut { &mut {

View file

@ -73,6 +73,7 @@ pub enum ProjectWorkspace {
cfg_overrides: CfgOverrides, cfg_overrides: CfgOverrides,
toolchain: Option<Version>, toolchain: Option<Version>,
target_layout: Result<String, String>, target_layout: Result<String, String>,
cargo_config_extra_env: FxHashMap<String, String>,
}, },
/// Project workspace was manually specified using a `rust-project.json` file. /// Project workspace was manually specified using a `rust-project.json` file.
Json { Json {
@ -115,7 +116,8 @@ impl fmt::Debug for ProjectWorkspace {
rustc_cfg, rustc_cfg,
cfg_overrides, cfg_overrides,
toolchain, toolchain,
target_layout: data_layout, target_layout,
cargo_config_extra_env,
} => f } => f
.debug_struct("Cargo") .debug_struct("Cargo")
.field("root", &cargo.workspace_root().file_name()) .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_rustc_cfg", &rustc_cfg.len())
.field("n_cfg_overrides", &cfg_overrides.len()) .field("n_cfg_overrides", &cfg_overrides.len())
.field("toolchain", &toolchain) .field("toolchain", &toolchain)
.field("data_layout", &data_layout) .field("data_layout", &target_layout)
.field("cargo_config_extra_env", &cargo_config_extra_env)
.finish(), .finish(),
ProjectWorkspace::Json { ProjectWorkspace::Json {
project, project,
@ -320,6 +323,8 @@ impl ProjectWorkspace {
})?; })?;
let cargo = CargoWorkspace::new(meta); let cargo = CargoWorkspace::new(meta);
let cargo_config_extra_env =
cargo_config_env(cargo_toml, &config.extra_env, sysroot_ref);
ProjectWorkspace::Cargo { ProjectWorkspace::Cargo {
cargo, cargo,
build_scripts: WorkspaceBuildScripts::default(), build_scripts: WorkspaceBuildScripts::default(),
@ -329,6 +334,7 @@ impl ProjectWorkspace {
cfg_overrides, cfg_overrides,
toolchain, toolchain,
target_layout: data_layout.map_err(|it| it.to_string()), target_layout: data_layout.map_err(|it| it.to_string()),
cargo_config_extra_env,
} }
} }
}; };
@ -589,6 +595,7 @@ impl ProjectWorkspace {
build_scripts, build_scripts,
toolchain: _, toolchain: _,
target_layout: _, target_layout: _,
cargo_config_extra_env: _,
} => { } => {
cargo cargo
.packages() .packages()
@ -700,6 +707,7 @@ impl ProjectWorkspace {
build_scripts, build_scripts,
toolchain, toolchain,
target_layout, target_layout,
cargo_config_extra_env: _,
} => cargo_to_crate_graph( } => cargo_to_crate_graph(
load, load,
rustc.as_ref().map(|a| a.as_ref()).ok(), rustc.as_ref().map(|a| a.as_ref()).ok(),
@ -742,6 +750,7 @@ impl ProjectWorkspace {
rustc_cfg, rustc_cfg,
cfg_overrides, cfg_overrides,
toolchain, toolchain,
cargo_config_extra_env,
build_scripts: _, build_scripts: _,
target_layout: _, target_layout: _,
}, },
@ -752,6 +761,7 @@ impl ProjectWorkspace {
rustc_cfg: o_rustc_cfg, rustc_cfg: o_rustc_cfg,
cfg_overrides: o_cfg_overrides, cfg_overrides: o_cfg_overrides,
toolchain: o_toolchain, toolchain: o_toolchain,
cargo_config_extra_env: o_cargo_config_extra_env,
build_scripts: _, build_scripts: _,
target_layout: _, target_layout: _,
}, },
@ -762,6 +772,7 @@ impl ProjectWorkspace {
&& cfg_overrides == o_cfg_overrides && cfg_overrides == o_cfg_overrides
&& toolchain == o_toolchain && toolchain == o_toolchain
&& sysroot == o_sysroot && sysroot == o_sysroot
&& cargo_config_extra_env == o_cargo_config_extra_env
} }
( (
Self::Json { project, sysroot, rustc_cfg, toolchain, target_layout: _ }, 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.insert_atom("debug_assertions".into());
cfg_options 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()
}

View file

@ -468,8 +468,19 @@ impl GlobalState {
None => ws.find_sysroot_proc_macro_srv()?, 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}"); 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!( tracing::error!(
"Failed to run proc-macro server from path {path}, error: {err:?}", "Failed to run proc-macro server from path {path}, error: {err:?}",
); );