]>
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 | 27 | |
32a655c1 SL |
28 | #![deny(warnings)] |
29 | ||
7453a54e SL |
30 | extern crate bootstrap; |
31 | ||
32 | use std::env; | |
33 | use std::ffi::OsString; | |
32a655c1 | 34 | use std::str::FromStr; |
7453a54e | 35 | use std::path::PathBuf; |
476ff2be | 36 | use std::process::{Command, ExitStatus}; |
7453a54e SL |
37 | |
38 | fn main() { | |
7cac9316 XL |
39 | let mut args = env::args_os().skip(1).collect::<Vec<_>>(); |
40 | ||
41 | // Append metadata suffix for internal crates. See the corresponding entry | |
42 | // in bootstrap/lib.rs for details. | |
43 | if let Ok(s) = env::var("RUSTC_METADATA_SUFFIX") { | |
44 | for i in 1..args.len() { | |
45 | // Dirty code for borrowing issues | |
46 | let mut new = None; | |
47 | if let Some(current_as_str) = args[i].to_str() { | |
48 | if (&*args[i - 1] == "-C" && current_as_str.starts_with("metadata")) || | |
49 | current_as_str.starts_with("-Cmetadata") { | |
50 | new = Some(format!("{}-{}", current_as_str, s)); | |
51 | } | |
52 | } | |
53 | if let Some(new) = new { args[i] = new.into(); } | |
54 | } | |
55 | } | |
56 | ||
57 | // Drop `--error-format json` because despite our desire for json messages | |
58 | // from Cargo we don't want any from rustc itself. | |
59 | if let Some(n) = args.iter().position(|n| n == "--error-format") { | |
60 | args.remove(n); | |
61 | args.remove(n); | |
62 | } | |
63 | ||
7453a54e SL |
64 | // Detect whether or not we're a build script depending on whether --target |
65 | // is passed (a bit janky...) | |
c30ab7b3 SL |
66 | let target = args.windows(2) |
67 | .find(|w| &*w[0] == "--target") | |
68 | .and_then(|w| w[1].to_str()); | |
9e0c209e | 69 | let version = args.iter().find(|w| &**w == "-vV"); |
7453a54e | 70 | |
32a655c1 SL |
71 | let verbose = match env::var("RUSTC_VERBOSE") { |
72 | Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"), | |
73 | Err(_) => 0, | |
74 | }; | |
75 | ||
041b39d2 XL |
76 | // Use a different compiler for build scripts, since there may not yet be a |
77 | // libstd for the real compiler to use. However, if Cargo is attempting to | |
78 | // determine the version of the compiler, the real compiler needs to be | |
79 | // used. Currently, these two states are differentiated based on whether | |
80 | // --target and -vV is/isn't passed. | |
9e0c209e | 81 | let (rustc, libdir) = if target.is_none() && version.is_none() { |
a7813a04 | 82 | ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR") |
7453a54e | 83 | } else { |
a7813a04 | 84 | ("RUSTC_REAL", "RUSTC_LIBDIR") |
7453a54e | 85 | }; |
9e0c209e | 86 | let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set"); |
32a655c1 | 87 | let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); |
8bb4bdeb | 88 | let mut on_fail = env::var_os("RUSTC_ON_FAIL").map(|of| Command::new(of)); |
a7813a04 | 89 | |
9e0c209e SL |
90 | let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc)); |
91 | let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir)); | |
5bcae85e | 92 | let mut dylib_path = bootstrap::util::dylib_path(); |
a7813a04 | 93 | dylib_path.insert(0, PathBuf::from(libdir)); |
7453a54e SL |
94 | |
95 | let mut cmd = Command::new(rustc); | |
96 | cmd.args(&args) | |
c30ab7b3 SL |
97 | .arg("--cfg") |
98 | .arg(format!("stage{}", stage)) | |
99 | .env(bootstrap::util::dylib_path_var(), | |
100 | env::join_paths(&dylib_path).unwrap()); | |
7453a54e | 101 | |
a7813a04 XL |
102 | if let Some(target) = target { |
103 | // The stage0 compiler has a special sysroot distinct from what we | |
104 | // actually downloaded, so we just always pass the `--sysroot` option. | |
32a655c1 | 105 | cmd.arg("--sysroot").arg(sysroot); |
7453a54e SL |
106 | |
107 | // When we build Rust dylibs they're all intended for intermediate | |
108 | // usage, so make sure we pass the -Cprefer-dynamic flag instead of | |
109 | // linking all deps statically into the dylib. | |
32a655c1 SL |
110 | if env::var_os("RUSTC_NO_PREFER_DYNAMIC").is_none() { |
111 | cmd.arg("-Cprefer-dynamic"); | |
112 | } | |
7453a54e | 113 | |
a7813a04 XL |
114 | // Help the libc crate compile by assisting it in finding the MUSL |
115 | // native libraries. | |
7453a54e SL |
116 | if let Some(s) = env::var_os("MUSL_ROOT") { |
117 | let mut root = OsString::from("native="); | |
118 | root.push(&s); | |
119 | root.push("/lib"); | |
120 | cmd.arg("-L").arg(&root); | |
121 | } | |
a7813a04 | 122 | |
abe05a73 XL |
123 | // Override linker if necessary. |
124 | if let Ok(target_linker) = env::var("RUSTC_TARGET_LINKER") { | |
125 | cmd.arg(format!("-Clinker={}", target_linker)); | |
7453a54e | 126 | } |
7453a54e | 127 | |
32a655c1 SL |
128 | // Pass down incremental directory, if any. |
129 | if let Ok(dir) = env::var("RUSTC_INCREMENTAL") { | |
130 | cmd.arg(format!("-Zincremental={}", dir)); | |
32a655c1 SL |
131 | } |
132 | ||
041b39d2 XL |
133 | let crate_name = args.windows(2) |
134 | .find(|a| &*a[0] == "--crate-name") | |
135 | .unwrap(); | |
136 | let crate_name = &*crate_name[1]; | |
137 | ||
a7813a04 XL |
138 | // If we're compiling specifically the `panic_abort` crate then we pass |
139 | // the `-C panic=abort` option. Note that we do not do this for any | |
140 | // other crate intentionally as this is the only crate for now that we | |
141 | // ship with panic=abort. | |
142 | // | |
143 | // This... is a bit of a hack how we detect this. Ideally this | |
144 | // information should be encoded in the crate I guess? Would likely | |
145 | // require an RFC amendment to RFC 1513, however. | |
041b39d2 XL |
146 | // |
147 | // `compiler_builtins` are unconditionally compiled with panic=abort to | |
148 | // workaround undefined references to `rust_eh_unwind_resume` generated | |
149 | // otherwise, see issue https://github.com/rust-lang/rust/issues/43095. | |
150 | if crate_name == "panic_abort" || | |
151 | crate_name == "compiler_builtins" && stage != "0" { | |
a7813a04 XL |
152 | cmd.arg("-C").arg("panic=abort"); |
153 | } | |
154 | ||
155 | // Set various options from config.toml to configure how we're building | |
156 | // code. | |
157 | if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) { | |
158 | cmd.arg("-g"); | |
c30ab7b3 SL |
159 | } else if env::var("RUSTC_DEBUGINFO_LINES") == Ok("true".to_string()) { |
160 | cmd.arg("-Cdebuginfo=1"); | |
a7813a04 XL |
161 | } |
162 | let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") { | |
c30ab7b3 | 163 | Ok(s) => if s == "true" { "y" } else { "n" }, |
a7813a04 XL |
164 | Err(..) => "n", |
165 | }; | |
041b39d2 XL |
166 | |
167 | // The compiler builtins are pretty sensitive to symbols referenced in | |
168 | // libcore and such, so we never compile them with debug assertions. | |
169 | if crate_name == "compiler_builtins" { | |
170 | cmd.arg("-C").arg("debug-assertions=no"); | |
171 | } else { | |
172 | cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions)); | |
173 | } | |
174 | ||
a7813a04 XL |
175 | if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") { |
176 | cmd.arg("-C").arg(format!("codegen-units={}", s)); | |
177 | } | |
abe05a73 XL |
178 | if stage != "0" && env::var("RUSTC_THINLTO").is_ok() { |
179 | cmd.arg("-Ccodegen-units=16").arg("-Zthinlto"); | |
180 | } | |
a7813a04 | 181 | |
476ff2be SL |
182 | // Emit save-analysis info. |
183 | if env::var("RUSTC_SAVE_ANALYSIS") == Ok("api".to_string()) { | |
3b2f2976 XL |
184 | cmd.arg("-Zsave-analysis"); |
185 | cmd.env("RUST_SAVE_ANALYSIS_CONFIG", | |
186 | "{\"output_file\": null,\"full_docs\": false,\"pub_only\": true,\ | |
187 | \"distro_crate\": true,\"signatures\": false,\"borrow_data\": false}"); | |
476ff2be SL |
188 | } |
189 | ||
a7813a04 XL |
190 | // Dealing with rpath here is a little special, so let's go into some |
191 | // detail. First off, `-rpath` is a linker option on Unix platforms | |
192 | // which adds to the runtime dynamic loader path when looking for | |
193 | // dynamic libraries. We use this by default on Unix platforms to ensure | |
194 | // that our nightlies behave the same on Windows, that is they work out | |
195 | // of the box. This can be disabled, of course, but basically that's why | |
196 | // we're gated on RUSTC_RPATH here. | |
197 | // | |
198 | // Ok, so the astute might be wondering "why isn't `-C rpath` used | |
199 | // here?" and that is indeed a good question to task. This codegen | |
200 | // option is the compiler's current interface to generating an rpath. | |
201 | // Unfortunately it doesn't quite suffice for us. The flag currently | |
202 | // takes no value as an argument, so the compiler calculates what it | |
203 | // should pass to the linker as `-rpath`. This unfortunately is based on | |
204 | // the **compile time** directory structure which when building with | |
205 | // Cargo will be very different than the runtime directory structure. | |
206 | // | |
207 | // All that's a really long winded way of saying that if we use | |
208 | // `-Crpath` then the executables generated have the wrong rpath of | |
209 | // something like `$ORIGIN/deps` when in fact the way we distribute | |
210 | // rustc requires the rpath to be `$ORIGIN/../lib`. | |
211 | // | |
212 | // So, all in all, to set up the correct rpath we pass the linker | |
213 | // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it | |
214 | // fun to pass a flag to a tool to pass a flag to pass a flag to a tool | |
215 | // to change a flag in a binary? | |
216 | if env::var("RUSTC_RPATH") == Ok("true".to_string()) { | |
217 | let rpath = if target.contains("apple") { | |
476ff2be | 218 | |
cc61c64b | 219 | // Note that we need to take one extra step on macOS to also pass |
476ff2be SL |
220 | // `-Wl,-instal_name,@rpath/...` to get things to work right. To |
221 | // do that we pass a weird flag to the compiler to get it to do | |
222 | // so. Note that this is definitely a hack, and we should likely | |
223 | // flesh out rpath support more fully in the future. | |
041b39d2 | 224 | cmd.arg("-Z").arg("osx-rpath-install-name"); |
a7813a04 XL |
225 | Some("-Wl,-rpath,@loader_path/../lib") |
226 | } else if !target.contains("windows") { | |
227 | Some("-Wl,-rpath,$ORIGIN/../lib") | |
228 | } else { | |
229 | None | |
230 | }; | |
231 | if let Some(rpath) = rpath { | |
232 | cmd.arg("-C").arg(format!("link-args={}", rpath)); | |
233 | } | |
234 | } | |
8bb4bdeb | 235 | |
3b2f2976 XL |
236 | if let Ok(s) = env::var("RUSTC_CRT_STATIC") { |
237 | if s == "true" { | |
238 | cmd.arg("-C").arg("target-feature=+crt-static"); | |
239 | } | |
240 | if s == "false" { | |
241 | cmd.arg("-C").arg("target-feature=-crt-static"); | |
242 | } | |
8bb4bdeb | 243 | } |
7cac9316 | 244 | |
ea8adc8c XL |
245 | // When running miri tests, we need to generate MIR for all libraries |
246 | if env::var("TEST_MIRI").ok().map_or(false, |val| val == "true") { | |
247 | cmd.arg("-Zalways-encode-mir"); | |
248 | cmd.arg("-Zmir-emit-validate=1"); | |
249 | } | |
250 | ||
7cac9316 XL |
251 | // Force all crates compiled by this compiler to (a) be unstable and (b) |
252 | // allow the `rustc_private` feature to link to other unstable crates | |
253 | // also in the sysroot. | |
7cac9316 | 254 | if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() { |
041b39d2 | 255 | cmd.arg("-Z").arg("force-unstable-if-unmarked"); |
7cac9316 | 256 | } |
abe05a73 XL |
257 | } else { |
258 | // Override linker if necessary. | |
259 | if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") { | |
260 | cmd.arg(format!("-Clinker={}", host_linker)); | |
261 | } | |
7453a54e SL |
262 | } |
263 | ||
041b39d2 XL |
264 | let color = match env::var("RUSTC_COLOR") { |
265 | Ok(s) => usize::from_str(&s).expect("RUSTC_COLOR should be an integer"), | |
266 | Err(_) => 0, | |
267 | }; | |
268 | ||
269 | if color != 0 { | |
270 | cmd.arg("--color=always"); | |
271 | } | |
272 | ||
32a655c1 | 273 | if verbose > 1 { |
abe05a73 | 274 | eprintln!("rustc command: {:?}", cmd); |
32a655c1 SL |
275 | } |
276 | ||
7453a54e | 277 | // Actually run the compiler! |
8bb4bdeb XL |
278 | std::process::exit(if let Some(ref mut on_fail) = on_fail { |
279 | match cmd.status() { | |
280 | Ok(s) if s.success() => 0, | |
281 | _ => { | |
282 | println!("\nDid not run successfully:\n{:?}\n-------------", cmd); | |
283 | exec_cmd(on_fail).expect("could not run the backup command"); | |
284 | 1 | |
285 | } | |
286 | } | |
287 | } else { | |
288 | std::process::exit(match exec_cmd(&mut cmd) { | |
289 | Ok(s) => s.code().unwrap_or(0xfe), | |
290 | Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), | |
291 | }) | |
7453a54e SL |
292 | }) |
293 | } | |
476ff2be SL |
294 | |
295 | #[cfg(unix)] | |
296 | fn exec_cmd(cmd: &mut Command) -> ::std::io::Result<ExitStatus> { | |
297 | use std::os::unix::process::CommandExt; | |
298 | Err(cmd.exec()) | |
299 | } | |
300 | ||
301 | #[cfg(not(unix))] | |
302 | fn exec_cmd(cmd: &mut Command) -> ::std::io::Result<ExitStatus> { | |
303 | cmd.status() | |
304 | } |