let args = env::args_os().skip(1).collect::<Vec<_>>();
// 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()
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.
// 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!