Skip to content

Commit

Permalink
Introduce an ArchiveBuilderBuilder
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bjorn3 committed Jul 28, 2022
1 parent 90da3c6 commit 7c6c7e8
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 144 deletions.
60 changes: 33 additions & 27 deletions compiler/rustc_codegen_cranelift/src/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -29,29 +55,18 @@ 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(),
ArchiveEntry::File(file.to_owned()),
));
}

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();
Expand All @@ -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>),
Expand Down Expand Up @@ -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");
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
58 changes: 32 additions & 26 deletions compiler/rustc_codegen_gcc/src/archive.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -21,41 +21,56 @@ 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,
// FIXME test for linux and System V derivatives instead
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(),
ArchiveEntry::File(file.to_owned()),
));
}

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();

Expand All @@ -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) {
Expand Down Expand Up @@ -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!();
}
}
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_gcc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Expand Down
28 changes: 16 additions & 12 deletions compiler/rustc_codegen_llvm/src/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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)),
Expand All @@ -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],
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
25 changes: 15 additions & 10 deletions compiler/rustc_codegen_ssa/src/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,31 @@ 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.
/// This functions doesn't take `self` so that it can be called from
/// `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;
}
Loading

0 comments on commit 7c6c7e8

Please sign in to comment.