From 11ef3a9c932711233127ffc7108b3a2ceed292e1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Apr 2016 22:54:10 -0700 Subject: [PATCH] rustbuild: Fix --enable-rpath usage This commit fixes the `--enable-rpath` configure flag in rustbuild to work despite the compile-time directories being different than the runtime directories. This unfortunately means that we can't use `-C rpath` out of the box but hopefully the portability story here isn't too bad as `src/librustc_back/rpath.rs` isn't *too* complicated. Closes #32886 --- src/bootstrap/rustc.rs | 73 +++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/src/bootstrap/rustc.rs b/src/bootstrap/rustc.rs index d403d76bb1400..1ebf27b51adb4 100644 --- a/src/bootstrap/rustc.rs +++ b/src/bootstrap/rustc.rs @@ -36,16 +36,15 @@ fn main() { let args = env::args_os().skip(1).collect::>(); // Detect whether or not we're a build script depending on whether --target // is passed (a bit janky...) - let is_build_script = args.iter() - .position(|i| i.to_str() == Some("--target")) - .is_none(); + let target = args.windows(2).find(|w| &*w[0] == "--target") + .and_then(|w| w[1].to_str()); // Build scripts always use the snapshot compiler which is guaranteed to be // able to produce an executable, whereas intermediate compilers may not // have the standard library built yet and may not be able to produce an // executable. Otherwise we just use the standard compiler we're // bootstrapping with. - let rustc = if is_build_script { + let rustc = if target.is_none() { env::var_os("RUSTC_SNAPSHOT").unwrap() } else { env::var_os("RUSTC_REAL").unwrap() @@ -55,7 +54,7 @@ fn main() { cmd.args(&args) .arg("--cfg").arg(format!("stage{}", env::var("RUSTC_STAGE").unwrap())); - if is_build_script { + if target.is_none() { // Build scripts are always built with the snapshot compiler, so we need // to be sure to set up the right path information for the OS dynamic // linker to find the libraries in question. @@ -85,19 +84,57 @@ fn main() { // Set various options from config.toml to configure how we're building // code. - if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) { - cmd.arg("-g"); - } - if env::var("RUSTC_RPATH") == Ok("true".to_string()) { - cmd.arg("-Crpath"); - } - let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") { - Ok(s) => if s == "true" {"y"} else {"n"}, - Err(..) => "n", - }; - cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions)); - if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") { - cmd.arg("-C").arg(format!("codegen-units={}", s)); + if let Some(target) = target { + if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) { + cmd.arg("-g"); + } + let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") { + Ok(s) => if s == "true" {"y"} else {"n"}, + Err(..) => "n", + }; + cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions)); + if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") { + cmd.arg("-C").arg(format!("codegen-units={}", s)); + } + + // Dealing with rpath here is a little special, so let's go into some + // detail. First off, `-rpath` is a linker option on Unix platforms + // which adds to the runtime dynamic loader path when looking for + // dynamic libraries. We use this by default on Unix platforms to ensure + // that our nightlies behave the same on Windows, that is they work out + // of the box. This can be disabled, of course, but basically that's why + // we're gated on RUSTC_RPATH here. + // + // Ok, so the astute might be wondering "why isn't `-C rpath` used + // here?" and that is indeed a good question to task. This codegen + // option is the compiler's current interface to generating an rpath. + // Unfortunately it doesn't quite suffice for us. The flag currently + // takes no value as an argument, so the compiler calculates what it + // should pass to the linker as `-rpath`. This unfortunately is based on + // the **compile time** directory structure which when building with + // 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 + // 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 + // 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") { + Some("-Wl,-rpath,@loader_path/../lib") + } else if !target.contains("windows") { + Some("-Wl,-rpath,$ORIGIN/../lib") + } else { + None + }; + if let Some(rpath) = rpath { + cmd.arg("-C").arg(format!("link-args={}", rpath)); + } + } } // Actually run the compiler!