|
1 | 1 | use std::borrow::Cow; |
2 | 2 | use std::env; |
| 3 | +use std::num::ParseIntError; |
3 | 4 |
|
4 | 5 | usecrate::spec::{ |
5 | 6 | add_link_args, add_link_args_iter, cvs,Cc,DebuginfoKind,FramePointer,LinkArgs, |
@@ -123,15 +124,8 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: TargetAbi) -> LinkArgs { |
123 | 124 | }; |
124 | 125 |
|
125 | 126 | let min_version:StaticCow<str> = { |
126 | | -let(major, minor) = match os { |
127 | | -"ios" => ios_deployment_target(arch, abi.target_abi()), |
128 | | -"tvos" => tvos_deployment_target(), |
129 | | -"watchos" => watchos_deployment_target(), |
130 | | -"visionos" => visionos_deployment_target(), |
131 | | -"macos" => macos_deployment_target(arch), |
132 | | - _ => unreachable!(), |
133 | | -}; |
134 | | -format!("{major}.{minor}").into() |
| 127 | +let(major, minor, patch) = deployment_target(os, arch, abi); |
| 128 | +format!("{major}.{minor}.{patch}").into() |
135 | 129 | }; |
136 | 130 | let sdk_version = min_version.clone(); |
137 | 131 |
|
@@ -163,15 +157,22 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: TargetAbi) -> LinkArgs { |
163 | 157 | add_link_args_iter( |
164 | 158 | &mut args, |
165 | 159 | LinkerFlavor::Darwin(Cc::Yes,Lld::No), |
166 | | -["-target".into(),mac_catalyst_llvm_target(arch).into()].into_iter(), |
| 160 | +["-target".into(),llvm_target(os,arch, abi)].into_iter(), |
167 | 161 | ); |
168 | 162 | } |
169 | 163 |
|
170 | 164 | args |
171 | 165 | } |
172 | 166 |
|
173 | | -pub(crate)fnopts(os:&'staticstr,arch:Arch,abi:TargetAbi) -> TargetOptions{ |
174 | | -TargetOptions{ |
| 167 | +/// Get the base target options, LLVM target and `target_arch` from the three |
| 168 | +/// things that uniquely identify Rust's Apple targets: The OS, the |
| 169 | +/// architecture, and the ABI. |
| 170 | +pub(crate)fnbase( |
| 171 | +os:&'staticstr, |
| 172 | +arch:Arch, |
| 173 | +abi:TargetAbi, |
| 174 | +) -> (TargetOptions,StaticCow<str>,StaticCow<str>){ |
| 175 | +let opts = TargetOptions{ |
175 | 176 | abi: abi.target_abi().into(), |
176 | 177 | os: os.into(), |
177 | 178 | cpu: arch.target_cpu(abi).into(), |
@@ -221,10 +222,11 @@ pub(crate) fn opts(os: &'static str, arch: Arch, abi: TargetAbi) -> TargetOption |
221 | 222 | link_env:Cow::Borrowed(&[(Cow::Borrowed("ZERO_AR_DATE"),Cow::Borrowed("1"))]), |
222 | 223 |
|
223 | 224 | ..Default::default() |
224 | | -} |
| 225 | +}; |
| 226 | +(opts,llvm_target(os, arch, abi), arch.target_arch()) |
225 | 227 | } |
226 | 228 |
|
227 | | -pubfnsdk_version(platform:u32) -> Option<(u32,u32)>{ |
| 229 | +pubfnsdk_version(platform:u32) -> Option<(u16,u8)>{ |
228 | 230 | // NOTE: These values are from an arbitrary point in time but shouldn't make it into the final |
229 | 231 | // binary since the final link command will have the current SDK version passed to it. |
230 | 232 | match platform { |
@@ -258,58 +260,108 @@ pub fn platform(target: &Target) -> Option<u32> { |
258 | 260 | }) |
259 | 261 | } |
260 | 262 |
|
261 | | -pubfndeployment_target(target:&Target) -> Option<(u32,u32)>{ |
262 | | -let(major, minor) = match&*target.os{ |
263 | | -"macos" => { |
264 | | -// This does not need to be specific. It just needs to handle x86 vs M1. |
265 | | -let arch = match target.arch.as_ref(){ |
266 | | -"x86" | "x86_64" => X86_64, |
267 | | -"arm64e" => Arm64e, |
268 | | - _ => Arm64, |
269 | | -}; |
270 | | -macos_deployment_target(arch) |
271 | | -} |
272 | | -"ios" => { |
273 | | -let arch = match target.arch.as_ref(){ |
274 | | -"arm64e" => Arm64e, |
275 | | - _ => Arm64, |
276 | | -}; |
277 | | -ios_deployment_target(arch,&target.abi) |
278 | | -} |
279 | | -"watchos" => watchos_deployment_target(), |
280 | | -"tvos" => tvos_deployment_target(), |
281 | | -"visionos" => visionos_deployment_target(), |
282 | | - _ => returnNone, |
| 263 | +/// Hack for calling `deployment_target` outside of this module. |
| 264 | +pubfndeployment_target_for_target(target:&Target) -> (u16,u8,u8){ |
| 265 | +let arch = if target.llvm_target.starts_with("arm64e"){ |
| 266 | +Arch::Arm64e |
| 267 | +}elseif target.arch == "aarch64"{ |
| 268 | +Arch::Arm64 |
| 269 | +}else{ |
| 270 | +// Dummy architecture, only used by `deployment_target` anyhow |
| 271 | +Arch::X86_64 |
283 | 272 | }; |
284 | | - |
285 | | -Some((major, minor)) |
| 273 | +let abi = match&*target.abi{ |
| 274 | +"macabi" => TargetAbi::MacCatalyst, |
| 275 | +"sim" => TargetAbi::Simulator, |
| 276 | +"" => TargetAbi::Normal, |
| 277 | + abi => unreachable!("invalid abi '{abi}' for Apple target"), |
| 278 | +}; |
| 279 | +deployment_target(&target.os, arch, abi) |
286 | 280 | } |
287 | 281 |
|
288 | | -fnfrom_set_deployment_target(var_name:&str) -> Option<(u32,u32)>{ |
289 | | -let deployment_target = env::var(var_name).ok()?; |
290 | | -let(unparsed_major, unparsed_minor) = deployment_target.split_once('.')?; |
291 | | -let(major, minor) = (unparsed_major.parse().ok()?, unparsed_minor.parse().ok()?); |
| 282 | +/// Get the deployment target based on the standard environment variables, or |
| 283 | +/// fall back to a sane default. |
| 284 | +fndeployment_target(os:&str,arch:Arch,abi:TargetAbi) -> (u16,u8,u8){ |
| 285 | +// When bumping a version in here, remember to update the platform-support |
| 286 | +// docs too. |
| 287 | +// |
| 288 | +// NOTE: If you are looking for the default deployment target, prefer |
| 289 | +// `rustc --print deployment-target`, as the default here may change in |
| 290 | +// future `rustc` versions. |
| 291 | + |
| 292 | +// Minimum operating system versions currently supported by `rustc`. |
| 293 | +let os_min = match os { |
| 294 | +"macos" => (10,12,0), |
| 295 | +"ios" => (10,0,0), |
| 296 | +"tvos" => (10,0,0), |
| 297 | +"watchos" => (5,0,0), |
| 298 | +"visionos" => (1,0,0), |
| 299 | + _ => unreachable!("tried to get deployment target for non-Apple platform"), |
| 300 | +}; |
292 | 301 |
|
293 | | -Some((major, minor)) |
294 | | -} |
| 302 | +// On certain targets it makes sense to raise the minimum OS version. |
| 303 | +let min = match(os, arch, abi){ |
| 304 | +// Use 11.0 on Aarch64 as that's the earliest version with M1 support. |
| 305 | +("macos",Arch::Arm64 | Arch::Arm64e, _) => (11,0,0), |
| 306 | +("ios",Arch::Arm64e, _) => (14,0,0), |
| 307 | +// Mac Catalyst defaults to 13.1 in Clang. |
| 308 | +("ios", _,TargetAbi::MacCatalyst) => (13,1,0), |
| 309 | + _ => os_min, |
| 310 | +}; |
295 | 311 |
|
296 | | -fnmacos_default_deployment_target(arch:Arch) -> (u32,u32){ |
297 | | -match arch { |
298 | | -Arm64 | Arm64e => (11,0), |
299 | | - _ => (10,12), |
300 | | -} |
301 | | -} |
| 312 | +// The environment variable used to fetch the deployment target. |
| 313 | +let env_var = match os { |
| 314 | +"macos" => "MACOSX_DEPLOYMENT_TARGET", |
| 315 | +"ios" => "IPHONEOS_DEPLOYMENT_TARGET", |
| 316 | +"watchos" => "WATCHOS_DEPLOYMENT_TARGET", |
| 317 | +"tvos" => "TVOS_DEPLOYMENT_TARGET", |
| 318 | +"visionos" => "XROS_DEPLOYMENT_TARGET", |
| 319 | + _ => unreachable!("tried to get deployment target env var for non-Apple platform"), |
| 320 | +}; |
302 | 321 |
|
303 | | -fnmacos_deployment_target(arch:Arch) -> (u32,u32){ |
304 | | -// If you are looking for the default deployment target, prefer `rustc --print deployment-target`. |
305 | | -// Note: If bumping this version, remember to update it in the rustc/platform-support docs. |
306 | | -from_set_deployment_target("MACOSX_DEPLOYMENT_TARGET") |
307 | | -.unwrap_or_else(|| macos_default_deployment_target(arch)) |
| 322 | +ifletOk(deployment_target) = env::var(env_var){ |
| 323 | +matchparse_version(&deployment_target){ |
| 324 | +// It is common that the deployment target is set too low, e.g. on |
| 325 | +// macOS Aarch64 to also target older x86_64, the user may set a |
| 326 | +// lower deployment target than supported. |
| 327 | +// |
| 328 | +// To avoid such issues, we silently raise the deployment target |
| 329 | +// here. |
| 330 | +// FIXME: We want to show a warning when `version < os_min`. |
| 331 | +Ok(version) => version.max(min), |
| 332 | +// FIXME: Report erroneous environment variable to user. |
| 333 | +Err(_) => min, |
| 334 | +} |
| 335 | +}else{ |
| 336 | + min |
| 337 | +} |
308 | 338 | } |
309 | 339 |
|
310 | | -pub(crate)fnmacos_llvm_target(arch:Arch) -> String{ |
311 | | -let(major, minor) = macos_deployment_target(arch); |
312 | | -format!("{}-apple-macosx{}.{}.0", arch.target_name(), major, minor) |
| 340 | +/// Generate the target triple that we need to pass to LLVM and/or Clang. |
| 341 | +fnllvm_target(os:&str,arch:Arch,abi:TargetAbi) -> StaticCow<str>{ |
| 342 | +// The target triple depends on the deployment target, and is required to |
| 343 | +// enable features such as cross-language LTO, and for picking the right |
| 344 | +// Mach-O commands. |
| 345 | +// |
| 346 | +// Certain optimizations also depend on the deployment target. |
| 347 | +let(major, minor, patch) = deployment_target(os, arch, abi); |
| 348 | +let arch = arch.target_name(); |
| 349 | +// Convert to the "canonical" OS name used by LLVM: |
| 350 | +// https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L236-L282 |
| 351 | +let os = match os { |
| 352 | +"macos" => "macosx", |
| 353 | +"ios" => "ios", |
| 354 | +"watchos" => "watchos", |
| 355 | +"tvos" => "tvos", |
| 356 | +"visionos" => "xros", |
| 357 | + _ => unreachable!("tried to get LLVM target OS for non-Apple platform"), |
| 358 | +}; |
| 359 | +let environment = match abi { |
| 360 | +TargetAbi::Normal => "", |
| 361 | +TargetAbi::MacCatalyst => "-macabi", |
| 362 | +TargetAbi::Simulator => "-simulator", |
| 363 | +}; |
| 364 | +format!("{arch}-apple-{os}{major}.{minor}.{patch}{environment}").into() |
313 | 365 | } |
314 | 366 |
|
315 | 367 | fnlink_env_remove(os:&'staticstr) -> StaticCow<[StaticCow<str>]>{ |
@@ -349,83 +401,19 @@ fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> { |
349 | 401 | } |
350 | 402 | } |
351 | 403 |
|
352 | | -fnios_deployment_target(arch:Arch,abi:&str) -> (u32,u32){ |
353 | | -// If you are looking for the default deployment target, prefer `rustc --print deployment-target`. |
354 | | -// Note: If bumping this version, remember to update it in the rustc/platform-support docs. |
355 | | -let(major, minor) = match(arch, abi){ |
356 | | -(Arm64e, _) => (14,0), |
357 | | -// Mac Catalyst defaults to 13.1 in Clang. |
358 | | -(_,"macabi") => (13,1), |
359 | | - _ => (10,0), |
360 | | -}; |
361 | | -from_set_deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((major, minor)) |
362 | | -} |
363 | | - |
364 | | -pub(crate)fnios_llvm_target(arch:Arch) -> String{ |
365 | | -// Modern iOS tooling extracts information about deployment target |
366 | | -// from LC_BUILD_VERSION. This load command will only be emitted when |
367 | | -// we build with a version specific `llvm_target`, with the version |
368 | | -// set high enough. Luckily one LC_BUILD_VERSION is enough, for Xcode |
369 | | -// to pick it up (since std and core are still built with the fallback |
370 | | -// of version 7.0 and hence emit the old LC_IPHONE_MIN_VERSION). |
371 | | -let(major, minor) = ios_deployment_target(arch,""); |
372 | | -format!("{}-apple-ios{}.{}.0", arch.target_name(), major, minor) |
373 | | -} |
374 | | - |
375 | | -pub(crate)fnmac_catalyst_llvm_target(arch:Arch) -> String{ |
376 | | -let(major, minor) = ios_deployment_target(arch,"macabi"); |
377 | | -format!("{}-apple-ios{}.{}.0-macabi", arch.target_name(), major, minor) |
378 | | -} |
379 | | - |
380 | | -pub(crate)fnios_sim_llvm_target(arch:Arch) -> String{ |
381 | | -let(major, minor) = ios_deployment_target(arch,"sim"); |
382 | | -format!("{}-apple-ios{}.{}.0-simulator", arch.target_name(), major, minor) |
383 | | -} |
384 | | - |
385 | | -fntvos_deployment_target() -> (u32,u32){ |
386 | | -// If you are looking for the default deployment target, prefer `rustc --print deployment-target`. |
387 | | -// Note: If bumping this version, remember to update it in the rustc platform-support docs. |
388 | | -from_set_deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((10,0)) |
389 | | -} |
390 | | - |
391 | | -pub(crate)fntvos_llvm_target(arch:Arch) -> String{ |
392 | | -let(major, minor) = tvos_deployment_target(); |
393 | | -format!("{}-apple-tvos{}.{}.0", arch.target_name(), major, minor) |
394 | | -} |
395 | | - |
396 | | -pub(crate)fntvos_sim_llvm_target(arch:Arch) -> String{ |
397 | | -let(major, minor) = tvos_deployment_target(); |
398 | | -format!("{}-apple-tvos{}.{}.0-simulator", arch.target_name(), major, minor) |
399 | | -} |
400 | | - |
401 | | -fnwatchos_deployment_target() -> (u32,u32){ |
402 | | -// If you are looking for the default deployment target, prefer `rustc --print deployment-target`. |
403 | | -// Note: If bumping this version, remember to update it in the rustc platform-support docs. |
404 | | -from_set_deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5,0)) |
405 | | -} |
406 | | - |
407 | | -pub(crate)fnwatchos_llvm_target(arch:Arch) -> String{ |
408 | | -let(major, minor) = watchos_deployment_target(); |
409 | | -format!("{}-apple-watchos{}.{}.0", arch.target_name(), major, minor) |
410 | | -} |
411 | | - |
412 | | -pub(crate)fnwatchos_sim_llvm_target(arch:Arch) -> String{ |
413 | | -let(major, minor) = watchos_deployment_target(); |
414 | | -format!("{}-apple-watchos{}.{}.0-simulator", arch.target_name(), major, minor) |
415 | | -} |
416 | | - |
417 | | -fnvisionos_deployment_target() -> (u32,u32){ |
418 | | -// If you are looking for the default deployment target, prefer `rustc --print deployment-target`. |
419 | | -// Note: If bumping this version, remember to update it in the rustc platform-support docs. |
420 | | -from_set_deployment_target("XROS_DEPLOYMENT_TARGET").unwrap_or((1,0)) |
421 | | -} |
422 | | - |
423 | | -pub(crate)fnvisionos_llvm_target(arch:Arch) -> String{ |
424 | | -let(major, minor) = visionos_deployment_target(); |
425 | | -format!("{}-apple-visionos{}.{}.0", arch.target_name(), major, minor) |
426 | | -} |
427 | | - |
428 | | -pub(crate)fnvisionos_sim_llvm_target(arch:Arch) -> String{ |
429 | | -let(major, minor) = visionos_deployment_target(); |
430 | | -format!("{}-apple-visionos{}.{}.0-simulator", arch.target_name(), major, minor) |
| 404 | +/// Parse an OS version triple (SDK version or deployment target). |
| 405 | +/// |
| 406 | +/// The size of the returned numbers here are limited by Mach-O's |
| 407 | +/// `LC_BUILD_VERSION`. |
| 408 | +fnparse_version(version:&str) -> Result<(u16,u8,u8),ParseIntError>{ |
| 409 | +ifletSome((major, minor)) = version.split_once('.'){ |
| 410 | +let major = major.parse()?; |
| 411 | +ifletSome((minor, patch)) = minor.split_once('.'){ |
| 412 | +Ok((major, minor.parse()?, patch.parse()?)) |
| 413 | +}else{ |
| 414 | +Ok((major, minor.parse()?,0)) |
| 415 | +} |
| 416 | +}else{ |
| 417 | +Ok((version.parse()?,0,0)) |
| 418 | +} |
431 | 419 | } |
0 commit comments