From 7c93154a30a640b8120c5aca68bffb886dcd02e6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 28 Jul 2022 08:39:19 +0000 Subject: [PATCH 1/3] Move output argument from ArchiveBuilder::new to .build() --- .../rustc_codegen_cranelift/src/archive.rs | 12 ++++----- compiler/rustc_codegen_gcc/src/archive.rs | 18 +++++-------- .../rustc_codegen_llvm/src/back/archive.rs | 13 +++++----- .../rustc_codegen_ssa/src/back/archive.rs | 4 +-- compiler/rustc_codegen_ssa/src/back/link.rs | 26 +++++++------------ 5 files changed, 29 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index c92c1051139..9d39b4aa661 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -19,7 +19,6 @@ enum ArchiveEntry { pub(crate) struct ArArchiveBuilder<'a> { sess: &'a Session, - dst: PathBuf, use_gnu_style_archive: bool, no_builtin_ranlib: bool, @@ -30,10 +29,9 @@ pub(crate) struct ArArchiveBuilder<'a> { } impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { - fn new(sess: &'a Session, output: &Path) -> Self { + fn new(sess: &'a Session) -> Self { ArArchiveBuilder { sess, - dst: output.to_path_buf(), use_gnu_style_archive: sess.target.archive_format == "gnu", // FIXME fix builtin ranlib on macOS no_builtin_ranlib: sess.target.is_like_osx, @@ -74,7 +72,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { Ok(()) } - fn build(mut self) -> bool { + fn build(mut self, output: &Path) -> bool { enum BuilderKind { Bsd(ar::Builder), Gnu(ar::GnuBuilder), @@ -163,7 +161,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { let mut builder = if self.use_gnu_style_archive { BuilderKind::Gnu( ar::GnuBuilder::new( - File::create(&self.dst).unwrap_or_else(|err| { + File::create(output).unwrap_or_else(|err| { sess.fatal(&format!( "error opening destination during archive building: {}", err @@ -178,7 +176,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { } else { BuilderKind::Bsd( ar::Builder::new( - File::create(&self.dst).unwrap_or_else(|err| { + File::create(output).unwrap_or_else(|err| { sess.fatal(&format!( "error opening destination during archive building: {}", err @@ -209,7 +207,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { // Run ranlib to be able to link the archive let status = std::process::Command::new(ranlib) - .arg(self.dst) + .arg(output) .status() .expect("Couldn't run ranlib"); diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index 21f62a6b009..a8e94ad4b8d 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -8,7 +8,6 @@ use rustc_session::cstore::DllImport; struct ArchiveConfig<'a> { sess: &'a Session, - dst: PathBuf, use_native_ar: bool, use_gnu_style_archive: bool, } @@ -31,10 +30,9 @@ pub struct ArArchiveBuilder<'a> { } impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { - fn new(sess: &'a Session, output: &Path) -> Self { + fn new(sess: &'a Session) -> Self { let config = ArchiveConfig { sess, - dst: output.to_path_buf(), use_native_ar: false, // FIXME test for linux and System V derivatives instead use_gnu_style_archive: sess.target.options.archive_format == "gnu", @@ -77,7 +75,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { Ok(()) } - fn build(mut self) -> bool { + fn build(mut self, output: &Path) -> bool { use std::process::Command; fn add_file_using_ar(archive: &Path, file: &Path) { @@ -97,17 +95,17 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { } let mut builder = if self.config.use_native_ar { - BuilderKind::NativeAr(&self.config.dst) + BuilderKind::NativeAr(output) } else if self.config.use_gnu_style_archive { BuilderKind::Gnu(ar::GnuBuilder::new( - File::create(&self.config.dst).unwrap(), + File::create(output).unwrap(), self.entries .iter() .map(|(name, _)| name.as_bytes().to_vec()) .collect(), )) } else { - BuilderKind::Bsd(ar::Builder::new(File::create(&self.config.dst).unwrap())) + BuilderKind::Bsd(ar::Builder::new(File::create(output).unwrap())) }; let any_members = !self.entries.is_empty(); @@ -164,10 +162,8 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { std::mem::drop(builder); // Run ranlib to be able to link the archive - let status = std::process::Command::new("ranlib") - .arg(self.config.dst) - .status() - .expect("Couldn't run ranlib"); + let status = + std::process::Command::new("ranlib").arg(output).status().expect("Couldn't run ranlib"); if !status.success() { self.config.sess.fatal(&format!("Ranlib exited with code {:?}", status.code())); diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index baa858709a0..8d6e3673271 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -18,7 +18,6 @@ use rustc_session::Session; #[must_use = "must call build() to finish building the archive"] pub struct LlvmArchiveBuilder<'a> { sess: &'a Session, - dst: PathBuf, additions: Vec, } @@ -56,8 +55,8 @@ fn llvm_machine_type(cpu: &str) -> LLVMMachineType { impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { /// Creates a new static archive, ready for modifying the archive specified /// by `config`. - fn new(sess: &'a Session, output: &Path) -> LlvmArchiveBuilder<'a> { - LlvmArchiveBuilder { sess, dst: output.to_path_buf(), additions: Vec::new() } + fn new(sess: &'a Session) -> LlvmArchiveBuilder<'a> { + LlvmArchiveBuilder { sess, additions: Vec::new() } } fn add_archive(&mut self, archive: &Path, skip: F) -> io::Result<()> @@ -88,8 +87,8 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { /// Combine the provided files, rlibs, and native libraries into a single /// `Archive`. - fn build(mut self) -> bool { - match self.build_with_llvm() { + fn build(mut self, output: &Path) -> bool { + match self.build_with_llvm(output) { Ok(any_members) => any_members, Err(e) => self.sess.fatal(&format!("failed to build archive: {}", e)), } @@ -241,7 +240,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { } impl<'a> LlvmArchiveBuilder<'a> { - fn build_with_llvm(&mut self) -> io::Result { + fn build_with_llvm(&mut self, output: &Path) -> io::Result { let kind = &*self.sess.target.archive_format; let kind = kind.parse::().map_err(|_| kind).unwrap_or_else(|kind| { self.sess.fatal(&format!("Don't know how to build archive of type: {}", kind)) @@ -251,7 +250,7 @@ impl<'a> LlvmArchiveBuilder<'a> { let mut strings = Vec::new(); let mut members = Vec::new(); - let dst = CString::new(self.dst.to_str().unwrap())?; + let dst = CString::new(output.to_str().unwrap())?; unsafe { for addition in &mut additions { diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 53550b049db..d511c340802 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -41,7 +41,7 @@ pub(super) fn find_library( } pub trait ArchiveBuilder<'a> { - fn new(sess: &'a Session, output: &Path) -> Self; + fn new(sess: &'a Session) -> Self; fn add_file(&mut self, path: &Path); @@ -49,7 +49,7 @@ pub trait ArchiveBuilder<'a> { where F: FnMut(&str) -> bool + 'static; - fn build(self) -> bool; + fn build(self, output: &Path) -> bool; fn sess(&self) -> &Session; diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index f0d320c7c21..b1d4012474a 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -101,14 +101,9 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( match crate_type { CrateType::Rlib => { let _timer = sess.timer("link_rlib"); - link_rlib::( - sess, - codegen_results, - RlibFlavor::Normal, - &out_filename, - &path, - )? - .build(); + info!("preparing rlib to {:?}", out_filename); + link_rlib::(sess, codegen_results, RlibFlavor::Normal, &path)? + .build(&out_filename); } CrateType::Staticlib => { link_staticlib::(sess, codegen_results, &out_filename, &path)?; @@ -249,14 +244,11 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( sess: &'a Session, codegen_results: &CodegenResults, flavor: RlibFlavor, - out_filename: &Path, tmpdir: &MaybeTempDir, ) -> Result { - info!("preparing rlib to {:?}", out_filename); - let lib_search_paths = archive_search_paths(sess); - let mut ab = ::new(sess, out_filename); + let mut ab = ::new(sess); let trailing_metadata = match flavor { RlibFlavor::Normal => { @@ -451,8 +443,8 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( out_filename: &Path, tempdir: &MaybeTempDir, ) -> Result<(), ErrorGuaranteed> { - let mut ab = - link_rlib::(sess, codegen_results, RlibFlavor::StaticlibBase, out_filename, tempdir)?; + info!("preparing staticlib to {:?}", out_filename); + let mut ab = link_rlib::(sess, codegen_results, RlibFlavor::StaticlibBase, tempdir)?; let mut all_native_libs = vec![]; let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| { @@ -514,7 +506,7 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( sess.fatal(&e); } - ab.build(); + ab.build(out_filename); if !all_native_libs.is_empty() { if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) { @@ -2479,7 +2471,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( let is_builtins = sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum); - let mut archive = ::new(sess, &dst); + let mut archive = ::new(sess); if let Err(e) = archive.add_archive(cratepath, move |f| { if f == METADATA_FILENAME { return true; @@ -2510,7 +2502,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( }) { sess.fatal(&format!("failed to build archive from rlib: {}", e)); } - if archive.build() { + if archive.build(&dst) { link_upstream(&dst); } }); From 90da3c6f2b4db9bde02138830de1ea14982b1512 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 28 Jul 2022 08:43:15 +0000 Subject: [PATCH 2/3] Inline inject_dll_import_lib --- .../rustc_codegen_cranelift/src/archive.rs | 4 ---- compiler/rustc_codegen_gcc/src/archive.rs | 4 ---- .../rustc_codegen_llvm/src/back/archive.rs | 4 ---- .../rustc_codegen_ssa/src/back/archive.rs | 23 ------------------- compiler/rustc_codegen_ssa/src/back/link.rs | 7 +++++- 5 files changed, 6 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index 9d39b4aa661..e28c3813d3f 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -219,10 +219,6 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { any_members } - fn sess(&self) -> &Session { - self.sess - } - fn create_dll_import_lib( _sess: &Session, _lib_name: &str, diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index a8e94ad4b8d..f7745951d28 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -172,10 +172,6 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { any_members } - fn sess(&self) -> &Session { - self.config.sess - } - fn create_dll_import_lib( _sess: &Session, _lib_name: &str, diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 8d6e3673271..21a1e3a3b82 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -94,10 +94,6 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { } } - fn sess(&self) -> &Session { - self.sess - } - fn create_dll_import_lib( sess: &Session, lib_name: &str, diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index d511c340802..4b55085d720 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -1,4 +1,3 @@ -use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_session::cstore::DllImport; use rustc_session::Session; @@ -51,8 +50,6 @@ pub trait ArchiveBuilder<'a> { fn build(self, output: &Path) -> bool; - fn sess(&self) -> &Session; - /// Creates a DLL Import Library . /// and returns the path on disk to that import library. /// This functions doesn't take `self` so that it can be called from @@ -64,24 +61,4 @@ pub trait ArchiveBuilder<'a> { dll_imports: &[DllImport], tmpdir: &Path, ) -> PathBuf; - - /// Creates a DLL Import Library - /// and adds it to the current compilation's set of archives. - fn inject_dll_import_lib( - &mut self, - lib_name: &str, - dll_imports: &[DllImport], - tmpdir: &MaybeTempDir, - ) { - let output_path = - Self::create_dll_import_lib(self.sess(), lib_name, dll_imports, tmpdir.as_ref()); - - self.add_archive(&output_path, |_| false).unwrap_or_else(|e| { - self.sess().fatal(&format!( - "failed to add native library {}: {}", - output_path.display(), - e - )); - }); - } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index b1d4012474a..b9ad7c94773 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -346,7 +346,12 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( for (raw_dylib_name, raw_dylib_imports) in collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)? { - ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir); + let output_path = + B::create_dll_import_lib(sess, &raw_dylib_name, &raw_dylib_imports, tmpdir.as_ref()); + + ab.add_archive(&output_path, |_| false).unwrap_or_else(|e| { + sess.fatal(&format!("failed to add native library {}: {}", output_path.display(), e)); + }); } if let Some(trailing_metadata) = trailing_metadata { From 7c6c7e8785fa553baf43ea82382a97ec01466b9b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 28 Jul 2022 09:07:49 +0000 Subject: [PATCH 3/3] Introduce an ArchiveBuilderBuilder This avoids monomorphizing all linker code for each codegen backend and will allow passing in extra information to the archive builder from the codegen backend. --- .../rustc_codegen_cranelift/src/archive.rs | 60 +++--- compiler/rustc_codegen_cranelift/src/lib.rs | 2 +- compiler/rustc_codegen_gcc/src/archive.rs | 66 ++++--- compiler/rustc_codegen_gcc/src/lib.rs | 3 +- .../rustc_codegen_llvm/src/back/archive.rs | 28 +-- compiler/rustc_codegen_llvm/src/lib.rs | 4 +- .../rustc_codegen_ssa/src/back/archive.rs | 25 ++- compiler/rustc_codegen_ssa/src/back/link.rs | 174 +++++++++++------- 8 files changed, 214 insertions(+), 148 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index e28c3813d3f..b4c79096170 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -5,7 +5,7 @@ use std::fs::File; use std::io::{self, Read, Seek}; use std::path::{Path, PathBuf}; -use rustc_codegen_ssa::back::archive::ArchiveBuilder; +use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; use rustc_session::Session; use object::read::archive::ArchiveFile; @@ -17,6 +17,32 @@ enum ArchiveEntry { File(PathBuf), } +pub(crate) struct ArArchiveBuilderBuilder; + +impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { + fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box + 'a> { + Box::new(ArArchiveBuilder { + sess, + use_gnu_style_archive: sess.target.archive_format == "gnu", + // FIXME fix builtin ranlib on macOS + no_builtin_ranlib: sess.target.is_like_osx, + + src_archives: vec![], + entries: vec![], + }) + } + + fn create_dll_import_lib( + &self, + _sess: &Session, + _lib_name: &str, + _dll_imports: &[rustc_session::cstore::DllImport], + _tmpdir: &Path, + ) -> PathBuf { + bug!("creating dll imports is not supported"); + } +} + pub(crate) struct ArArchiveBuilder<'a> { sess: &'a Session, use_gnu_style_archive: bool, @@ -29,18 +55,6 @@ pub(crate) struct ArArchiveBuilder<'a> { } impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { - fn new(sess: &'a Session) -> Self { - ArArchiveBuilder { - sess, - use_gnu_style_archive: sess.target.archive_format == "gnu", - // FIXME fix builtin ranlib on macOS - no_builtin_ranlib: sess.target.is_like_osx, - - src_archives: vec![], - entries: vec![], - } - } - fn add_file(&mut self, file: &Path) { self.entries.push(( file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(), @@ -48,10 +62,11 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { )); } - fn add_archive(&mut self, archive_path: &Path, mut skip: F) -> std::io::Result<()> - where - F: FnMut(&str) -> bool + 'static, - { + fn add_archive( + &mut self, + archive_path: &Path, + mut skip: Box bool + 'static>, + ) -> std::io::Result<()> { let read_cache = ReadCache::new(std::fs::File::open(&archive_path)?); let archive = ArchiveFile::parse(&read_cache).unwrap(); let archive_index = self.src_archives.len(); @@ -72,7 +87,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { Ok(()) } - fn build(mut self, output: &Path) -> bool { + fn build(mut self: Box, output: &Path) -> bool { enum BuilderKind { Bsd(ar::Builder), Gnu(ar::GnuBuilder), @@ -218,13 +233,4 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { any_members } - - fn create_dll_import_lib( - _sess: &Session, - _lib_name: &str, - _dll_imports: &[rustc_session::cstore::DllImport], - _tmpdir: &Path, - ) -> PathBuf { - bug!("creating dll imports is not supported"); - } } diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 568bb20a3f4..bb0793b1deb 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -226,7 +226,7 @@ impl CodegenBackend for CraneliftCodegenBackend { ) -> Result<(), ErrorGuaranteed> { use rustc_codegen_ssa::back::link::link_binary; - link_binary::>(sess, &codegen_results, outputs) + link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs) } } diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index f7745951d28..f863abdcc97 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -1,7 +1,7 @@ use std::fs::File; use std::path::{Path, PathBuf}; -use rustc_codegen_ssa::back::archive::ArchiveBuilder; +use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; use rustc_session::Session; use rustc_session::cstore::DllImport; @@ -21,6 +21,35 @@ enum ArchiveEntry { File(PathBuf), } +pub struct ArArchiveBuilderBuilder; + +impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { + fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box + 'a> { + let config = ArchiveConfig { + sess, + use_native_ar: false, + // FIXME test for linux and System V derivatives instead + use_gnu_style_archive: sess.target.options.archive_format == "gnu", + }; + + Box::new(ArArchiveBuilder { + config, + src_archives: vec![], + entries: vec![], + }) + } + + fn create_dll_import_lib( + &self, + _sess: &Session, + _lib_name: &str, + _dll_imports: &[DllImport], + _tmpdir: &Path, + ) -> PathBuf { + unimplemented!(); + } +} + pub struct ArArchiveBuilder<'a> { config: ArchiveConfig<'a>, src_archives: Vec<(PathBuf, ar::Archive)>, @@ -30,21 +59,6 @@ pub struct ArArchiveBuilder<'a> { } impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { - fn new(sess: &'a Session) -> Self { - let config = ArchiveConfig { - sess, - use_native_ar: false, - // FIXME test for linux and System V derivatives instead - use_gnu_style_archive: sess.target.options.archive_format == "gnu", - }; - - ArArchiveBuilder { - config, - src_archives: vec![], - entries: vec![], - } - } - fn add_file(&mut self, file: &Path) { self.entries.push(( file.file_name().unwrap().to_str().unwrap().to_string(), @@ -52,10 +66,11 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { )); } - fn add_archive(&mut self, archive_path: &Path, mut skip: F) -> std::io::Result<()> - where - F: FnMut(&str) -> bool + 'static, - { + fn add_archive( + &mut self, + archive_path: &Path, + mut skip: Box bool + 'static>, + ) -> std::io::Result<()> { let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?); let archive_index = self.src_archives.len(); @@ -75,7 +90,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { Ok(()) } - fn build(mut self, output: &Path) -> bool { + fn build(mut self: Box, output: &Path) -> bool { use std::process::Command; fn add_file_using_ar(archive: &Path, file: &Path) { @@ -171,13 +186,4 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { any_members } - - fn create_dll_import_lib( - _sess: &Session, - _lib_name: &str, - _dll_imports: &[DllImport], - _tmpdir: &Path, - ) -> PathBuf { - unimplemented!(); - } } diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index c21e0c5a35b..8a206c0368f 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -133,8 +133,9 @@ impl CodegenBackend for GccCodegenBackend { fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) -> Result<(), ErrorGuaranteed> { use rustc_codegen_ssa::back::link::link_binary; - link_binary::>( + link_binary( sess, + &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs, ) diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 21a1e3a3b82..27039cda253 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -10,7 +10,7 @@ use std::str; use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; -use rustc_codegen_ssa::back::archive::ArchiveBuilder; +use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; use rustc_session::cstore::{DllCallingConvention, DllImport}; use rustc_session::Session; @@ -53,16 +53,11 @@ fn llvm_machine_type(cpu: &str) -> LLVMMachineType { } impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { - /// Creates a new static archive, ready for modifying the archive specified - /// by `config`. - fn new(sess: &'a Session) -> LlvmArchiveBuilder<'a> { - LlvmArchiveBuilder { sess, additions: Vec::new() } - } - - fn add_archive(&mut self, archive: &Path, skip: F) -> io::Result<()> - where - F: FnMut(&str) -> bool + 'static, - { + fn add_archive( + &mut self, + archive: &Path, + skip: Box bool + 'static>, + ) -> io::Result<()> { let archive_ro = match ArchiveRO::open(archive) { Ok(ar) => ar, Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), @@ -87,14 +82,23 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { /// Combine the provided files, rlibs, and native libraries into a single /// `Archive`. - fn build(mut self, output: &Path) -> bool { + fn build(mut self: Box, output: &Path) -> bool { match self.build_with_llvm(output) { Ok(any_members) => any_members, Err(e) => self.sess.fatal(&format!("failed to build archive: {}", e)), } } +} + +pub struct LlvmArchiveBuilderBuilder; + +impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { + fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box + 'a> { + Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() }) + } fn create_dll_import_lib( + &self, sess: &Session, lib_name: &str, dll_imports: &[DllImport], diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 25ce1cef944..eeb1ed61f28 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -370,12 +370,12 @@ impl CodegenBackend for LlvmCodegenBackend { codegen_results: CodegenResults, outputs: &OutputFilenames, ) -> Result<(), ErrorGuaranteed> { - use crate::back::archive::LlvmArchiveBuilder; + use crate::back::archive::LlvmArchiveBuilderBuilder; use rustc_codegen_ssa::back::link::link_binary; // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - link_binary::>(sess, &codegen_results, outputs) + link_binary(sess, &LlvmArchiveBuilderBuilder, &codegen_results, outputs) } } diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 4b55085d720..0d2aa483d3d 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -39,16 +39,8 @@ pub(super) fn find_library( )); } -pub trait ArchiveBuilder<'a> { - fn new(sess: &'a Session) -> Self; - - fn add_file(&mut self, path: &Path); - - fn add_archive(&mut self, archive: &Path, skip: F) -> io::Result<()> - where - F: FnMut(&str) -> bool + 'static; - - fn build(self, output: &Path) -> bool; +pub trait ArchiveBuilderBuilder { + fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box + 'a>; /// Creates a DLL Import Library . /// and returns the path on disk to that import library. @@ -56,9 +48,22 @@ pub trait ArchiveBuilder<'a> { /// `linker_with_args`, which is specialized on `ArchiveBuilder` but /// doesn't take or create an instance of that type. fn create_dll_import_lib( + &self, sess: &Session, lib_name: &str, dll_imports: &[DllImport], tmpdir: &Path, ) -> PathBuf; } + +pub trait ArchiveBuilder<'a> { + fn add_file(&mut self, path: &Path); + + fn add_archive( + &mut self, + archive: &Path, + skip: Box bool + 'static>, + ) -> io::Result<()>; + + fn build(self: Box, output: &Path) -> bool; +} diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index b9ad7c94773..7e6a5f0366a 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -24,7 +24,7 @@ use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback}; use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo}; use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target}; -use super::archive::{find_library, ArchiveBuilder}; +use super::archive::{find_library, ArchiveBuilder, ArchiveBuilderBuilder}; use super::command::Command; use super::linker::{self, Linker}; use super::metadata::{create_rmeta_file, MetadataPosition}; @@ -56,8 +56,9 @@ pub fn ensure_removed(diag_handler: &Handler, path: &Path) { /// Performs the linkage portion of the compilation phase. This will generate all /// of the requested outputs for this compilation session. -pub fn link_binary<'a, B: ArchiveBuilder<'a>>( +pub fn link_binary<'a>( sess: &'a Session, + archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, outputs: &OutputFilenames, ) -> Result<(), ErrorGuaranteed> { @@ -102,15 +103,28 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( CrateType::Rlib => { let _timer = sess.timer("link_rlib"); info!("preparing rlib to {:?}", out_filename); - link_rlib::(sess, codegen_results, RlibFlavor::Normal, &path)? - .build(&out_filename); + link_rlib( + sess, + archive_builder_builder, + codegen_results, + RlibFlavor::Normal, + &path, + )? + .build(&out_filename); } CrateType::Staticlib => { - link_staticlib::(sess, codegen_results, &out_filename, &path)?; + link_staticlib( + sess, + archive_builder_builder, + codegen_results, + &out_filename, + &path, + )?; } _ => { - link_natively::( + link_natively( sess, + archive_builder_builder, crate_type, &out_filename, codegen_results, @@ -240,15 +254,16 @@ pub fn each_linked_rlib( /// the object file of the crate, but it also contains all of the object files from native /// libraries. This is done by unzipping native libraries and inserting all of the contents into /// this archive. -fn link_rlib<'a, B: ArchiveBuilder<'a>>( +fn link_rlib<'a>( sess: &'a Session, + archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, flavor: RlibFlavor, tmpdir: &MaybeTempDir, -) -> Result { +) -> Result + 'a>, ErrorGuaranteed> { let lib_search_paths = archive_search_paths(sess); - let mut ab = ::new(sess); + let mut ab = archive_builder_builder.new_archive_builder(sess); let trailing_metadata = match flavor { RlibFlavor::Normal => { @@ -333,7 +348,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( if let Some(name) = lib.name { let location = find_library(name.as_str(), lib.verbatim.unwrap_or(false), &lib_search_paths, sess); - ab.add_archive(&location, |_| false).unwrap_or_else(|e| { + ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|e| { sess.fatal(&format!( "failed to add native library {}: {}", location.to_string_lossy(), @@ -346,10 +361,14 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( for (raw_dylib_name, raw_dylib_imports) in collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)? { - let output_path = - B::create_dll_import_lib(sess, &raw_dylib_name, &raw_dylib_imports, tmpdir.as_ref()); + let output_path = archive_builder_builder.create_dll_import_lib( + sess, + &raw_dylib_name, + &raw_dylib_imports, + tmpdir.as_ref(), + ); - ab.add_archive(&output_path, |_| false).unwrap_or_else(|e| { + ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|e| { sess.fatal(&format!("failed to add native library {}: {}", output_path.display(), e)); }); } @@ -442,14 +461,21 @@ fn collate_raw_dylibs( /// /// There's no need to include metadata in a static archive, so ensure to not link in the metadata /// object file (and also don't prepare the archive with a metadata file). -fn link_staticlib<'a, B: ArchiveBuilder<'a>>( +fn link_staticlib<'a>( sess: &'a Session, + archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, out_filename: &Path, tempdir: &MaybeTempDir, ) -> Result<(), ErrorGuaranteed> { info!("preparing staticlib to {:?}", out_filename); - let mut ab = link_rlib::(sess, codegen_results, RlibFlavor::StaticlibBase, tempdir)?; + let mut ab = link_rlib( + sess, + archive_builder_builder, + codegen_results, + RlibFlavor::StaticlibBase, + tempdir, + )?; let mut all_native_libs = vec![]; let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| { @@ -483,26 +509,29 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( // might be also an extra name suffix let obj_start = name.as_str().to_owned(); - ab.add_archive(path, move |fname: &str| { - // Ignore metadata files, no matter the name. - if fname == METADATA_FILENAME { - return true; - } + ab.add_archive( + path, + Box::new(move |fname: &str| { + // Ignore metadata files, no matter the name. + if fname == METADATA_FILENAME { + return true; + } - // Don't include Rust objects if LTO is enabled - if lto && looks_like_rust_object_file(fname) { - return true; - } + // Don't include Rust objects if LTO is enabled + if lto && looks_like_rust_object_file(fname) { + return true; + } - // Otherwise if this is *not* a rust object and we're skipping - // objects then skip this file - if skip_object_files && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) { - return true; - } + // Otherwise if this is *not* a rust object and we're skipping + // objects then skip this file + if skip_object_files && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) { + return true; + } - // ok, don't skip this - false - }) + // ok, don't skip this + false + }), + ) .unwrap(); all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned()); @@ -641,8 +670,9 @@ fn link_dwarf_object<'a>( /// /// This will invoke the system linker/cc to create the resulting file. This links to all upstream /// files as well. -fn link_natively<'a, B: ArchiveBuilder<'a>>( +fn link_natively<'a>( sess: &'a Session, + archive_builder_builder: &dyn ArchiveBuilderBuilder, crate_type: CrateType, out_filename: &Path, codegen_results: &CodegenResults, @@ -650,10 +680,11 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( ) -> Result<(), ErrorGuaranteed> { info!("preparing {:?} to {:?}", crate_type, out_filename); let (linker_path, flavor) = linker_and_flavor(sess); - let mut cmd = linker_with_args::( + let mut cmd = linker_with_args( &linker_path, flavor, sess, + archive_builder_builder, crate_type, tmpdir, out_filename, @@ -1839,10 +1870,11 @@ fn add_rpath_args( /// to the linking process as a whole. /// Order-independent options may still override each other in order-dependent fashion, /// e.g `--foo=yes --foo=no` may be equivalent to `--foo=no`. -fn linker_with_args<'a, B: ArchiveBuilder<'a>>( +fn linker_with_args<'a>( path: &Path, flavor: LinkerFlavor, sess: &'a Session, + archive_builder_builder: &dyn ArchiveBuilderBuilder, crate_type: CrateType, tmpdir: &Path, out_filename: &Path, @@ -1943,7 +1975,14 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( } // Upstream rust libraries and their non-bundled static libraries - add_upstream_rust_crates::(cmd, sess, codegen_results, crate_type, tmpdir); + add_upstream_rust_crates( + cmd, + sess, + archive_builder_builder, + codegen_results, + crate_type, + tmpdir, + ); // Upstream dynamic native libraries linked with `#[link]` attributes at and `-l` // command line options. @@ -1958,7 +1997,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( for (raw_dylib_name, raw_dylib_imports) in collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)? { - cmd.add_object(&B::create_dll_import_lib( + cmd.add_object(&archive_builder_builder.create_dll_import_lib( sess, &raw_dylib_name, &raw_dylib_imports, @@ -2248,9 +2287,10 @@ fn add_local_native_libraries( /// /// Rust crates are not considered at all when creating an rlib output. All dependencies will be /// linked when producing the final output (instead of the intermediate rlib version). -fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( +fn add_upstream_rust_crates<'a>( cmd: &mut dyn Linker, sess: &'a Session, + archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, crate_type: CrateType, tmpdir: &Path, @@ -2339,7 +2379,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( let src = &codegen_results.crate_info.used_crate_source[&cnum]; match data[cnum.as_usize() - 1] { _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => { - add_static_crate::(cmd, sess, codegen_results, tmpdir, cnum); + add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum); } // compiler-builtins are always placed last to ensure that they're // linked correctly. @@ -2349,7 +2389,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( } Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { - add_static_crate::(cmd, sess, codegen_results, tmpdir, cnum); + add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum); // Link static native libs with "-bundle" modifier only if the crate they originate from // is being linked statically to the current crate. If it's linked dynamically @@ -2408,7 +2448,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( // was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic` // is used) if let Some(cnum) = compiler_builtins { - add_static_crate::(cmd, sess, codegen_results, tmpdir, cnum); + add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum); } // Converts a library file-stem into a cc -l argument @@ -2434,9 +2474,10 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( // Note, however, that if we're not doing LTO we can just pass the rlib // blindly to the linker (fast) because it's fine if it's not actually // included as we're at the end of the dependency chain. - fn add_static_crate<'a, B: ArchiveBuilder<'a>>( + fn add_static_crate<'a>( cmd: &mut dyn Linker, sess: &'a Session, + archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, tmpdir: &Path, cnum: CrateNum, @@ -2476,35 +2517,38 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( let is_builtins = sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum); - let mut archive = ::new(sess); - if let Err(e) = archive.add_archive(cratepath, move |f| { - if f == METADATA_FILENAME { - return true; - } + let mut archive = archive_builder_builder.new_archive_builder(sess); + if let Err(e) = archive.add_archive( + cratepath, + Box::new(move |f| { + if f == METADATA_FILENAME { + return true; + } - let canonical = f.replace('-', "_"); + let canonical = f.replace('-', "_"); - let is_rust_object = - canonical.starts_with(&canonical_name) && looks_like_rust_object_file(&f); + let is_rust_object = + canonical.starts_with(&canonical_name) && looks_like_rust_object_file(&f); - // If we've been requested to skip all native object files - // (those not generated by the rust compiler) then we can skip - // this file. See above for why we may want to do this. - let skip_because_cfg_say_so = skip_native && !is_rust_object; + // If we've been requested to skip all native object files + // (those not generated by the rust compiler) then we can skip + // this file. See above for why we may want to do this. + let skip_because_cfg_say_so = skip_native && !is_rust_object; - // If we're performing LTO and this is a rust-generated object - // file, then we don't need the object file as it's part of the - // LTO module. Note that `#![no_builtins]` is excluded from LTO, - // though, so we let that object file slide. - let skip_because_lto = - upstream_rust_objects_already_included && is_rust_object && is_builtins; + // If we're performing LTO and this is a rust-generated object + // file, then we don't need the object file as it's part of the + // LTO module. Note that `#![no_builtins]` is excluded from LTO, + // though, so we let that object file slide. + let skip_because_lto = + upstream_rust_objects_already_included && is_rust_object && is_builtins; - if skip_because_cfg_say_so || skip_because_lto { - return true; - } + if skip_because_cfg_say_so || skip_because_lto { + return true; + } - false - }) { + false + }), + ) { sess.fatal(&format!("failed to build archive from rlib: {}", e)); } if archive.build(&dst) {