(index<- )        ./librustc/back/archive.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri Apr 25 22:40:04 2014
   1  // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  //! A helper class for dealing with static archives
  12  
  13  use back::link::{get_ar_prog};
  14  use driver::session::Session;
  15  use metadata::filesearch;
  16  use lib::llvm::{ArchiveRef, llvm};
  17  
  18  use std::cast;
  19  use std::io;
  20  use std::io::{fs, TempDir};
  21  use libc;
  22  use std::os;
  23  use std::io::process::{ProcessConfig, Process, ProcessOutput};
  24  use std::str;
  25  use std::raw;
  26  use syntax::abi;
  27  
  28  pub static METADATA_FILENAME: &'static str = "rust.metadata.bin";
  29  
  30  pub struct Archive<'a> {
  31      sess: &'a Session,
  32      dst: Path,
  33  }
  34  
  35  pub struct ArchiveRO {
  36      ptr: ArchiveRef,
  37  }
  38  
  39  fn run_ar(sess: &Session, args: &str, cwdOption<&Path>,
  40            paths: &[&Path]) -> ProcessOutput {
  41      let ar = get_ar_prog(sess);
  42  
  43      let mut args = vec!(args.to_owned());
  44      let paths = paths.iter().map(|p| p.as_str().unwrap().to_owned());
  45      args.extend(paths);
  46      debug!("{} {}", ar, args.connect(" "));
  47      match cwd {
  48          Some(p) => { debug!("inside {}", p.display()); }
  49          None => {}
  50      }
  51      match Process::configure(ProcessConfig {
  52          program: ar.as_slice(),
  53          args: args.as_slice(),
  54          cwd: cwd.map(|a| &*a),
  55          .. ProcessConfig::new()
  56      }) {
  57          Ok(mut prog) => {
  58              let o = prog.wait_with_output();
  59              if !o.status.success() {
  60                  sess.err(format!("{} {} failed with: {}", ar, args.connect(" "),
  61                                   o.status));
  62                  sess.note(format!("stdout ---\n{}",
  63                                    str::from_utf8(o.output.as_slice()).unwrap()));
  64                  sess.note(format!("stderr ---\n{}",
  65                                    str::from_utf8(o.error.as_slice()).unwrap()));
  66                  sess.abort_if_errors();
  67              }
  68              o
  69          },
  70          Err(e) => {
  71              sess.err(format!("could not exec `{}`: {}", ar, e));
  72              sess.abort_if_errors();
  73              fail!("rustc::back::archive::run_ar() should not reach this point");
  74          }
  75      }
  76  }
  77  
  78  impl<'a> Archive<'a> {
  79      /// Initializes a new static archive with the given object file
  80      pub fn create<'b>(sess&'a Session, dst&'b Path,
  81                        initial_object&'b Path) -> Archive<'a> {
  82          run_ar(sess, "crus", None, [dst, initial_object]);
  83          Archive { sess: sess, dst: dst.clone() }
  84      }
  85  
  86      /// Opens an existing static archive
  87      pub fn open(sess&'a Session, dstPath) -> Archive<'a> {
  88          assert!(dst.exists());
  89          Archive { sess: sess, dst: dst }
  90      }
  91  
  92      /// Adds all of the contents of a native library to this archive. This will
  93      /// search in the relevant locations for a library named `name`.
  94      pub fn add_native_library(&mut self, name&str) -> io::IoResult<()> {
  95          let location = self.find_library(name);
  96          self.add_archive(&location, name, [])
  97      }
  98  
  99      /// Adds all of the contents of the rlib at the specified path to this
 100      /// archive.
 101      ///
 102      /// This ignores adding the bytecode from the rlib, and if LTO is enabled
 103      /// then the object file also isn't added.
 104      pub fn add_rlib(&mut self, rlib&Path, name&str,
 105                      ltobool) -> io::IoResult<()> {
 106          let object = format!("{}.o", name);
 107          let bytecode = format!("{}.bc.deflate", name);
 108          let mut ignore = vec!(METADATA_FILENAME, bytecode.as_slice());
 109          if lto {
 110              ignore.push(object.as_slice());
 111          }
 112          self.add_archive(rlib, name, ignore.as_slice())
 113      }
 114  
 115      /// Adds an arbitrary file to this archive
 116      pub fn add_file(&mut self, file&Path, has_symbolsbool) {
 117          let cmd = if has_symbols {"r"} else {"rS"};
 118          run_ar(self.sess, cmd, None, [&self.dst, file]);
 119      }
 120  
 121      /// Removes a file from this archive
 122      pub fn remove_file(&mut self, file&str) {
 123          run_ar(self.sess, "d", None, [&self.dst, &Path::new(file)]);
 124      }
 125  
 126      /// Updates all symbols in the archive (runs 'ar s' over it)
 127      pub fn update_symbols(&mut self) {
 128          run_ar(self.sess, "s", None, [&self.dst]);
 129      }
 130  
 131      /// Lists all files in an archive
 132      pub fn files(&self) -> Vec<~str> {
 133          let output = run_ar(self.sess, "t", None, [&self.dst]);
 134          let output = str::from_utf8(output.output.as_slice()).unwrap();
 135          // use lines_any because windows delimits output with `\r\n` instead of
 136          // just `\n`
 137          output.lines_any().map(|s| s.to_owned()).collect()
 138      }
 139  
 140      fn add_archive(&mut self, archive&Path, name&str,
 141                     skip&[&str]) -> io::IoResult<()> {
 142          let loc = TempDir::new("rsar").unwrap();
 143  
 144          // First, extract the contents of the archive to a temporary directory
 145          let archive = os::make_absolute(archive);
 146          run_ar(self.sess, "x", Some(loc.path()), [&archive]);
 147  
 148          // Next, we must rename all of the inputs to "guaranteed unique names".
 149          // The reason for this is that archives are keyed off the name of the
 150          // files, so if two files have the same name they will override one
 151          // another in the archive (bad).
 152          //
 153          // We skip any files explicitly desired for skipping, and we also skip
 154          // all SYMDEF files as these are just magical placeholders which get
 155          // re-created when we make a new archive anyway.
 156          let files = try!(fs::readdir(loc.path()));
 157          let mut inputs = Vec::new();
 158          for file in files.iter() {
 159              let filename = file.filename_str().unwrap();
 160              if skip.iter().any(|s| *s == filename) { continue }
 161              if filename.contains(".SYMDEF") { continue }
 162  
 163              let filename = format!("r-{}-{}", name, filename);
 164              let new_filename = file.with_filename(filename);
 165              try!(fs::rename(file, &new_filename));
 166              inputs.push(new_filename);
 167          }
 168          if inputs.len() == 0 { return Ok(()) }
 169  
 170          // Finally, add all the renamed files to this archive
 171          let mut args = vec!(&self.dst);
 172          args.extend(inputs.iter());
 173          run_ar(self.sess, "r", None, args.as_slice());
 174          Ok(())
 175      }
 176  
 177      fn find_library(&self, name&str) -> Path {
 178          let (osprefix, osext) = match self.sess.targ_cfg.os {
 179              abi::OsWin32 => ("", "lib"), _ => ("lib", "a"),
 180          };
 181          // On Windows, static libraries sometimes show up as libfoo.a and other
 182          // times show up as foo.lib
 183          let oslibname = format!("{}{}.{}", osprefix, name, osext);
 184          let unixlibname = format!("lib{}.a", name);
 185  
 186          let mut rustpath = filesearch::rust_path();
 187          rustpath.push(self.sess.target_filesearch().get_lib_path());
 188          let search = self.sess.opts.addl_lib_search_paths.borrow();
 189          for path in search.iter().chain(rustpath.iter()) {
 190              debug!("looking for {} inside {}", name, path.display());
 191              let test = path.join(oslibname.as_slice());
 192              if test.exists() { return test }
 193              if oslibname != unixlibname {
 194                  let test = path.join(unixlibname.as_slice());
 195                  if test.exists() { return test }
 196              }
 197          }
 198          self.sess.fatal(format!("could not find native static library `{}`, \
 199                                   perhaps an -L flag is missing?", name));
 200      }
 201  }
 202  
 203  impl ArchiveRO {
 204      /// Opens a static archive for read-only purposes. This is more optimized
 205      /// than the `open` method because it uses LLVM's internal `Archive` class
 206      /// rather than shelling out to `ar` for everything.
 207      ///
 208      /// If this archive is used with a mutable method, then an error will be
 209      /// raised.
 210      pub fn open(dst&Path) -> Option<ArchiveRO> {
 211          unsafe {
 212              let ar = dst.with_c_str(|dst| {
 213                  llvm::LLVMRustOpenArchive(dst)
 214              });
 215              if ar.is_null() {
 216                  None
 217              } else {
 218                  Some(ArchiveRO { ptr: ar })
 219              }
 220          }
 221      }
 222  
 223      /// Reads a file in the archive
 224      pub fn read<'a>(&'a self, file&str) -> Option<&'a [u8]> {
 225          unsafe {
 226              let mut size = 0 as libc::size_t;
 227              let ptr = file.with_c_str(|file| {
 228                  llvm::LLVMRustArchiveReadSection(self.ptr, file, &mut size)
 229              });
 230              if ptr.is_null() {
 231                  None
 232              } else {
 233                  Some(cast::transmute(raw::Slice {
 234                      data: ptr,
 235                      len: size as uint,
 236                  }))
 237              }
 238          }
 239      }
 240  }
 241  
 242  impl Drop for ArchiveRO {
 243      fn drop(&mut self) {
 244          unsafe {
 245              llvm::LLVMRustDestroyArchive(self.ptr);
 246          }
 247      }
 248  }


