4747use serialize:: json:: { Json , ToJson } ;
4848use std:: collections:: BTreeMap ;
4949use std:: default:: Default ;
50+ use std:: { fmt, io} ;
51+ use std:: path:: { Path , PathBuf } ;
5052use syntax:: abi:: { Abi , lookup as lookup_abi} ;
5153
5254use { LinkerFlavor , PanicStrategy , RelroLevel } ;
@@ -824,11 +826,10 @@ impl Target {
824826 ///
825827 /// The error string could come from any of the APIs called, including
826828 /// filesystem access and JSON decoding.
827- pub fn search ( target : & str ) -> Result < Target , String > {
829+ pub fn search ( target_triple : & TargetTriple ) -> Result < Target , String > {
828830 use std:: env;
829831 use std:: ffi:: OsString ;
830832 use std:: fs;
831- use std:: path:: { Path , PathBuf } ;
832833 use serialize:: json;
833834
834835 fn load_file ( path : & Path ) -> Result < Target , String > {
@@ -838,35 +839,40 @@ impl Target {
838839 Target :: from_json ( obj)
839840 }
840841
841- if let Ok ( t) = load_specific ( target) {
842- return Ok ( t)
843- }
844-
845- let path = Path :: new ( target) ;
846-
847- if path. is_file ( ) {
848- return load_file ( & path) ;
849- }
842+ match target_triple {
843+ & TargetTriple :: TargetTriple ( ref target_triple) => {
844+ // check if triple is in list of supported targets
845+ if let Ok ( t) = load_specific ( target_triple) {
846+ return Ok ( t)
847+ }
850848
851- let path = {
852- let mut target = target. to_string ( ) ;
853- target. push_str ( ".json" ) ;
854- PathBuf :: from ( target)
855- } ;
849+ // search for a file named `target_triple`.json in RUST_TARGET_PATH
850+ let path = {
851+ let mut target = target_triple. to_string ( ) ;
852+ target. push_str ( ".json" ) ;
853+ PathBuf :: from ( target)
854+ } ;
856855
857- let target_path = env:: var_os ( "RUST_TARGET_PATH" )
858- . unwrap_or ( OsString :: new ( ) ) ;
856+ let target_path = env:: var_os ( "RUST_TARGET_PATH" )
857+ . unwrap_or ( OsString :: new ( ) ) ;
859858
860- // FIXME 16351: add a sane default search path?
859+ // FIXME 16351: add a sane default search path?
861860
862- for dir in env:: split_paths ( & target_path) {
863- let p = dir. join ( & path) ;
864- if p. is_file ( ) {
865- return load_file ( & p) ;
861+ for dir in env:: split_paths ( & target_path) {
862+ let p = dir. join ( & path) ;
863+ if p. is_file ( ) {
864+ return load_file ( & p) ;
865+ }
866+ }
867+ Err ( format ! ( "Could not find specification for target {:?}" , target_triple) )
868+ }
869+ & TargetTriple :: TargetPath ( ref target_path) => {
870+ if target_path. is_file ( ) {
871+ return load_file ( & target_path) ;
872+ }
873+ Err ( format ! ( "Target path {:?} is not a valid file" , target_path) )
866874 }
867875 }
868-
869- Err ( format ! ( "Could not find specification for target {:?}" , target) )
870876 }
871877}
872878
@@ -1014,3 +1020,61 @@ fn maybe_jemalloc() -> Option<String> {
10141020 None
10151021 }
10161022}
1023+
1024+ /// Either a target triple string or a path to a JSON file.
1025+ #[ derive( PartialEq , Clone , Debug , Hash , RustcEncodable , RustcDecodable ) ]
1026+ pub enum TargetTriple {
1027+ TargetTriple ( String ) ,
1028+ TargetPath ( PathBuf ) ,
1029+ }
1030+
1031+ impl TargetTriple {
1032+ /// Creates a target triple from the passed target triple string.
1033+ pub fn from_triple ( triple : & str ) -> Self {
1034+ TargetTriple :: TargetTriple ( triple. to_string ( ) )
1035+ }
1036+
1037+ /// Creates a target triple from the passed target path.
1038+ pub fn from_path ( path : & Path ) -> Result < Self , io:: Error > {
1039+ let canonicalized_path = path. canonicalize ( ) ?;
1040+ Ok ( TargetTriple :: TargetPath ( canonicalized_path) )
1041+ }
1042+
1043+ /// Returns a string triple for this target.
1044+ ///
1045+ /// If this target is a path, the file name (without extension) is returned.
1046+ pub fn triple ( & self ) -> & str {
1047+ match self {
1048+ & TargetTriple :: TargetTriple ( ref triple) => triple,
1049+ & TargetTriple :: TargetPath ( ref path) => {
1050+ path. file_stem ( ) . expect ( "target path must not be empty" ) . to_str ( )
1051+ . expect ( "target path must be valid unicode" )
1052+ }
1053+ }
1054+ }
1055+
1056+ /// Returns an extended string triple for this target.
1057+ ///
1058+ /// If this target is a path, a hash of the path is appended to the triple returned
1059+ /// by `triple()`.
1060+ pub fn debug_triple ( & self ) -> String {
1061+ use std:: hash:: { Hash , Hasher } ;
1062+ use std:: collections:: hash_map:: DefaultHasher ;
1063+
1064+ let triple = self . triple ( ) ;
1065+ if let & TargetTriple :: TargetPath ( ref path) = self {
1066+ let mut hasher = DefaultHasher :: new ( ) ;
1067+ path. hash ( & mut hasher) ;
1068+ let hash = hasher. finish ( ) ;
1069+ format ! ( "{}-{}" , triple, hash)
1070+ } else {
1071+ triple. to_owned ( )
1072+ }
1073+ }
1074+ }
1075+
1076+ impl fmt:: Display for TargetTriple {
1077+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
1078+ write ! ( f, "{}" , self . debug_triple( ) )
1079+ }
1080+ }
0 commit comments