1//! Everything needed to build auxilary files with rustc
2// lol we can't name this file `aux.rs` on windows
3
4use crate::{
5 build_manager::{Build, BuildManager},
6 custom_flags::Flag,
7 default_per_file_config, display,
8 per_test_config::{Comments, TestConfig},
9 status_emitter::SilentStatus,
10 CrateType, Error, Errored,
11};
12use bstr::ByteSlice;
13use spanned::Spanned;
14use std::{ffi::OsString, path::PathBuf, process::Command, sync::Arc};
15
16impl Flag for AuxBuilder {
17 fn must_be_unique(&self) -> bool {
18 false
19 }
20 fn clone_inner(&self) -> Box<dyn Flag> {
21 Box::new(self.clone())
22 }
23 fn apply(
24 &self,
25 cmd: &mut Command,
26 config: &TestConfig,
27 build_manager: &BuildManager,
28 ) -> Result<(), Errored> {
29 let aux = &self.aux_file;
30 let aux_dir = config.aux_dir.clone();
31 let aux_file = if aux.starts_with("..") {
32 aux_dir.parent().unwrap().join(&aux.content)
33 } else {
34 aux_dir.join(&aux.content)
35 };
36 let extra_args = build_manager
37 .build(
38 AuxBuilder {
39 aux_file: Spanned::new(
40 crate::core::strip_path_prefix(
41 &aux_file.canonicalize().map_err(|err| Errored {
42 command: format!("canonicalizing path `{}`", display(&aux_file)),
43 errors: vec![],
44 stderr: err.to_string().into_bytes(),
45 stdout: vec![],
46 })?,
47 &std::env::current_dir().unwrap(),
48 )
49 .collect(),
50 aux.span(),
51 ),
52 },
53 &config.status,
54 )
55 .map_err(
56 |Errored {
57 command,
58 errors,
59 stderr,
60 stdout,
61 }| Errored {
62 command,
63 errors: vec![Error::Aux {
64 path: Spanned::new(aux_file.to_path_buf(), aux.span()),
65 errors,
66 }],
67 stderr,
68 stdout,
69 },
70 )?;
71 cmd.args(extra_args);
72 Ok(())
73 }
74}
75
76/// Build an aux-build.
77/// Custom `//@aux-build` flag handler.
78#[derive(Clone, Debug)]
79pub struct AuxBuilder {
80 /// Full path to the file (including `auxiliary` folder prefix)
81 pub aux_file: Spanned<PathBuf>,
82}
83
84impl Build for AuxBuilder {
85 fn build(&self, build_manager: &BuildManager) -> Result<Vec<OsString>, Errored> {
86 let mut config = build_manager.config().clone();
87 let file_contents =
88 Spanned::read_from_file(&self.aux_file.content).map_err(|err| Errored {
89 command: format!("reading aux file `{}`", display(&self.aux_file)),
90 errors: vec![],
91 stderr: err.to_string().into_bytes(),
92 stdout: vec![],
93 })?;
94 let comments = Comments::parse(file_contents.as_ref(), &config)
95 .map_err(|errors| Errored::new(errors, "parse aux comments"))?;
96 assert_eq!(
97 comments.revisions, None,
98 "aux builds cannot specify revisions"
99 );
100
101 default_per_file_config(&mut config, &file_contents);
102
103 match CrateType::from_file_contents(&file_contents) {
104 // Proc macros must be run on the host
105 CrateType::ProcMacro => config.target.clone_from(&config.host),
106 CrateType::Test | CrateType::Bin | CrateType::Lib => {}
107 }
108
109 let mut config = TestConfig {
110 config,
111 comments: Arc::new(comments),
112 aux_dir: self.aux_file.parent().unwrap().to_owned(),
113 status: Box::new(SilentStatus {
114 revision: String::new(),
115 path: self.aux_file.content.clone(),
116 }),
117 };
118
119 config.patch_out_dir();
120
121 let mut aux_cmd = config.build_command(build_manager)?;
122
123 aux_cmd.arg("--emit=link");
124 let filename = self.aux_file.file_stem().unwrap().to_str().unwrap();
125 let output = config.config.run_command(&mut aux_cmd)?;
126 if !output.status.success() {
127 let error = Error::Command {
128 kind: "compilation of aux build failed".to_string(),
129 status: output.status,
130 };
131 return Err(Errored {
132 command: format!("{aux_cmd:?}"),
133 errors: vec![error],
134 stderr: config.process(&output.stderr).rendered,
135 stdout: output.stdout,
136 });
137 }
138
139 // Now run the command again to fetch the output filenames
140 aux_cmd.arg("--print").arg("file-names");
141 let output = config.config.run_command(&mut aux_cmd)?;
142
143 assert!(output.status.success());
144
145 let mut extra_args = vec![];
146 for file in output.stdout.lines() {
147 let file = std::str::from_utf8(file).unwrap();
148 let crate_name = filename.replace('-', "_");
149 let path = config.config.out_dir.join(file);
150 extra_args.push("--extern".into());
151 let mut cname = OsString::from(&crate_name);
152 cname.push("=");
153 cname.push(path);
154 extra_args.push(cname);
155 // Help cargo find the crates added with `--extern`.
156 extra_args.push("-L".into());
157 extra_args.push(config.config.out_dir.as_os_str().to_os_string());
158 }
159 Ok(extra_args)
160 }
161
162 fn description(&self) -> String {
163 format!("Building aux file {}", display(&self.aux_file))
164 }
165}
166

Provided by KDAB

Privacy Policy
Learn Rust with the experts
Find out more