aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-06-11 11:44:07 +0100
committerGitHub <[email protected]>2021-06-11 11:44:07 +0100
commit050232a37e71ec06e8810af29178b124c76a527d (patch)
tree6fddd9fbac95b72b24f0024586fe6d0c985aa429
parentde9e989cf4435c58b8347b16881e50d06f754f20 (diff)
parentd236fc6abecb308dab5e21898fa40f3bddf27640 (diff)
Merge #9192
9192: internal: Build test-macros in a build script r=jonas-schievink a=jonas-schievink This build the test-proc-macros in `proc_macro_test` in a build script, and copies the artifact to `OUT_DIR`. This should make it available throughout all of rust-analyzer at no cost other than depending on `proc_macro_test`, fixing https://github.com/rust-analyzer/rust-analyzer/issues/9067. This hopefully will let us later write inline tests that utilize proc macros, which makes my life fixing proc macro bugs easier. Opening this as a sort of RFC, because I'm not totally sure this approach is the best. Co-authored-by: Jonas Schievink <[email protected]>
-rw-r--r--Cargo.lock9
-rw-r--r--Cargo.toml1
-rw-r--r--crates/proc_macro_srv/src/dylib.rs11
-rw-r--r--crates/proc_macro_srv/src/tests/utils.rs29
-rw-r--r--crates/proc_macro_test/Cargo.toml6
-rw-r--r--crates/proc_macro_test/build.rs48
-rw-r--r--crates/proc_macro_test/imp/.gitignore2
-rw-r--r--crates/proc_macro_test/imp/Cargo.toml17
-rw-r--r--crates/proc_macro_test/imp/src/lib.rs48
-rw-r--r--crates/proc_macro_test/src/lib.rs48
10 files changed, 140 insertions, 79 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2bd8897f0..ea2c1aed7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1158,6 +1158,15 @@ dependencies = [
1158[[package]] 1158[[package]]
1159name = "proc_macro_test" 1159name = "proc_macro_test"
1160version = "0.0.0" 1160version = "0.0.0"
1161dependencies = [
1162 "cargo_metadata",
1163 "proc_macro_test_impl",
1164 "toolchain",
1165]
1166
1167[[package]]
1168name = "proc_macro_test_impl"
1169version = "0.0.0"
1161 1170
1162[[package]] 1171[[package]]
1163name = "profile" 1172name = "profile"
diff --git a/Cargo.toml b/Cargo.toml
index 32ba3923b..4d6908fa9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,7 @@
1[workspace] 1[workspace]
2resolver = "2" 2resolver = "2"
3members = ["xtask/", "lib/*", "crates/*"] 3members = ["xtask/", "lib/*", "crates/*"]
4exclude = ["crates/proc_macro_test/imp"]
4 5
5[profile.dev] 6[profile.dev]
6# Disabling debug info speeds up builds a bunch, 7# Disabling debug info speeds up builds a bunch,
diff --git a/crates/proc_macro_srv/src/dylib.rs b/crates/proc_macro_srv/src/dylib.rs
index cccc53220..5133e7c50 100644
--- a/crates/proc_macro_srv/src/dylib.rs
+++ b/crates/proc_macro_srv/src/dylib.rs
@@ -188,7 +188,9 @@ impl Expander {
188/// Copy the dylib to temp directory to prevent locking in Windows 188/// Copy the dylib to temp directory to prevent locking in Windows
189#[cfg(windows)] 189#[cfg(windows)]
190fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> { 190fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
191 use std::{ffi::OsString, time::SystemTime}; 191 use std::collections::hash_map::RandomState;
192 use std::ffi::OsString;
193 use std::hash::{BuildHasher, Hasher};
192 194
193 let mut to = std::env::temp_dir(); 195 let mut to = std::env::temp_dir();
194 196
@@ -199,10 +201,11 @@ fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
199 ) 201 )
200 })?; 202 })?;
201 203
202 // generate a time deps unique number 204 // Generate a unique number by abusing `HashMap`'s hasher.
203 let t = SystemTime::now().duration_since(std::time::UNIX_EPOCH).expect("Time went backwards"); 205 // Maybe this will also "inspire" a libs team member to finally put `rand` in libstd.
206 let t = RandomState::new().build_hasher().finish();
204 207
205 let mut unique_name = OsString::from(t.as_millis().to_string()); 208 let mut unique_name = OsString::from(t.to_string());
206 unique_name.push(file_name); 209 unique_name.push(file_name);
207 210
208 to.push(unique_name); 211 to.push(unique_name);
diff --git a/crates/proc_macro_srv/src/tests/utils.rs b/crates/proc_macro_srv/src/tests/utils.rs
index 2e950c113..2c093aa0a 100644
--- a/crates/proc_macro_srv/src/tests/utils.rs
+++ b/crates/proc_macro_srv/src/tests/utils.rs
@@ -7,35 +7,8 @@ use proc_macro_api::ListMacrosTask;
7use std::str::FromStr; 7use std::str::FromStr;
8 8
9pub mod fixtures { 9pub mod fixtures {
10 use cargo_metadata::Message;
11 use std::path::PathBuf;
12 use std::process::Command;
13
14 // Use current project metadata to get the proc-macro dylib path
15 pub fn proc_macro_test_dylib_path() -> std::path::PathBuf { 10 pub fn proc_macro_test_dylib_path() -> std::path::PathBuf {
16 let name = "proc_macro_test"; 11 proc_macro_test::PROC_MACRO_TEST_LOCATION.into()
17 let version = "0.0.0";
18 let command = Command::new(toolchain::cargo())
19 .args(&["check", "--tests", "--message-format", "json"])
20 .output()
21 .unwrap()
22 .stdout;
23
24 for message in Message::parse_stream(command.as_slice()) {
25 match message.unwrap() {
26 Message::CompilerArtifact(artifact) => {
27 if artifact.target.kind.contains(&"proc-macro".to_string()) {
28 let repr = format!("{} {}", name, version);
29 if artifact.package_id.repr.starts_with(&repr) {
30 return PathBuf::from(&artifact.filenames[0]);
31 }
32 }
33 }
34 _ => (), // Unknown message
35 }
36 }
37
38 panic!("No proc-macro dylib for {} found!", name);
39 } 12 }
40} 13}
41 14
diff --git a/crates/proc_macro_test/Cargo.toml b/crates/proc_macro_test/Cargo.toml
index 753443be2..1a88e361e 100644
--- a/crates/proc_macro_test/Cargo.toml
+++ b/crates/proc_macro_test/Cargo.toml
@@ -8,4 +8,8 @@ publish = false
8 8
9[lib] 9[lib]
10doctest = false 10doctest = false
11proc-macro = true 11
12[build-dependencies]
13proc_macro_test_impl = { path = "imp", version = "0.0.0" }
14toolchain = { path = "../toolchain", version = "0.0.0" }
15cargo_metadata = "0.13"
diff --git a/crates/proc_macro_test/build.rs b/crates/proc_macro_test/build.rs
new file mode 100644
index 000000000..4653a93dd
--- /dev/null
+++ b/crates/proc_macro_test/build.rs
@@ -0,0 +1,48 @@
1//! This will build the proc macro in `imp`, and copy the resulting dylib artifact into the
2//! `OUT_DIR`.
3//!
4//! `proc_macro_test` itself contains only a path to that artifact.
5
6use std::{
7 env, fs,
8 path::{Path, PathBuf},
9 process::Command,
10};
11
12use cargo_metadata::Message;
13
14fn main() {
15 let out_dir = env::var_os("OUT_DIR").unwrap();
16 let out_dir = Path::new(&out_dir);
17
18 let name = "proc_macro_test_impl";
19 let version = "0.0.0";
20 let output = Command::new(toolchain::cargo())
21 .current_dir("imp")
22 .args(&["build", "-p", "proc_macro_test_impl", "--message-format", "json"])
23 .output()
24 .unwrap();
25 assert!(output.status.success());
26
27 let mut artifact_path = None;
28 for message in Message::parse_stream(output.stdout.as_slice()) {
29 match message.unwrap() {
30 Message::CompilerArtifact(artifact) => {
31 if artifact.target.kind.contains(&"proc-macro".to_string()) {
32 let repr = format!("{} {}", name, version);
33 if artifact.package_id.repr.starts_with(&repr) {
34 artifact_path = Some(PathBuf::from(&artifact.filenames[0]));
35 }
36 }
37 }
38 _ => (), // Unknown message
39 }
40 }
41
42 let src_path = artifact_path.expect("no dylib for proc_macro_test_impl found");
43 let dest_path = out_dir.join(src_path.file_name().unwrap());
44 fs::copy(src_path, &dest_path).unwrap();
45
46 let info_path = out_dir.join("proc_macro_test_location.txt");
47 fs::write(info_path, dest_path.to_str().unwrap()).unwrap();
48}
diff --git a/crates/proc_macro_test/imp/.gitignore b/crates/proc_macro_test/imp/.gitignore
new file mode 100644
index 000000000..2c96eb1b6
--- /dev/null
+++ b/crates/proc_macro_test/imp/.gitignore
@@ -0,0 +1,2 @@
1target/
2Cargo.lock
diff --git a/crates/proc_macro_test/imp/Cargo.toml b/crates/proc_macro_test/imp/Cargo.toml
new file mode 100644
index 000000000..1c2e75401
--- /dev/null
+++ b/crates/proc_macro_test/imp/Cargo.toml
@@ -0,0 +1,17 @@
1[package]
2name = "proc_macro_test_impl"
3version = "0.0.0"
4license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"]
6edition = "2018"
7publish = false
8
9[lib]
10doctest = false
11proc-macro = true
12
13[workspace]
14
15[dependencies]
16# this crate should not have any dependencies, since it uses its own workspace,
17# and its own `Cargo.lock`
diff --git a/crates/proc_macro_test/imp/src/lib.rs b/crates/proc_macro_test/imp/src/lib.rs
new file mode 100644
index 000000000..4b26d2472
--- /dev/null
+++ b/crates/proc_macro_test/imp/src/lib.rs
@@ -0,0 +1,48 @@
1//! Exports a few trivial procedural macros for testing.
2
3use proc_macro::TokenStream;
4
5#[proc_macro]
6pub fn fn_like_noop(args: TokenStream) -> TokenStream {
7 args
8}
9
10#[proc_macro]
11pub fn fn_like_panic(args: TokenStream) -> TokenStream {
12 panic!("fn_like_panic!({})", args);
13}
14
15#[proc_macro]
16pub fn fn_like_error(args: TokenStream) -> TokenStream {
17 format!("compile_error!(\"fn_like_error!({})\");", args).parse().unwrap()
18}
19
20#[proc_macro_attribute]
21pub fn attr_noop(_args: TokenStream, item: TokenStream) -> TokenStream {
22 item
23}
24
25#[proc_macro_attribute]
26pub fn attr_panic(args: TokenStream, item: TokenStream) -> TokenStream {
27 panic!("#[attr_panic {}] {}", args, item);
28}
29
30#[proc_macro_attribute]
31pub fn attr_error(args: TokenStream, item: TokenStream) -> TokenStream {
32 format!("compile_error!(\"#[attr_error({})] {}\");", args, item).parse().unwrap()
33}
34
35#[proc_macro_derive(DeriveEmpty)]
36pub fn derive_empty(_item: TokenStream) -> TokenStream {
37 TokenStream::new()
38}
39
40#[proc_macro_derive(DerivePanic)]
41pub fn derive_panic(item: TokenStream) -> TokenStream {
42 panic!("#[derive(DerivePanic)] {}", item);
43}
44
45#[proc_macro_derive(DeriveError)]
46pub fn derive_error(item: TokenStream) -> TokenStream {
47 format!("compile_error!(\"#[derive(DeriveError)] {}\");", item).parse().unwrap()
48}
diff --git a/crates/proc_macro_test/src/lib.rs b/crates/proc_macro_test/src/lib.rs
index 4b26d2472..2edf23a63 100644
--- a/crates/proc_macro_test/src/lib.rs
+++ b/crates/proc_macro_test/src/lib.rs
@@ -1,48 +1,4 @@
1//! Exports a few trivial procedural macros for testing. 1//! Exports a few trivial procedural macros for testing.
2 2
3use proc_macro::TokenStream; 3pub static PROC_MACRO_TEST_LOCATION: &str =
4 4 include_str!(concat!(env!("OUT_DIR"), "/proc_macro_test_location.txt"));
5#[proc_macro]
6pub fn fn_like_noop(args: TokenStream) -> TokenStream {
7 args
8}
9
10#[proc_macro]
11pub fn fn_like_panic(args: TokenStream) -> TokenStream {
12 panic!("fn_like_panic!({})", args);
13}
14
15#[proc_macro]
16pub fn fn_like_error(args: TokenStream) -> TokenStream {
17 format!("compile_error!(\"fn_like_error!({})\");", args).parse().unwrap()
18}
19
20#[proc_macro_attribute]
21pub fn attr_noop(_args: TokenStream, item: TokenStream) -> TokenStream {
22 item
23}
24
25#[proc_macro_attribute]
26pub fn attr_panic(args: TokenStream, item: TokenStream) -> TokenStream {
27 panic!("#[attr_panic {}] {}", args, item);
28}
29
30#[proc_macro_attribute]
31pub fn attr_error(args: TokenStream, item: TokenStream) -> TokenStream {
32 format!("compile_error!(\"#[attr_error({})] {}\");", args, item).parse().unwrap()
33}
34
35#[proc_macro_derive(DeriveEmpty)]
36pub fn derive_empty(_item: TokenStream) -> TokenStream {
37 TokenStream::new()
38}
39
40#[proc_macro_derive(DerivePanic)]
41pub fn derive_panic(item: TokenStream) -> TokenStream {
42 panic!("#[derive(DerivePanic)] {}", item);
43}
44
45#[proc_macro_derive(DeriveError)]
46pub fn derive_error(item: TokenStream) -> TokenStream {
47 format!("compile_error!(\"#[derive(DeriveError)] {}\");", item).parse().unwrap()
48}