Skip to content

Commit

Permalink
Auto merge of #98098 - bjorn3:archive_refactor, r=michaelwoerister
Browse files Browse the repository at this point in the history
Remove the source archive functionality of ArchiveWriter

We now build archives through strictly additive means rather than taking an existing archive and potentially substracting parts. This is simpler and makes it easier to swap out the archive writer in #97485.
  • Loading branch information
bors committed Jun 21, 2022
2 parents 72fd41a + 7643f82 commit dc80ca7
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 193 deletions.
43 changes: 8 additions & 35 deletions compiler/rustc_codegen_cranelift/src/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,50 +30,19 @@ pub(crate) struct ArArchiveBuilder<'a> {
}

impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
let (src_archives, entries) = if let Some(input) = input {
let read_cache = ReadCache::new(File::open(input).unwrap());
let archive = ArchiveFile::parse(&read_cache).unwrap();
let mut entries = Vec::new();

for entry in archive.members() {
let entry = entry.unwrap();
entries.push((
entry.name().to_vec(),
ArchiveEntry::FromArchive { archive_index: 0, file_range: entry.file_range() },
));
}

(vec![read_cache.into_inner()], entries)
} else {
(vec![], Vec::new())
};

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,
entries,
src_archives: vec![],
entries: vec![],
}
}

fn src_files(&mut self) -> Vec<String> {
self.entries.iter().map(|(name, _)| String::from_utf8(name.clone()).unwrap()).collect()
}

fn remove_file(&mut self, name: &str) {
let index = self
.entries
.iter()
.position(|(entry_name, _)| entry_name == name.as_bytes())
.expect("Tried to remove file not existing in src archive");
self.entries.remove(index);
}

