rust/src/comp/metadata/creader.rs

269 lines
9.4 KiB
Rust
Raw Normal View History

2011-06-27 18:03:01 -05:00
// Extracting metadata from crate files
import driver::session;
2011-09-12 18:13:28 -05:00
import syntax::{ast, ast_util};
import lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
2011-06-30 01:42:35 -05:00
import front::attr;
import middle::resolve;
import syntax::visit;
import syntax::codemap::span;
import back::x86;
import util::{common, filesearch};
2011-09-12 18:13:28 -05:00
import std::{vec, str, fs, io, option};
import std::option::{none, some};
import std::map::{hashmap, new_int_hash};
import syntax::print::pprust;
import common::*;
2011-06-22 21:04:04 -05:00
export read_crates;
export list_file_metadata;
2011-07-07 23:03:09 -05:00
// Traverses an AST, reading all the information about use'd crates and native
// libraries necessary for later resolving, typechecking, linking, etc.
fn read_crates(sess: session::session, crate: ast::crate) {
2011-07-27 07:19:39 -05:00
let e =
@{sess: sess,
crate_cache: @std::map::new_str_hash::<int>(),
2011-07-27 07:19:39 -05:00
mutable next_crate_num: 1};
let v =
visit::mk_simple_visitor(@{visit_view_item:
bind visit_view_item(e, _),
visit_item: bind visit_item(e, _)
with *visit::default_simple_visitor()});
visit::visit_crate(crate, (), v);
2011-07-07 23:03:09 -05:00
}
2011-07-07 23:37:56 -05:00
type env =
2011-07-27 07:19:39 -05:00
@{sess: session::session,
2011-09-02 17:34:58 -05:00
crate_cache: @hashmap<str, int>,
2011-07-27 07:19:39 -05:00
mutable next_crate_num: ast::crate_num};
2011-07-07 23:37:56 -05:00
fn visit_view_item(e: env, i: @ast::view_item) {
2011-07-27 07:19:39 -05:00
alt i.node {
ast::view_item_use(ident, meta_items, id) {
let cnum = resolve_crate(e, ident, meta_items, i.span);
cstore::add_use_stmt_cnum(e.sess.get_cstore(), id, cnum);
}
_ { }
2011-07-07 23:37:56 -05:00
}
}
fn visit_item(e: env, i: @ast::item) {
2011-07-27 07:19:39 -05:00
alt i.node {
ast::item_native_mod(m) {
if m.abi != ast::native_abi_rust && m.abi != ast::native_abi_cdecl &&
2011-10-03 15:59:38 -05:00
m.abi != ast::native_abi_c_stack_cdecl &&
m.abi != ast::native_abi_c_stack_stdcall {
2011-07-27 07:19:39 -05:00
ret;
2011-07-07 23:37:56 -05:00
}
2011-07-27 07:19:39 -05:00
let cstore = e.sess.get_cstore();
2011-09-02 17:34:58 -05:00
if !cstore::add_used_library(cstore, m.native_name) { ret; }
for a: ast::attribute in
2011-09-02 17:34:58 -05:00
attr::find_attrs_by_name(i.attrs, "link_args") {
2011-07-27 07:19:39 -05:00
alt attr::get_meta_item_value_str(attr::attr_meta(a)) {
2011-09-02 17:34:58 -05:00
some(linkarg) { cstore::add_used_link_args(cstore, linkarg); }
2011-07-27 07:19:39 -05:00
none. {/* fallthrough */ }
}
2011-07-07 23:37:56 -05:00
}
2011-07-27 07:19:39 -05:00
}
_ { }
2011-07-07 23:37:56 -05:00
}
}
2011-07-07 23:03:09 -05:00
// A diagnostic function for dumping crate metadata to an output stream
fn list_file_metadata(sess: session::session, path: str, out: io::writer) {
alt get_metadata_section(sess, path) {
2011-07-27 07:19:39 -05:00
option::some(bytes) { decoder::list_crate_metadata(bytes, out); }
option::none. {
2011-09-02 17:34:58 -05:00
out.write_str("Could not find metadata in " + path + ".\n");
2011-07-27 07:19:39 -05:00
}
2011-07-07 23:03:09 -05:00
}
}
fn metadata_matches(crate_data: @[u8], metas: [@ast::meta_item]) -> bool {
2011-07-27 07:19:39 -05:00
let attrs = decoder::get_crate_attributes(crate_data);
let linkage_metas = attr::find_linkage_metas(attrs);
log #fmt["matching %u metadata requirements against %u items",
vec::len(metas), vec::len(linkage_metas)];
2011-10-29 17:04:44 -05:00
log #fmt("crate metadata:");
for have: @ast::meta_item in linkage_metas {
log #fmt(" %s", pprust::meta_item_to_str(*have));
}
for needed: @ast::meta_item in metas {
2011-10-29 17:04:44 -05:00
log #fmt["looking for %s", pprust::meta_item_to_str(*needed)];
2011-07-27 07:19:39 -05:00
if !attr::contains(linkage_metas, needed) {
2011-09-02 17:34:58 -05:00
log #fmt["missing %s", pprust::meta_item_to_str(*needed)];
ret false;
}
}
ret true;
}
2011-07-27 07:19:39 -05:00
fn default_native_lib_naming(sess: session::session, static: bool) ->
2011-09-02 17:34:58 -05:00
{prefix: str, suffix: str} {
if static { ret {prefix: "lib", suffix: ".rlib"}; }
2011-07-27 07:19:39 -05:00
alt sess.get_targ_cfg().os {
2011-09-02 17:34:58 -05:00
session::os_win32. { ret {prefix: "", suffix: ".dll"}; }
session::os_macos. { ret {prefix: "lib", suffix: ".dylib"}; }
session::os_linux. { ret {prefix: "lib", suffix: ".so"}; }
}
}
fn find_library_crate(sess: session::session, ident: ast::ident,
metas: [@ast::meta_item])
2011-09-02 17:34:58 -05:00
-> option::t<{ident: str, data: @[u8]}> {
2011-06-28 18:52:11 -05:00
attr::require_unique_names(sess, metas);
// Metadata "name" will be used to find the crate. Use `ident'
// as "name" if the attribute is not explicitly specified
if !attr::contains_name(metas, "name") {
metas += [attr::mk_name_value_item_str("name", ident)];
}
2011-07-27 07:19:39 -05:00
let nn = default_native_lib_naming(sess, sess.get_opts().static);
let x =
find_library_crate_aux(sess, nn, metas, sess.filesearch());
2011-07-27 07:19:39 -05:00
if x != none || sess.get_opts().static { ret x; }
let nn2 = default_native_lib_naming(sess, true);
ret find_library_crate_aux(sess, nn2, metas, sess.filesearch());
}
fn find_library_crate_aux(sess: session::session,
nn: {prefix: str, suffix: str},
metas: [@ast::meta_item],
filesearch: filesearch::filesearch) ->
2011-09-02 17:34:58 -05:00
option::t<{ident: str, data: @[u8]}> {
let prefix: str = nn.prefix;
2011-09-02 17:34:58 -05:00
let suffix: str = nn.suffix;
ret filesearch::search(filesearch, { |path|
2011-10-29 17:04:44 -05:00
log #fmt("inspecting file %s", path);
let f: str = fs::basename(path);
if !(str::starts_with(f, prefix) && str::ends_with(f, suffix)) {
log #fmt["skipping %s, doesn't look like %s*%s", path, prefix,
suffix];
option::none
} else {
2011-10-29 17:04:44 -05:00
log #fmt("%s is a candidate", path);
alt get_metadata_section(sess, path) {
2011-07-27 07:19:39 -05:00
option::some(cvec) {
if !metadata_matches(cvec, metas) {
2011-09-02 17:34:58 -05:00
log #fmt["skipping %s, metadata doesn't match", path];
option::none
} else {
log #fmt["found %s with matching metadata", path];
option::some({ident: path, data: cvec})
}
2011-07-27 07:19:39 -05:00
}
2011-10-29 17:04:44 -05:00
_ {
log #fmt("could not load metadata for %s", path);
option::none
}
}
}
});
}
fn get_metadata_section(sess: session::session,
2011-10-25 15:13:55 -05:00
filename: str) -> option::t<@[u8]> unsafe {
let mb = str::as_buf(filename, {|buf|
llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
});
if mb as int == 0 { ret option::none::<@[u8]>; }
let of = mk_object_file(mb);
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::str_from_cstr(name_buf) };
if str::eq(name, sess.get_targ_cfg().target_strs.meta_sect_name) {
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
let csz = llvm::LLVMGetSectionSize(si.llsi);
unsafe {
let cvbuf: *u8 = std::unsafe::reinterpret_cast(cbuf);
ret option::some::<@[u8]>(@vec::unsafe::from_buf(cvbuf, csz));
}
}
llvm::LLVMMoveToNextSection(si.llsi);
}
ret option::none::<@[u8]>;
}
fn load_library_crate(sess: session::session, span: span, ident: ast::ident,
metas: [@ast::meta_item])
2011-09-02 17:34:58 -05:00
-> {ident: str, data: @[u8]} {
2011-07-27 07:19:39 -05:00
alt find_library_crate(sess, ident, metas) {
2011-07-27 07:19:39 -05:00
some(t) { ret t; }
none. {
2011-09-02 17:34:58 -05:00
sess.span_fatal(span, #fmt["can't find crate for '%s'", ident]);
2011-07-27 07:19:39 -05:00
}
}
}
fn resolve_crate(e: env, ident: ast::ident, metas: [@ast::meta_item],
2011-07-27 07:19:39 -05:00
span: span) -> ast::crate_num {
2011-08-25 19:00:12 -05:00
if !e.crate_cache.contains_key(ident) {
2011-07-27 07:19:39 -05:00
let cinfo =
load_library_crate(e.sess, span, ident, metas);
2011-07-27 07:19:39 -05:00
let cfilename = cinfo.ident;
let cdata = cinfo.data;
// Claim this crate number and cache it
2011-07-27 07:19:39 -05:00
let cnum = e.next_crate_num;
2011-08-25 19:00:12 -05:00
e.crate_cache.insert(ident, cnum);
e.next_crate_num += 1;
// Now resolve the crates referenced by this crate
2011-07-27 07:19:39 -05:00
let cnum_map = resolve_crate_deps(e, cdata);
2011-09-02 17:34:58 -05:00
let cmeta = {name: ident, data: cdata, cnum_map: cnum_map};
2011-07-27 07:19:39 -05:00
let cstore = e.sess.get_cstore();
cstore::set_crate_data(cstore, cnum, cmeta);
2011-09-02 17:34:58 -05:00
cstore::add_used_crate_file(cstore, cfilename);
ret cnum;
2011-08-25 19:00:12 -05:00
} else { ret e.crate_cache.get(ident); }
}
// Go through the crate metadata and load any crates that it references
fn resolve_crate_deps(e: env, cdata: @[u8]) -> cstore::cnum_map {
log "resolving deps of external crate";
// The map from crate numbers in the crate we're resolving to local crate
// numbers
let cnum_map = new_int_hash::<ast::crate_num>();
for dep: decoder::crate_dep in decoder::get_crate_deps(cdata) {
2011-07-27 07:19:39 -05:00
let extrn_cnum = dep.cnum;
let cname = dep.ident;
log #fmt["resolving dep %s", cname];
if e.crate_cache.contains_key(cname) {
log "already have it";
// We've already seen this crate
let local_cnum = e.crate_cache.get(cname);
cnum_map.insert(extrn_cnum, local_cnum);
} else {
log "need to load it";
// This is a new one so we've got to load it
// FIXME: Need better error reporting than just a bogus span
let fake_span = ast_util::dummy_sp();
2011-09-02 17:34:58 -05:00
let local_cnum = resolve_crate(e, cname, [], fake_span);
cnum_map.insert(extrn_cnum, local_cnum);
}
}
ret cnum_map;
}
2011-03-24 19:35:27 -05:00
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
2011-03-24 19:35:27 -05:00
// End: