rustc_target/spec/base/apple/
mod.rs1use std::borrow::Cow;
2use std::env;
3use std::fmt::{Display, from_fn};
4use std::num::ParseIntError;
5use std::str::FromStr;
6
7use crate::spec::{
8 BinaryFormat, Cc, DebuginfoKind, FloatAbi, FramePointer, LinkerFlavor, Lld, RustcAbi,
9 SplitDebuginfo, StackProbeType, StaticCow, Target, TargetOptions, cvs,
10};
11
12#[cfg(test)]
13mod tests;
14
15use Arch::*;
16#[allow(non_camel_case_types)]
17#[derive(Copy, Clone, PartialEq)]
18pub(crate) enum Arch {
19 Armv7k,
20 Armv7s,
21 Arm64,
22 Arm64e,
23 Arm64_32,
24 I386,
25 I686,
26 X86_64,
27 X86_64h,
28}
29
30impl Arch {
31 fn target_name(self) -> &'static str {
32 match self {
33 Armv7k => "armv7k",
34 Armv7s => "armv7s",
35 Arm64 => "arm64",
36 Arm64e => "arm64e",
37 Arm64_32 => "arm64_32",
38 I386 => "i386",
39 I686 => "i686",
40 X86_64 => "x86_64",
41 X86_64h => "x86_64h",
42 }
43 }
44
45 pub(crate) fn target_arch(self) -> Cow<'static, str> {
46 Cow::Borrowed(match self {
47 Armv7k | Armv7s => "arm",
48 Arm64 | Arm64e | Arm64_32 => "aarch64",
49 I386 | I686 => "x86",
50 X86_64 | X86_64h => "x86_64",
51 })
52 }
53
54 fn target_cpu(self, abi: TargetAbi) -> &'static str {
55 match self {
56 Armv7k => "cortex-a8",
57 Armv7s => "swift", Arm64 => match abi {
59 TargetAbi::Normal => "apple-a7",
60 TargetAbi::Simulator => "apple-a12",
61 TargetAbi::MacCatalyst => "apple-a12",
62 },
63 Arm64e => "apple-a12",
64 Arm64_32 => "apple-s4",
65 I386 | I686 => "penryn",
69 X86_64 => "penryn",
70 X86_64h => "core-avx2",
74 }
75 }
76
77 fn stack_probes(self) -> StackProbeType {
78 match self {
79 Armv7k | Armv7s => StackProbeType::None,
80 Arm64 | Arm64e | Arm64_32 | I386 | I686 | X86_64 | X86_64h => StackProbeType::Inline,
81 }
82 }
83}
84
85#[derive(Copy, Clone, PartialEq)]
86pub(crate) enum TargetAbi {
87 Normal,
88 Simulator,
89 MacCatalyst,
90}
91
92impl TargetAbi {
93 fn target_abi(self) -> &'static str {
94 match self {
95 Self::Normal => "",
96 Self::MacCatalyst => "macabi",
97 Self::Simulator => "sim",
98 }
99 }
100}
101
102pub(crate) fn base(
105 os: &'static str,
106 arch: Arch,
107 abi: TargetAbi,
108) -> (TargetOptions, StaticCow<str>, StaticCow<str>) {
109 let mut opts = TargetOptions {
110 abi: abi.target_abi().into(),
111 llvm_floatabi: Some(FloatAbi::Hard),
112 os: os.into(),
113 cpu: arch.target_cpu(abi).into(),
114 link_env_remove: link_env_remove(os),
115 vendor: "apple".into(),
116 linker_flavor: LinkerFlavor::Darwin(Cc::Yes, Lld::No),
117 function_sections: false,
119 dynamic_linking: true,
120 families: cvs!["unix"],
121 is_like_darwin: true,
122 binary_format: BinaryFormat::MachO,
123 default_dwarf_version: 4,
127 frame_pointer: match arch {
128 Armv7k | Armv7s => FramePointer::Always,
130 Arm64 | Arm64e | Arm64_32 => FramePointer::NonLeaf,
132 I386 | I686 | X86_64 | X86_64h => FramePointer::Always,
133 },
134 has_rpath: true,
135 dll_suffix: ".dylib".into(),
136 archive_format: "darwin".into(),
137 has_thread_local: true,
140 abi_return_struct_as_int: true,
141 emit_debug_gdb_scripts: false,
142 eh_frame_header: false,
143 stack_probes: arch.stack_probes(),
144
145 debuginfo_kind: DebuginfoKind::DwarfDsym,
146 split_debuginfo: SplitDebuginfo::Packed,
149 supported_split_debuginfo: Cow::Borrowed(&[
150 SplitDebuginfo::Packed,
151 SplitDebuginfo::Unpacked,
152 SplitDebuginfo::Off,
153 ]),
154
155 link_env: Cow::Borrowed(&[(Cow::Borrowed("ZERO_AR_DATE"), Cow::Borrowed("1"))]),
164
165 ..Default::default()
166 };
167 if matches!(arch, Arch::I386 | Arch::I686) {
168 opts.rustc_abi = Some(RustcAbi::X86Sse2);
170 }
171 (opts, unversioned_llvm_target(os, arch, abi), arch.target_arch())
172}
173
174fn unversioned_llvm_target(os: &str, arch: Arch, abi: TargetAbi) -> StaticCow<str> {
179 let arch = arch.target_name();
180 let os = match os {
183 "macos" => "macosx",
184 "ios" => "ios",
185 "watchos" => "watchos",
186 "tvos" => "tvos",
187 "visionos" => "xros",
188 _ => unreachable!("tried to get LLVM target OS for non-Apple platform"),
189 };
190 let environment = match abi {
191 TargetAbi::Normal => "",
192 TargetAbi::MacCatalyst => "-macabi",
193 TargetAbi::Simulator => "-simulator",
194 };
195 format!("{arch}-apple-{os}{environment}").into()
196}
197
198fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> {
199 if os == "macos" {
205 let mut env_remove = Vec::with_capacity(2);
206 if let Ok(sdkroot) = env::var("SDKROOT") {
209 if sdkroot.contains("iPhoneOS.platform")
210 || sdkroot.contains("iPhoneSimulator.platform")
211 || sdkroot.contains("AppleTVOS.platform")
212 || sdkroot.contains("AppleTVSimulator.platform")
213 || sdkroot.contains("WatchOS.platform")
214 || sdkroot.contains("WatchSimulator.platform")
215 || sdkroot.contains("XROS.platform")
216 || sdkroot.contains("XRSimulator.platform")
217 {
218 env_remove.push("SDKROOT".into())
219 }
220 }
221 env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".into());
225 env_remove.push("TVOS_DEPLOYMENT_TARGET".into());
226 env_remove.push("XROS_DEPLOYMENT_TARGET".into());
227 env_remove.into()
228 } else {
229 cvs!["MACOSX_DEPLOYMENT_TARGET"]
232 }
233}
234
235#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
239pub struct OSVersion {
240 pub major: u16,
241 pub minor: u8,
242 pub patch: u8,
243}
244
245impl FromStr for OSVersion {
246 type Err = ParseIntError;
247
248 fn from_str(version: &str) -> Result<Self, ParseIntError> {
250 if let Some((major, minor)) = version.split_once('.') {
251 let major = major.parse()?;
252 if let Some((minor, patch)) = minor.split_once('.') {
253 Ok(Self { major, minor: minor.parse()?, patch: patch.parse()? })
254 } else {
255 Ok(Self { major, minor: minor.parse()?, patch: 0 })
256 }
257 } else {
258 Ok(Self { major: version.parse()?, minor: 0, patch: 0 })
259 }
260 }
261}
262
263impl OSVersion {
264 pub fn new(major: u16, minor: u8, patch: u8) -> Self {
265 Self { major, minor, patch }
266 }
267
268 pub fn fmt_pretty(self) -> impl Display {
269 let Self { major, minor, patch } = self;
270 from_fn(move |f| {
271 write!(f, "{major}.{minor}")?;
272 if patch != 0 {
273 write!(f, ".{patch}")?;
274 }
275 Ok(())
276 })
277 }
278
279 pub fn fmt_full(self) -> impl Display {
280 let Self { major, minor, patch } = self;
281 from_fn(move |f| write!(f, "{major}.{minor}.{patch}"))
282 }
283
284 pub fn os_minimum_deployment_target(os: &str) -> Self {
286 let (major, minor, patch) = 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 };
301 Self { major, minor, patch }
302 }
303
304 pub fn minimum_deployment_target(target: &Target) -> Self {
312 let (major, minor, patch) = match (&*target.os, &*target.arch, &*target.abi) {
313 ("macos", "aarch64", _) => (11, 0, 0),
314 ("ios", "aarch64", "macabi") => (14, 0, 0),
315 ("ios", "aarch64", "sim") => (14, 0, 0),
316 ("ios", _, _) if target.llvm_target.starts_with("arm64e") => (14, 0, 0),
317 ("ios", _, "macabi") => (13, 1, 0),
319 ("tvos", "aarch64", "sim") => (14, 0, 0),
320 ("watchos", "aarch64", "sim") => (7, 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}