]> git.lizzy.rs Git - rust.git/blobdiff - src/archive.rs
Rustup to rustc 1.49.0-nightly (dd7fc54eb 2020-10-15)
[rust.git] / src / archive.rs
index 7b0cffcfffa1bc968f76b87ca8e5e221e48e9be3..6382f8df3446b149218d0bef1f40f26614550ad4 100644 (file)
@@ -1,18 +1,14 @@
+//! Creation of ar archives like for the lib and staticlib crate type
+
+use std::collections::BTreeMap;
 use std::fs::File;
 use std::path::{Path, PathBuf};
 
-use crate::prelude::*;
-
 use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
-use rustc_codegen_ssa::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION};
+use rustc_codegen_ssa::METADATA_FILENAME;
+use rustc_session::Session;
 
-struct ArchiveConfig<'a> {
-    sess: &'a Session,
-    dst: PathBuf,
-    lib_search_paths: Vec<PathBuf>,
-    use_native_ar: bool,
-    use_gnu_style_archive: bool,
-}
+use object::{Object, SymbolKind};
 
 #[derive(Debug)]
 enum ArchiveEntry {
@@ -23,8 +19,13 @@ enum ArchiveEntry {
     File(PathBuf),
 }
 
-pub struct ArArchiveBuilder<'a> {
-    config: ArchiveConfig<'a>,
+pub(crate) struct ArArchiveBuilder<'a> {
+    sess: &'a Session,
+    dst: PathBuf,
+    lib_search_paths: Vec<PathBuf>,
+    use_gnu_style_archive: bool,
+    no_builtin_ranlib: bool,
+
     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.
@@ -35,14 +36,6 @@ pub struct ArArchiveBuilder<'a> {
 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 config = ArchiveConfig {
-            sess,
-            dst: output.to_path_buf(),
-            lib_search_paths: archive_search_paths(sess),
-            use_native_ar: true, // FIXME fix rust-ar to not emit corrupted archive files.
-            // FIXME test for linux and System V derivatives instead
-            use_gnu_style_archive: !sess.target.target.options.is_like_osx,
-        };
 
         let (src_archives, entries) = if let Some(input) = input {
             let mut archive = ar::Archive::new(File::open(input).unwrap());
@@ -67,7 +60,13 @@ fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
         };
 
         ArArchiveBuilder {
-            config,
+            sess,
+            dst: output.to_path_buf(),
+            lib_search_paths: archive_search_paths(sess),
+            use_gnu_style_archive: sess.target.options.archive_format == "gnu",
+            // FIXME fix builtin ranlib on macOS
+            no_builtin_ranlib: sess.target.options.is_like_osx,
+
             src_archives,
             entries,
             update_symbols: false,
@@ -94,8 +93,8 @@ fn add_file(&mut self, file: &Path) {
         ));
     }
 
