mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
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:
commit
bb544f863f
@ -40,6 +40,7 @@ use std::sync::Arc;
|
|||||||
use cranelift_codegen::isa::TargetIsa;
|
use cranelift_codegen::isa::TargetIsa;
|
||||||
use cranelift_codegen::settings::{self, Configurable};
|
use cranelift_codegen::settings::{self, Configurable};
|
||||||
use rustc_codegen_ssa::CodegenResults;
|
use rustc_codegen_ssa::CodegenResults;
|
||||||
|
use rustc_codegen_ssa::back::versioned_llvm_target;
|
||||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
@ -260,7 +261,9 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn target_triple(sess: &Session) -> target_lexicon::Triple {
|
fn target_triple(sess: &Session) -> target_lexicon::Triple {
|
||||||
match sess.target.llvm_target.parse() {
|
// FIXME(madsmtm): Use `sess.target.llvm_target` once target-lexicon supports unversioned macOS.
|
||||||
|
// See <https://github.com/bytecodealliance/target-lexicon/pull/113>
|
||||||
|
match versioned_llvm_target(sess).parse() {
|
||||||
Ok(triple) => triple,
|
Ok(triple) => triple,
|
||||||
Err(err) => sess.dcx().fatal(format!("target not recognized: {}", err)),
|
Err(err) => sess.dcx().fatal(format!("target not recognized: {}", err)),
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ use llvm::{
|
|||||||
LLVMRustLLVMHasZlibCompressionForDebugSymbols, LLVMRustLLVMHasZstdCompressionForDebugSymbols,
|
LLVMRustLLVMHasZlibCompressionForDebugSymbols, LLVMRustLLVMHasZstdCompressionForDebugSymbols,
|
||||||
};
|
};
|
||||||
use rustc_codegen_ssa::back::link::ensure_removed;
|
use rustc_codegen_ssa::back::link::ensure_removed;
|
||||||
|
use rustc_codegen_ssa::back::versioned_llvm_target;
|
||||||
use rustc_codegen_ssa::back::write::{
|
use rustc_codegen_ssa::back::write::{
|
||||||
BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
|
BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
|
||||||
TargetMachineFactoryFn,
|
TargetMachineFactoryFn,
|
||||||
@ -211,7 +212,7 @@ pub(crate) fn target_machine_factory(
|
|||||||
singlethread = false;
|
singlethread = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let triple = SmallCStr::new(&sess.target.llvm_target);
|
let triple = SmallCStr::new(&versioned_llvm_target(sess));
|
||||||
let cpu = SmallCStr::new(llvm_util::target_cpu(sess));
|
let cpu = SmallCStr::new(llvm_util::target_cpu(sess));
|
||||||
let features = CString::new(target_features.join(",")).unwrap();
|
let features = CString::new(target_features.join(",")).unwrap();
|
||||||
let abi = SmallCStr::new(&sess.target.llvm_abiname);
|
let abi = SmallCStr::new(&sess.target.llvm_abiname);
|
||||||
|
@ -3,6 +3,7 @@ use std::cell::{Cell, RefCell};
|
|||||||
use std::ffi::{CStr, c_uint};
|
use std::ffi::{CStr, c_uint};
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
|
use rustc_codegen_ssa::back::versioned_llvm_target;
|
||||||
use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh};
|
use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh};
|
||||||
use rustc_codegen_ssa::errors as ssa_errors;
|
use rustc_codegen_ssa::errors as ssa_errors;
|
||||||
use rustc_codegen_ssa::traits::*;
|
use rustc_codegen_ssa::traits::*;
|
||||||
@ -182,7 +183,7 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||||||
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
|
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
let llvm_target = SmallCStr::new(&sess.target.llvm_target);
|
let llvm_target = SmallCStr::new(&versioned_llvm_target(sess));
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
|
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,12 @@ codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not imp
|
|||||||
|
|
||||||
codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error}
|
codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error}
|
||||||
|
|
||||||
|
codegen_ssa_apple_deployment_target_invalid =
|
||||||
|
failed to parse deployment target specified in {$env_var}: {$error}
|
||||||
|
|
||||||
|
codegen_ssa_apple_deployment_target_too_low =
|
||||||
|
deployment target in {$env_var} was set to {$version}, but the minimum supported by `rustc` is {$os_min}
|
||||||
|
|
||||||
codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error}
|
codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error}
|
||||||
|
|
||||||
codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$error}
|
codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$error}
|
||||||
|
171
compiler/rustc_codegen_ssa/src/back/apple.rs
Normal file
171
compiler/rustc_codegen_ssa/src/back/apple.rs
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::fmt::{Display, from_fn};
|
||||||
|
use std::num::ParseIntError;
|
||||||
|
|
||||||
|
use rustc_session::Session;
|
||||||
|
use rustc_target::spec::Target;
|
||||||
|
|
||||||
|
use crate::errors::AppleDeploymentTarget;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
pub(super) fn macho_platform(target: &Target) -> u32 {
|
||||||
|
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,
|
||||||
|
("visionos", "sim") => object::macho::PLATFORM_XROSSIMULATOR,
|
||||||
|
("visionos", _) => object::macho::PLATFORM_XROS,
|
||||||
|
_ => unreachable!("tried to get Mach-O platform for non-Apple target"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deployment target or SDK version.
|
||||||
|
///
|
||||||
|
/// The size of the numbers in here are limited by Mach-O's `LC_BUILD_VERSION`.
|
||||||
|
type OSVersion = (u16, u8, u8);
|
||||||
|
|
||||||
|
/// Parse an OS version triple (SDK version or deployment target).
|
||||||
|
fn parse_version(version: &str) -> Result<OSVersion, 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_version(version: OSVersion) -> impl Display {
|
||||||
|
let (major, minor, patch) = version;
|
||||||
|
from_fn(move |f| {
|
||||||
|
write!(f, "{major}.{minor}")?;
|
||||||
|
if patch != 0 {
|
||||||
|
write!(f, ".{patch}")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Minimum operating system versions currently supported by `rustc`.
|
||||||
|
fn os_minimum_deployment_target(os: &str) -> OSVersion {
|
||||||
|
// When bumping a version in here, remember to update the platform-support docs too.
|
||||||
|
//
|
||||||
|
// NOTE: The defaults may change in future `rustc` versions, so if you are looking for the
|
||||||
|
// default deployment target, prefer:
|
||||||
|
// ```
|
||||||
|
// $ rustc --print deployment-target
|
||||||
|
// ```
|
||||||
|
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The deployment target for the given target.
|
||||||
|
///
|
||||||
|
/// This is similar to `os_minimum_deployment_target`, except that on certain targets it makes sense
|
||||||
|
/// to raise the minimum OS version.
|
||||||
|
///
|
||||||
|
/// This matches what LLVM does, see in part:
|
||||||
|
/// <https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L1900-L1932>
|
||||||
|
fn minimum_deployment_target(target: &Target) -> OSVersion {
|
||||||
|
match (&*target.os, &*target.arch, &*target.abi) {
|
||||||
|
("macos", "aarch64", _) => (11, 0, 0),
|
||||||
|
("ios", "aarch64", "macabi") => (14, 0, 0),
|
||||||
|
("ios", "aarch64", "sim") => (14, 0, 0),
|
||||||
|
("ios", _, _) if target.llvm_target.starts_with("arm64e") => (14, 0, 0),
|
||||||
|
// Mac Catalyst defaults to 13.1 in Clang.
|
||||||
|
("ios", _, "macabi") => (13, 1, 0),
|
||||||
|
("tvos", "aarch64", "sim") => (14, 0, 0),
|
||||||
|
("watchos", "aarch64", "sim") => (7, 0, 0),
|
||||||
|
(os, _, _) => os_minimum_deployment_target(os),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Name of the environment variable used to fetch the deployment target on the given OS.
|
||||||
|
fn deployment_target_env_var(os: &str) -> &'static str {
|
||||||
|
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the deployment target based on the standard environment variables, or fall back to the
|
||||||
|
/// minimum version supported by `rustc`.
|
||||||
|
pub fn deployment_target(sess: &Session) -> OSVersion {
|
||||||
|
let min = minimum_deployment_target(&sess.target);
|
||||||
|
let env_var = deployment_target_env_var(&sess.target.os);
|
||||||
|
|
||||||
|
if let Ok(deployment_target) = env::var(env_var) {
|
||||||
|
match parse_version(&deployment_target) {
|
||||||
|
Ok(version) => {
|
||||||
|
let os_min = os_minimum_deployment_target(&sess.target.os);
|
||||||
|
// It is common that the deployment target is set a bit too low, for example on
|
||||||
|
// macOS Aarch64 to also target older x86_64. So we only want to warn when variable
|
||||||
|
// is lower than the minimum OS supported by rustc, not when the variable is lower
|
||||||
|
// than the minimum for a specific target.
|
||||||
|
if version < os_min {
|
||||||
|
sess.dcx().emit_warn(AppleDeploymentTarget::TooLow {
|
||||||
|
env_var,
|
||||||
|
version: pretty_version(version).to_string(),
|
||||||
|
os_min: pretty_version(os_min).to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raise the deployment target to the minimum supported.
|
||||||
|
version.max(min)
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
sess.dcx().emit_err(AppleDeploymentTarget::Invalid { env_var, error });
|
||||||
|
min
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If no deployment target variable is set, default to the minimum found above.
|
||||||
|
min
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn add_version_to_llvm_target(
|
||||||
|
llvm_target: &str,
|
||||||
|
deployment_target: OSVersion,
|
||||||
|
) -> String {
|
||||||
|
let mut components = llvm_target.split("-");
|
||||||
|
let arch = components.next().expect("apple target should have arch");
|
||||||
|
let vendor = components.next().expect("apple target should have vendor");
|
||||||
|
let os = components.next().expect("apple target should have os");
|
||||||
|
let environment = components.next();
|
||||||
|
assert_eq!(components.next(), None, "too many LLVM triple components");
|
||||||
|
|
||||||
|
let (major, minor, patch) = deployment_target;
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
!os.contains(|c: char| c.is_ascii_digit()),
|
||||||
|
"LLVM target must not already be versioned"
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(env) = environment {
|
||||||
|
// Insert version into OS, before environment
|
||||||
|
format!("{arch}-{vendor}-{os}{major}.{minor}.{patch}-{env}")
|
||||||
|
} else {
|
||||||
|
format!("{arch}-{vendor}-{os}{major}.{minor}.{patch}")
|
||||||
|
}
|
||||||
|
}
|
21
compiler/rustc_codegen_ssa/src/back/apple/tests.rs
Normal file
21
compiler/rustc_codegen_ssa/src/back/apple/tests.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use super::{add_version_to_llvm_target, parse_version};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add_version_to_llvm_target() {
|
||||||
|
assert_eq!(
|
||||||
|
add_version_to_llvm_target("aarch64-apple-macosx", (10, 14, 1)),
|
||||||
|
"aarch64-apple-macosx10.14.1"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
add_version_to_llvm_target("aarch64-apple-ios-simulator", (16, 1, 0)),
|
||||||
|
"aarch64-apple-ios16.1.0-simulator"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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)));
|
||||||
|
}
|
@ -40,7 +40,7 @@ use rustc_target::spec::crt_objects::CrtObjects;
|
|||||||
use rustc_target::spec::{
|
use rustc_target::spec::{
|
||||||
Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures,
|
Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures,
|
||||||
LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, SanitizerSet,
|
LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, SanitizerSet,
|
||||||
SplitDebuginfo, current_apple_deployment_target,
|
SplitDebuginfo,
|
||||||
};
|
};
|
||||||
use tempfile::Builder as TempFileBuilder;
|
use tempfile::Builder as TempFileBuilder;
|
||||||
use tracing::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
@ -50,6 +50,7 @@ use super::command::Command;
|
|||||||
use super::linker::{self, Linker};
|
use super::linker::{self, Linker};
|
||||||
use super::metadata::{MetadataPosition, create_wrapper_file};
|
use super::metadata::{MetadataPosition, create_wrapper_file};
|
||||||
use super::rpath::{self, RPathConfig};
|
use super::rpath::{self, RPathConfig};
|
||||||
|
use super::{apple, versioned_llvm_target};
|
||||||
use crate::{
|
use crate::{
|
||||||
CodegenResults, CompiledModule, CrateInfo, NativeLib, common, errors,
|
CodegenResults, CompiledModule, CrateInfo, NativeLib, common, errors,
|
||||||
looks_like_rust_object_file,
|
looks_like_rust_object_file,
|
||||||
@ -2447,7 +2448,7 @@ fn add_order_independent_options(
|
|||||||
if flavor == LinkerFlavor::Llbc {
|
if flavor == LinkerFlavor::Llbc {
|
||||||
cmd.link_args(&[
|
cmd.link_args(&[
|
||||||
"--target",
|
"--target",
|
||||||
sess.target.llvm_target.as_ref(),
|
&versioned_llvm_target(sess),
|
||||||
"--target-cpu",
|
"--target-cpu",
|
||||||
&codegen_results.crate_info.target_cpu,
|
&codegen_results.crate_info.target_cpu,
|
||||||
]);
|
]);
|
||||||
@ -3039,7 +3040,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
|
|||||||
_ => bug!("invalid OS/ABI combination for Apple target: {target_os}, {target_abi}"),
|
_ => bug!("invalid OS/ABI combination for Apple target: {target_os}, {target_abi}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (major, minor, patch) = current_apple_deployment_target(&sess.target);
|
let (major, minor, patch) = apple::deployment_target(sess);
|
||||||
let min_version = format!("{major}.{minor}.{patch}");
|
let min_version = format!("{major}.{minor}.{patch}");
|
||||||
|
|
||||||
// The SDK version is used at runtime when compiling with a newer SDK / version of Xcode:
|
// The SDK version is used at runtime when compiling with a newer SDK / version of Xcode:
|
||||||
@ -3109,7 +3110,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
|
|||||||
|
|
||||||
// The presence of `-mmacosx-version-min` makes CC default to
|
// The presence of `-mmacosx-version-min` makes CC default to
|
||||||
// macOS, and it sets the deployment target.
|
// macOS, and it sets the deployment target.
|
||||||
let (major, minor, patch) = current_apple_deployment_target(&sess.target);
|
let (major, minor, patch) = apple::deployment_target(sess);
|
||||||
// Intentionally pass this as a single argument, Clang doesn't
|
// Intentionally pass this as a single argument, Clang doesn't
|
||||||
// seem to like it otherwise.
|
// seem to like it otherwise.
|
||||||
cmd.cc_arg(&format!("-mmacosx-version-min={major}.{minor}.{patch}"));
|
cmd.cc_arg(&format!("-mmacosx-version-min={major}.{minor}.{patch}"));
|
||||||
@ -3119,7 +3120,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
|
|||||||
//
|
//
|
||||||
// We avoid `-m32`/`-m64`, as this is already encoded by `-arch`.
|
// We avoid `-m32`/`-m64`, as this is already encoded by `-arch`.
|
||||||
} else {
|
} else {
|
||||||
cmd.cc_args(&["-target", &sess.target.llvm_target]);
|
cmd.cc_args(&["-target", &versioned_llvm_target(sess)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3345,7 +3346,7 @@ fn add_lld_args(
|
|||||||
// targeting a different linker flavor on macOS, and that's also always
|
// targeting a different linker flavor on macOS, and that's also always
|
||||||
// the case when targeting WASM.
|
// the case when targeting WASM.
|
||||||
if sess.target.linker_flavor != sess.host.linker_flavor {
|
if sess.target.linker_flavor != sess.host.linker_flavor {
|
||||||
cmd.cc_arg(format!("--target={}", sess.target.llvm_target));
|
cmd.cc_arg(format!("--target={}", versioned_llvm_target(sess)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,8 @@ use rustc_span::sym;
|
|||||||
use rustc_target::abi::Endian;
|
use rustc_target::abi::Endian;
|
||||||
use rustc_target::spec::{RelocModel, Target, ef_avr_arch};
|
use rustc_target::spec::{RelocModel, Target, ef_avr_arch};
|
||||||
|
|
||||||
|
use super::apple;
|
||||||
|
|
||||||
/// The default metadata loader. This is used by cg_llvm and cg_clif.
|
/// The default metadata loader. This is used by cg_llvm and cg_clif.
|
||||||
///
|
///
|
||||||
/// # Metadata location
|
/// # Metadata location
|
||||||
@ -238,7 +240,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
|||||||
file.set_macho_cpu_subtype(object::macho::CPU_SUBTYPE_ARM64E);
|
file.set_macho_cpu_subtype(object::macho::CPU_SUBTYPE_ARM64E);
|
||||||
}
|
}
|
||||||
|
|
||||||
file.set_macho_build_version(macho_object_build_version_for_target(&sess.target))
|
file.set_macho_build_version(macho_object_build_version_for_target(sess))
|
||||||
}
|
}
|
||||||
if binary_format == BinaryFormat::Coff {
|
if binary_format == BinaryFormat::Coff {
|
||||||
// Disable the default mangler to avoid mangling the special "@feat.00" symbol name.
|
// Disable the default mangler to avoid mangling the special "@feat.00" symbol name.
|
||||||
@ -392,7 +394,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
|||||||
///
|
///
|
||||||
/// Since Xcode 15, Apple's LD apparently requires object files to use this load command, so this
|
/// Since Xcode 15, Apple's LD apparently requires object files to use this load command, so this
|
||||||
/// returns the `MachOBuildVersion` for the target to do so.
|
/// returns the `MachOBuildVersion` for the target to do so.
|
||||||
fn macho_object_build_version_for_target(target: &Target) -> object::write::MachOBuildVersion {
|
fn macho_object_build_version_for_target(sess: &Session) -> object::write::MachOBuildVersion {
|
||||||
/// The `object` crate demands "X.Y.Z encoded in nibbles as xxxx.yy.zz"
|
/// The `object` crate demands "X.Y.Z encoded in nibbles as xxxx.yy.zz"
|
||||||
/// e.g. minOS 14.0 = 0x000E0000, or SDK 16.2 = 0x00100200
|
/// e.g. minOS 14.0 = 0x000E0000, or SDK 16.2 = 0x00100200
|
||||||
fn pack_version((major, minor, patch): (u16, u8, u8)) -> u32 {
|
fn pack_version((major, minor, patch): (u16, u8, u8)) -> u32 {
|
||||||
@ -400,9 +402,8 @@ fn macho_object_build_version_for_target(target: &Target) -> object::write::Mach
|
|||||||
(major << 16) | (minor << 8) | patch
|
(major << 16) | (minor << 8) | patch
|
||||||
}
|
}
|
||||||
|
|
||||||
let platform =
|
let platform = apple::macho_platform(&sess.target);
|
||||||
rustc_target::spec::current_apple_platform(target).expect("unknown Apple target OS");
|
let min_os = apple::deployment_target(sess);
|
||||||
let min_os = rustc_target::spec::current_apple_deployment_target(target);
|
|
||||||
|
|
||||||
let mut build_version = object::write::MachOBuildVersion::default();
|
let mut build_version = object::write::MachOBuildVersion::default();
|
||||||
build_version.platform = platform;
|
build_version.platform = platform;
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use rustc_session::Session;
|
||||||
|
|
||||||
|
pub mod apple;
|
||||||
pub mod archive;
|
pub mod archive;
|
||||||
pub(crate) mod command;
|
pub(crate) mod command;
|
||||||
pub mod link;
|
pub mod link;
|
||||||
@ -7,3 +12,19 @@ pub mod metadata;
|
|||||||
pub(crate) mod rpath;
|
pub(crate) mod rpath;
|
||||||
pub mod symbol_export;
|
pub mod symbol_export;
|
||||||
pub mod write;
|
pub mod write;
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
pub fn versioned_llvm_target(sess: &Session) -> Cow<'_, str> {
|
||||||
|
if sess.target.is_like_osx {
|
||||||
|
apple::add_version_to_llvm_target(&sess.target.llvm_target, apple::deployment_target(sess))
|
||||||
|
.into()
|
||||||
|
} else {
|
||||||
|
// FIXME(madsmtm): Certain other targets also include a version,
|
||||||
|
// we might want to move that here as well.
|
||||||
|
Cow::Borrowed(&sess.target.llvm_target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
|
use std::num::ParseIntError;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::ExitStatus;
|
use std::process::ExitStatus;
|
||||||
|
|
||||||
@ -539,6 +540,14 @@ pub(crate) struct UnsupportedArch<'a> {
|
|||||||
pub os: &'a str,
|
pub os: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
pub(crate) enum AppleDeploymentTarget {
|
||||||
|
#[diag(codegen_ssa_apple_deployment_target_invalid)]
|
||||||
|
Invalid { env_var: &'static str, error: ParseIntError },
|
||||||
|
#[diag(codegen_ssa_apple_deployment_target_too_low)]
|
||||||
|
TooLow { env_var: &'static str, version: String, os_min: String },
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
pub(crate) enum AppleSdkRootError<'a> {
|
pub(crate) enum AppleSdkRootError<'a> {
|
||||||
#[diag(codegen_ssa_apple_sdk_error_sdk_path)]
|
#[diag(codegen_ssa_apple_sdk_error_sdk_path)]
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#![doc(rust_logo)]
|
#![doc(rust_logo)]
|
||||||
#![feature(assert_matches)]
|
#![feature(assert_matches)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
#![feature(debug_closure_helpers)]
|
||||||
#![feature(file_buffered)]
|
#![feature(file_buffered)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
@ -33,6 +33,7 @@ use std::time::{Instant, SystemTime};
|
|||||||
use std::{env, str};
|
use std::{env, str};
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
|
use rustc_codegen_ssa::back::apple;
|
||||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||||
use rustc_codegen_ssa::{CodegenErrors, CodegenResults};
|
use rustc_codegen_ssa::{CodegenErrors, CodegenResults};
|
||||||
use rustc_data_structures::profiling::{
|
use rustc_data_structures::profiling::{
|
||||||
@ -855,12 +856,11 @@ fn print_crate_info(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
DeploymentTarget => {
|
DeploymentTarget => {
|
||||||
use rustc_target::spec::current_apple_deployment_target;
|
|
||||||
|
|
||||||
if sess.target.is_like_osx {
|
if sess.target.is_like_osx {
|
||||||
let (major, minor, patch) = current_apple_deployment_target(&sess.target);
|
println_info!(
|
||||||
let patch = if patch != 0 { format!(".{patch}") } else { String::new() };
|
"deployment_target={}",
|
||||||
println_info!("deployment_target={major}.{minor}{patch}")
|
apple::pretty_version(apple::deployment_target(sess))
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
sess.dcx().fatal("only Apple targets currently support deployment version info")
|
sess.dcx().fatal("only Apple targets currently support deployment version info")
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::num::ParseIntError;
|
|
||||||
|
|
||||||
use crate::spec::{
|
use crate::spec::{
|
||||||
Cc, DebuginfoKind, FramePointer, LinkerFlavor, Lld, SplitDebuginfo, StackProbeType, StaticCow,
|
Cc, DebuginfoKind, FramePointer, LinkerFlavor, Lld, SplitDebuginfo, StackProbeType, StaticCow,
|
||||||
Target, TargetOptions, cvs,
|
TargetOptions, cvs,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -97,9 +96,8 @@ impl TargetAbi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the base target options, LLVM target and `target_arch` from the three
|
/// 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
|
/// things that uniquely identify Rust's Apple targets: The OS, the architecture, and the ABI.
|
||||||
/// architecture, and the ABI.
|
|
||||||
pub(crate) fn base(
|
pub(crate) fn base(
|
||||||
os: &'static str,
|
os: &'static str,
|
||||||
arch: Arch,
|
arch: Arch,
|
||||||
@ -155,117 +153,14 @@ pub(crate) fn base(
|
|||||||
|
|
||||||
..Default::default()
|
..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> {
|
/// Generate part of the LLVM target triple.
|
||||||
Some(match (&*target.os, &*target.abi) {
|
///
|
||||||
("macos", _) => object::macho::PLATFORM_MACOS,
|
/// See `rustc_codegen_ssa::back::versioned_llvm_target` for the full triple passed to LLVM and
|
||||||
("ios", "macabi") => object::macho::PLATFORM_MACCATALYST,
|
/// Clang.
|
||||||
("ios", "sim") => object::macho::PLATFORM_IOSSIMULATOR,
|
fn unversioned_llvm_target(os: &str, arch: Arch, abi: TargetAbi) -> StaticCow<str> {
|
||||||
("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);
|
|
||||||
let arch = arch.target_name();
|
let arch = arch.target_name();
|
||||||
// Convert to the "canonical" OS name used by LLVM:
|
// 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
|
// 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::MacCatalyst => "-macabi",
|
||||||
TargetAbi::Simulator => "-simulator",
|
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>]> {
|
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"]
|
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use super::parse_version;
|
|
||||||
use crate::spec::targets::{
|
use crate::spec::targets::{
|
||||||
aarch64_apple_darwin, aarch64_apple_ios_sim, aarch64_apple_visionos_sim,
|
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,
|
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)));
|
|
||||||
}
|
|
||||||
|
@ -65,10 +65,6 @@ pub mod abi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod base;
|
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;
|
pub use base::avr_gnu::ef_avr_arch;
|
||||||
|
|
||||||
/// Linker is called through a C/C++ compiler.
|
/// 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.
|
/// Every field here must be specified, and has no default value.
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub struct Target {
|
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>,
|
pub llvm_target: StaticCow<str>,
|
||||||
/// Metadata about a target, for example the description or tier.
|
/// Metadata about a target, for example the description or tier.
|
||||||
/// Used for generating target documentation.
|
/// Used for generating target documentation.
|
||||||
|
Loading…
Reference in New Issue
Block a user