2012-12-03 18:48:01 -06:00
|
|
|
// Copyright 2012 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.
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
//! Finds crate binaries and loads their metadata
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2013-05-17 17:28:44 -05:00
|
|
|
|
2013-08-25 22:21:13 -05:00
|
|
|
use lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
|
2012-12-23 16:41:37 -06:00
|
|
|
use metadata::decoder;
|
|
|
|
use metadata::encoder;
|
2013-08-23 13:51:45 -05:00
|
|
|
use metadata::filesearch::{FileSearch, FileMatch, FileMatches, FileDoesntMatch};
|
2012-12-23 16:41:37 -06:00
|
|
|
use metadata::filesearch;
|
2013-08-31 11:13:04 -05:00
|
|
|
use syntax::codemap::Span;
|
2012-12-23 16:41:37 -06:00
|
|
|
use syntax::diagnostic::span_handler;
|
2012-09-04 13:54:36 -05:00
|
|
|
use syntax::parse::token::ident_interner;
|
2012-12-23 16:41:37 -06:00
|
|
|
use syntax::print::pprust;
|
|
|
|
use syntax::{ast, attr};
|
2013-07-19 06:51:37 -05:00
|
|
|
use syntax::attr::AttrMetaMethods;
|
2012-12-23 16:41:37 -06:00
|
|
|
|
2013-08-03 19:13:14 -05:00
|
|
|
use std::c_str::ToCStr;
|
2013-06-28 17:32:26 -05:00
|
|
|
use std::cast;
|
|
|
|
use std::io;
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 11:05:17 -05:00
|
|
|
use std::num;
|
2013-06-28 17:32:26 -05:00
|
|
|
use std::option;
|
|
|
|
use std::os::consts::{macos, freebsd, linux, android, win32};
|
|
|
|
use std::ptr;
|
|
|
|
use std::str;
|
|
|
|
use std::vec;
|
2013-08-25 22:21:13 -05:00
|
|
|
use extra::flate;
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2013-08-31 11:13:04 -05:00
|
|
|
pub enum Os {
|
|
|
|
OsMacos,
|
|
|
|
OsWin32,
|
|
|
|
OsLinux,
|
|
|
|
OsAndroid,
|
|
|
|
OsFreebsd
|
2012-05-22 19:16:26 -05:00
|
|
|
}
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2013-02-19 01:40:42 -06:00
|
|
|
pub struct Context {
|
2013-08-11 12:26:59 -05:00
|
|
|
diag: @mut span_handler,
|
2013-03-12 15:00:50 -05:00
|
|
|
filesearch: @FileSearch,
|
2013-08-31 11:13:04 -05:00
|
|
|
span: Span,
|
2013-07-31 15:47:32 -05:00
|
|
|
ident: @str,
|
2013-07-19 06:51:37 -05:00
|
|
|
metas: ~[@ast::MetaItem],
|
2013-06-12 12:02:55 -05:00
|
|
|
hash: @str,
|
2013-08-31 11:13:04 -05:00
|
|
|
os: Os,
|
2013-02-19 01:40:42 -06:00
|
|
|
is_static: bool,
|
2012-09-19 20:50:24 -05:00
|
|
|
intr: @ident_interner
|
2013-02-19 01:40:42 -06:00
|
|
|
}
|
2012-05-22 19:16:26 -05:00
|
|
|
|
2013-08-25 22:21:13 -05:00
|
|
|
pub fn load_library_crate(cx: &Context) -> (~str, @~[u8]) {
|
2012-08-06 14:34:08 -05:00
|
|
|
match find_library_crate(cx) {
|
2013-07-19 06:51:37 -05:00
|
|
|
Some(t) => t,
|
2012-08-20 14:23:37 -05:00
|
|
|
None => {
|
2013-07-02 14:47:32 -05:00
|
|
|
cx.diag.span_fatal(cx.span,
|
|
|
|
fmt!("can't find crate for `%s`",
|
2013-07-31 15:47:32 -05:00
|
|
|
cx.ident));
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-25 22:21:13 -05:00
|
|
|
fn find_library_crate(cx: &Context) -> Option<(~str, @~[u8])> {
|
2013-01-11 17:07:48 -06:00
|
|
|
attr::require_unique_names(cx.diag, cx.metas);
|
2012-05-22 19:48:04 -05:00
|
|
|
find_library_crate_aux(cx, libname(cx), cx.filesearch)
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
|
2013-04-17 11:15:37 -05:00
|
|
|
fn libname(cx: &Context) -> (~str, ~str) {
|
2013-02-19 01:40:42 -06:00
|
|
|
if cx.is_static { return (~"lib", ~".rlib"); }
|
2012-12-20 03:26:27 -06:00
|
|
|
let (dll_prefix, dll_suffix) = match cx.os {
|
2013-08-31 11:13:04 -05:00
|
|
|
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),
|
2012-12-20 03:26:27 -06:00
|
|
|
};
|
2013-02-19 01:40:42 -06:00
|
|
|
|
2013-07-23 08:49:17 -05:00
|
|
|
(dll_prefix.to_owned(), dll_suffix.to_owned())
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
|
2013-03-03 10:50:20 -06:00
|
|
|
fn find_library_crate_aux(
|
2013-04-17 11:15:37 -05:00
|
|
|
cx: &Context,
|
2013-03-03 10:50:20 -06:00
|
|
|
(prefix, suffix): (~str, ~str),
|
2013-03-12 15:00:50 -05:00
|
|
|
filesearch: @filesearch::FileSearch
|
2013-08-25 22:21:13 -05:00
|
|
|
) -> Option<(~str, @~[u8])> {
|
2013-03-03 10:50:20 -06:00
|
|
|
let crate_name = crate_name_from_metas(cx.metas);
|
2013-07-31 15:47:32 -05:00
|
|
|
// want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
|
|
|
|
let prefix = fmt!("%s%s-", prefix, crate_name);
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut matches = ~[];
|
2013-08-23 13:51:45 -05:00
|
|
|
filesearch::search(filesearch, |path| -> FileMatch {
|
2013-07-31 15:47:32 -05:00
|
|
|
let path_str = path.filename();
|
|
|
|
match path_str {
|
2013-08-23 13:51:45 -05:00
|
|
|
None => FileDoesntMatch,
|
2013-07-31 15:47:32 -05:00
|
|
|
Some(path_str) =>
|
|
|
|
if path_str.starts_with(prefix) && path_str.ends_with(suffix) {
|
|
|
|
debug!("%s is a candidate", path.to_str());
|
|
|
|
match get_metadata_section(cx.os, path) {
|
|
|
|
Some(cvec) =>
|
|
|
|
if !crate_matches(cvec, cx.metas, cx.hash) {
|
|
|
|
debug!("skipping %s, metadata doesn't match",
|
|
|
|
path.to_str());
|
2013-08-23 13:51:45 -05:00
|
|
|
FileDoesntMatch
|
2013-07-31 15:47:32 -05:00
|
|
|
} else {
|
|
|
|
debug!("found %s with matching metadata", path.to_str());
|
|
|
|
matches.push((path.to_str(), cvec));
|
2013-08-23 13:51:45 -05:00
|
|
|
FileMatches
|
2013-07-31 15:47:32 -05:00
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
debug!("could not load metadata for %s", path.to_str());
|
2013-08-23 13:51:45 -05:00
|
|
|
FileDoesntMatch
|
2013-07-31 15:47:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2013-08-23 13:51:45 -05:00
|
|
|
FileDoesntMatch
|
2013-07-31 15:47:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2013-06-24 14:38:14 -05:00
|
|
|
match matches.len() {
|
|
|
|
0 => None,
|
|
|
|
1 => Some(matches[0]),
|
|
|
|
_ => {
|
|
|
|
cx.diag.span_err(
|
|
|
|
cx.span, fmt!("multiple matching crates for `%s`", crate_name));
|
|
|
|
cx.diag.handler().note("candidates:");
|
2013-08-03 11:45:23 -05:00
|
|
|
for pair in matches.iter() {
|
2013-06-20 14:26:54 -05:00
|
|
|
let ident = pair.first();
|
|
|
|
let data = pair.second();
|
2013-06-24 14:38:14 -05:00
|
|
|
cx.diag.handler().note(fmt!("path: %s", ident));
|
|
|
|
let attrs = decoder::get_crate_attributes(data);
|
|
|
|
note_linkage_attrs(cx.intr, cx.diag, attrs);
|
|
|
|
}
|
|
|
|
cx.diag.handler().abort_if_errors();
|
|
|
|
None
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
2013-07-31 15:47:32 -05:00
|
|
|
}
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
|
2013-07-19 06:51:37 -05:00
|
|
|
pub fn crate_name_from_metas(metas: &[@ast::MetaItem]) -> @str {
|
2013-08-03 11:45:23 -05:00
|
|
|
for m in metas.iter() {
|
2013-07-19 06:51:37 -05:00
|
|
|
match m.name_str_pair() {
|
|
|
|
Some((name, s)) if "name" == name => { return s; }
|
|
|
|
_ => {}
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
2013-06-24 14:38:14 -05:00
|
|
|
fail!("expected to find the crate name")
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
|
2013-07-31 15:47:32 -05:00
|
|
|
pub fn package_id_from_metas(metas: &[@ast::MetaItem]) -> Option<@str> {
|
|
|
|
for m in metas.iter() {
|
|
|
|
match m.name_str_pair() {
|
|
|
|
Some((name, s)) if "package_id" == name => { return Some(s); }
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2013-03-12 15:00:50 -05:00
|
|
|
pub fn note_linkage_attrs(intr: @ident_interner,
|
2013-08-11 12:26:59 -05:00
|
|
|
diag: @mut span_handler,
|
2013-07-19 06:51:37 -05:00
|
|
|
attrs: ~[ast::Attribute]) {
|
2013-06-21 07:29:53 -05:00
|
|
|
let r = attr::find_linkage_metas(attrs);
|
2013-08-03 11:45:23 -05:00
|
|
|
for mi in r.iter() {
|
2013-06-21 07:29:53 -05:00
|
|
|
diag.handler().note(fmt!("meta: %s", pprust::meta_item_to_str(*mi,intr)));
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-25 22:21:13 -05:00
|
|
|
fn crate_matches(crate_data: @~[u8],
|
2013-07-19 06:51:37 -05:00
|
|
|
metas: &[@ast::MetaItem],
|
2013-06-12 12:02:55 -05:00
|
|
|
hash: @str) -> bool {
|
2012-05-15 22:23:06 -05:00
|
|
|
let attrs = decoder::get_crate_attributes(crate_data);
|
|
|
|
let linkage_metas = attr::find_linkage_metas(attrs);
|
2013-01-24 22:24:57 -06:00
|
|
|
if !hash.is_empty() {
|
2012-05-15 22:23:06 -05:00
|
|
|
let chash = decoder::get_crate_hash(crate_data);
|
2012-07-18 18:18:02 -05:00
|
|
|
if chash != hash { return false; }
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
metadata_matches(linkage_metas, metas)
|
|
|
|
}
|
|
|
|
|
2013-07-19 06:51:37 -05:00
|
|
|
pub fn metadata_matches(extern_metas: &[@ast::MetaItem],
|
|
|
|
local_metas: &[@ast::MetaItem]) -> bool {
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2013-07-31 15:47:32 -05:00
|
|
|
// extern_metas: metas we read from the crate
|
|
|
|
// local_metas: metas we're looking for
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("matching %u metadata requirements against %u items",
|
2013-05-14 04:52:12 -05:00
|
|
|
local_metas.len(), extern_metas.len());
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2013-07-19 06:51:37 -05:00
|
|
|
do local_metas.iter().all |needed| {
|
|
|
|
attr::contains(extern_metas, *needed)
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-31 11:13:04 -05:00
|
|
|
fn get_metadata_section(os: Os,
|
2013-08-25 22:21:13 -05:00
|
|
|
filename: &Path) -> Option<@~[u8]> {
|
2013-01-23 13:43:58 -06:00
|
|
|
unsafe {
|
2013-08-14 21:21:59 -05:00
|
|
|
let mb = do filename.with_c_str |buf| {
|
2013-01-23 13:43:58 -06:00
|
|
|
llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
|
2013-07-22 23:41:46 -05:00
|
|
|
};
|
2013-08-25 22:21:13 -05:00
|
|
|
if mb as int == 0 { return option::None::<@~[u8]>; }
|
|
|
|
let of = match mk_object_file(mb) {
|
2013-01-23 13:43:58 -06:00
|
|
|
option::Some(of) => of,
|
2013-08-25 22:21:13 -05:00
|
|
|
_ => return option::None::<@~[u8]>
|
2013-01-23 13:43:58 -06:00
|
|
|
};
|
2013-08-25 22:21:13 -05:00
|
|
|
let si = mk_section_iter(of.llof);
|
2013-01-23 13:43:58 -06:00
|
|
|
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
|
|
|
|
let name_buf = llvm::LLVMGetSectionName(si.llsi);
|
2013-06-20 00:52:02 -05:00
|
|
|
let name = str::raw::from_c_str(name_buf);
|
2013-05-03 18:20:29 -05:00
|
|
|
debug!("get_metadata_section: name %s", name);
|
2013-08-31 11:13:04 -05:00
|
|
|
if read_meta_section_name(os) == name {
|
2013-01-23 13:43:58 -06:00
|
|
|
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
|
|
|
|
let csz = llvm::LLVMGetSectionSize(si.llsi) as uint;
|
2013-08-25 22:21:13 -05:00
|
|
|
let mut found = None;
|
2013-06-20 00:52:02 -05:00
|
|
|
let cvbuf: *u8 = cast::transmute(cbuf);
|
|
|
|
let vlen = encoder::metadata_encoding_version.len();
|
|
|
|
debug!("checking %u bytes of metadata-version stamp",
|
|
|
|
vlen);
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 11:05:17 -05:00
|
|
|
let minsz = num::min(vlen, csz);
|
2013-06-20 00:52:02 -05:00
|
|
|
let mut version_ok = false;
|
|
|
|
do vec::raw::buf_as_slice(cvbuf, minsz) |buf0| {
|
|
|
|
version_ok = (buf0 ==
|
|
|
|
encoder::metadata_encoding_version);
|
|
|
|
}
|
|
|
|
if !version_ok { return None; }
|
|
|
|
|
2013-08-24 22:57:35 -05:00
|
|
|
let cvbuf1 = ptr::offset(cvbuf, vlen as int);
|
2013-08-25 22:21:13 -05:00
|
|
|
debug!("inflating %u bytes of compressed metadata",
|
|
|
|
csz - vlen);
|
|
|
|
do vec::raw::buf_as_slice(cvbuf1, csz-vlen) |bytes| {
|
|
|
|
let inflated = flate::inflate_bytes(bytes);
|
|
|
|
found = Some(@(inflated));
|
|
|
|
}
|
|
|
|
if found != None {
|
|
|
|
return found;
|
|
|
|
}
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
2013-01-23 13:43:58 -06:00
|
|
|
llvm::LLVMMoveToNextSection(si.llsi);
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
2013-08-25 22:21:13 -05:00
|
|
|
return option::None::<@~[u8]>;
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-31 11:13:04 -05:00
|
|
|
pub fn meta_section_name(os: Os) -> &'static str {
|
2012-08-06 14:34:08 -05:00
|
|
|
match os {
|
2013-08-31 11:13:04 -05:00
|
|
|
OsMacos => "__DATA,__note.rustc",
|
|
|
|
OsWin32 => ".note.rustc",
|
|
|
|
OsLinux => ".note.rustc",
|
|
|
|
OsAndroid => ".note.rustc",
|
|
|
|
OsFreebsd => ".note.rustc"
|
2012-05-22 19:16:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-31 11:13:04 -05:00
|
|
|
pub fn read_meta_section_name(os: Os) -> &'static str {
|
2013-03-13 03:22:01 -05:00
|
|
|
match os {
|
2013-08-31 11:13:04 -05:00
|
|
|
OsMacos => "__note.rustc",
|
|
|
|
OsWin32 => ".note.rustc",
|
|
|
|
OsLinux => ".note.rustc",
|
|
|
|
OsAndroid => ".note.rustc",
|
|
|
|
OsFreebsd => ".note.rustc"
|
2013-03-13 03:22:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-15 22:23:06 -05:00
|
|
|
// A diagnostic function for dumping crate metadata to an output stream
|
2013-01-29 18:51:16 -06:00
|
|
|
pub fn list_file_metadata(intr: @ident_interner,
|
2013-08-31 11:13:04 -05:00
|
|
|
os: Os,
|
2013-03-12 15:00:50 -05:00
|
|
|
path: &Path,
|
|
|
|
out: @io::Writer) {
|
2012-08-06 14:34:08 -05:00
|
|
|
match get_metadata_section(os, path) {
|
2012-08-20 14:23:37 -05:00
|
|
|
option::Some(bytes) => decoder::list_crate_metadata(intr, bytes, out),
|
|
|
|
option::None => {
|
2013-05-29 13:10:16 -05:00
|
|
|
out.write_str(fmt!("could not find metadata in %s.\n", path.to_str()))
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|