Skip to content

Commit 5ade71f

Browse files
committed
Redo from_cargo_environment_variables to be more error resilient
1 parent f857326 commit 5ade71f

File tree

1 file changed

+56
-24
lines changed

1 file changed

+56
-24
lines changed

src/target.rs

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -42,35 +42,66 @@ pub(crate) struct Target {
4242

4343
impl Target {
4444
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(
5959
ErrorKind::InvalidTarget,
60-
format!("target `{target}` had an unknown architecture"),
60+
format!("target `{target_triple}` had an unknown architecture"),
6161
))?;
6262

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+
}
7277
};
7378

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+
74105
Ok(Self {
75106
full_arch: full_arch.to_string().into(),
76107
arch: arch.into(),
@@ -85,6 +116,7 @@ impl Target {
85116
impl FromStr for Target {
86117
type Err = Error;
87118

119+
/// This will fail when using a custom target triple unknown to `rustc`.
88120
fn from_str(target_triple: &str) -> Result<Self, Error> {
89121
if let Some(target) = generated::get(target_triple) {
90122
Ok(target)

0 commit comments

Comments
 (0)