From d37fdc95d4558460f09e40e12ec83a0fc1779702 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 26 Jul 2023 20:18:03 -0700 Subject: [PATCH 1/3] Always add LC_BUILD_VERSION for metadata object files As of Xcode 15 Apple's linker has become a bit more strict about the warnings it produces. One of those new warnings requires all valid Mach-O object files in an archive to have a LC_BUILD_VERSION load command: ``` ld: warning: no platform load command found in 'ARCHIVE[arm64][2106](lib.rmeta)', assuming: iOS-simulator ``` This was already being done for Mac Catalyst so this change expands this logic to include it for all Apple platforms. I filed this behavior change as FB12546320 and was told it was the new intentional behavior. --- .../rustc_codegen_ssa/src/back/metadata.rs | 29 ++++------ compiler/rustc_driver_impl/src/lib.rs | 8 +-- compiler/rustc_target/src/spec/apple_base.rs | 57 ++++++++++++++++++- compiler/rustc_target/src/spec/mod.rs | 2 + 4 files changed, 71 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 4c8547407531d..c6f4bd35e293f 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -226,9 +226,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option { @@ -334,31 +332,28 @@ pub(crate) fn create_object_file(sess: &Session) -> Option Option { - if !target.llvm_target.ends_with("-macabi") { - return None; - } +/// Since Xcode 15 Apple's LD requires object files to contain information about what they were +/// built for (LC_BUILD_VERSION): the platform (macOS/watchOS etc), minimum OS version, and SDK +/// version. This returns a `MachOBuildVersion` for the target. +fn macho_object_build_version_for_target(target: &Target) -> object::write::MachOBuildVersion { /// 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 fn pack_version((major, minor): (u32, u32)) -> u32 { (major << 16) | (minor << 8) } - let platform = object::macho::PLATFORM_MACCATALYST; - let min_os = (14, 0); - let sdk = (16, 2); + let platform = + rustc_target::spec::current_apple_platform(target).expect("unknown Apple target OS"); + let min_os = rustc_target::spec::current_apple_deployment_target(target) + .expect("unknown Apple target OS"); + let sdk = + rustc_target::spec::current_apple_sdk_version(platform).expect("unknown Apple target OS"); let mut build_version = object::write::MachOBuildVersion::default(); build_version.platform = platform; build_version.minos = pack_version(min_os); build_version.sdk = pack_version(sdk); - Some(build_version) + build_version } pub enum MetadataPosition { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 7bbed0877f07b..4df4cc7a71c99 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -858,11 +858,9 @@ fn print_crate_info( use rustc_target::spec::current_apple_deployment_target; if sess.target.is_like_osx { - println_info!( - "deployment_target={}", - current_apple_deployment_target(&sess.target) - .expect("unknown Apple target OS") - ) + let (major, minor) = current_apple_deployment_target(&sess.target) + .expect("unknown Apple target OS"); + println_info!("deployment_target={}", format!("{major}.{minor}")) } else { handler .early_error("only Apple targets currently support deployment version info") diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index 8a8d1ab95e81e..e4df6a578a4b3 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -179,20 +179,66 @@ pub fn opts(os: &'static str, arch: Arch) -> TargetOptions { } } -pub fn deployment_target(target: &Target) -> Option { +pub fn sdk_version(platform: u32) -> Option<(u32, u32)> { + match platform { + object::macho::PLATFORM_MACOS => Some((13, 1)), + object::macho::PLATFORM_IOS + | object::macho::PLATFORM_IOSSIMULATOR + | object::macho::PLATFORM_TVOS + | object::macho::PLATFORM_TVOSSIMULATOR + | object::macho::PLATFORM_MACCATALYST => Some((16, 2)), + object::macho::PLATFORM_WATCHOS | object::macho::PLATFORM_WATCHOSSIMULATOR => Some((9, 1)), + _ => None, + } +} + +pub fn platform(target: &Target) -> Option { + Some(match &*target.os { + "macos" => object::macho::PLATFORM_MACOS, + "ios" => { + if target.llvm_target.ends_with("-macabi") { + object::macho::PLATFORM_MACCATALYST + } else if target.llvm_target.ends_with("-simulator") { + object::macho::PLATFORM_IOSSIMULATOR + } else { + object::macho::PLATFORM_IOS + } + } + "watchos" => { + if target.llvm_target.ends_with("-simulator") { + object::macho::PLATFORM_WATCHOSSIMULATOR + } else { + object::macho::PLATFORM_WATCHOS + } + } + "tvos" => { + if target.llvm_target.ends_with("-simulator") { + object::macho::PLATFORM_TVOSSIMULATOR + } else { + object::macho::PLATFORM_TVOS + } + } + _ => return None, + }) +} + +pub fn deployment_target(target: &Target) -> Option<(u32, u32)> { let (major, minor) = match &*target.os { "macos" => { // This does not need to be specific. It just needs to handle x86 vs M1. let arch = if target.arch == "x86" || target.arch == "x86_64" { X86_64 } else { Arm64 }; macos_deployment_target(arch) } - "ios" => ios_deployment_target(), + "ios" => match &*target.options.abi { + "macabi" => mac_catalyst_deployment_target(), + _ => ios_deployment_target(), + }, "watchos" => watchos_deployment_target(), "tvos" => tvos_deployment_target(), _ => return None, }; - Some(format!("{major}.{minor}")) + Some((major, minor)) } fn from_set_deployment_target(var_name: &str) -> Option<(u32, u32)> { @@ -274,6 +320,11 @@ fn ios_deployment_target() -> (u32, u32) { from_set_deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0)) } +fn mac_catalyst_deployment_target() -> (u32, u32) { + // If you are looking for the default deployment target, prefer `rustc --print deployment-target`. + from_set_deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((14, 0)) +} + pub fn ios_llvm_target(arch: Arch) -> String { // Modern iOS tooling extracts information about deployment target // from LC_BUILD_VERSION. This load command will only be emitted when diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 31b6961bb6220..856967ebefe4a 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -61,6 +61,8 @@ mod aix_base; mod android_base; mod apple_base; pub use apple_base::deployment_target as current_apple_deployment_target; +pub use apple_base::platform as current_apple_platform; +pub use apple_base::sdk_version as current_apple_sdk_version; mod avr_gnu_base; pub use avr_gnu_base::ef_avr_arch; mod bpf_base; From f988cbb06515bf7daeb5ce3d7b11a57fe94bb0d3 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 21 Aug 2023 13:32:14 -0700 Subject: [PATCH 2/3] Use target.abi instead of string matching llvm_target --- compiler/rustc_target/src/spec/apple_base.rs | 36 ++++++-------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index e4df6a578a4b3..73ae0666fe805 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -193,31 +193,15 @@ pub fn sdk_version(platform: u32) -> Option<(u32, u32)> { } pub fn platform(target: &Target) -> Option { - Some(match &*target.os { - "macos" => object::macho::PLATFORM_MACOS, - "ios" => { - if target.llvm_target.ends_with("-macabi") { - object::macho::PLATFORM_MACCATALYST - } else if target.llvm_target.ends_with("-simulator") { - object::macho::PLATFORM_IOSSIMULATOR - } else { - object::macho::PLATFORM_IOS - } - } - "watchos" => { - if target.llvm_target.ends_with("-simulator") { - object::macho::PLATFORM_WATCHOSSIMULATOR - } else { - object::macho::PLATFORM_WATCHOS - } - } - "tvos" => { - if target.llvm_target.ends_with("-simulator") { - object::macho::PLATFORM_TVOSSIMULATOR - } else { - object::macho::PLATFORM_TVOS - } - } + 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, _ => return None, }) } @@ -229,7 +213,7 @@ pub fn deployment_target(target: &Target) -> Option<(u32, u32)> { let arch = if target.arch == "x86" || target.arch == "x86_64" { X86_64 } else { Arm64 }; macos_deployment_target(arch) } - "ios" => match &*target.options.abi { + "ios" => match &*target.abi { "macabi" => mac_catalyst_deployment_target(), _ => ios_deployment_target(), }, From 2939e8534aabcf5777a648a3d1c3d68953fdfa44 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 22 Aug 2023 08:55:41 -0700 Subject: [PATCH 3/3] Add comment about unused sdk versions --- compiler/rustc_target/src/spec/apple_base.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index 73ae0666fe805..f7dcec307ddd0 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -180,6 +180,8 @@ pub fn opts(os: &'static str, arch: Arch) -> TargetOptions { } pub fn sdk_version(platform: u32) -> Option<(u32, u32)> { + // NOTE: These values are from an arbitrary point in time but shouldn't make it into the final + // binary since the final link command will have the current SDK version passed to it. match platform { object::macho::PLATFORM_MACOS => Some((13, 1)), object::macho::PLATFORM_IOS