rustc: Extract loader mod from creader mod
loader is a utility for locating crates and loading their metadata. creader is a compiler pass that loads metadata for all used libraries.
This commit is contained in:
parent
4bfa19b100
commit
0e21a05e6c
@ -672,7 +672,7 @@ fn early_error(emitter: diagnostic::emitter, msg: str) -> ! {
|
||||
}
|
||||
|
||||
fn list_metadata(sess: session, path: str, out: io::writer) {
|
||||
metadata::creader::list_file_metadata(sess, path, out);
|
||||
metadata::loader::list_file_metadata(sess, path, out);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,20 +1,20 @@
|
||||
// Extracting metadata from crate files
|
||||
#[doc = "
|
||||
|
||||
Validates all used crates and native libraries and loads their metadata
|
||||
|
||||
"];
|
||||
|
||||
import driver::session;
|
||||
import session::session;
|
||||
import syntax::{ast, ast_util};
|
||||
import lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
|
||||
import syntax::attr;
|
||||
import syntax::visit;
|
||||
import syntax::codemap::span;
|
||||
import util::{filesearch};
|
||||
import io::writer_util;
|
||||
import std::map::{hashmap, int_hash};
|
||||
import syntax::print::pprust;
|
||||
import common::*;
|
||||
|
||||
export read_crates;
|
||||
export list_file_metadata;
|
||||
|
||||
// Traverses an AST, reading all the information about use'd crates and native
|
||||
// libraries necessary for later resolving, typechecking, linking, etc.
|
||||
@ -59,10 +59,10 @@ fn warn_if_multiple_versions(sess: session::session,
|
||||
import either::*;
|
||||
|
||||
if crate_cache.is_not_empty() {
|
||||
let name = crate_name_from_metas(*crate_cache.last().metas);
|
||||
let name = loader::crate_name_from_metas(*crate_cache.last().metas);
|
||||
let {lefts: matches, rights: non_matches} =
|
||||
partition(crate_cache.map {|entry|
|
||||
let othername = crate_name_from_metas(*entry.metas);
|
||||
let othername = loader::crate_name_from_metas(*entry.metas);
|
||||
if name == othername {
|
||||
left(entry)
|
||||
} else {
|
||||
@ -79,7 +79,7 @@ fn warn_if_multiple_versions(sess: session::session,
|
||||
let attrs = [
|
||||
attr::mk_attr(attr::mk_list_item("link", *match.metas))
|
||||
];
|
||||
note_linkage_attrs(sess, attrs);
|
||||
loader::note_linkage_attrs(sess, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,195 +148,6 @@ fn visit_item(e: env, i: @ast::item) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
option::some(bytes) { decoder::list_crate_metadata(bytes, out); }
|
||||
option::none {
|
||||
out.write_str("could not find metadata in " + path + ".\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
fn default_native_lib_naming(sess: session::session, static: bool) ->
|
||||
{prefix: str, suffix: str} {
|
||||
if static { ret {prefix: "lib", suffix: ".rlib"}; }
|
||||
alt sess.targ_cfg.os {
|
||||
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"}; }
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// is using the wrong type of meta item
|
||||
_ { fail }
|
||||
}
|
||||
}
|
||||
none { fail "expected to find the crate name" }
|
||||
}
|
||||
}
|
||||
|
||||
fn find_library_crate(sess: session::session, span: span,
|
||||
metas: [@ast::meta_item], hash: str)
|
||||
-> option<{ident: str, data: @[u8]}> {
|
||||
|
||||
attr::require_unique_names(sess.diagnostic(), metas);
|
||||
let metas = metas;
|
||||
|
||||
let nn = default_native_lib_naming(sess, sess.opts.static);
|
||||
let x =
|
||||
find_library_crate_aux(sess, span, nn,
|
||||
metas, hash, sess.filesearch);
|
||||
if x != none || sess.opts.static { ret x; }
|
||||
let nn2 = default_native_lib_naming(sess, true);
|
||||
ret find_library_crate_aux(sess, span, nn2, metas, hash,
|
||||
sess.filesearch);
|
||||
}
|
||||
|
||||
fn find_library_crate_aux(sess: session::session,
|
||||
span: span,
|
||||
nn: {prefix: str, suffix: str},
|
||||
metas: [@ast::meta_item],
|
||||
hash: str,
|
||||
filesearch: filesearch::filesearch) ->
|
||||
option<{ident: str, data: @[u8]}> {
|
||||
let crate_name = crate_name_from_metas(metas);
|
||||
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);
|
||||
alt get_metadata_section(sess, path) {
|
||||
option::some(cvec) {
|
||||
if !crate_matches(cvec, metas, hash) {
|
||||
#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 {
|
||||
sess.span_err(
|
||||
span, #fmt("multiple matching crates for `%s`", crate_name));
|
||||
sess.note("candidates:");
|
||||
for matches.each {|match|
|
||||
sess.note(#fmt("path: %s", match.ident));
|
||||
let attrs = decoder::get_crate_attributes(match.data);
|
||||
note_linkage_attrs(sess, attrs);
|
||||
}
|
||||
sess.abort_if_errors();
|
||||
none
|
||||
}
|
||||
}
|
||||
|
||||
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 get_metadata_section(sess: session::session,
|
||||
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) };
|
||||
if str::eq(name, sess.targ_cfg.target_strs.meta_sect_name) {
|
||||
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]>;
|
||||
}
|
||||
|
||||
fn load_library_crate(sess: session::session, ident: ast::ident, span: span,
|
||||
metas: [@ast::meta_item], hash: str)
|
||||
-> {ident: str, data: @[u8]} {
|
||||
|
||||
|
||||
alt find_library_crate(sess, span, metas, hash) {
|
||||
some(t) { ret t; }
|
||||
none {
|
||||
sess.span_fatal(span, #fmt["can't find crate for '%s'", ident]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn metas_with(ident: ast::ident, key: str,
|
||||
metas: [@ast::meta_item]) -> [@ast::meta_item] {
|
||||
let name_items = attr::find_meta_items_by_name(metas, key);
|
||||
@ -355,7 +166,7 @@ fn metas_with_ident(ident: ast::ident,
|
||||
fn existing_match(e: env, metas: [@ast::meta_item], hash: str) ->
|
||||
option<int> {
|
||||
let maybe_entry = e.crate_cache.find {|c|
|
||||
metadata_matches(*c.metas, metas) &&
|
||||
loader::metadata_matches(*c.metas, metas) &&
|
||||
(hash.is_empty() || c.hash == hash)
|
||||
};
|
||||
|
||||
@ -369,7 +180,7 @@ fn resolve_crate(e: env, ident: ast::ident, metas: [@ast::meta_item],
|
||||
alt existing_match(e, metas, hash) {
|
||||
none {
|
||||
let cinfo =
|
||||
load_library_crate(e.sess, ident, span, metas, hash);
|
||||
loader::load_library_crate(e.sess, ident, span, metas, hash);
|
||||
|
||||
let cfilename = cinfo.ident;
|
||||
let cdata = cinfo.data;
|
||||
|
209
src/rustc/metadata/loader.rs
Normal file
209
src/rustc/metadata/loader.rs
Normal file
@ -0,0 +1,209 @@
|
||||
#[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;
|
||||
|
||||
export load_library_crate;
|
||||
export list_file_metadata;
|
||||
export note_linkage_attrs;
|
||||
export crate_name_from_metas;
|
||||
export metadata_matches;
|
||||
|
||||
fn load_library_crate(sess: session::session, ident: ast::ident, span: span,
|
||||
metas: [@ast::meta_item], hash: str)
|
||||
-> {ident: str, data: @[u8]} {
|
||||
|
||||
|
||||
alt find_library_crate(sess, span, metas, hash) {
|
||||
some(t) { ret t; }
|
||||
none {
|
||||
sess.span_fatal(span, #fmt["can't find crate for '%s'", ident]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_library_crate(sess: session::session, span: span,
|
||||
metas: [@ast::meta_item], hash: str)
|
||||
-> option<{ident: str, data: @[u8]}> {
|
||||
|
||||
attr::require_unique_names(sess.diagnostic(), metas);
|
||||
let metas = metas;
|
||||
|
||||
let nn = default_native_lib_naming(sess, sess.opts.static);
|
||||
let x =
|
||||
find_library_crate_aux(sess, span, nn,
|
||||
metas, hash, sess.filesearch);
|
||||
if x != none || sess.opts.static { ret x; }
|
||||
let nn2 = default_native_lib_naming(sess, true);
|
||||
ret find_library_crate_aux(sess, span, nn2, metas, hash,
|
||||
sess.filesearch);
|
||||
}
|
||||
|
||||
fn default_native_lib_naming(sess: session::session, static: bool) ->
|
||||
{prefix: str, suffix: str} {
|
||||
if static { ret {prefix: "lib", suffix: ".rlib"}; }
|
||||
alt sess.targ_cfg.os {
|
||||
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"}; }
|
||||
}
|
||||
}
|
||||
|
||||
fn find_library_crate_aux(sess: session::session,
|
||||
span: span,
|
||||
nn: {prefix: str, suffix: str},
|
||||
metas: [@ast::meta_item],
|
||||
hash: str,
|
||||
filesearch: filesearch::filesearch) ->
|
||||
option<{ident: str, data: @[u8]}> {
|
||||
let crate_name = crate_name_from_metas(metas);
|
||||
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);
|
||||
alt get_metadata_section(sess, path) {
|
||||
option::some(cvec) {
|
||||
if !crate_matches(cvec, metas, hash) {
|
||||
#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 {
|
||||
sess.span_err(
|
||||
span, #fmt("multiple matching crates for `%s`", crate_name));
|
||||
sess.note("candidates:");
|
||||
for matches.each {|match|
|
||||
sess.note(#fmt("path: %s", match.ident));
|
||||
let attrs = decoder::get_crate_attributes(match.data);
|
||||
note_linkage_attrs(sess, attrs);
|
||||
}
|
||||
sess.abort_if_errors();
|
||||
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
|
||||
// is using the wrong type of meta item
|
||||
_ { 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;
|
||||
}
|
||||
|
||||
fn get_metadata_section(sess: session::session,
|
||||
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) };
|
||||
if str::eq(name, sess.targ_cfg.target_strs.meta_sect_name) {
|
||||
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]>;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
option::some(bytes) { decoder::list_crate_metadata(bytes, out); }
|
||||
option::none {
|
||||
out.write_str("could not find metadata in " + path + ".\n");
|
||||
}
|
||||
}
|
||||
}
|
@ -117,6 +117,7 @@ mod metadata {
|
||||
export decoder;
|
||||
export tyencode;
|
||||
export tydecode;
|
||||
export loader;
|
||||
|
||||
mod common;
|
||||
mod tyencode;
|
||||
@ -126,6 +127,7 @@ mod metadata {
|
||||
mod creader;
|
||||
mod cstore;
|
||||
mod csearch;
|
||||
mod loader;
|
||||
}
|
||||
|
||||
mod driver {
|
||||
|
Loading…
Reference in New Issue
Block a user