Auto merge of #114114 - keith:ks/always-add-lc_build_version-for-metadata-object-files, r=wesleywiser
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.
This commit is contained in:
commit
84a9f4c6e6
4 changed files with 57 additions and 25 deletions
|
@ -226,9 +226,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
||||||
|
|
||||||
let mut file = write::Object::new(binary_format, architecture, endianness);
|
let mut file = write::Object::new(binary_format, architecture, endianness);
|
||||||
if sess.target.is_like_osx {
|
if sess.target.is_like_osx {
|
||||||
if let Some(build_version) = macho_object_build_version_for_target(&sess.target) {
|
file.set_macho_build_version(macho_object_build_version_for_target(&sess.target))
|
||||||
file.set_macho_build_version(build_version)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let e_flags = match architecture {
|
let e_flags = match architecture {
|
||||||
Architecture::Mips => {
|
Architecture::Mips => {
|
||||||
|
@ -334,31 +332,28 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
||||||
Some(file)
|
Some(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apple's LD, when linking for Mac Catalyst, requires object files to
|
/// Since Xcode 15 Apple's LD requires object files to contain information about what they were
|
||||||
/// contain information about what they were built for (LC_BUILD_VERSION):
|
/// built for (LC_BUILD_VERSION): the platform (macOS/watchOS etc), minimum OS version, and SDK
|
||||||
/// the platform (macOS/watchOS etc), minimum OS version, and SDK version.
|
/// version. This returns a `MachOBuildVersion` for the target.
|
||||||
/// This returns a `MachOBuildVersion` if necessary for the target.
|
fn macho_object_build_version_for_target(target: &Target) -> object::write::MachOBuildVersion {
|
||||||
fn macho_object_build_version_for_target(
|
|
||||||
target: &Target,
|
|
||||||
) -> Option<object::write::MachOBuildVersion> {
|
|
||||||
if !target.llvm_target.ends_with("-macabi") {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
/// 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): (u32, u32)) -> u32 {
|
fn pack_version((major, minor): (u32, u32)) -> u32 {
|
||||||
(major << 16) | (minor << 8)
|
(major << 16) | (minor << 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
let platform = object::macho::PLATFORM_MACCATALYST;
|
let platform =
|
||||||
let min_os = (14, 0);
|
rustc_target::spec::current_apple_platform(target).expect("unknown Apple target OS");
|
||||||
let sdk = (16, 2);
|
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();
|
let mut build_version = object::write::MachOBuildVersion::default();
|
||||||
build_version.platform = platform;
|
build_version.platform = platform;
|
||||||
build_version.minos = pack_version(min_os);
|
build_version.minos = pack_version(min_os);
|
||||||
build_version.sdk = pack_version(sdk);
|
build_version.sdk = pack_version(sdk);
|
||||||
Some(build_version)
|
build_version
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum MetadataPosition {
|
pub enum MetadataPosition {
|
||||||
|
|
|
@ -852,11 +852,9 @@ fn print_crate_info(
|
||||||
use rustc_target::spec::current_apple_deployment_target;
|
use rustc_target::spec::current_apple_deployment_target;
|
||||||
|
|
||||||
if sess.target.is_like_osx {
|
if sess.target.is_like_osx {
|
||||||
println_info!(
|
let (major, minor) = current_apple_deployment_target(&sess.target)
|
||||||
"deployment_target={}",
|
.expect("unknown Apple target OS");
|
||||||
current_apple_deployment_target(&sess.target)
|
println_info!("deployment_target={}", format!("{major}.{minor}"))
|
||||||
.expect("unknown Apple target OS")
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
handler
|
handler
|
||||||
.early_error("only Apple targets currently support deployment version info")
|
.early_error("only Apple targets currently support deployment version info")
|
||||||
|
|
|
@ -179,20 +179,52 @@ pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deployment_target(target: &Target) -> Option<String> {
|
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
|
||||||
|
| 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<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,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deployment_target(target: &Target) -> Option<(u32, u32)> {
|
||||||
let (major, minor) = match &*target.os {
|
let (major, minor) = match &*target.os {
|
||||||
"macos" => {
|
"macos" => {
|
||||||
// This does not need to be specific. It just needs to handle x86 vs M1.
|
// 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 };
|
let arch = if target.arch == "x86" || target.arch == "x86_64" { X86_64 } else { Arm64 };
|
||||||
macos_deployment_target(arch)
|
macos_deployment_target(arch)
|
||||||
}
|
}
|
||||||
"ios" => ios_deployment_target(),
|
"ios" => match &*target.abi {
|
||||||
|
"macabi" => mac_catalyst_deployment_target(),
|
||||||
|
_ => ios_deployment_target(),
|
||||||
|
},
|
||||||
"watchos" => watchos_deployment_target(),
|
"watchos" => watchos_deployment_target(),
|
||||||
"tvos" => tvos_deployment_target(),
|
"tvos" => tvos_deployment_target(),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(format!("{major}.{minor}"))
|
Some((major, minor))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_set_deployment_target(var_name: &str) -> Option<(u32, u32)> {
|
fn from_set_deployment_target(var_name: &str) -> Option<(u32, u32)> {
|
||||||
|
@ -274,6 +306,11 @@ fn ios_deployment_target() -> (u32, u32) {
|
||||||
from_set_deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
|
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 {
|
pub fn ios_llvm_target(arch: Arch) -> String {
|
||||||
// Modern iOS tooling extracts information about deployment target
|
// Modern iOS tooling extracts information about deployment target
|
||||||
// from LC_BUILD_VERSION. This load command will only be emitted when
|
// from LC_BUILD_VERSION. This load command will only be emitted when
|
||||||
|
|
|
@ -61,6 +61,8 @@ mod aix_base;
|
||||||
mod android_base;
|
mod android_base;
|
||||||
mod apple_base;
|
mod apple_base;
|
||||||
pub use apple_base::deployment_target as current_apple_deployment_target;
|
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;
|
mod avr_gnu_base;
|
||||||
pub use avr_gnu_base::ef_avr_arch;
|
pub use avr_gnu_base::ef_avr_arch;
|
||||||
mod bpf_base;
|
mod bpf_base;
|
||||||
|
|
Loading…
Add table
Reference in a new issue