22//!
33//! See the `target-lexicon` crate for a more principled approach to this.
44
5- use std:: str:: FromStr ;
6-
7- use crate :: { Error , ErrorKind } ;
8-
95mod apple;
10- mod generated;
116mod llvm;
127mod parser;
138
@@ -43,47 +38,11 @@ pub(crate) struct TargetInfo<'a> {
4338 ///
4439 /// This is the same as the value of `cfg!(target_abi)`.
4540 pub abi : & ' a str ,
46- /// The unversioned LLVM/Clang target triple.
47- ///
48- /// NOTE: You should never need to match on this explicitly, use the other
49- /// fields on [`TargetInfo`] instead.
50- pub llvm_target : & ' a str ,
51- }
52-
53- impl FromStr for TargetInfo < ' _ > {
54- type Err = Error ;
55-
56- /// This will fail when using a custom target triple unknown to `rustc`.
57- fn from_str ( target_triple : & str ) -> Result < Self , Error > {
58- if let Ok ( index) =
59- generated:: LIST . binary_search_by_key ( & target_triple, |( target_triple, _) | target_triple)
60- {
61- let ( _, info) = & generated:: LIST [ index] ;
62- Ok ( info. clone ( ) )
63- } else {
64- Err ( Error :: new (
65- ErrorKind :: UnknownTarget ,
66- format ! (
67- "unknown target `{target_triple}`.
68-
69- NOTE: `cc-rs` only supports a fixed set of targets when not in a build script.
70- - If adding a new target, you will need to fork of `cc-rs` until the target
71- has landed on nightly and the auto-generated list has been updated. See also
72- the `rustc` dev guide on adding a new target:
73- https://rustc-dev-guide.rust-lang.org/building/new-target.html
74- - If using a custom target, prefer to upstream it to `rustc` if possible,
75- otherwise open an issue with `cc-rs`:
76- https://github.com/rust-lang/cc-rs/issues/new
77- "
78- ) ,
79- ) )
80- }
81- }
8241}
8342
8443#[ cfg( test) ]
8544mod tests {
86- use std:: str :: FromStr ;
45+ use std:: process :: Command ;
8746
8847 use super :: TargetInfo ;
8948
@@ -104,13 +63,92 @@ mod tests {
10463
10564 for target in targets {
10665 // Check that it parses
107- let _ = TargetInfo :: from_str ( target) . unwrap ( ) ;
66+ let _ = TargetInfo :: from_rustc_target ( target) . unwrap ( ) ;
67+ }
68+ }
69+
70+ fn target_from_rustc_cfgs < ' a > ( target : & ' a str , cfgs : & ' a str ) -> TargetInfo < ' a > {
71+ // Cannot determine full architecture from cfgs.
72+ let ( full_arch, _rest) = target. split_once ( '-' ) . expect ( "target to have arch" ) ;
73+
74+ let mut target = TargetInfo {
75+ full_arch : full_arch. into ( ) ,
76+ arch : "invalid-none-set" . into ( ) ,
77+ vendor : "invalid-none-set" . into ( ) ,
78+ os : "invalid-none-set" . into ( ) ,
79+ env : "invalid-none-set" . into ( ) ,
80+ // Not set in older Rust versions
81+ abi : "" . into ( ) ,
82+ } ;
83+
84+ for cfg in cfgs. lines ( ) {
85+ if let Some ( ( name, value) ) = cfg. split_once ( '=' ) {
86+ // Remove whitespace, if `rustc` decided to insert any
87+ let name = name. trim ( ) ;
88+ let value = value. trim ( ) ;
89+
90+ // Remove quotes around value
91+ let value = value. strip_prefix ( '"' ) . unwrap_or ( value) ;
92+ let value = value. strip_suffix ( '"' ) . unwrap_or ( value) ;
93+
94+ match name {
95+ "target_arch" => target. arch = value,
96+ "target_vendor" => target. vendor = value,
97+ "target_os" => target. os = value,
98+ "target_env" => target. env = value,
99+ "target_abi" => target. abi = value,
100+ _ => { }
101+ }
102+ } else {
103+ // Skip cfgs like `debug_assertions` and `unix`.
104+ }
105+ }
106+
107+ target
108+ }
109+
110+ #[ test]
111+ fn parse_rustc_targets ( ) {
112+ let rustc = std:: env:: var ( "RUSTC" ) . unwrap_or_else ( |_| "rustc" . to_string ( ) ) ;
113+
114+ let target_list = Command :: new ( & rustc)
115+ . arg ( "--print=target-list" )
116+ . output ( )
117+ . unwrap ( )
118+ . stdout ;
119+ let target_list = String :: from_utf8 ( target_list) . unwrap ( ) ;
120+
121+ let mut has_failure = false ;
122+ for target in target_list. lines ( ) {
123+ let cfgs = Command :: new ( & rustc)
124+ . arg ( "--target" )
125+ . arg ( target)
126+ . arg ( "--print=cfg" )
127+ . output ( )
128+ . unwrap ( )
129+ . stdout ;
130+ let cfgs = String :: from_utf8 ( cfgs) . unwrap ( ) ;
131+
132+ let expected = target_from_rustc_cfgs ( target, & cfgs) ;
133+ let actual = TargetInfo :: from_rustc_target ( target) ;
134+
135+ if Some ( & expected) != actual. as_ref ( ) . ok ( ) {
136+ eprintln ! ( "failed comparing {target}:" ) ;
137+ eprintln ! ( " expected: Ok({expected:?})" ) ;
138+ eprintln ! ( " actual: {actual:?}" ) ;
139+ eprintln ! ( ) ;
140+ has_failure = true ;
141+ }
142+ }
143+
144+ if has_failure {
145+ panic ! ( "failed comparing targets" ) ;
108146 }
109147 }
110148
111149 // Various custom target triples not (or no longer) known by `rustc`
112150 #[ test]
113- fn cannot_parse_extra ( ) {
151+ fn parse_extra ( ) {
114152 let targets = [
115153 "aarch64-unknown-none-gnu" ,
116154 "aarch64-uwp-windows-gnu" ,
@@ -120,13 +158,20 @@ mod tests {
120158 "armv7neon-unknown-linux-musleabihf" ,
121159 "thumbv7-unknown-linux-gnueabihf" ,
122160 "thumbv7-unknown-linux-musleabihf" ,
161+ "armv7-apple-ios" ,
162+ "wasm32-wasi" ,
123163 "x86_64-rumprun-netbsd" ,
124164 "x86_64-unknown-linux" ,
165+ "x86_64-alpine-linux-musl" ,
166+ "x86_64-chimera-linux-musl" ,
167+ "x86_64-foxkit-linux-musl" ,
168+ "arm-poky-linux-gnueabi" ,
169+ "x86_64-unknown-moturus" ,
125170 ] ;
126171
127172 for target in targets {
128- // Check that it does not parse
129- let _ = TargetInfo :: from_str ( target) . unwrap_err ( ) ;
173+ // Check that it parses
174+ let _ = TargetInfo :: from_rustc_target ( target) . unwrap ( ) ;
130175 }
131176 }
132177}
0 commit comments