@@ -42,35 +42,66 @@ pub(crate) struct Target {
42
42
43
43
impl Target {
44
44
pub fn from_cargo_environment_variables ( ) -> Result < Self , Error > {
45
- let getenv = |name| {
46
- // No need to emit `rerun-if-env-changed` for these variables,
47
- // as they are controlled by Cargo itself.
48
- # [ allow ( clippy :: disallowed_methods ) ]
49
- env :: var ( name ) . map_err ( |err| {
50
- Error :: new (
51
- ErrorKind :: EnvVarNotFound ,
52
- format ! ( "failed reading {name}: {err}" ) ,
53
- )
54
- } )
55
- } ;
56
-
57
- let target = getenv ( "TARGET" ) ? ;
58
- let ( full_arch, _rest) = target . split_once ( '-' ) . ok_or ( Error :: new (
45
+ // `TARGET` must be present.
46
+ //
47
+ // No need to emit `rerun-if-env-changed` for this,
48
+ // as it is controlled by Cargo itself.
49
+ # [ allow ( clippy :: disallowed_methods ) ]
50
+ let target_triple = env :: var ( "TARGET" ) . map_err ( |err| {
51
+ Error :: new (
52
+ ErrorKind :: EnvVarNotFound ,
53
+ format ! ( "failed reading TARGET: {err}" ) ,
54
+ )
55
+ } ) ? ;
56
+
57
+ // Parse the full architecture name from the target triple.
58
+ let ( full_arch, _rest) = target_triple . split_once ( '-' ) . ok_or ( Error :: new (
59
59
ErrorKind :: InvalidTarget ,
60
- format ! ( "target `{target }` had an unknown architecture" ) ,
60
+ format ! ( "target `{target_triple }` had an unknown architecture" ) ,
61
61
) ) ?;
62
62
63
- let arch = getenv ( "CARGO_CFG_TARGET_ARCH" ) ?;
64
- let vendor = getenv ( "CARGO_CFG_TARGET_VENDOR" ) ?;
65
- let os = getenv ( "CARGO_CFG_TARGET_OS" ) ?;
66
- let env = getenv ( "CARGO_CFG_TARGET_ENV" ) ?;
67
- // `target_abi` was stabilized in Rust 1.78, so may not always be available.
68
- let abi = if let Ok ( abi) = getenv ( "CARGO_CFG_TARGET_ABI" ) {
69
- abi. into ( )
70
- } else {
71
- Self :: from_str ( & target) ?. abi
63
+ let cargo_env = |name, fallback| {
64
+ // No need to emit `rerun-if-env-changed` for these,
65
+ // as they are controlled by Cargo itself.
66
+ #[ allow( clippy:: disallowed_methods) ]
67
+ match env:: var ( name) {
68
+ Ok ( var) => Ok ( Cow :: Owned ( var) ) ,
69
+ Err ( err) => match fallback {
70
+ Some ( fallback) => Ok ( fallback) ,
71
+ None => Err ( Error :: new (
72
+ ErrorKind :: EnvVarNotFound ,
73
+ format ! ( "did not find fallback information for target `{target_triple}`, and failed reading {name}: {err}" ) ,
74
+ ) ) ,
75
+ } ,
76
+ }
72
77
} ;
73
78
79
+ // Prefer to use `CARGO_ENV_*` if set, since these contain the most
80
+ // correct information relative to the current `rustc`, and makes it
81
+ // possible to support custom target JSON specs unknown to `rustc`.
82
+ //
83
+ // NOTE: If the user is using an older `rustc`, that data may be older
84
+ // than our pre-generated data, but we still prefer Cargo's view of
85
+ // the world, since at least `cc` won't differ from `rustc` in that
86
+ // case.
87
+ //
88
+ // These may not be set in case the user depended on being able to
89
+ // just set `TARGET` outside of build scripts; in those cases, fall
90
+ // back back to data from the known set of target triples instead.
91
+ //
92
+ // See discussion in #1225 for further details.
93
+ let fallback_target = Target :: from_str ( & target_triple) . ok ( ) ;
94
+ let ft = fallback_target. as_ref ( ) ;
95
+ let arch = cargo_env ( "CARGO_CFG_TARGET_ARCH" , ft. map ( |t| t. arch . clone ( ) ) ) ?;
96
+ let vendor = cargo_env ( "CARGO_CFG_TARGET_VENDOR" , ft. map ( |t| t. vendor . clone ( ) ) ) ?;
97
+ let os = cargo_env ( "CARGO_CFG_TARGET_OS" , ft. map ( |t| t. os . clone ( ) ) ) ?;
98
+ let env = cargo_env ( "CARGO_CFG_TARGET_ENV" , ft. map ( |t| t. env . clone ( ) ) ) ?;
99
+ // `target_abi` was stabilized in Rust 1.78, which is higher than our
100
+ // MSRV, so it may not always be available; In that case, fall back to
101
+ // `""`, which is _probably_ correct for unknown target triples.
102
+ let abi = cargo_env ( "CARGO_CFG_TARGET_ABI" , ft. map ( |t| t. abi . clone ( ) ) )
103
+ . unwrap_or ( Cow :: Borrowed ( "" ) ) ;
104
+
74
105
Ok ( Self {
75
106
full_arch : full_arch. to_string ( ) . into ( ) ,
76
107
arch : arch. into ( ) ,
@@ -85,6 +116,7 @@ impl Target {
85
116
impl FromStr for Target {
86
117
type Err = Error ;
87
118
119
+ /// This will fail when using a custom target triple unknown to `rustc`.
88
120
fn from_str ( target_triple : & str ) -> Result < Self , Error > {
89
121
if let Some ( target) = generated:: get ( target_triple) {
90
122
Ok ( target)
0 commit comments