about summary refs log tree commit diff
path: root/compiler/rustc_codegen_ssa
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-09-27 17:28:47 +0000
committerbors <bors@rust-lang.org>2024-09-27 17:28:47 +0000
commitfa724e5d8cbbdfbd1e53c4c656121af01b694406 (patch)
treecb03957ec3e5050d456cb76445a55c146af42ce6 /compiler/rustc_codegen_ssa
parenta3f76a26e045a760bb1163b7eab36872985242d5 (diff)
parent966a0b76bc21ba65071b4d50dfb0536e0581604f (diff)
downloadrust-fa724e5d8cbbdfbd1e53c4c656121af01b694406.tar.gz
rust-fa724e5d8cbbdfbd1e53c4c656121af01b694406.zip
Auto merge of #130934 - matthiaskrgr:rollup-4puticr, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #129087 (Stabilize `option_get_or_insert_default`)
 - #130435 (Move Apple linker args from `rustc_target` to `rustc_codegen_ssa`)
 - #130459 (delete sub build directory "debug" to not delete the change-id file)
 - #130873 (rustc_target: Add powerpc64 atomic-related features)
 - #130916 (Use `&raw` in the compiler)
 - #130917 (Fix error span if arg to `asm!()` is a macro call)
 - #130927 (update outdated comments)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_codegen_ssa')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs133
1 files changed, 132 insertions, 1 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 69693230ce0..80e8111516e 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -40,7 +40,7 @@ use rustc_target::spec::crt_objects::CrtObjects;
 use rustc_target::spec::{
     Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures,
     LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, SanitizerSet,
-    SplitDebuginfo,
+    SplitDebuginfo, current_apple_deployment_target,
 };
 use tempfile::Builder as TempFileBuilder;
 use tracing::{debug, info, warn};
@@ -2405,6 +2405,8 @@ fn add_order_independent_options(
     // Take care of the flavors and CLI options requesting the `lld` linker.
     add_lld_args(cmd, sess, flavor, self_contained_components);
 
+    add_apple_link_args(cmd, sess, flavor);
+
     let apple_sdk_root = add_apple_sdk(cmd, sess, flavor);
 
     add_link_script(cmd, sess, tmpdir, crate_type);
@@ -2957,6 +2959,135 @@ pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool
     }
 }
 
