Skip to content

Add support for link-flavor rust-lld for macOS #100286

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2674,11 +2674,16 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
let os = &sess.target.os;
let llvm_target = &sess.target.llvm_target;
if sess.target.vendor != "apple"
|| !matches!(os.as_ref(), "ios" | "tvos" | "watchos")
|| !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "macos")
|| (flavor != LinkerFlavor::Gcc && flavor != LinkerFlavor::Lld(LldFlavor::Ld64))
{
return;
}

if os == "macos" && flavor != LinkerFlavor::Lld(LldFlavor::Ld64) {
return;
}

let sdk_name = match (arch.as_ref(), os.as_ref()) {
("aarch64", "tvos") => "appletvos",
("x86_64", "tvos") => "appletvsimulator",
Expand All @@ -2694,6 +2699,7 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
("aarch64", "watchos") if llvm_target.ends_with("-simulator") => "watchsimulator",
("aarch64", "watchos") => "watchos",
("arm", "watchos") => "watchos",
(_, "macos") => "macosx",
_ => {
sess.err(&format!("unsupported arch `{}` for os `{}`", arch, os));
return;
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, Target, TargetOptions};
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};

pub fn target() -> Target {
let mut base = super::apple_base::opts("macos");
let arch = "arm64";
let mut base = super::apple_base::opts("macos", arch, "");
base.cpu = "apple-a14".into();
base.max_atomic_width = Some(128);

// FIXME: The leak sanitizer currently fails the tests, see #88132.
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;

base.add_pre_link_args(LinkerFlavor::Gcc, &["-arch", "arm64"]);
base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());

// Clang automatically chooses a more specific target based on
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
// correctly, we do too.
let llvm_target = super::apple_base::macos_llvm_target("arm64");
let llvm_target = super::apple_base::macos_llvm_target(arch);

Target {
llvm_target: llvm_target.into(),
Expand Down
53 changes: 48 additions & 5 deletions compiler/rustc_target/src/spec/apple_base.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,45 @@
use std::{borrow::Cow, env};

use crate::spec::{cvs, FramePointer, LldFlavor, SplitDebuginfo, TargetOptions};
use crate::spec::{cvs, FramePointer, SplitDebuginfo, TargetOptions};
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor};

fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs {
let mut args = LinkArgs::new();

let platform_name = match abi {
"sim" => format!("{}-simulator", os),
"macabi" => "mac-catalyst".to_string(),
_ => os.to_string(),
};

let platform_version = match os.as_ref() {
"ios" => ios_lld_platform_version(),
"tvos" => tvos_lld_platform_version(),
"watchos" => watchos_lld_platform_version(),
"macos" => macos_lld_platform_version(arch),
_ => unreachable!(),
};

if abi != "macabi" {
args.insert(LinkerFlavor::Gcc, vec!["-arch".into(), arch.into()]);
}

args.insert(
LinkerFlavor::Lld(LldFlavor::Ld64),
vec![
"-arch".into(),
arch.into(),
"-platform_version".into(),
platform_name.into(),
platform_version.clone().into(),
platform_version.into(),
],
);

args
}

