2012-05-15 22:23:06 -05:00
|
|
|
#[doc = "
|
|
|
|
|
|
|
|
Finds crate binaries and loads their metadata
|
|
|
|
|
|
|
|
"];
|
|
|
|
|
|
|
|
import driver::session;
|
|
|
|
import session::session;
|
|
|
|
import syntax::{ast, attr};
|
|
|
|
import syntax::print::pprust;
|
|
|
|
import syntax::codemap::span;
|
|
|
|
import lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
|
|
|
|
import util::{filesearch};
|
|
|
|
import io::writer_util;
|
|
|
|
|
2012-05-22 19:16:26 -05:00
|
|
|
export os;
|
|
|
|
export ctxt;
|
2012-05-15 22:23:06 -05:00
|
|
|
export load_library_crate;
|
|
|
|
export list_file_metadata;
|
|
|
|
export note_linkage_attrs;
|
|
|
|
export crate_name_from_metas;
|
|
|
|
export metadata_matches;
|
2012-05-22 19:16:26 -05:00
|
|
|
export meta_section_name;
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2012-05-22 19:16:26 -05:00
|
|
|
enum os {
|
|
|
|
os_macos,
|
|
|
|
os_win32,
|
|
|
|
os_linux,
|
|
|
|
os_freebsd
|
|
|
|
}
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2012-05-22 19:16:26 -05:00
|
|
|
type ctxt = {
|
|
|
|
sess: session,
|
|
|
|
span: span,
|
|
|
|
ident: ast::ident,
|
|
|
|
metas: [@ast::meta_item],
|
|
|
|
hash: str,
|
|
|
|
os: os,
|
|
|
|
static: bool
|
|
|
|
};
|
|
|
|
|
|
|
|
fn load_library_crate(cx: ctxt) -> {ident: str, data: @[u8]} {
|
|
|
|
alt find_library_crate(cx) {
|
2012-05-15 22:23:06 -05:00
|
|
|
some(t) { ret t; }
|
|
|
|
none {
|
2012-05-22 19:16:26 -05:00
|
|
|
cx.sess.span_fatal(
|
|
|
|
cx.span, #fmt["can't find crate for '%s'", cx.ident]);
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-22 19:16:26 -05:00
|
|
|
fn find_library_crate(cx: ctxt) -> option<{ident: str, data: @[u8]}> {
|
|
|
|
attr::require_unique_names(cx.sess.diagnostic(), cx.metas);
|
|
|
|
find_library_crate_aux(cx, libname(cx), cx.sess.filesearch)
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
|
2012-05-22 19:16:26 -05:00
|
|
|
fn libname(cx: ctxt) -> {prefix: str, suffix: str} {
|
|
|
|
if cx.static { ret {prefix: "lib", suffix: ".rlib"}; }
|
|
|
|
alt cx.os {
|
|
|
|
os_win32 { ret {prefix: "", suffix: ".dll"}; }
|
|
|
|
os_macos { ret {prefix: "lib", suffix: ".dylib"}; }
|
|
|
|
os_linux { ret {prefix: "lib", suffix: ".so"}; }
|
|
|
|
os_freebsd { ret {prefix: "lib", suffix: ".so"}; }
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-22 19:16:26 -05:00
|
|
|
fn find_library_crate_aux(cx: ctxt,
|
2012-05-15 22:23:06 -05:00
|
|
|
nn: {prefix: str, suffix: str},
|
|
|
|
filesearch: filesearch::filesearch) ->
|
|
|
|
option<{ident: str, data: @[u8]}> {
|
2012-05-22 19:16:26 -05:00
|
|
|
let crate_name = crate_name_from_metas(cx.metas);
|
2012-05-15 22:23:06 -05:00
|
|
|
let prefix: str = nn.prefix + crate_name + "-";
|
|
|
|
let suffix: str = nn.suffix;
|
|
|
|
|
|
|
|
let mut matches = [];
|
|
|
|
filesearch::search(filesearch, { |path|
|
|
|
|
#debug("inspecting file %s", path);
|
|
|
|
let f: str = path::basename(path);
|
|
|
|
if !(str::starts_with(f, prefix) && str::ends_with(f, suffix)) {
|
|
|
|
#debug("skipping %s, doesn't look like %s*%s", path, prefix,
|
|
|
|
suffix);
|
|
|
|
option::none::<()>
|
|
|
|
} else {
|
|
|
|
#debug("%s is a candidate", path);
|
2012-05-22 19:16:26 -05:00
|
|
|
alt get_metadata_section(cx.os, path) {
|
2012-05-15 22:23:06 -05:00
|
|
|
option::some(cvec) {
|
2012-05-22 19:16:26 -05:00
|
|
|
if !crate_matches(cvec, cx.metas, cx.hash) {
|
2012-05-15 22:23:06 -05:00
|
|
|
#debug("skipping %s, metadata doesn't match", path);
|
|
|
|
option::none::<()>
|
|
|
|
} else {
|
|
|
|
#debug("found %s with matching metadata", path);
|
|
|
|
matches += [{ident: path, data: cvec}];
|
|
|
|
option::none::<()>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ {
|
|
|
|
#debug("could not load metadata for %s", path);
|
|
|
|
option::none::<()>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if matches.is_empty() {
|
|
|
|
none
|
|
|
|
} else if matches.len() == 1u {
|
|
|
|
some(matches[0])
|
|
|
|
} else {
|
2012-05-22 19:16:26 -05:00
|
|
|
cx.sess.span_err(
|
|
|
|
cx.span, #fmt("multiple matching crates for `%s`", crate_name));
|
|
|
|
cx.sess.note("candidates:");
|
2012-05-15 22:23:06 -05:00
|
|
|
for matches.each {|match|
|
2012-05-22 19:16:26 -05:00
|
|
|
cx.sess.note(#fmt("path: %s", match.ident));
|
2012-05-15 22:23:06 -05:00
|
|
|
let attrs = decoder::get_crate_attributes(match.data);
|
2012-05-22 19:16:26 -05:00
|
|
|
note_linkage_attrs(cx.sess, attrs);
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
2012-05-22 19:16:26 -05:00
|
|
|
cx.sess.abort_if_errors();
|
2012-05-15 22:23:06 -05:00
|
|
|
none
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn crate_name_from_metas(metas: [@ast::meta_item]) -> str {
|
|
|
|
let name_items = attr::find_meta_items_by_name(metas, "name");
|
|
|
|
alt vec::last_opt(name_items) {
|
|
|
|
some(i) {
|
|
|
|
alt attr::get_meta_item_value_str(i) {
|
|
|
|
some(n) { n }
|
|
|
|
// FIXME: Probably want a warning here since the user
|
2012-05-18 00:15:07 -05:00
|
|
|
// is using the wrong type of meta item (#2406)
|
2012-05-15 22:23:06 -05:00
|
|
|
_ { fail }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
none { fail "expected to find the crate name" }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn note_linkage_attrs(sess: session::session, attrs: [ast::attribute]) {
|
|
|
|
for attr::find_linkage_attrs(attrs).each {|attr|
|
|
|
|
sess.note(#fmt("meta: %s", pprust::attr_to_str(attr)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn crate_matches(crate_data: @[u8], metas: [@ast::meta_item], hash: str) ->
|
|
|
|
bool {
|
|
|
|
let attrs = decoder::get_crate_attributes(crate_data);
|
|
|
|
let linkage_metas = attr::find_linkage_metas(attrs);
|
|
|
|
if hash.is_not_empty() {
|
|
|
|
let chash = decoder::get_crate_hash(crate_data);
|
|
|
|
if chash != hash { ret false; }
|
|
|
|
}
|
|
|
|
metadata_matches(linkage_metas, metas)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn metadata_matches(extern_metas: [@ast::meta_item],
|
|
|
|
local_metas: [@ast::meta_item]) -> bool {
|
|
|
|
|
|
|
|
#debug("matching %u metadata requirements against %u items",
|
|
|
|
vec::len(local_metas), vec::len(extern_metas));
|
|
|
|
|
|
|
|
#debug("crate metadata:");
|
|
|
|
for extern_metas.each {|have|
|
|
|
|
#debug(" %s", pprust::meta_item_to_str(*have));
|
|
|
|
}
|
|
|
|
|
|
|
|
for local_metas.each {|needed|
|
|
|
|
#debug("looking for %s", pprust::meta_item_to_str(*needed));
|
|
|
|
if !attr::contains(extern_metas, needed) {
|
|
|
|
#debug("missing %s", pprust::meta_item_to_str(*needed));
|
|
|
|
ret false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret true;
|
|
|
|
}
|
|
|
|
|
2012-05-22 19:16:26 -05:00
|
|
|
fn get_metadata_section(os: os,
|
2012-05-15 22:23:06 -05:00
|
|
|
filename: str) -> option<@[u8]> unsafe {
|
|
|
|
let mb = str::as_c_str(filename, {|buf|
|
|
|
|
llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
|
|
|
|
});
|
|
|
|
if mb as int == 0 { ret option::none::<@[u8]>; }
|
|
|
|
let of = alt mk_object_file(mb) {
|
|
|
|
option::some(of) { of }
|
|
|
|
_ { ret option::none::<@[u8]>; }
|
|
|
|
};
|
|
|
|
let si = mk_section_iter(of.llof);
|
|
|
|
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
|
|
|
|
let name_buf = llvm::LLVMGetSectionName(si.llsi);
|
|
|
|
let name = unsafe { str::unsafe::from_c_str(name_buf) };
|
2012-05-22 19:16:26 -05:00
|
|
|
if str::eq(name, meta_section_name(os)) {
|
2012-05-15 22:23:06 -05:00
|
|
|
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
|
|
|
|
let csz = llvm::LLVMGetSectionSize(si.llsi) as uint;
|
|
|
|
unsafe {
|
|
|
|
let cvbuf: *u8 = unsafe::reinterpret_cast(cbuf);
|
|
|
|
ret some(@vec::unsafe::from_buf(cvbuf, csz));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
llvm::LLVMMoveToNextSection(si.llsi);
|
|
|
|
}
|
|
|
|
ret option::none::<@[u8]>;
|
|
|
|
}
|
|
|
|
|
2012-05-22 19:16:26 -05:00
|
|
|
fn meta_section_name(os: os) -> str {
|
|
|
|
alt os {
|
|
|
|
os_macos { "__DATA,__note.rustc" }
|
|
|
|
os_win32 { ".note.rustc" }
|
|
|
|
os_linux { ".note.rustc" }
|
|
|
|
os_freebsd { ".note.rustc" }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-15 22:23:06 -05:00
|
|
|
// A diagnostic function for dumping crate metadata to an output stream
|
2012-05-22 19:16:26 -05:00
|
|
|
fn list_file_metadata(os: os, path: str, out: io::writer) {
|
|
|
|
alt get_metadata_section(os, path) {
|
2012-05-15 22:23:06 -05:00
|
|
|
option::some(bytes) { decoder::list_crate_metadata(bytes, out); }
|
|
|
|
option::none {
|
|
|
|
out.write_str("could not find metadata in " + path + ".\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|