|
| 1 | +use std::env; |
| 2 | +use std::num::ParseIntError; |
| 3 | + |
| 4 | +use rustc_session::Session; |
| 5 | +use rustc_target::spec::Target; |
| 6 | + |
| 7 | +#[cfg(test)] |
| 8 | +mod tests; |
| 9 | + |
| 10 | +/// Deployment target or SDK version. |
| 11 | +/// |
| 12 | +/// The size of the numbers in here are limited by Mach-O's `LC_BUILD_VERSION`. |
| 13 | +typeOSVersion = (u16,u8,u8); |
| 14 | + |
| 15 | +/// Parse an OS version triple (SDK version or deployment target). |
| 16 | +fnparse_version(version:&str) -> Result<OSVersion,ParseIntError>{ |
| 17 | +ifletSome((major, minor)) = version.split_once('.'){ |
| 18 | +let major = major.parse()?; |
| 19 | +ifletSome((minor, patch)) = minor.split_once('.'){ |
| 20 | +Ok((major, minor.parse()?, patch.parse()?)) |
| 21 | +}else{ |
| 22 | +Ok((major, minor.parse()?,0)) |
| 23 | +} |
| 24 | +}else{ |
| 25 | +Ok((version.parse()?,0,0)) |
| 26 | +} |
| 27 | +} |
| 28 | + |
| 29 | +/// Minimum operating system versions currently supported by `rustc`. |
| 30 | +fnos_minimum_deployment_target(os:&str) -> OSVersion{ |
| 31 | +// When bumping a version in here, remember to update the platform-support docs too. |
| 32 | +// |
| 33 | +// NOTE: The defaults may change in future `rustc` versions, so if you are looking for the |
| 34 | +// default deployment target, prefer: |
| 35 | +// ``` |
| 36 | +// $ rustc --print deployment-target |
| 37 | +// ``` |
| 38 | +match os { |
| 39 | +"macos" => (10,12,0), |
| 40 | +"ios" => (10,0,0), |
| 41 | +"tvos" => (10,0,0), |
| 42 | +"watchos" => (5,0,0), |
| 43 | +"visionos" => (1,0,0), |
| 44 | + _ => unreachable!("tried to get deployment target for non-Apple platform"), |
| 45 | +} |
| 46 | +} |
| 47 | + |
| 48 | +/// The deployment target for the given target. |
| 49 | +/// |
| 50 | +/// This is similar to `os_minimum_deployment_target`, except that on certain targets it makes sense |
| 51 | +/// to raise the minimum OS version. |
| 52 | +/// |
| 53 | +/// This matches what LLVM does, see in part: |
| 54 | +/// <https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L1900-L1932> |
| 55 | +fnminimum_deployment_target(target:&Target) -> OSVersion{ |
| 56 | +match(&*target.os,&*target.arch,&*target.abi){ |
| 57 | +("macos","aarch64", _) => (11,0,0), |
| 58 | +("ios","aarch64","macabi") => (14,0,0), |
| 59 | +("ios","aarch64","sim") => (14,0,0), |
| 60 | +("ios", _, _)if target.llvm_target.starts_with("arm64e") => (14,0,0), |
| 61 | +// Mac Catalyst defaults to 13.1 in Clang. |
| 62 | +("ios", _,"macabi") => (13,1,0), |
| 63 | +("tvos","aarch64","sim") => (14,0,0), |
| 64 | +("watchos","aarch64","sim") => (7,0,0), |
| 65 | +(os, _, _) => os_minimum_deployment_target(os), |
| 66 | +} |
| 67 | +} |
| 68 | + |
| 69 | +/// Name of the environment variable used to fetch the deployment target on the given OS. |
| 70 | +fndeployment_target_env_var(os:&str) -> &'staticstr{ |
| 71 | +match os { |
| 72 | +"macos" => "MACOSX_DEPLOYMENT_TARGET", |
| 73 | +"ios" => "IPHONEOS_DEPLOYMENT_TARGET", |
| 74 | +"watchos" => "WATCHOS_DEPLOYMENT_TARGET", |
| 75 | +"tvos" => "TVOS_DEPLOYMENT_TARGET", |
| 76 | +"visionos" => "XROS_DEPLOYMENT_TARGET", |
| 77 | + _ => unreachable!("tried to get deployment target env var for non-Apple platform"), |
| 78 | +} |
| 79 | +} |
| 80 | + |
| 81 | +/// Get the deployment target based on the standard environment variables, or fall back to the |
| 82 | +/// minimum version supported by `rustc`. |
| 83 | +pubfndeployment_target(sess:&Session) -> OSVersion{ |
| 84 | +let min = minimum_deployment_target(&sess.target); |
| 85 | + |
| 86 | +ifletOk(deployment_target) = env::var(deployment_target_env_var(&sess.target.os)){ |
| 87 | +matchparse_version(&deployment_target){ |
| 88 | +// It is common that the deployment target is set too low, e.g. on macOS Aarch64 to also |
| 89 | +// target older x86_64, the user may set a lower deployment target than supported. |
| 90 | +// |
| 91 | +// To avoid such issues, we silently raise the deployment target here. |
| 92 | +// FIXME: We want to show a warning when `version < os_min`. |
| 93 | +Ok(version) => version.max(min), |
| 94 | +// FIXME: Report erroneous environment variable to user. |
| 95 | +Err(_) => min, |
| 96 | +} |
| 97 | +}else{ |
| 98 | +// If no deployment target variable is set, default to the minimum found above. |
| 99 | + min |
| 100 | +} |
| 101 | +} |
| 102 | + |
| 103 | +pub(super)fnadd_version_to_llvm_target( |
| 104 | +llvm_target:&str, |
| 105 | +deployment_target:OSVersion, |
| 106 | +) -> String{ |
| 107 | +letmut components = llvm_target.split("-"); |
| 108 | +let arch = components.next().expect("apple target should have arch"); |
| 109 | +let vendor = components.next().expect("apple target should have vendor"); |
| 110 | +let os = components.next().expect("apple target should have os"); |
| 111 | +let environment = components.next(); |
| 112 | +assert_eq!(components.next(),None,"too many LLVM triple components"); |
| 113 | + |
| 114 | +let(major, minor, patch) = deployment_target; |
| 115 | + |
| 116 | +assert!( |
| 117 | + !os.contains(|c:char| c.is_ascii_digit()), |
| 118 | +"LLVM target must not already be versioned" |
| 119 | +); |
| 120 | + |
| 121 | +ifletSome(env) = environment { |
| 122 | +// Insert version into OS, before environment |
| 123 | +format!("{arch}-{vendor}-{os}{major}.{minor}.{patch}-{env}") |
| 124 | +}else{ |
| 125 | +format!("{arch}-{vendor}-{os}{major}.{minor}.{patch}") |
| 126 | +} |
| 127 | +} |
0 commit comments