| 1 | //! Everything needed to build auxilary files with rustc | 
| 2 | // lol we can't name this file `aux.rs` on windows | 
|---|
| 3 |  | 
|---|
| 4 | use 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 | }; | 
|---|
| 12 | use bstr::ByteSlice; | 
|---|
| 13 | use spanned::Spanned; | 
|---|
| 14 | use std::{ffi::OsString, path::PathBuf, process::Command, sync::Arc}; | 
|---|
| 15 |  | 
|---|
| 16 | impl 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)] | 
|---|
| 79 | pub struct AuxBuilder { | 
|---|
| 80 | /// Full path to the file (including `auxiliary` folder prefix) | 
|---|
| 81 | pub aux_file: Spanned<PathBuf>, | 
|---|
| 82 | } | 
|---|
| 83 |  | 
|---|
| 84 | impl 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 |  | 
|---|