about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/metadata/loader.rs15
-rw-r--r--src/librustc_back/archive.rs73
-rw-r--r--src/librustc_back/lib.rs1
-rw-r--r--src/librustc_llvm/archive_ro.rs73
-rw-r--r--src/librustc_llvm/lib.rs16
-rw-r--r--src/librustc_trans/back/lto.rs19
-rw-r--r--src/rustllvm/RustWrapper.cpp79
-rw-r--r--src/test/run-make/archive-duplicate-names/Makefile11
-rw-r--r--src/test/run-make/archive-duplicate-names/bar.c11
-rw-r--r--src/test/run-make/archive-duplicate-names/bar.rs15
-rw-r--r--src/test/run-make/archive-duplicate-names/foo.c11
-rw-r--r--src/test/run-make/archive-duplicate-names/foo.rs24
12 files changed, 264 insertions, 84 deletions
diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs
index 398e4cd33b9..bbb2452ca29 100644
--- a/src/librustc/metadata/loader.rs
+++ b/src/librustc/metadata/loader.rs
@@ -692,11 +692,16 @@ pub fn note_crate_name(diag: &SpanHandler, name: &str) {
 
 impl ArchiveMetadata {
     fn new(ar: ArchiveRO) -> Option<ArchiveMetadata> {
-        let data = match ar.read(METADATA_FILENAME) {
-            Some(data) => data as *const [u8],
-            None => {
-                debug!("didn't find '{}' in the archive", METADATA_FILENAME);
-                return None;
+        let data = {
+            let section = ar.iter().find(|sect| {
+                sect.name() == Some(METADATA_FILENAME)
+            });
+            match section {
+                Some(s) => s.data() as *const [u8],
+                None => {
+                    debug!("didn't find '{}' in the archive", METADATA_FILENAME);
+                    return None;
+                }
             }
         };
 
diff --git a/src/librustc_back/archive.rs b/src/librustc_back/archive.rs
index 9f5751c421e..37d784692fd 100644
--- a/src/librustc_back/archive.rs
+++ b/src/librustc_back/archive.rs
@@ -11,13 +11,14 @@
 //! A helper class for dealing with static archives
 
 use std::env;
-use std::fs;
+use std::fs::{self, File};
 use std::io::prelude::*;
 use std::io;
 use std::path::{Path, PathBuf};
 use std::process::{Command, Output, Stdio};
 use std::str;
 use syntax::diagnostic::Handler as ErrorHandler;
+use rustc_llvm::archive_ro::ArchiveRO;
 
 use tempdir::TempDir;
 
@@ -282,17 +283,14 @@ impl<'a> ArchiveBuilder<'a> {
                       mut skip: F) -> io::Result<()>
         where F: FnMut(&str) -> bool,
     {
-        let loc = TempDir::new("rsar").unwrap();
-
-        // First, extract the contents of the archive to a temporary directory.
-        // We don't unpack directly into `self.work_dir` due to the possibility
-        // of filename collisions.
-        let archive = env::current_dir().unwrap().join(archive);
-        run_ar(self.archive.handler, &self.archive.maybe_ar_prog,
-               "x", Some(loc.path()), &[&archive]);
+        let archive = match ArchiveRO::open(archive) {
+            Some(ar) => ar,
+            None => return Err(io::Error::new(io::ErrorKind::Other,
+                                              "failed to open archive")),
+        };
 
         // Next, we must rename all of the inputs to "guaranteed unique names".
-        // We move each file into `self.work_dir` under its new unique name.
+        // We write each file into `self.work_dir` under its new unique name.
         // The reason for this renaming is that archives are keyed off the name
         // of the files, so if two files have the same name they will override
         // one another in the archive (bad).
@@ -300,27 +298,46 @@ impl<'a> ArchiveBuilder<'a> {
         // We skip any files explicitly desired for skipping, and we also skip
         // all SYMDEF files as these are just magical placeholders which get
         // re-created when we make a new archive anyway.
-        let files = try!(fs::read_dir(loc.path()));
-        for file in files {
-            let file = try!(file).path();
-            let filename = file.file_name().unwrap().to_str().unwrap();
-            if skip(filename) { continue }
+        for file in archive.iter() {
+            let filename = match file.name() {
+                Some(s) => s,
+                None => continue,
+            };
             if filename.contains(".SYMDEF") { continue }
+            if skip(filename) { continue }
 
-            let filename = format!("r-{}-{}", name, filename);
-            // LLDB (as mentioned in back::link) crashes on filenames of exactly
-            // 16 bytes in length. If we're including an object file with
-            // exactly 16-bytes of characters, give it some prefix so that it's
-            // not 16 bytes.
-            let filename = if filename.len() == 16 {
-                format!("lldb-fix-{}", filename)
-            } else {
-                filename
-            };
-            let new_filename = self.work_dir.path().join(&filename[..]);
-            try!(fs::rename(&file, &new_filename));
-            self.members.push(PathBuf::from(filename));
+            // An archive can contain files of the same name multiple times, so
+            // we need to be sure to not have them overwrite one another when we
+            // extract them. Consequently we need to find a truly unique file
+            // name for us!
+            let mut new_filename = String::new();
+            for n in 0.. {
+                let n = if n == 0 {String::new()} else {format!("-{}", n)};
+                new_filename = format!("r{}-{}-{}", n, name, filename);
+
+                // LLDB (as mentioned in back::link) crashes on filenames of
+                // exactly
+                // 16 bytes in length. If we're including an object file with
+                //    exactly 16-bytes of characters, give it some prefix so
+                //    that it's not 16 bytes.
+                new_filename = if new_filename.len() == 16 {
+                    format!("lldb-fix-{}", new_filename)
+                } else {
+                    new_filename
+                };
+
+                let present = self.members.iter().filter_map(|p| {
+                    p.file_name().and_then(|f| f.to_str())
+                }).any(|s| s == new_filename);
+                if !present {
+                    break
+                }
+            }
+            let dst = self.work_dir.path().join(&new_filename);
+            try!(try!(File::create(&dst)).write_all(file.data()));
+            self.members.push(PathBuf::from(new_filename));
         }
+
         Ok(())
     }
 }
diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs
index 3c54d6631f8..22dea4757ed 100644
--- a/src/librustc_back/lib.rs
+++ b/src/librustc_back/lib.rs
@@ -46,6 +46,7 @@
 extern crate syntax;
 extern crate libc;
 extern crate serialize;
+extern crate rustc_llvm;
 #[macro_use] extern crate log;
 
 pub mod abi;
diff --git a/src/librustc_llvm/archive_ro.rs b/src/librustc_llvm/archive_ro.rs
index 647f4bc6a40..c8f3e204c4e 100644
--- a/src/librustc_llvm/archive_ro.rs
+++ b/src/librustc_llvm/archive_ro.rs
@@ -10,15 +10,23 @@
 
 //! A wrapper around LLVM's archive (.a) code
 
-use libc;
 use ArchiveRef;
 
 use std::ffi::CString;
-use std::slice;
 use std::path::Path;
+use std::slice;
+use std::str;
 
-pub struct ArchiveRO {
-    ptr: ArchiveRef,
+pub struct ArchiveRO { ptr: ArchiveRef }
+
+pub struct Iter<'a> {
+    archive: &'a ArchiveRO,
+    ptr: ::ArchiveIteratorRef,
+}
+
+pub struct Child<'a> {
+    name: Option<&'a str>,
+    data: &'a [u8],
 }
 
 impl ArchiveRO {
@@ -52,18 +60,9 @@ impl ArchiveRO {
         }
     }
 
-    /// Reads a file in the archive
-    pub fn read<'a>(&'a self, file: &str) -> Option<&'a [u8]> {
+    pub fn iter(&self) -> Iter {
         unsafe {
-            let mut size = 0 as libc::size_t;
-            let file = CString::new(file).unwrap();
-            let ptr = ::LLVMRustArchiveReadSection(self.ptr, file.as_ptr(),
-                                                   &mut size);
-            if ptr.is_null() {
-                None
-            } else {
-                Some(slice::from_raw_parts(ptr as *const u8, size as usize))
-            }
+            Iter { ptr: ::LLVMRustArchiveIteratorNew(self.ptr), archive: self }
         }
     }
 }
@@ -75,3 +74,47 @@ impl Drop for ArchiveRO {
         }
     }
 }
+
+impl<'a> Iterator for Iter<'a> {
+    type Item = Child<'a>;
+
+    fn next(&mut self) -> Option<Child<'a>> {
+        unsafe {
+            let ptr = ::LLVMRustArchiveIteratorCurrent(self.ptr);
+            if ptr.is_null() {
+                return None
+            }
+            let mut name_len = 0;
+            let name_ptr = ::LLVMRustArchiveChildName(ptr, &mut name_len);
+            let mut data_len = 0;
+            let data_ptr = ::LLVMRustArchiveChildData(ptr, &mut data_len);
+            let child = Child {
+                name: if name_ptr.is_null() {
+                    None
+                } else {
+                    let name = slice::from_raw_parts(name_ptr as *const u8,
+                                                     name_len as usize);
+                    str::from_utf8(name).ok().map(|s| s.trim())
+                },
+                data: slice::from_raw_parts(data_ptr as *const u8,
+                                            data_len as usize),
+            };
+            ::LLVMRustArchiveIteratorNext(self.ptr);
+            Some(child)
+        }
+    }
+}
+
+#[unsafe_destructor]
+impl<'a> Drop for Iter<'a> {
+    fn drop(&mut self) {
+        unsafe {
+            ::LLVMRustArchiveIteratorFree(self.ptr);
+        }
+    }
+}
+
+impl<'a> Child<'a> {
+    pub fn name(&self) -> Option<&'a str> { self.name }
+    pub fn data(&self) -> &'a [u8] { self.data }
+}
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 7030ee56979..104fc6700cc 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -30,6 +30,7 @@
 #![feature(libc)]
 #![feature(link_args)]
 #![feature(staged_api)]
