Skip to content

Use the linker directly on darwin,ios #46255

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

Closed
wants to merge 2 commits into from
Closed
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
22 changes: 13 additions & 9 deletions src/bootstrap/bin/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,31 +206,35 @@ fn main() {
// Cargo will be very different than the runtime directory structure.
//
// All that's a really long winded way of saying that if we use
// `-Crpath` then the executables generated have the wrong rpath of
// `-C rpath` then the executables generated have the wrong rpath of
// something like `$ORIGIN/deps` when in fact the way we distribute
// rustc requires the rpath to be `$ORIGIN/../lib`.
//
// So, all in all, to set up the correct rpath we pass the linker
// argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
// argument manually via `-C link-args=-rpath,...`. Plus isn't it
// fun to pass a flag to a tool to pass a flag to pass a flag to a tool
// to change a flag in a binary?
if env::var("RUSTC_RPATH") == Ok("true".to_string()) {
let rpath = if target.contains("apple") {

let rpath_flags = if target.contains("apple") {
// Note that we need to take one extra step on macOS to also pass
// `-Wl,-instal_name,@rpath/...` to get things to work right. To
// `-install_name,@rpath/...` to get things to work right. To
// do that we pass a weird flag to the compiler to get it to do
// so. Note that this is definitely a hack, and we should likely
// flesh out rpath support more fully in the future.
cmd.arg("-Z").arg("osx-rpath-install-name");
Some("-Wl,-rpath,@loader_path/../lib")
Some(&["-rpath", "@loader_path/../lib"])
} else if !target.contains("windows") {
Some("-Wl,-rpath,$ORIGIN/../lib")
Some(&["-rpath", "$ORIGIN/../lib"])
} else {
None
};
if let Some(rpath) = rpath {
cmd.arg("-C").arg(format!("link-args={}", rpath));
if let Some(rpath_flags) = rpath_flags {
for rpath_flag in rpath_flags {
if stage == "0" {
cmd.arg("-C").arg("link-arg=-Xlinker");
}
cmd.arg("-C").arg(format!("link-arg={}", rpath_flag));
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_back/target/aarch64_apple_ios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub fn target() -> TargetResult {
target_os: "ios".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
linker_flavor: LinkerFlavor::Gcc,
linker_flavor: LinkerFlavor::Ld,
options: TargetOptions {
features: "+neon,+fp-armv8,+cyclone".to_string(),
eliminate_frame_pointer: false,
Expand Down
53 changes: 42 additions & 11 deletions src/librustc_back/target/apple_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,43 @@
// except according to those terms.

use std::env;
use std::io;
use std::process::Command;
use std::str;

use target::{LinkArgs, TargetOptions};
use target::TargetOptions;

pub fn xcrun(print_arg: &str, sdk_name: &str) -> io::Result<String> {
Command::new("xcrun").arg(print_arg).arg("--sdk").arg(sdk_name).output().and_then(|output| {
if output.status.success() {
Ok(str::from_utf8(&output.stdout[..]).unwrap().trim().to_string())
} else {
let error = format!(
"process exit with error: {}",
str::from_utf8(&output.stderr[..]).unwrap(),
);
Err(io::Error::new(io::ErrorKind::Other, &error[..]))
}
})
}

pub fn get_sdk_root(sdk_name: &str) -> Result<String, String> {
xcrun("--show-sdk-path", sdk_name).map_err(|e| {
format!("failed to get {} SDK path: {}", sdk_name, e)
})
}

pub fn get_sdk_version(sdk_name: &str) -> Result<String, String> {
xcrun("--show-sdk-version", sdk_name).map_err(|e| {
format!("failed to get {} SDK version: {}", sdk_name, e)
})
}

pub fn get_deployment_target() -> String {
env::var("MACOSX_DEPLOYMENT_TARGET").or_else(|_e| {
get_sdk_version("macosx")
}).unwrap_or("10.7".to_string())
}

pub fn opts() -> TargetOptions {
// ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
Expand All @@ -22,15 +57,11 @@ pub fn opts() -> TargetOptions {
// MACOSX_DEPLOYMENT_TARGET set to 10.6 will cause the linker to generate
// warnings about the usage of ELF TLS.
//
// Here we detect what version is being requested, defaulting to 10.7. ELF
// TLS is flagged as enabled if it looks to be supported.
let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok();
let version = deployment_target.as_ref().and_then(|s| {
let mut i = s.splitn(2, ".");
i.next().and_then(|a| i.next().map(|b| (a, b)))
}).and_then(|(a, b)| {
a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok()
}).unwrap_or((10, 7));
// Here we detect what version is being requested. ELF TLS is flagged as
// enabled if it looks to be supported.
let deployment_target = get_deployment_target();
let mut i = deployment_target.splitn(2, '.').map(|s| s.parse::<u32>().unwrap());
let version = (i.next().unwrap(), i.next().unwrap());

TargetOptions {
// macOS has -dead_strip, which doesn't rely on function_sections
Expand All @@ -43,9 +74,9 @@ pub fn opts() -> TargetOptions {
dll_prefix: "lib".to_string(),
dll_suffix: ".dylib".to_string(),
archive_format: "bsd".to_string(),
pre_link_args: LinkArgs::new(),
exe_allocation_crate: super::maybe_jemalloc(),
has_elf_tls: version >= (10, 7),
linker: "ld".to_string(),
.. Default::default()
}
}
32 changes: 3 additions & 29 deletions src/librustc_back/target/apple_ios_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
// except according to those terms.

use LinkerFlavor;
use std::io;
use std::process::Command;
use target::{LinkArgs, TargetOptions};

use self::Arch::*;
Expand All @@ -37,30 +35,6 @@ impl Arch {
}
}

pub fn get_sdk_root(sdk_name: &str) -> Result<String, String> {
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<LinkArgs, String> {
let sdk_name = match arch {
Armv7 | Armv7s | Arm64 => "iphoneos",
Expand All @@ -69,13 +43,13 @@ fn build_pre_link_args(arch: Arch) -> Result<LinkArgs, String> {

let arch_name = arch.to_string();

let sdk_root = get_sdk_root(sdk_name)?;
let sdk_root = super::apple_base::get_sdk_root(sdk_name)?;

let mut args = LinkArgs::new();
args.insert(LinkerFlavor::Gcc,
args.insert(LinkerFlavor::Ld,
vec!["-arch".to_string(),
arch_name.to_string(),
"-Wl,-syslibroot".to_string(),
"-syslibroot".to_string(),
sdk_root]);

Ok(args)
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_back/target/armv7_apple_ios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub fn target() -> TargetResult {
target_os: "ios".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
linker_flavor: LinkerFlavor::Gcc,
linker_flavor: LinkerFlavor::Ld,
options: TargetOptions {
features: "+v7,+vfp3,+neon".to_string(),
max_atomic_width: Some(64),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_back/target/armv7s_apple_ios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub fn target() -> TargetResult {
target_os: "ios".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
linker_flavor: LinkerFlavor::Gcc,
linker_flavor: LinkerFlavor::Ld,
options: TargetOptions {
features: "+v7,+vfp4,+neon".to_string(),
max_atomic_width: Some(64),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_back/target/i386_apple_ios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub fn target() -> TargetResult {
target_os: "ios".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
linker_flavor: LinkerFlavor::Gcc,
linker_flavor: LinkerFlavor::Ld,
options: TargetOptions {
max_atomic_width: Some(64),
stack_probes: true,
Expand Down
3 changes: 1 addition & 2 deletions src/librustc_back/target/i686_apple_darwin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ pub fn target() -> TargetResult {
let mut base = super::apple_base::opts();
base.cpu = "yonah".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
base.stack_probes = true;

Ok(Target {
Expand All @@ -28,7 +27,7 @@ pub fn target() -> TargetResult {
target_os: "macos".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
linker_flavor: LinkerFlavor::Gcc,
linker_flavor: LinkerFlavor::Ld,
options: base,
})
}
2 changes: 1 addition & 1 deletion src/librustc_back/target/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use syntax::abi::{Abi, lookup as lookup_abi};
use {LinkerFlavor, PanicStrategy, RelroLevel};

mod android_base;
mod apple_base;
pub mod apple_base;
mod apple_ios_base;
mod arm_base;
mod bitrig_base;
Expand Down
3 changes: 1 addition & 2 deletions src/librustc_back/target/x86_64_apple_darwin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ pub fn target() -> TargetResult {
base.cpu = "core2".to_string();
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()]);
base.stack_probes = true;

Ok(Target {
Expand All @@ -29,7 +28,7 @@ pub fn target() -> TargetResult {
target_os: "macos".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
linker_flavor: LinkerFlavor::Gcc,
linker_flavor: LinkerFlavor::Ld,
options: base,
})
}
2 changes: 1 addition & 1 deletion src/librustc_back/target/x86_64_apple_ios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub fn target() -> TargetResult {
target_os: "ios".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
linker_flavor: LinkerFlavor::Gcc,
linker_flavor: LinkerFlavor::Ld,
options: TargetOptions {
max_atomic_width: Some(64),
stack_probes: true,
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_trans/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1108,9 +1108,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
}
}

// We must link the sanitizer runtime using -Wl,--whole-archive but since
// it's packed in a .rlib, it contains stuff that are not objects that will
// make the linker error. So we must remove those bits from the .rlib before
// We must link the sanitizer runtime using --whole-archive but since it's
// packed in a .rlib, it contains stuff that are not objects that will make
// the linker error. So we must remove those bits from the .rlib before
// linking it.
fn link_sanitizer_runtime(cmd: &mut Linker,
sess: &Session,
Expand All @@ -1129,7 +1129,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
// FIXME: Remove this logic into librustc_*san once Cargo supports it
let rpath = cratepath.parent().unwrap();
let rpath = rpath.to_str().expect("non-utf8 component in path");
cmd.args(&["-Wl,-rpath".into(), "-Xlinker".into(), rpath.into()]);
cmd.args(&["-rpath".into(), rpath.into()]);
}

let dst = tmpdir.join(cratepath.file_name().unwrap());
Expand Down
Loading