From 5f54ec0e859a020b125519d56ad2a08defd3ddf3 Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Sat, 23 Jul 2022 22:47:34 +0200 Subject: [PATCH 1/8] Add a proc-macro-srv-cli crate --- Cargo.lock | 7 +++++++ crates/proc-macro-srv-cli/Cargo.toml | 13 +++++++++++++ crates/proc-macro-srv-cli/src/main.rs | 5 +++++ 3 files changed, 25 insertions(+) create mode 100644 crates/proc-macro-srv-cli/Cargo.toml create mode 100644 crates/proc-macro-srv-cli/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 4c830006832..703f0e5b8af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1198,6 +1198,13 @@ dependencies = [ "tt", ] +[[package]] +name = "proc-macro-srv-cli" +version = "0.0.0" +dependencies = [ + "proc-macro-srv", +] + [[package]] name = "proc-macro-test" version = "0.0.0" diff --git a/crates/proc-macro-srv-cli/Cargo.toml b/crates/proc-macro-srv-cli/Cargo.toml new file mode 100644 index 00000000000..959002f664a --- /dev/null +++ b/crates/proc-macro-srv-cli/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "proc-macro-srv-cli" +version = "0.0.0" +description = "TBD" +license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.57" + +[dependencies] +proc-macro-srv = { version = "0.0.0", path = "../proc-macro-srv" } + +[features] +sysroot-abi = ["proc-macro-srv/sysroot-abi"] diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs new file mode 100644 index 00000000000..ea16cfff4b9 --- /dev/null +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -0,0 +1,5 @@ +use proc_macro_srv::cli; + +fn main() { + cli::run().unwrap(); +} From fba6adfae48d55984934872a81d533dc405b7cd3 Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Sun, 24 Jul 2022 00:48:20 +0200 Subject: [PATCH 2/8] Add doc comment to pass tidy check --- crates/proc-macro-srv-cli/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index ea16cfff4b9..0f23a7daafa 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -1,3 +1,5 @@ +//! A standalone binary for `proc-macro-srv`. + use proc_macro_srv::cli; fn main() { From fd1b64ec718d8483a98872bd91ee8f11b6893e7f Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Sun, 24 Jul 2022 14:50:30 +0200 Subject: [PATCH 3/8] Return result directly Co-authored-by: Lukas Wirth --- crates/proc-macro-srv-cli/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index 0f23a7daafa..8398f2ba6cb 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -2,6 +2,6 @@ use proc_macro_srv::cli; -fn main() { - cli::run().unwrap(); +fn main() -> std::io::Result<()> { + cli::run() } From 4364531c2f3db41d9ba3a72f3e77ab26d16db8b0 Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Sun, 24 Jul 2022 14:53:20 +0200 Subject: [PATCH 4/8] Name the binary 'proc-macro-srv' --- crates/proc-macro-srv-cli/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/proc-macro-srv-cli/Cargo.toml b/crates/proc-macro-srv-cli/Cargo.toml index 959002f664a..badb594f062 100644 --- a/crates/proc-macro-srv-cli/Cargo.toml +++ b/crates/proc-macro-srv-cli/Cargo.toml @@ -11,3 +11,7 @@ proc-macro-srv = { version = "0.0.0", path = "../proc-macro-srv" } [features] sysroot-abi = ["proc-macro-srv/sysroot-abi"] + +[[bin]] +name = "proc-macro-srv" +path = "src/main.rs" From dadb83282d7dc7bfb408d93d4953019a328e8e2b Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Mon, 25 Jul 2022 16:07:41 +0200 Subject: [PATCH 5/8] Remember the difference between 'sysroot root' and 'sysroot src root', start looking in there for a rust-analyzer-proc-macro-srv binary --- crates/project-model/src/project_json.rs | 5 ++++ crates/project-model/src/sysroot.rs | 21 +++++++++++++---- crates/project-model/src/tests.rs | 7 ++++-- crates/project-model/src/workspace.rs | 12 +++++++--- crates/rust-analyzer/src/reload.rs | 30 ++++++++++++++++++++++-- 5 files changed, 63 insertions(+), 12 deletions(-) diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs index a3c5ac16740..63d1d0ace96 100644 --- a/crates/project-model/src/project_json.rs +++ b/crates/project-model/src/project_json.rs @@ -17,6 +17,9 @@ /// Roots and crates that compose this Rust project. #[derive(Clone, Debug, Eq, PartialEq)] pub struct ProjectJson { + /// e.g. `path/to/sysroot` + pub(crate) sysroot: Option, + /// e.g. `path/to/sysroot/lib/rustlib/src/rust` pub(crate) sysroot_src: Option, project_root: AbsPathBuf, crates: Vec, @@ -52,6 +55,7 @@ impl ProjectJson { /// configuration. pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { ProjectJson { + sysroot: data.sysroot.map(|it| base.join(it)), sysroot_src: data.sysroot_src.map(|it| base.join(it)), project_root: base.to_path_buf(), crates: data @@ -122,6 +126,7 @@ pub fn path(&self) -> &AbsPath { #[derive(Deserialize, Debug, Clone)] pub struct ProjectJsonData { + sysroot: Option, sysroot_src: Option, crates: Vec, } diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index 52750f48969..b17a59b10bb 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -15,6 +15,7 @@ #[derive(Debug, Clone, Eq, PartialEq)] pub struct Sysroot { root: AbsPathBuf, + src_root: AbsPathBuf, crates: Arena, } @@ -35,6 +36,15 @@ fn index(&self, index: SysrootCrate) -> &SysrootCrateData { } impl Sysroot { + /// Returns sysroot directory, where `bin/`, `etc/`, `lib/`, `libexec/` + /// subfolder live, like: + /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library` + pub fn src_root(&self) -> &AbsPath { + &self.src_root + } + + /// Returns sysroot "src" directory, where stdlib sources are located, like: + /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu` pub fn root(&self) -> &AbsPath { &self.root } @@ -61,7 +71,7 @@ pub fn discover(dir: &AbsPath) -> Result { tracing::debug!("Discovering sysroot for {}", dir.display()); let sysroot_dir = discover_sysroot_dir(dir)?; let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir)?; - let res = Sysroot::load(sysroot_src_dir)?; + let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?; Ok(res) } @@ -71,14 +81,15 @@ pub fn discover_rustc(cargo_toml: &ManifestPath) -> Option { discover_sysroot_dir(current_dir).ok().and_then(|sysroot_dir| get_rustc_src(&sysroot_dir)) } - pub fn load(sysroot_src_dir: AbsPathBuf) -> Result { - let mut sysroot = Sysroot { root: sysroot_src_dir, crates: Arena::default() }; + pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Result { + let mut sysroot = + Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() }; for path in SYSROOT_CRATES.trim().lines() { let name = path.split('/').last().unwrap(); let root = [format!("{}/src/lib.rs", path), format!("lib{}/lib.rs", path)] .into_iter() - .map(|it| sysroot.root.join(it)) + .map(|it| sysroot.src_root.join(it)) .filter_map(|it| ManifestPath::try_from(it).ok()) .find(|it| fs::metadata(it).is_ok()); @@ -119,7 +130,7 @@ pub fn load(sysroot_src_dir: AbsPathBuf) -> Result { }; anyhow::bail!( "could not find libcore in sysroot path `{}`{}", - sysroot.root.as_path().display(), + sysroot.src_root.as_path().display(), var_note, ); } diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index ddfea0ce4c4..e304a59c018 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -75,8 +75,11 @@ fn get_test_path(file: &str) -> PathBuf { fn get_fake_sysroot() -> Sysroot { let sysroot_path = get_test_path("fake-sysroot"); - let sysroot_src_dir = AbsPathBuf::assert(sysroot_path); - Sysroot::load(sysroot_src_dir).unwrap() + // there's no `libexec/` directory with a `proc-macro-srv` binary in that + // fake sysroot, so we give them both the same path: + let sysroot_dir = AbsPathBuf::assert(sysroot_path); + let sysroot_src_dir = sysroot_dir.clone(); + Sysroot::load(sysroot_dir, sysroot_src_dir).unwrap() } fn rooted_project_json(data: ProjectJsonData) -> ProjectJson { diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index de424583545..63882466fa4 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -230,8 +230,14 @@ pub fn load_inline( project_json: ProjectJson, target: Option<&str>, ) -> Result { - let sysroot = match &project_json.sysroot_src { - Some(path) => Some(Sysroot::load(path.clone())?), + let sysroot = match project_json.sysroot_src.clone() { + Some(sysroot_src) => { + // if `sysroot` isn't specified (only `sysroot_src`), we won't have + // a real sysroot path, that's fine. it's just used to discover + // the standalone `proc-macro-srv` binary. + let sysroot = project_json.sysroot.clone().unwrap_or_else(|| sysroot_src.clone()); + Some(Sysroot::load(sysroot, sysroot_src)?) + } None => None, }; let rustc_cfg = rustc_cfg::get(None, target); @@ -345,7 +351,7 @@ pub fn to_roots(&self) -> Vec { }) .chain(sysroot.iter().map(|sysroot| PackageRoot { is_local: false, - include: vec![sysroot.root().to_path_buf()], + include: vec![sysroot.src_root().to_path_buf()], exclude: Vec::new(), })) .chain(rustc.iter().flat_map(|rustc| { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index e5802773e74..4256c2a764a 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -305,8 +305,34 @@ fn eq_ignore_build_data<'a>( if self.proc_macro_clients.is_empty() { if let Some((path, args)) = self.config.proc_macro_srv() { - self.proc_macro_clients = (0..self.workspaces.len()) - .map(|_| { + self.proc_macro_clients = self + .workspaces + .iter() + .map(|ws| { + let mut path = path.clone(); + if let ProjectWorkspace::Cargo { sysroot, .. } = ws { + tracing::info!("Found a cargo workspace..."); + if let Some(sysroot) = sysroot.as_ref() { + tracing::info!("Found a cargo workspace with a sysroot..."); + let server_path = sysroot + .root() + .join("libexec") + .join("rust-analyzer-proc-macro-srv"); + if std::fs::metadata(&server_path).is_ok() { + tracing::info!( + "And the server exists at {}", + server_path.display() + ); + path = server_path; + } else { + tracing::info!( + "And the server does not exist at {}", + server_path.display() + ); + } + } + } + ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| { let error = format!( "Failed to run proc_macro_srv from path {}, error: {:?}", From 74a2fad5e6b6193842fe52b50ee174736efb266d Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Mon, 25 Jul 2022 16:22:39 +0200 Subject: [PATCH 6/8] Gate and rename binary, use it if it's in the sysroot --- crates/proc-macro-api/src/process.rs | 1 + crates/proc-macro-srv-cli/Cargo.toml | 2 +- crates/proc-macro-srv-cli/src/main.rs | 12 ++++++++++++ crates/rust-analyzer/src/reload.rs | 8 ++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index ff4c59447d8..c4018d3b39e 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -86,6 +86,7 @@ fn mk_child( ) -> io::Result { Command::new(path.as_os_str()) .args(args) + .env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable") .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::inherit()) diff --git a/crates/proc-macro-srv-cli/Cargo.toml b/crates/proc-macro-srv-cli/Cargo.toml index badb594f062..9d0da5dee9c 100644 --- a/crates/proc-macro-srv-cli/Cargo.toml +++ b/crates/proc-macro-srv-cli/Cargo.toml @@ -13,5 +13,5 @@ proc-macro-srv = { version = "0.0.0", path = "../proc-macro-srv" } sysroot-abi = ["proc-macro-srv/sysroot-abi"] [[bin]] -name = "proc-macro-srv" +name = "rust-analyzer-proc-macro-srv" path = "src/main.rs" diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index 8398f2ba6cb..ac9fa9f5a4c 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -3,5 +3,17 @@ use proc_macro_srv::cli; fn main() -> std::io::Result<()> { + let v = std::env::var("RUST_ANALYZER_INTERNALS_DO_NOT_USE"); + match v.as_deref() { + Ok("this is unstable") => { + // very well, if you must + } + _ => { + eprintln!("If you're rust-analyzer, you can use this tool by exporting RUST_ANALYZER_INTERNALS_DO_NOT_USE='this is unstable'."); + eprintln!("If not, you probably shouldn't use this tool. But do what you want: I'm an error message, not a cop."); + std::process::exit(122); + } + } + cli::run() } diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 4256c2a764a..9ae361b034e 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -309,7 +309,9 @@ fn eq_ignore_build_data<'a>( .workspaces .iter() .map(|ws| { + let mut args = args.clone(); let mut path = path.clone(); + if let ProjectWorkspace::Cargo { sysroot, .. } = ws { tracing::info!("Found a cargo workspace..."); if let Some(sysroot) = sysroot.as_ref() { @@ -324,6 +326,7 @@ fn eq_ignore_build_data<'a>( server_path.display() ); path = server_path; + args = vec![]; } else { tracing::info!( "And the server does not exist at {}", @@ -333,6 +336,11 @@ fn eq_ignore_build_data<'a>( } } + tracing::info!( + "Using proc-macro server at {} with args {:?}", + path.display(), + args + ); ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| { let error = format!( "Failed to run proc_macro_srv from path {}, error: {:?}", From 696775153dffaa701bcabe67b5fe601db862c4f4 Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Mon, 25 Jul 2022 16:59:10 +0200 Subject: [PATCH 7/8] Fix mix up in comments --- crates/project-model/src/sysroot.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index b17a59b10bb..362bb0f5e79 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -36,19 +36,19 @@ fn index(&self, index: SysrootCrate) -> &SysrootCrateData { } impl Sysroot { - /// Returns sysroot directory, where `bin/`, `etc/`, `lib/`, `libexec/` + /// Returns sysroot "root" directory, where `bin/`, `etc/`, `lib/`, `libexec/` /// subfolder live, like: - /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library` - pub fn src_root(&self) -> &AbsPath { - &self.src_root - } - - /// Returns sysroot "src" directory, where stdlib sources are located, like: /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu` pub fn root(&self) -> &AbsPath { &self.root } + /// 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` + pub fn src_root(&self) -> &AbsPath { + &self.src_root + } + pub fn public_deps(&self) -> impl Iterator + '_ { // core is added as a dependency before std in order to // mimic rustcs dependency order From 2c2520fbb48b977a805b46af79e4016a4394e719 Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Mon, 25 Jul 2022 17:52:38 +0200 Subject: [PATCH 8/8] Allow specifying sysroot OR sysroot_src --- crates/project-model/src/workspace.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 63882466fa4..b144006b44e 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -230,16 +230,26 @@ pub fn load_inline( project_json: ProjectJson, target: Option<&str>, ) -> Result { - let sysroot = match project_json.sysroot_src.clone() { - Some(sysroot_src) => { - // if `sysroot` isn't specified (only `sysroot_src`), we won't have - // a real sysroot path, that's fine. it's just used to discover - // the standalone `proc-macro-srv` binary. - let sysroot = project_json.sysroot.clone().unwrap_or_else(|| sysroot_src.clone()); + let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) { + (Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)?), + (Some(sysroot), None) => { + // assume sysroot is structured like rustup's and guess `sysroot_src` + let sysroot_src = + sysroot.join("lib").join("rustlib").join("src").join("rust").join("library"); + Some(Sysroot::load(sysroot, sysroot_src)?) } - None => None, + (None, Some(sysroot_src)) => { + // assume sysroot is structured like rustup's and guess `sysroot` + let mut sysroot = sysroot_src.clone(); + for _ in 0..5 { + sysroot.pop(); + } + Some(Sysroot::load(sysroot, sysroot_src)?) + } + (None, None) => None, }; + let rustc_cfg = rustc_cfg::get(None, target); Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) }