Skip to content

Commit 050232a

Browse files
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 #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 <jonasschievink@gmail.com>
2 parents de9e989 + d236fc6 commit 050232a

File tree

10 files changed

+140
-79
lines changed

10 files changed

+140
-79
lines changed

Cargo.lock

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[workspace]
22
resolver = "2"
33
members = ["xtask/", "lib/*", "crates/*"]
4+
exclude = ["crates/proc_macro_test/imp"]
45

56
[profile.dev]
67
# Disabling debug info speeds up builds a bunch,

crates/proc_macro_srv/src/dylib.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,9 @@ impl Expander {
188188
/// Copy the dylib to temp directory to prevent locking in Windows
189189
#[cfg(windows)]
190190
fn 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};
192194

193195
let mut to = std::env::temp_dir();
194196

@@ -199,10 +201,11 @@ fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
199201
)
200202
})?;
201203

202-
// generate a time deps unique number
203-
let t = SystemTime::now().duration_since(std::time::UNIX_EPOCH).expect("Time went backwards");
204+
// Generate a unique number by abusing `HashMap`'s hasher.
205+
// Maybe this will also "inspire" a libs team member to finally put `rand` in libstd.
206+
let t = RandomState::new().build_hasher().finish();
204207

205-
let mut unique_name = OsString::from(t.as_millis().to_string());
208+
let mut unique_name = OsString::from(t.to_string());
206209
unique_name.push(file_name);
207210

208211
to.push(unique_name);

crates/proc_macro_srv/src/tests/utils.rs

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,35 +7,8 @@ use proc_macro_api::ListMacrosTask;
77
use std::str::FromStr;
88

99
pub 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
1510
pub fn proc_macro_test_dylib_path() -> std::path::PathBuf {
16-
let name = "proc_macro_test";
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);
11+
proc_macro_test::PROC_MACRO_TEST_LOCATION.into()
3912
}
4013
}
4114

crates/proc_macro_test/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ publish = false
88

99
[lib]
1010
doctest = false
11-
proc-macro = true
11+
12+
[build-dependencies]
13+
proc_macro_test_impl = { path = "imp", version = "0.0.0" }
14+
toolchain = { path = "../toolchain", version = "0.0.0" }
15+
cargo_metadata = "0.13"

crates/proc_macro_test/build.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
6+
use std::{
7+
env, fs,
8+
path::{Path, PathBuf},
9+
process::Command,
10+
};
11+
12+
use cargo_metadata::Message;
13+
14+
fn 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+
}

crates/proc_macro_test/imp/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
target/
2+
Cargo.lock

crates/proc_macro_test/imp/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "proc_macro_test_impl"
3+
version = "0.0.0"
4+
license = "MIT OR Apache-2.0"
5+
authors = ["rust-analyzer developers"]
6+
edition = "2018"
7+
publish = false
8+
9+
[lib]
10+
doctest = false
11+
proc-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`

crates/proc_macro_test/imp/src/lib.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//! Exports a few trivial procedural macros for testing.
2+
3+
use proc_macro::TokenStream;
4+
5+
#[proc_macro]
6+
pub fn fn_like_noop(args: TokenStream) -> TokenStream {
7+
args
8+
}
9+
10+
#[proc_macro]
11+
pub fn fn_like_panic(args: TokenStream) -> TokenStream {
12+
panic!("fn_like_panic!({})", args);
13+
}
14+
15+
#[proc_macro]
16+
pub fn fn_like_error(args: TokenStream) -> TokenStream {
17+
format!("compile_error!(\"fn_like_error!({})\");", args).parse().unwrap()
18+
}
19+
20+
#[proc_macro_attribute]
21+
pub fn attr_noop(_args: TokenStream, item: TokenStream) -> TokenStream {
22+
item
23+
}
24+
25+
#[proc_macro_attribute]
26+
pub fn attr_panic(args: TokenStream, item: TokenStream) -> TokenStream {
27+
panic!("#[attr_panic {}] {}", args, item);
28+
}
29+
30+
#[proc_macro_attribute]
31+
pub 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)]
36+
pub fn derive_empty(_item: TokenStream) -> TokenStream {
37+
TokenStream::new()
38+
}
39+
40+
#[proc_macro_derive(DerivePanic)]
41+
pub fn derive_panic(item: TokenStream) -> TokenStream {
42+
panic!("#[derive(DerivePanic)] {}", item);
43+
}
44+
45+
#[proc_macro_derive(DeriveError)]
46+
pub fn derive_error(item: TokenStream) -> TokenStream {
47+
format!("compile_error!(\"#[derive(DeriveError)] {}\");", item).parse().unwrap()
48+
}

crates/proc_macro_test/src/lib.rs

Lines changed: 2 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,4 @@
11
//! Exports a few trivial procedural macros for testing.
22
3-
use proc_macro::TokenStream;
4-
5-
#[proc_macro]
6-
pub fn fn_like_noop(args: TokenStream) -> TokenStream {
7-
args
8-
}
9-
10-
#[proc_macro]
11-
pub fn fn_like_panic(args: TokenStream) -> TokenStream {
12-
panic!("fn_like_panic!({})", args);
13-
}
14-
15-
#[proc_macro]
16-
pub fn fn_like_error(args: TokenStream) -> TokenStream {
17-
format!("compile_error!(\"fn_like_error!({})\");", args).parse().unwrap()
18-
}
19-
20-
#[proc_macro_attribute]
21-
pub fn attr_noop(_args: TokenStream, item: TokenStream) -> TokenStream {
22-
item
23-
}
24-
25-
#[proc_macro_attribute]
26-
pub fn attr_panic(args: TokenStream, item: TokenStream) -> TokenStream {
27-
panic!("#[attr_panic {}] {}", args, item);
28-
}
29-
30-
#[proc_macro_attribute]
31-
pub 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)]
36-
pub fn derive_empty(_item: TokenStream) -> TokenStream {
37-
TokenStream::new()
38-
}
39-
40-
#[proc_macro_derive(DerivePanic)]
41-
pub fn derive_panic(item: TokenStream) -> TokenStream {
42-
panic!("#[derive(DerivePanic)] {}", item);
43-
}
44-
45-
#[proc_macro_derive(DeriveError)]
46-
pub fn derive_error(item: TokenStream) -> TokenStream {
47-
format!("compile_error!(\"#[derive(DeriveError)] {}\");", item).parse().unwrap()
48-
}
3+
pub static PROC_MACRO_TEST_LOCATION: &str =
4+
include_str!(concat!(env!("OUT_DIR"), "/proc_macro_test_location.txt"));

0 commit comments

Comments
 (0)