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;
|
2011-07-05 04:48:19 -05:00
|
|
|
import syntax::ast;
|
2011-05-12 10:24:54 -05:00
|
|
|
import lib::llvm::False;
|
|
|
|
import lib::llvm::llvm;
|
|
|
|
import lib::llvm::mk_object_file;
|
|
|
|
import lib::llvm::mk_section_iter;
|
2011-06-30 01:42:35 -05:00
|
|
|
import front::attr;
|
2011-05-26 19:16:54 -05:00
|
|
|
import middle::resolve;
|
2011-07-05 04:48:19 -05:00
|
|
|
import syntax::walk;
|
|
|
|
import syntax::codemap::span;
|
2011-05-12 10:24:54 -05:00
|
|
|
import back::x86;
|
|
|
|
import util::common;
|
2011-07-05 19:57:34 -05:00
|
|
|
import std::ivec;
|
2011-05-17 13:41:41 -05:00
|
|
|
import std::str;
|
|
|
|
import std::vec;
|
2011-05-12 10:24:54 -05:00
|
|
|
import std::ebml;
|
|
|
|
import std::fs;
|
|
|
|
import std::io;
|
|
|
|
import std::option;
|
|
|
|
import std::option::none;
|
|
|
|
import std::option::some;
|
|
|
|
import std::map::hashmap;
|
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-07-07 23:37:56 -05:00
|
|
|
fn read_crates(session::session sess,
|
2011-07-07 23:03:09 -05:00
|
|
|
&ast::crate crate) {
|
|
|
|
auto e =
|
|
|
|
@rec(sess=sess,
|
|
|
|
crate_cache=@std::map::new_str_hash[int](),
|
|
|
|
library_search_paths=sess.get_opts().library_search_paths,
|
|
|
|
mutable next_crate_num=1);
|
|
|
|
auto v =
|
|
|
|
rec(visit_view_item_pre=bind visit_view_item(e, _),
|
|
|
|
visit_item_pre=bind visit_item(e, _)
|
|
|
|
with walk::default_visitor());
|
|
|
|
walk::walk_crate(v, crate);
|
|
|
|
}
|
|
|
|
|
2011-07-07 23:37:56 -05:00
|
|
|
type env =
|
|
|
|
@rec(session::session sess,
|
|
|
|
@hashmap[str, int] crate_cache,
|
|
|
|
vec[str] library_search_paths,
|
2011-07-08 00:01:38 -05:00
|
|
|
mutable ast::crate_num next_crate_num);
|
2011-07-07 23:37:56 -05:00
|
|
|
|
|
|
|
fn visit_view_item(env e, &@ast::view_item i) {
|
|
|
|
alt (i.node) {
|
|
|
|
case (ast::view_item_use(?ident, ?meta_items, ?id)) {
|
|
|
|
auto cnum;
|
|
|
|
if (!e.crate_cache.contains_key(ident)) {
|
|
|
|
cnum = e.next_crate_num;
|
|
|
|
load_library_crate(e.sess, i.span, cnum, ident,
|
|
|
|
meta_items, e.library_search_paths);
|
|
|
|
e.crate_cache.insert(ident, e.next_crate_num);
|
|
|
|
e.next_crate_num += 1;
|
|
|
|
} else { cnum = e.crate_cache.get(ident); }
|
|
|
|
cstore::add_use_stmt_cnum(e.sess.get_cstore(), id, cnum);
|
|
|
|
}
|
|
|
|
case (_) { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_item(env e, &@ast::item i) {
|
|
|
|
alt (i.node) {
|
|
|
|
case (ast::item_native_mod(?m)) {
|
|
|
|
if (m.abi != ast::native_abi_rust &&
|
|
|
|
m.abi != ast::native_abi_cdecl) {
|
|
|
|
ret;
|
|
|
|
}
|
|
|
|
auto cstore = e.sess.get_cstore();
|
|
|
|
if (!cstore::add_used_library(cstore, m.native_name)) {
|
|
|
|
ret;
|
|
|
|
}
|
|
|
|
for (ast::attribute a in
|
|
|
|
attr::find_attrs_by_name(i.attrs, "link_args")) {
|
|
|
|
alt (attr::get_meta_item_value_str(attr::attr_meta(a))) {
|
|
|
|
case (some(?linkarg)) {
|
|
|
|
cstore::add_used_link_args(cstore, linkarg);
|
|
|
|
}
|
|
|
|
case (none) { /* fallthrough */ }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-07 23:03:09 -05:00
|
|
|
// A diagnostic function for dumping crate metadata to an output stream
|
|
|
|
fn list_file_metadata(str path, io::writer out) {
|
|
|
|
alt (get_metadata_section(path)) {
|
|
|
|
case (option::some(?bytes)) {
|
|
|
|
decoder::list_crate_metadata(bytes, out);
|
|
|
|
}
|
|
|
|
case (option::none) {
|
|
|
|
out.write_str("Could not find metadata in " + path + ".\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-28 14:53:59 -05:00
|
|
|
fn metadata_matches(&vec[u8] crate_data,
|
2011-07-05 19:57:34 -05:00
|
|
|
&(@ast::meta_item)[] metas) -> bool {
|
2011-06-28 14:53:59 -05:00
|
|
|
auto attrs = decoder::get_crate_attributes(crate_data);
|
|
|
|
auto linkage_metas = attr::find_linkage_metas(attrs);
|
|
|
|
|
|
|
|
log #fmt("matching %u metadata requirements against %u items",
|
2011-07-05 19:57:34 -05:00
|
|
|
ivec::len(metas), ivec::len(linkage_metas));
|
2011-06-28 14:53:59 -05:00
|
|
|
|
|
|
|
for (@ast::meta_item needed in metas) {
|
|
|
|
if (!attr::contains(linkage_metas, needed)) {
|
|
|
|
log #fmt("missing %s", pprust::meta_item_to_str(*needed));
|
|
|
|
ret false;
|
2011-06-10 17:54:41 -05:00
|
|
|
}
|
|
|
|
}
|
2011-06-10 14:56:42 -05:00
|
|
|
ret true;
|
|
|
|
}
|
|
|
|
|
2011-07-08 14:33:00 -05:00
|
|
|
fn default_native_lib_naming(session::session sess, bool static) ->
|
2011-06-27 14:24:44 -05:00
|
|
|
rec(str prefix, str suffix) {
|
2011-07-08 14:33:00 -05:00
|
|
|
if (static) {
|
2011-07-08 14:03:48 -05:00
|
|
|
ret rec(prefix="lib", suffix=".rlib");
|
|
|
|
}
|
2011-06-27 14:24:44 -05:00
|
|
|
alt (sess.get_targ_cfg().os) {
|
|
|
|
case (session::os_win32) { ret rec(prefix="", suffix=".dll"); }
|
|
|
|
case (session::os_macos) { ret rec(prefix="lib", suffix=".dylib"); }
|
|
|
|
case (session::os_linux) { ret rec(prefix="lib", suffix=".so"); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 13:19:50 -05:00
|
|
|
fn find_library_crate(&session::session sess, &ast::ident ident,
|
2011-07-05 19:57:34 -05:00
|
|
|
&(@ast::meta_item)[] metas,
|
2011-06-15 13:19:50 -05:00
|
|
|
&vec[str] library_search_paths) ->
|
|
|
|
option::t[tup(str, vec[u8])] {
|
2011-06-28 18:52:11 -05:00
|
|
|
|
2011-07-05 17:58:48 -05:00
|
|
|
attr::require_unique_names(sess, metas);
|
|
|
|
|
2011-06-28 18:52:11 -05:00
|
|
|
auto crate_name = {
|
|
|
|
auto name_items = attr::find_meta_items_by_name(metas, "name");
|
2011-07-05 19:57:34 -05:00
|
|
|
alt (ivec::last(name_items)) {
|
2011-06-28 18:52:11 -05:00
|
|
|
case (some(?i)) {
|
2011-07-05 19:01:23 -05:00
|
|
|
alt (attr::get_meta_item_value_str(i)) {
|
|
|
|
case (some(?n)) { n }
|
2011-06-28 18:52:11 -05:00
|
|
|
case (_) {
|
|
|
|
// FIXME: Probably want a warning here since the user
|
|
|
|
// is using the wrong type of meta item
|
|
|
|
ident
|
|
|
|
}
|
2011-06-21 16:23:16 -05:00
|
|
|
}
|
|
|
|
}
|
2011-06-28 18:52:11 -05:00
|
|
|
case (none) { ident }
|
2011-06-21 16:23:16 -05:00
|
|
|
}
|
2011-06-28 18:52:11 -05:00
|
|
|
};
|
|
|
|
|
2011-07-08 14:33:00 -05:00
|
|
|
auto nn = default_native_lib_naming(sess, sess.get_opts().static);
|
|
|
|
auto x = find_library_crate_aux(nn, crate_name, metas,
|
|
|
|
library_search_paths);
|
|
|
|
if (x != none || sess.get_opts().static) {
|
|
|
|
ret x;
|
|
|
|
}
|
|
|
|
auto nn2 = default_native_lib_naming(sess, true);
|
|
|
|
ret find_library_crate_aux(nn2, crate_name, metas, library_search_paths);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn find_library_crate_aux(&rec(str prefix, str suffix) nn, str crate_name,
|
|
|
|
&(@ast::meta_item)[] metas,
|
|
|
|
&vec[str] library_search_paths) ->
|
|
|
|
option::t[tup(str, vec[u8])] {
|
2011-06-10 14:56:42 -05:00
|
|
|
let str prefix = nn.prefix + crate_name;
|
|
|
|
// FIXME: we could probably use a 'glob' function in std::fs but it will
|
|
|
|
// be much easier to write once the unsafe module knows more about FFI
|
|
|
|
// tricks. Currently the glob(3) interface is a bit more than we can
|
|
|
|
// stomach from here, and writing a C++ wrapper is more work than just
|
|
|
|
// manually filtering fs::list_dir here.
|
|
|
|
|
2011-03-15 19:33:05 -05:00
|
|
|
for (str library_search_path in library_search_paths) {
|
2011-06-29 13:54:35 -05:00
|
|
|
log #fmt("searching %s", library_search_path);
|
2011-06-10 14:56:42 -05:00
|
|
|
for (str path in fs::list_dir(library_search_path)) {
|
2011-06-29 13:54:35 -05:00
|
|
|
log #fmt("searching %s", path);
|
2011-06-10 14:56:42 -05:00
|
|
|
let str f = fs::basename(path);
|
2011-06-15 13:19:50 -05:00
|
|
|
if (!(str::starts_with(f, prefix) &&
|
|
|
|
str::ends_with(f, nn.suffix))) {
|
|
|
|
log #fmt("skipping %s, doesn't look like %s*%s", path, prefix,
|
|
|
|
nn.suffix);
|
2011-06-10 14:56:42 -05:00
|
|
|
cont;
|
|
|
|
}
|
|
|
|
alt (get_metadata_section(path)) {
|
|
|
|
case (option::some(?cvec)) {
|
2011-06-28 14:53:59 -05:00
|
|
|
if (!metadata_matches(cvec, metas)) {
|
2011-06-10 14:56:42 -05:00
|
|
|
log #fmt("skipping %s, metadata doesn't match", path);
|
|
|
|
cont;
|
|
|
|
}
|
|
|
|
log #fmt("found %s with matching metadata", path);
|
|
|
|
ret some(tup(path, cvec));
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
case (_) { }
|
2011-03-24 19:21:09 -05:00
|
|
|
}
|
|
|
|
}
|
2011-03-15 19:33:05 -05:00
|
|
|
}
|
2011-06-10 14:56:42 -05:00
|
|
|
ret none;
|
|
|
|
}
|
2011-03-15 19:33:05 -05:00
|
|
|
|
2011-06-27 17:30:17 -05:00
|
|
|
fn get_metadata_section(str filename) -> option::t[vec[u8]] {
|
|
|
|
auto b = str::buf(filename);
|
|
|
|
auto mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(b);
|
|
|
|
if (mb as int == 0) { ret option::none[vec[u8]]; }
|
|
|
|
auto of = mk_object_file(mb);
|
|
|
|
auto si = mk_section_iter(of.llof);
|
|
|
|
while (llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False) {
|
|
|
|
auto name_buf = llvm::LLVMGetSectionName(si.llsi);
|
|
|
|
auto name = str::str_from_cstr(name_buf);
|
|
|
|
if (str::eq(name, x86::get_meta_sect_name())) {
|
|
|
|
auto cbuf = llvm::LLVMGetSectionContents(si.llsi);
|
|
|
|
auto csz = llvm::LLVMGetSectionSize(si.llsi);
|
|
|
|
auto cvbuf = cbuf as vec::vbuf;
|
|
|
|
ret option::some[vec[u8]](vec::vec_from_vbuf[u8](cvbuf, csz));
|
|
|
|
}
|
|
|
|
llvm::LLVMMoveToNextSection(si.llsi);
|
|
|
|
}
|
|
|
|
ret option::none[vec[u8]];
|
|
|
|
}
|
|
|
|
|
2011-07-08 00:01:38 -05:00
|
|
|
fn load_library_crate(&session::session sess, span span, ast::crate_num cnum,
|
2011-07-05 19:57:34 -05:00
|
|
|
&ast::ident ident, &(@ast::meta_item)[] metas,
|
2011-06-10 14:56:42 -05:00
|
|
|
&vec[str] library_search_paths) {
|
|
|
|
alt (find_library_crate(sess, ident, metas, library_search_paths)) {
|
|
|
|
case (some(?t)) {
|
2011-07-07 20:25:56 -05:00
|
|
|
auto cstore = sess.get_cstore();
|
|
|
|
cstore::set_crate_data(cstore, cnum,
|
2011-07-07 20:13:24 -05:00
|
|
|
rec(name=ident, data=t._1));
|
2011-07-07 20:25:56 -05:00
|
|
|
cstore::add_used_crate_file(cstore, t._0);
|
2011-06-10 14:56:42 -05:00
|
|
|
ret;
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
case (_) { }
|
2011-06-10 14:56:42 -05:00
|
|
|
}
|
2011-06-28 18:04:09 -05:00
|
|
|
sess.span_fatal(span, #fmt("can't find crate for '%s'", ident));
|
2011-03-15 19:33:05 -05:00
|
|
|
}
|
2011-03-15 18:30:43 -05:00
|
|
|
|
2011-05-26 19:16:54 -05:00
|
|
|
|
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
|
2011-03-25 17:07:27 -05:00
|
|
|
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
2011-03-24 19:35:27 -05:00
|
|
|
// End:
|