about summary refs log tree commit diff
path: root/compiler/rustc_target/src/spec/apple_sdk_base.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_target/src/spec/apple_sdk_base.rs')
-rw-r--r--compiler/rustc_target/src/spec/apple_sdk_base.rs151
1 files changed, 151 insertions, 0 deletions
diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs
new file mode 100644
index 00000000000..0d0a0da9d1c
--- /dev/null
+++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs
@@ -0,0 +1,151 @@
+use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
+use std::env;
+use std::io;
+use std::path::Path;
+use std::process::Command;
+
+use Arch::*;
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone)]
+pub enum Arch {
+    Armv7,
+    Armv7s,
+    Arm64,
+    I386,
+    X86_64,
+    X86_64_macabi,
+}
+
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone)]
+pub enum AppleOS {
+    tvOS,
+    iOS,
+}
+
+impl Arch {
+    pub fn to_string(self) -> &'static str {
+        match self {
+            Armv7 => "armv7",
+            Armv7s => "armv7s",
+            Arm64 => "arm64",
+            I386 => "i386",
+            X86_64 => "x86_64",
+            X86_64_macabi => "x86_64",
+        }
+    }
+}
+
+pub fn get_sdk_root(sdk_name: &str) -> Result<String, String> {
+    // Following what clang does
+    // (https://github.com/llvm/llvm-project/blob/
+    // 296a80102a9b72c3eda80558fb78a3ed8849b341/clang/lib/Driver/ToolChains/Darwin.cpp#L1661-L1678)
+    // to allow the SDK path to be set. (For clang, xcrun sets
+    // SDKROOT; for rustc, the user or build system can set it, or we
+    // can fall back to checking for xcrun on PATH.)
+    if let Ok(sdkroot) = env::var("SDKROOT") {
+        let p = Path::new(&sdkroot);
+        match sdk_name {
+            // Ignore `SDKROOT` if it's clearly set for the wrong platform.
+            "appletvos"
+                if sdkroot.contains("TVSimulator.platform")
+                    || sdkroot.contains("MacOSX.platform") => {}
+            "appletvsimulator"
+                if sdkroot.contains("TVOS.platform") || sdkroot.contains("MacOSX.platform") => {}
+            "iphoneos"
+                if sdkroot.contains("iPhoneSimulator.platform")
+                    || sdkroot.contains("MacOSX.platform") => {}
+            "iphonesimulator"
+                if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("MacOSX.platform") => {
+            }
+            "macosx10.15"
+                if sdkroot.contains("iPhoneOS.platform")
+                    || sdkroot.contains("iPhoneSimulator.platform") => {}
+            // Ignore `SDKROOT` if it's not a valid path.
+            _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {}
+            _ => return Ok(sdkroot),
+        }
+    }
+    let res =
+        Command::new("xcrun").arg("--show-sdk-path").arg("-sdk").arg(sdk_name).output().and_then(
+            |output| {
+                if output.status.success() {
+                    Ok(String::from_utf8(output.stdout).unwrap())
+                } else {
+                    let error = String::from_utf8(output.stderr);
+                    let error = format!("process exit with error: {}", error.unwrap());
+                    Err(io::Error::new(io::ErrorKind::Other, &error[..]))
+                }
+            },
+        );
+
+    match res {
+        Ok(output) => Ok(output.trim().to_string()),
+        Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)),
+    }
+}
+
+fn build_pre_link_args(arch: Arch, os: AppleOS) -> Result<LinkArgs, String> {
+    let sdk_name = match (arch, os) {
+        (Arm64, AppleOS::tvOS) => "appletvos",
+        (X86_64, AppleOS::tvOS) => "appletvsimulator",
+        (Armv7, AppleOS::iOS) => "iphoneos",
+        (Armv7s, AppleOS::iOS) => "iphoneos",
+        (Arm64, AppleOS::iOS) => "iphoneos",
+        (I386, AppleOS::iOS) => "iphonesimulator",
+        (X86_64, AppleOS::iOS) => "iphonesimulator",
+        (X86_64_macabi, AppleOS::iOS) => "macosx10.15",
+        _ => unreachable!(),
+    };
+
+    let arch_name = arch.to_string();
+
+    let sdk_root = get_sdk_root(sdk_name)?;
+
+    let mut args = LinkArgs::new();
+    args.insert(
+        LinkerFlavor::Gcc,
+        vec![
+            "-arch".to_string(),
+            arch_name.to_string(),
+            "-isysroot".to_string(),
+            sdk_root.clone(),
+            "-Wl,-syslibroot".to_string(),
+            sdk_root,
+        ],
+    );
+
+    Ok(args)
+}
+
+fn target_cpu(arch: Arch) -> String {
+    match arch {
+        Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher
+        Armv7s => "cortex-a9",
+        Arm64 => "apple-a7",
+        I386 => "yonah",
+        X86_64 => "core2",
+        X86_64_macabi => "core2",
+    }
+    .to_string()
+}
+
+fn link_env_remove(arch: Arch) -> Vec<String> {
+    match arch {
+        Armv7 | Armv7s | Arm64 | I386 | X86_64 => vec!["MACOSX_DEPLOYMENT_TARGET".to_string()],
+        X86_64_macabi => vec!["IPHONEOS_DEPLOYMENT_TARGET".to_string()],
+    }
+}
+
+pub fn opts(arch: Arch, os: AppleOS) -> Result<TargetOptions, String> {
+    let pre_link_args = build_pre_link_args(arch, os)?;
+    Ok(TargetOptions {
+        cpu: target_cpu(arch),
+        executables: true,
+        pre_link_args,
+        link_env_remove: link_env_remove(arch),
+        has_elf_tls: false,
+        eliminate_frame_pointer: false,
+        ..super::apple_base::opts()
+    })
+}