1
Fork 0

Rollup merge of #131037 - madsmtm:move-llvm-target-versioning, r=petrochenkov

Move versioned Apple LLVM targets from `rustc_target` to `rustc_codegen_ssa`

Fully specified LLVM targets contain the OS version on macOS/iOS/tvOS/watchOS/visionOS, and this version depends on the deployment target environment variables like `MACOSX_DEPLOYMENT_TARGET`, `IPHONEOS_DEPLOYMENT_TARGET` etc.

We would like to move this to later in the compilation pipeline, both because it feels impure to access environment variables when fetching target information, but mostly because we need access to more information from https://github.com/rust-lang/rust/pull/130883 to do https://github.com/rust-lang/rust/issues/118204. See also https://github.com/rust-lang/rust/pull/129342#issuecomment-2335156119 for some discussion.

The first and second commit does the actual refactor, it should be a non-functional change, the third commit adds diagnostics for invalid deployment targets, which are now possible to do because we have access to the session.

Tested with the same commands as in https://github.com/rust-lang/rust/pull/130435.

r? ``````@petrochenkov``````
This commit is contained in:
Matthias Krüger 2024-11-02 08:33:10 +01:00 committed by GitHub
commit bb544f863f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 271 additions and 165 deletions

View file

@ -1,10 +1,9 @@
use std::borrow::Cow;
use std::env;
use std::num::ParseIntError;
use crate::spec::{
Cc, DebuginfoKind, FramePointer, LinkerFlavor, Lld, SplitDebuginfo, StackProbeType, StaticCow,
Target, TargetOptions, cvs,
TargetOptions, cvs,
};
#[cfg(test)]
@ -97,9 +96,8 @@ impl TargetAbi {
}
}
/// Get the base target options, LLVM target and `target_arch` from the three
/// things that uniquely identify Rust's Apple targets: The OS, the
/// architecture, and the ABI.
/// Get the base target options, unversioned LLVM target and `target_arch` from the three
/// things that uniquely identify Rust's Apple targets: The OS, the architecture, and the ABI.
pub(crate) fn base(
os: &'static str,
arch: Arch,
@ -155,117 +153,14 @@ pub(crate) fn base(
..Default::default()
};
(opts, llvm_target(os, arch, abi), arch.target_arch())
(opts, unversioned_llvm_target(os, arch, abi), arch.target_arch())
}
pub fn platform(target: &Target) -> Option<u32> {
Some(match (&*target.os, &*target.abi) {
("macos", _) => object::macho::PLATFORM_MACOS,
("ios", "macabi") => object::macho::PLATFORM_MACCATALYST,
("ios", "sim") => object::macho::PLATFORM_IOSSIMULATOR,
("ios", _) => object::macho::PLATFORM_IOS,
("watchos", "sim") => object::macho::PLATFORM_WATCHOSSIMULATOR,
("watchos", _) => object::macho::PLATFORM_WATCHOS,
("tvos", "sim") => object::macho::PLATFORM_TVOSSIMULATOR,
("tvos", _) => object::macho::PLATFORM_TVOS,
// FIXME: Upgrade to `object-rs` 0.33+ implementation with visionOS platform definition
("visionos", "sim") => 12,
("visionos", _) => 11,
_ => return None,
})
}
/// Hack for calling `deployment_target` outside of this module.
pub fn deployment_target_for_target(target: &Target) -> (u16, u8, u8) {
let arch = if target.llvm_target.starts_with("arm64e") {
Arch::Arm64e
} else if target.arch == "aarch64" {
Arch::Arm64
} else {
// Dummy architecture, only used by `deployment_target` anyhow
Arch::X86_64
};
let abi = match &*target.abi {
"macabi" => TargetAbi::MacCatalyst,
"sim" => TargetAbi::Simulator,
"" => TargetAbi::Normal,
abi => unreachable!("invalid abi '{abi}' for Apple target"),
};
deployment_target(&target.os, arch, abi)
}
/// Get the deployment target based on the standard environment variables, or
/// fall back to a sane default.
fn deployment_target(os: &str, arch: Arch, abi: TargetAbi) -> (u16, u8, u8) {
// When bumping a version in here, remember to update the platform-support
// docs too.
//
// NOTE: If you are looking for the default deployment target, prefer
// `rustc --print deployment-target`, as the default here may change in
// future `rustc` versions.
// Minimum operating system versions currently supported by `rustc`.
let os_min = match os {
"macos" => (10, 12, 0),
"ios" => (10, 0, 0),
"tvos" => (10, 0, 0),
"watchos" => (5, 0, 0),
"visionos" => (1, 0, 0),
_ => unreachable!("tried to get deployment target for non-Apple platform"),
};
// On certain targets it makes sense to raise the minimum OS version.
//
// This matches what LLVM does, see:
// <https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L1900-L1932>
let min = match (os, arch, abi) {
("macos", Arch::Arm64 | Arch::Arm64e, _) => (11, 0, 0),
("ios", Arch::Arm64 | Arch::Arm64e, TargetAbi::MacCatalyst) => (14, 0, 0),
("ios", Arch::Arm64 | Arch::Arm64e, TargetAbi::Simulator) => (14, 0, 0),
("ios", Arch::Arm64e, TargetAbi::Normal) => (14, 0, 0),
// Mac Catalyst defaults to 13.1 in Clang.
("ios", _, TargetAbi::MacCatalyst) => (13, 1, 0),
("tvos", Arch::Arm64 | Arch::Arm64e, TargetAbi::Simulator) => (14, 0, 0),
("watchos", Arch::Arm64 | Arch::Arm64e, TargetAbi::Simulator) => (7, 0, 0),
_ => os_min,
};
// The environment variable used to fetch the deployment target.
let env_var = match os {
"macos" => "MACOSX_DEPLOYMENT_TARGET",
"ios" => "IPHONEOS_DEPLOYMENT_TARGET",
"watchos" => "WATCHOS_DEPLOYMENT_TARGET",
"tvos" => "TVOS_DEPLOYMENT_TARGET",
"visionos" => "XROS_DEPLOYMENT_TARGET",
_ => unreachable!("tried to get deployment target env var for non-Apple platform"),
};
if let Ok(deployment_target) = env::var(env_var) {
match parse_version(&deployment_target) {
// It is common that the deployment target is set too low, e.g. on
// macOS Aarch64 to also target older x86_64, the user may set a
// lower deployment target than supported.
//
// To avoid such issues, we silently raise the deployment target
// here.
// FIXME: We want to show a warning when `version < os_min`.
Ok(version) => version.max(min),
// FIXME: Report erroneous environment variable to user.
Err(_) => min,
}
} else {
min
}
}
/// Generate the target triple that we need to pass to LLVM and/or Clang.
fn llvm_target(os: &str, arch: Arch, abi: TargetAbi) -> StaticCow<str> {
// The target triple depends on the deployment target, and is required to
// enable features such as cross-language LTO, and for picking the right
// Mach-O commands.
//
// Certain optimizations also depend on the deployment target.
let (major, minor, patch) = deployment_target(os, arch, abi);
/// Generate part of the LLVM target triple.
///
/// See `rustc_codegen_ssa::back::versioned_llvm_target` for the full triple passed to LLVM and
/// Clang.
fn unversioned_llvm_target(os: &str, arch: Arch, abi: TargetAbi) -> StaticCow<str> {
let arch = arch.target_name();
// Convert to the "canonical" OS name used by LLVM:
// https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L236-L282
@ -282,7 +177,7 @@ fn llvm_target(os: &str, arch: Arch, abi: TargetAbi) -> StaticCow<str> {
TargetAbi::MacCatalyst => "-macabi",
TargetAbi::Simulator => "-simulator",
};
format!("{arch}-apple-{os}{major}.{minor}.{patch}{environment}").into()
format!("{arch}-apple-{os}{environment}").into()
}
fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> {
@ -321,20 +216,3 @@ fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> {
cvs!["MACOSX_DEPLOYMENT_TARGET"]
}
}
/// Parse an OS version triple (SDK version or deployment target).
///
/// The size of the returned numbers here are limited by Mach-O's
/// `LC_BUILD_VERSION`.
fn parse_version(version: &str) -> Result<(u16, u8, u8), ParseIntError> {
if let Some((major, minor)) = version.split_once('.') {
let major = major.parse()?;
if let Some((minor, patch)) = minor.split_once('.') {
Ok((major, minor.parse()?, patch.parse()?))
} else {
Ok((major, minor.parse()?, 0))
}
} else {
Ok((version.parse()?, 0, 0))
}
}

View file

@ -1,4 +1,3 @@
use super::parse_version;
use crate::spec::targets::{
aarch64_apple_darwin, aarch64_apple_ios_sim, aarch64_apple_visionos_sim,
aarch64_apple_watchos_sim, i686_apple_darwin, x86_64_apple_darwin, x86_64_apple_ios,
@ -40,11 +39,3 @@ fn macos_link_environment_unmodified() {
],);
}
}
#[test]
fn test_parse_version() {
assert_eq!(parse_version("10"), Ok((10, 0, 0)));
assert_eq!(parse_version("10.12"), Ok((10, 12, 0)));
assert_eq!(parse_version("10.12.6"), Ok((10, 12, 6)));
assert_eq!(parse_version("9999.99.99"), Ok((9999, 99, 99)));
}

View file

@ -65,10 +65,6 @@ pub mod abi {
}
mod base;
pub use base::apple::{
deployment_target_for_target as current_apple_deployment_target,
platform as current_apple_platform,
};
pub use base::avr_gnu::ef_avr_arch;
/// Linker is called through a C/C++ compiler.
@ -2009,7 +2005,12 @@ impl TargetWarnings {
/// Every field here must be specified, and has no default value.
#[derive(PartialEq, Clone, Debug)]
pub struct Target {
/// Target triple to pass to LLVM.
/// Unversioned target triple to pass to LLVM.
///
/// Target triples can optionally contain an OS version (notably Apple targets), which rustc
/// cannot know without querying the environment.
///
/// Use `rustc_codegen_ssa::back::versioned_llvm_target` if you need the full LLVM target.
pub llvm_target: StaticCow<str>,
/// Metadata about a target, for example the description or tier.
/// Used for generating target documentation.