2012-12-03 18:48:01 -06:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2013-01-07 16:16:52 -06:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
//! Finds crate binaries and loads their metadata
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2013-01-08 21:37:25 -06:00
|
|
|
use core::prelude::*;
|
|
|
|
|
2012-09-04 13:54:36 -05:00
|
|
|
use lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
|
2012-12-23 16:41:37 -06:00
|
|
|
use metadata::decoder;
|
|
|
|
use metadata::encoder;
|
2012-12-13 15:05:22 -06:00
|
|
|
use metadata::filesearch::FileSearch;
|
2012-12-23 16:41:37 -06:00
|
|
|
use metadata::filesearch;
|
|
|
|
use syntax::codemap::span;
|
|
|
|
use syntax::diagnostic::span_handler;
|
2012-09-04 13:54:36 -05:00
|
|
|
use syntax::parse::token::ident_interner;
|
2012-12-23 16:41:37 -06:00
|
|
|
use syntax::print::pprust;
|
|
|
|
use syntax::{ast, attr};
|
|
|
|
|
|
|
|
use core::cast;
|
|
|
|
use core::flate;
|
|
|
|
use core::io::WriterUtil;
|
|
|
|
use core::io;
|
2012-11-29 18:21:49 -06:00
|
|
|
use core::os::consts::{macos, freebsd, linux, android, win32};
|
2012-12-23 16:41:37 -06:00
|
|
|
use core::option;
|
|
|
|
use core::ptr;
|
|
|
|
use core::str;
|
|
|
|
use core::uint;
|
|
|
|
use core::vec;
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2012-05-22 19:16:26 -05:00
|
|
|
export os;
|
2012-11-29 18:21:49 -06:00
|
|
|
export os_macos, os_win32, os_linux, os_freebsd, os_android;
|
2012-05-22 19:16:26 -05:00
|
|
|
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,
|
2012-11-29 18:21:49 -06:00
|
|
|
os_android,
|
2012-05-22 19:16:26 -05:00
|
|
|
os_freebsd
|
|
|
|
}
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2012-05-22 19:16:26 -05:00
|
|
|
type ctxt = {
|
2012-05-22 19:48:04 -05:00
|
|
|
diag: span_handler,
|
2012-10-15 16:56:42 -05:00
|
|
|
filesearch: FileSearch,
|
2012-05-22 19:16:26 -05:00
|
|
|
span: span,
|
|
|
|
ident: ast::ident,
|
2012-09-20 20:15:39 -05:00
|
|
|
metas: ~[@ast::meta_item],
|
2012-07-14 00:57:48 -05:00
|
|
|
hash: ~str,
|
2012-05-22 19:16:26 -05:00
|
|
|
os: os,
|
2012-07-18 18:18:02 -05:00
|
|
|
static: bool,
|
2012-09-19 20:50:24 -05:00
|
|
|
intr: @ident_interner
|
2012-05-22 19:16:26 -05:00
|
|
|
};
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn load_library_crate(cx: ctxt) -> {ident: ~str, data: @~[u8]} {
|
2012-08-06 14:34:08 -05:00
|
|
|
match find_library_crate(cx) {
|
2013-01-07 16:16:52 -06:00
|
|
|
Some(ref t) => return (/*bad*/copy *t),
|
2012-08-20 14:23:37 -05:00
|
|
|
None => {
|
2012-05-22 19:48:04 -05:00
|
|
|
cx.diag.span_fatal(
|
2012-08-22 19:24:52 -05:00
|
|
|
cx.span, fmt!("can't find crate for `%s`",
|
|
|
|
*cx.intr.get(cx.ident)));
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-20 14:23:37 -05:00
|
|
|
fn find_library_crate(cx: ctxt) -> Option<{ident: ~str, data: @~[u8]}> {
|
2013-01-11 17:07:48 -06:00
|
|
|
attr::require_unique_names(cx.diag, cx.metas);
|
2012-05-22 19:48:04 -05:00
|
|
|
find_library_crate_aux(cx, libname(cx), cx.filesearch)
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn libname(cx: ctxt) -> {prefix: ~str, suffix: ~str} {
|
2012-08-01 19:30:05 -05:00
|
|
|
if cx.static { return {prefix: ~"lib", suffix: ~".rlib"}; }
|
2012-12-20 03:26:27 -06:00
|
|
|
let (dll_prefix, dll_suffix) = match cx.os {
|
|
|
|
os_win32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
|
|
|
|
os_macos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
|
|
|
|
os_linux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
|
2012-11-29 18:21:49 -06:00
|
|
|
os_android => (android::DLL_PREFIX, android::DLL_SUFFIX),
|
2012-12-20 03:26:27 -06:00
|
|
|
os_freebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
|
|
|
|
};
|
|
|
|
return {
|
|
|
|
prefix: str::from_slice(dll_prefix),
|
|
|
|
suffix: str::from_slice(dll_suffix)
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-22 19:16:26 -05:00
|
|
|
fn find_library_crate_aux(cx: ctxt,
|
2012-07-14 00:57:48 -05:00
|
|
|
nn: {prefix: ~str, suffix: ~str},
|
2012-10-15 16:56:42 -05:00
|
|
|
filesearch: filesearch::FileSearch) ->
|
2012-08-20 14:23:37 -05:00
|
|
|
Option<{ident: ~str, data: @~[u8]}> {
|
2013-01-07 16:16:52 -06:00
|
|
|
let crate_name = crate_name_from_metas(/*bad*/copy cx.metas);
|
2012-07-18 18:18:02 -05:00
|
|
|
let prefix: ~str = nn.prefix + crate_name + ~"-";
|
2013-01-07 16:16:52 -06:00
|
|
|
let suffix: ~str = /*bad*/copy nn.suffix;
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut matches = ~[];
|
2012-06-30 18:19:07 -05:00
|
|
|
filesearch::search(filesearch, |path| {
|
2012-08-24 17:28:43 -05:00
|
|
|
debug!("inspecting file %s", path.to_str());
|
2012-09-21 21:37:57 -05:00
|
|
|
let f: ~str = path.filename().get();
|
2012-05-15 22:23:06 -05:00
|
|
|
if !(str::starts_with(f, prefix) && str::ends_with(f, suffix)) {
|
2012-08-24 17:28:43 -05:00
|
|
|
debug!("skipping %s, doesn't look like %s*%s", path.to_str(),
|
|
|
|
prefix, suffix);
|
2012-08-20 14:23:37 -05:00
|
|
|
option::None::<()>
|
2012-05-15 22:23:06 -05:00
|
|
|
} else {
|
2012-08-24 17:28:43 -05:00
|
|
|
debug!("%s is a candidate", path.to_str());
|
2012-08-06 14:34:08 -05:00
|
|
|
match get_metadata_section(cx.os, path) {
|
2012-08-20 14:23:37 -05:00
|
|
|
option::Some(cvec) => {
|
2012-05-22 19:16:26 -05:00
|
|
|
if !crate_matches(cvec, cx.metas, cx.hash) {
|
2012-08-24 17:28:43 -05:00
|
|
|
debug!("skipping %s, metadata doesn't match",
|
|
|
|
path.to_str());
|
2012-08-20 14:23:37 -05:00
|
|
|
option::None::<()>
|
2012-05-15 22:23:06 -05:00
|
|
|
} else {
|
2012-08-24 17:28:43 -05:00
|
|
|
debug!("found %s with matching metadata", path.to_str());
|
2012-09-26 19:33:34 -05:00
|
|
|
matches.push({ident: path.to_str(), data: cvec});
|
2012-08-20 14:23:37 -05:00
|
|
|
option::None::<()>
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => {
|
2012-08-24 17:28:43 -05:00
|
|
|
debug!("could not load metadata for %s", path.to_str());
|
2012-08-20 14:23:37 -05:00
|
|
|
option::None::<()>
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if matches.is_empty() {
|
2012-08-20 14:23:37 -05:00
|
|
|
None
|
2012-05-15 22:23:06 -05:00
|
|
|
} else if matches.len() == 1u {
|
2013-01-07 16:16:52 -06:00
|
|
|
Some(/*bad*/copy matches[0])
|
2012-05-15 22:23:06 -05:00
|
|
|
} else {
|
2012-05-22 19:48:04 -05:00
|
|
|
cx.diag.span_err(
|
2012-08-22 19:24:52 -05:00
|
|
|
cx.span, fmt!("multiple matching crates for `%s`", crate_name));
|
2012-07-14 00:57:48 -05:00
|
|
|
cx.diag.handler().note(~"candidates:");
|
2012-07-31 18:38:41 -05:00
|
|
|
for matches.each |match_| {
|
2012-08-22 19:24:52 -05:00
|
|
|
cx.diag.handler().note(fmt!("path: %s", match_.ident));
|
2012-07-31 18:38:41 -05:00
|
|
|
let attrs = decoder::get_crate_attributes(match_.data);
|
2012-07-18 18:18:02 -05:00
|
|
|
note_linkage_attrs(cx.intr, cx.diag, attrs);
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
2012-05-22 19:48:04 -05:00
|
|
|
cx.diag.handler().abort_if_errors();
|
2012-08-20 14:23:37 -05:00
|
|
|
None
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-07 16:16:52 -06:00
|
|
|
fn crate_name_from_metas(+metas: ~[@ast::meta_item]) -> ~str {
|
2012-07-14 00:57:48 -05:00
|
|
|
let name_items = attr::find_meta_items_by_name(metas, ~"name");
|
2012-08-06 14:34:08 -05:00
|
|
|
match vec::last_opt(name_items) {
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(i) => {
|
2012-09-20 20:15:39 -05:00
|
|
|
match attr::get_meta_item_value_str(i) {
|
2013-01-07 16:16:52 -06:00
|
|
|
Some(ref n) => (/*bad*/copy *n),
|
2012-06-21 18:44:10 -05:00
|
|
|
// FIXME (#2406): Probably want a warning here since the user
|
|
|
|
// is using the wrong type of meta item.
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => fail
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
None => fail ~"expected to find the crate name"
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-19 20:50:24 -05:00
|
|
|
fn note_linkage_attrs(intr: @ident_interner, diag: span_handler,
|
2012-07-18 18:18:02 -05:00
|
|
|
attrs: ~[ast::attribute]) {
|
2012-08-22 18:43:23 -05:00
|
|
|
for attr::find_linkage_metas(attrs).each |mi| {
|
2012-08-22 19:24:52 -05:00
|
|
|
diag.handler().note(fmt!("meta: %s",
|
2012-09-19 18:55:01 -05:00
|
|
|
pprust::meta_item_to_str(*mi,intr)));
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-07 16:16:52 -06:00
|
|
|
fn crate_matches(crate_data: @~[u8], +metas: ~[@ast::meta_item],
|
2012-07-14 00:57:48 -05:00
|
|
|
hash: ~str) -> bool {
|
2012-05-15 22:23:06 -05:00
|
|
|
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);
|
2012-07-18 18:18:02 -05:00
|
|
|
if chash != hash { return false; }
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
metadata_matches(linkage_metas, metas)
|
|
|
|
}
|
|
|
|
|
2012-09-20 20:15:39 -05:00
|
|
|
fn metadata_matches(extern_metas: ~[@ast::meta_item],
|
|
|
|
local_metas: ~[@ast::meta_item]) -> bool {
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("matching %u metadata requirements against %u items",
|
|
|
|
vec::len(local_metas), vec::len(extern_metas));
|
2012-05-15 22:23:06 -05:00
|
|
|
|
2012-06-30 18:19:07 -05:00
|
|
|
for local_metas.each |needed| {
|
2012-09-20 20:15:39 -05:00
|
|
|
if !attr::contains(extern_metas, *needed) {
|
2012-08-01 19:30:05 -05:00
|
|
|
return false;
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return true;
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
|
2012-05-22 19:16:26 -05:00
|
|
|
fn get_metadata_section(os: os,
|
2013-01-23 13:43:58 -06:00
|
|
|
filename: &Path) -> Option<@~[u8]> {
|
|
|
|
unsafe {
|
|
|
|
let mb = str::as_c_str(filename.to_str(), |buf| {
|
|
|
|
llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
|
|
|
|
});
|
|
|
|
if mb as int == 0 { return option::None::<@~[u8]>; }
|
|
|
|
let of = match mk_object_file(mb) {
|
|
|
|
option::Some(of) => of,
|
|
|
|
_ => return 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::raw::from_c_str(name_buf) };
|
|
|
|
if name == meta_section_name(os) {
|
|
|
|
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
|
|
|
|
let csz = llvm::LLVMGetSectionSize(si.llsi) as uint;
|
|
|
|
let mut found = None;
|
|
|
|
unsafe {
|
|
|
|
let cvbuf: *u8 = cast::reinterpret_cast(&cbuf);
|
|
|
|
let vlen = vec::len(encoder::metadata_encoding_version);
|
|
|
|
debug!("checking %u bytes of metadata-version stamp",
|
|
|
|
vlen);
|
|
|
|
let minsz = uint::min(vlen, csz);
|
|
|
|
let mut version_ok = false;
|
|
|
|
do vec::raw::buf_as_slice(cvbuf, minsz) |buf0| {
|
|
|
|
version_ok = (buf0 ==
|
|
|
|
encoder::metadata_encoding_version);
|
|
|
|
}
|
|
|
|
if !version_ok { return None; }
|
2012-09-05 17:27:22 -05:00
|
|
|
|
2013-01-23 13:43:58 -06:00
|
|
|
let cvbuf1 = ptr::offset(cvbuf, vlen);
|
|
|
|
debug!("inflating %u bytes of compressed metadata",
|
|
|
|
csz - vlen);
|
|
|
|
do vec::raw::buf_as_slice(cvbuf1, csz-vlen) |bytes| {
|
|
|
|
let inflated = flate::inflate_bytes(bytes);
|
|
|
|
found = move Some(@(move inflated));
|
|
|
|
}
|
|
|
|
if found != None {
|
|
|
|
return found;
|
|
|
|
}
|
2012-09-05 17:27:22 -05:00
|
|
|
}
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
2013-01-23 13:43:58 -06:00
|
|
|
llvm::LLVMMoveToNextSection(si.llsi);
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
2013-01-23 13:43:58 -06:00
|
|
|
return option::None::<@~[u8]>;
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn meta_section_name(os: os) -> ~str {
|
2012-08-06 14:34:08 -05:00
|
|
|
match os {
|
2012-08-03 21:59:04 -05:00
|
|
|
os_macos => ~"__DATA,__note.rustc",
|
|
|
|
os_win32 => ~".note.rustc",
|
|
|
|
os_linux => ~".note.rustc",
|
2012-11-29 18:21:49 -06:00
|
|
|
os_android => ~".note.rustc",
|
2012-08-03 21:59:04 -05:00
|
|
|
os_freebsd => ~".note.rustc"
|
2012-05-22 19:16:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-15 22:23:06 -05:00
|
|
|
// A diagnostic function for dumping crate metadata to an output stream
|
2012-09-19 20:50:24 -05:00
|
|
|
fn list_file_metadata(intr: @ident_interner,
|
2012-08-24 17:28:43 -05:00
|
|
|
os: os, path: &Path, out: io::Writer) {
|
2012-08-06 14:34:08 -05:00
|
|
|
match get_metadata_section(os, path) {
|
2012-08-20 14:23:37 -05:00
|
|
|
option::Some(bytes) => decoder::list_crate_metadata(intr, bytes, out),
|
|
|
|
option::None => {
|
2012-08-24 17:28:43 -05:00
|
|
|
out.write_str(~"could not find metadata in "
|
|
|
|
+ path.to_str() + ~".\n");
|
2012-05-15 22:23:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|