(index<- )        ./librustc/metadata/creader.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  #![allow(non_camel_case_types)]
  12  
  13  //! Validates all used crates and extern libraries and loads their metadata
  14  
  15  use back::link;
  16  use back::svh::Svh;
  17  use driver::session::Session;
  18  use driver::{driver, session};
  19  use metadata::cstore;
  20  use metadata::cstore::CStore;
  21  use metadata::decoder;
  22  use metadata::loader;
  23  use metadata::loader::CratePaths;
  24  
  25  use std::rc::Rc;
  26  use collections::HashMap;
  27  use syntax::ast;
  28  use syntax::abi;
  29  use syntax::attr;
  30  use syntax::attr::AttrMetaMethods;
  31  use syntax::codemap::{Span};
  32  use syntax::diagnostic::SpanHandler;
  33  use syntax::ext::base::{CrateLoader, MacroCrate};
  34  use syntax::parse::token::InternedString;
  35  use syntax::parse::token;
  36  use syntax::crateid::CrateId;
  37  use syntax::visit;
  38  
  39  struct Env<'a> {
  40      sess: &'a Session,
  41      next_crate_num: ast::CrateNum,
  42  }
  43  
  44  // Traverses an AST, reading all the information about use'd crates and extern
  45  // libraries necessary for later resolving, typechecking, linking, etc.
  46  pub fn read_crates(sess: &Session,
  47                     krate: &ast::Crate) {
  48      let mut e = Env {
  49          sess: sess,
  50          next_crate_num: sess.cstore.next_crate_num(),
  51      };
  52      visit_crate(&e, krate);
  53      visit::walk_crate(&mut e, krate, ());
  54      dump_crates(&sess.cstore);
  55      warn_if_multiple_versions(sess.diagnostic(), &sess.cstore)
  56  }
  57  
  58  impl<'a> visit::Visitor<()> for Env<'a> {
  59      fn visit_view_item(&mut self, a&ast::ViewItem, _()) {
  60          visit_view_item(self, a);
  61          visit::walk_view_item(self, a, ());
  62      }
  63      fn visit_item(&mut self, a&ast::Item, _()) {
  64          visit_item(self, a);
  65          visit::walk_item(self, a, ());
  66      }
  67  }
  68  
  69  fn dump_crates(cstore: &CStore) {
  70      debug!("resolved crates:");
  71      cstore.iter_crate_data(|_, data| {
  72          debug!("crate_id: {}", data.crate_id());
  73          debug!("  cnum: {}", data.cnum);
  74          debug!("  hash: {}", data.hash());
  75      })
  76  }
  77  
  78  fn warn_if_multiple_versions(diag: &SpanHandler, cstore: &CStore) {
  79      let mut map = HashMap::new();
  80      cstore.iter_crate_data(|cnum, data| {
  81          let crateid = data.crate_id();
  82          let key = (crateid.name.clone(), crateid.path.clone());
  83          map.find_or_insert_with(key, |_| Vec::new()).push(cnum);
  84      });
  85  
  86      for ((name, _), dupes) in map.move_iter() {
  87          if dupes.len() == 1 { continue }
  88          diag.handler().warn(
  89              format!("using multiple versions of crate `{}`", name));
  90          for dupe in dupes.move_iter() {
  91              let data = cstore.get_crate_data(dupe);
  92              diag.span_note(data.span, "used here");
  93              loader::note_crateid_attr(diag, &data.crate_id());
  94          }
  95      }
  96  }
  97  
  98  fn visit_crate(e: &Env, c: &ast::Crate) {
  99      for a in c.attrs.iter().filter(|m| m.name().equiv(&("link_args"))) {
 100          match a.value_str() {
 101              Some(ref linkarg) => e.sess.cstore.add_used_link_args(linkarg.get()),
 102              None => { /* fallthrough */ }
 103          }
 104      }
 105  }
 106  
 107  fn should_link(i: &ast::ViewItem) -> bool {
 108      i.attrs.iter().all(|attr| {
 109          attr.name().get() != "phase" ||
 110              attr.meta_item_list().map_or(false, |phases| {
 111                  attr::contains_name(phases.as_slice(), "link")
 112              })
 113      })
 114  }
 115  
 116  fn visit_view_item(e: &mut Env, i: &ast::ViewItem) {
 117      if !should_link(i) {
 118          return;
 119      }
 120  
 121      match extract_crate_info(e, i) {
 122          Some(info) => {
 123              let (cnum, _, _) = resolve_crate(e, &None, info.ident,
 124                                               &info.crate_id, None,
 125                                               i.span);
 126              e.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
 127          }
 128          None => ()
 129      }
 130  }
 131  
 132  struct CrateInfo {
 133      ident: ~str,
 134      crate_id: CrateId,
 135      id: ast::NodeId,
 136      should_link: bool,
 137  }
 138  
 139  fn extract_crate_info(e: &Env, i: &ast::ViewItem) -> Option<CrateInfo> {
 140      match i.node {
 141          ast::ViewItemExternCrate(ident, ref path_opt, id) => {
 142              let ident = token::get_ident(ident);
 143              debug!("resolving extern crate stmt. ident: {:?} path_opt: {:?}",
 144                     ident, path_opt);
 145              let crate_id = match *path_opt {
 146                  Some((ref path_str, _)) => {
 147                      let crateidOption<CrateId> = from_str(path_str.get());
 148                      match crateid {
 149                          None => {
 150                              e.sess.span_err(i.span, "malformed crate id");
 151                              return None
 152                          }
 153                          Some(id) => id
 154                      }
 155                  }
 156                  None => from_str(ident.get().to_str()).unwrap()
 157              };
 158              Some(CrateInfo {
 159                  ident: ident.get().to_str(),
 160                  crate_id: crate_id,
 161                  id: id,
 162                  should_link: should_link(i),
 163              })
 164          }
 165          _ => None
 166      }
 167  }
 168  
 169  fn visit_item(e: &Env, i: &ast::Item) {
 170      match i.node {
 171          ast::ItemForeignMod(ref fm) => {
 172              if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic {
 173                  return;
 174              }
 175  
 176              // First, add all of the custom link_args attributes
 177              let link_args = i.attrs.iter()
 178                  .filter_map(|at| if at.name().equiv(&("link_args")) {
 179                      Some(at)
 180                  } else {
 181                      None
 182                  })
 183                  .collect::<Vec<&ast::Attribute>>();
 184              for m in link_args.iter() {
 185                  match m.value_str() {
 186                      Some(linkarg) => e.sess.cstore.add_used_link_args(linkarg.get()),
 187                      None => { /* fallthrough */ }
 188                  }
 189              }
 190  
 191              // Next, process all of the #[link(..)]-style arguments
 192              let link_args = i.attrs.iter()
 193                  .filter_map(|at| if at.name().equiv(&("link")) {
 194                      Some(at)
 195                  } else {
 196                      None
 197                  })
 198                  .collect::<Vec<&ast::Attribute>>();
 199              for m in link_args.iter() {
 200                  match m.meta_item_list() {
 201                      Some(items) => {
 202                          let kind = items.iter().find(|k| {
 203                              k.name().equiv(&("kind"))
 204                          }).and_then(|a| a.value_str());
 205                          let kind = match kind {
 206                              Some(k) => {
 207                                  if k.equiv(&("static")) {
 208                                      cstore::NativeStatic
 209                                  } else if e.sess.targ_cfg.os == abi::OsMacos &&
 210                                            k.equiv(&("framework")) {
 211                                      cstore::NativeFramework
 212                                  } else if k.equiv(&("framework")) {
 213                                      e.sess.span_err(m.span,
 214                                          "native frameworks are only available \
 215                                           on OSX targets");
 216                                      cstore::NativeUnknown
 217                                  } else {
 218                                      e.sess.span_err(m.span,
 219                                          format!("unknown kind: `{}`", k));
 220                                      cstore::NativeUnknown
 221                                  }
 222                              }
 223                              None => cstore::NativeUnknown
 224                          };
 225                          let n = items.iter().find(|n| {
 226                              n.name().equiv(&("name"))
 227                          }).and_then(|a| a.value_str());
 228                          let n = match n {
 229                              Some(n) => n,
 230                              None => {
 231                                  e.sess.span_err(m.span,
 232                                      "#[link(...)] specified without \
 233                                       `name = \"foo\"`");
 234                                  InternedString::new("foo")
 235                              }
 236                          };
 237                          if n.get().is_empty() {
 238                              e.sess.span_err(m.span, "#[link(name = \"\")] given with empty name");
 239                          } else {
 240                              e.sess.cstore.add_used_library(n.get().to_owned(), kind);
 241                          }
 242                      }
 243                      None => {}
 244                  }
 245              }
 246          }
 247          _ => { }
 248      }
 249  }
 250  
 251  fn existing_match(e: &Env, crate_id: &CrateId,
 252                    hashOption<&Svh>) -> Option<ast::CrateNum> {
 253      let mut ret = None;
 254      e.sess.cstore.iter_crate_data(|cnum, data| {
 255          let other_id = data.crate_id();
 256          if crate_id.matches(&other_id) {
 257              let other_hash = data.hash();
 258              match hash {
 259                  Some(hash) if *hash != other_hash => {}
 260                  Some(..) | None => { ret = Some(cnum); }
 261              }
 262          }
 263      });
 264      return ret;
 265  }
 266  
 267  fn register_crate<'a>(e: &mut Env,
 268                    root: &Option<CratePaths>,
 269                    ident: &str,
 270                    crate_id: &CrateId,
 271                    spanSpan,
 272                    libloader::Library)
 273                          -> (ast::CrateNum, Rc<cstore::crate_metadata>,
 274                              cstore::CrateSource) {
 275      // Claim this crate number and cache it
 276      let cnum = e.next_crate_num;
 277      e.next_crate_num += 1;
 278  
 279      // Stash paths for top-most crate locally if necessary.
 280      let crate_paths = if root.is_none() {
 281          Some(CratePaths {
 282              ident: ident.to_owned(),
 283              dylib: lib.dylib.clone(),
 284              rlib:  lib.rlib.clone(),
 285          })
 286      } else {
 287          None
 288      };
 289      // Maintain a reference to the top most crate.
 290      let root = if root.is_some() { root } else { &crate_paths };
 291  
 292      let cnum_map = resolve_crate_deps(e, root, lib.metadata.as_slice(), span);
 293  
 294      let loader::Library{ dylib, rlib, metadata } = lib;
 295  
 296      let cmeta = Rc::new( cstore::crate_metadata {
 297          name: crate_id.name.to_owned(),
 298          data: metadata,
 299          cnum_map: cnum_map,
 300          cnum: cnum,
 301          span: span,
 302      });
 303  
 304      let source = cstore::CrateSource {
 305          dylib: dylib,
 306          rlib: rlib,
 307          cnum: cnum,
 308      };
 309  
 310      e.sess.cstore.set_crate_data(cnum, cmeta.clone());
 311      e.sess.cstore.add_used_crate_source(source.clone());
 312      (cnum, cmeta, source)
 313  }
 314  
 315  fn resolve_crate<'a>(e: &mut Env,
 316                   root: &Option<CratePaths>,
 317                   ident: &str,
 318                   crate_id: &CrateId,
 319                   hashOption<&Svh>,
 320                   spanSpan)
 321                       -> (ast::CrateNum, Rc<cstore::crate_metadata>,
 322                           cstore::CrateSource) {
 323      match existing_match(e, crate_id, hash) {
 324          None => {
 325              let id_hash = link::crate_id_hash(crate_id);
 326              let mut load_ctxt = loader::Context {
 327                  sess: e.sess,
 328                  span: span,
 329                  ident: ident,
 330                  crate_id: crate_id,
 331                  id_hash: id_hash,
 332                  hash: hash.map(|a| &*a),
 333                  filesearch: e.sess.target_filesearch(),
 334                  os: session::sess_os_to_meta_os(e.sess.targ_cfg.os),
 335                  triple: e.sess.targ_cfg.target_strs.target_triple.as_slice(),
 336                  root: root,
 337                  rejected_via_hash: vec!(),
 338                  rejected_via_triple: vec!(),
 339              };
 340              let library = load_ctxt.load_library_crate();
 341              register_crate(e, root, ident, crate_id, span, library)
 342          }
 343          Some(cnum) => (cnum,
 344                         e.sess.cstore.get_crate_data(cnum),
 345                         e.sess.cstore.get_used_crate_source(cnum).unwrap())
 346      }
 347  }
 348  
 349  // Go through the crate metadata and load any crates that it references
 350  fn resolve_crate_deps(e: &mut Env,
 351                        root: &Option<CratePaths>,
 352                        cdata: &[u8], span : Span)
 353                     -> cstore::cnum_map {
 354      debug!("resolving deps of external crate");
 355      // The map from crate numbers in the crate we're resolving to local crate
 356      // numbers
 357      decoder::get_crate_deps(cdata).iter().map(|dep| {
 358          debug!("resolving dep crate {} hash: `{}`", dep.crate_id, dep.hash);
 359          let (local_cnum, _, _) = resolve_crate(e, root,
 360                                                 dep.crate_id.name.as_slice(),
 361                                                 &dep.crate_id,
 362                                                 Some(&dep.hash),
 363                                                 span);
 364          (dep.cnum, local_cnum)
 365      }).collect()
 366  }
 367  
 368  pub struct Loader<'a> {
 369      env: Env<'a>,
 370  }
 371  
 372  impl<'a> Loader<'a> {
 373      pub fn new(sess&'a Session) -> Loader<'a> {
 374          Loader {
 375              env: Env {
 376                  sess: sess,
 377                  next_crate_num: sess.cstore.next_crate_num(),
 378              }
 379          }
 380      }
 381  }
 382  
 383  impl<'a> CrateLoader for Loader<'a> {
 384      fn load_crate(&mut self, krate&ast::ViewItem) -> MacroCrate {
 385          let info = extract_crate_info(&self.env, krate).unwrap();
 386          let target_triple = self.env.sess.targ_cfg.target_strs.target_triple.as_slice();
 387          let is_cross = target_triple != driver::host_triple();
 388          let mut should_link = info.should_link && !is_cross;
 389          let id_hash = link::crate_id_hash(&info.crate_id);
 390          let os = driver::get_os(driver::host_triple()).unwrap();
 391          let mut load_ctxt = loader::Context {
 392              sess: self.env.sess,
 393              span: krate.span,
 394              ident: info.ident,
 395              crate_id: &info.crate_id,
 396              id_hash: id_hash,
 397              hash: None,
 398              filesearch: self.env.sess.host_filesearch(),
 399              triple: driver::host_triple(),
 400              os: session::sess_os_to_meta_os(os),
 401              root: &None,
 402              rejected_via_hash: vec!(),
 403              rejected_via_triple: vec!(),
 404          };
 405          let library = match load_ctxt.maybe_load_library_crate() {
 406              Some (l) => l,
 407              None if is_cross => {
 408                  // try loading from target crates (only valid if there are
 409                  // no syntax extensions)
 410                  load_ctxt.triple = target_triple;
 411                  load_ctxt.os = session::sess_os_to_meta_os(self.env.sess.targ_cfg.os);
 412                  load_ctxt.filesearch = self.env.sess.target_filesearch();
 413                  let lib = load_ctxt.load_library_crate();
 414                  if decoder::get_macro_registrar_fn(lib.metadata.as_slice()).is_some() {
 415                      let message = format!("crate `{}` contains a macro_registrar fn but \
 416                                    only a version for triple `{}` could be found (need {})",
 417                                    info.ident, target_triple, driver::host_triple());
 418                      self.env.sess.span_err(krate.span, message);
 419                      // need to abort now because the syntax expansion
 420                      // code will shortly attempt to load and execute
 421                      // code from the found library.
 422                      self.env.sess.abort_if_errors();
 423                  }
 424                  should_link = info.should_link;
 425                  lib
 426              }
 427              None => { load_ctxt.report_load_errs(); unreachable!() },
 428          };
 429          let macros = decoder::get_exported_macros(library.metadata.as_slice());
 430          let registrar = decoder::get_macro_registrar_fn(library.metadata.as_slice()).map(|id| {
 431              decoder::get_symbol(library.metadata.as_slice(), id).to_strbuf()
 432          });
 433          let mc = MacroCrate {
 434              lib: library.dylib.clone(),
 435              macros: macros.move_iter().map(|x| x.to_strbuf()).collect(),
 436              registrar_symbol: registrar,
 437          };
 438          if should_link {
 439              // register crate now to avoid double-reading metadata
 440              register_crate(&mut self.env, &None, info.ident.as_slice(),
 441                             &info.crate_id, krate.span, library);
 442          }
 443          mc
 444      }
 445  }


librustc/metadata/creader.rs:367:1-367:1 -struct- definition:
pub struct Loader<'a> {
    env: Env<'a>,
}
references:- 4
373:     pub fn new(sess: &'a Session) -> Loader<'a> {
374:         Loader {
375:             env: Env {
--
383: impl<'a> CrateLoader for Loader<'a> {
384:     fn load_crate(&mut self, krate: &ast::ViewItem) -> MacroCrate {


librustc/metadata/creader.rs:138:1-138:1 -fn- definition:
fn extract_crate_info(e: &Env, i: &ast::ViewItem) -> Option<CrateInfo> {
    match i.node {
        ast::ViewItemExternCrate(ident, ref path_opt, id) => {
references:- 2
384:     fn load_crate(&mut self, krate: &ast::ViewItem) -> MacroCrate {
385:         let info = extract_crate_info(&self.env, krate).unwrap();
386:         let target_triple = self.env.sess.targ_cfg.target_strs.target_triple.as_slice();


librustc/metadata/creader.rs:131:1-131:1 -struct- definition:
struct CrateInfo {
    ident: ~str,
    crate_id: CrateId,
references:- 2
157:             };
158:             Some(CrateInfo {
159:                 ident: ident.get().to_str(),


librustc/metadata/creader.rs:106:1-106:1 -fn- definition:
fn should_link(i: &ast::ViewItem) -> bool {
    i.attrs.iter().all(|attr| {
        attr.name().get() != "phase" ||
references:- 2
116: fn visit_view_item(e: &mut Env, i: &ast::ViewItem) {
117:     if !should_link(i) {
118:         return;
--
161:                 id: id,
162:                 should_link: should_link(i),
163:             })


librustc/metadata/creader.rs:38:1-38:1 -struct- definition:
struct Env<'a> {
    sess: &'a Session,
    next_crate_num: ast::CrateNum,
references:- 12
47:                    krate: &ast::Crate) {
48:     let mut e = Env {
49:         sess: sess,
--
374:         Loader {
375:             env: Env {
376:                 sess: sess,


librustc/metadata/creader.rs:314:1-314:1 -fn- definition:
fn resolve_crate<'a>(e: &mut Env,
                 root: &Option<CratePaths>,
                 ident: &str,
references:- 2
122:         Some(info) => {
123:             let (cnum, _, _) = resolve_crate(e, &None, info.ident,
124:                                              &info.crate_id, None,
--
358:         debug!("resolving dep crate {} hash: `{}`", dep.crate_id, dep.hash);
359:         let (local_cnum, _, _) = resolve_crate(e, root,
360:                                                dep.crate_id.name.as_slice(),


librustc/metadata/creader.rs:266:1-266:1 -fn- definition:
fn register_crate<'a>(e: &mut Env,
                  root: &Option<CratePaths>,
                  ident: &str,
references:- 2
340:             let library = load_ctxt.load_library_crate();
341:             register_crate(e, root, ident, crate_id, span, library)
342:         }
--
439:             // register crate now to avoid double-reading metadata
440:             register_crate(&mut self.env, &None, info.ident.as_slice(),
441:                            &info.crate_id, krate.span, library);