about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbjorn3 <17426603+bjorn3@users.noreply.github.com>2022-07-28 09:07:49 +0000
committerbjorn3 <17426603+bjorn3@users.noreply.github.com>2022-07-28 09:08:47 +0000
commit7c6c7e8785fa553baf43ea82382a97ec01466b9b (patch)
tree5db0200867b436e0a450e3ba31fdbd6eb36a24c0
parent90da3c6f2b4db9bde02138830de1ea14982b1512 (diff)
downloadrust-7c6c7e8785fa553baf43ea82382a97ec01466b9b.tar.gz
rust-7c6c7e8785fa553baf43ea82382a97ec01466b9b.zip
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.
-rw-r--r--compiler/rustc_codegen_cranelift/src/archive.rs60
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/archive.rs58
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs28
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs25
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs174
8 files changed, 210 insertions, 144 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<dyn ArchiveBuilder<'a> + '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<F>(&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<dyn FnMut(&str) -> 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<Self>, output: &Path) -> bool {
         enum BuilderKind {
             Bsd(ar::Builder<File>),
             Gnu(ar::GnuBuilder<File>),
@@ -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::<crate::archive::ArArchiveBuilder<'_>>(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,16 +21,10 @@ enum ArchiveEntry {
     File(PathBuf),
 }
 
-pub struct ArArchiveBuilder<'a> {
-    config: ArchiveConfig<'a>,
-    src_archives: Vec<(PathBuf, ar::Archive<File>)>,
-    // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
-    // the end of an archive for linkers to not get confused.
-    entries: Vec<(String, ArchiveEntry)>,
-}
+pub struct ArArchiveBuilderBuilder;
 
-impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
-    fn new(sess: &'a Session) -> Self {
+impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
+    fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> {
         let config = ArchiveConfig {
             sess,
             use_native_ar: false,
@@ -38,13 +32,33 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
             use_gnu_style_archive: sess.target.options.archive_format == "gnu",
         };
 
-        ArArchiveBuilder {
+        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<File>)>,
+    // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
+    // the end of an archive for linkers to not get confused.
+    entries: Vec<(String, ArchiveEntry)>,
+}
+
+impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
     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<F>(&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<dyn FnMut(&str) -> 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<Self>, 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::<crate::archive::ArArchiveBuilder<'_>>(
+        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<F>(&mut self, archive: &Path, skip: F) -> io::Result<()>
-    where
-        F: FnMut(&str) -> bool + 'static,
-    {
+    fn add_archive(
+        &mut self,
+        archive: &Path,
+        skip: Box<dyn FnMut(&str) -> 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<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)),
         }
     }
+}
+
+pub struct LlvmArchiveBuilderBuilder;
+
+impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
+    fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + '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::<LlvmArchiveBuilder<'_>>(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<F>(&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<dyn ArchiveBuilder<'a> + 'a>;
 
     /// Creates a DLL Import Library <https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-creation#creating-an-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<dyn FnMut(&str) -> bool + 'static>,
+    ) -> io::Result<()>;
+
+    fn build(self: Box<Self>, 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::<B>(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::<B>(sess, codegen_results, &out_filename, &path)?;
+                    link_staticlib(
+                        sess,
+                        archive_builder_builder,
+                        codegen_results,
+                        &out_filename,
+                        &path,
+                    )?;
                 }
                 _ => {
-                    link_natively::<B>(
+                    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<B, ErrorGuaranteed> {
+) -> Result<Box<dyn ArchiveBuilder<'a> + 'a>, ErrorGuaranteed> {
     let lib_search_paths = archive_search_paths(sess);
 
-    let mut ab = <B as ArchiveBuilder>::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::<B>(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::<B>(
+    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::<B>(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::<B>(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::<B>(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::<B>(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 = <B as ArchiveBuilder>::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) {