rustc: Simplify crate loading constraints

The previous code passed around a {name,version} pair everywhere, but this is
better expressed as a CrateId. This patch changes these paths to store and pass
around crate ids instead of these pairs of name/version. This also prepares the
code to change the type of hash that is stored in crates.
This commit is contained in:
Alex Crichton 2014-02-24 18:13:51 -08:00
parent 9b1be3d182
commit 8213e18447
8 changed files with 161 additions and 241 deletions

View File

@ -70,12 +70,12 @@ pub static tag_crate_deps: uint = 0x18;
pub static tag_crate_dep: uint = 0x19;
pub static tag_crate_hash: uint = 0x1a;
pub static tag_crate_crateid: uint = 0x1b;
pub static tag_parent_item: uint = 0x1b;
pub static tag_parent_item: uint = 0x1c;
pub static tag_crate_dep_name: uint = 0x1c;
pub static tag_crate_dep_hash: uint = 0x1d;
pub static tag_crate_dep_vers: uint = 0x1e;
pub static tag_crate_dep_crateid: uint = 0x1d;
pub static tag_crate_dep_hash: uint = 0x1e;
pub static tag_mod_impl: uint = 0x1f;

View File

@ -79,7 +79,7 @@ struct cache_entry {
cnum: ast::CrateNum,
span: Span,
hash: ~str,
crateid: CrateId,
crate_id: CrateId,
}
fn dump_crates(crate_cache: &[cache_entry]) {
@ -95,10 +95,10 @@ fn warn_if_multiple_versions(e: &mut Env,
diag: @SpanHandler,
crate_cache: &[cache_entry]) {
if crate_cache.len() != 0u {
let name = crate_cache[crate_cache.len() - 1].crateid.name.clone();
let name = crate_cache[crate_cache.len() - 1].crate_id.name.clone();
let (matches, non_matches) = crate_cache.partitioned(|entry|
name == entry.crateid.name);
name == entry.crate_id.name);
assert!(!matches.is_empty());
@ -107,7 +107,7 @@ fn warn_if_multiple_versions(e: &mut Env,
format!("using multiple versions of crate `{}`", name));
for match_ in matches.iter() {
diag.span_note(match_.span, "used here");
loader::note_crateid_attr(diag, &match_.crateid);
loader::note_crateid_attr(diag, &match_.crate_id);
}
}
@ -146,14 +146,9 @@ fn visit_view_item(e: &mut Env, i: &ast::ViewItem) {
return;
}
match extract_crate_info(i) {
match extract_crate_info(e, i) {
Some(info) => {
let cnum = resolve_crate(e,
None,
info.ident.clone(),
info.name.clone(),
info.version.clone(),
~"",
let cnum = resolve_crate(e, None, info.ident, &info.crate_id, "",
i.span);
e.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
}
@ -163,38 +158,33 @@ fn visit_view_item(e: &mut Env, i: &ast::ViewItem) {
struct CrateInfo {
ident: ~str,
name: ~str,
version: ~str,
crate_id: CrateId,
id: ast::NodeId,
}
fn extract_crate_info(i: &ast::ViewItem) -> Option<CrateInfo> {
fn extract_crate_info(e: &Env, i: &ast::ViewItem) -> Option<CrateInfo> {
match i.node {
ast::ViewItemExternMod(ident, ref path_opt, id) => {
let ident = token::get_ident(ident);
debug!("resolving extern crate stmt. ident: {:?} path_opt: {:?}",
ident, path_opt);
let (name, version) = match *path_opt {
let crate_id = match *path_opt {
Some((ref path_str, _)) => {
let crateid: Option<CrateId> = from_str(path_str.get());
match crateid {
None => (~"", ~""),
Some(crateid) => {
let version = match crateid.version {
None => ~"",
Some(ref ver) => ver.to_str(),
};
(crateid.name.to_str(), version)
None => {
e.sess.span_err(i.span, "malformed crate id");
return None
}
Some(id) => id
}
}
None => (ident.get().to_str(), ~""),
None => from_str(ident.get().to_str()).unwrap()
};
Some(CrateInfo {
ident: ident.get().to_str(),
name: name,
version: version,
id: id,
ident: ident.get().to_str(),
crate_id: crate_id,
id: id,
})
}
_ => None
@ -285,100 +275,93 @@ fn visit_item(e: &Env, i: &ast::Item) {
}
}
fn existing_match(e: &Env, name: &str, version: &str, hash: &str) -> Option<ast::CrateNum> {
fn existing_match(e: &Env, crate_id: &CrateId,
hash: &str) -> Option<ast::CrateNum> {
let crate_cache = e.crate_cache.borrow();
for c in crate_cache.get().iter() {
let crateid_version = match c.crateid.version {
None => ~"0.0",
Some(ref ver) => ver.to_str(),
};
if (name.is_empty() || name == c.crateid.name) &&
(version.is_empty() || version == crateid_version) &&
(hash.is_empty() || hash == c.hash) {
return Some(c.cnum);
if crate_id.matches(&c.crate_id) &&
(hash.is_empty() || hash == c.hash.as_slice()) {
return Some(c.cnum)
}
}
None
}
fn resolve_crate(e: &mut Env,
root_ident: Option<~str>,
ident: ~str,
name: ~str,
version: ~str,
hash: ~str,
root_ident: Option<&str>,
ident: &str,
crate_id: &CrateId,
hash: &str,
span: Span)
-> ast::CrateNum {
match existing_match(e, name, version, hash) {
None => {
let load_ctxt = loader::Context {
sess: e.sess,
span: span,
ident: ident,
name: name,
version: version,
hash: hash,
os: e.os,
intr: e.intr
};
let loader::Library {
dylib, rlib, metadata
} = load_ctxt.load_library_crate(root_ident.clone());
let attrs = decoder::get_crate_attributes(metadata.as_slice());
let crateid = attr::find_crateid(attrs).unwrap();
let hash = decoder::get_crate_hash(metadata.as_slice());
// Claim this crate number and cache it
let cnum = e.next_crate_num;
{
let mut crate_cache = e.crate_cache.borrow_mut();
crate_cache.get().push(cache_entry {
cnum: cnum,
match existing_match(e, crate_id, hash) {
None => {
let load_ctxt = loader::Context {
sess: e.sess,
span: span,
ident: ident,
crate_id: crate_id,
hash: hash,
crateid: crateid,
os: e.os,
intr: e.intr
};
let loader::Library {
dylib, rlib, metadata
} = load_ctxt.load_library_crate(root_ident);
let crate_id = decoder::get_crate_id(metadata.as_slice());
let hash = decoder::get_crate_hash(metadata.as_slice());
// Claim this crate number and cache it
let cnum = e.next_crate_num;
{
let mut crate_cache = e.crate_cache.borrow_mut();
crate_cache.get().push(cache_entry {
cnum: cnum,
span: span,
hash: hash,
crate_id: crate_id,
});
}
e.next_crate_num += 1;
// Maintain a reference to the top most crate.
let root_crate = match root_ident {
Some(c) => c,
None => load_ctxt.ident.clone()
};
// Now resolve the crates referenced by this crate
let cnum_map = resolve_crate_deps(e,
Some(root_crate),
metadata.as_slice(),
span);
let cmeta = @cstore::crate_metadata {
name: load_ctxt.crate_id.name.to_owned(),
data: metadata,
cnum_map: cnum_map,
cnum: cnum
};
let cstore = e.sess.cstore;
cstore.set_crate_data(cnum, cmeta);
cstore.add_used_crate_source(cstore::CrateSource {
dylib: dylib,
rlib: rlib,
cnum: cnum,
});
return cnum;
}
Some(cnum) => {
return cnum;
}
e.next_crate_num += 1;
// Maintain a reference to the top most crate.
let root_crate = match root_ident {
Some(c) => c,
None => load_ctxt.ident.clone()
};
// Now resolve the crates referenced by this crate
let cnum_map = resolve_crate_deps(e,
Some(root_crate),
metadata.as_slice(),
span);
let cmeta = @cstore::crate_metadata {
name: load_ctxt.name,
data: metadata,
cnum_map: cnum_map,
cnum: cnum
};
let cstore = e.sess.cstore;
cstore.set_crate_data(cnum, cmeta);
cstore.add_used_crate_source(cstore::CrateSource {
dylib: dylib,
rlib: rlib,
cnum: cnum,
});
return cnum;
}
Some(cnum) => {
return cnum;
}
}
}
// Go through the crate metadata and load any crates that it references
fn resolve_crate_deps(e: &mut Env,
root_ident: Option<~str>,
root_ident: Option<&str>,
cdata: &[u8], span : Span)
-> cstore::cnum_map {
debug!("resolving deps of external crate");
@ -388,31 +371,13 @@ fn resolve_crate_deps(e: &mut Env,
let r = decoder::get_crate_deps(cdata);
for dep in r.iter() {
let extrn_cnum = dep.cnum;
let cname_str = token::get_ident(dep.name);
debug!("resolving dep crate {} ver: {} hash: {}",
cname_str, dep.vers, dep.hash);
match existing_match(e,
cname_str.get(),
dep.vers,
dep.hash) {
Some(local_cnum) => {
debug!("already have it");
// We've already seen this crate
cnum_map.insert(extrn_cnum, local_cnum);
}
None => {
debug!("need to load it");
// This is a new one so we've got to load it
let local_cnum = resolve_crate(e,
root_ident.clone(),
cname_str.get().to_str(),
cname_str.get().to_str(),
dep.vers.clone(),
dep.hash.clone(),
span);
cnum_map.insert(extrn_cnum, local_cnum);
}
}
debug!("resolving dep crate {} hash: `{}`", dep.crate_id, dep.hash);
let local_cnum = resolve_crate(e, root_ident,
dep.crate_id.name.as_slice(),
&dep.crate_id,
dep.hash,
span);
cnum_map.insert(extrn_cnum, local_cnum);
}
return @RefCell::new(cnum_map);
}
@ -439,14 +404,9 @@ impl Loader {
impl CrateLoader for Loader {
fn load_crate(&mut self, krate: &ast::ViewItem) -> MacroCrate {
let info = extract_crate_info(krate).unwrap();
let cnum = resolve_crate(&mut self.env,
None,
info.ident.clone(),
info.name.clone(),
info.version.clone(),
~"",
krate.span);
let info = extract_crate_info(&self.env, krate).unwrap();
let cnum = resolve_crate(&mut self.env, None, info.ident,
&info.crate_id, "", krate.span);
let library = self.env.sess.cstore.get_used_crate_source(cnum).unwrap();
MacroCrate {
lib: library.dylib,

View File

@ -21,6 +21,7 @@ use collections::HashMap;
use extra::c_vec::CVec;
use syntax::ast;
use syntax::parse::token::IdentInterner;
use syntax::crateid::CrateId;
// A map from external crate numbers (as decoded from some crate file) to
// local crate numbers (as generated during this session). Each external
@ -96,9 +97,9 @@ impl CStore {
decoder::get_crate_hash(cdata.data())
}
pub fn get_crate_vers(&self, cnum: ast::CrateNum) -> ~str {
pub fn get_crate_id(&self, cnum: ast::CrateNum) -> CrateId {
let cdata = self.get_crate_data(cnum);
decoder::get_crate_vers(cdata.data())
decoder::get_crate_id(cdata.data())
}
pub fn set_crate_data(&self, cnum: ast::CrateNum, data: @crate_metadata) {
@ -191,41 +192,6 @@ impl CStore {
let extern_mod_crate_map = self.extern_mod_crate_map.borrow();
extern_mod_crate_map.get().find(&emod_id).map(|x| *x)
}
// returns hashes of crates directly used by this crate. Hashes are sorted by
// (crate name, crate version, crate hash) in lexicographic order (not semver)
pub fn get_dep_hashes(&self) -> ~[~str] {
let mut result = ~[];
let extern_mod_crate_map = self.extern_mod_crate_map.borrow();
for (_, &cnum) in extern_mod_crate_map.get().iter() {
let cdata = self.get_crate_data(cnum);
let hash = decoder::get_crate_hash(cdata.data());
let vers = decoder::get_crate_vers(cdata.data());
debug!("Add hash[{}]: {} {}", cdata.name, vers, hash);
result.push(crate_hash {
name: cdata.name.clone(),
vers: vers,
hash: hash
});
}
result.sort();
debug!("sorted:");
for x in result.iter() {
debug!(" hash[{}]: {}", x.name, x.hash);
}
result.move_iter().map(|crate_hash { hash, ..}| hash).collect()
}
}
#[deriving(Clone, TotalEq, TotalOrd)]
struct crate_hash {
name: ~str,
vers: ~str,
hash: ~str,
}
impl crate_metadata {

View File

@ -17,7 +17,6 @@ use metadata::common::*;
use metadata::csearch::StaticMethodInfo;
use metadata::csearch;
use metadata::cstore;
use metadata::decoder;
use metadata::tydecode::{parse_ty_data, parse_def_id,
parse_type_param_def_data,
parse_bare_fn_ty_data, parse_trait_ref_data};
@ -44,6 +43,7 @@ use syntax::parse::token;
use syntax::print::pprust;
use syntax::ast;
use syntax::codemap;
use syntax::crateid::CrateId;
type Cmd = @crate_metadata;
@ -1108,9 +1108,8 @@ pub fn get_crate_attributes(data: &[u8]) -> ~[ast::Attribute] {
#[deriving(Clone)]
pub struct CrateDep {
cnum: ast::CrateNum,
name: ast::Ident,
vers: ~str,
hash: ~str
crate_id: CrateId,
hash: ~str,
}
pub fn get_crate_deps(data: &[u8]) -> ~[CrateDep] {
@ -1123,10 +1122,13 @@ pub fn get_crate_deps(data: &[u8]) -> ~[CrateDep] {
d.as_str_slice().to_str()
}
reader::tagged_docs(depsdoc, tag_crate_dep, |depdoc| {
deps.push(CrateDep {cnum: crate_num,
name: token::str_to_ident(docstr(depdoc, tag_crate_dep_name)),
vers: docstr(depdoc, tag_crate_dep_vers),
hash: docstr(depdoc, tag_crate_dep_hash)});
let crate_id = from_str(docstr(depdoc, tag_crate_dep_crateid)).unwrap();
let hash = docstr(depdoc, tag_crate_dep_hash);
deps.push(CrateDep {
cnum: crate_num,
crate_id: crate_id,
hash: hash,
});
crate_num += 1;
true
});
@ -1135,17 +1137,9 @@ pub fn get_crate_deps(data: &[u8]) -> ~[CrateDep] {
fn list_crate_deps(data: &[u8], out: &mut io::Writer) -> io::IoResult<()> {
try!(write!(out, "=External Dependencies=\n"));
let r = get_crate_deps(data);
for dep in r.iter() {
try!(write!(out,
"{} {}-{}-{}\n",
dep.cnum,
token::get_ident(dep.name),
dep.hash,
dep.vers));
for dep in get_crate_deps(data).iter() {
try!(write!(out, "{} {}-{}\n", dep.cnum, dep.crate_id, dep.hash));
}
try!(write!(out, "\n"));
Ok(())
}
@ -1156,12 +1150,10 @@ pub fn get_crate_hash(data: &[u8]) -> ~str {
hashdoc.as_str_slice().to_str()
}
pub fn get_crate_vers(data: &[u8]) -> ~str {
let attrs = decoder::get_crate_attributes(data);
match attr::find_crateid(attrs) {
None => ~"0.0",
Some(crateid) => crateid.version_or_default().to_str(),
}
pub fn get_crate_id(data: &[u8]) -> CrateId {
let cratedoc = reader::Doc(data);
let hashdoc = reader::get_doc(cratedoc, tag_crate_crateid);
from_str(hashdoc.as_str_slice()).unwrap()
}
pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Writer) -> io::IoResult<()> {

View File

@ -40,6 +40,7 @@ use syntax::ast_util::*;
use syntax::ast_util;
use syntax::attr::AttrMetaMethods;
use syntax::attr;
use syntax::crateid::CrateId;
use syntax::diagnostic::SpanHandler;
use syntax::parse::token::InternedString;
use syntax::parse::token::special_idents;
@ -1510,8 +1511,7 @@ fn encode_crate_deps(ebml_w: &mut writer::Encoder, cstore: &cstore::CStore) {
cstore.iter_crate_data(|key, val| {
let dep = decoder::CrateDep {
cnum: key,
name: token::str_to_ident(val.name),
vers: decoder::get_crate_vers(val.data()),
crate_id: decoder::get_crate_id(val.data()),
hash: decoder::get_crate_hash(val.data())
};
deps.push(dep);
@ -1729,12 +1729,8 @@ fn encode_misc_info(ecx: &EncodeContext,
fn encode_crate_dep(ebml_w: &mut writer::Encoder,
dep: decoder::CrateDep) {
ebml_w.start_tag(tag_crate_dep);
ebml_w.start_tag(tag_crate_dep_name);
let s = token::get_ident(dep.name);
ebml_w.writer.write(s.get().as_bytes());
ebml_w.end_tag();
ebml_w.start_tag(tag_crate_dep_vers);
ebml_w.writer.write(dep.vers.as_bytes());
ebml_w.start_tag(tag_crate_dep_crateid);
ebml_w.writer.write(dep.crate_id.to_str().as_bytes());
ebml_w.end_tag();
ebml_w.start_tag(tag_crate_dep_hash);
ebml_w.writer.write(dep.hash.as_bytes());
@ -1748,6 +1744,12 @@ fn encode_hash(ebml_w: &mut writer::Encoder, hash: &str) {
ebml_w.end_tag();
}
fn encode_crate_id(ebml_w: &mut writer::Encoder, crate_id: &CrateId) {
ebml_w.start_tag(tag_crate_crateid);
ebml_w.writer.write(crate_id.to_str().as_bytes());
ebml_w.end_tag();
}
// NB: Increment this as you change the metadata encoding version.
pub static metadata_encoding_version : &'static [u8] =
&[0x72, //'r' as u8,
@ -1806,6 +1808,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
let mut ebml_w = writer::Encoder(wr);
encode_crate_id(&mut ebml_w, &ecx.link_meta.crateid);
encode_hash(&mut ebml_w, ecx.link_meta.crate_hash);
let mut i = ebml_w.writer.tell().unwrap();

View File

@ -44,13 +44,12 @@ pub enum Os {
OsFreebsd
}
pub struct Context {
pub struct Context<'a> {
sess: Session,
span: Span,
ident: ~str,
name: ~str,
version: ~str,
hash: ~str,
ident: &'a str,
crate_id: &'a CrateId,
hash: &'a str,
os: Os,
intr: @IdentInterner
}
@ -79,8 +78,8 @@ fn realpath(p: &Path) -> Path {
}
}
impl Context {
pub fn load_library_crate(&self, root_ident: Option<~str>) -> Library {
impl<'a> Context<'a> {
pub fn load_library_crate(&self, root_ident: Option<&str>) -> Library {
match self.find_library_crate() {
Some(t) => t,
None => {
@ -101,8 +100,8 @@ impl Context {
let (dyprefix, dysuffix) = self.dylibname();
// want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
let dylib_prefix = format!("{}{}-", dyprefix, self.name);
let rlib_prefix = format!("lib{}-", self.name);
let dylib_prefix = format!("{}{}-", dyprefix, self.crate_id.name);
let rlib_prefix = format!("lib{}-", self.crate_id.name);
let mut candidates = HashMap::new();
@ -196,7 +195,8 @@ impl Context {
1 => Some(libraries[0]),
_ => {
self.sess.span_err(self.span,
format!("multiple matching crates for `{}`", self.name));
format!("multiple matching crates for `{}`",
self.crate_id.name));
self.sess.note("candidates:");
for lib in libraries.iter() {
match lib.dylib {
@ -243,11 +243,12 @@ impl Context {
debug!("matching -- {}, hash: {}", file, hash);
let vers = match parts.next() { Some(v) => v, None => return None };
debug!("matching -- {}, vers: {}", file, vers);
if !self.version.is_empty() && self.version.as_slice() != vers {
return None
match self.crate_id.version {
Some(ref version) if version.as_slice() != vers => return None,
Some(..) | None => {}
}
debug!("matching -- {}, vers ok (requested {})", file,
self.version);
self.crate_id.version);
// hashes in filenames are prefixes of the "true hash"
if self.hash.is_empty() || self.hash.starts_with(hash) {
debug!("matching -- {}, hash ok (requested {})", file, self.hash);
@ -275,7 +276,7 @@ impl Context {
if m.len() > 1 {
self.sess.span_err(self.span,
format!("multiple {} candidates for `{}` \
found", flavor, self.name));
found", flavor, self.crate_id.name));
for (i, path) in m.iter().enumerate() {
self.sess.span_note(self.span,
format!(r"candidate \#{}: {}", i + 1,
@ -289,8 +290,7 @@ impl Context {
info!("{} reading meatadata from: {}", flavor, lib.display());
match get_metadata_section(self.os, &lib) {
Some(blob) => {
if crate_matches(blob.as_slice(), self.name,
self.version, self.hash) {
if crate_matches(blob.as_slice(), self.crate_id, self.hash){
*slot = Some(blob);
} else {
info!("metadata mismatch");
@ -323,23 +323,13 @@ pub fn note_crateid_attr(diag: @SpanHandler, crateid: &CrateId) {
diag.handler().note(format!("crate_id: {}", crateid.to_str()));
}
fn crate_matches(crate_data: &[u8],
name: &str,
version: &str,
hash: &str) -> bool {
let attrs = decoder::get_crate_attributes(crate_data);
match attr::find_crateid(attrs) {
None => false,
Some(crateid) => {
if !hash.is_empty() {
let chash = decoder::get_crate_hash(crate_data);
if chash.as_slice() != hash { return false; }
}
name == crateid.name &&
(version.is_empty() ||
crateid.version_or_default() == version)
}
fn crate_matches(crate_data: &[u8], crate_id: &CrateId, hash: &str) -> bool {
let other_id = decoder::get_crate_id(crate_data);
if !crate_id.matches(&other_id) { return false }
if hash != "" && hash != decoder::get_crate_hash(crate_data).as_slice() {
return false
}
return true;
}
impl ArchiveMetadata {

View File

@ -2488,7 +2488,7 @@ pub fn fill_crate_map(ccx: @CrateContext, map: ValueRef) {
let cdata = cstore.get_crate_data(i);
let nm = symname(format!("_rust_crate_map_{}", cdata.name),
cstore.get_crate_hash(i),
cstore.get_crate_vers(i));
cstore.get_crate_id(i).version_or_default());
let cr = nm.with_c_str(|buf| {
unsafe {
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf)

View File

@ -107,6 +107,15 @@ impl CrateId {
pub fn short_name_with_version(&self) -> ~str {
format!("{}-{}", self.name, self.version_or_default())
}
pub fn matches(&self, other: &CrateId) -> bool {
// FIXME: why does this not match on `path`?
if self.name != other.name { return false }
match (&self.version, &other.version) {
(&Some(ref v1), &Some(ref v2)) => v1 == v2,
_ => true,
}
}
}
#[test]