+#![feature(unsafe_destructor)]
 
 extern crate libc;
 #[macro_use] #[no_link] extern crate rustc_bitflags;
@@ -488,9 +489,12 @@ pub type PassRef = *mut Pass_opaque;
 #[allow(missing_copy_implementations)]
 pub enum TargetMachine_opaque {}
 pub type TargetMachineRef = *mut TargetMachine_opaque;
-#[allow(missing_copy_implementations)]
 pub enum Archive_opaque {}
 pub type ArchiveRef = *mut Archive_opaque;
+pub enum ArchiveIterator_opaque {}
+pub type ArchiveIteratorRef = *mut ArchiveIterator_opaque;
+pub enum ArchiveChild_opaque {}
+pub type ArchiveChildRef = *mut ArchiveChild_opaque;
 #[allow(missing_copy_implementations)]
 pub enum Twine_opaque {}
 pub type TwineRef = *mut Twine_opaque;
@@ -2051,8 +2055,14 @@ extern {
     pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef);
 
     pub fn LLVMRustOpenArchive(path: *const c_char) -> ArchiveRef;
-    pub fn LLVMRustArchiveReadSection(AR: ArchiveRef, name: *const c_char,
-                                      out_len: *mut size_t) -> *const c_char;
+    pub fn LLVMRustArchiveIteratorNew(AR: ArchiveRef) -> ArchiveIteratorRef;
+    pub fn LLVMRustArchiveIteratorNext(AIR: ArchiveIteratorRef);
+    pub fn LLVMRustArchiveIteratorCurrent(AIR: ArchiveIteratorRef) -> ArchiveChildRef;
+    pub fn LLVMRustArchiveChildName(ACR: ArchiveChildRef,
+                                    size: *mut size_t) -> *const c_char;
+    pub fn LLVMRustArchiveChildData(ACR: ArchiveChildRef,
+                                    size: *mut size_t) -> *const c_char;
+    pub fn LLVMRustArchiveIteratorFree(AIR: ArchiveIteratorRef);
     pub fn LLVMRustDestroyArchive(AR: ArchiveRef);
 
     pub fn LLVMRustSetDLLExportStorageClass(V: ValueRef);
diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs
index 4e099a4ca87..e06a7b882e6 100644
--- a/src/librustc_trans/back/lto.rs
+++ b/src/librustc_trans/back/lto.rs
@@ -63,13 +63,13 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
         let file = &file[3..file.len() - 5]; // chop off lib/.rlib
         debug!("reading {}", file);
         for i in 0.. {
-            let bc_encoded = time(sess.time_passes(),
-                                  &format!("check for {}.{}.bytecode.deflate", name, i),
-                                  (),
-                                  |_| {
-                                      archive.read(&format!("{}.{}.bytecode.deflate",
-                                                           file, i))
-                                  });
+            let filename = format!("{}.{}.bytecode.deflate", file, i);
+            let msg = format!("check for {}", filename);
+            let bc_encoded = time(sess.time_passes(), &msg, (), |_| {
+                archive.iter().find(|section| {
+                    section.name() == Some(&filename[..])
+                })
+            });
             let bc_encoded = match bc_encoded {
                 Some(data) => data,
                 None => {
@@ -79,9 +79,10 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
                                            path.display()));
                     }
                     // No more bitcode files to read.
-                    break;
-                },
+                    break
+                }
             };
+            let bc_encoded = bc_encoded.data();
 
             let bc_decoded = if is_versioned_bytecode_format(bc_encoded) {
                 time(sess.time_passes(), &format!("decode {}.{}.bc", file, i), (), |_| {
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 31f75ae03b0..492993ec9a9 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -770,37 +770,68 @@ LLVMRustOpenArchive(char *path) {
     return ret;
 }
 
-extern "C" const char*
 #if LLVM_VERSION_MINOR >= 6
-LLVMRustArchiveReadSection(OwningBinary<Archive> *ob, char *name, size_t *size) {
-
-    Archive *ar = ob->getBinary();
+typedef OwningBinary<Archive> RustArchive;
+#define GET_ARCHIVE(a) ((a)->getBinary())
 #else
-LLVMRustArchiveReadSection(Archive *ar, char *name, size_t *size) {
+typedef Archive RustArchive;
+#define GET_ARCHIVE(a) (a)
 #endif
 
-    Archive::child_iterator child = ar->child_begin(),
-                              end = ar->child_end();
-    for (; child != end; ++child) {
-        ErrorOr<StringRef> name_or_err = child->getName();
-        if (name_or_err.getError()) continue;
-        StringRef sect_name = name_or_err.get();
-        if (sect_name.trim(" ") == name) {
-            StringRef buf = child->getBuffer();
-            *size = buf.size();
-            return buf.data();
-        }
-    }
-    return NULL;
+extern "C" void
+LLVMRustDestroyArchive(RustArchive *ar) {
+    delete ar;
+}
+
+struct RustArchiveIterator {
+    Archive::child_iterator cur;
+    Archive::child_iterator end;
+};
+
+extern "C" RustArchiveIterator*
+LLVMRustArchiveIteratorNew(RustArchive *ra) {
+    Archive *ar = GET_ARCHIVE(ra);
+    RustArchiveIterator *rai = new RustArchiveIterator();
+    rai->cur = ar->child_begin();
+    rai->end = ar->child_end();
+    return rai;
+}
+
+extern "C" const Archive::Child*
+LLVMRustArchiveIteratorCurrent(RustArchiveIterator *rai) {
+    if (rai->cur == rai->end)
+        return NULL;
+    const Archive::Child &ret = *rai->cur;
+    return &ret;
 }
 
 extern "C" void
-#if LLVM_VERSION_MINOR >= 6
-LLVMRustDestroyArchive(OwningBinary<Archive> *ar) {
-#else
-LLVMRustDestroyArchive(Archive *ar) {
-#endif
-    delete ar;
+LLVMRustArchiveIteratorNext(RustArchiveIterator *rai) {
+    if (rai->cur == rai->end)
+        return;
+    ++rai->cur;
+}
+
+extern "C" void
+LLVMRustArchiveIteratorFree(RustArchiveIterator *rai) {
+    delete rai;
+}
+
+extern "C" const char*
+LLVMRustArchiveChildName(const Archive::Child *child, size_t *size) {
+    ErrorOr<StringRef> name_or_err = child->getName();
+    if (name_or_err.getError())
+        return NULL;
+    StringRef name = name_or_err.get();
+    *size = name.size();
+    return name.data();
+}
+
+extern "C" const char*
+LLVMRustArchiveChildData(Archive::Child *child, size_t *size) {
+    StringRef buf = child->getBuffer();
+    *size = buf.size();
+    return buf.data();
 }
 
 extern "C" void
diff --git a/src/test/run-make/archive-duplicate-names/Makefile b/src/test/run-make/archive-duplicate-names/Makefile
new file mode 100644
index 00000000000..72c2d389e2a
--- /dev/null
+++ b/src/test/run-make/archive-duplicate-names/Makefile
@@ -0,0 +1,11 @@
+-include ../tools.mk
+
+all:
+	mkdir $(TMPDIR)/a
+	mkdir $(TMPDIR)/b
+	$(CC) -c -o $(TMPDIR)/a/foo.o foo.c
+	$(CC) -c -o $(TMPDIR)/b/foo.o bar.c
+	ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o
+	$(RUSTC) foo.rs
+	$(RUSTC) bar.rs
+	$(call RUN,bar)
diff --git a/src/test/run-make/archive-duplicate-names/bar.c b/src/test/run-make/archive-duplicate-names/bar.c
new file mode 100644
index 00000000000..a25fa10f4d3
--- /dev/null
+++ b/src/test/run-make/archive-duplicate-names/bar.c
@@ -0,0 +1,11 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+void bar() {}
diff --git a/src/test/run-make/archive-duplicate-names/bar.rs b/src/test/run-make/archive-duplicate-names/bar.rs
new file mode 100644
index 00000000000..1200a6de8e2
--- /dev/null
+++ b/src/test/run-make/archive-duplicate-names/bar.rs
@@ -0,0 +1,15 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate foo;
+
+fn main() {
+    foo::baz();
+}
diff --git a/src/test/run-make/archive-duplicate-names/foo.c b/src/test/run-make/archive-duplicate-names/foo.c
new file mode 100644
index 00000000000..61d5d154078
--- /dev/null
+++ b/src/test/run-make/archive-duplicate-names/foo.c
@@ -0,0 +1,11 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+void foo() {}
diff --git a/src/test/run-make/archive-duplicate-names/foo.rs b/src/test/run-make/archive-duplicate-names/foo.rs
new file mode 100644
index 00000000000..24b4734f2cd
--- /dev/null
+++ b/src/test/run-make/archive-duplicate-names/foo.rs
@@ -0,0 +1,24 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "rlib"]
+
+#[link(name = "foo", kind = "static")]
+extern {
+    fn foo();
+    fn bar();
+}
+
+pub fn baz() {
+    unsafe {
+        foo();
+        bar();
+    }
+}