+/// We need to communicate four things to the linker on Apple/Darwin targets:
+/// - The architecture.
+/// - The operating system (and that it's an Apple platform).
+/// - The deployment target.
+/// - The environment / ABI.
+fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
+    if !sess.target.is_like_osx {
+        return;
+    }
+    let LinkerFlavor::Darwin(cc, _) = flavor else {
+        return;
+    };
+
+    // `sess.target.arch` (`target_arch`) is not detailed enough.
+    let llvm_arch = sess.target.llvm_target.split_once('-').expect("LLVM target must have arch").0;
+    let target_os = &*sess.target.os;
+    let target_abi = &*sess.target.abi;
+
+    // The architecture name to forward to the linker.
+    //
+    // Supported architecture names can be found in the source:
+    // https://github.com/apple-oss-distributions/ld64/blob/ld64-951.9/src/abstraction/MachOFileAbstraction.hpp#L578-L648
+    //
+    // Intentially verbose to ensure that the list always matches correctly
+    // with the list in the source above.
+    let ld64_arch = match llvm_arch {
+        "armv7k" => "armv7k",
+        "armv7s" => "armv7s",
+        "arm64" => "arm64",
+        "arm64e" => "arm64e",
+        "arm64_32" => "arm64_32",
+        // ld64 doesn't understand i686, so fall back to i386 instead.
+        //
+        // Same story when linking with cc, since that ends up invoking ld64.
+        "i386" | "i686" => "i386",
+        "x86_64" => "x86_64",
+        "x86_64h" => "x86_64h",
+        _ => bug!("unsupported architecture in Apple target: {}", sess.target.llvm_target),
+    };
+
+    if cc == Cc::No {
+        // From the man page for ld64 (`man ld`):
+        // > The linker accepts universal (multiple-architecture) input files,
+        // > but always creates a "thin" (single-architecture), standard
+        // > Mach-O output file. The architecture for the output file is
+        // > specified using the -arch option.
+        //
+        // The linker has heuristics to determine the desired architecture,
+        // but to be safe, and to avoid a warning, we set the architecture
+        // explicitly.
+        cmd.link_args(&["-arch", ld64_arch]);
+
+        // Man page says that ld64 supports the following platform names:
+        // > - macos
+        // > - ios
+        // > - tvos
+        // > - watchos
+        // > - bridgeos
+        // > - visionos
+        // > - xros
+        // > - mac-catalyst
+        // > - ios-simulator
+        // > - tvos-simulator
+        // > - watchos-simulator
+        // > - visionos-simulator
+        // > - xros-simulator
+        // > - driverkit
+        let platform_name = match (target_os, target_abi) {
+            (os, "") => os,
+            ("ios", "macabi") => "mac-catalyst",
+            ("ios", "sim") => "ios-simulator",
+            ("tvos", "sim") => "tvos-simulator",
+            ("watchos", "sim") => "watchos-simulator",
+            ("visionos", "sim") => "visionos-simulator",
+            _ => bug!("invalid OS/ABI combination for Apple target: {target_os}, {target_abi}"),
+        };
+
+        let (major, minor, patch) = current_apple_deployment_target(&sess.target);
+        let min_version = format!("{major}.{minor}.{patch}");
+
+        // Lie about the SDK version, we don't know it here
+        let sdk_version = &*min_version;
+
+        // From the man page for ld64 (`man ld`):
+        // > This is set to indicate the platform, oldest supported version of
+        // > that platform that output is to be used on, and the SDK that the
+        // > output was built against.
+        //
+        // Like with `-arch`, the linker can figure out the platform versions
+        // itself from the binaries being linked, but to be safe, we specify
+        // the desired versions here explicitly.
+        cmd.link_args(&["-platform_version", platform_name, &*min_version, sdk_version]);
+    } else {
+        // cc == Cc::Yes
+        // We'd _like_ to use `-target` everywhere, since that can uniquely
+        // communicate all the required details, but that doesn't work on GCC,
+        // and since we don't know whether the `cc` compiler is Clang, GCC, or
+        // something else, we fall back to other options that also work on GCC
+        // when compiling for macOS.
+        //
+        // Targets other than macOS are ill-supported by GCC (it doesn't even
+        // support e.g. `-miphoneos-version-min`), so in those cases we can
+        // fairly safely use `-target`. See also the following, where it is
+        // made explicit that the recommendation by LLVM developers is to use
+        // `-target`: <https://github.com/llvm/llvm-project/issues/88271>
+        if target_os == "macos" {
+            // `-arch` communicates the architecture.
+            //
+            // CC forwards the `-arch` to the linker, so we use the same value
+            // here intentionally.
+            cmd.cc_args(&["-arch", ld64_arch]);
+
+            // The presence of `-mmacosx-version-min` makes CC default to
+            // macOS, and it sets the deployment target.
+            let (major, minor, patch) = current_apple_deployment_target(&sess.target);
+            // Intentionally pass this as a single argument, Clang doesn't
+            // seem to like it otherwise.
+            cmd.cc_arg(&format!("-mmacosx-version-min={major}.{minor}.{patch}"));
+
+            // macOS has no environment, so with these two, we've told CC the
+            // four desired parameters.
+            //
+            // We avoid `-m32`/`-m64`, as this is already encoded by `-arch`.
+        } else {
+            cmd.cc_args(&["-target", &sess.target.llvm_target]);
+        }
+    }
+}
+
 fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> Option<PathBuf> {
     let arch = &sess.target.arch;
     let os = &sess.target.os;