Skip to content

Commit 968da78

Browse files
authored
Parse rustc target names (#1413)
Parse target names instead of using a pre-generated list. Allows target names like those used by certain Linux distributions, even when compiling outside build.rs.
1 parent 20300d5 commit 968da78

File tree

10 files changed

+1134
-3838
lines changed

10 files changed

+1134
-3838
lines changed
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: Test nightly `rustc` targets and add issue comment if changed
2+
3+
on:
4+
workflow_dispatch: # Allow running on-demand
5+
schedule:
6+
- cron: '0 3 * * 1,4' # Every Monday and Thursdag
7+
push:
8+
branches:
9+
- 'main'
10+
paths:
11+
- 'src/target/**'
12+
13+
jobs:
14+
regenerate:
15+
if: github.repository_owner == 'rust-lang'
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v4
19+
with:
20+
persist-credentials: true
21+
22+
- name: Install current nightly Rust
23+
run: |
24+
rustup toolchain install nightly --no-self-update --profile minimal
25+
rustup default nightly
26+
- run: cargo update
27+
- uses: Swatinem/rust-cache@v2
28+
29+
- name: Test with `RUSTFLAGS=--cfg=rustc_target_test cargo test --lib`
30+
id: test
31+
continue-on-error: true # We want to open an issue if it fails
32+
run: cargo test --lib 2>&1 | tee test_output.txt
33+
env:
34+
RUSTFLAGS: --cfg=rustc_target_test
35+
36+
# Added to https://github.com/rust-lang/cc-rs/issues/1426
37+
- name: Add issue comment if test failed
38+
if: steps.test.outcome == 'failure'
39+
env:
40+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41+
run: |
42+
gh issue comment 1426 --body "
43+
Failed parsing `rustc` target on `$(rustc --version)`.
44+
45+
<details><summary>Test output</summary>
46+
<p>
47+
\`\`\`
48+
$(cat test_output.txt)
49+
\`\`\`
50+
</p>
51+
</details>
52+
" --head $(git branch --show-current)

dev-tools/gen-target-info/src/lib.rs

-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,3 @@ pub use target_specs::*;
33

44
mod read;
55
pub use read::*;
6-
7-
mod write;
8-
pub use write::*;

dev-tools/gen-target-info/src/main.rs

+12-70
Original file line numberDiff line numberDiff line change
@@ -5,76 +5,18 @@ use gen_target_info::{
55
get_target_spec_from_msrv, get_target_specs_from_json, get_targets_msrv, RustcTargetSpecs,
66
};
77

8-
const PRELUDE: &str = r#"//! This file is generated code. Please edit the generator
9-
//! in dev-tools/gen-target-info if you need to make changes.
8+
const PRELUDE: &str = r#"//! This file is generated code. Please edit the generator in
9+
//! dev-tools/gen-target-info if you need to make changes, or see
10+
//! src/target/llvm.rs if you need to configure a specific LLVM triple.
1011
1112
"#;
1213

1314
fn generate_target_mapping(f: &mut File, target_specs: &RustcTargetSpecs) -> std::io::Result<()> {
14-
writeln!(f, "use super::TargetInfo;")?;
15-
writeln!(f)?;
16-
writeln!(
17-
f,
18-
"pub(crate) const LIST: &[(&str, TargetInfo<'static>)] = &["
19-
)?;
15+
writeln!(f, "#[rustfmt::skip]")?;
16+
writeln!(f, "pub(crate) const LLVM_TARGETS: &[(&str, &str)] = &[")?;
2017

21-
for (triple, spec) in &target_specs.0 {
22-
let full_arch = triple.split_once('-').unwrap().0;
23-
let arch = &spec.arch;
24-
let vendor = spec.vendor.as_deref().unwrap_or("unknown");
25-
let os = spec.os.as_deref().unwrap_or("none");
26-
let env = spec.env.as_deref().unwrap_or("");
27-
let abi = spec.abi.as_deref().unwrap_or("");
28-
29-
// FIXME(madsmtm): Unnecessary once we bump MSRV to Rust 1.74
30-
let llvm_target = if spec.llvm_target == "armv7-apple-ios7.0.0" {
31-
"armv7-apple-ios".to_string()
32-
} else if os == "uefi" {
33-
// Override the UEFI LLVM targets.
34-
//
35-
// The rustc mappings (as of 1.82) for the UEFI targets are:
36-
// * i686-unknown-uefi -> i686-unknown-windows-gnu
37-
// * x86_64-unknown-uefi -> x86_64-unknown-windows
38-
// * aarch64-unknown-uefi -> aarch64-unknown-windows
39-
//
40-
// However, in cc-rs all the UEFI targets use
41-
// -windows-gnu. This has been the case since 2021 [1].
42-
// * i686-unknown-uefi -> i686-unknown-windows-gnu
43-
// * x86_64-unknown-uefi -> x86_64-unknown-windows-gnu
44-
// * aarch64-unknown-uefi -> aarch64-unknown-windows-gnu
45-
//
46-
// For now, override the UEFI mapping to keep the behavior
47-
// of cc-rs unchanged.
48-
//
49-
// TODO: as discussed in [2], it may be possible to switch
50-
// to new UEFI targets added to clang, and regardless it
51-
// would be good to have consistency between rustc and
52-
// cc-rs.
53-
//
54-
// [1]: https://github.com/rust-lang/cc-rs/pull/623
55-
// [2]: https://github.com/rust-lang/cc-rs/pull/1264
56-
let arch = if spec.arch == "x86" {
57-
"i686"
58-
} else {
59-
&spec.arch
60-
};
61-
format!("{}-unknown-windows-gnu", arch)
62-
} else {
63-
spec.llvm_target.clone()
64-
};
65-
66-
writeln!(f, " (")?;
67-
writeln!(f, " {triple:?},")?;
68-
writeln!(f, " TargetInfo {{")?;
69-
writeln!(f, " full_arch: {full_arch:?},")?;
70-
writeln!(f, " arch: {arch:?},")?;
71-
writeln!(f, " vendor: {vendor:?},")?;
72-
writeln!(f, " os: {os:?},")?;
73-
writeln!(f, " env: {env:?},")?;
74-
writeln!(f, " abi: {abi:?},")?;
75-
writeln!(f, " llvm_target: {llvm_target:?},")?;
76-
writeln!(f, " }},")?;
77-
writeln!(f, " ),")?;
18+
for (target_name, spec) in &target_specs.0 {
19+
writeln!(f, " ({target_name:?}, {:?}),", spec.llvm_target)?;
7820
}
7921

8022
writeln!(f, "];")?;
@@ -92,13 +34,13 @@ fn main() {
9234
.unwrap()
9335
!= 0
9436
{
95-
for target_triple in get_targets_msrv().lines() {
96-
let target_triple = target_triple.unwrap();
97-
let target_triple = target_triple.trim();
37+
for target_name in get_targets_msrv().lines() {
38+
let target_name = target_name.unwrap();
39+
let target_name = target_name.trim();
9840
target_specs
9941
.0
100-
.entry(target_triple.to_string())
101-
.or_insert_with(|| get_target_spec_from_msrv(target_triple));
42+
.entry(target_name.to_string())
43+
.or_insert_with(|| get_target_spec_from_msrv(target_name));
10244
}
10345
}
10446

dev-tools/gen-target-info/src/write.rs

-18
This file was deleted.

src/lib.rs

+19-11
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,11 @@
145145
//!
146146
//! * Unix platforms require `cc` to be the C compiler. This can be found by
147147
//! installing cc/clang on Linux distributions and Xcode on macOS, for example.
148-
//! * Windows platforms targeting MSVC (e.g. your target triple ends in `-msvc`)
148+
//! * Windows platforms targeting MSVC (e.g. your target name ends in `-msvc`)
149149
//! require Visual Studio to be installed. `cc-rs` attempts to locate it, and
150150
//! if it fails, `cl.exe` is expected to be available in `PATH`. This can be
151151
//! set up by running the appropriate developer tools shell.
152-
//! * Windows platforms targeting MinGW (e.g. your target triple ends in `-gnu`)
152+
//! * Windows platforms targeting MinGW (e.g. your target name ends in `-gnu`)
153153
//! require `cc` to be available in `PATH`. We recommend the
154154
//! [MinGW-w64](https://www.mingw-w64.org/) distribution.
155155
//! You may also acquire it via
@@ -2177,9 +2177,9 @@ impl Build {
21772177
// libstdc++ (this behavior was changed in llvm 14).
21782178
//
21792179
// This breaks C++11 (or greater) builds if targeting FreeBSD with the
2180-
// generic xxx-unknown-freebsd triple on clang 13 or below *without*
2180+
// generic xxx-unknown-freebsd target on clang 13 or below *without*
21812181
// explicitly specifying that libc++ should be used.
2182-
// When cross-compiling, we can't infer from the rust/cargo target triple
2182+
// When cross-compiling, we can't infer from the rust/cargo target name
21832183
// which major version of FreeBSD we are targeting, so we need to make sure
21842184
// that libc++ is used (unless the user has explicitly specified otherwise).
21852185
// There's no compelling reason to use a different approach when compiling
@@ -2227,14 +2227,14 @@ impl Build {
22272227
// So instead, we pass the deployment target with `-m*-version-min=`, and only
22282228
// pass it here on visionOS and Mac Catalyst where that option does not exist:
22292229
// https://github.com/rust-lang/cc-rs/issues/1383
2230-
let clang_target = if target.os == "visionos" || target.abi == "macabi" {
2231-
Cow::Owned(
2232-
target.versioned_llvm_target(&self.apple_deployment_target(target)),
2233-
)
2230+
let version = if target.os == "visionos" || target.abi == "macabi" {
2231+
Some(self.apple_deployment_target(target))
22342232
} else {
2235-
Cow::Borrowed(target.llvm_target)
2233+
None
22362234
};
22372235

2236+
let clang_target =
2237+
target.llvm_target(&self.get_raw_target()?, version.as_deref());
22382238
cmd.push_cc_arg(format!("--target={clang_target}").into());
22392239
}
22402240
}
@@ -2260,7 +2260,13 @@ impl Build {
22602260
// <https://github.com/microsoft/STL/pull/4741>.
22612261
cmd.push_cc_arg("-arch:SSE2".into());
22622262
} else {
2263-
cmd.push_cc_arg(format!("--target={}", target.llvm_target).into());
2263+
cmd.push_cc_arg(
2264+
format!(
2265+
"--target={}",
2266+
target.llvm_target(&self.get_raw_target()?, None)
2267+
)
2268+
.into(),
2269+
);
22642270
}
22652271
} else if target.full_arch == "i586" {
22662272
cmd.push_cc_arg("-arch:IA32".into());
@@ -3545,7 +3551,9 @@ impl Build {
35453551

35463552
fn get_target(&self) -> Result<TargetInfo<'_>, Error> {
35473553
match &self.target {
3548-
Some(t) if Some(&**t) != self.getenv_unwrap_str("TARGET").ok().as_deref() => t.parse(),
3554+
Some(t) if Some(&**t) != self.getenv_unwrap_str("TARGET").ok().as_deref() => {
3555+
TargetInfo::from_rustc_target(t)
3556+
}
35493557
// Fetch target information from environment if not set, or if the
35503558
// target was the same as the TARGET environment variable, in
35513559
// case the user did `build.target(&env::var("TARGET").unwrap())`.

src/target.rs

+2-93
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
1-
//! Very basic parsing of `rustc` target triples.
2-
//!
3-
//! See the `target-lexicon` crate for a more principled approach to this.
4-
5-
use std::str::FromStr;
6-
7-
use crate::{Error, ErrorKind};
1+
//! Parsing of `rustc` target names to match the values exposed to Cargo
2+
//! build scripts (`CARGO_CFG_*`).
83
94
mod apple;
105
mod generated;
@@ -43,90 +38,4 @@ 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-
}
82-
}
83-
84-
#[cfg(test)]
85-
mod tests {
86-
use std::str::FromStr;
87-
88-
use super::TargetInfo;
89-
90-
// Test tier 1 targets
91-
#[test]
92-
fn tier1() {
93-
let targets = [
94-
"aarch64-unknown-linux-gnu",
95-
"aarch64-apple-darwin",
96-
"i686-pc-windows-gnu",
97-
"i686-pc-windows-msvc",
98-
"i686-unknown-linux-gnu",
99-
"x86_64-apple-darwin",
100-
"x86_64-pc-windows-gnu",
101-
"x86_64-pc-windows-msvc",
102-
"x86_64-unknown-linux-gnu",
103-
];
104-
105-
for target in targets {
106-
// Check that it parses
107-
let _ = TargetInfo::from_str(target).unwrap();
108-
}
109-
}
110-
111-
// Various custom target triples not (or no longer) known by `rustc`
112-
#[test]
113-
fn cannot_parse_extra() {
114-
let targets = [
115-
"aarch64-unknown-none-gnu",
116-
"aarch64-uwp-windows-gnu",
117-
"arm-frc-linux-gnueabi",
118-
"arm-unknown-netbsd-eabi",
119-
"armv7neon-unknown-linux-gnueabihf",
120-
"armv7neon-unknown-linux-musleabihf",
121-
"thumbv7-unknown-linux-gnueabihf",
122-
"thumbv7-unknown-linux-musleabihf",
123-
"x86_64-rumprun-netbsd",
124-
"x86_64-unknown-linux",
125-
];
126-
127-
for target in targets {
128-
// Check that it does not parse
129-
let _ = TargetInfo::from_str(target).unwrap_err();
130-
}
131-
}
13241
}

0 commit comments

Comments
 (0)