Skip to content

Commit 4d0ce6c

Browse files
committed
Parse target triples
1 parent 5fbe4d5 commit 4d0ce6c

File tree

5 files changed

+545
-3664
lines changed

5 files changed

+545
-3664
lines changed

src/lib.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -2192,14 +2192,13 @@ impl Build {
21922192
// So instead, we pass the deployment target with `-m*-version-min=`, and only
21932193
// pass it here on visionOS and Mac Catalyst where that option does not exist:
21942194
// https://github.com/rust-lang/cc-rs/issues/1383
2195-
let clang_target = if target.os == "visionos" || target.abi == "macabi" {
2196-
Cow::Owned(
2197-
target.versioned_llvm_target(&self.apple_deployment_target(target)),
2198-
)
2195+
let version = if target.os == "visionos" || target.abi == "macabi" {
2196+
Some(self.apple_deployment_target(target))
21992197
} else {
2200-
Cow::Borrowed(target.llvm_target)
2198+
None
22012199
};
22022200

2201+
let clang_target = target.llvm_target(version.as_deref());
22032202
cmd.push_cc_arg(format!("--target={clang_target}").into());
22042203
}
22052204
}
@@ -2216,7 +2215,7 @@ impl Build {
22162215
cmd.push_cc_arg("-m32".into());
22172216
cmd.push_cc_arg("-arch:IA32".into());
22182217
} else {
2219-
cmd.push_cc_arg(format!("--target={}", target.llvm_target).into());
2218+
cmd.push_cc_arg(format!("--target={}", target.llvm_target(None)).into());
22202219
}
22212220
} else if target.full_arch == "i586" {
22222221
cmd.push_cc_arg("-arch:IA32".into());
@@ -3501,7 +3500,9 @@ impl Build {
35013500

35023501
fn get_target(&self) -> Result<TargetInfo<'_>, Error> {
35033502
match &self.target {
3504-
Some(t) if Some(&**t) != self.getenv_unwrap_str("TARGET").ok().as_deref() => t.parse(),
3503+
Some(t) if Some(&**t) != self.getenv_unwrap_str("TARGET").ok().as_deref() => {
3504+
TargetInfo::from_rustc_target(t)
3505+
}
35053506
// Fetch target information from environment if not set, or if the
35063507
// target was the same as the TARGET environment variable, in
35073508
// case the user did `build.target(&env::var("TARGET").unwrap())`.

src/target.rs

+91-46
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,7 @@
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-
95
mod apple;
10-
mod generated;
116
mod llvm;
127
mod 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)]
8544
mod 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

Comments
 (0)