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 Abi, BinaryFormat, Cc, DebuginfoKind, Env, FloatAbi, FramePointer, LinkerFlavor, Lld, Os,
8 RustcAbi, SplitDebuginfo, StackProbeType, StaticCow, Target, TargetOptions, cvs,
9};
10
11#[cfg(test)]
12mod tests;
13
14#[allow(non_camel_case_types)]
15#[derive(Copy, Clone, PartialEq)]
16pub(crate) enum Arch {
17 Armv7k,
18 Armv7s,
19 Arm64,
20 Arm64e,
21 Arm64_32,
22 I386,
23 I686,
24 X86_64,
25 X86_64h,
26}
27
28impl Arch {
29 fn target_name(self) -> &'static str {
30 match self {
31 Self::Armv7k => "armv7k",
32 Self::Armv7s => "armv7s",
33 Self::Arm64 => "arm64",
34 Self::Arm64e => "arm64e",
35 Self::Arm64_32 => "arm64_32",
36 Self::I386 => "i386",
37 Self::I686 => "i686",
38 Self::X86_64 => "x86_64",
39 Self::X86_64h => "x86_64h",
40 }
41 }
42
43 pub(crate) fn target_arch(self) -> crate::spec::Arch {
44 match self {
45 Self::Armv7k | Self::Armv7s => crate::spec::Arch::Arm,
46 Self::Arm64 | Self::Arm64e | Self::Arm64_32 => crate::spec::Arch::AArch64,
47 Self::I386 | Self::I686 => crate::spec::Arch::X86,
48 Self::X86_64 | Self::X86_64h => crate::spec::Arch::X86_64,
49 }
50 }
51
52 fn target_cpu(self, env: TargetEnv) -> &'static str {
53 match self {
54 Self::Armv7k => "cortex-a8",
55 Self::Armv7s => "swift", Self::Arm64 => match env {
57 TargetEnv::Normal => "apple-a7",
58 TargetEnv::Simulator => "apple-a12",
59 TargetEnv::MacCatalyst => "apple-a12",
60 },
61 Self::Arm64e => "apple-a12",
62 Self::Arm64_32 => "apple-s4",
63 Self::I386 | Self::I686 => "penryn",
67 Self::X86_64 => "penryn",
68 Self::X86_64h => "core-avx2",
72 }
73 }
74
75 fn stack_probes(self) -> StackProbeType {
76 match self {
77 Self::Armv7k | Self::Armv7s => StackProbeType::None,
78 Self::Arm64
79 | Self::Arm64e
80 | Self::Arm64_32
81 | Self::I386
82 | Self::I686
83 | Self::X86_64
84 | Self::X86_64h => StackProbeType::Inline,
85 }
86 }
87}
88
89#[derive(Copy, Clone, PartialEq)]
90pub(crate) enum TargetEnv {
91 Normal,
92 Simulator,
93 MacCatalyst,
94}
95
96impl TargetEnv {
97 fn target_env(self) -> Env {
98 match self {
99 Self::Normal => Env::Unspecified,
100 Self::MacCatalyst => Env::MacAbi,
101 Self::Simulator => Env::Sim,
102 }
103 }
104
105 fn target_abi(self) -> Abi {
112 match self {
113 Self::Normal => Abi::Unspecified,
114 Self::MacCatalyst => Abi::MacAbi,
115 Self::Simulator => Abi::Sim,
116 }
117 }
118}
119
120pub(crate) fn base(
123 os: Os,
124 arch: Arch,
125 env: TargetEnv,
126) -> (TargetOptions, StaticCow<str>, crate::spec::Arch) {
127 let link_env_remove = link_env_remove(&os);
128 let unversioned_llvm_target = unversioned_llvm_target(&os, arch, env);
129 let mut opts = TargetOptions {
130 llvm_floatabi: Some(FloatAbi::Hard),
131 os,
132 env: env.target_env(),
133 abi: env.target_abi(),
134 cpu: arch.target_cpu(env).into(),
135 link_env_remove,
136 vendor: "apple".into(),
137 linker_flavor: LinkerFlavor::Darwin(Cc::Yes, Lld::No),
138 function_sections: false,
140 dynamic_linking: true,
141 families: cvs!["unix"],
142 is_like_darwin: true,
143 binary_format: BinaryFormat::MachO,
144 default_dwarf_version: 4,
148 frame_pointer: match arch {
149 Arch::Armv7k | Arch::Armv7s => FramePointer::Always,
151 Arch::Arm64 | Arch::Arm64e | Arch::Arm64_32 => FramePointer::NonLeaf,
153 Arch::I386 | Arch::I686 | Arch::X86_64 | Arch::X86_64h => FramePointer::Always,
154 },
155 has_rpath: true,
156 dll_suffix: ".dylib".into(),
157 archive_format: "darwin".into(),
158 has_thread_local: true,
161 abi_return_struct_as_int: true,
162 emit_debug_gdb_scripts: false,
163 eh_frame_header: false,
164 stack_probes: arch.stack_probes(),
165
166 debuginfo_kind: DebuginfoKind::DwarfDsym,
167 split_debuginfo: SplitDebuginfo::Packed,
170 supported_split_debuginfo: Cow::Borrowed(&[
171 SplitDebuginfo::Packed,
172 SplitDebuginfo::Unpacked,
173 SplitDebuginfo::Off,
174 ]),
175
176 link_env: Cow::Borrowed(&[(Cow::Borrowed("ZERO_AR_DATE"), Cow::Borrowed("1"))]),
195
196 ..Default::default()
197 };
198 if matches!(arch, Arch::I386 | Arch::I686) {
199 opts.rustc_abi = Some(RustcAbi::X86Sse2);
201 }
202 (opts, unversioned_llvm_target, arch.target_arch())
203}
204
205fn unversioned_llvm_target(os: &Os, arch: Arch, env: TargetEnv) -> StaticCow<str> {
210 let arch = arch.target_name();
211 let os = match os {
214 Os::MacOs => "macosx",
215 Os::IOs => "ios",
216 Os::WatchOs => "watchos",
217 Os::TvOs => "tvos",
218 Os::VisionOs => "xros",
219 _ => unreachable!("tried to get LLVM target OS for non-Apple platform"),
220 };
221 let environment = match env {
222 TargetEnv::Normal => "",
223 TargetEnv::MacCatalyst => "-macabi",
224 TargetEnv::Simulator => "-simulator",
225 };
226 format!("{arch}-apple-{os}{environment}").into()
227}
228
229fn link_env_remove(os: &Os) -> StaticCow<[StaticCow<str>]> {
230 if *os == Os::MacOs {
236 cvs!["IPHONEOS_DEPLOYMENT_TARGET", "TVOS_DEPLOYMENT_TARGET", "XROS_DEPLOYMENT_TARGET"]
240 } else {
241 cvs!["MACOSX_DEPLOYMENT_TARGET"]
244 }
245}
246
247#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
251pub struct OSVersion {
252 pub major: u16,
253 pub minor: u8,
254 pub patch: u8,
255}
256
257impl FromStr for OSVersion {
258 type Err = ParseIntError;
259
260 fn from_str(version: &str) -> Result<Self, ParseIntError> {
262 if let Some((major, minor)) = version.split_once('.') {
263 let major = major.parse()?;
264 if let Some((minor, patch)) = minor.split_once('.') {
265 Ok(Self { major, minor: minor.parse()?, patch: patch.parse()? })
266 } else {
267 Ok(Self { major, minor: minor.parse()?, patch: 0 })
268 }
269 } else {
270 Ok(Self { major: version.parse()?, minor: 0, patch: 0 })
271 }
272 }
273}
274
275impl OSVersion {
276 pub fn new(major: u16, minor: u8, patch: u8) -> Self {
277 Self { major, minor, patch }
278 }
279
280 pub fn fmt_pretty(self) -> impl Display {
281 let Self { major, minor, patch } = self;
282 from_fn(move |f| {
283 write!(f, "{major}.{minor}")?;
284 if patch != 0 {
285 write!(f, ".{patch}")?;
286 }
287 Ok(())
288 })
289 }
290
291 pub fn fmt_full(self) -> impl Display {
292 let Self { major, minor, patch } = self;
293 from_fn(move |f| write!(f, "{major}.{minor}.{patch}"))
294 }
295
296 pub fn os_minimum_deployment_target(os: &Os) -> Self {
298 let (major, minor, patch) = match os {
306 Os::MacOs => (10, 12, 0),
307 Os::IOs => (10, 0, 0),
308 Os::TvOs => (10, 0, 0),
309 Os::WatchOs => (5, 0, 0),
310 Os::VisionOs => (1, 0, 0),
311 other => {
312 unreachable!("tried to get deployment target for non-Apple platform: {:?}", other)
313 }
314 };
315 Self { major, minor, patch }
316 }
317
318 pub fn minimum_deployment_target(target: &Target) -> Self {
326 let (major, minor, patch) = match (&target.os, &target.arch, &target.env) {
327 (Os::MacOs, crate::spec::Arch::AArch64, _) => (11, 0, 0),
328 (Os::IOs, crate::spec::Arch::AArch64, Env::MacAbi) => (14, 0, 0),
329 (Os::IOs, crate::spec::Arch::AArch64, Env::Sim) => (14, 0, 0),
330 (Os::IOs, _, _) if target.llvm_target.starts_with("arm64e") => (14, 0, 0),
331 (Os::IOs, _, Env::MacAbi) => (13, 1, 0),
333 (Os::TvOs, crate::spec::Arch::AArch64, Env::Sim) => (14, 0, 0),
334 (Os::WatchOs, crate::spec::Arch::AArch64, Env::Sim) => (7, 0, 0),
335 (Os::WatchOs, crate::spec::Arch::AArch64, Env::Unspecified)
338 if !target.llvm_target.starts_with("arm64_32") =>
339 {
340 (26, 0, 0)
341 }
342 _ => return Self::os_minimum_deployment_target(&target.os),
343 };
344 Self { major, minor, patch }
345 }
346}
347
348pub fn deployment_target_env_var(os: &Os) -> &'static str {
350 match os {
351 Os::MacOs => "MACOSX_DEPLOYMENT_TARGET",
352 Os::IOs => "IPHONEOS_DEPLOYMENT_TARGET",
353 Os::WatchOs => "WATCHOS_DEPLOYMENT_TARGET",
354 Os::TvOs => "TVOS_DEPLOYMENT_TARGET",
355 Os::VisionOs => "XROS_DEPLOYMENT_TARGET",
356 _ => unreachable!("tried to get deployment target env var for non-Apple platform"),
357 }
358}