about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-04-23 13:11:37 -0700
committerbors <bors@rust-lang.org>2014-04-23 13:11:37 -0700
commit07aef98a3262b69f0a4b20c9677d63f2f2f50f27 (patch)
tree14eedde61809d48fc9e7d7f467aeb8e1940792c6
parent6beb376b5c27c6b028092f227f865ba564fea17b (diff)
parent4ac89cd27613ffe574a6fc6009793c1900e5cfca (diff)
downloadrust-07aef98a3262b69f0a4b20c9677d63f2f2f50f27.tar.gz
rust-07aef98a3262b69f0a4b20c9677d63f2f2f50f27.zip
auto merge of #13584 : rcxdude/rust/cross-syntax-ext, r=alexcrichton
This allows the use of syntax extensions when cross-compiling (fixing #12102). It does this by encoding the target triple in the crate metadata and checking it when searching for files. Currently the crate triple must match the host triple when there is a macro_registrar_fn, it must match the target triple when linking, and can match either when only macro_rules! macros are used.

due to carelessness, this is pretty much a duplicate of https://github.com/mozilla/rust/pull/13450.
-rw-r--r--mk/tests.mk4
-rw-r--r--src/librustc/back/archive.rs2
-rw-r--r--src/librustc/back/link.rs2
-rw-r--r--src/librustc/back/rpath.rs2
-rw-r--r--src/librustc/driver/driver.rs10
-rw-r--r--src/librustc/driver/session.rs20
-rw-r--r--src/librustc/metadata/common.rs2
-rw-r--r--src/librustc/metadata/creader.rs206
-rw-r--r--src/librustc/metadata/csearch.rs14
-rw-r--r--src/librustc/metadata/decoder.rs14
-rw-r--r--src/librustc/metadata/encoder.rs7
-rw-r--r--src/librustc/metadata/filesearch.rs29
-rw-r--r--src/librustc/metadata/loader.rs124
-rw-r--r--src/test/compile-fail/macro-crate-unexported-macro.rs1
-rw-r--r--src/test/compile-fail/phase-syntax-doesnt-resolve.rs1
-rw-r--r--src/test/compile-fail/syntax-extension-fourcc-bad-len.rs1
-rw-r--r--src/test/compile-fail/syntax-extension-fourcc-invalid-endian.rs1
-rw-r--r--src/test/compile-fail/syntax-extension-fourcc-non-ascii-str.rs1
-rw-r--r--src/test/compile-fail/syntax-extension-fourcc-non-literal.rs1
-rw-r--r--src/test/compile-fail/syntax-extension-fourcc-unsupported-literal.rs1
-rw-r--r--src/test/compile-fail/syntax-extension-hexfloat-bad-lits.rs1
-rw-r--r--src/test/compile-fail/syntax-extension-hexfloat-bad-types.rs1
-rw-r--r--src/test/run-pass-fulldeps/issue-13560.rs2
-rw-r--r--src/test/run-pass-fulldeps/macro-crate-outlive-expansion-phase.rs2
-rw-r--r--src/test/run-pass-fulldeps/macro-crate.rs2
-rw-r--r--src/test/run-pass-fulldeps/phase-syntax-link-does-resolve.rs13
-rw-r--r--src/test/run-pass-fulldeps/syntax-extension-fourcc.rs1
-rw-r--r--src/test/run-pass-fulldeps/syntax-extension-hexfloat.rs1
28 files changed, 257 insertions, 209 deletions
diff --git a/mk/tests.mk b/mk/tests.mk
index b14b5a51527..9fc1c7390cc 100644
--- a/mk/tests.mk
+++ b/mk/tests.mk
@@ -526,8 +526,6 @@ endif
 # triples).  The associated message will be printed as a warning
 # during attempts to run those tests.
 
-CTEST_DISABLE_NONSELFHOST_rpass-full = "run-pass-full suite is unavailable when cross-compiling."
-
 define DEF_CTEST_VARS
 
 # All the per-stage build rules you might want to call from the
@@ -573,7 +571,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) :=						\
         $$(CTEST_TESTARGS)
 
 CTEST_DEPS_rpass_$(1)-T-$(2)-H-$(3) = $$(RPASS_TESTS)
-CTEST_DEPS_rpass-full_$(1)-T-$(2)-H-$(3) = $$(RPASS_FULL_TESTS) $$(CSREQ$(1)_T_$(2)_H_$(3))
+CTEST_DEPS_rpass-full_$(1)-T-$(2)-H-$(3) = $$(RPASS_FULL_TESTS) $$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3))
 CTEST_DEPS_rfail_$(1)-T-$(2)-H-$(3) = $$(RFAIL_TESTS)
 CTEST_DEPS_cfail_$(1)-T-$(2)-H-$(3) = $$(CFAIL_TESTS)
 CTEST_DEPS_bench_$(1)-T-$(2)-H-$(3) = $$(BENCH_TESTS)
