Skip to content

Commit

Permalink
Rollup merge of rust-lang#99844 - bjorn3:archive_builder_interface_re…
Browse files Browse the repository at this point in the history
…factor, r=nagisa

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. I'm going to use this in rust-lang#97485 to allow passing in the right function to extract symbols from object files to a generic archive builder to be used by cg_llvm, cg_clif and cg_gcc.
  • Loading branch information
Dylan-DPC authored Jul 31, 2022
2 parents 2c14bc3 + 7c6c7e8 commit 1d010d4
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 197 deletions.
72 changes: 36 additions & 36 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,9 +17,34 @@ 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,
dst: PathBuf,
use_gnu_style_archive: bool,
no_builtin_ranlib: bool,

Expand All @@ -30,30 +55,18 @@ pub(crate) struct ArArchiveBuilder<'a> {
}

impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
fn new(sess: &'a Session, output: &Path) -> 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,

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 @@ -74,7 +87,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
Ok(())
}

fn build(mut self) -> bool {
fn build(mut self: Box<Self>, output: &Path) -> bool {
enum BuilderKind {
Bsd(ar::Builder<File>),
Gnu(ar::GnuBuilder<File>),
Expand Down Expand Up @@ -163,7 +176,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
Expand All @@ -178,7 +191,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
Expand Down Expand Up @@ -209,7 +222,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");

Expand All @@ -220,17 +233,4 @@ 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,
_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
76 changes: 37 additions & 39 deletions compiler/rustc_codegen_gcc/src/archive.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
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;

struct ArchiveConfig<'a> {
sess: &'a Session,
dst: PathBuf,
use_native_ar: bool,
use_gnu_style_archive: bool,
}
Expand All @@ -22,42 +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, output: &Path) -> Self {
impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> {
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",
};

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 @@ -77,7 +90,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
Ok(())
}

fn build(mut self) -> bool {
fn build(mut self: Box<Self>, output: &Path) -> bool {
use std::process::Command;

fn add_file_using_ar(archive: &Path, file: &Path) {
Expand All @@ -97,17 +110,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();
Expand Down Expand Up @@ -164,28 +177,13 @@ 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()));
}

any_members
}

fn sess(&self) -> &Session {
self.config.sess
}

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
35 changes: 17 additions & 18 deletions compiler/rustc_codegen_llvm/src/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@ 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;

/// Helper for adding many files to an archive.
#[must_use = "must call build() to finish building the archive"]
pub struct LlvmArchiveBuilder<'a> {
sess: &'a Session,
dst: PathBuf,
additions: Vec<Addition>,
}

Expand Down Expand Up @@ -54,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, output: &Path) -> LlvmArchiveBuilder<'a> {
LlvmArchiveBuilder { sess, dst: output.to_path_buf(), 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 @@ -88,18 +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) -> bool {
match self.build_with_llvm() {
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;

fn sess(&self) -> &Session {
self.sess
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 Expand Up @@ -241,7 +240,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
}

impl<'a> LlvmArchiveBuilder<'a> {
fn build_with_llvm(&mut self) -> io::Result<bool> {
fn build_with_llvm(&mut self, output: &Path) -> io::Result<bool> {
let kind = &*self.sess.target.archive_format;
let kind = kind.parse::<ArchiveKind>().map_err(|_| kind).unwrap_or_else(|kind| {
self.sess.fatal(&format!("Don't know how to build archive of type: {}", kind))
Expand All @@ -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 {
Expand Down
Loading

0 comments on commit 1d010d4

Please sign in to comment.