Skip to content

Commit

Permalink
Compiletest: Add proc-macro header
Browse files Browse the repository at this point in the history
This adds a proc-macro header to make it easier to depend on a
proc-macro, and remove some of the boilerplate necessary.
  • Loading branch information
ehuss committed Nov 27, 2024
1 parent 39cb338 commit f592dd9
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 23 deletions.
1 change: 1 addition & 0 deletions src/tools/compiletest/src/directive-list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
"pp-exact",
"pretty-compare-only",
"pretty-mode",
"proc-macro",
"reference",
"regex-error-pattern",
"remap-src-base",
Expand Down
1 change: 1 addition & 0 deletions src/tools/compiletest/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ mod directives {
pub const AUX_BIN: &'static str = "aux-bin";
pub const AUX_BUILD: &'static str = "aux-build";
pub const AUX_CRATE: &'static str = "aux-crate";
pub const PROC_MACRO: &'static str = "proc-macro";
pub const AUX_CODEGEN_BACKEND: &'static str = "aux-codegen-backend";
pub const EXEC_ENV: &'static str = "exec-env";
pub const RUSTC_ENV: &'static str = "rustc-env";
Expand Down
11 changes: 8 additions & 3 deletions src/tools/compiletest/src/header/auxiliary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use std::iter;

use crate::common::Config;
use crate::header::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE};
use crate::header::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};

