]>
Commit | Line | Data |
---|---|---|
7453a54e SL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
54a0048b SL |
10 | |
11 | //! Shim which is passed to Cargo as "rustc" when running the bootstrap. | |
12 | //! | |
13 | //! This shim will take care of some various tasks that our build process | |
14 | //! requires that Cargo can't quite do through normal configuration: | |
15 | //! | |
16 | //! 1. When compiling build scripts and build dependencies, we need a guaranteed | |
17 | //! full standard library available. The only compiler which actually has | |
18 | //! this is the snapshot, so we detect this situation and always compile with | |
19 | //! the snapshot compiler. | |
20 | //! 2. We pass a bunch of `--cfg` and other flags based on what we're compiling | |
21 | //! (and this slightly differs based on a whether we're using a snapshot or | |
22 | //! not), so we do that all here. | |
23 | //! | |
24 | //! This may one day be replaced by RUSTFLAGS, but the dynamic nature of | |
25 | //! switching compilers for the bootstrap and for build scripts will probably | |
26 | //! never get replaced. | |
7453a54e SL |
27 | |
28 | extern crate bootstrap; | |
29 | ||
30 | use std::env; | |
31 | use std::ffi::OsString; | |
32 | use std::path::PathBuf; | |
33 | use std::process::Command; | |
34 | ||
35 | fn main() { | |
36 | let args = env::args_os().skip(1).collect::<Vec<_>>(); | |
37 | // Detect whether or not we're a build script depending on whether --target | |
38 | // is passed (a bit janky...) | |
c30ab7b3 SL |
39 | let target = args.windows(2) |
40 | .find(|w| &*w[0] == "--target") | |
41 | .and_then(|w| w[1].to_str()); | |
9e0c209e | 42 | let version = args.iter().find(|w| &**w == "-vV"); |
7453a54e SL |
43 | |
44 | // Build scripts always use the snapshot compiler which is guaranteed to be | |
45 | // able to produce an executable, whereas intermediate compilers may not | |
46 | // have the standard library built yet and may not be able to produce an | |
47 | // executable. Otherwise we just use the standard compiler we're | |
48 | // bootstrapping with. | |
9e0c209e SL |
49 | // |
50 | // Also note that cargo will detect the version of the compiler to trigger | |
51 | // a rebuild when the compiler changes. If this happens, we want to make | |
52 | // sure to use the actual compiler instead of the snapshot compiler becase | |
53 | // that's the one that's actually changing. | |
54 | let (rustc, libdir) = if target.is_none() && version.is_none() { | |
a7813a04 | 55 | ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR") |
7453a54e | 56 | } else { |
a7813a04 | 57 | ("RUSTC_REAL", "RUSTC_LIBDIR") |
7453a54e | 58 | }; |
9e0c209e | 59 | let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set"); |
a7813a04 | 60 | |
9e0c209e SL |
61 | let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc)); |
62 | let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir)); | |
5bcae85e | 63 | let mut dylib_path = bootstrap::util::dylib_path(); |
a7813a04 | 64 | dylib_path.insert(0, PathBuf::from(libdir)); |
7453a54e SL |
65 | |
66 | let mut cmd = Command::new(rustc); | |
67 | cmd.args(&args) | |
c30ab7b3 SL |
68 | .arg("--cfg") |
69 | .arg(format!("stage{}", stage)) | |
70 | .env(bootstrap::util::dylib_path_var(), | |
71 | env::join_paths(&dylib_path).unwrap()); | |
7453a54e | 72 | |
a7813a04 XL |
73 | if let Some(target) = target { |
74 | // The stage0 compiler has a special sysroot distinct from what we | |
75 | // actually downloaded, so we just always pass the `--sysroot` option. | |
9e0c209e | 76 | cmd.arg("--sysroot").arg(env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set")); |
7453a54e SL |
77 | |
78 | // When we build Rust dylibs they're all intended for intermediate | |
79 | // usage, so make sure we pass the -Cprefer-dynamic flag instead of | |
80 | // linking all deps statically into the dylib. | |
81 | cmd.arg("-Cprefer-dynamic"); | |
82 | ||
a7813a04 XL |
83 | // Help the libc crate compile by assisting it in finding the MUSL |
84 | // native libraries. | |
7453a54e SL |
85 | if let Some(s) = env::var_os("MUSL_ROOT") { |
86 | let mut root = OsString::from("native="); | |
87 | root.push(&s); | |
88 | root.push("/lib"); | |
89 | cmd.arg("-L").arg(&root); | |
90 | } | |
a7813a04 XL |
91 | |
92 | // Pass down extra flags, commonly used to configure `-Clinker` when | |
93 | // cross compiling. | |
7453a54e SL |
94 | if let Ok(s) = env::var("RUSTC_FLAGS") { |
95 | cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::<Vec<_>>()); | |
96 | } | |
7453a54e | 97 | |
a7813a04 XL |
98 | // If we're compiling specifically the `panic_abort` crate then we pass |
99 | // the `-C panic=abort` option. Note that we do not do this for any | |
100 | // other crate intentionally as this is the only crate for now that we | |
101 | // ship with panic=abort. | |
102 | // | |
103 | // This... is a bit of a hack how we detect this. Ideally this | |
104 | // information should be encoded in the crate I guess? Would likely | |
105 | // require an RFC amendment to RFC 1513, however. | |
c30ab7b3 SL |
106 | let is_panic_abort = args.windows(2) |
107 | .any(|a| &*a[0] == "--crate-name" && &*a[1] == "panic_abort"); | |
108 | if is_panic_abort { | |
a7813a04 XL |
109 | cmd.arg("-C").arg("panic=abort"); |
110 | } | |
111 | ||
112 | // Set various options from config.toml to configure how we're building | |
113 | // code. | |
114 | if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) { | |
115 | cmd.arg("-g"); | |
c30ab7b3 SL |
116 | } else if env::var("RUSTC_DEBUGINFO_LINES") == Ok("true".to_string()) { |
117 | cmd.arg("-Cdebuginfo=1"); | |
a7813a04 XL |
118 | } |
119 | let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") { | |
c30ab7b3 | 120 | Ok(s) => if s == "true" { "y" } else { "n" }, |
a7813a04 XL |
121 | Err(..) => "n", |
122 | }; | |
123 | cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions)); | |
124 | if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") { | |
125 | cmd.arg("-C").arg(format!("codegen-units={}", s)); | |
126 | } | |
127 | ||
128 | // Dealing with rpath here is a little special, so let's go into some | |
129 | // detail. First off, `-rpath` is a linker option on Unix platforms | |
130 | // which adds to the runtime dynamic loader path when looking for | |
131 | // dynamic libraries. We use this by default on Unix platforms to ensure | |
132 | // that our nightlies behave the same on Windows, that is they work out | |
133 | // of the box. This can be disabled, of course, but basically that's why | |
134 | // we're gated on RUSTC_RPATH here. | |
135 | // | |
136 | // Ok, so the astute might be wondering "why isn't `-C rpath` used | |
137 | // here?" and that is indeed a good question to task. This codegen | |
138 | // option is the compiler's current interface to generating an rpath. | |
139 | // Unfortunately it doesn't quite suffice for us. The flag currently | |
140 | // takes no value as an argument, so the compiler calculates what it | |
141 | // should pass to the linker as `-rpath`. This unfortunately is based on | |
142 | // the **compile time** directory structure which when building with | |
143 | // Cargo will be very different than the runtime directory structure. | |
144 | // | |
145 | // All that's a really long winded way of saying that if we use | |
146 | // `-Crpath` then the executables generated have the wrong rpath of | |
147 | // something like `$ORIGIN/deps` when in fact the way we distribute | |
148 | // rustc requires the rpath to be `$ORIGIN/../lib`. | |
149 | // | |
150 | // So, all in all, to set up the correct rpath we pass the linker | |
151 | // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it | |
152 | // fun to pass a flag to a tool to pass a flag to pass a flag to a tool | |
153 | // to change a flag in a binary? | |
154 | if env::var("RUSTC_RPATH") == Ok("true".to_string()) { | |
155 | let rpath = if target.contains("apple") { | |
156 | Some("-Wl,-rpath,@loader_path/../lib") | |
157 | } else if !target.contains("windows") { | |
158 | Some("-Wl,-rpath,$ORIGIN/../lib") | |
159 | } else { | |
160 | None | |
161 | }; | |
162 | if let Some(rpath) = rpath { | |
163 | cmd.arg("-C").arg(format!("link-args={}", rpath)); | |
164 | } | |
165 | } | |
7453a54e SL |
166 | } |
167 | ||
168 | // Actually run the compiler! | |
169 | std::process::exit(match cmd.status() { | |
170 | Ok(s) => s.code().unwrap_or(1), | |
171 | Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), | |
172 | }) | |
173 | } |