From 1d1316240f0fa60b042bcead8ab29609c0090489 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 11 Aug 2025 20:46:31 +0200 Subject: [PATCH] Always attempt to invoke xcrun to get the Apple SDK The exact reasoning why we do not always pass the SDK root when linking on macOS eludes me, but I suspect it's because we want to support compiler drivers which do not support the `-isysroot` option. Since we now pass the SDK root via the environment variable SDKROOT, compiler drivers that don't support it can just ignore it. Similarly, since we only warn when xcrun fails, users that expect their compiler driver to provide the SDK location can do so now. --- compiler/rustc_codegen_ssa/src/back/link.rs | 12 +++++--- tests/run-make/link-under-xcode/foo.rs | 1 + tests/run-make/link-under-xcode/rmake.rs | 32 +++++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 tests/run-make/link-under-xcode/foo.rs create mode 100644 tests/run-make/link-under-xcode/rmake.rs diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 49454f2d845f..4ebe59dc2a79 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3200,11 +3200,15 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> let LinkerFlavor::Darwin(cc, _) = flavor else { return None; }; - if os == "macos" && cc != Cc::No { - // FIXME(madsmtm): Remove this branch. - return None; - } + // The default compiler driver on macOS is at `/usr/bin/cc`. This is a trampoline binary that + // effectively invokes `xcrun cc` internally to look up both the compiler binary and the SDK + // root from the current Xcode installation. When cross-compiling, when `rustc` is invoked + // inside Xcode, or when invoking the linker directly, this default logic is unsuitable, so + // instead we invoke `xcrun` manually. + // + // (Note that this doesn't mean we get a duplicate lookup here - passing `SDKROOT` below will + // cause the trampoline binary to skip looking up the SDK itself). let sdkroot = sess.time("get_apple_sdk_root", || get_apple_sdk_root(sess))?; if cc == Cc::Yes { diff --git a/tests/run-make/link-under-xcode/foo.rs b/tests/run-make/link-under-xcode/foo.rs new file mode 100644 index 000000000000..f328e4d9d04c --- /dev/null +++ b/tests/run-make/link-under-xcode/foo.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make/link-under-xcode/rmake.rs b/tests/run-make/link-under-xcode/rmake.rs new file mode 100644 index 000000000000..c9394feb000a --- /dev/null +++ b/tests/run-make/link-under-xcode/rmake.rs @@ -0,0 +1,32 @@ +//! Test that linking works under an environment similar to what Xcode sets up. +//! +//! Regression test for https://github.com/rust-lang/rust/issues/80817. + +//@ only-apple + +use run_make_support::{cmd, rustc, target}; + +fn main() { + // Fetch toolchain `/usr/bin` directory. Usually: + // /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin + let clang_bin = cmd("xcrun").arg("--find").arg("clang").run().stdout_utf8(); + let toolchain_bin = clang_bin.trim().strip_suffix("/clang").unwrap(); + + // Put toolchain directory at the front of PATH. + let path = format!("{}:{}", toolchain_bin, std::env::var("PATH").unwrap()); + + // Check that compiling and linking still works. + // + // Removing `SDKROOT` is necessary for the test to excercise what we want, since bootstrap runs + // under `/usr/bin/python3`, which will set SDKROOT for us. + rustc().target(target()).env_remove("SDKROOT").env("PATH", &path).input("foo.rs").run(); + + // Also check linking directly with the system linker. + rustc() + .target(target()) + .env_remove("SDKROOT") + .env("PATH", &path) + .input("foo.rs") + .arg("-Clinker-flavor=ld") + .run(); +}