]> git.lizzy.rs Git - rust.git/blobdiff - src/archive.rs
Enable inline asm on macOS
[rust.git] / src / archive.rs
index 55590f2a67560173732b6b9b354f5980c41a007b..b4c790961707900f839ad4977a89d5e725cf9f69 100644 (file)
@@ -1,16 +1,15 @@
 //! Creation of ar archives like for the lib and staticlib crate type
 
 use std::collections::BTreeMap;
-use std::convert::TryFrom;
 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;
-use object::{Object, ObjectSymbol, ReadCache, SymbolKind};
+use object::{Object, ObjectSymbol, ReadCache};
 
 #[derive(Debug)]
 enum ArchiveEntry {
@@ -18,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,
 
@@ -31,50 +55,6 @@ 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())
-        };
-
-        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,
-        }
-    }
-
-    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(),
@@ -82,10 +62,11 @@ fn add_file(&mut self, file: &Path) {
         ));
     }
 
-    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();
@@ -104,12 +85,9 @@ fn add_archive<F>(&mut self, archive_path: &Path, mut skip: F) -> std::io::Resul
 
         self.src_archives.push(read_cache.into_inner());
         Ok(())
-
     }
 
-    fn update_symbols(&mut self) {}
-
-    fn build(mut self) {
+    fn build(mut self: Box<Self>, output: &Path) -> bool {
         enum BuilderKind {
             Bsd(ar::Builder<File>),
             Gnu(ar::GnuBuilder<File>),
@@ -121,7 +99,7 @@ enum BuilderKind {
 
         let mut entries = Vec::new();
 
-        for (entry_name, entry) in self.entries {
+        for (mut 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 {
@@ -144,6 +122,23 @@ enum BuilderKind {
             };
 
             if !self.no_builtin_ranlib {
+                if symbol_table.contains_key(&entry_name) {
+                    // The ar crate can't handle creating a symbol table in case of multiple archive
+                    // members with the same name. Work around this by prepending a number until we
+                    // get a unique name.
+                    for i in 1.. {
+                        let new_name = format!("{}_", i)
+                            .into_bytes()
+                            .into_iter()
+                            .chain(entry_name.iter().copied())
+                            .collect::<Vec<_>>();
+                        if !symbol_table.contains_key(&new_name) {
+                            entry_name = new_name;
+                            break;
+                        }
+                    }
+                }
+
                 match object::File::parse(&*data) {
                     Ok(object) => {
                         symbol_table.insert(
@@ -151,12 +146,7 @@ enum BuilderKind {
                             object
                                 .symbols()
                                 .filter_map(|symbol| {
-                                    if symbol.is_undefined()
-                                        || symbol.is_local()
-                                        || symbol.kind() != SymbolKind::Data
-                                            && symbol.kind() != SymbolKind::Text
-                                            && symbol.kind() != SymbolKind::Tls
-                                    {
+                                    if symbol.is_undefined() || symbol.is_local() {
                                         None
                                     } else {
                                         symbol.name().map(|name| name.as_bytes().to_vec()).ok()
@@ -186,7 +176,7 @@ enum BuilderKind {
         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
@@ -201,7 +191,7 @@ enum BuilderKind {
         } 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
@@ -213,6 +203,8 @@ enum BuilderKind {
             )
         };
 
+        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);
@@ -230,7 +222,7 @@ enum BuilderKind {
 
             // 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");
 
@@ -238,14 +230,7 @@ enum BuilderKind {
                 self.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
             }
         }
-    }
 
-    fn inject_dll_import_lib(
-        &mut self,
-        _lib_name: &str,
-        _dll_imports: &[rustc_middle::middle::cstore::DllImport],
-        _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir,
-    ) {
-        bug!("injecting dll imports is not supported");
+        any_members
     }
 }