2011-06-27 18:03:01 -05:00
|
|
|
// Extracting metadata from crate files
|
2011-03-15 18:30:43 -05:00
|
|
|
|
2011-05-12 10:24:54 -05:00
|
|
|
import driver::session;
|
2012-01-12 10:59:49 -06:00
|
|
|
import session::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;
|
2011-07-26 09:47:13 -05:00
|
|
|
import syntax::visit;
|
2011-07-05 04:48:19 -05:00
|
|
|
import syntax::codemap::span;
|
2011-11-10 10:41:42 -06:00
|
|
|
import util::{filesearch};
|
2012-01-11 08:15:54 -06:00
|
|
|
import io::writer_util;
|
2012-03-14 14:07:23 -05:00
|
|
|
import std::map::{hashmap, int_hash};
|
2011-07-05 04:48:19 -05:00
|
|
|
import syntax::print::pprust;
|
2011-07-07 14:22:39 -05:00
|
|
|
import common::*;
|
2011-03-15 18:30:43 -05:00
|
|
|
|
2011-06-22 21:04:04 -05:00
|
|
|
export read_crates;
|
|
|
|
export list_file_metadata;
|
2011-03-15 19:33:05 -05:00
|
|
|
|
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.
|
2011-09-12 04:27:30 -05:00
|
|
|
fn read_crates(sess: session::session, crate: ast::crate) {
|
2012-01-09 09:24:53 -06:00
|
|
|
let e = @{sess: sess,
|
2012-03-14 14:07:23 -05:00
|
|
|
crate_cache: std::map::str_hash::<int>(),
|
2012-01-09 09:24:53 -06:00
|
|
|
mutable next_crate_num: 1};
|
2011-07-27 07:19:39 -05:00
|
|
|
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()});
|
2011-07-26 09:47:13 -05:00
|
|
|
visit::visit_crate(crate, (), v);
|
2011-07-07 23:03:09 -05:00
|
|
|
}
|
|
|
|
|
2012-01-09 09:24:53 -06:00
|
|
|
type env = @{sess: session::session,
|
|
|
|
crate_cache: hashmap<str, int>,
|
|
|
|
mutable next_crate_num: ast::crate_num};
|
2011-07-07 23:37:56 -05:00
|
|
|
|
2011-09-12 04:27:30 -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);
|
2012-01-12 10:59:49 -06:00
|
|
|
cstore::add_use_stmt_cnum(e.sess.cstore, id, cnum);
|
2011-07-27 07:19:39 -05:00
|
|
|
}
|
|
|
|
_ { }
|
2011-07-07 23:37:56 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 04:27:30 -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) {
|
2011-11-20 12:15:40 -06:00
|
|
|
alt attr::native_abi(i.attrs) {
|
|
|
|
either::right(abi) {
|
|
|
|
if abi != ast::native_abi_cdecl &&
|
|
|
|
abi != ast::native_abi_stdcall { ret; }
|
|
|
|
}
|
|
|
|
either::left(msg) { e.sess.span_fatal(i.span, msg); }
|
2011-07-07 23:37:56 -05:00
|
|
|
}
|
2011-12-15 14:25:29 -06:00
|
|
|
|
2012-01-12 10:59:49 -06:00
|
|
|
let cstore = e.sess.cstore;
|
2012-01-11 21:27:08 -06:00
|
|
|
let native_name =
|
|
|
|
alt attr::get_meta_item_value_str_by_name(i.attrs, "link_name") {
|
|
|
|
some(nn) {
|
|
|
|
if nn == "" {
|
|
|
|
e.sess.span_fatal(
|
|
|
|
i.span,
|
|
|
|
"empty #[link_name] not allowed; use #[nolink].");
|
|
|
|
}
|
|
|
|
nn
|
|
|
|
}
|
2012-01-19 00:37:22 -06:00
|
|
|
none { i.ident }
|
2012-01-11 21:27:08 -06:00
|
|
|
};
|
2011-12-16 10:04:11 -06:00
|
|
|
let already_added = false;
|
|
|
|
if vec::len(attr::find_attrs_by_name(i.attrs, "nolink")) == 0u {
|
|
|
|
already_added = !cstore::add_used_library(cstore, native_name);
|
2011-11-16 22:49:38 -06:00
|
|
|
}
|
2011-12-16 10:04:11 -06:00
|
|
|
let link_args = attr::find_attrs_by_name(i.attrs, "link_args");
|
|
|
|
if vec::len(link_args) > 0u && already_added {
|
|
|
|
e.sess.span_fatal(i.span, "library '" + native_name +
|
|
|
|
"' already added: can't specify link_args.");
|
2011-12-15 14:25:29 -06:00
|
|
|
}
|
2011-12-16 10:04:11 -06:00
|
|
|
for a: ast::attribute in link_args {
|
2011-07-27 07:19:39 -05:00
|
|
|
alt attr::get_meta_item_value_str(attr::attr_meta(a)) {
|
2011-12-16 10:04:11 -06:00
|
|
|
some(linkarg) {
|
|
|
|
cstore::add_used_link_args(cstore, linkarg);
|
|
|
|
}
|
2012-01-19 00:37:22 -06:00
|
|
|
none {/* fallthrough */ }
|
2011-07-27 07:19:39 -05:00
|
|
|
}
|
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
|
2011-10-12 14:29:08 -05:00
|
|
|
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); }
|
2012-01-19 00:37:22 -06:00
|
|
|
option::none {
|
2012-03-05 18:27:27 -06: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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 04:27:30 -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);
|
2011-06-28 14:53:59 -05:00
|
|
|
|
2011-12-22 18:13:40 -06:00
|
|
|
#debug("matching %u metadata requirements against %u items",
|
|
|
|
vec::len(metas), vec::len(linkage_metas));
|
2011-06-28 14:53:59 -05:00
|
|
|
|
2011-12-22 16:42:52 -06:00
|
|
|
#debug("crate metadata:");
|
2011-10-29 17:04:44 -05:00
|
|
|
for have: @ast::meta_item in linkage_metas {
|
2011-12-22 16:42:52 -06:00
|
|
|
#debug(" %s", pprust::meta_item_to_str(*have));
|
2011-10-29 17:04:44 -05:00
|
|
|
}
|
|
|
|
|
2011-08-15 23:54:52 -05:00
|
|
|
for needed: @ast::meta_item in metas {
|
2011-12-22 16:42:52 -06:00
|
|
|
#debug("looking for %s", pprust::meta_item_to_str(*needed));
|
2011-07-27 07:19:39 -05:00
|
|
|
if !attr::contains(linkage_metas, needed) {
|
2011-12-22 16:42:52 -06:00
|
|
|
#debug("missing %s", pprust::meta_item_to_str(*needed));
|
2011-06-28 14:53:59 -05:00
|
|
|
ret false;
|
2011-06-10 17:54:41 -05:00
|
|
|
}
|
|
|
|
}
|
2011-06-10 14:56:42 -05:00
|
|
|
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"}; }
|
2012-01-12 10:59:49 -06:00
|
|
|
alt sess.targ_cfg.os {
|
2012-01-19 03:03:57 -06:00
|
|
|
session::os_win32 { ret {prefix: "", suffix: ".dll"}; }
|
|
|
|
session::os_macos { ret {prefix: "lib", suffix: ".dylib"}; }
|
|
|
|
session::os_linux { ret {prefix: "lib", suffix: ".so"}; }
|
|
|
|
session::os_freebsd { ret {prefix: "lib", suffix: ".so"}; }
|
2011-06-27 14:24:44 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 04:27:30 -05:00
|
|
|
fn find_library_crate(sess: session::session, ident: ast::ident,
|
2011-10-03 15:13:21 -05:00
|
|
|
metas: [@ast::meta_item])
|
2012-01-31 19:05:20 -06:00
|
|
|
-> option<{ident: str, data: @[u8]}> {
|
2011-06-28 18:52:11 -05:00
|
|
|
|
2011-07-05 17:58:48 -05:00
|
|
|
attr::require_unique_names(sess, metas);
|
2011-11-03 04:57:54 -05:00
|
|
|
let metas = metas;
|
2011-07-05 17:58:48 -05:00
|
|
|
|
2011-11-18 02:00:28 -06:00
|
|
|
let crate_name =
|
|
|
|
{
|
|
|
|
let name_items = attr::find_meta_items_by_name(metas, "name");
|
2012-03-08 17:24:27 -06:00
|
|
|
alt vec::last_opt(name_items) {
|
2011-11-18 02:00:28 -06:00
|
|
|
some(i) {
|
|
|
|
alt attr::get_meta_item_value_str(i) {
|
|
|
|
some(n) { n }
|
|
|
|
// FIXME: Probably want a warning here since the user
|
|
|
|
// is using the wrong type of meta item
|
|
|
|
_ { ident }
|
|
|
|
}
|
|
|
|
}
|
2012-01-19 00:37:22 -06:00
|
|
|
none { ident }
|
2011-11-18 02:00:28 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-01-12 10:59:49 -06:00
|
|
|
let nn = default_native_lib_naming(sess, sess.opts.static);
|
2011-07-27 07:19:39 -05:00
|
|
|
let x =
|
2011-11-18 02:00:28 -06:00
|
|
|
find_library_crate_aux(sess, nn, crate_name,
|
2012-01-12 10:59:49 -06:00
|
|
|
metas, sess.filesearch);
|
|
|
|
if x != none || sess.opts.static { ret x; }
|
2011-07-27 07:19:39 -05:00
|
|
|
let nn2 = default_native_lib_naming(sess, true);
|
2011-11-18 02:00:28 -06:00
|
|
|
ret find_library_crate_aux(sess, nn2, crate_name, metas,
|
2012-01-12 10:59:49 -06:00
|
|
|
sess.filesearch);
|
2011-07-08 14:33:00 -05:00
|
|
|
}
|
|
|
|
|
2011-10-12 14:29:08 -05:00
|
|
|
fn find_library_crate_aux(sess: session::session,
|
|
|
|
nn: {prefix: str, suffix: str},
|
2011-11-18 02:00:28 -06:00
|
|
|
crate_name: str,
|
2011-09-12 04:27:30 -05:00
|
|
|
metas: [@ast::meta_item],
|
2011-10-03 15:54:13 -05:00
|
|
|
filesearch: filesearch::filesearch) ->
|
2012-01-31 19:05:20 -06:00
|
|
|
option<{ident: str, data: @[u8]}> {
|
2011-12-02 10:51:59 -06:00
|
|
|
let prefix: str = nn.prefix + crate_name + "-";
|
2011-09-02 17:34:58 -05:00
|
|
|
let suffix: str = nn.suffix;
|
2011-10-03 15:54:13 -05:00
|
|
|
|
|
|
|
ret filesearch::search(filesearch, { |path|
|
2011-12-22 16:42:52 -06:00
|
|
|
#debug("inspecting file %s", path);
|
2012-03-12 22:04:27 -05:00
|
|
|
let f: str = path::basename(path);
|
2011-10-03 15:54:13 -05:00
|
|
|
if !(str::starts_with(f, prefix) && str::ends_with(f, suffix)) {
|
2011-12-22 18:13:40 -06:00
|
|
|
#debug("skipping %s, doesn't look like %s*%s", path, prefix,
|
|
|
|
suffix);
|
2011-10-03 15:54:13 -05:00
|
|
|
option::none
|
|
|
|
} else {
|
2011-12-22 16:42:52 -06:00
|
|
|
#debug("%s is a candidate", path);
|
2011-10-12 14:29:08 -05:00
|
|
|
alt get_metadata_section(sess, path) {
|
2011-07-27 07:19:39 -05:00
|
|
|
option::some(cvec) {
|
|
|
|
if !metadata_matches(cvec, metas) {
|
2011-12-22 16:42:52 -06:00
|
|
|
#debug("skipping %s, metadata doesn't match", path);
|
2011-10-03 15:54:13 -05:00
|
|
|
option::none
|
|
|
|
} else {
|
2011-12-22 16:42:52 -06:00
|
|
|
#debug("found %s with matching metadata", path);
|
2011-10-03 15:54:13 -05:00
|
|
|
option::some({ident: path, data: cvec})
|
2011-06-10 14:56:42 -05:00
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
}
|
2011-10-29 17:04:44 -05:00
|
|
|
_ {
|
2011-12-22 16:42:52 -06:00
|
|
|
#debug("could not load metadata for %s", path);
|
2011-10-29 17:04:44 -05:00
|
|
|
option::none
|
|
|
|
}
|
2011-03-24 19:21:09 -05:00
|
|
|
}
|
|
|
|
}
|
2011-10-03 15:54:13 -05:00
|
|
|
});
|
2011-06-10 14:56:42 -05:00
|
|
|
}
|
2011-03-15 19:33:05 -05:00
|
|
|
|
2011-10-12 14:29:08 -05:00
|
|
|
fn get_metadata_section(sess: session::session,
|
2012-01-31 19:05:20 -06:00
|
|
|
filename: str) -> option<@[u8]> unsafe {
|
2012-03-14 17:10:34 -05:00
|
|
|
let mb = str::as_c_str(filename, {|buf|
|
2011-10-12 15:31:41 -05:00
|
|
|
llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
|
|
|
|
});
|
|
|
|
if mb as int == 0 { ret option::none::<@[u8]>; }
|
2011-11-06 20:29:16 -06:00
|
|
|
let of = alt mk_object_file(mb) {
|
|
|
|
option::some(of) { of }
|
|
|
|
_ { ret option::none::<@[u8]>; }
|
|
|
|
};
|
2011-10-12 15:31:41 -05:00
|
|
|
let si = mk_section_iter(of.llof);
|
|
|
|
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
|
|
|
|
let name_buf = llvm::LLVMGetSectionName(si.llsi);
|
2012-03-14 17:10:34 -05:00
|
|
|
let name = unsafe { str::from_c_str(name_buf) };
|
2012-01-12 10:59:49 -06:00
|
|
|
if str::eq(name, sess.targ_cfg.target_strs.meta_sect_name) {
|
2011-10-12 15:31:41 -05:00
|
|
|
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
|
2012-01-16 04:21:01 -06:00
|
|
|
let csz = llvm::LLVMGetSectionSize(si.llsi) as uint;
|
2011-10-12 14:29:08 -05:00
|
|
|
unsafe {
|
2011-12-13 18:25:51 -06:00
|
|
|
let cvbuf: *u8 = unsafe::reinterpret_cast(cbuf);
|
2012-03-14 17:10:34 -05:00
|
|
|
ret some(@vec::unsafe::from_buf(cvbuf, csz));
|
2011-10-12 14:29:08 -05:00
|
|
|
}
|
2011-06-27 17:30:17 -05:00
|
|
|
}
|
2011-10-12 15:31:41 -05:00
|
|
|
llvm::LLVMMoveToNextSection(si.llsi);
|
2011-06-27 17:30:17 -05:00
|
|
|
}
|
2011-10-12 15:31:41 -05:00
|
|
|
ret option::none::<@[u8]>;
|
2011-06-27 17:30:17 -05:00
|
|
|
}
|
|
|
|
|
2011-09-12 04:27:30 -05:00
|
|
|
fn load_library_crate(sess: session::session, span: span, ident: ast::ident,
|
2011-10-03 15:13:21 -05:00
|
|
|
metas: [@ast::meta_item])
|
2011-09-02 17:34:58 -05:00
|
|
|
-> {ident: str, data: @[u8]} {
|
2011-07-08 14:40:16 -05:00
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
|
2011-10-03 15:13:21 -05:00
|
|
|
alt find_library_crate(sess, ident, metas) {
|
2011-07-27 07:19:39 -05:00
|
|
|
some(t) { ret t; }
|
2012-01-19 00:37:22 -06:00
|
|
|
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
|
|
|
}
|
2011-06-10 14:56:42 -05:00
|
|
|
}
|
2011-03-15 19:33:05 -05:00
|
|
|
}
|
2011-03-15 18:30:43 -05:00
|
|
|
|
2011-09-12 04:27:30 -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 =
|
2011-10-03 15:13:21 -05:00
|
|
|
load_library_crate(e.sess, span, ident, metas);
|
2011-07-08 14:40:16 -05:00
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
let cfilename = cinfo.ident;
|
|
|
|
let cdata = cinfo.data;
|
2011-07-08 14:40:16 -05:00
|
|
|
|
2011-07-08 14:55:38 -05:00
|
|
|
// 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);
|
2011-07-08 14:04:52 -05:00
|
|
|
e.next_crate_num += 1;
|
2011-07-08 14:40:16 -05:00
|
|
|
|
2011-07-08 14:55:38 -05:00
|
|
|
// 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-07-08 14:55:38 -05:00
|
|
|
|
2012-01-05 09:04:59 -06:00
|
|
|
let cmeta = @{name: ident, data: cdata,
|
|
|
|
cnum_map: cnum_map, cnum: cnum};
|
2011-07-08 14:55:38 -05:00
|
|
|
|
2012-01-12 10:59:49 -06:00
|
|
|
let cstore = e.sess.cstore;
|
2011-07-08 14:40:16 -05:00
|
|
|
cstore::set_crate_data(cstore, cnum, cmeta);
|
2011-09-02 17:34:58 -05:00
|
|
|
cstore::add_used_crate_file(cstore, cfilename);
|
2011-07-08 14:04:52 -05:00
|
|
|
ret cnum;
|
2011-08-25 19:00:12 -05:00
|
|
|
} else { ret e.crate_cache.get(ident); }
|
2011-07-08 14:55:38 -05:00
|
|
|
}
|
2011-05-26 19:16:54 -05:00
|
|
|
|
2011-07-08 14:55:38 -05:00
|
|
|
// Go through the crate metadata and load any crates that it references
|
2011-09-12 04:27:30 -05:00
|
|
|
fn resolve_crate_deps(e: env, cdata: @[u8]) -> cstore::cnum_map {
|
2011-12-22 16:42:52 -06:00
|
|
|
#debug("resolving deps of external crate");
|
2011-07-08 14:55:38 -05:00
|
|
|
// The map from crate numbers in the crate we're resolving to local crate
|
|
|
|
// numbers
|
2012-03-14 14:07:23 -05:00
|
|
|
let cnum_map = int_hash::<ast::crate_num>();
|
2011-08-15 23:54:52 -05:00
|
|
|
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;
|
2011-12-22 16:42:52 -06:00
|
|
|
#debug("resolving dep %s", cname);
|
2011-08-27 00:48:10 -05:00
|
|
|
if e.crate_cache.contains_key(cname) {
|
2011-12-22 16:42:52 -06:00
|
|
|
#debug("already have it");
|
2011-07-08 14:55:38 -05:00
|
|
|
// We've already seen this crate
|
2011-08-27 00:48:10 -05:00
|
|
|
let local_cnum = e.crate_cache.get(cname);
|
2011-07-08 14:55:38 -05:00
|
|
|
cnum_map.insert(extrn_cnum, local_cnum);
|
|
|
|
} else {
|
2011-12-22 16:42:52 -06:00
|
|
|
#debug("need to load it");
|
2011-07-08 14:55:38 -05:00
|
|
|
// This is a new one so we've got to load it
|
|
|
|
// FIXME: Need better error reporting than just a bogus span
|
2011-08-21 23:44:41 -05:00
|
|
|
let fake_span = ast_util::dummy_sp();
|
2011-09-02 17:34:58 -05:00
|
|
|
let local_cnum = resolve_crate(e, cname, [], fake_span);
|
2011-07-08 14:55:38 -05:00
|
|
|
cnum_map.insert(extrn_cnum, local_cnum);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret cnum_map;
|
|
|
|
}
|
2011-04-07 13:20:57 -05:00
|
|
|
|
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
|
|
|
|
// End:
|