diff --git a/Cargo.lock b/Cargo.lock index aeddf35eb0d..a7b8447ef35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2802,6 +2802,7 @@ dependencies = [ "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_borrowck 0.0.0", + "rustc_codegen_ssa 0.0.0", "rustc_codegen_utils 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -2821,6 +2822,7 @@ dependencies = [ "syntax 0.0.0", "syntax_ext 0.0.0", "syntax_pos 0.0.0", + "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index f8061844105..f25891d77ce 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -7,7 +7,7 @@ use rustc::session::config::{ }; use rustc::session::search_paths::PathKind; use rustc::middle::dependency_format::Linkage; -use rustc::middle::cstore::{LibSource, NativeLibrary, NativeLibraryKind}; +use rustc::middle::cstore::{EncodedMetadata, LibSource, NativeLibrary, NativeLibraryKind}; use rustc::util::common::{time, time_ext}; use rustc::hir::def_id::CrateNum; use rustc_data_structures::fx::FxHashSet; @@ -50,9 +50,9 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, outputs: &OutputFilenames, crate_name: &str, target_cpu: &str) { + let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); for &crate_type in sess.crate_types.borrow().iter() { // Ignore executable crates if we have -Z no-codegen, as they will error. - let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) && !output_metadata && crate_type == config::CrateType::Executable { @@ -68,29 +68,6 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, check_file_is_writeable(obj, sess); } - if outputs.outputs.contains_key(&OutputType::Metadata) { - let out_filename = filename_for_metadata(sess, crate_name, outputs); - // To avoid races with another rustc process scanning the output directory, - // we need to write the file somewhere else and atomically move it to its - // final destination, with a `fs::rename` call. In order for the rename to - // always succeed, the temporary file needs to be on the same filesystem, - // which is why we create it inside the output directory specifically. - let metadata_tmpdir = TempFileBuilder::new() - .prefix("rmeta") - .tempdir_in(out_filename.parent().unwrap()) - .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err))); - let metadata = emit_metadata(sess, codegen_results, &metadata_tmpdir); - match fs::rename(&metadata, &out_filename) { - Ok(_) => { - if sess.opts.debugging_opts.emit_directives { - sess.parse_sess.span_diagnostic.maybe_emit_json_directive( - format!("metadata file written: {}", out_filename.display())); - } - } - Err(e) => sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)), - } - } - let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err))); @@ -248,13 +225,13 @@ pub fn each_linked_rlib(sess: &Session, /// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a /// directory being searched for `extern crate` (observing an incomplete file). /// The returned path is the temporary file containing the complete metadata. -fn emit_metadata<'a>( +pub fn emit_metadata<'a>( sess: &'a Session, - codegen_results: &CodegenResults, + metadata: &EncodedMetadata, tmpdir: &TempDir ) -> PathBuf { let out_filename = tmpdir.path().join(METADATA_FILENAME); - let result = fs::write(&out_filename, &codegen_results.metadata.raw_data); + let result = fs::write(&out_filename, &metadata.raw_data); if let Err(e) = result { sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); @@ -338,7 +315,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, RlibFlavor::Normal => { // Instead of putting the metadata in an object file section, rlibs // contain the metadata in a separate file. - ab.add_file(&emit_metadata(sess, codegen_results, tmpdir)); + ab.add_file(&emit_metadata(sess, &codegen_results.metadata, tmpdir)); // For LTO purposes, the bytecode of this library is also inserted // into the archive. diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index fa2a5d2fc89..bcaa4216109 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -24,6 +24,7 @@ rustc_borrowck = { path = "../librustc_borrowck" } rustc_incremental = { path = "../librustc_incremental" } rustc_traits = { path = "../librustc_traits" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_metadata = { path = "../librustc_metadata" } rustc_mir = { path = "../librustc_mir" } @@ -34,3 +35,4 @@ rustc_errors = { path = "../librustc_errors" } rustc_plugin = { path = "../librustc_plugin" } rustc_privacy = { path = "../librustc_privacy" } rustc_resolve = { path = "../librustc_resolve" } +tempfile = "3.0.5" diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 38d641d2f60..6d3115c6213 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -20,7 +20,9 @@ use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType use rustc::session::search_paths::PathKind; use rustc_allocator as allocator; use rustc_borrowck as borrowck; +use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_codegen_utils::link::filename_for_metadata; use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::StableHasher; @@ -50,6 +52,7 @@ use syntax_pos::{FileName, hygiene}; use syntax_ext; use serialize::json; +use tempfile::Builder as TempFileBuilder; use std::any::Any; use std::env; @@ -999,7 +1002,10 @@ fn analysis<'tcx>( Ok(()) } -fn encode_metadata<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> (middle::cstore::EncodedMetadata, bool) { +fn encode_and_write_metadata<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + outputs: &OutputFilenames, +) -> (middle::cstore::EncodedMetadata, bool) { #[derive(PartialEq, Eq, PartialOrd, Ord)] enum MetadataKind { None, @@ -1020,14 +1026,41 @@ fn encode_metadata<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> (middle::cstore::Encode } }).max().unwrap_or(MetadataKind::None); - let need_metadata_module = metadata_kind == MetadataKind::Compressed; - let metadata = match metadata_kind { MetadataKind::None => middle::cstore::EncodedMetadata::new(), MetadataKind::Uncompressed | MetadataKind::Compressed => tcx.encode_metadata(), }; + let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata); + if need_metadata_file { + let crate_name = &tcx.crate_name(LOCAL_CRATE).as_str(); + let out_filename = filename_for_metadata(tcx.sess, crate_name, outputs); + // To avoid races with another rustc process scanning the output directory, + // we need to write the file somewhere else and atomically move it to its + // final destination, with an `fs::rename` call. In order for the rename to + // always succeed, the temporary file needs to be on the same filesystem, + // which is why we create it inside the output directory specifically. + let metadata_tmpdir = TempFileBuilder::new() + .prefix("rmeta") + .tempdir_in(out_filename.parent().unwrap()) + .unwrap_or_else(|err| { + tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)) + }); + let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir); + match std::fs::rename(&metadata_filename, &out_filename) { + Ok(_) => { + if tcx.sess.opts.debugging_opts.emit_directives { + tcx.sess.parse_sess.span_diagnostic.maybe_emit_json_directive( + format!("metadata file written: {}", out_filename.display())); + } + } + Err(e) => tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)), + } + } + + let need_metadata_module = metadata_kind == MetadataKind::Compressed; + (metadata, need_metadata_module) } @@ -1048,8 +1081,8 @@ pub fn start_codegen<'tcx>( middle::dependency_format::calculate(tcx) }); - let (metadata, need_metadata_module) = time(tcx.sess, "metadata encoding", || { - encode_metadata(tcx) + let (metadata, need_metadata_module) = time(tcx.sess, "metadata encoding and writing", || { + encode_and_write_metadata(tcx, outputs) }); tcx.sess.profiler(|p| p.start_activity("codegen crate"));