librustc/back/archive.rs:38:1-38:1 -fn- definition:
fn run_ar(sess: &Session, args: &str, cwd: Option<&Path>,
          paths: &[&Path]) -> ProcessOutput {
    let ar = get_ar_prog(sess);
references:- 7
122:     pub fn remove_file(&mut self, file: &str) {
123:         run_ar(self.sess, "d", None, [&self.dst, &Path::new(file)]);
124:     }
--
132:     pub fn files(&self) -> Vec<~str> {
133:         let output = run_ar(self.sess, "t", None, [&self.dst]);
134:         let output = str::from_utf8(output.output.as_slice()).unwrap();
--
145:         let archive = os::make_absolute(archive);
146:         run_ar(self.sess, "x", Some(loc.path()), [&archive]);
--
172:         args.extend(inputs.iter());
173:         run_ar(self.sess, "r", None, args.as_slice());
174:         Ok(())


librustc/back/archive.rs:34:1-34:1 -struct- definition:
pub struct ArchiveRO {
    ptr: ArchiveRef,
}
references:- 6
217:             } else {
218:                 Some(ArchiveRO { ptr: ar })
219:             }
--
242: impl Drop for ArchiveRO {
243:     fn drop(&mut self) {
librustc/metadata/loader.rs:
88: pub struct ArchiveMetadata {
89:     archive: ArchiveRO,
90:     // See comments in ArchiveMetadata::new for why this is static
--
452: impl ArchiveMetadata {
453:     fn new(ar: ArchiveRO) -> Option<ArchiveMetadata> {
454:         let data: &'static [u8] = {
librustc/back/archive.rs:
209:     /// raised.
210:     pub fn open(dst: &Path) -> Option<ArchiveRO> {
211:         unsafe {


librustc/back/archive.rs:29:1-29:1 -struct- definition:
pub struct Archive<'a> {
    sess: &'a Session,
    dst: Path,
references:- 6
88:         assert!(dst.exists());
89:         Archive { sess: sess, dst: dst }
90:     }
librustc/back/link.rs:
905:                  obj_filename: &Path,
906:                  out_filename: &Path) -> Archive<'a> {
907:     let mut a = Archive::create(sess, out_filename, obj_filename);
librustc/back/archive.rs:
86:     /// Opens an existing static archive
87:     pub fn open(sess: &'a Session, dst: Path) -> Archive<'a> {
88:         assert!(dst.exists());