rustc_target/spec/base/apple/
mod.rs1use std::borrow::Cow;
2use std::fmt::{Display, from_fn};
3use std::num::ParseIntError;
4use std::str::FromStr;
5
6use crate::spec::{
7 BinaryFormat, Cc, DebuginfoKind, FloatAbi, FramePointer, LinkerFlavor, Lld, RustcAbi,
8 SplitDebuginfo, StackProbeType, StaticCow, Target, TargetOptions, cvs,
9};
10
11#[cfg(test)]
12mod tests;
13
14use Arch::*;
15#[allow(non_camel_case_types)]
16#[derive(Copy, Clone, PartialEq)]
17pub(crate) enum Arch {
18 Armv7k,
19 Armv7s,
20 Arm64,
21 Arm64e,
22 Arm64_32,
23 I386,
24 I686,
25 X86_64,
26 X86_64h,
27}
28
29impl Arch {
30 fn target_name(self) -> &'static str {
31 match self {
32 Armv7k => "armv7k",
33 Armv7s => "armv7s",
34 Arm64 => "arm64",
35 Arm64e => "arm64e",
36 Arm64_32 => "arm64_32",
37 I386 => "i386",
38 I686 => "i686",
39 X86_64 => "x86_64",
40 X86_64h => "x86_64h",
41 }
42 }
43
44 pub(crate) fn target_arch(self) -> Cow<'static, str> {
45 Cow::Borrowed(match self {
46 Armv7k | Armv7s => "arm",
47 Arm64 | Arm64e | Arm64_32 => "aarch64",
48 I386 | I686 => "x86",
49 X86_64 | X86_64h => "x86_64",
50 })
51 }
52
53 fn target_cpu(self, env: TargetEnv) -> &'static str {
54 match self {
55 Armv7k => "cortex-a8",
56 Armv7s => "swift", Arm64 => match env {
58 TargetEnv::Normal => "apple-a7",
59 TargetEnv::Simulator => "apple-a12",
60 TargetEnv::MacCatalyst => "apple-a12",
61 },
62 Arm64e => "apple-a12",
63 Arm64_32 => "apple-s4",
64 I386 | I686 => "penryn",
68 X86_64 => "penryn",
69 X86_64h => "core-avx2",
73 }
74 }
75
76 fn stack_probes(self) -> StackProbeType {
77 match self {
78 Armv7k | Armv7s => StackProbeType::None,
79 Arm64 | Arm64e | Arm64_32 | I386 | I686 | X86_64 | X86_64h => StackProbeType::Inline,
80 }
81 }
82}
83
84#[derive(Copy, Clone, PartialEq)]
85pub(crate) enum TargetEnv {
86 Normal,
87 Simulator,
88 MacCatalyst,
89}
90
91impl TargetEnv {
92 fn target_env(self) -> &'static str {
93 match self {
94 Self::Normal => "",
95 Self::MacCatalyst => "macabi",
96 Self::Simulator => "sim",
97 }
98 }
99}
100
101pub(crate) fn base(
104 os: &'static str,
105 arch: Arch,
106 env: TargetEnv,
107) -> (TargetOptions, StaticCow<str>, StaticCow<str>) {
108 let mut opts = TargetOptions {
109 llvm_floatabi: Some(FloatAbi::Hard),
110 os: os.into(),
111 env: env.target_env().into(),
112 abi: env.target_env().into(),
119 cpu: arch.target_cpu(env).into(),
120 link_env_remove: link_env_remove(os),
121 vendor: "apple".into(),
122 linker_flavor: LinkerFlavor::Darwin(Cc::Yes, Lld::No),
123 function_sections: false,
125 dynamic_linking: true,
126 families: cvs!["unix"],
127 is_like_darwin: true,
128 binary_format: BinaryFormat::MachO,
129 default_dwarf_version: 4,
133 frame_pointer: match arch {
134 Armv7k | Armv7s => FramePointer::Always,
136 Arm64 | Arm64e | Arm64_32 => FramePointer::NonLeaf,
138 I386 | I686 | X86_64 | X86_64h => FramePointer::Always,
139 },
140 has_rpath: true,
141 dll_suffix: ".dylib".into(),
142 archive_format: "darwin".into(),
143 has_thread_local: true,
146 abi_return_struct_as_int: true,
147 emit_debug_gdb_scripts: false,
148 eh_frame_header: false,
149 stack_probes: arch.stack_probes(),
150
151 debuginfo_kind: DebuginfoKind::DwarfDsym,
152 split_debuginfo: SplitDebuginfo::Packed,
155 supported_split_debuginfo: Cow::Borrowed(&[
156 SplitDebuginfo::Packed,
157 SplitDebuginfo::Unpacked,
158 SplitDebuginfo::Off,
159 ]),
160
161 link_env: Cow::Borrowed(&[(Cow::Borrowed("ZERO_AR_DATE"), Cow::Borrowed("1"))]),
180
181 ..Default::default()
182 };
183 if matches!(arch, Arch::I386 | Arch::I686) {
184 opts.rustc_abi = Some(RustcAbi::X86Sse2);
186 }
187 (opts, unversioned_llvm_target(os, arch, env), arch.target_arch())
188}
189
190fn unversioned_llvm_target(os: &str, arch: Arch, env: TargetEnv) -> StaticCow<str> {
195 let arch = arch.target_name();
196 let os = match os {
199 "macos" => "macosx",
200 "ios" => "ios",
201 "watchos" => "watchos",
202 "tvos" => "tvos",
203 "visionos" => "xros",
204 _ => unreachable!("tried to get LLVM target OS for non-Apple platform"),
205 };
206 let environment = match env {
207 TargetEnv::Normal => "",
208 TargetEnv::MacCatalyst => "-macabi",
209 TargetEnv::Simulator => "-simulator",
210 };
211 format!("{arch}-apple-{os}{environment}").into()
212}
213
214fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> {
215 if os == "macos" {
221 cvs!["IPHONEOS_DEPLOYMENT_TARGET", "TVOS_DEPLOYMENT_TARGET", "XROS_DEPLOYMENT_TARGET"]
225 } else {
226 cvs!["MACOSX_DEPLOYMENT_TARGET"]
229 }
230}
231
232#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
236pub struct OSVersion {
237 pub major: u16,
238 pub minor: u8,
239 pub patch: u8,
240}
241
242impl FromStr for OSVersion {
243 type Err = ParseIntError;
244
245 fn from_str(version: &str) -> Result<Self, ParseIntError> {
247 if let Some((major, minor)) = version.split_once('.') {
248 let major = major.parse()?;
249 if let Some((minor, patch)) = minor.split_once('.') {
250 Ok(Self { major, minor: minor.parse()?, patch: patch.parse()? })
251 } else {
252 Ok(Self { major, minor: minor.parse()?, patch: 0 })
253 }
254 } else {
255 Ok(Self { major: version.parse()?, minor: 0, patch: 0 })
256 }
257 }
258}
259
260impl OSVersion {
261 pub fn new(major: u16, minor: u8, patch: u8) -> Self {
262 Self { major, minor, patch }
263 }
264
265 pub fn fmt_pretty(self) -> impl Display {
266 let Self { major, minor, patch } = self;
267 from_fn(move |f| {
268 write!(f, "{major}.{minor}")?;
269 if patch != 0 {
270 write!(f, ".{patch}")?;
271 }
272 Ok(())
273 })
274 }
275
276 pub fn fmt_full(self) -> impl Display {
277 let Self { major, minor, patch } = self;
278 from_fn(move |f| write!(f, "{major}.{minor}.{patch}"))
279 }
280
281 pub fn os_minimum_deployment_target(os: &str) -> Self {
283 let (major, minor, patch) = match os {
291 "macos" => (10, 12, 0),
292 "ios" => (10, 0, 0),
293 "tvos" => (10, 0, 0),
294 "watchos" => (5, 0, 0),
295 "visionos" => (1, 0, 0),
296 _ => unreachable!("tried to get deployment target for non-Apple platform"),
297 };
298 Self { major, minor, patch }
299 }
300
301 pub fn minimum_deployment_target(target: &Target) -> Self {
309 let (major, minor, patch) = match (&*target.os, &*target.arch, &*target.env) {
310 ("macos", "aarch64", _) => (11, 0, 0),
311 ("ios", "aarch64", "macabi") => (14, 0, 0),
312 ("ios", "aarch64", "sim") => (14, 0, 0),
313 ("ios", _, _) if target.llvm_target.starts_with("arm64e") => (14, 0, 0),
314 ("ios", _, "macabi") => (13, 1, 0),
316 ("tvos", "aarch64", "sim") => (14, 0, 0),
317 ("watchos", "aarch64", "sim") => (7, 0, 0),
318 ("watchos", "aarch64", "") if !target.llvm_target.starts_with("arm64_32") => (26, 0, 0),
321 (os, _, _) => return Self::os_minimum_deployment_target(os),
322 };
323 Self { major, minor, patch }
324 }
325}
326
327pub fn deployment_target_env_var(os: &str) -> &'static str {
329 match os {
330 "macos" => "MACOSX_DEPLOYMENT_TARGET",
331 "ios" => "IPHONEOS_DEPLOYMENT_TARGET",
332 "watchos" => "WATCHOS_DEPLOYMENT_TARGET",
333 "tvos" => "TVOS_DEPLOYMENT_TARGET",
334 "visionos" => "XROS_DEPLOYMENT_TARGET",
335 _ => unreachable!("tried to get deployment target env var for non-Apple platform"),
336 }
337}