diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index d24da1ff7c8e5..92da47b9d436c 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -21,7 +21,7 @@ use session::search_paths::SearchPaths; use ich::StableHashingContext; use rustc_back::{LinkerFlavor, PanicStrategy, RelroLevel}; -use rustc_back::target::Target; +use rustc_back::target::{Target, TargetTriple}; use rustc_data_structures::stable_hasher::ToStableHashKey; use lint; use middle::cstore; @@ -47,7 +47,7 @@ use std::hash::Hasher; use std::collections::hash_map::DefaultHasher; use std::collections::HashSet; use std::iter::FromIterator; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; pub struct Config { pub target: Target, @@ -367,7 +367,7 @@ top_level_options!( libs: Vec<(String, Option, Option)> [TRACKED], maybe_sysroot: Option [TRACKED], - target_triple: String [TRACKED], + target_triple: TargetTriple [TRACKED], test: bool [TRACKED], error_format: ErrorOutputType [UNTRACKED], @@ -567,7 +567,7 @@ pub fn basic_options() -> Options { output_types: OutputTypes(BTreeMap::new()), search_paths: SearchPaths::new(), maybe_sysroot: None, - target_triple: host_triple().to_string(), + target_triple: TargetTriple::from_triple(host_triple()), test: false, incremental: None, debugging_opts: basic_debugging_options(), @@ -1903,9 +1903,21 @@ pub fn build_session_options_and_crate_config( let cg = cg; let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m)); - let target = matches - .opt_str("target") - .unwrap_or(host_triple().to_string()); + let target_triple = if let Some(target) = matches.opt_str("target") { + if target.ends_with(".json") { + let path = Path::new(&target); + match TargetTriple::from_path(&path) { + Ok(triple) => triple, + Err(_) => { + early_error(error_format, &format!("target file {:?} does not exist", path)) + } + } + } else { + TargetTriple::TargetTriple(target) + } + } else { + TargetTriple::from_triple(host_triple()) + }; let opt_level = { if matches.opt_present("O") { if cg.opt_level.is_some() { @@ -2113,7 +2125,7 @@ pub fn build_session_options_and_crate_config( output_types: OutputTypes(output_types), search_paths, maybe_sysroot: sysroot_opt, - target_triple: target, + target_triple, test, incremental, debugging_opts, @@ -2264,6 +2276,7 @@ mod dep_tracking { Passes, Sanitizer}; use syntax::feature_gate::UnstableFeatures; use rustc_back::{PanicStrategy, RelroLevel}; + use rustc_back::target::TargetTriple; pub trait DepTrackingHash { fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType); @@ -2323,6 +2336,7 @@ mod dep_tracking { impl_dep_tracking_hash_via_hash!(Sanitizer); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Edition); + impl_dep_tracking_hash_via_hash!(TargetTriple); impl_dep_tracking_hash_for_sortable_vec_of!(String); impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 556255e06ed00..77cf50a8341ed 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -42,7 +42,7 @@ use syntax::feature_gate::AttributeType; use syntax_pos::{MultiSpan, Span}; use rustc_back::{LinkerFlavor, PanicStrategy}; -use rustc_back::target::Target; +use rustc_back::target::{Target, TargetTriple}; use rustc_data_structures::flock; use jobserver::Client; @@ -707,7 +707,7 @@ impl Session { pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch { filesearch::FileSearch::new( self.sysroot(), - &self.opts.target_triple, + self.opts.target_triple.triple(), &self.opts.search_paths, kind, ) @@ -1085,7 +1085,8 @@ pub fn build_session_( span_diagnostic: errors::Handler, codemap: Lrc, ) -> Session { - let host = match Target::search(config::host_triple()) { + let host_triple = TargetTriple::from_triple(config::host_triple()); + let host = match Target::search(&host_triple) { Ok(t) => t, Err(e) => { span_diagnostic diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index f53eeb86a9c56..507243a58a5f9 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -47,6 +47,8 @@ use serialize::json::{Json, ToJson}; use std::collections::BTreeMap; use std::default::Default; +use std::{fmt, io}; +use std::path::{Path, PathBuf}; use syntax::abi::{Abi, lookup as lookup_abi}; use {LinkerFlavor, PanicStrategy, RelroLevel}; @@ -824,11 +826,10 @@ impl Target { /// /// The error string could come from any of the APIs called, including /// filesystem access and JSON decoding. - pub fn search(target: &str) -> Result { + pub fn search(target_triple: &TargetTriple) -> Result { use std::env; use std::ffi::OsString; use std::fs; - use std::path::{Path, PathBuf}; use serialize::json; fn load_file(path: &Path) -> Result { @@ -838,35 +839,40 @@ impl Target { Target::from_json(obj) } - if let Ok(t) = load_specific(target) { - return Ok(t) - } - - let path = Path::new(target); - - if path.is_file() { - return load_file(&path); - } + match target_triple { + &TargetTriple::TargetTriple(ref target_triple) => { + // check if triple is in list of supported targets + if let Ok(t) = load_specific(target_triple) { + return Ok(t) + } - let path = { - let mut target = target.to_string(); - target.push_str(".json"); - PathBuf::from(target) - }; + // search for a file named `target_triple`.json in RUST_TARGET_PATH + let path = { + let mut target = target_triple.to_string(); + target.push_str(".json"); + PathBuf::from(target) + }; - let target_path = env::var_os("RUST_TARGET_PATH") - .unwrap_or(OsString::new()); + let target_path = env::var_os("RUST_TARGET_PATH") + .unwrap_or(OsString::new()); - // FIXME 16351: add a sane default search path? + // FIXME 16351: add a sane default search path? - for dir in env::split_paths(&target_path) { - let p = dir.join(&path); - if p.is_file() { - return load_file(&p); + for dir in env::split_paths(&target_path) { + let p = dir.join(&path); + if p.is_file() { + return load_file(&p); + } + } + Err(format!("Could not find specification for target {:?}", target_triple)) + } + &TargetTriple::TargetPath(ref target_path) => { + if target_path.is_file() { + return load_file(&target_path); + } + Err(format!("Target path {:?} is not a valid file", target_path)) } } - - Err(format!("Could not find specification for target {:?}", target)) } } @@ -1014,3 +1020,61 @@ fn maybe_jemalloc() -> Option { None } } + +/// Either a target triple string or a path to a JSON file. +#[derive(PartialEq, Clone, Debug, Hash, RustcEncodable, RustcDecodable)] +pub enum TargetTriple { + TargetTriple(String), + TargetPath(PathBuf), +} + +impl TargetTriple { + /// Creates a target triple from the passed target triple string. + pub fn from_triple(triple: &str) -> Self { + TargetTriple::TargetTriple(triple.to_string()) + } + + /// Creates a target triple from the passed target path. + pub fn from_path(path: &Path) -> Result { + let canonicalized_path = path.canonicalize()?; + Ok(TargetTriple::TargetPath(canonicalized_path)) + } + + /// Returns a string triple for this target. + /// + /// If this target is a path, the file name (without extension) is returned. + pub fn triple(&self) -> &str { + match self { + &TargetTriple::TargetTriple(ref triple) => triple, + &TargetTriple::TargetPath(ref path) => { + path.file_stem().expect("target path must not be empty").to_str() + .expect("target path must be valid unicode") + } + } + } + + /// Returns an extended string triple for this target. + /// + /// If this target is a path, a hash of the path is appended to the triple returned + /// by `triple()`. + pub fn debug_triple(&self) -> String { + use std::hash::{Hash, Hasher}; + use std::collections::hash_map::DefaultHasher; + + let triple = self.triple(); + if let &TargetTriple::TargetPath(ref path) = self { + let mut hasher = DefaultHasher::new(); + path.hash(&mut hasher); + let hash = hasher.finish(); + format!("{}-{}", triple, hash) + } else { + triple.to_owned() + } + } +} + +impl fmt::Display for TargetTriple { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.debug_triple()) + } +} diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index baaf57c890898..616fbc6cac5a7 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -22,6 +22,7 @@ use rustc::middle::cstore::DepKind; use rustc::session::{Session, CrateDisambiguator}; use rustc::session::config::{Sanitizer, self}; use rustc_back::PanicStrategy; +use rustc_back::target::TargetTriple; use rustc::session::search_paths::PathKind; use rustc::middle; use rustc::middle::cstore::{validate_crate_name, ExternCrate}; @@ -295,7 +296,7 @@ impl<'a> CrateLoader<'a> { let mut proc_macro_locator = locator::Context { target: &self.sess.host, - triple: config::host_triple(), + triple: &TargetTriple::from_triple(config::host_triple()), filesearch: self.sess.host_filesearch(path_kind), rejected_via_hash: vec![], rejected_via_triple: vec![], @@ -339,7 +340,7 @@ impl<'a> CrateLoader<'a> { // don't want to match a host crate against an equivalent target one // already loaded. let root = library.metadata.get_root(); - if locate_ctxt.triple == self.sess.opts.target_triple { + if locate_ctxt.triple == &self.sess.opts.target_triple { let mut result = LoadResult::Loaded(library); self.cstore.iter_crate_data(|cnum, data| { if data.name() == root.name && root.hash == data.hash() { @@ -426,8 +427,9 @@ impl<'a> CrateLoader<'a> { fn read_extension_crate(&mut self, span: Span, orig_name: Symbol, rename: Symbol) -> ExtensionCrate { info!("read extension crate `extern crate {} as {}`", orig_name, rename); - let target_triple = &self.sess.opts.target_triple[..]; - let is_cross = target_triple != config::host_triple(); + let target_triple = &self.sess.opts.target_triple; + let host_triple = TargetTriple::from_triple(config::host_triple()); + let is_cross = target_triple != &host_triple; let mut target_only = false; let mut locate_ctxt = locator::Context { sess: self.sess, @@ -437,7 +439,7 @@ impl<'a> CrateLoader<'a> { hash: None, filesearch: self.sess.host_filesearch(PathKind::Crate), target: &self.sess.host, - triple: config::host_triple(), + triple: &host_triple, root: &None, rejected_via_hash: vec![], rejected_via_triple: vec![], diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index c56674bd6c5a9..41e10b4755d01 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -233,7 +233,7 @@ use rustc::util::nodemap::FxHashMap; use errors::DiagnosticBuilder; use syntax::symbol::Symbol; use syntax_pos::Span; -use rustc_back::target::Target; +use rustc_back::target::{Target, TargetTriple}; use std::cmp; use std::fmt; @@ -258,7 +258,7 @@ pub struct Context<'a> { pub hash: Option<&'a Svh>, // points to either self.sess.target.target or self.sess.host, must match triple pub target: &'a Target, - pub triple: &'a str, + pub triple: &'a TargetTriple, pub filesearch: FileSearch<'a>, pub root: &'a Option, pub rejected_via_hash: Vec, @@ -394,7 +394,7 @@ impl<'a> Context<'a> { add); if (self.ident == "std" || self.ident == "core") - && self.triple != config::host_triple() { + && self.triple != &TargetTriple::from_triple(config::host_triple()) { err.note(&format!("the `{}` target may not be installed", self.triple)); } err.span_label(self.span, "can't find crate"); @@ -698,13 +698,13 @@ impl<'a> Context<'a> { } } - if root.triple != self.triple { + if &root.triple != self.triple { info!("Rejecting via crate triple: expected {} got {}", self.triple, root.triple); self.rejected_via_triple.push(CrateMismatch { path: libpath.to_path_buf(), - got: root.triple, + got: format!("{}", root.triple), }); return None; } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 9832794529701..d04a4001c5023 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -22,6 +22,7 @@ use rustc::mir; use rustc::session::CrateDisambiguator; use rustc::ty::{self, Ty, ReprOptions}; use rustc_back::PanicStrategy; +use rustc_back::target::TargetTriple; use rustc_serialize as serialize; use syntax::{ast, attr}; @@ -186,7 +187,7 @@ pub enum LazyState { #[derive(RustcEncodable, RustcDecodable)] pub struct CrateRoot { pub name: Symbol, - pub triple: String, + pub triple: TargetTriple, pub hash: hir::svh::Svh, pub disambiguator: CrateDisambiguator, pub panic_strategy: PanicStrategy, diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 44c18c371a40f..9adcdf56e86f6 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -950,7 +950,7 @@ impl<'a, 'tcx> FnType<'tcx> { "s390x" => cabi_s390x::compute_abi_info(cx, self), "asmjs" => cabi_asmjs::compute_abi_info(cx, self), "wasm32" => { - if cx.sess().opts.target_triple.contains("emscripten") { + if cx.sess().opts.target_triple.triple().contains("emscripten") { cabi_asmjs::compute_abi_info(cx, self) } else { cabi_wasm32::compute_abi_info(cx, self) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 542cdc5baad32..c4dbbff459368 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -31,6 +31,7 @@ use rustc::util::fs::fix_windows_verbatim_for_gcc; use rustc::hir::def_id::CrateNum; use tempdir::TempDir; use rustc_back::{PanicStrategy, RelroLevel}; +use rustc_back::target::TargetTriple; use context::get_reloc_model; use llvm; @@ -81,7 +82,7 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command) { } }; - let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple, "link.exe"); + let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe"); let linker_path = sess.opts.cg.linker.as_ref().map(|s| &**s) .or(sess.target.target.options.linker.as_ref().map(|s| s.as_ref())) @@ -812,7 +813,7 @@ fn link_natively(sess: &Session, } } - if sess.opts.target_triple == "wasm32-unknown-unknown" { + if sess.opts.target_triple == TargetTriple::from_triple("wasm32-unknown-unknown") { wasm::rewrite_imports(&out_filename, &trans.crate_info.wasm_imports); wasm::add_custom_sections(&out_filename, &trans.crate_info.wasm_custom_sections); @@ -1090,7 +1091,7 @@ fn link_args(cmd: &mut Linker, // addl_lib_search_paths if sess.opts.cg.rpath { let sysroot = sess.sysroot(); - let target_triple = &sess.opts.target_triple; + let target_triple = sess.opts.target_triple.triple(); let mut get_install_prefix_lib_path = || { let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX"); let tlib = filesearch::relative_target_lib_path(sysroot, target_triple); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 3e7422557e9b6..adf5e4a8a7130 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -848,7 +848,7 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext, "rustc.embedded.module\0".as_ptr() as *const _, ); llvm::LLVMSetInitializer(llglobal, llconst); - let section = if cgcx.opts.target_triple.contains("-ios") { + let section = if cgcx.opts.target_triple.triple().contains("-ios") { "__LLVM,__bitcode\0" } else { ".llvmbc\0" @@ -863,7 +863,7 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext, "rustc.embedded.cmdline\0".as_ptr() as *const _, ); llvm::LLVMSetInitializer(llglobal, llconst); - let section = if cgcx.opts.target_triple.contains("-ios") { + let section = if cgcx.opts.target_triple.triple().contains("-ios") { "__LLVM,__cmdline\0" } else { ".llvmcmd\0" diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 56eece9f31e7e..0ce26f2295e4a 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -73,6 +73,7 @@ use type_of::LayoutLlvmExt; use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet}; use CrateInfo; use rustc_data_structures::sync::Lrc; +use rustc_back::target::TargetTriple; use std::any::Any; use std::collections::BTreeMap; @@ -1079,7 +1080,7 @@ impl CrateInfo { let load_wasm_items = tcx.sess.crate_types.borrow() .iter() .any(|c| *c != config::CrateTypeRlib) && - tcx.sess.opts.target_triple == "wasm32-unknown-unknown"; + tcx.sess.opts.target_triple == TargetTriple::from_triple("wasm32-unknown-unknown"); if load_wasm_items { info!("attempting to load all wasm sections"); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 1e0fafc8d9dfd..0bf3a8f368dcd 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -22,6 +22,7 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_resolve as resolve; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::CStore; +use rustc_back::target::TargetTriple; use syntax::ast::NodeId; use syntax::codemap; @@ -116,7 +117,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: config::Externs, input: Input, - triple: Option, + triple: Option, maybe_sysroot: Option, allow_warnings: bool, crate_name: Option, @@ -131,6 +132,7 @@ pub fn run_core(search_paths: SearchPaths, let warning_lint = lint::builtin::WARNINGS.name_lower(); + let host_triple = TargetTriple::from_triple(config::host_triple()); let sessopts = config::Options { maybe_sysroot, search_paths, @@ -138,7 +140,7 @@ pub fn run_core(search_paths: SearchPaths, lint_opts: if !allow_warnings { vec![(warning_lint, lint::Allow)] } else { vec![] }, lint_cap: Some(lint::Allow), externs, - target_triple: triple.unwrap_or(config::host_triple().to_string()), + target_triple: triple.unwrap_or(host_triple), // Ensure that rustdoc works even if rustc is feature-staged unstable_features: UnstableFeatures::Allow, actually_rustdoc: true, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index bec25a98227a2..0339a58d58219 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -64,6 +64,7 @@ use std::sync::mpsc::channel; use externalfiles::ExternalHtml; use rustc::session::search_paths::SearchPaths; use rustc::session::config::{ErrorOutputType, RustcOptGroup, nightly_options, Externs}; +use rustc_back::target::TargetTriple; #[macro_use] pub mod externalfiles; @@ -542,7 +543,13 @@ where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R { paths.add_path(s, ErrorOutputType::default()); } let cfgs = matches.opt_strs("cfg"); - let triple = matches.opt_str("target"); + let triple = matches.opt_str("target").map(|target| { + if target.ends_with(".json") { + TargetTriple::TargetPath(PathBuf::from(target)) + } else { + TargetTriple::TargetTriple(target) + } + }); let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); let crate_name = matches.opt_str("crate-name"); let crate_version = matches.opt_str("crate-version");