diff options
| author | Mads Marquart <mads@marquart.dk> | 2025-08-11 22:29:00 +0200 |
|---|---|---|
| committer | Mads Marquart <mads@marquart.dk> | 2025-08-11 22:29:00 +0200 |
| commit | 1cc44bfd22f4db5bcf3921f4a8b64df4e9cf4124 (patch) | |
| tree | 33bd58076ecd2455726ce1ab942336e57fd1faa6 | |
| parent | 1dc37df51476b568b1fa94db14a7669656989862 (diff) | |
| download | rust-1cc44bfd22f4db5bcf3921f4a8b64df4e9cf4124.tar.gz rust-1cc44bfd22f4db5bcf3921f4a8b64df4e9cf4124.zip | |
Pass Apple SDK root to compiler driver via SDKROOT env var
This is more in-line with what Apple's tooling expects, and allows us to better support custom compiler drivers (such as certain Homebrew and Nixpkgs compilers) that prefer their own `-isysroot` flag. Effectively, we now invoke the compiler driver as-if it was invoked as `xcrun -sdk $sdk_name $tool`.
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/link.rs | 44 | ||||
| -rw-r--r-- | compiler/rustc_target/src/spec/base/apple/mod.rs | 24 | ||||
| -rw-r--r-- | src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md | 2 |
3 files changed, 39 insertions, 31 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index bda8eeb4c92..49454f2d845 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3208,15 +3208,37 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> let sdkroot = sess.time("get_apple_sdk_root", || get_apple_sdk_root(sess))?; if cc == Cc::Yes { - // Use `-isysroot` instead of `--sysroot`, as only the former - // makes Clang treat it as a platform SDK. + // There are a few options to pass the SDK root when linking with a C/C++ compiler: + // - The `--sysroot` flag. + // - The `-isysroot` flag. + // - The `SDKROOT` environment variable. // - // This is admittedly a bit strange, as on most targets - // `-isysroot` only applies to include header files, but on Apple - // targets this also applies to libraries and frameworks. - cmd.cc_arg("-isysroot"); - cmd.cc_arg(&sdk_root); + // `--sysroot` isn't actually enough to get Clang to treat it as a platform SDK, you need + // to specify `-isysroot`. This is admittedly a bit strange, as on most targets `-isysroot` + // only applies to include header files, but on Apple targets it also applies to libraries + // and frameworks. + // + // This leaves the choice between `-isysroot` and `SDKROOT`. Both are supported by Clang and + // GCC, though they may not be supported by all compiler drivers. We choose `SDKROOT`, + // primarily because that is the same interface that is used when invoking the tool under + // `xcrun -sdk macosx $tool`. + // + // In that sense, if a given compiler driver does not support `SDKROOT`, the blame is fairly + // clearly in the tool in question, since they also don't support being run under `xcrun`. + // + // Additionally, `SDKROOT` is an environment variable and thus optional. It also has lower + // precedence than `-isysroot`, so a custom compiler driver that does not support it and + // instead figures out the SDK on their own can easily do so by using `-isysroot`. + // + // (This in particular affects Clang built with the `DEFAULT_SYSROOT` CMake flag, such as + // the one provided by some versions of Homebrew's `llvm` package. Those will end up + // ignoring the value we set here, and instead use their built-in sysroot). + cmd.cmd().env("SDKROOT", &sdkroot); } else { + // When invoking the linker directly, we use the `-syslibroot` parameter. `SDKROOT` is not + // read by the linker, so it's really the only option. + // + // This is also what Clang does. cmd.link_arg("-syslibroot"); cmd.link_arg(&sdkroot); } @@ -3250,7 +3272,13 @@ fn get_apple_sdk_root(sess: &Session) -> Option<PathBuf> { } "macosx" if sdkroot.contains("iPhoneOS.platform") - || sdkroot.contains("iPhoneSimulator.platform") => {} + || sdkroot.contains("iPhoneSimulator.platform") + || sdkroot.contains("AppleTVOS.platform") + || sdkroot.contains("AppleTVSimulator.platform") + || sdkroot.contains("WatchOS.platform") + || sdkroot.contains("WatchSimulator.platform") + || sdkroot.contains("XROS.platform") + || sdkroot.contains("XRSimulator.platform") => {} "watchos" if sdkroot.contains("WatchSimulator.platform") || sdkroot.contains("MacOSX.platform") => {} diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index da9f96ce37d..ecc74264160 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -1,5 +1,4 @@ use std::borrow::Cow; -use std::env; use std::fmt::{Display, from_fn}; use std::num::ParseIntError; use std::str::FromStr; @@ -209,29 +208,10 @@ fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> { // that's only applicable to cross-OS compilation. Always leave anything for the // host OS alone though. if os == "macos" { - let mut env_remove = Vec::with_capacity(2); - // Remove 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 Ok(sdkroot) = env::var("SDKROOT") { - if sdkroot.contains("iPhoneOS.platform") - || sdkroot.contains("iPhoneSimulator.platform") - || sdkroot.contains("AppleTVOS.platform") - || sdkroot.contains("AppleTVSimulator.platform") - || sdkroot.contains("WatchOS.platform") - || sdkroot.contains("WatchSimulator.platform") - || sdkroot.contains("XROS.platform") - || sdkroot.contains("XRSimulator.platform") - { - env_remove.push("SDKROOT".into()) - } - } - // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at + // `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_remove.push("IPHONEOS_DEPLOYMENT_TARGET".into()); - env_remove.push("TVOS_DEPLOYMENT_TARGET".into()); - env_remove.push("XROS_DEPLOYMENT_TARGET".into()); - env_remove.into() + cvs!["IPHONEOS_DEPLOYMENT_TARGET", "TVOS_DEPLOYMENT_TARGET", "XROS_DEPLOYMENT_TARGET"] } else { // Otherwise if cross-compiling for a different OS/SDK (including Mac Catalyst), remove any part // of the linking environment that's wrong and reversed. diff --git a/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md b/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md index be9ed02f54d..6d371ae289f 100644 --- a/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md +++ b/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md @@ -1,6 +1,6 @@ # `SDKROOT` This environment variable is used on Apple targets. -It is passed through to the linker (currently either as `-isysroot` or `-syslibroot`). +It is passed through to the linker (currently either directly or via the `-syslibroot` flag). Note that this variable is not always respected. When the SDKROOT is clearly wrong (e.g. when the platform of the SDK does not match the `--target` used by rustc), this is ignored and rustc does its own detection. |