diff --git a/src/librustc/back/archive.rs b/src/librustc/back/archive.rs
index 27211c4779f..7ecea29db2e 100644
--- a/src/librustc/back/archive.rs
+++ b/src/librustc/back/archive.rs
@@ -184,7 +184,7 @@ impl<'a> Archive<'a> {
         let unixlibname = format!("lib{}.a", name);
 
         let mut rustpath = filesearch::rust_path();
-        rustpath.push(self.sess.filesearch().get_target_lib_path());
+        rustpath.push(self.sess.target_filesearch().get_lib_path());
         let search = self.sess.opts.addl_lib_search_paths.borrow();
         for path in search.iter().chain(rustpath.iter()) {
             debug!("looking for {} inside {}", name, path.display());
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index 9fd3894d794..b7842936af3 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -1088,7 +1088,7 @@ fn link_args(sess: &Session,
     // The default library location, we need this to find the runtime.
     // The location of crates will be determined as needed.
     // FIXME (#9639): This needs to handle non-utf8 paths
-    let lib_path = sess.filesearch().get_target_lib_path();
+    let lib_path = sess.target_filesearch().get_lib_path();
     let stage: ~str = "-L".to_owned() + lib_path.as_str().unwrap();
 
     let mut args = vec!(stage);
diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs
index d7d86e077de..ce79bea5cee 100644
--- a/src/librustc/back/rpath.rs
+++ b/src/librustc/back/rpath.rs
@@ -40,7 +40,7 @@ pub fn get_rpath_flags(sess: &Session, out_filename: &Path) -> Vec<~str> {
 
     debug!("preparing the RPATH!");
 
-    let sysroot = sess.filesearch().sysroot;
+    let sysroot = sess.sysroot();
     let output = out_filename;
     let libs = sess.cstore.get_used_crates(cstore::RequireDynamic);
     let libs = libs.move_iter().filter_map(|(_, l)| {
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index cf0e7e161c1..95ee250e24c 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -284,9 +284,7 @@ pub fn phase_3_run_analysis_passes(sess: Session,
     let time_passes = sess.time_passes();
 
     time(time_passes, "external crate/lib resolution", (), |_|
-         creader::read_crates(&sess, krate,
-                              session::sess_os_to_meta_os(sess.targ_cfg.os),
-                              token::get_ident_interner()));
+         creader::read_crates(&sess, krate));
 
     let lang_items = time(time_passes, "language item collection", (), |_|
                           middle::lang_items::collect_language_items(krate, &sess));
@@ -794,7 +792,7 @@ pub fn build_target_config(sopts: &session::Options) -> session::Config {
     }
 }
 
-pub fn host_triple() -> ~str {
+pub fn host_triple() -> &'static str {
     // Get the host triple out of the build environment. This ensures that our
     // idea of the host triple is the same as for the set of libraries we've
     // actually built.  We can't just take LLVM's host triple because they
@@ -803,7 +801,7 @@ pub fn host_triple() -> ~str {
     // Instead of grabbing the host triple (for the current host), we grab (at
     // compile time) the target triple that this rustc is built with and
     // calling that (at runtime) the host triple.
-    (env!("CFG_COMPILER_HOST_TRIPLE")).to_owned()
+    env!("CFG_COMPILER_HOST_TRIPLE")
 }
 
 pub fn build_session_options(matches: &getopts::Matches) -> session::Options {
@@ -895,7 +893,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> session::Options {
     }
 
     let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
-    let target = matches.opt_str("target").unwrap_or(host_triple());
+    let target = matches.opt_str("target").unwrap_or(host_triple().to_owned());
     let opt_level = {
         if (debugging_opts & session::NO_OPT) != 0 {
             No
diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs
index e23423bcd0b..950e6bd8ee8 100644
--- a/src/librustc/driver/session.rs
+++ b/src/librustc/driver/session.rs
@@ -319,17 +319,25 @@ impl Session {
     pub fn show_span(&self) -> bool {
         self.debugging_opt(SHOW_SPAN)
     }
-    pub fn filesearch<'a>(&'a self) -> filesearch::FileSearch<'a> {
-        let sysroot = match self.opts.maybe_sysroot {
-            Some(ref sysroot) => sysroot,
+    pub fn sysroot<'a>(&'a self) -> &'a Path {
+        match self.opts.maybe_sysroot {
+            Some (ref sysroot) => sysroot,
             None => self.default_sysroot.as_ref()
                         .expect("missing sysroot and default_sysroot in Session")
-        };
+        }
+    }
+    pub fn target_filesearch<'a>(&'a self) -> filesearch::FileSearch<'a> {
         filesearch::FileSearch::new(
-            sysroot,
+            self.sysroot(),
             self.opts.target_triple,
             &self.opts.addl_lib_search_paths)
     }
+    pub fn host_filesearch<'a>(&'a self) -> filesearch::FileSearch<'a> {
+        filesearch::FileSearch::new(
+            self.sysroot(),
+            host_triple(),
+            &self.opts.addl_lib_search_paths)
+    }
 }
 
 /// Some reasonable defaults
@@ -343,7 +351,7 @@ pub fn basic_options() -> Options {
         output_types: Vec::new(),
         addl_lib_search_paths: RefCell::new(HashSet::new()),
         maybe_sysroot: None,
-        target_triple: host_triple(),
+        target_triple: host_triple().to_owned(),
         cfg: Vec::new(),
         test: false,
         parse_only: false,
diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs
index 0ea6598a99f..8f71ac4ebf7 100644
--- a/src/librustc/metadata/common.rs
+++ b/src/librustc/metadata/common.rs
@@ -201,6 +201,8 @@ pub static tag_macro_registrar_fn: uint = 0x8b;
 pub static tag_exported_macros: uint = 0x8c;
 pub static tag_macro_def: uint = 0x8d;
 
+pub static tag_crate_triple: uint = 0x66;
+
 #[deriving(Clone, Show)]
 pub struct LinkMeta {
     pub crateid: CrateId,
diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index efbfce1b2bb..916d2a6f07c 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -14,13 +14,12 @@
 
 use back::link;
 use back::svh::Svh;
-use driver::{driver, session};
 use driver::session::Session;
+use driver::{driver, session};
 use metadata::cstore;
 use metadata::cstore::CStore;
 use metadata::decoder;
 use metadata::loader;
-use metadata::loader::Os;
 use metadata::loader::CratePaths;
 
 use std::rc::Rc;
@@ -32,29 +31,23 @@ use syntax::attr::AttrMetaMethods;
 use syntax::codemap::{Span};
 use syntax::diagnostic::SpanHandler;
 use syntax::ext::base::{CrateLoader, MacroCrate};
-use syntax::parse::token::{IdentInterner, InternedString};
+use syntax::parse::token::InternedString;
 use syntax::parse::token;
 use syntax::crateid::CrateId;
 use syntax::visit;
 
 struct Env<'a> {
     sess: &'a Session,
-    os: loader::Os,
     next_crate_num: ast::CrateNum,
-    intr: Rc<IdentInterner>
 }
 
 // Traverses an AST, reading all the information about use'd crates and extern
 // libraries necessary for later resolving, typechecking, linking, etc.
 pub fn read_crates(sess: &Session,
-                   krate: &ast::Crate,
-                   os: loader::Os,
-                   intr: Rc<IdentInterner>) {
+                   krate: &ast::Crate) {
     let mut e = Env {
         sess: sess,
-        os: os,
         next_crate_num: sess.cstore.next_crate_num(),
-        intr: intr
     };
     visit_crate(&e, krate);
     visit::walk_crate(&mut e, krate, ());
@@ -84,7 +77,6 @@ fn dump_crates(cstore: &CStore) {
 
 fn warn_if_multiple_versions(diag: &SpanHandler, cstore: &CStore) {
     let mut map = HashMap::new();
-
     cstore.iter_crate_data(|cnum, data| {
         let crateid = data.crate_id();
         let key = (crateid.name.clone(), crateid.path.clone());
@@ -129,7 +121,7 @@ fn visit_view_item(e: &mut Env, i: &ast::ViewItem) {
     match extract_crate_info(e, i) {
         Some(info) => {
             let (cnum, _, _) = resolve_crate(e, &None, info.ident,
-                                             &info.crate_id, None, true,
+                                             &info.crate_id, None,
                                              i.span);
             e.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
         }
@@ -272,13 +264,60 @@ fn existing_match(e: &Env, crate_id: &CrateId,
     return ret;
 }
 
+fn register_crate<'a>(e: &mut Env,
+                  root: &Option<CratePaths>,
+                  ident: &str,
+                  crate_id: &CrateId,
+                  span: Span,
+                  lib: loader::Library)
+                        -> (ast::CrateNum, Rc<cstore::crate_metadata>,
+                            cstore::CrateSource) {
+    // Claim this crate number and cache it
+    let cnum = e.next_crate_num;
+    e.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_owned(),
+            dylib: lib.dylib.clone(),
+            rlib:  lib.rlib.clone(),
+        })
+    } else {
+        None
+    };
+    // Maintain a reference to the top most crate.
+    let root = if root.is_some() { root } else { &crate_paths };
+
+    let cnum_map = resolve_crate_deps(e, root, lib.metadata.as_slice(), span);
+
+    let loader::Library{ dylib, rlib, metadata } = lib;
+
+    let cmeta = Rc::new( cstore::crate_metadata {
+        name: crate_id.name.to_owned(),
+        data: metadata,
+        cnum_map: cnum_map,
+        cnum: cnum,
+        span: span,
+    });
+
+    let source = cstore::CrateSource {
+        dylib: dylib,
+        rlib: rlib,
+        cnum: cnum,
+    };
+
+    e.sess.cstore.set_crate_data(cnum, cmeta.clone());
+    e.sess.cstore.add_used_crate_source(source.clone());
+    (cnum, cmeta, source)
+}
+
 fn resolve_crate<'a>(e: &mut Env,
-                     root: &Option<CratePaths>,
-                     ident: &str,
-                     crate_id: &CrateId,
-                     hash: Option<&Svh>,
-                     should_link: bool,
-                     span: Span)
+                 root: &Option<CratePaths>,
+                 ident: &str,
+                 crate_id: &CrateId,
+                 hash: Option<&Svh>,
+                 span: Span)
                      -> (ast::CrateNum, Rc<cstore::crate_metadata>,
                          cstore::CrateSource) {
     match existing_match(e, crate_id, hash) {
@@ -291,64 +330,15 @@ fn resolve_crate<'a>(e: &mut Env,
                 crate_id: crate_id,
                 id_hash: id_hash,
                 hash: hash.map(|a| &*a),
-                os: e.os,
-                intr: e.intr.clone(),
+                filesearch: e.sess.target_filesearch(),
+                os: session::sess_os_to_meta_os(e.sess.targ_cfg.os),
+                triple: e.sess.targ_cfg.target_strs.target_triple.as_slice(),
+                root: root,
                 rejected_via_hash: vec!(),
+                rejected_via_triple: vec!(),
             };
-            let loader::Library {
-                dylib, rlib, metadata
-            } = load_ctxt.load_library_crate(root);
-
-            // Stash paths for top-most crate locally if necessary.
-            let crate_paths = if root.is_none() {
-                Some(CratePaths {
-                    ident: load_ctxt.ident.to_owned(),
-                    dylib: dylib.clone(),
-                    rlib:  rlib.clone(),
-                })
-            } else {
-                None
-            };
-            // Maintain a reference to the top most crate.
-            let root = if root.is_some() { root } else { &crate_paths };
-
-            // Now resolve the crates referenced by this crate
-            let cnum_map = if should_link {
-                resolve_crate_deps(e, root, metadata.as_slice(), span)
-            } else {
-                HashMap::new()
-            };
-
-            // Claim this crate number and cache it if we're linking to the
-            // crate, otherwise it's a syntax-only crate and we don't need to
-            // reserve a number
-            let cnum = if should_link {
-                let n = e.next_crate_num;
-                e.next_crate_num += 1;
-                n
-            } else {
-                -1
-            };
-
-            let cmeta = Rc::new(cstore::crate_metadata {
-                name: load_ctxt.crate_id.name.to_owned(),
-                data: metadata,
-                cnum_map: cnum_map,
-                cnum: cnum,
-                span: span,
-            });
-
-            let source = cstore::CrateSource {
-                dylib: dylib,
-                rlib: rlib,
-                cnum: cnum,
-            };
-
-            if should_link {
-                e.sess.cstore.set_crate_data(cnum, cmeta.clone());
-                e.sess.cstore.add_used_crate_source(source.clone());
-            }
-            (cnum, cmeta, source)
+            let library = load_ctxt.load_library_crate();
+            register_crate(e, root, ident, crate_id, span, library)
         }
         Some(cnum) => (cnum,
                        e.sess.cstore.get_crate_data(cnum),
@@ -370,7 +360,6 @@ fn resolve_crate_deps(e: &mut Env,
                                                dep.crate_id.name.as_slice(),
                                                &dep.crate_id,
                                                Some(&dep.hash),
-                                               true,
                                                span);
         (dep.cnum, local_cnum)
     }).collect()
@@ -382,14 +371,10 @@ pub struct Loader<'a> {
 
 impl<'a> Loader<'a> {
     pub fn new(sess: &'a Session) -> Loader<'a> {
-        let os = driver::get_os(driver::host_triple()).unwrap();
-        let os = session::sess_os_to_meta_os(os);
         Loader {
             env: Env {
                 sess: sess,
-                os: os,
                 next_crate_num: sess.cstore.next_crate_num(),
-                intr: token::get_ident_interner(),
             }
         }
     }
@@ -398,18 +383,63 @@ impl<'a> Loader<'a> {
 impl<'a> CrateLoader for Loader<'a> {
     fn load_crate(&mut self, krate: &ast::ViewItem) -> MacroCrate {
         let info = extract_crate_info(&self.env, krate).unwrap();
-        let (_, data, library) = resolve_crate(&mut self.env, &None,
-                                               info.ident, &info.crate_id,
-                                               None, info.should_link,
-                                               krate.span);
-        let macros = decoder::get_exported_macros(&*data);
-        let registrar = decoder::get_macro_registrar_fn(&*data).map(|id| {
-            decoder::get_symbol(data.data.as_slice(), id)
+        let target_triple = self.env.sess.targ_cfg.target_strs.target_triple.as_slice();
+        let is_cross = target_triple != driver::host_triple();
+        let mut should_link = info.should_link && !is_cross;
+        let id_hash = link::crate_id_hash(&info.crate_id);
+        let os = driver::get_os(driver::host_triple()).unwrap();
+        let mut load_ctxt = loader::Context {
+            sess: self.env.sess,
+            span: krate.span,
+            ident: info.ident,
+            crate_id: &info.crate_id,
+            id_hash: id_hash,
+            hash: None,
+            filesearch: self.env.sess.host_filesearch(),
+            triple: driver::host_triple(),
+            os: session::sess_os_to_meta_os(os),
+            root: &None,
+            rejected_via_hash: vec!(),
+            rejected_via_triple: vec!(),
+        };
+        let library = match load_ctxt.maybe_load_library_crate() {
+            Some (l) => l,
+            None if is_cross => {
+                // try loading from target crates (only valid if there are
+                // no syntax extensions)
+                load_ctxt.triple = target_triple;
+                load_ctxt.os = session::sess_os_to_meta_os(self.env.sess.targ_cfg.os);
+                load_ctxt.filesearch = self.env.sess.target_filesearch();
+                let lib = load_ctxt.load_library_crate();
+                if decoder::get_macro_registrar_fn(lib.metadata.as_slice()).is_some() {
+                    let message = format!("crate `{}` contains a macro_registrar fn but \
+                                  only a version for triple `{}` could be found (need {})",
+                                  info.ident, target_triple, driver::host_triple());
+                    self.env.sess.span_err(krate.span, message);
+                    // need to abort now because the syntax expansion
+                    // code will shortly attempt to load and execute
+                    // code from the found library.
+                    self.env.sess.abort_if_errors();
+                }
+                should_link = info.should_link;
+                lib
+            }
+            None => { load_ctxt.report_load_errs(); unreachable!() },
+        };
+        let macros = decoder::get_exported_macros(library.metadata.as_slice());
+        let registrar = decoder::get_macro_registrar_fn(library.metadata.as_slice()).map(|id| {
+            decoder::get_symbol(library.metadata.as_slice(), id)
         });
-        MacroCrate {
-            lib: library.dylib,
+        let mc = MacroCrate {
+            lib: library.dylib.clone(),
             macros: macros.move_iter().collect(),
             registrar_symbol: registrar,
+        };
+        if should_link {
+            // register crate now to avoid double-reading metadata
+            register_crate(&mut self.env, &None, info.ident.as_slice(),
+                           &info.crate_id, krate.span, library);
         }
+        mc
     }
 }
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index 4ebf4a52e41..77b4871ea8b 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -277,20 +277,6 @@ pub fn get_trait_of_method(cstore: &cstore::CStore,
     decoder::get_trait_of_method(&*cdata, def_id.node, tcx)
 }
 
-pub fn get_macro_registrar_fn(cstore: &cstore::CStore,
-                              crate_num: ast::CrateNum)
-                              -> Option<ast::NodeId> {
-    let cdata = cstore.get_crate_data(crate_num);
-    decoder::get_macro_registrar_fn(&*cdata)
-}
-
-pub fn get_exported_macros(cstore: &cstore::CStore,
-                           crate_num: ast::CrateNum)
-                           -> Vec<~str> {
-    let cdata = cstore.get_crate_data(crate_num);
-    decoder::get_exported_macros(&*cdata)
-}
-
 pub fn get_tuple_struct_definition_if_ctor(cstore: &cstore::CStore,
                                            def_id: ast::DefId)
     -> Option<ast::DefId>
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index b76b6d0c380..6d5744340cc 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -1147,6 +1147,12 @@ pub fn maybe_get_crate_id(data: &[u8]) -> Option<CrateId> {
     })
 }
 
+pub fn get_crate_triple(data: &[u8]) -> ~str {
+    let cratedoc = reader::Doc(data);
+    let triple_doc = reader::maybe_get_doc(cratedoc, tag_crate_triple);
+    triple_doc.expect("No triple in crate").as_str()
+}
+
 pub fn get_crate_id(data: &[u8]) -> CrateId {
     let cratedoc = reader::Doc(data);
     let hashdoc = reader::get_doc(cratedoc, tag_crate_crateid);
@@ -1252,13 +1258,13 @@ pub fn get_native_libraries(cdata: Cmd) -> Vec<(cstore::NativeLibaryKind, ~str)>
     return result;
 }
 
-pub fn get_macro_registrar_fn(cdata: Cmd) -> Option<ast::NodeId> {
-    reader::maybe_get_doc(reader::Doc(cdata.data()), tag_macro_registrar_fn)
+pub fn get_macro_registrar_fn(data: &[u8]) -> Option<ast::NodeId> {
+    reader::maybe_get_doc(reader::Doc(data), tag_macro_registrar_fn)
         .map(|doc| FromPrimitive::from_u32(reader::doc_as_u32(doc)).unwrap())
 }
 
-pub fn get_exported_macros(cdata: Cmd) -> Vec<~str> {
-    let macros = reader::get_doc(reader::Doc(cdata.data()),
+pub fn get_exported_macros(data: &[u8]) -> Vec<~str> {
+    let macros = reader::get_doc(reader::Doc(data),
                                  tag_exported_macros);
     let mut result = Vec::new();
     reader::tagged_docs(macros, tag_macro_def, |macro_doc| {
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 884fa70dc28..214fa3ee04b 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -1690,6 +1690,12 @@ fn encode_crate_id(ebml_w: &mut Encoder, crate_id: &CrateId) {
     ebml_w.end_tag();
 }
 
+fn encode_crate_triple(ebml_w: &mut Encoder, triple: &str) {
+    ebml_w.start_tag(tag_crate_triple);
+    ebml_w.writer.write(triple.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,
@@ -1759,6 +1765,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_crate_triple(&mut ebml_w, tcx.sess.targ_cfg.target_strs.target_triple);
     encode_hash(&mut ebml_w, &ecx.link_meta.crate_hash);
 
     let mut i = ebml_w.writer.tell().unwrap();
diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs
index 5e0b249ce3f..a72e28eb805 100644
--- a/src/librustc/metadata/filesearch.rs
+++ b/src/librustc/metadata/filesearch.rs
@@ -30,7 +30,7 @@ pub type pick<'a> = |path: &Path|: 'a -> FileMatch;
 pub struct FileSearch<'a> {
     pub sysroot: &'a Path,
     pub addl_lib_search_paths: &'a RefCell<HashSet<Path>>,
-    pub target_triple: &'a str
+    pub triple: &'a str,
 }
 
 impl<'a> FileSearch<'a> {
@@ -48,22 +48,23 @@ impl<'a> FileSearch<'a> {
             visited_dirs.insert(path.as_vec().to_owned());
         }
 
-        debug!("filesearch: searching target lib path");
+        debug!("filesearch: searching lib path");
         let tlib_path = make_target_lib_path(self.sysroot,
-                                    self.target_triple);
+                                    self.triple);
         if !visited_dirs.contains_equiv(&tlib_path.as_vec()) {
             match f(&tlib_path) {
                 FileMatches => found = true,
                 FileDoesntMatch => ()
             }
         }
+
         visited_dirs.insert(tlib_path.as_vec().to_owned());
         // Try RUST_PATH
         if !found {
             let rustpath = rust_path();
             for path in rustpath.iter() {
-                let tlib_path = make_rustpkg_target_lib_path(
-                    self.sysroot, path, self.target_triple);
+                let tlib_path = make_rustpkg_lib_path(
+                    self.sysroot, path, self.triple);
                 debug!("is {} in visited_dirs? {:?}", tlib_path.display(),
                         visited_dirs.contains_equiv(&tlib_path.as_vec().to_owned()));
 
@@ -82,8 +83,8 @@ impl<'a> FileSearch<'a> {
         }
     }
 
-    pub fn get_target_lib_path(&self) -> Path {
-        make_target_lib_path(self.sysroot, self.target_triple)
+    pub fn get_lib_path(&self) -> Path {
+        make_target_lib_path(self.sysroot, self.triple)
     }
 
     pub fn search(&self, pick: pick) {
@@ -122,13 +123,13 @@ impl<'a> FileSearch<'a> {
     }
 
     pub fn new(sysroot: &'a Path,
-               target_triple: &'a str,
+               triple: &'a str,
                addl_lib_search_paths: &'a RefCell<HashSet<Path>>) -> FileSearch<'a> {
-        debug!("using sysroot = {}", sysroot.display());
+        debug!("using sysroot = {}, triple = {}", sysroot.display(), triple);
         FileSearch {
             sysroot: sysroot,
             addl_lib_search_paths: addl_lib_search_paths,
-            target_triple: target_triple
+            triple: triple,
         }
     }
 }
@@ -147,11 +148,11 @@ fn make_target_lib_path(sysroot: &Path,
     sysroot.join(&relative_target_lib_path(sysroot, target_triple))
 }
 
-fn make_rustpkg_target_lib_path(sysroot: &Path,
-                                dir: &Path,
-                                target_triple: &str) -> Path {
+fn make_rustpkg_lib_path(sysroot: &Path,
+                         dir: &Path,
+                         triple: &str) -> Path {
     let mut p = dir.join(find_libdir(sysroot));
-    p.push(target_triple);
+    p.push(triple);
     p
 }
 
diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs
index bd95ba95c70..4e6f4e2c965 100644
--- a/src/librustc/metadata/loader.rs
+++ b/src/librustc/metadata/loader.rs
@@ -17,10 +17,9 @@ use lib::llvm::{False, llvm, ObjectFile, mk_section_iter};
 use metadata::cstore::{MetadataBlob, MetadataVec, MetadataArchive};
 use metadata::decoder;
 use metadata::encoder;
-use metadata::filesearch::{FileMatches, FileDoesntMatch};
+use metadata::filesearch::{FileSearch, FileMatches, FileDoesntMatch};
 use syntax::codemap::Span;
 use syntax::diagnostic::SpanHandler;
-use syntax::parse::token::IdentInterner;
 use syntax::crateid::CrateId;
 use syntax::attr::AttrMetaMethods;
 
@@ -30,7 +29,6 @@ use std::cmp;
 use std::io;
 use std::os::consts::{macos, freebsd, linux, android, win32};
 use std::ptr;
-use std::rc::Rc;
 use std::slice;
 use std::str;
 
@@ -46,8 +44,9 @@ pub enum Os {
     OsFreebsd
 }
 
-pub struct HashMismatch {
+pub struct CrateMismatch {
     path: Path,
+    got: ~str,
 }
 
 pub struct Context<'a> {
@@ -57,9 +56,12 @@ pub struct Context<'a> {
     pub crate_id: &'a CrateId,
     pub id_hash: &'a str,
     pub hash: Option<&'a Svh>,
+    pub triple: &'a str,
     pub os: Os,
-    pub intr: Rc<IdentInterner>,
-    pub rejected_via_hash: Vec<HashMismatch>
+    pub filesearch: FileSearch<'a>,
+    pub root: &'a Option<CratePaths>,
+    pub rejected_via_hash: Vec<CrateMismatch>,
+    pub rejected_via_triple: Vec<CrateMismatch>,
 }
 
 pub struct Library {
@@ -104,52 +106,69 @@ fn realpath(p: &Path) -> Path {
 }
 
 impl<'a> Context<'a> {
-    pub fn load_library_crate(&mut self, root: &Option<CratePaths>) -> Library {
+    pub fn maybe_load_library_crate(&mut self) -> Option<Library> {
+        self.find_library_crate()
+    }
+
+    pub fn load_library_crate(&mut self) -> Library {
         match self.find_library_crate() {
             Some(t) => t,
             None => {
-                self.sess.abort_if_errors();
-                let message = if self.rejected_via_hash.len() > 0 {
-                    format!("found possibly newer version of crate `{}`",
-                            self.ident)
-                } else {
-                    format!("can't find crate for `{}`", self.ident)
-                };
-                let message = match root {
-                    &None => message,
-                    &Some(ref r) => format!("{} which `{}` depends on",
-                                            message, r.ident)
-                };
-                self.sess.span_err(self.span, message);
-
-                if self.rejected_via_hash.len() > 0 {
-                    self.sess.span_note(self.span, "perhaps this crate needs \
-                                                    to be recompiled?");
-                    let mismatches = self.rejected_via_hash.iter();
-                    for (i, &HashMismatch{ ref path }) in mismatches.enumerate() {
+                self.report_load_errs();
+                unreachable!()
+            }
+        }
+    }
+
+    pub fn report_load_errs(&mut self) {
+        let message = if self.rejected_via_hash.len() > 0 {
+            format!("found possibly newer version of crate `{}`",
+                    self.ident)
+        } else if self.rejected_via_triple.len() > 0 {
+            format!("found incorrect triple for crate `{}`", self.ident)
+        } else {
+            format!("can't find crate for `{}`", self.ident)
+        };
+        let message = match self.root {
+            &None => message,
+            &Some(ref r) => format!("{} which `{}` depends on",
+                                    message, r.ident)
+        };
+        self.sess.span_err(self.span, message);
+
+        let mismatches = self.rejected_via_triple.iter();
+        if self.rejected_via_triple.len() > 0 {
+            self.sess.span_note(self.span, format!("expected triple of {}", self.triple));
+            for (i, &CrateMismatch{ ref path, ref got }) in mismatches.enumerate() {
+                self.sess.fileline_note(self.span,
+                    format!("crate `{}` path \\#{}, triple {}: {}",
+                            self.ident, i+1, got, path.display()));
+            }
+        }
+        if self.rejected_via_hash.len() > 0 {
+            self.sess.span_note(self.span, "perhaps this crate needs \
+                                            to be recompiled?");
+            let mismatches = self.rejected_via_hash.iter();
+            for (i, &CrateMismatch{ ref path, .. }) in mismatches.enumerate() {
+                self.sess.fileline_note(self.span,
+                    format!("crate `{}` path \\#{}: {}",
+                            self.ident, i+1, path.display()));
+            }
+            match self.root {
+                &None => {}
+                &Some(ref r) => {
+                    for (i, path) in r.paths().iter().enumerate() {
                         self.sess.fileline_note(self.span,
                             format!("crate `{}` path \\#{}: {}",
-                                    self.ident, i+1, path.display()));
-                    }
-                    match root {
-                        &None => {}
-                        &Some(ref r) => {
-                            for (i, path) in r.paths().iter().enumerate() {
-                                self.sess.fileline_note(self.span,
-                                    format!("crate `{}` path \\#{}: {}",
-                                            r.ident, i+1, path.display()));
-                            }
-                        }
+                                    r.ident, i+1, path.display()));
                     }
                 }
-                self.sess.abort_if_errors();
-                unreachable!()
             }
         }
+        self.sess.abort_if_errors();
     }
 
     fn find_library_crate(&mut self) -> Option<Library> {
-        let filesearch = self.sess.filesearch();
         let (dyprefix, dysuffix) = self.dylibname();
 
         // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
@@ -171,11 +190,12 @@ impl<'a> Context<'a> {
         // of the crate id (path/name/id).
         //
         // The goal of this step is to look at as little metadata as possible.
-        filesearch.search(|path| {
+        self.filesearch.search(|path| {
             let file = match path.filename_str() {
                 None => return FileDoesntMatch,
                 Some(file) => file,
             };
+            info!("file: {}", file);
             if file.starts_with(rlib_prefix) && file.ends_with(".rlib") {
                 info!("rlib candidate: {}", path.display());
                 match self.try_match(file, rlib_prefix, ".rlib") {
@@ -376,16 +396,30 @@ impl<'a> Context<'a> {
     fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> bool {
         match decoder::maybe_get_crate_id(crate_data) {
             Some(ref id) if self.crate_id.matches(id) => {}
-            _ => return false
+            _ => { info!("Rejecting via crate_id"); return false }
         }
         let hash = match decoder::maybe_get_crate_hash(crate_data) {
-            Some(hash) => hash, None => return false
+            Some(hash) => hash, None => {
+                info!("Rejecting via lack of crate hash");
+                return false;
+            }
         };
+
+        let triple = decoder::get_crate_triple(crate_data);
+        if triple.as_slice() != self.triple {
+            info!("Rejecting via crate triple: expected {} got {}", self.triple, triple);
+            self.rejected_via_triple.push(CrateMismatch{ path: libpath.clone(),
+                                                         got: triple.to_owned() });
+            return false;
+        }
+
         match self.hash {
             None => true,
             Some(myhash) => {
                 if *myhash != hash {
-                    self.rejected_via_hash.push(HashMismatch{ path: libpath.clone() });
+                    info!("Rejecting via hash: expected {} got {}", *myhash, hash);
+                    self.rejected_via_hash.push(CrateMismatch{ path: libpath.clone(),
+                                                               got: myhash.as_str().to_owned() });
                     false
                 } else {
                     true
@@ -394,6 +428,7 @@ impl<'a> Context<'a> {
         }
     }
 
+
     // Returns the corresponding (prefix, suffix) that files need to have for
     // dynamic libraries
     fn dylibname(&self) -> (&'static str, &'static str) {
@@ -405,6 +440,7 @@ impl<'a> Context<'a> {
             OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
         }
     }
+
 }
 
 pub fn note_crateid_attr(diag: &SpanHandler, crateid: &CrateId) {
diff --git a/src/test/compile-fail/macro-crate-unexported-macro.rs b/src/test/compile-fail/macro-crate-unexported-macro.rs
index 6f4c450940e..f8eb9868a5b 100644
--- a/src/test/compile-fail/macro-crate-unexported-macro.rs
+++ b/src/test/compile-fail/macro-crate-unexported-macro.rs
@@ -11,7 +11,6 @@
 // aux-build:macro_crate_test.rs
 // ignore-stage1
 // ignore-android
-// ignore-cross-compile #12102
 
 #![feature(phase)]
 
diff --git a/src/test/compile-fail/phase-syntax-doesnt-resolve.rs b/src/test/compile-fail/phase-syntax-doesnt-resolve.rs
index 9bfc7fc34bb..2053f81683d 100644
--- a/src/test/compile-fail/phase-syntax-doesnt-resolve.rs
+++ b/src/test/compile-fail/phase-syntax-doesnt-resolve.rs
@@ -11,7 +11,6 @@
 // aux-build:macro_crate_test.rs
 // ignore-stage1
 // ignore-android
-// ignore-cross-compile #12102
 
 #![feature(phase)]
 
diff --git a/src/test/compile-fail/syntax-extension-fourcc-bad-len.rs b/src/test/compile-fail/syntax-extension-fourcc-bad-len.rs
index 865ab7e6e84..fbcdf55f1ac 100644
--- a/src/test/compile-fail/syntax-extension-fourcc-bad-len.rs
+++ b/src/test/compile-fail/syntax-extension-fourcc-bad-len.rs
@@ -10,7 +10,6 @@
 
 // ignore-stage1
 // ignore-pretty
-// ignore-cross-compile #12102
 
 #![feature(phase)]
 
diff --git a/src/test/compile-fail/syntax-extension-fourcc-invalid-endian.rs b/src/test/compile-fail/syntax-extension-fourcc-invalid-endian.rs
index c127035bf1e..569b54b93fb 100644
--- a/src/test/compile-fail/syntax-extension-fourcc-invalid-endian.rs
+++ b/src/test/compile-fail/syntax-extension-fourcc-invalid-endian.rs
@@ -10,7 +10,6 @@
 
 // ignore-stage1
 // ignore-pretty
-// ignore-cross-compile #12102
 
 #![feature(phase)]
 
diff --git a/src/test/compile-fail/syntax-extension-fourcc-non-ascii-str.rs b/src/test/compile-fail/syntax-extension-fourcc-non-ascii-str.rs
index 28b146635f1..c0e2304354c 100644
--- a/src/test/compile-fail/syntax-extension-fourcc-non-ascii-str.rs
+++ b/src/test/compile-fail/syntax-extension-fourcc-non-ascii-str.rs
@@ -10,7 +10,6 @@
 
 // ignore-stage1
 // ignore-pretty
-// ignore-cross-compile #12102
 
 #![feature(phase)]
 
diff --git a/src/test/compile-fail/syntax-extension-fourcc-non-literal.rs b/src/test/compile-fail/syntax-extension-fourcc-non-literal.rs
index 1f1a7ab80f9..536594f3063 100644
--- a/src/test/compile-fail/syntax-extension-fourcc-non-literal.rs
+++ b/src/test/compile-fail/syntax-extension-fourcc-non-literal.rs
@@ -10,7 +10,6 @@
 
 // ignore-stage1
 // ignore-pretty
-// ignore-cross-compile #12102
 
 #![feature(phase)]
 
diff --git a/src/test/compile-fail/syntax-extension-fourcc-unsupported-literal.rs b/src/test/compile-fail/syntax-extension-fourcc-unsupported-literal.rs
index a745c227fb1..8a0b0856d24 100644
--- a/src/test/compile-fail/syntax-extension-fourcc-unsupported-literal.rs
+++ b/src/test/compile-fail/syntax-extension-fourcc-unsupported-literal.rs
@@ -10,7 +10,6 @@
 
 // ignore-stage1
 // ignore-pretty
-// ignore-cross-compile #12102
 
 #![feature(phase)]
 
diff --git a/src/test/compile-fail/syntax-extension-hexfloat-bad-lits.rs b/src/test/compile-fail/syntax-extension-hexfloat-bad-lits.rs
index 04b34c85b78..1cd4f654d2e 100644
--- a/src/test/compile-fail/syntax-extension-hexfloat-bad-lits.rs
+++ b/src/test/compile-fail/syntax-extension-hexfloat-bad-lits.rs
@@ -10,7 +10,6 @@
 
 // ignore-stage1
 // ignore-pretty
-// ignore-cross-compile #12102
 
 #![feature(phase)]
 
diff --git a/src/test/compile-fail/syntax-extension-hexfloat-bad-types.rs b/src/test/compile-fail/syntax-extension-hexfloat-bad-types.rs
index 6b2f8067ccc..4a6475cea96 100644
--- a/src/test/compile-fail/syntax-extension-hexfloat-bad-types.rs
+++ b/src/test/compile-fail/syntax-extension-hexfloat-bad-types.rs
@@ -10,7 +10,6 @@
 
 // ignore-stage1
 // ignore-pretty
-// ignore-cross-compile #12102
 
 #![feature(phase)]
 
diff --git a/src/test/run-pass-fulldeps/issue-13560.rs b/src/test/run-pass-fulldeps/issue-13560.rs
index 24010c7c8b1..d72c82852dd 100644
--- a/src/test/run-pass-fulldeps/issue-13560.rs
+++ b/src/test/run-pass-fulldeps/issue-13560.rs
@@ -12,8 +12,6 @@
 // aux-build:issue-13560-2.rs
 // aux-build:issue-13560-3.rs
 // ignore-stage1
-// ignore-android
-// ignore-cross-compile #12102
 
 // Regression test for issue #13560, the test itself is all in the dependent
 // libraries. The fail which previously failed to compile is the one numbered 3.
diff --git a/src/test/run-pass-fulldeps/macro-crate-outlive-expansion-phase.rs b/src/test/run-pass-fulldeps/macro-crate-outlive-expansion-phase.rs
index f61cddace82..58663bb44c7 100644
--- a/src/test/run-pass-fulldeps/macro-crate-outlive-expansion-phase.rs
+++ b/src/test/run-pass-fulldeps/macro-crate-outlive-expansion-phase.rs
@@ -10,8 +10,6 @@
 
 // aux-build:macro_crate_outlive_expansion_phase.rs
 // ignore-stage1
-// ignore-android
-// ignore-cross-compile #12102
 
 #![feature(phase)]
 
diff --git a/src/test/run-pass-fulldeps/macro-crate.rs b/src/test/run-pass-fulldeps/macro-crate.rs
index 24d416a416c..0c086ae99f7 100644
--- a/src/test/run-pass-fulldeps/macro-crate.rs
+++ b/src/test/run-pass-fulldeps/macro-crate.rs
@@ -10,8 +10,6 @@
 
 // aux-build:macro_crate_test.rs
 // ignore-stage1
-// ignore-android
-// ignore-cross-compile #12102
 
 #![feature(phase)]
 
diff --git a/src/test/run-pass-fulldeps/phase-syntax-link-does-resolve.rs b/src/test/run-pass-fulldeps/phase-syntax-link-does-resolve.rs
index 1700ceaec4f..b8d3ab23831 100644
--- a/src/test/run-pass-fulldeps/phase-syntax-link-does-resolve.rs
+++ b/src/test/run-pass-fulldeps/phase-syntax-link-does-resolve.rs
@@ -10,17 +10,10 @@
 
 // aux-build:macro_crate_test.rs
 // ignore-stage1
-// ignore-android
-// force-host
-
-// You'll note that there's lots of directives above. This is a very particular
-// test in which we're both linking to a macro crate and loading macros from it.
-// This implies that both versions are the host architecture, meaning this test
-// must also be compiled with the host arch.
+// ignore-cross-compile
 //
-// because this doesn't work with that test runner, ignore-android because it
-// can't run host binaries, and force-host to make this test build as the host
-// arch.
+// macro_crate_test will not compile on a cross-compiled target because
+// libsyntax is not compiled for it.
 
 #![feature(phase)]
 
diff --git a/src/test/run-pass-fulldeps/syntax-extension-fourcc.rs b/src/test/run-pass-fulldeps/syntax-extension-fourcc.rs
index 53ea4fbe0c3..0681ec63b9e 100644
--- a/src/test/run-pass-fulldeps/syntax-extension-fourcc.rs
+++ b/src/test/run-pass-fulldeps/syntax-extension-fourcc.rs
@@ -10,7 +10,6 @@
 
 // ignore-stage1
 // ignore-pretty
-// ignore-cross-compile
 
 #![feature(phase)]
 
diff --git a/src/test/run-pass-fulldeps/syntax-extension-hexfloat.rs b/src/test/run-pass-fulldeps/syntax-extension-hexfloat.rs
index 5eb6a30c015..3601b610115 100644
--- a/src/test/run-pass-fulldeps/syntax-extension-hexfloat.rs
+++ b/src/test/run-pass-fulldeps/syntax-extension-hexfloat.rs
@@ -10,7 +10,6 @@
 
 // ignore-stage1
 // ignore-pretty
-// ignore-cross-compile #12102
 
 #![feature(phase)]
 #[phase(syntax)]