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"))]),
170
171 ..Default::default()
172 };
173 if matches!(arch, Arch::I386 | Arch::I686) {
174 opts.rustc_abi = Some(RustcAbi::X86Sse2);
176 }
177 (opts, unversioned_llvm_target(os, arch, env), arch.target_arch())
178}
179
180fn unversioned_llvm_target(os: &str, arch: Arch, env: TargetEnv) -> StaticCow<str> {
185 let arch = arch.target_name();
186 let os = match os {
189 "macos" => "macosx",
190 "ios" => "ios",
191 "watchos" => "watchos",
192 "tvos" => "tvos",
193 "visionos" => "xros",
194 _ => unreachable!("tried to get LLVM target OS for non-Apple platform"),
195 };
196 let environment = match env {
197 TargetEnv::Normal => "",
198 TargetEnv::MacCatalyst => "-macabi",
199 TargetEnv::Simulator => "-simulator",
200 };
201 format!("{arch}-apple-{os}{environment}").into()
202}
203
204fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> {
205 if os == "macos" {
211 cvs!["IPHONEOS_DEPLOYMENT_TARGET", "TVOS_DEPLOYMENT_TARGET", "XROS_DEPLOYMENT_TARGET"]
215 } else {
216 cvs!["MACOSX_DEPLOYMENT_TARGET"]
219 }
220}
221
222#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
226pub struct OSVersion {
227 pub major: u16,
228 pub minor: u8,
229 pub patch: u8,
230}
231
232impl FromStr for OSVersion {
233 type Err = ParseIntError;
234
235 fn from_str(version: &str) -> Result<Self, ParseIntError> {
237 if let Some((major, minor)) = version.split_once('.') {
238 let major = major.parse()?;
239 if let Some((minor, patch)) = minor.split_once('.') {
240 Ok(Self { major, minor: minor.parse()?, patch: patch.parse()? })
241 } else {
242 Ok(Self { major, minor: minor.parse()?, patch: 0 })
243 }
244 } else {
245 Ok(Self { major: version.parse()?, minor: 0, patch: 0 })
246 }
247 }
248}
249
250impl OSVersion {
251 pub fn new(major: u16, minor: u8, patch: u8) -> Self {
252 Self { major, minor, patch }
253 }
254
255 pub fn fmt_pretty(self) -> impl Display {
256 let Self { major, minor, patch } = self;
257 from_fn(move |f| {
258 write!(f, "{major}.{minor}")?;
259 if patch != 0 {
260 write!(f, ".{patch}")?;
261 }
262 Ok(())
263 })
264 }
265
266 pub fn fmt_full(self) -> impl Display {
267 let Self { major, minor, patch } = self;
268 from_fn(move |f| write!(f, "{major}.{minor}.{patch}"))
269 }
270
271 pub fn os_minimum_deployment_target(os: &str) -> Self {
273 let (major, minor, patch) = match os {
281 "macos" => (10, 12, 0),
282 "ios" => (10, 0, 0),
283 "tvos" => (10, 0, 0),
284 "watchos" => (5, 0, 0),
285 "visionos" => (1, 0, 0),
286 _ => unreachable!("tried to get deployment target for non-Apple platform"),
287 };
288 Self { major, minor, patch }
289 }
290
291 pub fn minimum_deployment_target(target: &Target) -> Self {
299 let (major, minor, patch) = match (&*target.os, &*target.arch, &*target.env) {
300 ("macos", "aarch64", _) => (11, 0, 0),
301 ("ios", "aarch64", "macabi") => (14, 0, 0),
302 ("ios", "aarch64", "sim") => (14, 0, 0),
303 ("ios", _, _) if target.llvm_target.starts_with("arm64e") => (14, 0, 0),
304 ("ios", _, "macabi") => (13, 1, 0),
306 ("tvos", "aarch64", "sim") => (14, 0, 0),
307 ("watchos", "aarch64", "sim") => (7, 0, 0),
308 (os, _, _) => return Self::os_minimum_deployment_target(os),
309 };
310 Self { major, minor, patch }
311 }
312}
313
314pub fn deployment_target_env_var(os: &str) -> &'static str {
316 match os {
317 "macos" => "MACOSX_DEPLOYMENT_TARGET",
318 "ios" => "IPHONEOS_DEPLOYMENT_TARGET",
319 "watchos" => "WATCHOS_DEPLOYMENT_TARGET",
320 "tvos" => "TVOS_DEPLOYMENT_TARGET",
321 "visionos" => "XROS_DEPLOYMENT_TARGET",
322 _ => unreachable!("tried to get deployment target env var for non-Apple platform"),
323 }
324}