blob: 67a7221a17d12e3c0408ebc246d9c50999e9d517 [file] [log] [blame] [edit]
//! Everything needed to build auxilary files with rustc
// lol we can't name this file `aux.rs` on windows
use bstr::ByteSlice;
use spanned::Spanned;
use std::{ffi::OsString, path::PathBuf, process::Command, sync::Arc};
use crate::{
build_manager::{Build, BuildManager},
custom_flags::Flag,
default_per_file_config, display,
per_test_config::{Comments, TestConfig},
status_emitter::SilentStatus,
CrateType, Error, Errored,
};
impl Flag for AuxBuilder {
fn must_be_unique(&self) -> bool {
false
}
fn clone_inner(&self) -> Box<dyn Flag> {
Box::new(self.clone())
}
fn apply(
&self,
cmd: &mut Command,
config: &TestConfig,
build_manager: &BuildManager,
) -> Result<(), Errored> {
let aux = &self.aux_file;
let aux_dir = config.aux_dir.clone();
let aux_file = if aux.starts_with("..") {
aux_dir.parent().unwrap().join(&aux.content)
} else {
aux_dir.join(&aux.content)
};
let extra_args = build_manager
.build(
AuxBuilder {
aux_file: Spanned::new(
crate::core::strip_path_prefix(
&aux_file.canonicalize().map_err(|err| Errored {
command: format!("canonicalizing path `{}`", display(&aux_file)),
errors: vec![],
stderr: err.to_string().into_bytes(),
stdout: vec![],
})?,
&std::env::current_dir().unwrap(),
)
.collect(),
aux.span(),
),
},
&config.status,
)
.map_err(
|Errored {
command,
errors,
stderr,
stdout,
}| Errored {
command,
errors: vec![Error::Aux {
path: Spanned::new(aux_file.to_path_buf(), aux.span()),
errors,
}],
stderr,
stdout,
},
)?;
cmd.args(extra_args);
Ok(())
}
}
/// Build an aux-build.
/// Custom `//@aux-build` flag handler.
#[derive(Clone, Debug)]
pub struct AuxBuilder {
/// Full path to the file (including `auxiliary` folder prefix)
pub aux_file: Spanned<PathBuf>,
}
impl Build for AuxBuilder {
fn build(&self, build_manager: &BuildManager) -> Result<Vec<OsString>, Errored> {
let mut config = build_manager.config().clone();
let file_contents =
Spanned::read_from_file(&self.aux_file.content).map_err(|err| Errored {
command: format!("reading aux file `{}`", display(&self.aux_file)),
errors: vec![],
stderr: err.to_string().into_bytes(),
stdout: vec![],
})?;
let comments = Comments::parse(file_contents.as_ref(), &config)
.map_err(|errors| Errored::new(errors, "parse aux comments"))?;
assert_eq!(
comments.revisions, None,
"aux builds cannot specify revisions"
);
default_per_file_config(&mut config, &file_contents);
match CrateType::from_file_contents(&file_contents) {
// Proc macros must be run on the host
CrateType::ProcMacro => config.target.clone_from(&config.host),
CrateType::Test | CrateType::Bin | CrateType::Lib => {}
}
let mut config = TestConfig {
config,
comments: Arc::new(comments),
aux_dir: self.aux_file.parent().unwrap().to_owned(),
status: Box::new(SilentStatus {
revision: String::new(),
path: self.aux_file.content.clone(),
}),
};
config.patch_out_dir();
let mut aux_cmd = config.build_command(build_manager)?;
aux_cmd.arg("--emit=link");
let filename = self.aux_file.file_stem().unwrap().to_str().unwrap();
let output = aux_cmd.output().unwrap();
if !output.status.success() {
let error = Error::Command {
kind: "compilation of aux build failed".to_string(),
status: output.status,
};
return Err(Errored {
command: format!("{aux_cmd:?}"),
errors: vec![error],
stderr: config.process(&output.stderr).rendered,
stdout: output.stdout,
});
}
// Now run the command again to fetch the output filenames
aux_cmd.arg("--print").arg("file-names");
let output = aux_cmd.output().unwrap();
if build_manager.aborted() {
return Err(Errored::aborted());
}
assert!(output.status.success());
let mut extra_args = vec![];
for file in output.stdout.lines() {
let file = std::str::from_utf8(file).unwrap();
let crate_name = filename.replace('-', "_");
let path = config.config.out_dir.join(file);
extra_args.push("--extern".into());
let mut cname = OsString::from(&crate_name);
cname.push("=");
cname.push(path);
extra_args.push(cname);
// Help cargo find the crates added with `--extern`.
extra_args.push("-L".into());
extra_args.push(config.config.out_dir.as_os_str().to_os_string());
}
Ok(extra_args)
}
fn description(&self) -> String {
format!("Building aux file {}", display(&self.aux_file))
}
}