1
Fork 0

Rollup merge of #122634 - Enselic:aux-bin, r=oli-obk

compiletest: Add support for `//@ aux-bin: foo.rs`

Which enables ui tests to use auxiliary binaries. See the added
self-test for an example.

This is an enabler for the test in https://github.com/rust-lang/rust/pull/121573.
This commit is contained in:
Matthias Krüger 2024-03-19 18:03:50 +01:00 committed by GitHub
commit 42dec6f874
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 98 additions and 29 deletions

View file

@ -36,6 +36,7 @@ impl HeadersCache {
#[derive(Default)] #[derive(Default)]
pub struct EarlyProps { pub struct EarlyProps {
pub aux: Vec<String>, pub aux: Vec<String>,
pub aux_bin: Vec<String>,
pub aux_crate: Vec<(String, String)>, pub aux_crate: Vec<(String, String)>,
pub revisions: Vec<String>, pub revisions: Vec<String>,
} }
@ -59,6 +60,12 @@ impl EarlyProps {
config.push_name_value_directive(ln, directives::AUX_BUILD, &mut props.aux, |r| { config.push_name_value_directive(ln, directives::AUX_BUILD, &mut props.aux, |r| {
r.trim().to_string() r.trim().to_string()
}); });
config.push_name_value_directive(
ln,
directives::AUX_BIN,
&mut props.aux_bin,
|r| r.trim().to_string(),
);
config.push_name_value_directive( config.push_name_value_directive(
ln, ln,
directives::AUX_CRATE, directives::AUX_CRATE,
@ -95,6 +102,8 @@ pub struct TestProps {
// directory as the test, but for backwards compatibility reasons // directory as the test, but for backwards compatibility reasons
// we also check the auxiliary directory) // we also check the auxiliary directory)
pub aux_builds: Vec<String>, pub aux_builds: Vec<String>,
// Auxiliary crates that should be compiled as `#![crate_type = "bin"]`.
pub aux_bins: Vec<String>,
// Similar to `aux_builds`, but a list of NAME=somelib.rs of dependencies // Similar to `aux_builds`, but a list of NAME=somelib.rs of dependencies
// to build and pass with the `--extern` flag. // to build and pass with the `--extern` flag.
pub aux_crates: Vec<(String, String)>, pub aux_crates: Vec<(String, String)>,
@ -217,6 +226,7 @@ mod directives {
pub const PRETTY_EXPANDED: &'static str = "pretty-expanded"; pub const PRETTY_EXPANDED: &'static str = "pretty-expanded";
pub const PRETTY_MODE: &'static str = "pretty-mode"; pub const PRETTY_MODE: &'static str = "pretty-mode";
pub const PRETTY_COMPARE_ONLY: &'static str = "pretty-compare-only"; pub const PRETTY_COMPARE_ONLY: &'static str = "pretty-compare-only";
pub const AUX_BIN: &'static str = "aux-bin";
pub const AUX_BUILD: &'static str = "aux-build"; pub const AUX_BUILD: &'static str = "aux-build";
pub const AUX_CRATE: &'static str = "aux-crate"; pub const AUX_CRATE: &'static str = "aux-crate";
pub const EXEC_ENV: &'static str = "exec-env"; pub const EXEC_ENV: &'static str = "exec-env";
@ -252,6 +262,7 @@ impl TestProps {
run_flags: None, run_flags: None,
pp_exact: None, pp_exact: None,
aux_builds: vec![], aux_builds: vec![],
aux_bins: vec![],
aux_crates: vec![], aux_crates: vec![],
revisions: vec![], revisions: vec![],
rustc_env: vec![("RUSTC_ICE".to_string(), "0".to_string())], rustc_env: vec![("RUSTC_ICE".to_string(), "0".to_string())],
@ -417,6 +428,9 @@ impl TestProps {
config.push_name_value_directive(ln, AUX_BUILD, &mut self.aux_builds, |r| { config.push_name_value_directive(ln, AUX_BUILD, &mut self.aux_builds, |r| {
r.trim().to_string() r.trim().to_string()
}); });
config.push_name_value_directive(ln, AUX_BIN, &mut self.aux_bins, |r| {
r.trim().to_string()
});
config.push_name_value_directive( config.push_name_value_directive(
ln, ln,
AUX_CRATE, AUX_CRATE,
@ -683,6 +697,7 @@ pub fn line_directive<'line>(
const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
// tidy-alphabetical-start // tidy-alphabetical-start
"assembly-output", "assembly-output",
"aux-bin",
"aux-build", "aux-build",
"aux-crate", "aux-crate",
"build-aux-docs", "build-aux-docs",

View file

@ -82,21 +82,21 @@ fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
} }
/// The platform-specific library name /// The platform-specific library name
pub fn get_lib_name(lib: &str, dylib: bool) -> String { fn get_lib_name(lib: &str, aux_type: AuxType) -> Option<String> {
// In some casess (e.g. MUSL), we build a static match aux_type {
// library, rather than a dynamic library. AuxType::Bin => None,
// In this case, the only path we can pass // In some cases (e.g. MUSL), we build a static
// with '--extern-meta' is the '.lib' file // library, rather than a dynamic library.
if !dylib { // In this case, the only path we can pass
return format!("lib{}.rlib", lib); // with '--extern-meta' is the '.rlib' file
} AuxType::Lib => Some(format!("lib{}.rlib", lib)),
AuxType::Dylib => Some(if cfg!(windows) {
if cfg!(windows) { format!("{}.dll", lib)
format!("{}.dll", lib) } else if cfg!(target_os = "macos") {
} else if cfg!(target_os = "macos") { format!("lib{}.dylib", lib)
format!("lib{}.dylib", lib) } else {
} else { format!("lib{}.so", lib)
format!("lib{}.so", lib) }),
} }
} }
@ -2098,19 +2098,36 @@ impl<'test> TestCx<'test> {
create_dir_all(&aux_dir).unwrap(); create_dir_all(&aux_dir).unwrap();
} }
if !self.props.aux_bins.is_empty() {
let aux_bin_dir = self.aux_bin_output_dir_name();
let _ = fs::remove_dir_all(&aux_bin_dir);
create_dir_all(&aux_bin_dir).unwrap();
}
aux_dir aux_dir
} }
fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Command) { fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Command) {
for rel_ab in &self.props.aux_builds { for rel_ab in &self.props.aux_builds {
self.build_auxiliary(of, rel_ab, &aux_dir); self.build_auxiliary(of, rel_ab, &aux_dir, false /* is_bin */);
}
for rel_ab in &self.props.aux_bins {
self.build_auxiliary(of, rel_ab, &aux_dir, true /* is_bin */);
} }
for (aux_name, aux_path) in &self.props.aux_crates { for (aux_name, aux_path) in &self.props.aux_crates {
let is_dylib = self.build_auxiliary(of, &aux_path, &aux_dir); let aux_type = self.build_auxiliary(of, &aux_path, &aux_dir, false /* is_bin */);
let lib_name = let lib_name =
get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), is_dylib); get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), aux_type);
rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir.display(), lib_name)); if let Some(lib_name) = lib_name {
rustc.arg("--extern").arg(format!(
"{}={}/{}",
aux_name,
aux_dir.display(),
lib_name
));
}
} }
} }
@ -2129,12 +2146,23 @@ impl<'test> TestCx<'test> {
} }
/// Builds an aux dependency. /// Builds an aux dependency.
/// fn build_auxiliary(
/// Returns whether or not it is a dylib. &self,
fn build_auxiliary(&self, of: &TestPaths, source_path: &str, aux_dir: &Path) -> bool { of: &TestPaths,
source_path: &str,
aux_dir: &Path,
is_bin: bool,
) -> AuxType {
let aux_testpaths = self.compute_aux_test_paths(of, source_path); 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 aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config);
let aux_output = TargetLocation::ThisDirectory(aux_dir.to_path_buf()); let mut aux_dir = aux_dir.to_path_buf();
if is_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.
aux_dir.push("bin");
}
let aux_output = TargetLocation::ThisDirectory(aux_dir.clone());
let aux_cx = TestCx { let aux_cx = TestCx {
config: self.config, config: self.config,
props: &aux_props, props: &aux_props,
@ -2152,15 +2180,17 @@ impl<'test> TestCx<'test> {
LinkToAux::No, LinkToAux::No,
Vec::new(), Vec::new(),
); );
aux_cx.build_all_auxiliary(of, aux_dir, &mut aux_rustc); aux_cx.build_all_auxiliary(of, &aux_dir, &mut aux_rustc);
for key in &aux_props.unset_rustc_env { for key in &aux_props.unset_rustc_env {
aux_rustc.env_remove(key); aux_rustc.env_remove(key);
} }
aux_rustc.envs(aux_props.rustc_env.clone()); aux_rustc.envs(aux_props.rustc_env.clone());
let (dylib, crate_type) = if aux_props.no_prefer_dynamic { let (aux_type, crate_type) = if is_bin {
(true, None) (AuxType::Bin, Some("bin"))
} else if aux_props.no_prefer_dynamic {
(AuxType::Dylib, None)
} else if self.config.target.contains("emscripten") } else if self.config.target.contains("emscripten")
|| (self.config.target.contains("musl") || (self.config.target.contains("musl")
&& !aux_props.force_host && !aux_props.force_host
@ -2185,9 +2215,9 @@ impl<'test> TestCx<'test> {
// Coverage tests want static linking by default so that coverage // Coverage tests want static linking by default so that coverage
// mappings in auxiliary libraries can be merged into the final // mappings in auxiliary libraries can be merged into the final
// executable. // executable.
(false, Some("lib")) (AuxType::Lib, Some("lib"))
} else { } else {
(true, Some("dylib")) (AuxType::Dylib, Some("dylib"))
}; };
if let Some(crate_type) = crate_type { if let Some(crate_type) = crate_type {
@ -2211,7 +2241,7 @@ impl<'test> TestCx<'test> {
&auxres, &auxres,
); );
} }
dylib aux_type
} }
fn read2_abbreviated(&self, child: Child) -> (Output, Truncated) { fn read2_abbreviated(&self, child: Child) -> (Output, Truncated) {
@ -2677,6 +2707,12 @@ impl<'test> TestCx<'test> {
.with_extra_extension(self.config.mode.aux_dir_disambiguator()) .with_extra_extension(self.config.mode.aux_dir_disambiguator())
} }
/// Gets the directory where auxiliary binaries are written.
/// E.g., `/.../testname.revision.mode/auxiliary/bin`.
fn aux_bin_output_dir_name(&self) -> PathBuf {
self.aux_output_dir_name().join("bin")
}
/// Generates a unique name for the test, such as `testname.revision.mode`. /// Generates a unique name for the test, such as `testname.revision.mode`.
fn output_testname_unique(&self) -> PathBuf { fn output_testname_unique(&self) -> PathBuf {
output_testname_unique(self.config, self.testpaths, self.safe_revision()) output_testname_unique(self.config, self.testpaths, self.safe_revision())
@ -4826,3 +4862,9 @@ enum LinkToAux {
Yes, Yes,
No, No,
} }
enum AuxType {
Bin,
Lib,
Dylib,
}

View file

@ -0,0 +1,3 @@
fn main() {
println!("it works");
}

View file

@ -0,0 +1,9 @@
//@ ignore-cross-compile because we run the compiled code
//@ aux-bin: print-it-works.rs
//@ run-pass
fn main() {
let stdout =
std::process::Command::new("auxiliary/bin/print-it-works").output().unwrap().stdout;
assert_eq!(stdout, b"it works\n");
}