diff --git a/src/librustc_target/spec/apple_base.rs b/src/librustc_target/spec/apple_base.rs index a8d6290aa43..e2632fc1414 100644 --- a/src/librustc_target/spec/apple_base.rs +++ b/src/librustc_target/spec/apple_base.rs @@ -1,4 +1,4 @@ -use std::{env, path::Path}; +use std::env; use crate::spec::{LinkArgs, TargetOptions}; @@ -52,62 +52,18 @@ pub fn macos_llvm_target(arch: &str) -> String { format!("{}-apple-macosx{}.{}.0", arch, major, minor) } -#[cfg(target_os = "macos")] -pub fn sysroot(sdk: &str) -> Result, String> { - // Like Clang, allow the `SDKROOT` environment variable used by Xcode to define the sysroot. - if let Some(sdk_root) = env::var("SDKROOT").ok() { - let actual_sdk_path = sdk_path(sdk)?; - let sdk_root_p = Path::new(&sdk_root); - // Ignore `SDKROOT` if it's not a valid path. - if !sdk_root_p.is_absolute() || sdk_root_p == Path::new("/") || !sdk_root_p.exists() { - return Ok(Some(actual_sdk_path)); - } - // Ignore `SDKROOT` if it's clearly set for the wrong platform, which may occur when we're - // compiling a custom build script while targeting iOS for example. - return Ok(Some(match sdk { - "iphoneos" if sdk_root.contains("iPhoneSimulator.platform") - || sdk_root.contains("MacOSX.platform") => actual_sdk_path, - "iphonesimulator" if sdk_root.contains("iPhoneOS.platform") - || sdk_root.contains("MacOSX.platform") => actual_sdk_path, - "macosx" | "macosx10.15" if sdk_root.contains("iPhoneOS.platform") - || sdk_root.contains("iPhoneSimulator.platform") => actual_sdk_path, - _ => sdk_root, - })) - } - Ok(None) -} - -// `xcrun` is only available on macOS. -#[cfg(not(target_os = "macos"))] -pub fn sysroot(_sdk: &str) -> Result, String> { - if let Some(sdk_root) = env::var("SDKROOT").ok() { - let sdk_root_p = Path::new(&sdk_root); - // Use `SDKROOT` only if it's a valid path. - if sdk_root_p.is_absolute() && sdk_root_p != Path::new("/") && sdk_root_p.exists() { - return Ok(Some(sdk_root)); +pub fn macos_link_env() -> Vec<(String, String)> { + let mut env = Vec::with_capacity(2); + // Ignore the `SDKROOT` environment variable if it's clearly set for the wrong platform, which + // may occur when we're linking a custom build script while targeting iOS for example. + if let Some(sdkroot) = env::var("SDKROOT").ok() { + if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") { + env.push(("SDKROOT".to_string(), String::new())) } } - Ok(None) -} - -#[cfg(target_os = "macos")] -fn sdk_path(sdk_name: &str) -> Result { - let res = std::process::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(std::io::Error::new(std::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)), - } + // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at + // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld", + // although this is apparently ignored when using the linker at "/usr/bin/ld". + env.push(("IPHONEOS_DEPLOYMENT_TARGET".to_string(), String::new())); + env } diff --git a/src/librustc_target/spec/apple_ios_base.rs b/src/librustc_target/spec/apple_ios_base.rs index 801736944f4..6d3900c0b20 100644 --- a/src/librustc_target/spec/apple_ios_base.rs +++ b/src/librustc_target/spec/apple_ios_base.rs @@ -1,3 +1,7 @@ +use std::env; +use std::io; +use std::path::Path; +use std::process::Command; use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions}; use Arch::*; @@ -26,6 +30,42 @@ impl Arch { } } +pub fn get_sdk_root(sdk_name: &str) -> Result { + // 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 Some(sdkroot) = env::var("SDKROOT").ok() { + let sdkroot_path = Path::new(&sdkroot); + if sdkroot_path.is_absolute() && sdkroot_path != Path::new("/") && sdkroot_path.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) -> Result { let sdk_name = match arch { Armv7 | Armv7s | Arm64 => "iphoneos", @@ -35,19 +75,16 @@ fn build_pre_link_args(arch: Arch) -> Result { 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()]); - if let Some(sdk_root) = super::apple_base::sysroot(sdk_name)? { - args.insert( - LinkerFlavor::Gcc, - vec![ - "-isysroot".to_string(), - sdk_root.clone(), - "-Wl,-syslibroot".to_string(), - sdk_root - ], - ); - } + 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) } diff --git a/src/librustc_target/spec/i686_apple_darwin.rs b/src/librustc_target/spec/i686_apple_darwin.rs index b08ed560252..ba44cdccb7c 100644 --- a/src/librustc_target/spec/i686_apple_darwin.rs +++ b/src/librustc_target/spec/i686_apple_darwin.rs @@ -5,12 +5,7 @@ pub fn target() -> TargetResult { base.cpu = "yonah".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]); - if let Some(sysroot) = super::apple_base::sysroot("macosx")? { - base.pre_link_args.insert( - LinkerFlavor::Gcc, - vec!["-isysroot".to_string(), sysroot.clone(), "-Wl,-syslibroot".to_string(), sysroot], - ); - } + base.link_env.extend(super::apple_base::macos_link_env()); base.stack_probes = true; base.eliminate_frame_pointer = false; diff --git a/src/librustc_target/spec/x86_64_apple_darwin.rs b/src/librustc_target/spec/x86_64_apple_darwin.rs index f299c27e7e1..442c2650bbb 100644 --- a/src/librustc_target/spec/x86_64_apple_darwin.rs +++ b/src/librustc_target/spec/x86_64_apple_darwin.rs @@ -6,12 +6,7 @@ pub fn target() -> TargetResult { base.max_atomic_width = Some(128); // core2 support cmpxchg16b base.eliminate_frame_pointer = false; base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); - if let Some(sysroot) = super::apple_base::sysroot("macosx")? { - base.pre_link_args.insert( - LinkerFlavor::Gcc, - vec!["-isysroot".to_string(), sysroot.clone(), "-Wl,-syslibroot".to_string(), sysroot], - ); - } + base.link_env.extend(super::apple_base::macos_link_env()); base.stack_probes = true; // Clang automatically chooses a more specific target based on