Skip to content

Commit d37fdc9

Browse files
committed
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.
1 parent fe5f591 commit d37fdc9

File tree

4 files changed

+71
-25
lines changed

4 files changed

+71
-25
lines changed

compiler/rustc_codegen_ssa/src/back/metadata.rs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
226226

227227
let mut file = write::Object::new(binary_format, architecture, endianness);
228228
if sess.target.is_like_osx {
229-
if let Some(build_version) = macho_object_build_version_for_target(&sess.target) {
230-
file.set_macho_build_version(build_version)
231-
}
229+
file.set_macho_build_version(macho_object_build_version_for_target(&sess.target))
232230
}
233231
let e_flags = match architecture {
234232
Architecture::Mips => {
@@ -334,31 +332,28 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
334332
Some(file)
335333
}
336334

337-
/// Apple's LD, when linking for Mac Catalyst, requires object files to
338-
/// contain information about what they were built for (LC_BUILD_VERSION):
339-
/// the platform (macOS/watchOS etc), minimum OS version, and SDK version.
340-
/// This returns a `MachOBuildVersion` if necessary for the target.
341-
fn macho_object_build_version_for_target(
342-
target: &Target,
343-
) -> Option<object::write::MachOBuildVersion> {
344-
if !target.llvm_target.ends_with("-macabi") {
345-
return None;
346-
}
335+
/// Since Xcode 15 Apple's LD requires object files to contain information about what they were
336+
/// built for (LC_BUILD_VERSION): the platform (macOS/watchOS etc), minimum OS version, and SDK
337+
/// version. This returns a `MachOBuildVersion` for the target.
338+
fn macho_object_build_version_for_target(target: &Target) -> object::write::MachOBuildVersion {
347339
/// The `object` crate demands "X.Y.Z encoded in nibbles as xxxx.yy.zz"
348340
/// e.g. minOS 14.0 = 0x000E0000, or SDK 16.2 = 0x00100200
349341
fn pack_version((major, minor): (u32, u32)) -> u32 {
350342
(major << 16) | (minor << 8)
351343
}
352344

353-
let platform = object::macho::PLATFORM_MACCATALYST;
354-
let min_os = (14, 0);
355-
let sdk = (16, 2);
345+
let platform =
346+
rustc_target::spec::current_apple_platform(target).expect("unknown Apple target OS");
347+
let min_os = rustc_target::spec::current_apple_deployment_target(target)
348+
.expect("unknown Apple target OS");
349+
let sdk =
350+
rustc_target::spec::current_apple_sdk_version(platform).expect("unknown Apple target OS");
356351

357352
let mut build_version = object::write::MachOBuildVersion::default();
358353
build_version.platform = platform;
359354
build_version.minos = pack_version(min_os);
360355
build_version.sdk = pack_version(sdk);
361-
Some(build_version)
356+
build_version
362357
}
363358

364359
pub enum MetadataPosition {

compiler/rustc_driver_impl/src/lib.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -858,11 +858,9 @@ fn print_crate_info(
858858
use rustc_target::spec::current_apple_deployment_target;
859859

860860
if sess.target.is_like_osx {
861-
println_info!(
862-
"deployment_target={}",
863-
current_apple_deployment_target(&sess.target)
864-
.expect("unknown Apple target OS")
865-
)
861+
let (major, minor) = current_apple_deployment_target(&sess.target)
862+
.expect("unknown Apple target OS");
863+
println_info!("deployment_target={}", format!("{major}.{minor}"))
866864
} else {
867865
handler
868866
.early_error("only Apple targets currently support deployment version info")

compiler/rustc_target/src/spec/apple_base.rs

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,20 +179,66 @@ pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
179179
}
180180
}
181181

182-
pub fn deployment_target(target: &Target) -> Option<String> {
182+
pub fn sdk_version(platform: u32) -> Option<(u32, u32)> {
183+
match platform {
184+
object::macho::PLATFORM_MACOS => Some((13, 1)),
185+
object::macho::PLATFORM_IOS
186+
| object::macho::PLATFORM_IOSSIMULATOR
187+
| object::macho::PLATFORM_TVOS
188+
| object::macho::PLATFORM_TVOSSIMULATOR
189+
| object::macho::PLATFORM_MACCATALYST => Some((16, 2)),
190+
object::macho::PLATFORM_WATCHOS | object::macho::PLATFORM_WATCHOSSIMULATOR => Some((9, 1)),
191+
_ => None,
192+
}
193+
}
194+
195+
pub fn platform(target: &Target) -> Option<u32> {
196+
Some(match &*target.os {
197+
"macos" => object::macho::PLATFORM_MACOS,
198+
"ios" => {
199+
if target.llvm_target.ends_with("-macabi") {
200+
object::macho::PLATFORM_MACCATALYST
201+
} else if target.llvm_target.ends_with("-simulator") {
202+
object::macho::PLATFORM_IOSSIMULATOR
203+
} else {
204+
object::macho::PLATFORM_IOS
205+
}
206+
}
207+
"watchos" => {
208+
if target.llvm_target.ends_with("-simulator") {
209+
object::macho::PLATFORM_WATCHOSSIMULATOR
210+
} else {
211+
object::macho::PLATFORM_WATCHOS
212+
}
213+
}
214+
"tvos" => {
215+
if target.llvm_target.ends_with("-simulator") {
216+
object::macho::PLATFORM_TVOSSIMULATOR
217+
} else {
218+
object::macho::PLATFORM_TVOS
219+
}
220+
}
221+
_ => return None,
222+
})
223+
}
224+
225+
pub fn deployment_target(target: &Target) -> Option<(u32, u32)> {
183226
let (major, minor) = match &*target.os {
184227
"macos" => {
185228
// This does not need to be specific. It just needs to handle x86 vs M1.
186229
let arch = if target.arch == "x86" || target.arch == "x86_64" { X86_64 } else { Arm64 };
187230
macos_deployment_target(arch)
188231
}
189-
"ios" => ios_deployment_target(),
232+
"ios" => match &*target.options.abi {
233+
"macabi" => mac_catalyst_deployment_target(),
234+
_ => ios_deployment_target(),
235+
},
190236
"watchos" => watchos_deployment_target(),
191237
"tvos" => tvos_deployment_target(),
192238
_ => return None,
193239
};
194240

195-
Some(format!("{major}.{minor}"))
241+
Some((major, minor))
196242
}
197243

198244
fn from_set_deployment_target(var_name: &str) -> Option<(u32, u32)> {
@@ -274,6 +320,11 @@ fn ios_deployment_target() -> (u32, u32) {
274320
from_set_deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
275321
}
276322

323+
fn mac_catalyst_deployment_target() -> (u32, u32) {
324+
// If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
325+
from_set_deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((14, 0))
326+
}
327+
277328
pub fn ios_llvm_target(arch: Arch) -> String {
278329
// Modern iOS tooling extracts information about deployment target
279330
// from LC_BUILD_VERSION. This load command will only be emitted when

compiler/rustc_target/src/spec/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ mod aix_base;
6161
mod android_base;
6262
mod apple_base;
6363
pub use apple_base::deployment_target as current_apple_deployment_target;
64+
pub use apple_base::platform as current_apple_platform;
65+
pub use apple_base::sdk_version as current_apple_sdk_version;
6466
mod avr_gnu_base;
6567
pub use avr_gnu_base::ef_avr_arch;
6668
mod bpf_base;

0 commit comments

Comments
 (0)