11use std:: env;
22use std:: ffi:: OsString ;
3- use std:: fmt:: { Display , from_fn} ;
4- use std:: num:: ParseIntError ;
3+ use std:: str:: FromStr ;
54use std:: path:: PathBuf ;
65use std:: process:: Command ;
76
87use itertools:: Itertools ;
98use rustc_middle:: middle:: exported_symbols:: SymbolExportKind ;
109use rustc_session:: Session ;
1110use rustc_target:: spec:: Target ;
11+ pub ( super ) use rustc_target:: spec:: apple:: OSVersion ;
1212use tracing:: debug;
1313
1414use crate :: errors:: { AppleDeploymentTarget , XcrunError , XcrunSdkPathWarning } ;
@@ -134,76 +134,6 @@ pub(super) fn add_data_and_relocation(
134134 Ok ( ( ) )
135135}
136136
137- /// Deployment target or SDK version.
138- ///
139- /// The size of the numbers in here are limited by Mach-O's `LC_BUILD_VERSION`.
140- type OSVersion = ( u16 , u8 , u8 ) ;
141-
142- /// Parse an OS version triple (SDK version or deployment target).
143- fn parse_version ( version : & str ) -> Result < OSVersion , ParseIntError > {
144- if let Some ( ( major, minor) ) = version. split_once ( '.' ) {
145- let major = major. parse ( ) ?;
146- if let Some ( ( minor, patch) ) = minor. split_once ( '.' ) {
147- Ok ( ( major, minor. parse ( ) ?, patch. parse ( ) ?) )
148- } else {
149- Ok ( ( major, minor. parse ( ) ?, 0 ) )
150- }
151- } else {
152- Ok ( ( version. parse ( ) ?, 0 , 0 ) )
153- }
154- }
155-
156- pub fn pretty_version ( version : OSVersion ) -> impl Display {
157- let ( major, minor, patch) = version;
158- from_fn ( move |f| {
159- write ! ( f, "{major}.{minor}" ) ?;
160- if patch != 0 {
161- write ! ( f, ".{patch}" ) ?;
162- }
163- Ok ( ( ) )
164- } )
165- }
166-
167- /// Minimum operating system versions currently supported by `rustc`.
168- fn os_minimum_deployment_target ( os : & str ) -> OSVersion {
169- // When bumping a version in here, remember to update the platform-support docs too.
170- //
171- // NOTE: The defaults may change in future `rustc` versions, so if you are looking for the
172- // default deployment target, prefer:
173- // ```
174- // $ rustc --print deployment-target
175- // ```
176- match os {
177- "macos" => ( 10 , 12 , 0 ) ,
178- "ios" => ( 10 , 0 , 0 ) ,
179- "tvos" => ( 10 , 0 , 0 ) ,
180- "watchos" => ( 5 , 0 , 0 ) ,
181- "visionos" => ( 1 , 0 , 0 ) ,
182- _ => unreachable ! ( "tried to get deployment target for non-Apple platform" ) ,
183- }
184- }
185-
186- /// The deployment target for the given target.
187- ///
188- /// This is similar to `os_minimum_deployment_target`, except that on certain targets it makes sense
189- /// to raise the minimum OS version.
190- ///
191- /// This matches what LLVM does, see in part:
192- /// <https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L1900-L1932>
193- fn minimum_deployment_target ( target : & Target ) -> OSVersion {
194- match ( & * target. os , & * target. arch , & * target. abi ) {
195- ( "macos" , "aarch64" , _) => ( 11 , 0 , 0 ) ,
196- ( "ios" , "aarch64" , "macabi" ) => ( 14 , 0 , 0 ) ,
197- ( "ios" , "aarch64" , "sim" ) => ( 14 , 0 , 0 ) ,
198- ( "ios" , _, _) if target. llvm_target . starts_with ( "arm64e" ) => ( 14 , 0 , 0 ) ,
199- // Mac Catalyst defaults to 13.1 in Clang.
200- ( "ios" , _, "macabi" ) => ( 13 , 1 , 0 ) ,
201- ( "tvos" , "aarch64" , "sim" ) => ( 14 , 0 , 0 ) ,
202- ( "watchos" , "aarch64" , "sim" ) => ( 7 , 0 , 0 ) ,
203- ( os, _, _) => os_minimum_deployment_target ( os) ,
204- }
205- }
206-
207137/// Name of the environment variable used to fetch the deployment target on the given OS.
208138pub fn deployment_target_env_var ( os : & str ) -> & ' static str {
209139 match os {
@@ -219,22 +149,22 @@ pub fn deployment_target_env_var(os: &str) -> &'static str {
219149/// Get the deployment target based on the standard environment variables, or fall back to the
220150/// minimum version supported by `rustc`.
221151pub fn deployment_target ( sess : & Session ) -> OSVersion {
222- let min = minimum_deployment_target ( & sess. target ) ;
152+ let min = OSVersion :: minimum_deployment_target ( & sess. target ) ;
223153 let env_var = deployment_target_env_var ( & sess. target . os ) ;
224154
225155 if let Ok ( deployment_target) = env:: var ( env_var) {
226- match parse_version ( & deployment_target) {
156+ match OSVersion :: from_str ( & deployment_target) {
227157 Ok ( version) => {
228- let os_min = os_minimum_deployment_target ( & sess. target . os ) ;
158+ let os_min = OSVersion :: os_minimum_deployment_target ( & sess. target . os ) ;
229159 // It is common that the deployment target is set a bit too low, for example on
230160 // macOS Aarch64 to also target older x86_64. So we only want to warn when variable
231161 // is lower than the minimum OS supported by rustc, not when the variable is lower
232162 // than the minimum for a specific target.
233163 if version < os_min {
234164 sess. dcx ( ) . emit_warn ( AppleDeploymentTarget :: TooLow {
235165 env_var,
236- version : pretty_version ( version) . to_string ( ) ,
237- os_min : pretty_version ( os_min) . to_string ( ) ,
166+ version : version. fmt_pretty ( ) . to_string ( ) ,
167+ os_min : os_min. fmt_pretty ( ) . to_string ( ) ,
238168 } ) ;
239169 }
240170
@@ -263,18 +193,17 @@ pub(super) fn add_version_to_llvm_target(
263193 let environment = components. next ( ) ;
264194 assert_eq ! ( components. next( ) , None , "too many LLVM triple components" ) ;
265195
266- let ( major, minor, patch) = deployment_target;
267-
268196 assert ! (
269197 !os. contains( |c: char | c. is_ascii_digit( ) ) ,
270198 "LLVM target must not already be versioned"
271199 ) ;
272200
201+ let version = deployment_target. fmt_full ( ) ;
273202 if let Some ( env) = environment {
274203 // Insert version into OS, before environment
275- format ! ( "{arch}-{vendor}-{os}{major}.{minor}.{patch }-{env}" )
204+ format ! ( "{arch}-{vendor}-{os}{version }-{env}" )
276205 } else {
277- format ! ( "{arch}-{vendor}-{os}{major}.{minor}.{patch }" )
206+ format ! ( "{arch}-{vendor}-{os}{version }" )
278207 }
279208}
280209
0 commit comments