pub fn opts(os: &'static str) -> TargetOptions {
pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOptions {
// ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
// either the linker will complain if it is used or the binary will end up
// segfaulting at runtime when run on 10.6. Rust by default supports macOS
Expand All @@ -24,6 +61,7 @@ pub fn opts(os: &'static str) -> TargetOptions {
// macOS has -dead_strip, which doesn't rely on function_sections
function_sections: false,
dynamic_linking: true,
pre_link_args: pre_link_args(os, arch, abi),
linker_is_gnu: false,
families: cvs!["unix"],
is_like_osx: true,
Expand Down Expand Up @@ -73,6 +111,11 @@ fn macos_deployment_target(arch: &str) -> (u32, u32) {
.unwrap_or_else(|| macos_default_deployment_target(arch))
}

fn macos_lld_platform_version(arch: &str) -> String {
let (major, minor) = macos_deployment_target(arch);
format!("{}.{}", major, minor)
}

pub fn macos_llvm_target(arch: &str) -> String {
let (major, minor) = macos_deployment_target(arch);
format!("{}-apple-macosx{}.{}.0", arch, major, minor)
Expand Down Expand Up @@ -109,7 +152,7 @@ pub fn ios_llvm_target(arch: &str) -> String {
format!("{}-apple-ios{}.{}.0", arch, major, minor)
}

pub fn ios_lld_platform_version() -> String {
fn ios_lld_platform_version() -> String {
let (major, minor) = ios_deployment_target();
format!("{}.{}", major, minor)
}
Expand All @@ -123,7 +166,7 @@ fn tvos_deployment_target() -> (u32, u32) {
deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
}

pub fn tvos_lld_platform_version() -> String {
fn tvos_lld_platform_version() -> String {
let (major, minor) = tvos_deployment_target();
format!("{}.{}", major, minor)
}
Expand All @@ -132,7 +175,7 @@ fn watchos_deployment_target() -> (u32, u32) {
deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
}

pub fn watchos_lld_platform_version() -> String {
fn watchos_lld_platform_version() -> String {
let (major, minor) = watchos_deployment_target();
format!("{}.{}", major, minor)
}
Expand Down
44 changes: 2 additions & 42 deletions compiler/rustc_target/src/spec/apple_sdk_base.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::spec::{cvs, LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
use crate::spec::{cvs, TargetOptions};
use std::borrow::Cow;

use Arch::*;
Expand Down Expand Up @@ -61,53 +61,13 @@ fn link_env_remove(arch: Arch) -> Cow<'static, [Cow<'static, str>]> {
}
}

fn pre_link_args(os: &'static str, arch: Arch) -> LinkArgs {
let mut args = LinkArgs::new();

let target_abi = target_abi(arch);

let platform_name = match target_abi {
"sim" => format!("{}-simulator", os),
"macabi" => "mac-catalyst".to_string(),
_ => os.to_string(),
};

let platform_version = match os.as_ref() {
"ios" => super::apple_base::ios_lld_platform_version(),
"tvos" => super::apple_base::tvos_lld_platform_version(),
"watchos" => super::apple_base::watchos_lld_platform_version(),
_ => unreachable!(),
};

let arch_str = target_arch_name(arch);

if target_abi != "macabi" {
args.insert(LinkerFlavor::Gcc, vec!["-arch".into(), arch_str.into()]);
}

args.insert(
LinkerFlavor::Lld(LldFlavor::Ld64),
vec![
"-arch".into(),
arch_str.into(),
"-platform_version".into(),
platform_name.into(),
platform_version.clone().into(),
platform_version.into(),
],
);

args
}

pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
TargetOptions {
abi: target_abi(arch).into(),
cpu: target_cpu(arch).into(),
dynamic_linking: false,
pre_link_args: pre_link_args(os, arch),
link_env_remove: link_env_remove(arch),
has_thread_local: false,
..super::apple_base::opts(os)
..super::apple_base::opts(os, target_arch_name(arch), target_abi(arch))
}
}
3 changes: 2 additions & 1 deletion compiler/rustc_target/src/spec/i686_apple_darwin.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::spec::{FramePointer, LinkerFlavor, StackProbeType, Target, TargetOptions};

pub fn target() -> Target {
let mut base = super::apple_base::opts("macos");
// ld64 only understand i386 and not i686
let mut base = super::apple_base::opts("macos", "i386", "");
base.cpu = "yonah".into();
base.max_atomic_width = Some(64);
base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ use crate::spec::TargetOptions;
use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, StackProbeType, Target};

pub fn target() -> Target {
let mut base = super::apple_base::opts("macos");
let arch = "x86_64";
let mut base = super::apple_base::opts("macos", arch, "");
base.cpu = "core2".into();
base.max_atomic_width = Some(128); // core2 support cmpxchg16b
base.frame_pointer = FramePointer::Always;
base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-arch", "x86_64"]);
base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
Expand All @@ -16,7 +17,6 @@ pub fn target() -> Target {
// Clang automatically chooses a more specific target based on
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
// correctly, we do too.
let arch = "x86_64";
let llvm_target = super::apple_base::macos_llvm_target(&arch);

Target {
Expand Down