-    fn add_native_library(&mut self, name: &str) {
-        let location = find_library(name, &self.config.lib_search_paths, self.config.sess);
+    fn add_native_library(&mut self, name: rustc_span::symbol::Symbol) {
+        let location = find_library(name, &self.lib_search_paths, self.sess);
         self.add_archive(location.clone(), |_| false)
             .unwrap_or_else(|e| {
                 panic!(
@@ -116,8 +115,8 @@ fn add_rlib(
         let obj_start = name.to_owned();
 
         self.add_archive(rlib.to_owned(), move |fname: &str| {
-            // Ignore bytecode/metadata files, no matter the name.
-            if fname.ends_with(RLIB_BYTECODE_EXTENSION) || fname == METADATA_FILENAME {
+            // Ignore metadata files, no matter the name.
+            if fname == METADATA_FILENAME {
                 return true;
             }
 
@@ -142,102 +141,140 @@ fn update_symbols(&mut self) {
     }
 
     fn build(mut self) {
-        use std::process::Command;
-
-        fn add_file_using_ar(archive: &Path, file: &Path) {
-            Command::new("ar")
-                .arg("r") // add or replace file
-                .arg("-c") // silence created file message
-                .arg(archive)
-                .arg(&file)
-                .status()
-                .unwrap();
-        }
-
-        enum BuilderKind<'a> {
+        enum BuilderKind {
             Bsd(ar::Builder<File>),
             Gnu(ar::GnuBuilder<File>),
-            NativeAr(&'a Path),
         }
 
-        let mut builder = if self.config.use_native_ar {
-            BuilderKind::NativeAr(&self.config.dst)
-        } else if self.config.use_gnu_style_archive {
-            BuilderKind::Gnu(ar::GnuBuilder::new(
-                File::create(&self.config.dst).unwrap(),
-                self.entries
-                    .iter()
-                    .map(|(name, _)| name.as_bytes().to_vec())
-                    .collect(),
-            ))
-        } else {
-            BuilderKind::Bsd(ar::Builder::new(File::create(&self.config.dst).unwrap()))
-        };
+        let sess = self.sess;
 
-        // Add all files
-        for (entry_name, entry) in self.entries.into_iter() {
-            match entry {
+        let mut symbol_table = BTreeMap::new();
+
+        let mut entries = Vec::new();
+
+        for (entry_name, entry) in self.entries {
+            // FIXME only read the symbol table of the object files to avoid having to keep all
+            // object files in memory at once, or read them twice.
+            let data = match entry {
                 ArchiveEntry::FromArchive {
                     archive_index,
                     entry_index,
                 } => {
-                    let (ref src_archive_path, ref mut src_archive) =
+                    // FIXME read symbols from symtab
+                    use std::io::Read;
+                    let (ref _src_archive_path, ref mut src_archive) =
                         self.src_archives[archive_index];
-                    let entry = src_archive.jump_to_entry(entry_index).unwrap();
-                    let orig_header = entry.header();
-
-                    // FIXME implement clone for `ar::Archive`.
-                    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());
-
-                    match builder {
-                        BuilderKind::Bsd(ref mut builder) => {
-                            builder.append(&header, entry).unwrap()
-                        }
-                        BuilderKind::Gnu(ref mut builder) => {
-                            builder.append(&header, entry).unwrap()
-                        }
-                        BuilderKind::NativeAr(archive_file) => {
-                            Command::new("ar")
-                                .arg("x")
-                                .arg(src_archive_path)
-                                .arg(&entry_name)
-                                .status()
-                                .unwrap();
-                            add_file_using_ar(archive_file, Path::new(&entry_name));
-                            std::fs::remove_file(entry_name).unwrap();
+                    let mut entry = src_archive.jump_to_entry(entry_index).unwrap();
+                    let mut data = Vec::new();
+                    entry.read_to_end(&mut data).unwrap();
+                    data
+                }
+                ArchiveEntry::File(file) => std::fs::read(file).unwrap_or_else(|err| {
+                    sess.fatal(&format!(
+                        "error while reading object file during archive building: {}",
+                        err
+                    ));
+                }),
+            };
+
+            if !self.no_builtin_ranlib {
+                match object::File::parse(&data) {
+                    Ok(object) => {
+                        symbol_table.insert(
+                            entry_name.as_bytes().to_vec(),
+                            object
+                                .symbols()
+                                .filter_map(|(_index, symbol)| {
+                                    if symbol.is_undefined()
+                                        || symbol.is_local()
+                                        || symbol.kind() != SymbolKind::Data
+                                            && symbol.kind() != SymbolKind::Text
+                                            && symbol.kind() != SymbolKind::Tls
+                                    {
+                                        None
+                                    } else {
+                                        symbol.name().map(|name| name.as_bytes().to_vec())
+                                    }
+                                })
+                                .collect::<Vec<_>>(),
+                        );
+                    }
+                    Err(err) => {
+                        let err = err.to_string();
+                        if err == "Unknown file magic" {
+                            // Not an object file; skip it.
+                        } else {
+                            sess.fatal(&format!(
+                                "error parsing `{}` during archive creation: {}",
+                                entry_name, err
+                            ));
                         }
                     }
                 }
-                ArchiveEntry::File(file) => match builder {
-                    BuilderKind::Bsd(ref mut builder) => builder
-                        .append_file(entry_name.as_bytes(), &mut File::open(file).unwrap())
-                        .unwrap(),
-                    BuilderKind::Gnu(ref mut builder) => builder
-                        .append_file(entry_name.as_bytes(), &mut File::open(file).unwrap())
-                        .unwrap(),
-                    BuilderKind::NativeAr(archive_file) => add_file_using_ar(archive_file, &file),
-                },
+            }
+
+            entries.push((entry_name, data));
+        }
+
+        let mut builder = if self.use_gnu_style_archive {
+            BuilderKind::Gnu(
+                ar::GnuBuilder::new(
+                    File::create(&self.dst).unwrap_or_else(|err| {
+                        sess.fatal(&format!(
+                            "error opening destination during archive building: {}",
+                            err
+                        ));
+                    }),
+                    entries
+                        .iter()
+                        .map(|(name, _)| name.as_bytes().to_vec())
+                        .collect(),
+                    ar::GnuSymbolTableFormat::Size32,
+                    symbol_table,
+                )
+                .unwrap(),
+            )
+        } else {
+            BuilderKind::Bsd(
+                ar::Builder::new(
+                    File::create(&self.dst).unwrap_or_else(|err| {
+                        sess.fatal(&format!(
+                            "error opening destination during archive building: {}",
+                            err
+                        ));
+                    }),
+                    symbol_table,
+                )
+                .unwrap(),
+            )
+        };
+
+        // Add all files
+        for (entry_name, data) in entries.into_iter() {
+            let header = ar::Header::new(entry_name.into_bytes(), data.len() as u64);
+            match builder {
+                BuilderKind::Bsd(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
+                BuilderKind::Gnu(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
             }
         }
 
         // Finalize archive
         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");
-        assert!(
-            status.success(),
-            "Ranlib exited with code {:?}",
-            status.code()
-        );
+        if self.no_builtin_ranlib {
+            let ranlib = crate::toolchain::get_toolchain_binary(self.sess, "ranlib");
+
+            // Run ranlib to be able to link the archive
+            let status = std::process::Command::new(ranlib)
+                .arg(self.dst)
+                .status()
+                .expect("Couldn't run ranlib");
+
+            if !status.success() {
+                self.sess
+                    .fatal(&format!("Ranlib exited with code {:?}", status.code()));
+            }
+        }
     }
 }
 
@@ -251,8 +288,9 @@ fn add_archive<F>(&mut self, archive_path: PathBuf, mut skip: F) -> std::io::Res
 
         let mut i = 0;
         while let Some(entry) = archive.next_entry() {
-            let entry = entry.unwrap();
-            let file_name = String::from_utf8(entry.header().identifier().to_vec()).unwrap();
+            let entry = entry?;
+            let file_name = String::from_utf8(entry.header().identifier().to_vec())
+                .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
             if !skip(&file_name) {
                 self.entries.push((
                     file_name,