Skip to content

Commit

Permalink
rustc: Add a flag for specifying dependencies
Browse files Browse the repository at this point in the history
This comit implements a new flag, --extern, which is used to specify where a
crate is located. The purpose of this flag is to bypass the normal crate
loading/matching of the compiler to point it directly at the right file.

This flag takes the form `--extern foo=bar` where `foo` is the name of a crate
and `bar` is the location at which to find the crate. Multiple `--extern`
directives are allowed with the same crate name to specify the rlib/dylib pair
for a crate. It is invalid to specify more than one rlib or more than one dylib,
and it's required that the crates are valid rust crates.

I have also added some extensive documentation to metadata::loader about how
crate loading should work.

RFC: 0035-remove-crate-id
  • Loading branch information
alexcrichton committed Jul 5, 2014
1 parent df4ea9c commit cc3c8bb
Show file tree
Hide file tree
Showing 17 changed files with 444 additions and 15 deletions.
5 changes: 3 additions & 2 deletions src/librustc/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,10 +588,11 @@ pub fn find_crate_name(sess: Option<&Session>,
}), None)
}

pub fn build_link_meta(krate: &ast::Crate, name: String) -> LinkMeta {
pub fn build_link_meta(sess: &Session, krate: &ast::Crate,
name: String) -> LinkMeta {
let r = LinkMeta {
crate_name: name,
crate_hash: Svh::calculate(krate),
crate_hash: Svh::calculate(sess, krate),
};
info!("{}", r);
return r;
Expand Down
8 changes: 7 additions & 1 deletion src/librustc/back/svh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ use std::iter::range_step;
use syntax::ast;
use syntax::visit;

use driver::session::Session;

#[deriving(Clone, PartialEq)]
pub struct Svh {
hash: String,
Expand All @@ -68,7 +70,7 @@ impl Svh {
self.hash.as_slice()
}

pub fn calculate(krate: &ast::Crate) -> Svh {
pub fn calculate(sess: &Session, krate: &ast::Crate) -> Svh {
// FIXME (#14132): This is better than it used to be, but it still not
// ideal. We now attempt to hash only the relevant portions of the
// Crate AST as well as the top-level crate attributes. (However,
Expand All @@ -80,6 +82,10 @@ impl Svh {
// avoid collisions.
let mut state = SipState::new();

for data in sess.opts.cg.metadata.iter() {
data.hash(&mut state);
}

{
let mut visit = svh_visitor::make(&mut state);
visit::walk_crate(&mut visit, krate, ());
Expand Down
26 changes: 23 additions & 3 deletions src/librustc/driver/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use syntax::diagnostic::{ColorConfig, Auto, Always, Never};
use syntax::parse;
use syntax::parse::token::InternedString;

use std::collections::HashSet;
use std::collections::{HashSet, HashMap};
use getopts::{optopt, optmulti, optflag, optflagopt};
use getopts;
use lib::llvm::llvm;
Expand Down Expand Up @@ -95,6 +95,7 @@ pub struct Options {
pub print_metas: (bool, bool),
pub cg: CodegenOptions,
pub color: ColorConfig,
pub externs: HashMap<String, Vec<String>>,
}

/// Some reasonable defaults
Expand All @@ -120,6 +121,7 @@ pub fn basic_options() -> Options {
print_metas: (false, false),
cg: basic_codegen_options(),
color: Auto,
externs: HashMap::new(),
}
}

Expand Down Expand Up @@ -551,7 +553,9 @@ pub fn optgroups() -> Vec<getopts::OptGroup> {
optopt("", "color", "Configure coloring of output:
auto = colorize, if output goes to a tty (default);
always = always colorize output;
never = never colorize output", "auto|always|never")
never = never colorize output", "auto|always|never"),
optmulti("", "extern", "Specify where an external rust library is located",
"PATH"),
)
}

Expand Down Expand Up @@ -730,6 +734,21 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
}
};

let mut externs = HashMap::new();
for arg in matches.opt_strs("extern").iter() {
let mut parts = arg.as_slice().splitn('=', 1);
let name = match parts.next() {
Some(s) => s,
None => early_error("--extern value must not be empty"),
};
let location = match parts.next() {
Some(s) => s,
None => early_error("--extern value must be of the format `foo=bar`"),
};
let locs = externs.find_or_insert(name.to_string(), Vec::new());
locs.push(location.to_string());
}

Options {
crate_types: crate_types,
gc: gc,
Expand All @@ -750,7 +769,8 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
write_dependency_info: write_dependency_info,
print_metas: print_metas,
cg: cg,
color: color
color: color,
externs: externs,
}
}

Expand Down
32 changes: 27 additions & 5 deletions src/librustc/metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,12 +280,32 @@ fn existing_match(e: &Env, name: &str,
hash: Option<&Svh>) -> Option<ast::CrateNum> {
let mut ret = None;
e.sess.cstore.iter_crate_data(|cnum, data| {
if data.name().as_slice() == name {
let other_hash = data.hash();
match hash {
Some(hash) if *hash != other_hash => {}
Some(..) | None => { ret = Some(cnum); }
if data.name().as_slice() != name { return }

match hash {
Some(hash) if *hash == data.hash() => { ret = Some(cnum); return }
Some(..) => return,
None => {}
}

// 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.
let source = e.sess.cstore.get_used_crate_source(cnum).unwrap();
let dylib = source.dylib.as_ref().map(|p| p.as_vec());
let rlib = source.rlib.as_ref().map(|p| p.as_vec());
match e.sess.opts.externs.find_equiv(&name) {
Some(locs) => {
let found = locs.iter().any(|l| {
Some(l.as_bytes()) == dylib || Some(l.as_bytes()) == rlib
});
if found {
ret = Some(cnum);
}
}
None => ret = Some(cnum),
}
});
return ret;
Expand Down Expand Up @@ -361,6 +381,7 @@ fn resolve_crate<'a>(e: &mut Env,
root: root,
rejected_via_hash: vec!(),
rejected_via_triple: vec!(),
should_match_name: true,
};
let library = load_ctxt.load_library_crate();
register_crate(e, root, ident, name, span, library)
Expand Down Expand Up @@ -422,6 +443,7 @@ impl<'a> PluginMetadataReader<'a> {
root: &None,
rejected_via_hash: vec!(),
rejected_via_triple: vec!(),
should_match_name: true,
};
let library = match load_ctxt.maybe_load_library_crate() {
Some (l) => l,
Expand Down
Loading

0 comments on commit cc3c8bb

Please sign in to comment.