]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_target/src/spec/apple_base.rs
Rollup merge of #101298 - notriddle:notriddle/rustdoc-main-since, r=GuillaumeGomez
[rust.git] / compiler / rustc_target / src / spec / apple_base.rs
1 use std::{borrow::Cow, env};
2
3 use crate::spec::{cvs, DebuginfoKind, FramePointer, SplitDebuginfo, StaticCow, TargetOptions};
4 use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor};
5
6 fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs {
7     let platform_name: StaticCow<str> = match abi {
8         "sim" => format!("{}-simulator", os).into(),
9         "macabi" => "mac-catalyst".into(),
10         _ => os.into(),
11     };
12
13     let platform_version: StaticCow<str> = match os.as_ref() {
14         "ios" => ios_lld_platform_version(),
15         "tvos" => tvos_lld_platform_version(),
16         "watchos" => watchos_lld_platform_version(),
17         "macos" => macos_lld_platform_version(arch),
18         _ => unreachable!(),
19     }
20     .into();
21
22     let mut args = TargetOptions::link_args(
23         LinkerFlavor::Lld(LldFlavor::Ld64),
24         &["-arch", arch, "-platform_version"],
25     );
26     // Manually add owned args unsupported by link arg building helpers.
27     args.entry(LinkerFlavor::Lld(LldFlavor::Ld64)).or_default().extend([
28         platform_name,
29         platform_version.clone(),
30         platform_version,
31     ]);
32     if abi != "macabi" {
33         super::add_link_args(&mut args, LinkerFlavor::Gcc, &["-arch", arch]);
34     }
35
36     args
37 }
38
39 pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOptions {
40     // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
41     // either the linker will complain if it is used or the binary will end up
42     // segfaulting at runtime when run on 10.6. Rust by default supports macOS
43     // 10.7+, but there is a standard environment variable,
44     // MACOSX_DEPLOYMENT_TARGET, which is used to signal targeting older
45     // versions of macOS. For example compiling on 10.10 with
46     // MACOSX_DEPLOYMENT_TARGET set to 10.6 will cause the linker to generate
47     // warnings about the usage of ELF TLS.
48     //
49     // Here we detect what version is being requested, defaulting to 10.7. ELF
50     // TLS is flagged as enabled if it looks to be supported. The architecture
51     // only matters for default deployment target which is 11.0 for ARM64 and
52     // 10.7 for everything else.
53     let has_thread_local = macos_deployment_target("x86_64") >= (10, 7);
54
55     TargetOptions {
56         os: os.into(),
57         vendor: "apple".into(),
58         // macOS has -dead_strip, which doesn't rely on function_sections
59         function_sections: false,
60         dynamic_linking: true,
61         pre_link_args: pre_link_args(os, arch, abi),
62         linker_is_gnu: false,
63         families: cvs!["unix"],
64         is_like_osx: true,
65         default_dwarf_version: 2,
66         frame_pointer: FramePointer::Always,
67         has_rpath: true,
68         dll_suffix: ".dylib".into(),
69         archive_format: "darwin".into(),
70         has_thread_local,
71         abi_return_struct_as_int: true,
72         emit_debug_gdb_scripts: false,
73         eh_frame_header: false,
74         lld_flavor: LldFlavor::Ld64,
75
76         debuginfo_kind: DebuginfoKind::DwarfDsym,
77         // The historical default for macOS targets is to run `dsymutil` which
78         // generates a packed version of debuginfo split from the main file.
79         split_debuginfo: SplitDebuginfo::Packed,
80         supported_split_debuginfo: Cow::Borrowed(&[
81             SplitDebuginfo::Packed,
82             SplitDebuginfo::Unpacked,
83             SplitDebuginfo::Off,
84         ]),
85
86         // This environment variable is pretty magical but is intended for
87         // producing deterministic builds. This was first discovered to be used
88         // by the `ar` tool as a way to control whether or not mtime entries in
89         // the archive headers were set to zero or not. It appears that
90         // eventually the linker got updated to do the same thing and now reads
91         // this environment variable too in recent versions.
92         //
93         // For some more info see the commentary on #47086
94         link_env: Cow::Borrowed(&[(Cow::Borrowed("ZERO_AR_DATE"), Cow::Borrowed("1"))]),
95
96         ..Default::default()
97     }
98 }
99
100 fn deployment_target(var_name: &str) -> Option<(u32, u32)> {
101     let deployment_target = env::var(var_name).ok();
102     deployment_target
103         .as_ref()
104         .and_then(|s| s.split_once('.'))
105         .and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok())
106 }
107
108 fn macos_default_deployment_target(arch: &str) -> (u32, u32) {
109     if arch == "arm64" { (11, 0) } else { (10, 7) }
110 }
111
112 fn macos_deployment_target(arch: &str) -> (u32, u32) {
113     deployment_target("MACOSX_DEPLOYMENT_TARGET")
114         .unwrap_or_else(|| macos_default_deployment_target(arch))
115 }
116
117 fn macos_lld_platform_version(arch: &str) -> String {
118     let (major, minor) = macos_deployment_target(arch);
119     format!("{}.{}", major, minor)
120 }
121
122 pub fn macos_llvm_target(arch: &str) -> String {
123     let (major, minor) = macos_deployment_target(arch);
124     format!("{}-apple-macosx{}.{}.0", arch, major, minor)
125 }
126
127 pub fn macos_link_env_remove() -> Vec<StaticCow<str>> {
128     let mut env_remove = Vec::with_capacity(2);
129     // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which
130     // may occur when we're linking a custom build script while targeting iOS for example.
131     if let Ok(sdkroot) = env::var("SDKROOT") {
132         if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") {
133             env_remove.push("SDKROOT".into())
134         }
135     }
136     // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
137     // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld",
138     // although this is apparently ignored when using the linker at "/usr/bin/ld".
139     env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".into());
140     env_remove
141 }
142
143 fn ios_deployment_target() -> (u32, u32) {
144     deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
145 }
146
147 pub fn ios_llvm_target(arch: &str) -> String {
148     // Modern iOS tooling extracts information about deployment target
149     // from LC_BUILD_VERSION. This load command will only be emitted when
150     // we build with a version specific `llvm_target`, with the version
151     // set high enough. Luckily one LC_BUILD_VERSION is enough, for Xcode
152     // to pick it up (since std and core are still built with the fallback
153     // of version 7.0 and hence emit the old LC_IPHONE_MIN_VERSION).
154     let (major, minor) = ios_deployment_target();
155     format!("{}-apple-ios{}.{}.0", arch, major, minor)
156 }
157
158 fn ios_lld_platform_version() -> String {
159     let (major, minor) = ios_deployment_target();
160     format!("{}.{}", major, minor)
161 }
162
163 pub fn ios_sim_llvm_target(arch: &str) -> String {
164     let (major, minor) = ios_deployment_target();
165     format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
166 }
167
168 fn tvos_deployment_target() -> (u32, u32) {
169     deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
170 }
171
172 fn tvos_lld_platform_version() -> String {
173     let (major, minor) = tvos_deployment_target();
174     format!("{}.{}", major, minor)
175 }
176
177 fn watchos_deployment_target() -> (u32, u32) {
178     deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
179 }
180
181 fn watchos_lld_platform_version() -> String {
182     let (major, minor) = watchos_deployment_target();
183     format!("{}.{}", major, minor)
184 }
185
186 pub fn watchos_sim_llvm_target(arch: &str) -> String {
187     let (major, minor) = watchos_deployment_target();
188     format!("{}-apple-watchos{}.{}.0-simulator", arch, major, minor)
189 }