Auto merge of #49019 - phil-opp:target-spec, r=pnkfelix

Introduce a TargetTriple enum to support absolute target paths

This PR replaces target triple strings with a `TargetTriple` enum, which represents either a target triple or a path to a JSON target file. The path variant is used if the `--target` argument has a `.json` extension, else the target triple variant is used.

The motivation of this PR is support for absolute target paths to avoid the need for setting the `RUST_TARGET_PATH` environment variable (see rust-lang/cargo#4905 for more information). For places where some kind of triple is needed (e.g. in the sysroot folder), we use the file name (without extension).

For compatibility, we keep the old behavior of searching for a file named `$(target_triple).json` in `RUST_TARGET_PATH` for non-official target triples.
This commit is contained in:
bors 2018-03-28 12:56:09 +00:00
commit d87c19db6d
12 changed files with 150 additions and 57 deletions

View File

@ -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<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
maybe_sysroot: Option<PathBuf> [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(),
@ -1922,9 +1922,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() {
@ -2132,7 +2144,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,
@ -2283,6 +2295,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);
@ -2342,6 +2355,7 @@ mod dep_tracking {
impl_dep_tracking_hash_via_hash!(Sanitizer);
impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
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);

View File

@ -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<codemap::CodeMap>,
) -> 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

View File

@ -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<Target, String> {
pub fn search(target_triple: &TargetTriple) -> Result<Target, String> {
use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{Path, PathBuf};
use serialize::json;
fn load_file(path: &Path) -> Result<Target, String> {
@ -838,35 +839,40 @@ impl Target {
Target::from_json(obj)
}
if let Ok(t) = load_specific(target) {
return Ok(t)
}
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 = Path::new(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)
};
if path.is_file() {
return load_file(&path);
}
let target_path = env::var_os("RUST_TARGET_PATH")
.unwrap_or(OsString::new());
let path = {
let mut target = target.to_string();
target.push_str(".json");
PathBuf::from(target)
};
// FIXME 16351: add a sane default search path?
let target_path = env::var_os("RUST_TARGET_PATH")
.unwrap_or(OsString::new());
// 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<String> {
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<Self, io::Error> {
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())
}
}

View File

@ -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![],

View File

@ -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<CratePaths>,
pub rejected_via_hash: Vec<CrateMismatch>,
@ -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;
}

View File

@ -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,

View File

@ -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)

View File

@ -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);
@ -1094,7 +1095,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);

View File

@ -859,7 +859,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"
@ -874,7 +874,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"

View File

@ -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;
@ -1086,7 +1087,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");

View File

@ -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;
@ -118,7 +119,7 @@ pub fn run_core(search_paths: SearchPaths,
cfgs: Vec<String>,
externs: config::Externs,
input: Input,
triple: Option<String>,
triple: Option<TargetTriple>,
maybe_sysroot: Option<PathBuf>,
allow_warnings: bool,
crate_name: Option<String>,
@ -133,6 +134,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,
@ -140,7 +142,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,

View File

@ -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");