//! Finds crate binaries and loads their metadata
-
-use lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
+use back::archive::Archive;
+use driver::session::Session;
+use lib::llvm::{False, llvm, ObjectFile, mk_section_iter};
use metadata::decoder;
use metadata::encoder;
-use metadata::filesearch::{FileSearch, FileMatch, FileMatches, FileDoesntMatch};
+use metadata::filesearch::{FileMatches, FileDoesntMatch};
use metadata::filesearch;
use syntax::codemap::Span;
use syntax::diagnostic::span_handler;
use std::c_str::ToCStr;
use std::cast;
use std::io;
+use std::libc;
use std::num;
use std::option;
use std::os::consts::{macos, freebsd, linux, android, win32};
}
pub struct Context {
- diag: @mut span_handler,
- filesearch: @FileSearch,
+ sess: Session,
span: Span,
ident: @str,
metas: ~[@ast::MetaItem],
hash: @str,
os: Os,
- is_static: bool,
intr: @ident_interner
}
-pub fn load_library_crate(cx: &Context) -> (~str, @~[u8]) {
- match find_library_crate(cx) {
- Some(t) => t,
- None => {
- cx.diag.span_fatal(cx.span,
- format!("can't find crate for `{}`",
- cx.ident));
- }
- }
+pub struct Library {
+ dylib: Option<Path>,
+ rlib: Option<Path>,
+ metadata: @~[u8],
}
-fn find_library_crate(cx: &Context) -> Option<(~str, @~[u8])> {
- attr::require_unique_names(cx.diag, cx.metas);
- find_library_crate_aux(cx, libname(cx), cx.filesearch)
-}
+impl Context {
+ pub fn load_library_crate(&self) -> Library {
+ match self.find_library_crate() {
+ Some(t) => t,
+ None => {
+ self.sess.span_fatal(self.span,
+ format!("can't find crate for `{}`",
+ self.ident));
+ }
+ }
+ }
-fn libname(cx: &Context) -> (~str, ~str) {
- if cx.is_static { return (~"lib", ~".rlib"); }
- let (dll_prefix, dll_suffix) = match cx.os {
- OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
- OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
- OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
- OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
- OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
- };
+ fn find_library_crate(&self) -> Option<Library> {
+ attr::require_unique_names(self.sess.diagnostic(), self.metas);
+ let filesearch = self.sess.filesearch;
+ let crate_name = crate_name_from_metas(self.metas);
+ let (dyprefix, dysuffix) = self.dylibname();
- (dll_prefix.to_owned(), dll_suffix.to_owned())
-}
+ // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
+ let dylib_prefix = format!("{}{}-", dyprefix, crate_name);
+ let rlib_prefix = format!("lib{}-", crate_name);
-fn find_library_crate_aux(
- cx: &Context,
- (prefix, suffix): (~str, ~str),
- filesearch: @filesearch::FileSearch
-) -> Option<(~str, @~[u8])> {
- let crate_name = crate_name_from_metas(cx.metas);
- // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
- let prefix = format!("{}{}-", prefix, crate_name);
- let mut matches = ~[];
- filesearch::search(filesearch, |path| -> FileMatch {
- // FIXME (#9639): This needs to handle non-utf8 paths
- let path_str = path.filename_str();
- match path_str {
- None => FileDoesntMatch,
- Some(path_str) =>
- if path_str.starts_with(prefix) && path_str.ends_with(suffix) {
- debug!("{} is a candidate", path.display());
- match get_metadata_section(cx.os, path) {
- Some(cvec) =>
- if !crate_matches(cvec, cx.metas, cx.hash) {
- debug!("skipping {}, metadata doesn't match",
- path.display());
- FileDoesntMatch
- } else {
- debug!("found {} with matching metadata", path.display());
- // FIXME (#9639): This needs to handle non-utf8 paths
- matches.push((path.as_str().unwrap().to_owned(), cvec));
- FileMatches
- },
- _ => {
- debug!("could not load metadata for {}", path.display());
- FileDoesntMatch
- }
- }
- }
- else {
- FileDoesntMatch
- }
- }
- });
+ let mut matches = ~[];
+ do filesearch::search(filesearch) |path| {
+ match path.filename_str() {
+ None => FileDoesntMatch,
+ Some(file) => {
+ let (candidate, existing) = if file.starts_with(rlib_prefix) &&
+ file.ends_with(".rlib") {
+ debug!("{} is an rlib candidate", path.display());
+ (true, self.add_existing_rlib(matches, path, file))
+ } else if file.starts_with(dylib_prefix) &&
+ file.ends_with(dysuffix) {
+ debug!("{} is a dylib candidate", path.display());
+ (true, self.add_existing_dylib(matches, path, file))
+ } else {
+ (false, false)
+ };
- match matches.len() {
- 0 => None,
- 1 => Some(matches[0]),
- _ => {
- cx.diag.span_err(
- cx.span, format!("multiple matching crates for `{}`", crate_name));
- cx.diag.handler().note("candidates:");
- for pair in matches.iter() {
- let ident = pair.first();
- let data = pair.second();
- cx.diag.handler().note(format!("path: {}", ident));
- let attrs = decoder::get_crate_attributes(data);
- note_linkage_attrs(cx.intr, cx.diag, attrs);
+ if candidate && existing {
+ FileMatches
+ } else if candidate {
+ match get_metadata_section(self.sess, self.os, path,
+ crate_name) {
+ Some(cvec) =>
+ if crate_matches(cvec, self.metas, self.hash) {
+ debug!("found {} with matching metadata",
+ path.display());
+ let (rlib, dylib) = if file.ends_with(".rlib") {
+ (Some(path.clone()), None)
+ } else {
+ (None, Some(path.clone()))
+ };
+ matches.push(Library {
+ rlib: rlib,
+ dylib: dylib,
+ metadata: cvec,
+ });
+ FileMatches
+ } else {
+ debug!("skipping {}, metadata doesn't match",
+ path.display());
+ FileDoesntMatch
+ },
+ _ => {
+ debug!("could not load metadata for {}",
+ path.display());
+ FileDoesntMatch
+ }
+ }
+ } else {
+ FileDoesntMatch
+ }
}
- cx.diag.handler().abort_if_errors();
+ }
+ }
+
+ match matches.len() {
+ 0 => None,
+ 1 => Some(matches[0]),
+ _ => {
+ self.sess.span_err(self.span,
+ format!("multiple matching crates for `{}`", crate_name));
+ self.sess.note("candidates:");
+ for lib in matches.iter() {
+ match lib.dylib {
+ Some(ref p) => {
+ self.sess.note(format!("path: {}", p.display()));
+ }
+ None => {}
+ }
+ match lib.rlib {
+ Some(ref p) => {
+ self.sess.note(format!("path: {}", p.display()));
+ }
+ None => {}
+ }
+ let attrs = decoder::get_crate_attributes(lib.metadata);
+ note_linkage_attrs(self.intr, self.sess.diagnostic(), attrs);
+ }
+ self.sess.abort_if_errors();
None
+ }
+ }
+ }
+
+ fn add_existing_rlib(&self, libs: &mut [Library],
+ path: &Path, file: &str) -> bool {
+ let (prefix, suffix) = self.dylibname();
+ let file = file.slice_from(3); // chop off 'lib'
+ let file = file.slice_to(file.len() - 5); // chop off '.rlib'
+ let file = format!("{}{}{}", prefix, file, suffix);
+
+ for lib in libs.mut_iter() {
+ match lib.dylib {
+ Some(ref p) if p.filename_str() == Some(file.as_slice()) => {
+ assert!(lib.rlib.is_none()); // XXX: legit compiler error
+ lib.rlib = Some(path.clone());
+ return true;
+ }
+ Some(*) | None => {}
+ }
+ }
+ return false;
+ }
+
+ fn add_existing_dylib(&self, libs: &mut [Library],
+ path: &Path, file: &str) -> bool {
+ let (prefix, suffix) = self.dylibname();
+ let file = file.slice_from(prefix.len());
+ let file = file.slice_to(file.len() - suffix.len());
+ let file = format!("lib{}.rlib", file);
+
+ for lib in libs.mut_iter() {
+ match lib.rlib {
+ Some(ref p) if p.filename_str() == Some(file.as_slice()) => {
+ assert!(lib.dylib.is_none()); // XXX: legit compiler error
+ lib.dylib = Some(path.clone());
+ return true;
+ }
+ Some(*) | None => {}
+ }
+ }
+ return false;
+ }
+
+ // Returns the corresponding (prefix, suffix) that files need to have for
+ // dynamic libraries
+ fn dylibname(&self) -> (&'static str, &'static str) {
+ match self.os {
+ OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
+ OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
+ OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
+ OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
+ OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
}
}
}
local_metas.iter().all(|needed| attr::contains(extern_metas, *needed))
}
-fn get_metadata_section(os: Os,
- filename: &Path) -> Option<@~[u8]> {
+fn get_metadata_section(sess: Session, os: Os, filename: &Path,
+ crate_name: &str) -> Option<@~[u8]> {
unsafe {
- let mb = filename.with_c_str(|buf| {
- llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
- });
- if mb as int == 0 { return option::None::<@~[u8]>; }
- let of = match mk_object_file(mb) {
- option::Some(of) => of,
- _ => return option::None::<@~[u8]>
+ let mb = if filename.filename_str().unwrap().ends_with(".rlib") {
+ let archive = Archive::open(sess, filename.clone());
+ let contents = archive.read(crate_name + ".o");
+ let ptr = vec::raw::to_ptr(contents);
+ crate_name.with_c_str(|name| {
+ llvm::LLVMCreateMemoryBufferWithMemoryRangeCopy(
+ ptr as *i8, contents.len() as libc::size_t, name)
+ })
+ } else {
+ filename.with_c_str(|buf| {
+ llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
+ })
+ };
+ if mb as int == 0 { return None }
+ let of = match ObjectFile::new(mb) {
+ Some(of) => of,
+ _ => return None
};
let si = mk_section_iter(of.llof);
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
}
// A diagnostic function for dumping crate metadata to an output stream
-pub fn list_file_metadata(intr: @ident_interner,
+pub fn list_file_metadata(sess: Session,
+ intr: @ident_interner,
os: Os,
path: &Path,
out: @mut io::Writer) {
- match get_metadata_section(os, path) {
+ // guess the crate name from the pathname
+ let crate_name = path.filename_str().unwrap();
+ let crate_name = if crate_name.starts_with("lib") {
+ crate_name.slice_from(3) } else { crate_name };
+ let crate_name = crate_name.split_iter('-').next().unwrap();
+ match get_metadata_section(sess, os, path, crate_name) {
option::Some(bytes) => decoder::list_crate_metadata(intr, bytes, out),
option::None => {
write!(out, "could not find metadata in {}.\n", path.display())