diff --git a/src/archive.rs b/src/archive.rs index 44d1fd2c6f2..1445e291ce7 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -1,26 +1,37 @@ use std::collections::HashMap; use std::fs::File; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use crate::prelude::*; -pub struct ArchiveConfig<'a> { +use rustc_codegen_ssa::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION}; +use rustc_codegen_ssa::back::archive::{ArchiveBuilder, find_library}; + +struct ArchiveConfig<'a> { pub sess: &'a Session, pub dst: PathBuf, pub src: Option, pub lib_search_paths: Vec, } -pub struct ArchiveBuilder<'a> { - cfg: ArchiveConfig<'a>, +pub struct ArArchiveBuilder<'a> { + config: ArchiveConfig<'a>, src_archive: Option>, src_entries: HashMap, builder: ar::Builder, update_symbols: bool, } -impl<'a> ArchiveBuilder<'a> { - pub fn new(cfg: ArchiveConfig<'a>) -> Self { +impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { + fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self { + use rustc_codegen_ssa::back::link::archive_search_paths; + let cfg = ArchiveConfig { + sess, + dst: output.to_path_buf(), + src: input.map(|p| p.to_path_buf()), + lib_search_paths: archive_search_paths(sess), + }; + let (src_archive, src_entries) = if let Some(src) = &cfg.src { let mut archive = ar::Archive::new(File::open(src).unwrap()); let mut entries = HashMap::new(); @@ -42,8 +53,8 @@ impl<'a> ArchiveBuilder<'a> { let builder = ar::Builder::new(File::create(&cfg.dst).unwrap()); - ArchiveBuilder { - cfg, + ArArchiveBuilder { + config: cfg, src_archive, src_entries, builder, @@ -51,11 +62,11 @@ impl<'a> ArchiveBuilder<'a> { } } - pub fn src_files(&self) -> Vec { + fn src_files(&mut self) -> Vec { self.src_entries.keys().cloned().collect() } - pub fn remove_file(&mut self, name: &str) { + fn remove_file(&mut self, name: &str) { let file = self.src_entries.remove(name); assert!( file.is_some(), @@ -63,11 +74,47 @@ impl<'a> ArchiveBuilder<'a> { ); } - pub fn update_symbols(&mut self) { + fn add_file(&mut self, file: &Path) { + self.builder.append_path(file).unwrap(); + } + + fn add_native_library(&mut self, name: &str) { + let location = find_library(name, &self.config.lib_search_paths, self.config.sess); + self.add_archive(&location, |_| false).unwrap_or_else(|e| { + panic!("failed to add native library {}: {}", location.to_string_lossy(), e); + }); + } + + fn add_rlib(&mut self, rlib: &Path, name: &str, lto: bool, skip_objects: bool) -> std::io::Result<()> { + let obj_start = name.to_owned(); + + self.add_archive(rlib, move |fname: &str| { + // Ignore bytecode/metadata files, no matter the name. + if fname.ends_with(RLIB_BYTECODE_EXTENSION) || fname == METADATA_FILENAME { + return true; + } + + // Don't include Rust objects if LTO is enabled + if lto && 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_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) { + return true; + } + + // ok, don't skip this + return false; + }) + } + + fn update_symbols(&mut self) { self.update_symbols = true; } - pub fn build(mut self) { + fn build(mut self) { // Add files from original archive if let Some(mut src_archive) = self.src_archive { for (_entry_name, entry_idx) in self.src_entries.into_iter() { @@ -88,7 +135,7 @@ impl<'a> ArchiveBuilder<'a> { // Run ranlib to be able to link the archive let status = std::process::Command::new("ranlib") - .arg(self.cfg.dst) + .arg(self.config.dst) .status() .expect("Couldn't run ranlib"); assert!( @@ -98,3 +145,28 @@ impl<'a> ArchiveBuilder<'a> { ); } } + +impl<'a> ArArchiveBuilder<'a> { + fn add_archive(&mut self, archive: &Path, mut skip: F) -> std::io::Result<()> + where F: FnMut(&str) -> bool + 'static + { + let mut archive = ar::Archive::new(std::fs::File::open(archive)?); + while let Some(entry) = archive.next_entry() { + let entry = entry?; + let orig_header = entry.header(); + + if skip(std::str::from_utf8(orig_header.identifier()).unwrap()) { + continue; + } + + let mut header = + ar::Header::new(orig_header.identifier().to_vec(), orig_header.size()); + header.set_mtime(orig_header.mtime()); + header.set_uid(orig_header.uid()); + header.set_gid(orig_header.gid()); + header.set_mode(orig_header.mode()); + self.builder.append(&header, entry).unwrap(); + } + Ok(()) + } +} diff --git a/src/link_copied.rs b/src/link_copied.rs index d58ffda3336..a1205b07943 100644 --- a/src/link_copied.rs +++ b/src/link_copied.rs @@ -1,38 +1,22 @@ //! All functions here are copied from https://github.com/rust-lang/rust/blob/942864a000efd74b73e36bda5606b2cdb55ecf39/src/librustc_codegen_llvm/back/link.rs -use std::path::{Path, PathBuf}; +use std::path::Path; -use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind}; +use rustc::middle::cstore::NativeLibraryKind; use rustc::middle::dependency_format::Linkage; use rustc::session::config::{self, OutputType, RUST_CGU_EXT}; -use rustc::session::search_paths::PathKind; use rustc::session::Session; use rustc::util::common::time; use rustc_codegen_ssa::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION}; +use rustc_codegen_ssa::back::archive::ArchiveBuilder; use rustc_codegen_ssa::back::linker::*; use rustc_codegen_ssa::back::link::*; use rustc_data_structures::fx::FxHashSet; use rustc_fs_util::fix_windows_verbatim_for_gcc; -use syntax::attr; use crate::prelude::*; -use crate::archive::{ArchiveBuilder, ArchiveConfig}; - -fn archive_search_paths(sess: &Session) -> Vec { - sess.target_filesearch(PathKind::Native).search_path_dirs() -} - -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()), - lib_search_paths: archive_search_paths(sess), - } -} +use crate::archive::ArArchiveBuilder; // # Rust Crate linking // @@ -184,8 +168,7 @@ pub fn add_upstream_rust_crates(cmd: &mut dyn Linker, } let dst = tmpdir.join(cratepath.file_name().unwrap()); - let cfg = archive_config(sess, &dst, Some(cratepath)); - let mut archive = ArchiveBuilder::new(cfg); + let mut archive = ArArchiveBuilder::new(sess, &dst, Some(cratepath)); archive.update_symbols(); for f in archive.src_files() { @@ -261,8 +244,7 @@ pub fn add_upstream_rust_crates(cmd: &mut dyn Linker, let name = &name[3..name.len() - 5]; // chop off lib/.rlib time(sess, &format!("altering {}.rlib", name), || { - let cfg = archive_config(sess, &dst, Some(cratepath)); - let mut archive = ArchiveBuilder::new(cfg); + let mut archive = ArArchiveBuilder::new(sess, &dst, Some(cratepath)); archive.update_symbols(); let mut any_objects = false;