/// Properties parsed from `aux-*` test directives.
#[derive(Clone, Debug, Default)]
Expand All @@ -17,6 +17,8 @@ pub(crate) struct AuxProps {
/// Similar to `builds`, but a list of NAME=somelib.rs of dependencies
/// to build and pass with the `--extern` flag.
pub(crate) crates: Vec<(String, String)>,
/// Same as `builds`, but for proc-macros.
pub(crate) proc_macros: Vec<String>,
/// Similar to `builds`, but also uses the resulting dylib as a
/// `-Zcodegen-backend` when compiling the test file.
pub(crate) codegen_backend: Option<String>,
Expand All @@ -26,26 +28,29 @@ impl AuxProps {
/// Yields all of the paths (relative to `./auxiliary/`) that have been
/// specified in `aux-*` directives for this test.
pub(crate) fn all_aux_path_strings(&self) -> impl Iterator<Item = &str> {
let Self { builds, bins, crates, codegen_backend } = self;
let Self { builds, bins, crates, proc_macros, codegen_backend } = self;

iter::empty()
.chain(builds.iter().map(String::as_str))
.chain(bins.iter().map(String::as_str))
.chain(crates.iter().map(|(_, path)| path.as_str()))
.chain(proc_macros.iter().map(String::as_str))
.chain(codegen_backend.iter().map(String::as_str))
}
}

/// If the given test directive line contains an `aux-*` directive, parse it
/// and update [`AuxProps`] accordingly.
pub(super) fn parse_and_update_aux(config: &Config, ln: &str, aux: &mut AuxProps) {
if !ln.starts_with("aux-") {
if !(ln.starts_with("aux-") || ln.starts_with("proc-macro")) {
return;
}

config.push_name_value_directive(ln, AUX_BUILD, &mut aux.builds, |r| r.trim().to_string());
config.push_name_value_directive(ln, AUX_BIN, &mut aux.bins, |r| r.trim().to_string());
config.push_name_value_directive(ln, AUX_CRATE, &mut aux.crates, parse_aux_crate);
config
.push_name_value_directive(ln, PROC_MACRO, &mut aux.proc_macros, |r| r.trim().to_string());
if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) {
aux.codegen_backend = Some(r.trim().to_owned());
}
Expand Down
76 changes: 56 additions & 20 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ fn get_lib_name(name: &str, aux_type: AuxType) -> Option<String> {
// In this case, the only path we can pass
// with '--extern-meta' is the '.rlib' file
AuxType::Lib => Some(format!("lib{name}.rlib")),
AuxType::Dylib => Some(dylib_name(name)),
AuxType::Dylib | AuxType::ProcMacro => Some(dylib_name(name)),
}
}

Expand Down Expand Up @@ -1097,7 +1097,9 @@ impl<'test> TestCx<'test> {
}

fn has_aux_dir(&self) -> bool {
!self.props.aux.builds.is_empty() || !self.props.aux.crates.is_empty()
!self.props.aux.builds.is_empty()
|| !self.props.aux.crates.is_empty()
|| !self.props.aux.proc_macros.is_empty()
}

fn aux_output_dir(&self) -> PathBuf {
Expand All @@ -1118,31 +1120,48 @@ impl<'test> TestCx<'test> {

fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Command) {
for rel_ab in &self.props.aux.builds {
self.build_auxiliary(of, rel_ab, &aux_dir, false /* is_bin */);
self.build_auxiliary(of, rel_ab, &aux_dir, None);
}

for rel_ab in &self.props.aux.bins {
self.build_auxiliary(of, rel_ab, &aux_dir, true /* is_bin */);
self.build_auxiliary(of, rel_ab, &aux_dir, Some(AuxType::Bin));
}

let path_to_crate_name = |path: &str| -> String {
path.rsplit_once('/')
.map_or(path, |(_, tail)| tail)
.trim_end_matches(".rs")
.replace('-', "_")
};

let add_extern =
|rustc: &mut Command, aux_name: &str, aux_path: &str, aux_type: AuxType| {
let lib_name = get_lib_name(&path_to_crate_name(aux_path), aux_type);
if let Some(lib_name) = lib_name {
rustc.arg("--extern").arg(format!(
"{}={}/{}",
aux_name,
aux_dir.display(),
lib_name
));
}
};

for (aux_name, aux_path) in &self.props.aux.crates {
let aux_type = self.build_auxiliary(of, &aux_path, &aux_dir, false /* is_bin */);
let lib_name =
get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), aux_type);
if let Some(lib_name) = lib_name {
rustc.arg("--extern").arg(format!(
"{}={}/{}",
aux_name,
aux_dir.display(),
lib_name
));
}
let aux_type = self.build_auxiliary(of, &aux_path, &aux_dir, None);
add_extern(rustc, aux_name, aux_path, aux_type);
}

for proc_macro in &self.props.aux.proc_macros {
self.build_auxiliary(of, proc_macro, &aux_dir, Some(AuxType::ProcMacro));
let crate_name = path_to_crate_name(proc_macro);
add_extern(rustc, &crate_name, proc_macro, AuxType::ProcMacro);
}

// Build any `//@ aux-codegen-backend`, and pass the resulting library
// to `-Zcodegen-backend` when compiling the test file.
if let Some(aux_file) = &self.props.aux.codegen_backend {
let aux_type = self.build_auxiliary(of, aux_file, aux_dir, false);
let aux_type = self.build_auxiliary(of, aux_file, aux_dir, None);
if let Some(lib_name) = get_lib_name(aux_file.trim_end_matches(".rs"), aux_type) {
let lib_path = aux_dir.join(&lib_name);
rustc.arg(format!("-Zcodegen-backend={}", lib_path.display()));
Expand Down Expand Up @@ -1209,17 +1228,23 @@ impl<'test> TestCx<'test> {
}

/// Builds an aux dependency.
///
/// If `aux_type` is `None`, then this will determine the aux-type automatically.
fn build_auxiliary(
&self,
of: &TestPaths,
source_path: &str,
aux_dir: &Path,
is_bin: bool,
aux_type: Option<AuxType>,
) -> AuxType {
let aux_testpaths = self.compute_aux_test_paths(of, source_path);
let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config);
let mut aux_props =
self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config);
if aux_type == Some(AuxType::ProcMacro) {
aux_props.force_host = true;
}
let mut aux_dir = aux_dir.to_path_buf();
if is_bin {
if aux_type == Some(AuxType::Bin) {
// On unix, the binary of `auxiliary/foo.rs` will be named
// `auxiliary/foo` which clashes with the _dir_ `auxiliary/foo`, so
// put bins in a `bin` subfolder.
Expand Down Expand Up @@ -1250,8 +1275,12 @@ impl<'test> TestCx<'test> {
aux_rustc.env_remove(key);
}

let (aux_type, crate_type) = if is_bin {
let (aux_type, crate_type) = if aux_type == Some(AuxType::Bin) {
(AuxType::Bin, Some("bin"))
} else if aux_type == Some(AuxType::ProcMacro) {
(AuxType::ProcMacro, Some("proc-macro"))
} else if aux_type.is_some() {
panic!("aux_type {aux_type:?} not expected");
} else if aux_props.no_prefer_dynamic {
(AuxType::Dylib, None)
} else if self.config.target.contains("emscripten")
Expand Down Expand Up @@ -1287,6 +1316,11 @@ impl<'test> TestCx<'test> {
aux_rustc.args(&["--crate-type", crate_type]);
}

if aux_type == AuxType::ProcMacro {
// For convenience, but this only works on 2018.
aux_rustc.args(&["--extern", "proc_macro"]);
}

aux_rustc.arg("-L").arg(&aux_dir);

let auxres = aux_cx.compose_and_run(
Expand Down Expand Up @@ -2768,8 +2802,10 @@ enum LinkToAux {
No,
}

#[derive(Debug, PartialEq)]
enum AuxType {
Bin,
Lib,
Dylib,
ProcMacro,
}

0 comments on commit f592dd9

Please sign in to comment.