Description
Motivation
While code in build.rs
can and should take advantage of CARGO_CFG_*
, cc-rs
still has to parse rustc
target names/triples/tuples to support bootstrap and other such code outside build.rs
. I suspect cc-rs
is not the only one that wants to do this.
Parsing the arch, vendor, OS, env and ABI information from rustc
targets is difficult however, because while they may have started out as mostly matching Clang's naming scheme, they have slowly diverged from that, and are at this point mostly an arbitary mapping to target information.
To remedy this, I propose that we define a set of machine-verifyable "rules" that can govern new target tuples, to ensure that the cfgs target_arch
, target_vendor
, target_os
, target_env
and target_abi
can (more) easily be figured out from the tuple alone.
To be clear here, I'm not against letting targets fix their definitions (e.g. in the past, i386-apple-ios
did not set target_abi = "sim"
, but fixing that was the correct move). But making the target name diverge from the information it contains does impose a cost that we should be aware of.
Related: rust-lang/rust#135376, rust-lang/rust#136495, #846 and rust-lang/lang-team#102.
Implementation
A consistency check for rustc_target::spec::Target
with roughly the following logic:
- Each target tuple has 2, 3 or 4 components.
- 2-components names are of the format
arch+subarch-os
. - 3-components names are of either the format
arch+subarch-os-env+abi
orarch+subarch-vendor-os
. - 4-components names are of the format
arch+subarch-vendor-os-env+abi
. - New vendored targets are discouraged when the vendor is
unknown
, and the vendor-less forms should be preferred.
There would be targets that wouldn't fit under these rules, and would have to be added to an exception table. I think the full list is below (but I'd have to fully implement it to be certain):
Existing target tuple | More correct target tuple | Remark |
---|---|---|
x86_64-unknown-linux-none |
x86_64-unknown-linux |
none is not an environment |
*-apple-darwin |
*-apple-macos |
macOS is the actual OS, Darwin is a remnant |
i386-apple-ios |
i686-apple-ios-sim |
Actually a simulator target |
x86_64-apple-ios |
x86_64-apple-ios-sim |
^ |
x86_64-apple-tvos |
x86_64-apple-tvos-sim |
^ |
mips64-openwrt-linux-musl |
mips64-openwrt-linux-muslabi64 |
Match mips64-unknown-linux-muslabi64 |
armv6-unknown-freebsd |
armv6-unknown-freebsd-eabihf |
Match armv6-unknown-netbsd-eabihf , armv7-wrs-vxworks-eabihf etc. |
armv7-unknown-freebsd |
armv7-unknown-freebsd-eabihf |
^ |
armv6k-nintendo-3ds |
armv6k-nintendo-3ds-eabihf |
^ |
armv7-unknown-trusty |
armv7-unknown-trusty-eabi |
^ |
wasm*-unknown-unknown |
wasm*-none |
unknown is not an OS, none is |
wasm32-wasip1 |
wasm32-wasi-p1 |
Make it clear what is target_os , and what is target_env . Alternatively we'd use target_os = "wasip1" |
wasm32-wasip2 |
wasm32-wasi-p2 |
^ |
wasm32-wasip1-threads |
Unclear? | ^ |
*-linux-android |
*-android |
Android is the OS name, the "Linux" part is a remnant |
*-linux-androideabi |
*-android-eabi |
^ |
*-unknown-linux-ohos |
*-ohos |
^ (probably) |
x86_64-fortanix-unknown-sgx |
Unclear? | Sets both target_vendor = "fortanix" and target_abi = "fortanix" |
xtensa-esp32*-none-elf |
xtensa-espressif-none-esp32* |
esp32 is not the vendor, Espressif is |
xtensa-esp32*-espidf |
xtensa-espressif-espidf-esp32* |
^ |
*-uwp-windows-gnu |
*-windows-gnuuwp |
UWP isn't a vendor (sets target_abi = "uwp" ) |
*-uwp-windows-msvc |
*-windows-msvcuwp |
^ |
*-unknown-linux-gnu_ilp32 |
*-unknown-linux-gnuilp32 |
Environment + ABI should not be underscore-separated |
Note that I am not proposing renaming these, that is probably not feasible for most of them, and should be done separately in any case. I am only proposing that new targets do not have the same flaws.
Example reasons to add to the exceptions table in the future (but should ideally happen rarely):
- When
target_env
/target_abi
is added where it was previously incorrect/missing for a target. - If consistency with other targets is valued higher (e.g. maybe we want
wasm32-wasip3
overwasm32-wasi-p3
).
Precedent / Prior art
Zig's -target
is pretty consistent with roughly $ARCH-$OS-$ENV
, though they can more easily do that because they don't ship a pre-compiled standard library like rustup does (and because they can still make sweeping breaking changes). Also, they're considering adding a fourth component to more clearly represent ABI information.
rustc
already does a consistency check on the target information, see Target::check_consistency
. This would probably "just" be an expansion of that to take into account the target name itself as well.
Alternatives
- Do nothing, and declare that Target Names Are Not To Be Parsed And All That Attempt To Shall Be Struck Down Before Their Enemies.
Users must invoke and parserustc --print cfg --target $target
when outsidebuild.rs
. - Choose another naming scheme than the one I proposed (I don't have a strong preference, any scheme is fine as long as there is one).
Process
The main points of the Major Change Process are as follows:
- File an issue describing the proposal.
- A compiler team member or contributor who is knowledgeable in the area can second by writing
@rustbot second
.- Finding a "second" suffices for internal changes. If however, you are proposing a new public-facing feature, such as a
-C flag
, then full team check-off is required. - Compiler team members can initiate a check-off via
@rfcbot fcp merge
on either the MCP or the PR.
- Finding a "second" suffices for internal changes. If however, you are proposing a new public-facing feature, such as a
- Once an MCP is seconded, the Final Comment Period begins. If no objections are raised after 10 days, the MCP is considered approved.
You can read more about Major Change Proposals on forge.