]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_target/src/spec/apple_base.rs
Rollup merge of #87904 - kpreid:unsize, r=jyn514
[rust.git] / compiler / rustc_target / src / spec / apple_base.rs
1 use std::env;
2
3 use crate::spec::{FramePointer, LldFlavor, SplitDebuginfo, TargetOptions};
4
5 pub fn opts(os: &str) -> TargetOptions {
6     // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
7     // either the linker will complain if it is used or the binary will end up
8     // segfaulting at runtime when run on 10.6. Rust by default supports macOS
9     // 10.7+, but there is a standard environment variable,
10     // MACOSX_DEPLOYMENT_TARGET, which is used to signal targeting older
11     // versions of macOS. For example compiling on 10.10 with
12     // MACOSX_DEPLOYMENT_TARGET set to 10.6 will cause the linker to generate
13     // warnings about the usage of ELF TLS.
14     //
15     // Here we detect what version is being requested, defaulting to 10.7. ELF
16     // TLS is flagged as enabled if it looks to be supported.
17     let version = macos_deployment_target();
18
19     TargetOptions {
20         os: os.to_string(),
21         vendor: "apple".to_string(),
22         // macOS has -dead_strip, which doesn't rely on function_sections
23         function_sections: false,
24         dynamic_linking: true,
25         linker_is_gnu: false,
26         executables: true,
27         families: vec!["unix".to_string()],
28         is_like_osx: true,
29         dwarf_version: Some(2),
30         frame_pointer: FramePointer::Always,
31         has_rpath: true,
32         dll_suffix: ".dylib".to_string(),
33         archive_format: "darwin".to_string(),
34         has_elf_tls: version >= (10, 7),
35         abi_return_struct_as_int: true,
36         emit_debug_gdb_scripts: false,
37         eh_frame_header: false,
38         lld_flavor: LldFlavor::Ld64,
39
40         // The historical default for macOS targets is to run `dsymutil` which
41         // generates a packed version of debuginfo split from the main file.
42         split_debuginfo: SplitDebuginfo::Packed,
43
44         // This environment variable is pretty magical but is intended for
45         // producing deterministic builds. This was first discovered to be used
46         // by the `ar` tool as a way to control whether or not mtime entries in
47         // the archive headers were set to zero or not. It appears that
48         // eventually the linker got updated to do the same thing and now reads
49         // this environment variable too in recent versions.
50         //
51         // For some more info see the commentary on #47086
52         link_env: vec![("ZERO_AR_DATE".to_string(), "1".to_string())],
53
54         ..Default::default()
55     }
56 }
57
58 fn deployment_target(var_name: &str) -> Option<(u32, u32)> {
59     let deployment_target = env::var(var_name).ok();
60     deployment_target
61         .as_ref()
62         .and_then(|s| s.split_once('.'))
63         .and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok())
64 }
65
66 fn macos_deployment_target() -> (u32, u32) {
67     deployment_target("MACOSX_DEPLOYMENT_TARGET").unwrap_or((10, 7))
68 }
69
70 pub fn macos_llvm_target(arch: &str) -> String {
71     let (major, minor) = macos_deployment_target();
72     format!("{}-apple-macosx{}.{}.0", arch, major, minor)
73 }
74
75 pub fn macos_link_env_remove() -> Vec<String> {
76     let mut env_remove = Vec::with_capacity(2);
77     // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which
78     // may occur when we're linking a custom build script while targeting iOS for example.
79     if let Ok(sdkroot) = env::var("SDKROOT") {
80         if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") {
81             env_remove.push("SDKROOT".to_string())
82         }
83     }
84     // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
85     // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld",
86     // although this is apparently ignored when using the linker at "/usr/bin/ld".
87     env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".to_string());
88     env_remove
89 }
90
91 fn ios_deployment_target() -> (u32, u32) {
92     deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
93 }
94
95 pub fn ios_llvm_target(arch: &str) -> String {
96     // Modern iOS tooling extracts information about deployment target
97     // from LC_BUILD_VERSION. This load command will only be emitted when
98     // we build with a version specific `llvm_target`, with the version
99     // set high enough. Luckily one LC_BUILD_VERSION is enough, for Xcode
100     // to pick it up (since std and core are still built with the fallback
101     // of version 7.0 and hence emit the old LC_IPHONE_MIN_VERSION).
102     let (major, minor) = ios_deployment_target();
103     format!("{}-apple-ios{}.{}.0", arch, major, minor)
104 }
105
106 pub fn ios_sim_llvm_target(arch: &str) -> String {
107     let (major, minor) = ios_deployment_target();
108     format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
109 }