|
1 | 1 | //! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a
|
2 | 2 | //! standalone executable.
|
3 | 3 |
|
4 |
| -use std::fs::File; |
5 |
| -use std::path::PathBuf; |
| 4 | +use std::fs::{self, File}; |
| 5 | +use std::path::{Path, PathBuf}; |
6 | 6 | use std::sync::Arc;
|
7 | 7 | use std::thread::JoinHandle;
|
8 | 8 |
|
9 | 9 | use cranelift_object::{ObjectBuilder, ObjectModule};
|
10 | 10 | use rustc_codegen_ssa::assert_module_sources::CguReuse;
|
| 11 | +use rustc_codegen_ssa::back::link::ensure_removed; |
11 | 12 | use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file;
|
12 | 13 | use rustc_codegen_ssa::base::determine_cgu_reuse;
|
| 14 | +use rustc_codegen_ssa::errors as ssa_errors; |
13 | 15 | use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
|
14 | 16 | use rustc_data_structures::profiling::SelfProfilerRef;
|
15 | 17 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
| 18 | +use rustc_metadata::fs::copy_to_stdout; |
16 | 19 | use rustc_metadata::EncodedMetadata;
|
17 | 20 | use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
18 | 21 | use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
|
19 |
| -use rustc_session::config::{DebugInfo, OutputFilenames, OutputType}; |
| 22 | +use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType}; |
20 | 23 | use rustc_session::Session;
|
21 | 24 |
|
22 | 25 | use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken};
|
@@ -53,6 +56,7 @@ impl OngoingCodegen {
|
53 | 56 | pub(crate) fn join(
|
54 | 57 | self,
|
55 | 58 | sess: &Session,
|
| 59 | + outputs: &OutputFilenames, |
56 | 60 | backend_config: &BackendConfig,
|
57 | 61 | ) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
58 | 62 | let mut work_products = FxIndexMap::default();
|
@@ -110,17 +114,183 @@ impl OngoingCodegen {
|
110 | 114 |
|
111 | 115 | sess.dcx().abort_if_errors();
|
112 | 116 |
|
113 |
| - ( |
114 |
| - CodegenResults { |
115 |
| - modules, |
116 |
| - allocator_module: self.allocator_module, |
117 |
| - metadata_module: self.metadata_module, |
118 |
| - metadata: self.metadata, |
119 |
| - crate_info: self.crate_info, |
120 |
| - }, |
121 |
| - work_products, |
122 |
| - ) |
| 117 | + let codegen_results = CodegenResults { |
| 118 | + modules, |
| 119 | + allocator_module: self.allocator_module, |
| 120 | + metadata_module: self.metadata_module, |
| 121 | + metadata: self.metadata, |
| 122 | + crate_info: self.crate_info, |
| 123 | + }; |
| 124 | + |
| 125 | + produce_final_output_artifacts(sess, &codegen_results, outputs); |
| 126 | + |
| 127 | + (codegen_results, work_products) |
| 128 | + } |
| 129 | +} |
| 130 | + |
| 131 | +// Adapted from https://github.com/rust-lang/rust/blob/73476d49904751f8d90ce904e16dfbc278083d2c/compiler/rustc_codegen_ssa/src/back/write.rs#L547C1-L706C2 |
| 132 | +fn produce_final_output_artifacts( |
| 133 | + sess: &Session, |
| 134 | + codegen_results: &CodegenResults, |
| 135 | + crate_output: &OutputFilenames, |
| 136 | +) { |
| 137 | + let user_wants_bitcode = false; |
| 138 | + let mut user_wants_objects = false; |
| 139 | + |
| 140 | + // Produce final compile outputs. |
| 141 | + let copy_gracefully = |from: &Path, to: &OutFileName| match to { |
| 142 | + OutFileName::Stdout => { |
| 143 | + if let Err(e) = copy_to_stdout(from) { |
| 144 | + sess.dcx().emit_err(ssa_errors::CopyPath::new(from, to.as_path(), e)); |
| 145 | + } |
| 146 | + } |
| 147 | + OutFileName::Real(path) => { |
| 148 | + if let Err(e) = fs::copy(from, path) { |
| 149 | + sess.dcx().emit_err(ssa_errors::CopyPath::new(from, path, e)); |
| 150 | + } |
| 151 | + } |
| 152 | + }; |
| 153 | + |
| 154 | + let copy_if_one_unit = |output_type: OutputType, keep_numbered: bool| { |
| 155 | + if codegen_results.modules.len() == 1 { |
| 156 | + // 1) Only one codegen unit. In this case it's no difficulty |
| 157 | + // to copy `foo.0.x` to `foo.x`. |
| 158 | + let module_name = Some(&codegen_results.modules[0].name[..]); |
| 159 | + let path = crate_output.temp_path(output_type, module_name); |
| 160 | + let output = crate_output.path(output_type); |
| 161 | + if !output_type.is_text_output() && output.is_tty() { |
| 162 | + sess.dcx() |
| 163 | + .emit_err(ssa_errors::BinaryOutputToTty { shorthand: output_type.shorthand() }); |
| 164 | + } else { |
| 165 | + copy_gracefully(&path, &output); |
| 166 | + } |
| 167 | + if !sess.opts.cg.save_temps && !keep_numbered { |
| 168 | + // The user just wants `foo.x`, not `foo.#module-name#.x`. |
| 169 | + ensure_removed(sess.dcx(), &path); |
| 170 | + } |
| 171 | + } else { |
| 172 | + let extension = crate_output |
| 173 | + .temp_path(output_type, None) |
| 174 | + .extension() |
| 175 | + .unwrap() |
| 176 | + .to_str() |
| 177 | + .unwrap() |
| 178 | + .to_owned(); |
| 179 | + |
| 180 | + if crate_output.outputs.contains_explicit_name(&output_type) { |
| 181 | + // 2) Multiple codegen units, with `--emit foo=some_name`. We have |
| 182 | + // no good solution for this case, so warn the user. |
| 183 | + sess.dcx().emit_warn(ssa_errors::IgnoringEmitPath { extension }); |
| 184 | + } else if crate_output.single_output_file.is_some() { |
| 185 | + // 3) Multiple codegen units, with `-o some_name`. We have |
| 186 | + // no good solution for this case, so warn the user. |
| 187 | + sess.dcx().emit_warn(ssa_errors::IgnoringOutput { extension }); |
| 188 | + } else { |
| 189 | + // 4) Multiple codegen units, but no explicit name. We |
| 190 | + // just leave the `foo.0.x` files in place. |
| 191 | + // (We don't have to do any work in this case.) |
| 192 | + } |
| 193 | + } |
| 194 | + }; |
| 195 | + |
| 196 | + // Flag to indicate whether the user explicitly requested bitcode. |
| 197 | + // Otherwise, we produced it only as a temporary output, and will need |
| 198 | + // to get rid of it. |
| 199 | + for output_type in crate_output.outputs.keys() { |
| 200 | + match *output_type { |
| 201 | + OutputType::Bitcode => { |
| 202 | + // Cranelift doesn't have bitcode |
| 203 | + // user_wants_bitcode = true; |
| 204 | + // // Copy to .bc, but always keep the .0.bc. There is a later |
| 205 | + // // check to figure out if we should delete .0.bc files, or keep |
| 206 | + // // them for making an rlib. |
| 207 | + // copy_if_one_unit(OutputType::Bitcode, true); |
| 208 | + } |
| 209 | + OutputType::LlvmAssembly => { |
| 210 | + // Cranelift IR text already emitted during codegen |
| 211 | + // copy_if_one_unit(OutputType::LlvmAssembly, false); |
| 212 | + } |
| 213 | + OutputType::Assembly => { |
| 214 | + // Currently no support for emitting raw assembly files |
| 215 | + // copy_if_one_unit(OutputType::Assembly, false); |
| 216 | + } |
| 217 | + OutputType::Object => { |
| 218 | + user_wants_objects = true; |
| 219 | + copy_if_one_unit(OutputType::Object, true); |
| 220 | + } |
| 221 | + OutputType::Mir | OutputType::Metadata | OutputType::Exe | OutputType::DepInfo => {} |
| 222 | + } |
| 223 | + } |
| 224 | + |
| 225 | + // Clean up unwanted temporary files. |
| 226 | + |
| 227 | + // We create the following files by default: |
| 228 | + // - #crate#.#module-name#.bc |
| 229 | + // - #crate#.#module-name#.o |
| 230 | + // - #crate#.crate.metadata.bc |
| 231 | + // - #crate#.crate.metadata.o |
| 232 | + // - #crate#.o (linked from crate.##.o) |
| 233 | + // - #crate#.bc (copied from crate.##.bc) |
| 234 | + // We may create additional files if requested by the user (through |
| 235 | + // `-C save-temps` or `--emit=` flags). |
| 236 | + |
| 237 | + if !sess.opts.cg.save_temps { |
| 238 | + // Remove the temporary .#module-name#.o objects. If the user didn't |
| 239 | + // explicitly request bitcode (with --emit=bc), and the bitcode is not |
| 240 | + // needed for building an rlib, then we must remove .#module-name#.bc as |
| 241 | + // well. |
| 242 | + |
| 243 | + // Specific rules for keeping .#module-name#.bc: |
| 244 | + // - If the user requested bitcode (`user_wants_bitcode`), and |
| 245 | + // codegen_units > 1, then keep it. |
| 246 | + // - If the user requested bitcode but codegen_units == 1, then we |
| 247 | + // can toss .#module-name#.bc because we copied it to .bc earlier. |
| 248 | + // - If we're not building an rlib and the user didn't request |
| 249 | + // bitcode, then delete .#module-name#.bc. |
| 250 | + // If you change how this works, also update back::link::link_rlib, |
| 251 | + // where .#module-name#.bc files are (maybe) deleted after making an |
| 252 | + // rlib. |
| 253 | + let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe); |
| 254 | + |
| 255 | + let keep_numbered_bitcode = user_wants_bitcode && sess.codegen_units().as_usize() > 1; |
| 256 | + |
| 257 | + let keep_numbered_objects = |
| 258 | + needs_crate_object || (user_wants_objects && sess.codegen_units().as_usize() > 1); |
| 259 | + |
| 260 | + for module in codegen_results.modules.iter() { |
| 261 | + if let Some(ref path) = module.object { |
| 262 | + if !keep_numbered_objects { |
| 263 | + ensure_removed(sess.dcx(), path); |
| 264 | + } |
| 265 | + } |
| 266 | + |
| 267 | + if let Some(ref path) = module.dwarf_object { |
| 268 | + if !keep_numbered_objects { |
| 269 | + ensure_removed(sess.dcx(), path); |
| 270 | + } |
| 271 | + } |
| 272 | + |
| 273 | + if let Some(ref path) = module.bytecode { |
| 274 | + if !keep_numbered_bitcode { |
| 275 | + ensure_removed(sess.dcx(), path); |
| 276 | + } |
| 277 | + } |
| 278 | + } |
| 279 | + |
| 280 | + if !user_wants_bitcode { |
| 281 | + if let Some(ref allocator_module) = codegen_results.allocator_module { |
| 282 | + if let Some(ref path) = allocator_module.bytecode { |
| 283 | + ensure_removed(sess.dcx(), path); |
| 284 | + } |
| 285 | + } |
| 286 | + } |
123 | 287 | }
|
| 288 | + |
| 289 | + // We leave the following files around by default: |
| 290 | + // - #crate#.o |
| 291 | + // - #crate#.crate.metadata.o |
| 292 | + // - #crate#.bc |
| 293 | + // These are used in linking steps and will be cleaned up afterward. |
124 | 294 | }
|
125 | 295 |
|
126 | 296 | fn make_module(sess: &Session, backend_config: &BackendConfig, name: String) -> ObjectModule {
|
|
0 commit comments