fn add_file(&mut self, file: &Path) {
self.entries.push((
file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(),
Expand Down Expand Up @@ -105,7 +74,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
Ok(())
}

fn build(mut self) {
fn build(mut self) -> bool {
enum BuilderKind {
Bsd(ar::Builder<File>),
Gnu(ar::GnuBuilder<File>),
Expand Down Expand Up @@ -204,6 +173,8 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
)
};

let any_members = !entries.is_empty();

// Add all files
for (entry_name, data) in entries.into_iter() {
let header = ar::Header::new(entry_name, data.len() as u64);
Expand All @@ -229,6 +200,8 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
self.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
}
}

any_members
}

fn inject_dll_import_lib(
Expand Down
47 changes: 8 additions & 39 deletions compiler/rustc_codegen_gcc/src/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub struct ArArchiveBuilder<'a> {
}

impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
fn new(sess: &'a Session, output: &Path) -> Self {
let config = ArchiveConfig {
sess,
dst: output.to_path_buf(),
Expand All @@ -41,48 +41,13 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
use_gnu_style_archive: sess.target.options.archive_format == "gnu",
};

let (src_archives, entries) = if let Some(input) = input {
let mut archive = ar::Archive::new(File::open(input).unwrap());
let mut entries = Vec::new();

let mut i = 0;
while let Some(entry) = archive.next_entry() {
let entry = entry.unwrap();
entries.push((
String::from_utf8(entry.header().identifier().to_vec()).unwrap(),
ArchiveEntry::FromArchive {
archive_index: 0,
entry_index: i,
},
));
i += 1;
}

(vec![(input.to_owned(), archive)], entries)
} else {
(vec![], Vec::new())
};

ArArchiveBuilder {
config,
src_archives,
entries,
src_archives: vec![],
entries: vec![],
}
}

fn src_files(&mut self) -> Vec<String> {
self.entries.iter().map(|(name, _)| name.clone()).collect()
}

fn remove_file(&mut self, name: &str) {
let index = self
.entries
.iter()
.position(|(entry_name, _)| entry_name == name)
.expect("Tried to remove file not existing in src archive");
self.entries.remove(index);
}

fn add_file(&mut self, file: &Path) {
self.entries.push((
file.file_name().unwrap().to_str().unwrap().to_string(),
Expand Down Expand Up @@ -113,7 +78,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
Ok(())
}

fn build(mut self) {
fn build(mut self) -> bool {
use std::process::Command;

fn add_file_using_ar(archive: &Path, file: &Path) {
Expand Down Expand Up @@ -146,6 +111,8 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
BuilderKind::Bsd(ar::Builder::new(File::create(&self.config.dst).unwrap()))
};

let any_members = !self.entries.is_empty();

// Add all files
for (entry_name, entry) in self.entries.into_iter() {
match entry {
Expand Down Expand Up @@ -206,6 +173,8 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
if !status.success() {
self.config.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
}

any_members
}

fn inject_dll_import_lib(&mut self, _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &MaybeTempDir) {
Expand Down
120 changes: 25 additions & 95 deletions compiler/rustc_codegen_llvm/src/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,12 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_session::cstore::{DllCallingConvention, DllImport};
use rustc_session::Session;

struct ArchiveConfig<'a> {
pub sess: &'a Session,
pub dst: PathBuf,
pub src: Option<PathBuf>,
}

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

enum Addition {
Expand All @@ -50,10 +43,6 @@ fn is_relevant_child(c: &Child<'_>) -> bool {
}
}

fn archive_config<'a>(sess: &'a Session, output: &Path, input: Option<&Path>) -> ArchiveConfig<'a> {
ArchiveConfig { sess, dst: output.to_path_buf(), src: input.map(|p| p.to_path_buf()) }
}

/// Map machine type strings to values of LLVM's MachineTypes enum.
fn llvm_machine_type(cpu: &str) -> LLVMMachineType {
match cpu {
Expand All @@ -68,37 +57,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, input: Option<&Path>) -> LlvmArchiveBuilder<'a> {
let config = archive_config(sess, output, input);
LlvmArchiveBuilder {
config,
removals: Vec::new(),
additions: Vec::new(),
src_archive: None,
}
}

/// Removes a file from this archive
fn remove_file(&mut self, file: &str) {
self.removals.push(file.to_string());
}

/// Lists all files in an archive
fn src_files(&mut self) -> Vec<String> {
if self.src_archive().is_none() {
return Vec::new();
}

let archive = self.src_archive.as_ref().unwrap().as_ref().unwrap();

archive
.iter()
.filter_map(|child| child.ok())
.filter(is_relevant_child)
.filter_map(|child| child.name())
.filter(|name| !self.removals.iter().any(|x| x == name))
.map(|name| name.to_owned())
.collect()
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<()>
Expand Down Expand Up @@ -129,13 +89,10 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {

/// Combine the provided files, rlibs, and native libraries into a single
/// `Archive`.
fn build(mut self) {
let kind = self.llvm_archive_kind().unwrap_or_else(|kind| {
self.config.sess.fatal(&format!("Don't know how to build archive of type: {}", kind))
});

if let Err(e) = self.build_with_llvm(kind) {
self.config.sess.fatal(&format!("failed to build archive: {}", e));
fn build(mut self) -> bool {
match self.build_with_llvm() {
Ok(any_members) => any_members,
Err(e) => self.sess.fatal(&format!("failed to build archive: {}", e)),
}
}

Expand All @@ -151,7 +108,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
output_path.with_extension("lib")
};

let target = &self.config.sess.target;
let target = &self.sess.target;
let mingw_gnu_toolchain = target.vendor == "pc"
&& target.os == "windows"
&& target.env == "gnu"
Expand All @@ -160,7 +117,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
.iter()
.map(|import: &DllImport| {
if self.config.sess.target.arch == "x86" {
if self.sess.target.arch == "x86" {
(
LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain),
import.ordinal,
Expand Down Expand Up @@ -197,11 +154,11 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
match std::fs::write(&def_file_path, def_file_content) {
Ok(_) => {}
Err(e) => {
self.config.sess.fatal(&format!("Error writing .DEF file: {}", e));
self.sess.fatal(&format!("Error writing .DEF file: {}", e));
}
};

let dlltool = find_binutils_dlltool(self.config.sess);
let dlltool = find_binutils_dlltool(self.sess);
let result = std::process::Command::new(dlltool)
.args([
"-d",
Expand All @@ -215,9 +172,9 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {

match result {
Err(e) => {
self.config.sess.fatal(&format!("Error calling dlltool: {}", e));
self.sess.fatal(&format!("Error calling dlltool: {}", e));
}
Ok(output) if !output.status.success() => self.config.sess.fatal(&format!(
Ok(output) if !output.status.success() => self.sess.fatal(&format!(
"Dlltool could not create import library: {}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
Expand Down Expand Up @@ -263,13 +220,13 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
output_path_z.as_ptr(),
ffi_exports.as_ptr(),
ffi_exports.len(),
llvm_machine_type(&self.config.sess.target.arch) as u16,
!self.config.sess.target.is_like_msvc,
llvm_machine_type(&self.sess.target.arch) as u16,
!self.sess.target.is_like_msvc,
)
};

if result == crate::llvm::LLVMRustResult::Failure {
self.config.sess.fatal(&format!(
self.sess.fatal(&format!(
"Error creating import library for {}: {}",
lib_name,
llvm::last_error().unwrap_or("unknown LLVM error".to_string())
Expand All @@ -278,7 +235,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
};

self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
self.config.sess.fatal(&format!(
self.sess.fatal(&format!(
"failed to add native library {}: {}",
output_path.display(),
e
Expand All @@ -288,46 +245,19 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
}

impl<'a> LlvmArchiveBuilder<'a> {
fn src_archive(&mut self) -> Option<&ArchiveRO> {
if let Some(ref a) = self.src_archive {
return a.as_ref();
}
let src = self.config.src.as_ref()?;
self.src_archive = Some(ArchiveRO::open(src).ok());
self.src_archive.as_ref().unwrap().as_ref()
}

fn llvm_archive_kind(&self) -> Result<ArchiveKind, &str> {
let kind = &*self.config.sess.target.archive_format;
kind.parse().map_err(|_| kind)
}
fn build_with_llvm(&mut self) -> 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))
});

fn build_with_llvm(&mut self, kind: ArchiveKind) -> io::Result<()> {
let removals = mem::take(&mut self.removals);
let mut additions = mem::take(&mut self.additions);
let mut strings = Vec::new();
let mut members = Vec::new();

let dst = CString::new(self.config.dst.to_str().unwrap())?;
let dst = CString::new(self.dst.to_str().unwrap())?;

unsafe {
if let Some(archive) = self.src_archive() {
for child in archive.iter() {
let child = child.map_err(string_to_io_error)?;
let Some(child_name) = child.name() else { continue };
if removals.iter().any(|r| r == child_name) {
continue;
}

let name = CString::new(child_name)?;
members.push(llvm::LLVMRustArchiveMemberNew(
ptr::null(),
name.as_ptr(),
Some(child.raw),
));
strings.push(name);
}
}
for addition in &mut additions {
match addition {
Addition::File { path, name_in_archive } => {
Expand Down Expand Up @@ -389,7 +319,7 @@ impl<'a> LlvmArchiveBuilder<'a> {
};
Err(io::Error::new(io::ErrorKind::Other, msg))
} else {
Ok(())
Ok(!members.is_empty())
};
for member in members {
llvm::LLVMRustArchiveMemberFree(member);
Expand Down
Loading

0 comments on commit dc80ca7

Please sign in to comment.