2015-02-05 14:28:17 -06:00
|
|
|
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06:00
|
|
|
// 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.
|
|
|
|
|
2014-03-21 20:05:05 -05:00
|
|
|
#![allow(non_camel_case_types)]
|
2014-02-10 08:36:31 -06:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
//! Validates all used crates and extern libraries and loads their metadata
|
2011-03-15 18:30:43 -05:00
|
|
|
|
2014-02-24 21:45:20 -06:00
|
|
|
use back::svh::Svh;
|
2014-11-15 19:30:33 -06:00
|
|
|
use session::{config, Session};
|
2014-12-16 16:32:02 -06:00
|
|
|
use session::search_paths::PathKind;
|
2012-12-23 16:41:37 -06:00
|
|
|
use metadata::cstore;
|
2014-12-31 21:48:39 -06:00
|
|
|
use metadata::cstore::{CStore, CrateSource, MetadataBlob};
|
2012-12-23 16:41:37 -06:00
|
|
|
use metadata::decoder;
|
|
|
|
use metadata::loader;
|
2014-04-03 10:43:57 -05:00
|
|
|
use metadata::loader::CratePaths;
|
2012-12-23 16:41:37 -06:00
|
|
|
|
2015-02-26 23:00:43 -06:00
|
|
|
use std::path::{Path, PathBuf};
|
2014-03-27 12:28:38 -05:00
|
|
|
use std::rc::Rc;
|
2013-07-19 20:42:11 -05:00
|
|
|
use syntax::ast;
|
2013-11-30 13:39:55 -06:00
|
|
|
use syntax::abi;
|
2012-09-04 13:54:36 -05:00
|
|
|
use syntax::attr;
|
2013-07-19 06:51:37 -05:00
|
|
|
use syntax::attr::AttrMetaMethods;
|
2015-02-11 11:29:49 -06:00
|
|
|
use syntax::codemap::{self, Span, mk_sp, Pos};
|
2014-12-30 21:10:46 -06:00
|
|
|
use syntax::parse;
|
2014-04-17 10:52:25 -05:00
|
|
|
use syntax::parse::token::InternedString;
|
2013-06-04 14:34:25 -05:00
|
|
|
use syntax::parse::token;
|
2013-08-26 04:01:39 -05:00
|
|
|
use syntax::visit;
|
2014-08-14 16:42:37 -05:00
|
|
|
use util::fs;
|
2014-12-21 00:36:50 -06:00
|
|
|
use log;
|
2011-03-15 18:30:43 -05:00
|
|
|
|
2014-12-21 01:02:38 -06:00
|
|
|
pub struct CrateReader<'a> {
|
2014-04-07 14:14:33 -05:00
|
|
|
sess: &'a Session,
|
|
|
|
next_crate_num: ast::CrateNum,
|
|
|
|
}
|
|
|
|
|
2014-12-21 01:02:38 -06:00
|
|
|
impl<'a, 'v> visit::Visitor<'v> for CrateReader<'a> {
|
2014-09-12 05:10:30 -05:00
|
|
|
fn visit_item(&mut self, a: &ast::Item) {
|
2014-12-21 00:36:50 -06:00
|
|
|
self.process_item(a);
|
2014-09-12 05:10:30 -05:00
|
|
|
visit::walk_item(self, a);
|
2013-08-26 04:01:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-07 14:14:33 -05:00
|
|
|
fn dump_crates(cstore: &CStore) {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("resolved crates:");
|
2014-04-25 11:06:49 -05:00
|
|
|
cstore.iter_crate_data_origins(|_, data, opt_source| {
|
2014-06-06 15:21:18 -05:00
|
|
|
debug!(" name: {}", data.name());
|
2014-04-07 14:14:33 -05:00
|
|
|
debug!(" cnum: {}", data.cnum);
|
|
|
|
debug!(" hash: {}", data.hash());
|
2014-04-25 11:06:49 -05:00
|
|
|
opt_source.map(|cs| {
|
|
|
|
let CrateSource { dylib, rlib, cnum: _ } = cs;
|
2015-01-06 10:46:07 -06:00
|
|
|
dylib.map(|dl| debug!(" dylib: {}", dl.0.display()));
|
|
|
|
rlib.map(|rl| debug!(" rlib: {}", rl.0.display()));
|
2014-04-25 11:06:49 -05:00
|
|
|
});
|
2014-04-07 14:14:33 -05:00
|
|
|
})
|
2012-04-09 17:06:38 -05:00
|
|
|
}
|
|
|
|
|
2014-12-23 13:33:44 -06:00
|
|
|
fn should_link(i: &ast::Item) -> bool {
|
2015-02-20 13:08:14 -06:00
|
|
|
!attr::contains_name(&i.attrs, "no_link")
|
2014-04-07 14:16:43 -05:00
|
|
|
}
|
2013-12-25 12:10:33 -06:00
|
|
|
|
|
|
|
struct CrateInfo {
|
2014-05-22 18:57:53 -05:00
|
|
|
ident: String,
|
2014-06-06 15:21:18 -05:00
|
|
|
name: String,
|
2013-12-25 12:10:33 -06:00
|
|
|
id: ast::NodeId,
|
2014-04-07 14:16:43 -05:00
|
|
|
should_link: bool,
|
2013-12-25 12:10:33 -06:00
|
|
|
}
|
|
|
|
|
2014-06-06 15:21:18 -05:00
|
|
|
pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
|
2015-03-26 19:35:13 -05:00
|
|
|
let say = |s: &str| {
|
2014-06-06 15:21:18 -05:00
|
|
|
match (sp, sess) {
|
2014-10-09 14:17:22 -05:00
|
|
|
(_, None) => panic!("{}", s),
|
2014-06-06 15:21:18 -05:00
|
|
|
(Some(sp), Some(sess)) => sess.span_err(sp, s),
|
|
|
|
(None, Some(sess)) => sess.err(s),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if s.len() == 0 {
|
2015-03-26 19:35:13 -05:00
|
|
|
say("crate name must not be empty");
|
2014-06-06 15:21:18 -05:00
|
|
|
}
|
|
|
|
for c in s.chars() {
|
|
|
|
if c.is_alphanumeric() { continue }
|
2015-03-26 19:35:13 -05:00
|
|
|
if c == '_' { continue }
|
|
|
|
say(&format!("invalid character `{}` in crate name: `{}`", c, s));
|
2014-06-06 15:21:18 -05:00
|
|
|
}
|
|
|
|
match sess {
|
|
|
|
Some(sess) => sess.abort_if_errors(),
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-01 18:56:28 -06:00
|
|
|
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
fn register_native_lib(sess: &Session,
|
|
|
|
span: Option<Span>,
|
|
|
|
name: String,
|
|
|
|
kind: cstore::NativeLibraryKind) {
|
2014-11-27 12:53:34 -06:00
|
|
|
if name.is_empty() {
|
2014-10-21 01:04:16 -05:00
|
|
|
match span {
|
|
|
|
Some(span) => {
|
|
|
|
sess.span_err(span, "#[link(name = \"\")] given with \
|
|
|
|
empty name");
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
sess.err("empty library name given via `-l`");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2014-07-23 13:56:36 -05:00
|
|
|
let is_osx = sess.target.target.options.is_like_osx;
|
2014-10-21 01:04:16 -05:00
|
|
|
if kind == cstore::NativeFramework && !is_osx {
|
|
|
|
let msg = "native frameworks are only available on OSX targets";
|
|
|
|
match span {
|
|
|
|
Some(span) => sess.span_err(span, msg),
|
|
|
|
None => sess.err(msg),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sess.cstore.add_used_library(name, kind);
|
|
|
|
}
|
|
|
|
|
2015-02-11 20:43:16 -06:00
|
|
|
// Extra info about a crate loaded for plugins or exported macros.
|
|
|
|
struct ExtensionCrate {
|
2014-12-31 21:48:39 -06:00
|
|
|
metadata: PMDSource,
|
2015-02-26 23:00:43 -06:00
|
|
|
dylib: Option<PathBuf>,
|
2014-12-31 21:48:39 -06:00
|
|
|
target_only: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
enum PMDSource {
|
|
|
|
Registered(Rc<cstore::crate_metadata>),
|
|
|
|
Owned(MetadataBlob),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PMDSource {
|
|
|
|
pub fn as_slice<'a>(&'a self) -> &'a [u8] {
|
|
|
|
match *self {
|
|
|
|
PMDSource::Registered(ref cmd) => cmd.data(),
|
|
|
|
PMDSource::Owned(ref mdb) => mdb.as_slice(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-21 01:02:38 -06:00
|
|
|
impl<'a> CrateReader<'a> {
|
|
|
|
pub fn new(sess: &'a Session) -> CrateReader<'a> {
|
|
|
|
CrateReader {
|
|
|
|
sess: sess,
|
|
|
|
next_crate_num: sess.cstore.next_crate_num(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-19 17:39:03 -05:00
|
|
|
// Traverses an AST, reading all the information about use'd crates and
|
|
|
|
// extern libraries necessary for later resolving, typechecking, linking,
|
|
|
|
// etc.
|
2014-12-21 01:02:38 -06:00
|
|
|
pub fn read_crates(&mut self, krate: &ast::Crate) {
|
|
|
|
self.process_crate(krate);
|
|
|
|
visit::walk_crate(self, krate);
|
|
|
|
|
|
|
|
if log_enabled!(log::DEBUG) {
|
|
|
|
dump_crates(&self.sess.cstore);
|
|
|
|
}
|
|
|
|
|
2015-01-31 11:20:46 -06:00
|
|
|
for &(ref name, kind) in &self.sess.opts.libs {
|
2014-12-21 01:02:38 -06:00
|
|
|
register_native_lib(self.sess, None, name.clone(), kind);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_crate(&self, c: &ast::Crate) {
|
2014-12-21 00:36:50 -06:00
|
|
|
for a in c.attrs.iter().filter(|m| m.name() == "link_args") {
|
|
|
|
match a.value_str() {
|
2015-02-04 14:48:12 -06:00
|
|
|
Some(ref linkarg) => self.sess.cstore.add_used_link_args(&linkarg),
|
2014-12-21 00:36:50 -06:00
|
|
|
None => { /* fallthrough */ }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-23 13:33:44 -06:00
|
|
|
fn extract_crate_info(&self, i: &ast::Item) -> Option<CrateInfo> {
|
2014-12-21 00:36:50 -06:00
|
|
|
match i.node {
|
2014-12-23 13:33:44 -06:00
|
|
|
ast::ItemExternCrate(ref path_opt) => {
|
|
|
|
let ident = token::get_ident(i.ident);
|
2015-01-06 18:16:35 -06:00
|
|
|
debug!("resolving extern crate stmt. ident: {} path_opt: {:?}",
|
2014-12-21 00:36:50 -06:00
|
|
|
ident, path_opt);
|
|
|
|
let name = match *path_opt {
|
2015-03-19 17:39:03 -05:00
|
|
|
Some(name) => {
|
|
|
|
validate_crate_name(Some(self.sess), name.as_str(),
|
2014-12-21 00:36:50 -06:00
|
|
|
Some(i.span));
|
2015-03-19 17:39:03 -05:00
|
|
|
name.as_str().to_string()
|
2014-12-21 00:36:50 -06:00
|
|
|
}
|
2015-02-03 17:03:39 -06:00
|
|
|
None => ident.to_string(),
|
2014-12-21 00:36:50 -06:00
|
|
|
};
|
|
|
|
Some(CrateInfo {
|
2015-02-03 17:03:39 -06:00
|
|
|
ident: ident.to_string(),
|
2014-12-21 00:36:50 -06:00
|
|
|
name: name,
|
2014-12-23 13:33:44 -06:00
|
|
|
id: i.id,
|
2014-12-21 00:36:50 -06:00
|
|
|
should_link: should_link(i),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
_ => None
|
2014-07-01 10:37:54 -05:00
|
|
|
}
|
2014-12-21 00:36:50 -06:00
|
|
|
}
|
|
|
|
|
2014-12-23 13:33:44 -06:00
|
|
|
fn process_item(&mut self, i: &ast::Item) {
|
2014-12-21 00:36:50 -06:00
|
|
|
match i.node {
|
2014-12-23 13:33:44 -06:00
|
|
|
ast::ItemExternCrate(_) => {
|
|
|
|
if !should_link(i) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
match self.extract_crate_info(i) {
|
|
|
|
Some(info) => {
|
|
|
|
let (cnum, _, _) = self.resolve_crate(&None,
|
2015-02-20 13:08:14 -06:00
|
|
|
&info.ident,
|
|
|
|
&info.name,
|
2014-12-23 13:33:44 -06:00
|
|
|
None,
|
|
|
|
i.span,
|
|
|
|
PathKind::Crate);
|
|
|
|
self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
|
|
|
|
}
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
}
|
2014-12-21 00:36:50 -06:00
|
|
|
ast::ItemForeignMod(ref fm) => {
|
|
|
|
if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// First, add all of the custom link_args attributes
|
|
|
|
let link_args = i.attrs.iter()
|
|
|
|
.filter_map(|at| if at.name() == "link_args" {
|
|
|
|
Some(at)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
})
|
|
|
|
.collect::<Vec<&ast::Attribute>>();
|
2015-01-31 11:20:46 -06:00
|
|
|
for m in &link_args {
|
2014-12-21 00:36:50 -06:00
|
|
|
match m.value_str() {
|
2015-02-04 14:48:12 -06:00
|
|
|
Some(linkarg) => self.sess.cstore.add_used_link_args(&linkarg),
|
2014-12-21 00:36:50 -06:00
|
|
|
None => { /* fallthrough */ }
|
|
|
|
}
|
|
|
|
}
|
2014-07-01 10:37:54 -05:00
|
|
|
|
2014-12-21 00:36:50 -06:00
|
|
|
// Next, process all of the #[link(..)]-style arguments
|
|
|
|
let link_args = i.attrs.iter()
|
|
|
|
.filter_map(|at| if at.name() == "link" {
|
|
|
|
Some(at)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
})
|
|
|
|
.collect::<Vec<&ast::Attribute>>();
|
2015-01-31 11:20:46 -06:00
|
|
|
for m in &link_args {
|
2014-12-21 00:36:50 -06:00
|
|
|
match m.meta_item_list() {
|
|
|
|
Some(items) => {
|
|
|
|
let kind = items.iter().find(|k| {
|
|
|
|
k.name() == "kind"
|
|
|
|
}).and_then(|a| a.value_str());
|
|
|
|
let kind = match kind {
|
|
|
|
Some(k) => {
|
|
|
|
if k == "static" {
|
|
|
|
cstore::NativeStatic
|
|
|
|
} else if self.sess.target.target.options.is_like_osx
|
|
|
|
&& k == "framework" {
|
|
|
|
cstore::NativeFramework
|
|
|
|
} else if k == "framework" {
|
|
|
|
cstore::NativeFramework
|
|
|
|
} else if k == "dylib" {
|
|
|
|
cstore::NativeUnknown
|
|
|
|
} else {
|
|
|
|
self.sess.span_err(m.span,
|
2015-01-07 10:58:31 -06:00
|
|
|
&format!("unknown kind: `{}`",
|
2015-02-20 13:08:14 -06:00
|
|
|
k));
|
2014-12-21 00:36:50 -06:00
|
|
|
cstore::NativeUnknown
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => cstore::NativeUnknown
|
|
|
|
};
|
|
|
|
let n = items.iter().find(|n| {
|
|
|
|
n.name() == "name"
|
|
|
|
}).and_then(|a| a.value_str());
|
|
|
|
let n = match n {
|
|
|
|
Some(n) => n,
|
|
|
|
None => {
|
|
|
|
self.sess.span_err(m.span,
|
|
|
|
"#[link(...)] specified without \
|
|
|
|
`name = \"foo\"`");
|
|
|
|
InternedString::new("foo")
|
|
|
|
}
|
|
|
|
};
|
|
|
|
register_native_lib(self.sess, Some(m.span),
|
2015-02-03 17:03:39 -06:00
|
|
|
n.to_string(), kind);
|
2014-12-21 00:36:50 -06:00
|
|
|
}
|
|
|
|
None => {}
|
|
|
|
}
|
2014-07-01 10:37:54 -05:00
|
|
|
}
|
2014-04-07 14:14:33 -05:00
|
|
|
}
|
2014-12-21 00:36:50 -06:00
|
|
|
_ => { }
|
2012-06-04 10:03:14 -05:00
|
|
|
}
|
2014-12-21 00:36:50 -06:00
|
|
|
}
|
2012-04-05 20:31:03 -05:00
|
|
|
|
2015-01-06 10:46:07 -06:00
|
|
|
fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind)
|
|
|
|
-> Option<ast::CrateNum> {
|
2014-12-21 00:36:50 -06:00
|
|
|
let mut ret = None;
|
|
|
|
self.sess.cstore.iter_crate_data(|cnum, data| {
|
2015-03-26 19:35:13 -05:00
|
|
|
if data.name != name { return }
|
2014-12-21 00:36:50 -06:00
|
|
|
|
|
|
|
match hash {
|
|
|
|
Some(hash) if *hash == data.hash() => { ret = Some(cnum); return }
|
|
|
|
Some(..) => return,
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
|
2015-01-06 10:46:07 -06:00
|
|
|
// When the hash is None we're dealing with a top-level dependency
|
|
|
|
// in which case we may have a specification on the command line for
|
|
|
|
// this library. Even though an upstream library may have loaded
|
|
|
|
// something of the same name, we have to make sure it was loaded
|
|
|
|
// from the exact same location as well.
|
2014-12-21 00:36:50 -06:00
|
|
|
//
|
|
|
|
// We're also sure to compare *paths*, not actual byte slices. The
|
|
|
|
// `source` stores paths which are normalized which may be different
|
|
|
|
// from the strings on the command line.
|
|
|
|
let source = self.sess.cstore.get_used_crate_source(cnum).unwrap();
|
2015-01-06 10:46:07 -06:00
|
|
|
if let Some(locs) = self.sess.opts.externs.get(name) {
|
|
|
|
let found = locs.iter().any(|l| {
|
2015-02-18 13:48:57 -06:00
|
|
|
let l = fs::realpath(&Path::new(&l[..])).ok();
|
2015-01-06 10:46:07 -06:00
|
|
|
source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
|
|
|
|
source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
|
|
|
|
});
|
|
|
|
if found {
|
|
|
|
ret = Some(cnum);
|
2014-12-21 00:36:50 -06:00
|
|
|
}
|
2015-01-30 11:48:23 -06:00
|
|
|
return
|
2015-01-06 10:46:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Alright, so we've gotten this far which means that `data` has the
|
|
|
|
// right name, we don't have a hash, and we don't have a --extern
|
|
|
|
// pointing for ourselves. We're still not quite yet done because we
|
|
|
|
// have to make sure that this crate was found in the crate lookup
|
|
|
|
// path (this is a top-level dependency) as we don't want to
|
|
|
|
// implicitly load anything inside the dependency lookup path.
|
|
|
|
let prev_kind = source.dylib.as_ref().or(source.rlib.as_ref())
|
|
|
|
.unwrap().1;
|
|
|
|
if ret.is_none() && (prev_kind == kind || prev_kind == PathKind::All) {
|
|
|
|
ret = Some(cnum);
|
2014-12-21 00:36:50 -06:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return ret;
|
|
|
|
}
|
2014-04-17 10:52:25 -05:00
|
|
|
|
2014-12-21 00:36:50 -06:00
|
|
|
fn register_crate(&mut self,
|
|
|
|
root: &Option<CratePaths>,
|
|
|
|
ident: &str,
|
|
|
|
name: &str,
|
|
|
|
span: Span,
|
|
|
|
lib: loader::Library)
|
|
|
|
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
|
|
|
|
cstore::CrateSource) {
|
|
|
|
// Claim this crate number and cache it
|
|
|
|
let cnum = self.next_crate_num;
|
|
|
|
self.next_crate_num += 1;
|
|
|
|
|
|
|
|
// Stash paths for top-most crate locally if necessary.
|
|
|
|
let crate_paths = if root.is_none() {
|
|
|
|
Some(CratePaths {
|
|
|
|
ident: ident.to_string(),
|
2015-01-06 10:46:07 -06:00
|
|
|
dylib: lib.dylib.clone().map(|p| p.0),
|
|
|
|
rlib: lib.rlib.clone().map(|p| p.0),
|
2014-12-21 00:36:50 -06:00
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
// Maintain a reference to the top most crate.
|
|
|
|
let root = if root.is_some() { root } else { &crate_paths };
|
2014-04-17 10:52:25 -05:00
|
|
|
|
2015-02-11 11:29:49 -06:00
|
|
|
let loader::Library { dylib, rlib, metadata } = lib;
|
2014-04-17 10:52:25 -05:00
|
|
|
|
2015-02-11 11:29:49 -06:00
|
|
|
let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), span);
|
|
|
|
let codemap_import_info = import_codemap(self.sess.codemap(), &metadata);
|
2014-04-17 10:52:25 -05:00
|
|
|
|
2014-12-21 00:36:50 -06:00
|
|
|
let cmeta = Rc::new( cstore::crate_metadata {
|
|
|
|
name: name.to_string(),
|
|
|
|
data: metadata,
|
|
|
|
cnum_map: cnum_map,
|
|
|
|
cnum: cnum,
|
2015-02-11 11:29:49 -06:00
|
|
|
codemap_import_info: codemap_import_info,
|
2014-12-21 00:36:50 -06:00
|
|
|
span: span,
|
|
|
|
});
|
2014-04-17 10:52:25 -05:00
|
|
|
|
2014-12-21 00:36:50 -06:00
|
|
|
let source = cstore::CrateSource {
|
|
|
|
dylib: dylib,
|
|
|
|
rlib: rlib,
|
|
|
|
cnum: cnum,
|
|
|
|
};
|
|
|
|
|
|
|
|
self.sess.cstore.set_crate_data(cnum, cmeta.clone());
|
|
|
|
self.sess.cstore.add_used_crate_source(source.clone());
|
|
|
|
(cnum, cmeta, source)
|
|
|
|
}
|
2014-04-17 10:52:25 -05:00
|
|
|
|
2014-12-21 00:36:50 -06:00
|
|
|
fn resolve_crate(&mut self,
|
|
|
|
root: &Option<CratePaths>,
|
|
|
|
ident: &str,
|
|
|
|
name: &str,
|
|
|
|
hash: Option<&Svh>,
|
|
|
|
span: Span,
|
|
|
|
kind: PathKind)
|
|
|
|
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
|
|
|
|
cstore::CrateSource) {
|
2015-01-06 10:46:07 -06:00
|
|
|
match self.existing_match(name, hash, kind) {
|
2014-12-21 00:36:50 -06:00
|
|
|
None => {
|
|
|
|
let mut load_ctxt = loader::Context {
|
|
|
|
sess: self.sess,
|
|
|
|
span: span,
|
|
|
|
ident: ident,
|
|
|
|
crate_name: name,
|
|
|
|
hash: hash.map(|a| &*a),
|
|
|
|
filesearch: self.sess.target_filesearch(kind),
|
2015-01-08 19:14:10 -06:00
|
|
|
target: &self.sess.target.target,
|
2015-02-20 13:08:14 -06:00
|
|
|
triple: &self.sess.opts.target_triple,
|
2014-12-21 00:36:50 -06:00
|
|
|
root: root,
|
|
|
|
rejected_via_hash: vec!(),
|
|
|
|
rejected_via_triple: vec!(),
|
2015-02-05 14:28:17 -06:00
|
|
|
rejected_via_kind: vec!(),
|
2014-12-21 00:36:50 -06:00
|
|
|
should_match_name: true,
|
|
|
|
};
|
|
|
|
let library = load_ctxt.load_library_crate();
|
|
|
|
self.register_crate(root, ident, name, span, library)
|
|
|
|
}
|
|
|
|
Some(cnum) => (cnum,
|
|
|
|
self.sess.cstore.get_crate_data(cnum),
|
|
|
|
self.sess.cstore.get_used_crate_source(cnum).unwrap())
|
2014-02-24 20:13:51 -06:00
|
|
|
}
|
2012-04-05 20:31:03 -05:00
|
|
|
}
|
2011-05-26 19:16:54 -05:00
|
|
|
|
2014-12-21 00:36:50 -06:00
|
|
|
// Go through the crate metadata and load any crates that it references
|
|
|
|
fn resolve_crate_deps(&mut self,
|
|
|
|
root: &Option<CratePaths>,
|
|
|
|
cdata: &[u8], span : Span)
|
|
|
|
-> cstore::cnum_map {
|
|
|
|
debug!("resolving deps of external crate");
|
|
|
|
// The map from crate numbers in the crate we're resolving to local crate
|
|
|
|
// numbers
|
|
|
|
decoder::get_crate_deps(cdata).iter().map(|dep| {
|
|
|
|
debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
|
|
|
|
let (local_cnum, _, _) = self.resolve_crate(root,
|
2015-02-20 13:08:14 -06:00
|
|
|
&dep.name,
|
|
|
|
&dep.name,
|
2014-12-21 00:36:50 -06:00
|
|
|
Some(&dep.hash),
|
|
|
|
span,
|
|
|
|
PathKind::Dependency);
|
|
|
|
(dep.cnum, local_cnum)
|
|
|
|
}).collect()
|
|
|
|
}
|
2013-12-25 12:10:33 -06:00
|
|
|
|
2015-02-11 20:43:16 -06:00
|
|
|
fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate {
|
2015-02-20 13:08:14 -06:00
|
|
|
let target_triple = &self.sess.opts.target_triple[..];
|
2014-11-15 19:30:33 -06:00
|
|
|
let is_cross = target_triple != config::host_triple();
|
2014-04-17 10:52:25 -05:00
|
|
|
let mut should_link = info.should_link && !is_cross;
|
2014-12-31 21:48:39 -06:00
|
|
|
let mut target_only = false;
|
|
|
|
let ident = info.ident.clone();
|
|
|
|
let name = info.name.clone();
|
2014-04-17 10:52:25 -05:00
|
|
|
let mut load_ctxt = loader::Context {
|
2014-12-21 01:02:38 -06:00
|
|
|
sess: self.sess,
|
2014-12-09 10:03:05 -06:00
|
|
|
span: span,
|
2015-02-18 13:48:57 -06:00
|
|
|
ident: &ident[..],
|
|
|
|
crate_name: &name[..],
|
2014-04-17 10:52:25 -05:00
|
|
|
hash: None,
|
2014-12-21 01:02:38 -06:00
|
|
|
filesearch: self.sess.host_filesearch(PathKind::Crate),
|
2015-01-08 19:14:10 -06:00
|
|
|
target: &self.sess.host,
|
2014-11-15 19:30:33 -06:00
|
|
|
triple: config::host_triple(),
|
2014-04-17 10:52:25 -05:00
|
|
|
root: &None,
|
|
|
|
rejected_via_hash: vec!(),
|
|
|
|
rejected_via_triple: vec!(),
|
2015-02-05 14:28:17 -06:00
|
|
|
rejected_via_kind: vec!(),
|
2014-07-01 10:37:54 -05:00
|
|
|
should_match_name: true,
|
2014-04-17 10:52:25 -05:00
|
|
|
};
|
|
|
|
let library = match load_ctxt.maybe_load_library_crate() {
|
2014-07-09 21:13:28 -05:00
|
|
|
Some(l) => l,
|
2014-04-17 10:52:25 -05:00
|
|
|
None if is_cross => {
|
2015-01-06 10:46:07 -06:00
|
|
|
// Try loading from target crates. This will abort later if we
|
|
|
|
// try to load a plugin registrar function,
|
2014-12-31 21:48:39 -06:00
|
|
|
target_only = true;
|
|
|
|
should_link = info.should_link;
|
|
|
|
|
2015-01-08 19:14:10 -06:00
|
|
|
load_ctxt.target = &self.sess.target.target;
|
2014-04-17 10:52:25 -05:00
|
|
|
load_ctxt.triple = target_triple;
|
2014-12-21 01:02:38 -06:00
|
|
|
load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate);
|
2014-12-31 21:48:39 -06:00
|
|
|
load_ctxt.load_library_crate()
|
2014-04-17 10:52:25 -05:00
|
|
|
}
|
|
|
|
None => { load_ctxt.report_load_errs(); unreachable!() },
|
|
|
|
};
|
2014-12-30 21:10:46 -06:00
|
|
|
|
2014-12-31 21:48:39 -06:00
|
|
|
let dylib = library.dylib.clone();
|
2015-03-07 20:08:48 -06:00
|
|
|
let register = should_link && self.existing_match(&info.name,
|
2015-01-06 10:46:07 -06:00
|
|
|
None,
|
|
|
|
PathKind::Crate).is_none();
|
2014-12-31 21:48:39 -06:00
|
|
|
let metadata = if register {
|
|
|
|
// Register crate now to avoid double-reading metadata
|
2015-02-20 13:08:14 -06:00
|
|
|
let (_, cmd, _) = self.register_crate(&None, &info.ident,
|
|
|
|
&info.name, span, library);
|
2014-12-31 21:48:39 -06:00
|
|
|
PMDSource::Registered(cmd)
|
|
|
|
} else {
|
|
|
|
// Not registering the crate; just hold on to the metadata
|
|
|
|
PMDSource::Owned(library.metadata)
|
|
|
|
};
|
|
|
|
|
2015-02-11 20:43:16 -06:00
|
|
|
ExtensionCrate {
|
2014-12-31 21:48:39 -06:00
|
|
|
metadata: metadata,
|
2015-01-06 10:46:07 -06:00
|
|
|
dylib: dylib.map(|p| p.0),
|
2014-12-31 21:48:39 -06:00
|
|
|
target_only: target_only,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-11 20:43:16 -06:00
|
|
|
/// Read exported macros.
|
|
|
|
pub fn read_exported_macros(&mut self, krate: &ast::Item) -> Vec<ast::MacroDef> {
|
|
|
|
let ci = self.extract_crate_info(krate).unwrap();
|
|
|
|
let ekrate = self.read_extension_crate(krate.span, &ci);
|
2014-12-09 10:03:05 -06:00
|
|
|
|
2015-02-11 20:43:16 -06:00
|
|
|
let source_name = format!("<{} macros>", krate.ident);
|
2014-12-30 21:10:46 -06:00
|
|
|
let mut macros = vec![];
|
2015-02-11 20:43:16 -06:00
|
|
|
decoder::each_exported_macro(ekrate.metadata.as_slice(),
|
2014-12-31 21:48:39 -06:00
|
|
|
&*self.sess.cstore.intr,
|
2014-12-30 21:10:46 -06:00
|
|
|
|name, attrs, body| {
|
|
|
|
// NB: Don't use parse::parse_tts_from_source_str because it parses with
|
|
|
|
// quote_depth > 0.
|
|
|
|
let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess,
|
|
|
|
self.sess.opts.cfg.clone(),
|
|
|
|
source_name.clone(),
|
|
|
|
body);
|
|
|
|
let lo = p.span.lo;
|
|
|
|
let body = p.parse_all_token_trees();
|
|
|
|
let span = mk_sp(lo, p.last_span.hi);
|
|
|
|
p.abort_if_errors();
|
|
|
|
macros.push(ast::MacroDef {
|
|
|
|
ident: name.ident(),
|
|
|
|
attrs: attrs,
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
span: span,
|
2015-02-11 20:43:16 -06:00
|
|
|
imported_from: Some(krate.ident),
|
2015-01-02 14:50:45 -06:00
|
|
|
// overridden in plugin/load.rs
|
|
|
|
export: false,
|
|
|
|
use_locally: false,
|
Add #[allow_internal_unstable] to track stability for macros better.
Unstable items used in a macro expansion will now always trigger
stability warnings, *unless* the unstable items are directly inside a
macro marked with `#[allow_internal_unstable]`. IOW, the compiler warns
unless the span of the unstable item is a subspan of the definition of a
macro marked with that attribute.
E.g.
#[allow_internal_unstable]
macro_rules! foo {
($e: expr) => {{
$e;
unstable(); // no warning
only_called_by_foo!();
}}
}
macro_rules! only_called_by_foo {
() => { unstable() } // warning
}
foo!(unstable()) // warning
The unstable inside `foo` is fine, due to the attribute. But the
`unstable` inside `only_called_by_foo` is not, since that macro doesn't
have the attribute, and the `unstable` passed into `foo` is also not
fine since it isn't contained in the macro itself (that is, even though
it is only used directly in the macro).
In the process this makes the stability tracking much more precise,
e.g. previously `println!("{}", unstable())` got no warning, but now it
does. As such, this is a bug fix that may cause [breaking-change]s.
The attribute is definitely feature gated, since it explicitly allows
side-stepping the feature gating system.
2015-02-28 21:09:28 -06:00
|
|
|
allow_internal_unstable: false,
|
2015-01-02 14:50:45 -06:00
|
|
|
|
2014-12-30 21:10:46 -06:00
|
|
|
body: body,
|
|
|
|
});
|
|
|
|
true
|
|
|
|
}
|
|
|
|
);
|
2014-12-31 21:48:39 -06:00
|
|
|
macros
|
|
|
|
}
|
2014-12-30 21:10:46 -06:00
|
|
|
|
2014-12-31 21:48:39 -06:00
|
|
|
/// Look for a plugin registrar. Returns library path and symbol name.
|
2015-02-26 23:00:43 -06:00
|
|
|
pub fn find_plugin_registrar(&mut self, span: Span, name: &str)
|
|
|
|
-> Option<(PathBuf, String)> {
|
2015-02-11 20:43:16 -06:00
|
|
|
let ekrate = self.read_extension_crate(span, &CrateInfo {
|
|
|
|
name: name.to_string(),
|
|
|
|
ident: name.to_string(),
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
should_link: false,
|
|
|
|
});
|
|
|
|
|
|
|
|
if ekrate.target_only {
|
2014-12-31 21:48:39 -06:00
|
|
|
// Need to abort before syntax expansion.
|
2015-02-11 20:43:16 -06:00
|
|
|
let message = format!("plugin `{}` is not available for triple `{}` \
|
2014-12-31 21:48:39 -06:00
|
|
|
(only found {})",
|
2015-02-11 20:43:16 -06:00
|
|
|
name,
|
2014-12-31 21:48:39 -06:00
|
|
|
config::host_triple(),
|
|
|
|
self.sess.opts.target_triple);
|
2015-02-18 13:48:57 -06:00
|
|
|
self.sess.span_err(span, &message[..]);
|
2014-12-31 21:48:39 -06:00
|
|
|
self.sess.abort_if_errors();
|
2014-07-09 21:13:28 -05:00
|
|
|
}
|
2014-12-31 21:48:39 -06:00
|
|
|
|
2015-02-11 20:43:16 -06:00
|
|
|
let registrar = decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice())
|
|
|
|
.map(|id| decoder::get_symbol(ekrate.metadata.as_slice(), id));
|
2014-12-31 21:48:39 -06:00
|
|
|
|
2015-02-11 20:43:16 -06:00
|
|
|
match (ekrate.dylib.as_ref(), registrar) {
|
2015-02-26 23:00:43 -06:00
|
|
|
(Some(dylib), Some(reg)) => Some((dylib.to_path_buf(), reg)),
|
2014-12-31 21:48:39 -06:00
|
|
|
(None, Some(_)) => {
|
2015-02-11 20:43:16 -06:00
|
|
|
let message = format!("plugin `{}` only found in rlib format, \
|
2014-12-31 21:48:39 -06:00
|
|
|
but must be available in dylib format",
|
2015-02-11 20:43:16 -06:00
|
|
|
name);
|
2015-02-18 13:48:57 -06:00
|
|
|
self.sess.span_err(span, &message[..]);
|
2014-12-31 21:48:39 -06:00
|
|
|
// No need to abort because the loading code will just ignore this
|
|
|
|
// empty dylib.
|
|
|
|
None
|
|
|
|
}
|
|
|
|
_ => None,
|
2013-12-25 12:10:33 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-02-11 11:29:49 -06:00
|
|
|
|
|
|
|
/// Imports the codemap from an external crate into the codemap of the crate
|
|
|
|
/// currently being compiled (the "local crate").
|
|
|
|
///
|
|
|
|
/// The import algorithm works analogous to how AST items are inlined from an
|
|
|
|
/// external crate's metadata:
|
|
|
|
/// For every FileMap in the external codemap an 'inline' copy is created in the
|
|
|
|
/// local codemap. The correspondence relation between external and local
|
|
|
|
/// FileMaps is recorded in the `ImportedFileMap` objects returned from this
|
|
|
|
/// function. When an item from an external crate is later inlined into this
|
|
|
|
/// crate, this correspondence information is used to translate the span
|
|
|
|
/// information of the inlined item so that it refers the correct positions in
|
|
|
|
/// the local codemap (see `astencode::DecodeContext::tr_span()`).
|
|
|
|
///
|
|
|
|
/// The import algorithm in the function below will reuse FileMaps already
|
|
|
|
/// existing in the local codemap. For example, even if the FileMap of some
|
|
|
|
/// source file of libstd gets imported many times, there will only ever be
|
|
|
|
/// one FileMap object for the corresponding file in the local codemap.
|
|
|
|
///
|
|
|
|
/// Note that imported FileMaps do not actually contain the source code of the
|
|
|
|
/// file they represent, just information about length, line breaks, and
|
|
|
|
/// multibyte characters. This information is enough to generate valid debuginfo
|
|
|
|
/// for items inlined from other crates.
|
|
|
|
fn import_codemap(local_codemap: &codemap::CodeMap,
|
|
|
|
metadata: &MetadataBlob)
|
|
|
|
-> Vec<cstore::ImportedFileMap> {
|
|
|
|
let external_codemap = decoder::get_imported_filemaps(metadata.as_slice());
|
|
|
|
|
|
|
|
let imported_filemaps = external_codemap.into_iter().map(|filemap_to_import| {
|
|
|
|
// Try to find an existing FileMap that can be reused for the filemap to
|
|
|
|
// be imported. A FileMap is reusable if it is exactly the same, just
|
|
|
|
// positioned at a different offset within the codemap.
|
|
|
|
let reusable_filemap = {
|
|
|
|
local_codemap.files
|
|
|
|
.borrow()
|
|
|
|
.iter()
|
|
|
|
.find(|fm| are_equal_modulo_startpos(&fm, &filemap_to_import))
|
|
|
|
.map(|rc| rc.clone())
|
|
|
|
};
|
|
|
|
|
|
|
|
match reusable_filemap {
|
|
|
|
Some(fm) => {
|
|
|
|
cstore::ImportedFileMap {
|
|
|
|
original_start_pos: filemap_to_import.start_pos,
|
|
|
|
original_end_pos: filemap_to_import.end_pos,
|
|
|
|
translated_filemap: fm
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
// We can't reuse an existing FileMap, so allocate a new one
|
|
|
|
// containing the information we need.
|
|
|
|
let codemap::FileMap {
|
|
|
|
name,
|
|
|
|
start_pos,
|
|
|
|
end_pos,
|
|
|
|
lines,
|
|
|
|
multibyte_chars,
|
|
|
|
..
|
|
|
|
} = filemap_to_import;
|
|
|
|
|
|
|
|
let source_length = (end_pos - start_pos).to_usize();
|
|
|
|
|
|
|
|
// Translate line-start positions and multibyte character
|
|
|
|
// position into frame of reference local to file.
|
|
|
|
// `CodeMap::new_imported_filemap()` will then translate those
|
|
|
|
// coordinates to their new global frame of reference when the
|
|
|
|
// offset of the FileMap is known.
|
|
|
|
let lines = lines.into_inner().map_in_place(|pos| pos - start_pos);
|
|
|
|
let multibyte_chars = multibyte_chars
|
|
|
|
.into_inner()
|
|
|
|
.map_in_place(|mbc|
|
|
|
|
codemap::MultiByteChar {
|
|
|
|
pos: mbc.pos + start_pos,
|
|
|
|
bytes: mbc.bytes
|
|
|
|
});
|
|
|
|
|
|
|
|
let local_version = local_codemap.new_imported_filemap(name,
|
|
|
|
source_length,
|
|
|
|
lines,
|
|
|
|
multibyte_chars);
|
|
|
|
cstore::ImportedFileMap {
|
|
|
|
original_start_pos: start_pos,
|
|
|
|
original_end_pos: end_pos,
|
|
|
|
translated_filemap: local_version
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}).collect();
|
|
|
|
|
|
|
|
return imported_filemaps;
|
|
|
|
|
|
|
|
fn are_equal_modulo_startpos(fm1: &codemap::FileMap,
|
|
|
|
fm2: &codemap::FileMap)
|
|
|
|
-> bool {
|
|
|
|
if fm1.name != fm2.name {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let lines1 = fm1.lines.borrow();
|
|
|
|
let lines2 = fm2.lines.borrow();
|
|
|
|
|
|
|
|
if lines1.len() != lines2.len() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (&line1, &line2) in lines1.iter().zip(lines2.iter()) {
|
|
|
|
if (line1 - fm1.start_pos) != (line2 - fm2.start_pos) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let multibytes1 = fm1.multibyte_chars.borrow();
|
|
|
|
let multibytes2 = fm2.multibyte_chars.borrow();
|
|
|
|
|
|
|
|
if multibytes1.len() != multibytes2.len() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (mb1, mb2) in multibytes1.iter().zip(multibytes2.iter()) {
|
|
|
|
if (mb1.bytes != mb2.bytes) ||
|
|
|
|
((mb1.pos - fm1.start_pos) != (mb2.pos - fm2.start_pos)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|