]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
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. | |
10 | ||
5bcae85e | 11 | //! Implementation of rustbuild, the Rust build system. |
a7813a04 | 12 | //! |
5bcae85e SL |
13 | //! This module, and its descendants, are the implementation of the Rust build |
14 | //! system. Most of this build system is backed by Cargo but the outer layer | |
15 | //! here serves as the ability to orchestrate calling Cargo, sequencing Cargo | |
476ff2be | 16 | //! builds, building artifacts like LLVM, etc. The goals of rustbuild are: |
5bcae85e | 17 | //! |
476ff2be SL |
18 | //! * To be an easily understandable, easily extensible, and maintainable build |
19 | //! system. | |
20 | //! * Leverage standard tools in the Rust ecosystem to build the compiler, aka | |
21 | //! crates.io and Cargo. | |
22 | //! * A standard interface to build across all platforms, including MSVC | |
23 | //! | |
24 | //! ## Architecture | |
25 | //! | |
26 | //! Although this build system defers most of the complicated logic to Cargo | |
27 | //! itself, it still needs to maintain a list of targets and dependencies which | |
28 | //! it can itself perform. Rustbuild is made up of a list of rules with | |
29 | //! dependencies amongst them (created in the `step` module) and then knows how | |
30 | //! to execute each in sequence. Each time rustbuild is invoked, it will simply | |
31 | //! iterate through this list of steps and execute each serially in turn. For | |
32 | //! each step rustbuild relies on the step internally being incremental and | |
33 | //! parallel. Note, though, that the `-j` parameter to rustbuild gets forwarded | |
34 | //! to appropriate test harnesses and such. | |
35 | //! | |
36 | //! Most of the "meaty" steps that matter are backed by Cargo, which does indeed | |
37 | //! have its own parallelism and incremental management. Later steps, like | |
38 | //! tests, aren't incremental and simply run the entire suite currently. | |
39 | //! | |
40 | //! When you execute `x.py build`, the steps which are executed are: | |
41 | //! | |
42 | //! * First, the python script is run. This will automatically download the | |
43 | //! stage0 rustc and cargo according to `src/stage0.txt`, or using the cached | |
44 | //! versions if they're available. These are then used to compile rustbuild | |
45 | //! itself (using Cargo). Finally, control is then transferred to rustbuild. | |
46 | //! | |
47 | //! * Rustbuild takes over, performs sanity checks, probes the environment, | |
48 | //! reads configuration, builds up a list of steps, and then starts executing | |
49 | //! them. | |
50 | //! | |
51 | //! * The stage0 libstd is compiled | |
52 | //! * The stage0 libtest is compiled | |
53 | //! * The stage0 librustc is compiled | |
54 | //! * The stage1 compiler is assembled | |
55 | //! * The stage1 libstd, libtest, librustc are compiled | |
56 | //! * The stage2 compiler is assembled | |
57 | //! * The stage2 libstd, libtest, librustc are compiled | |
58 | //! | |
59 | //! Each step is driven by a separate Cargo project and rustbuild orchestrates | |
60 | //! copying files between steps and otherwise preparing for Cargo to run. | |
61 | //! | |
62 | //! ## Further information | |
63 | //! | |
64 | //! More documentation can be found in each respective module below, and you can | |
65 | //! also check out the `src/bootstrap/README.md` file for more information. | |
5bcae85e | 66 | |
32a655c1 SL |
67 | #![deny(warnings)] |
68 | ||
8bb4bdeb | 69 | #[macro_use] |
5bcae85e SL |
70 | extern crate build_helper; |
71 | extern crate cmake; | |
72 | extern crate filetime; | |
73 | extern crate gcc; | |
74 | extern crate getopts; | |
5bcae85e SL |
75 | extern crate num_cpus; |
76 | extern crate rustc_serialize; | |
77 | extern crate toml; | |
a7813a04 | 78 | |
7cac9316 XL |
79 | #[cfg(unix)] |
80 | extern crate libc; | |
81 | ||
82 | use std::cell::Cell; | |
32a655c1 | 83 | use std::cmp; |
8bb4bdeb | 84 | use std::collections::HashMap; |
7453a54e | 85 | use std::env; |
476ff2be | 86 | use std::ffi::OsString; |
5bcae85e | 87 | use std::fs::{self, File}; |
8bb4bdeb | 88 | use std::io::Read; |
7cac9316 | 89 | use std::path::{PathBuf, Path}; |
5bcae85e SL |
90 | use std::process::Command; |
91 | ||
7cac9316 | 92 | use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime}; |
5bcae85e | 93 | |
7cac9316 | 94 | use util::{exe, libdir, add_lib_path, OutputFolder, CiEnv}; |
5bcae85e SL |
95 | |
96 | mod cc; | |
97 | mod channel; | |
98 | mod check; | |
99 | mod clean; | |
100 | mod compile; | |
c30ab7b3 | 101 | mod metadata; |
5bcae85e SL |
102 | mod config; |
103 | mod dist; | |
104 | mod doc; | |
105 | mod flags; | |
c30ab7b3 | 106 | mod install; |
5bcae85e SL |
107 | mod native; |
108 | mod sanity; | |
109 | mod step; | |
110 | pub mod util; | |
111 | ||
112 | #[cfg(windows)] | |
113 | mod job; | |
114 | ||
7cac9316 XL |
115 | #[cfg(unix)] |
116 | mod job { | |
117 | use libc; | |
118 | ||
119 | pub unsafe fn setup(build: &mut ::Build) { | |
120 | if build.config.low_priority { | |
121 | libc::setpriority(libc::PRIO_PGRP as _, 0, 10); | |
122 | } | |
123 | } | |
124 | } | |
125 | ||
126 | #[cfg(not(any(unix, windows)))] | |
5bcae85e | 127 | mod job { |
7cac9316 XL |
128 | pub unsafe fn setup(_build: &mut ::Build) { |
129 | } | |
5bcae85e SL |
130 | } |
131 | ||
132 | pub use config::Config; | |
c30ab7b3 | 133 | pub use flags::{Flags, Subcommand}; |
5bcae85e SL |
134 | |
135 | /// A structure representing a Rust compiler. | |
136 | /// | |
137 | /// Each compiler has a `stage` that it is associated with and a `host` that | |
138 | /// corresponds to the platform the compiler runs on. This structure is used as | |
139 | /// a parameter to many methods below. | |
140 | #[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)] | |
141 | pub struct Compiler<'a> { | |
142 | stage: u32, | |
143 | host: &'a str, | |
144 | } | |
145 | ||
146 | /// Global configuration for the build system. | |
147 | /// | |
148 | /// This structure transitively contains all configuration for the build system. | |
149 | /// All filesystem-encoded configuration is in `config`, all flags are in | |
150 | /// `flags`, and then parsed or probed information is listed in the keys below. | |
151 | /// | |
152 | /// This structure is a parameter of almost all methods in the build system, | |
153 | /// although most functions are implemented as free functions rather than | |
154 | /// methods specifically on this structure itself (to make it easier to | |
155 | /// organize). | |
156 | pub struct Build { | |
157 | // User-specified configuration via config.toml | |
158 | config: Config, | |
159 | ||
160 | // User-specified configuration via CLI flags | |
161 | flags: Flags, | |
162 | ||
163 | // Derived properties from the above two configurations | |
164 | cargo: PathBuf, | |
165 | rustc: PathBuf, | |
166 | src: PathBuf, | |
167 | out: PathBuf, | |
8bb4bdeb XL |
168 | rust_info: channel::GitInfo, |
169 | cargo_info: channel::GitInfo, | |
cc61c64b | 170 | rls_info: channel::GitInfo, |
5bcae85e | 171 | local_rebuild: bool, |
5bcae85e SL |
172 | |
173 | // Probed tools at runtime | |
5bcae85e SL |
174 | lldb_version: Option<String>, |
175 | lldb_python_dir: Option<String>, | |
176 | ||
177 | // Runtime state filled in later on | |
178 | cc: HashMap<String, (gcc::Tool, Option<PathBuf>)>, | |
179 | cxx: HashMap<String, gcc::Tool>, | |
c30ab7b3 | 180 | crates: HashMap<String, Crate>, |
476ff2be | 181 | is_sudo: bool, |
8bb4bdeb | 182 | src_is_git: bool, |
7cac9316 XL |
183 | ci_env: CiEnv, |
184 | delayed_failures: Cell<usize>, | |
c30ab7b3 SL |
185 | } |
186 | ||
187 | #[derive(Debug)] | |
188 | struct Crate { | |
189 | name: String, | |
8bb4bdeb | 190 | version: String, |
c30ab7b3 SL |
191 | deps: Vec<String>, |
192 | path: PathBuf, | |
193 | doc_step: String, | |
194 | build_step: String, | |
195 | test_step: String, | |
476ff2be | 196 | bench_step: String, |
5bcae85e SL |
197 | } |
198 | ||
199 | /// The various "modes" of invoking Cargo. | |
200 | /// | |
201 | /// These entries currently correspond to the various output directories of the | |
202 | /// build system, with each mod generating output in a different directory. | |
cc61c64b | 203 | #[derive(Clone, Copy, PartialEq, Eq)] |
5bcae85e SL |
204 | pub enum Mode { |
205 | /// This cargo is going to build the standard library, placing output in the | |
206 | /// "stageN-std" directory. | |
207 | Libstd, | |
208 | ||
209 | /// This cargo is going to build libtest, placing output in the | |
210 | /// "stageN-test" directory. | |
211 | Libtest, | |
212 | ||
213 | /// This cargo is going to build librustc and compiler libraries, placing | |
214 | /// output in the "stageN-rustc" directory. | |
215 | Librustc, | |
216 | ||
7cac9316 | 217 | /// This cargo is going to build some tool, placing output in the |
5bcae85e SL |
218 | /// "stageN-tools" directory. |
219 | Tool, | |
220 | } | |
221 | ||
222 | impl Build { | |
223 | /// Creates a new set of build configuration from the `flags` on the command | |
224 | /// line and the filesystem `config`. | |
225 | /// | |
226 | /// By default all build output will be placed in the current directory. | |
227 | pub fn new(flags: Flags, config: Config) -> Build { | |
228 | let cwd = t!(env::current_dir()); | |
c30ab7b3 SL |
229 | let src = flags.src.clone().or_else(|| { |
230 | env::var_os("SRC").map(|x| x.into()) | |
231 | }).unwrap_or(cwd.clone()); | |
5bcae85e SL |
232 | let out = cwd.join("build"); |
233 | ||
234 | let stage0_root = out.join(&config.build).join("stage0/bin"); | |
235 | let rustc = match config.rustc { | |
236 | Some(ref s) => PathBuf::from(s), | |
237 | None => stage0_root.join(exe("rustc", &config.build)), | |
238 | }; | |
239 | let cargo = match config.cargo { | |
240 | Some(ref s) => PathBuf::from(s), | |
241 | None => stage0_root.join(exe("cargo", &config.build)), | |
242 | }; | |
243 | let local_rebuild = config.local_rebuild; | |
244 | ||
476ff2be SL |
245 | let is_sudo = match env::var_os("SUDO_USER") { |
246 | Some(sudo_user) => { | |
247 | match env::var_os("USER") { | |
248 | Some(user) => user != sudo_user, | |
249 | None => false, | |
250 | } | |
251 | } | |
252 | None => false, | |
253 | }; | |
8bb4bdeb | 254 | let rust_info = channel::GitInfo::new(&src); |
7cac9316 XL |
255 | let cargo_info = channel::GitInfo::new(&src.join("src/tools/cargo")); |
256 | let rls_info = channel::GitInfo::new(&src.join("src/tools/rls")); | |
8bb4bdeb | 257 | let src_is_git = src.join(".git").exists(); |
476ff2be | 258 | |
5bcae85e SL |
259 | Build { |
260 | flags: flags, | |
261 | config: config, | |
262 | cargo: cargo, | |
263 | rustc: rustc, | |
264 | src: src, | |
265 | out: out, | |
266 | ||
8bb4bdeb XL |
267 | rust_info: rust_info, |
268 | cargo_info: cargo_info, | |
cc61c64b | 269 | rls_info: rls_info, |
5bcae85e | 270 | local_rebuild: local_rebuild, |
5bcae85e SL |
271 | cc: HashMap::new(), |
272 | cxx: HashMap::new(), | |
c30ab7b3 | 273 | crates: HashMap::new(), |
5bcae85e SL |
274 | lldb_version: None, |
275 | lldb_python_dir: None, | |
476ff2be | 276 | is_sudo: is_sudo, |
8bb4bdeb | 277 | src_is_git: src_is_git, |
7cac9316 XL |
278 | ci_env: CiEnv::current(), |
279 | delayed_failures: Cell::new(0), | |
5bcae85e SL |
280 | } |
281 | } | |
282 | ||
283 | /// Executes the entire build, as configured by the flags and configuration. | |
284 | pub fn build(&mut self) { | |
5bcae85e | 285 | unsafe { |
7cac9316 | 286 | job::setup(self); |
5bcae85e SL |
287 | } |
288 | ||
c30ab7b3 | 289 | if let Subcommand::Clean = self.flags.cmd { |
5bcae85e SL |
290 | return clean::clean(self); |
291 | } | |
292 | ||
293 | self.verbose("finding compilers"); | |
294 | cc::find(self); | |
295 | self.verbose("running sanity check"); | |
296 | sanity::check(self); | |
c30ab7b3 | 297 | // If local-rust is the same major.minor as the current version, then force a local-rebuild |
5bcae85e SL |
298 | let local_version_verbose = output( |
299 | Command::new(&self.rustc).arg("--version").arg("--verbose")); | |
300 | let local_release = local_version_verbose | |
301 | .lines().filter(|x| x.starts_with("release:")) | |
302 | .next().unwrap().trim_left_matches("release:").trim(); | |
8bb4bdeb XL |
303 | let my_version = channel::CFG_RELEASE_NUM; |
304 | if local_release.split('.').take(2).eq(my_version.split('.').take(2)) { | |
c30ab7b3 | 305 | self.verbose(&format!("auto-detected local-rebuild {}", local_release)); |
5bcae85e SL |
306 | self.local_rebuild = true; |
307 | } | |
c30ab7b3 SL |
308 | self.verbose("learning about cargo"); |
309 | metadata::build(self); | |
5bcae85e | 310 | |
c30ab7b3 | 311 | step::run(self); |
5bcae85e SL |
312 | } |
313 | ||
5bcae85e SL |
314 | /// Clear out `dir` if `input` is newer. |
315 | /// | |
316 | /// After this executes, it will also ensure that `dir` exists. | |
317 | fn clear_if_dirty(&self, dir: &Path, input: &Path) { | |
318 | let stamp = dir.join(".stamp"); | |
319 | if mtime(&stamp) < mtime(input) { | |
320 | self.verbose(&format!("Dirty - {}", dir.display())); | |
321 | let _ = fs::remove_dir_all(dir); | |
9e0c209e SL |
322 | } else if stamp.exists() { |
323 | return | |
5bcae85e SL |
324 | } |
325 | t!(fs::create_dir_all(dir)); | |
326 | t!(File::create(stamp)); | |
327 | } | |
328 | ||
329 | /// Prepares an invocation of `cargo` to be run. | |
330 | /// | |
331 | /// This will create a `Command` that represents a pending execution of | |
332 | /// Cargo. This cargo will be configured to use `compiler` as the actual | |
333 | /// rustc compiler, its output will be scoped by `mode`'s output directory, | |
334 | /// it will pass the `--target` flag for the specified `target`, and will be | |
335 | /// executing the Cargo command `cmd`. | |
336 | fn cargo(&self, | |
337 | compiler: &Compiler, | |
338 | mode: Mode, | |
339 | target: &str, | |
340 | cmd: &str) -> Command { | |
341 | let mut cargo = Command::new(&self.cargo); | |
342 | let out_dir = self.stage_out(compiler, mode); | |
343 | cargo.env("CARGO_TARGET_DIR", out_dir) | |
344 | .arg(cmd) | |
345 | .arg("-j").arg(self.jobs().to_string()) | |
346 | .arg("--target").arg(target); | |
347 | ||
9e0c209e SL |
348 | // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005 |
349 | // Force cargo to output binaries with disambiguating hashes in the name | |
7cac9316 | 350 | cargo.env("__CARGO_DEFAULT_LIB_METADATA", &self.config.channel); |
9e0c209e | 351 | |
5bcae85e SL |
352 | let stage; |
353 | if compiler.stage == 0 && self.local_rebuild { | |
354 | // Assume the local-rebuild rustc already has stage1 features. | |
355 | stage = 1; | |
356 | } else { | |
357 | stage = compiler.stage; | |
358 | } | |
359 | ||
360 | // Customize the compiler we're running. Specify the compiler to cargo | |
361 | // as our shim and then pass it some various options used to configure | |
362 | // how the actual compiler itself is called. | |
363 | // | |
364 | // These variables are primarily all read by | |
476ff2be | 365 | // src/bootstrap/bin/{rustc.rs,rustdoc.rs} |
8bb4bdeb XL |
366 | cargo.env("RUSTBUILD_NATIVE_DIR", self.native_dir(target)) |
367 | .env("RUSTC", self.out.join("bootstrap/debug/rustc")) | |
5bcae85e SL |
368 | .env("RUSTC_REAL", self.compiler_path(compiler)) |
369 | .env("RUSTC_STAGE", stage.to_string()) | |
5bcae85e SL |
370 | .env("RUSTC_CODEGEN_UNITS", |
371 | self.config.rust_codegen_units.to_string()) | |
372 | .env("RUSTC_DEBUG_ASSERTIONS", | |
373 | self.config.rust_debug_assertions.to_string()) | |
5bcae85e SL |
374 | .env("RUSTC_SYSROOT", self.sysroot(compiler)) |
375 | .env("RUSTC_LIBDIR", self.rustc_libdir(compiler)) | |
5bcae85e SL |
376 | .env("RUSTC_RPATH", self.config.rust_rpath.to_string()) |
377 | .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) | |
378 | .env("RUSTDOC_REAL", self.rustdoc(compiler)) | |
379 | .env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")); | |
380 | ||
8bb4bdeb | 381 | if mode != Mode::Tool { |
7cac9316 XL |
382 | // Tools don't get debuginfo right now, e.g. cargo and rls don't |
383 | // get compiled with debuginfo. | |
384 | cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()) | |
385 | .env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string()) | |
386 | .env("RUSTC_FORCE_UNSTABLE", "1"); | |
387 | ||
388 | // Currently the compiler depends on crates from crates.io, and | |
389 | // then other crates can depend on the compiler (e.g. proc-macro | |
390 | // crates). Let's say, for example that rustc itself depends on the | |
391 | // bitflags crate. If an external crate then depends on the | |
392 | // bitflags crate as well, we need to make sure they don't | |
393 | // conflict, even if they pick the same verison of bitflags. We'll | |
394 | // want to make sure that e.g. a plugin and rustc each get their | |
395 | // own copy of bitflags. | |
396 | ||
397 | // Cargo ensures that this works in general through the -C metadata | |
398 | // flag. This flag will frob the symbols in the binary to make sure | |
399 | // they're different, even though the source code is the exact | |
400 | // same. To solve this problem for the compiler we extend Cargo's | |
401 | // already-passed -C metadata flag with our own. Our rustc.rs | |
402 | // wrapper around the actual rustc will detect -C metadata being | |
403 | // passed and frob it with this extra string we're passing in. | |
404 | cargo.env("RUSTC_METADATA_SUFFIX", "rustc"); | |
8bb4bdeb XL |
405 | } |
406 | ||
476ff2be SL |
407 | // Enable usage of unstable features |
408 | cargo.env("RUSTC_BOOTSTRAP", "1"); | |
409 | self.add_rust_test_threads(&mut cargo); | |
5bcae85e | 410 | |
8bb4bdeb XL |
411 | // Almost all of the crates that we compile as part of the bootstrap may |
412 | // have a build script, including the standard library. To compile a | |
413 | // build script, however, it itself needs a standard library! This | |
414 | // introduces a bit of a pickle when we're compiling the standard | |
415 | // library itself. | |
416 | // | |
417 | // To work around this we actually end up using the snapshot compiler | |
418 | // (stage0) for compiling build scripts of the standard library itself. | |
419 | // The stage0 compiler is guaranteed to have a libstd available for use. | |
420 | // | |
421 | // For other crates, however, we know that we've already got a standard | |
422 | // library up and running, so we can use the normal compiler to compile | |
423 | // build scripts in that situation. | |
cc61c64b | 424 | if mode == Mode::Libstd { |
8bb4bdeb XL |
425 | cargo.env("RUSTC_SNAPSHOT", &self.rustc) |
426 | .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()); | |
427 | } else { | |
428 | cargo.env("RUSTC_SNAPSHOT", self.compiler_path(compiler)) | |
429 | .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler)); | |
430 | } | |
431 | ||
7cac9316 | 432 | // There are two invariants we must maintain: |
cc61c64b XL |
433 | // * stable crates cannot depend on unstable crates (general Rust rule), |
434 | // * crates that end up in the sysroot must be unstable (rustbuild rule). | |
435 | // | |
436 | // In order to do enforce the latter, we pass the env var | |
437 | // `RUSTBUILD_UNSTABLE` down the line for any crates which will end up | |
438 | // in the sysroot. We read this in bootstrap/bin/rustc.rs and if it is | |
439 | // set, then we pass the `rustbuild` feature to rustc when building the | |
440 | // the crate. | |
441 | // | |
442 | // In turn, crates that can be used here should recognise the `rustbuild` | |
443 | // feature and opt-in to `rustc_private`. | |
444 | // | |
445 | // We can't always pass `rustbuild` because crates which are outside of | |
7cac9316 | 446 | // the compiler, libs, and tests are stable and we don't want to make |
cc61c64b XL |
447 | // their deps unstable (since this would break the first invariant |
448 | // above). | |
7cac9316 XL |
449 | // |
450 | // FIXME: remove this after next stage0 | |
451 | if mode != Mode::Tool && stage == 0 { | |
cc61c64b XL |
452 | cargo.env("RUSTBUILD_UNSTABLE", "1"); |
453 | } | |
454 | ||
32a655c1 | 455 | // Ignore incremental modes except for stage0, since we're |
7cac9316 | 456 | // not guaranteeing correctness across builds if the compiler |
32a655c1 SL |
457 | // is changing under your feet.` |
458 | if self.flags.incremental && compiler.stage == 0 { | |
459 | let incr_dir = self.incremental_dir(compiler); | |
460 | cargo.env("RUSTC_INCREMENTAL", incr_dir); | |
461 | } | |
462 | ||
8bb4bdeb XL |
463 | if let Some(ref on_fail) = self.flags.on_fail { |
464 | cargo.env("RUSTC_ON_FAIL", on_fail); | |
465 | } | |
466 | ||
32a655c1 SL |
467 | let verbose = cmp::max(self.config.verbose, self.flags.verbose); |
468 | cargo.env("RUSTC_VERBOSE", format!("{}", verbose)); | |
469 | ||
5bcae85e SL |
470 | // Specify some various options for build scripts used throughout |
471 | // the build. | |
472 | // | |
473 | // FIXME: the guard against msvc shouldn't need to be here | |
474 | if !target.contains("msvc") { | |
475 | cargo.env(format!("CC_{}", target), self.cc(target)) | |
476 | .env(format!("AR_{}", target), self.ar(target).unwrap()) // only msvc is None | |
477 | .env(format!("CFLAGS_{}", target), self.cflags(target).join(" ")); | |
478 | } | |
479 | ||
cc61c64b | 480 | if self.config.extended && compiler.is_final_stage(self) { |
476ff2be SL |
481 | cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); |
482 | } | |
483 | ||
7cac9316 XL |
484 | // When being built Cargo will at some point call `nmake.exe` on Windows |
485 | // MSVC. Unfortunately `nmake` will read these two environment variables | |
486 | // below and try to intepret them. We're likely being run, however, from | |
487 | // MSYS `make` which uses the same variables. | |
488 | // | |
489 | // As a result, to prevent confusion and errors, we remove these | |
490 | // variables from our environment to prevent passing MSYS make flags to | |
491 | // nmake, causing it to blow up. | |
492 | if cfg!(target_env = "msvc") { | |
493 | cargo.env_remove("MAKE"); | |
494 | cargo.env_remove("MAKEFLAGS"); | |
495 | } | |
496 | ||
497 | // Environment variables *required* throughout the build | |
5bcae85e SL |
498 | // |
499 | // FIXME: should update code to not require this env var | |
500 | cargo.env("CFG_COMPILER_HOST_TRIPLE", target); | |
501 | ||
32a655c1 | 502 | if self.config.verbose() || self.flags.verbose() { |
5bcae85e SL |
503 | cargo.arg("-v"); |
504 | } | |
476ff2be SL |
505 | // FIXME: cargo bench does not accept `--release` |
506 | if self.config.rust_optimize && cmd != "bench" { | |
5bcae85e SL |
507 | cargo.arg("--release"); |
508 | } | |
8bb4bdeb XL |
509 | if self.config.locked_deps { |
510 | cargo.arg("--locked"); | |
511 | } | |
476ff2be SL |
512 | if self.config.vendor || self.is_sudo { |
513 | cargo.arg("--frozen"); | |
514 | } | |
7cac9316 XL |
515 | |
516 | self.ci_env.force_coloring_in_ci(&mut cargo); | |
517 | ||
5bcae85e SL |
518 | return cargo |
519 | } | |
520 | ||
521 | /// Get a path to the compiler specified. | |
522 | fn compiler_path(&self, compiler: &Compiler) -> PathBuf { | |
523 | if compiler.is_snapshot(self) { | |
524 | self.rustc.clone() | |
525 | } else { | |
526 | self.sysroot(compiler).join("bin").join(exe("rustc", compiler.host)) | |
527 | } | |
528 | } | |
529 | ||
530 | /// Get the specified tool built by the specified compiler | |
531 | fn tool(&self, compiler: &Compiler, tool: &str) -> PathBuf { | |
532 | self.cargo_out(compiler, Mode::Tool, compiler.host) | |
533 | .join(exe(tool, compiler.host)) | |
534 | } | |
535 | ||
536 | /// Get the `rustdoc` executable next to the specified compiler | |
537 | fn rustdoc(&self, compiler: &Compiler) -> PathBuf { | |
538 | let mut rustdoc = self.compiler_path(compiler); | |
539 | rustdoc.pop(); | |
540 | rustdoc.push(exe("rustdoc", compiler.host)); | |
541 | return rustdoc | |
542 | } | |
543 | ||
544 | /// Get a `Command` which is ready to run `tool` in `stage` built for | |
545 | /// `host`. | |
546 | fn tool_cmd(&self, compiler: &Compiler, tool: &str) -> Command { | |
547 | let mut cmd = Command::new(self.tool(&compiler, tool)); | |
32a655c1 SL |
548 | self.prepare_tool_cmd(compiler, &mut cmd); |
549 | return cmd | |
550 | } | |
551 | ||
552 | /// Prepares the `cmd` provided to be able to run the `compiler` provided. | |
553 | /// | |
554 | /// Notably this munges the dynamic library lookup path to point to the | |
555 | /// right location to run `compiler`. | |
556 | fn prepare_tool_cmd(&self, compiler: &Compiler, cmd: &mut Command) { | |
5bcae85e | 557 | let host = compiler.host; |
476ff2be | 558 | let mut paths = vec![ |
32a655c1 | 559 | self.sysroot_libdir(compiler, compiler.host), |
5bcae85e SL |
560 | self.cargo_out(compiler, Mode::Tool, host).join("deps"), |
561 | ]; | |
476ff2be SL |
562 | |
563 | // On MSVC a tool may invoke a C compiler (e.g. compiletest in run-make | |
564 | // mode) and that C compiler may need some extra PATH modification. Do | |
565 | // so here. | |
566 | if compiler.host.contains("msvc") { | |
567 | let curpaths = env::var_os("PATH").unwrap_or(OsString::new()); | |
568 | let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>(); | |
569 | for &(ref k, ref v) in self.cc[compiler.host].0.env() { | |
570 | if k != "PATH" { | |
571 | continue | |
572 | } | |
573 | for path in env::split_paths(v) { | |
574 | if !curpaths.contains(&path) { | |
575 | paths.push(path); | |
576 | } | |
577 | } | |
578 | } | |
579 | } | |
32a655c1 | 580 | add_lib_path(paths, cmd); |
5bcae85e SL |
581 | } |
582 | ||
583 | /// Get the space-separated set of activated features for the standard | |
584 | /// library. | |
585 | fn std_features(&self) -> String { | |
476ff2be | 586 | let mut features = "panic-unwind".to_string(); |
8bb4bdeb | 587 | |
5bcae85e SL |
588 | if self.config.debug_jemalloc { |
589 | features.push_str(" debug-jemalloc"); | |
590 | } | |
591 | if self.config.use_jemalloc { | |
592 | features.push_str(" jemalloc"); | |
593 | } | |
594 | if self.config.backtrace { | |
595 | features.push_str(" backtrace"); | |
596 | } | |
597 | return features | |
598 | } | |
599 | ||
600 | /// Get the space-separated set of activated features for the compiler. | |
601 | fn rustc_features(&self) -> String { | |
602 | let mut features = String::new(); | |
603 | if self.config.use_jemalloc { | |
604 | features.push_str(" jemalloc"); | |
605 | } | |
606 | return features | |
607 | } | |
608 | ||
609 | /// Component directory that Cargo will produce output into (e.g. | |
610 | /// release/debug) | |
611 | fn cargo_dir(&self) -> &'static str { | |
612 | if self.config.rust_optimize {"release"} else {"debug"} | |
613 | } | |
614 | ||
615 | /// Returns the sysroot for the `compiler` specified that *this build system | |
616 | /// generates*. | |
617 | /// | |
618 | /// That is, the sysroot for the stage0 compiler is not what the compiler | |
619 | /// thinks it is by default, but it's the same as the default for stages | |
620 | /// 1-3. | |
621 | fn sysroot(&self, compiler: &Compiler) -> PathBuf { | |
622 | if compiler.stage == 0 { | |
623 | self.out.join(compiler.host).join("stage0-sysroot") | |
624 | } else { | |
625 | self.out.join(compiler.host).join(format!("stage{}", compiler.stage)) | |
626 | } | |
627 | } | |
628 | ||
32a655c1 SL |
629 | /// Get the directory for incremental by-products when using the |
630 | /// given compiler. | |
631 | fn incremental_dir(&self, compiler: &Compiler) -> PathBuf { | |
632 | self.out.join(compiler.host).join(format!("stage{}-incremental", compiler.stage)) | |
633 | } | |
634 | ||
5bcae85e SL |
635 | /// Returns the libdir where the standard library and other artifacts are |
636 | /// found for a compiler's sysroot. | |
637 | fn sysroot_libdir(&self, compiler: &Compiler, target: &str) -> PathBuf { | |
638 | self.sysroot(compiler).join("lib").join("rustlib") | |
639 | .join(target).join("lib") | |
640 | } | |
641 | ||
642 | /// Returns the root directory for all output generated in a particular | |
643 | /// stage when running with a particular host compiler. | |
644 | /// | |
645 | /// The mode indicates what the root directory is for. | |
646 | fn stage_out(&self, compiler: &Compiler, mode: Mode) -> PathBuf { | |
647 | let suffix = match mode { | |
648 | Mode::Libstd => "-std", | |
649 | Mode::Libtest => "-test", | |
650 | Mode::Tool => "-tools", | |
651 | Mode::Librustc => "-rustc", | |
652 | }; | |
653 | self.out.join(compiler.host) | |
654 | .join(format!("stage{}{}", compiler.stage, suffix)) | |
655 | } | |
656 | ||
657 | /// Returns the root output directory for all Cargo output in a given stage, | |
7cac9316 | 658 | /// running a particular compiler, wehther or not we're building the |
5bcae85e SL |
659 | /// standard library, and targeting the specified architecture. |
660 | fn cargo_out(&self, | |
661 | compiler: &Compiler, | |
662 | mode: Mode, | |
663 | target: &str) -> PathBuf { | |
664 | self.stage_out(compiler, mode).join(target).join(self.cargo_dir()) | |
665 | } | |
666 | ||
667 | /// Root output directory for LLVM compiled for `target` | |
668 | /// | |
669 | /// Note that if LLVM is configured externally then the directory returned | |
670 | /// will likely be empty. | |
671 | fn llvm_out(&self, target: &str) -> PathBuf { | |
672 | self.out.join(target).join("llvm") | |
673 | } | |
674 | ||
c30ab7b3 SL |
675 | /// Output directory for all documentation for a target |
676 | fn doc_out(&self, target: &str) -> PathBuf { | |
677 | self.out.join(target).join("doc") | |
678 | } | |
679 | ||
8bb4bdeb XL |
680 | /// Output directory for all crate documentation for a target (temporary) |
681 | /// | |
682 | /// The artifacts here are then copied into `doc_out` above. | |
683 | fn crate_doc_out(&self, target: &str) -> PathBuf { | |
684 | self.out.join(target).join("crate-docs") | |
685 | } | |
686 | ||
5bcae85e SL |
687 | /// Returns true if no custom `llvm-config` is set for the specified target. |
688 | /// | |
689 | /// If no custom `llvm-config` was specified then Rust's llvm will be used. | |
690 | fn is_rust_llvm(&self, target: &str) -> bool { | |
691 | match self.config.target_config.get(target) { | |
692 | Some(ref c) => c.llvm_config.is_none(), | |
693 | None => true | |
694 | } | |
695 | } | |
696 | ||
697 | /// Returns the path to `llvm-config` for the specified target. | |
698 | /// | |
699 | /// If a custom `llvm-config` was specified for target then that's returned | |
700 | /// instead. | |
701 | fn llvm_config(&self, target: &str) -> PathBuf { | |
702 | let target_config = self.config.target_config.get(target); | |
703 | if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { | |
704 | s.clone() | |
705 | } else { | |
706 | self.llvm_out(&self.config.build).join("bin") | |
707 | .join(exe("llvm-config", target)) | |
708 | } | |
709 | } | |
710 | ||
711 | /// Returns the path to `FileCheck` binary for the specified target | |
712 | fn llvm_filecheck(&self, target: &str) -> PathBuf { | |
713 | let target_config = self.config.target_config.get(target); | |
714 | if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { | |
32a655c1 SL |
715 | let llvm_bindir = output(Command::new(s).arg("--bindir")); |
716 | Path::new(llvm_bindir.trim()).join(exe("FileCheck", target)) | |
5bcae85e SL |
717 | } else { |
718 | let base = self.llvm_out(&self.config.build).join("build"); | |
719 | let exe = exe("FileCheck", target); | |
8bb4bdeb | 720 | if !self.config.ninja && self.config.build.contains("msvc") { |
5bcae85e SL |
721 | base.join("Release/bin").join(exe) |
722 | } else { | |
723 | base.join("bin").join(exe) | |
724 | } | |
725 | } | |
726 | } | |
727 | ||
8bb4bdeb XL |
728 | /// Directory for libraries built from C/C++ code and shared between stages. |
729 | fn native_dir(&self, target: &str) -> PathBuf { | |
730 | self.out.join(target).join("native") | |
731 | } | |
732 | ||
5bcae85e SL |
733 | /// Root output directory for rust_test_helpers library compiled for |
734 | /// `target` | |
735 | fn test_helpers_out(&self, target: &str) -> PathBuf { | |
8bb4bdeb | 736 | self.native_dir(target).join("rust-test-helpers") |
5bcae85e SL |
737 | } |
738 | ||
739 | /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic | |
740 | /// library lookup path. | |
741 | fn add_rustc_lib_path(&self, compiler: &Compiler, cmd: &mut Command) { | |
742 | // Windows doesn't need dylib path munging because the dlls for the | |
743 | // compiler live next to the compiler and the system will find them | |
744 | // automatically. | |
745 | if cfg!(windows) { | |
746 | return | |
747 | } | |
748 | ||
749 | add_lib_path(vec![self.rustc_libdir(compiler)], cmd); | |
750 | } | |
751 | ||
476ff2be SL |
752 | /// Adds the `RUST_TEST_THREADS` env var if necessary |
753 | fn add_rust_test_threads(&self, cmd: &mut Command) { | |
754 | if env::var_os("RUST_TEST_THREADS").is_none() { | |
755 | cmd.env("RUST_TEST_THREADS", self.jobs().to_string()); | |
756 | } | |
5bcae85e SL |
757 | } |
758 | ||
759 | /// Returns the compiler's libdir where it stores the dynamic libraries that | |
760 | /// it itself links against. | |
761 | /// | |
762 | /// For example this returns `<sysroot>/lib` on Unix and `<sysroot>/bin` on | |
763 | /// Windows. | |
764 | fn rustc_libdir(&self, compiler: &Compiler) -> PathBuf { | |
765 | if compiler.is_snapshot(self) { | |
766 | self.rustc_snapshot_libdir() | |
767 | } else { | |
768 | self.sysroot(compiler).join(libdir(compiler.host)) | |
769 | } | |
770 | } | |
771 | ||
772 | /// Returns the libdir of the snapshot compiler. | |
773 | fn rustc_snapshot_libdir(&self) -> PathBuf { | |
774 | self.rustc.parent().unwrap().parent().unwrap() | |
775 | .join(libdir(&self.config.build)) | |
776 | } | |
777 | ||
778 | /// Runs a command, printing out nice contextual information if it fails. | |
779 | fn run(&self, cmd: &mut Command) { | |
780 | self.verbose(&format!("running: {:?}", cmd)); | |
781 | run_silent(cmd) | |
782 | } | |
783 | ||
8bb4bdeb XL |
784 | /// Runs a command, printing out nice contextual information if it fails. |
785 | fn run_quiet(&self, cmd: &mut Command) { | |
786 | self.verbose(&format!("running: {:?}", cmd)); | |
787 | run_suppressed(cmd) | |
788 | } | |
789 | ||
7cac9316 XL |
790 | /// Runs a command, printing out nice contextual information if it fails. |
791 | /// Exits if the command failed to execute at all, otherwise returns its | |
792 | /// `status.success()`. | |
793 | fn try_run(&self, cmd: &mut Command) -> bool { | |
794 | self.verbose(&format!("running: {:?}", cmd)); | |
795 | try_run_silent(cmd) | |
796 | } | |
797 | ||
798 | /// Runs a command, printing out nice contextual information if it fails. | |
799 | /// Exits if the command failed to execute at all, otherwise returns its | |
800 | /// `status.success()`. | |
801 | fn try_run_quiet(&self, cmd: &mut Command) -> bool { | |
802 | self.verbose(&format!("running: {:?}", cmd)); | |
803 | try_run_suppressed(cmd) | |
804 | } | |
805 | ||
5bcae85e SL |
806 | /// Prints a message if this build is configured in verbose mode. |
807 | fn verbose(&self, msg: &str) { | |
32a655c1 | 808 | if self.flags.verbose() || self.config.verbose() { |
5bcae85e SL |
809 | println!("{}", msg); |
810 | } | |
811 | } | |
812 | ||
813 | /// Returns the number of parallel jobs that have been configured for this | |
814 | /// build. | |
815 | fn jobs(&self) -> u32 { | |
816 | self.flags.jobs.unwrap_or(num_cpus::get() as u32) | |
817 | } | |
818 | ||
819 | /// Returns the path to the C compiler for the target specified. | |
820 | fn cc(&self, target: &str) -> &Path { | |
821 | self.cc[target].0.path() | |
822 | } | |
823 | ||
824 | /// Returns a list of flags to pass to the C compiler for the target | |
825 | /// specified. | |
826 | fn cflags(&self, target: &str) -> Vec<String> { | |
827 | // Filter out -O and /O (the optimization flags) that we picked up from | |
828 | // gcc-rs because the build scripts will determine that for themselves. | |
829 | let mut base = self.cc[target].0.args().iter() | |
830 | .map(|s| s.to_string_lossy().into_owned()) | |
831 | .filter(|s| !s.starts_with("-O") && !s.starts_with("/O")) | |
832 | .collect::<Vec<_>>(); | |
833 | ||
cc61c64b | 834 | // If we're compiling on macOS then we add a few unconditional flags |
5bcae85e SL |
835 | // indicating that we want libc++ (more filled out than libstdc++) and |
836 | // we want to compile for 10.7. This way we can ensure that | |
837 | // LLVM/jemalloc/etc are all properly compiled. | |
838 | if target.contains("apple-darwin") { | |
839 | base.push("-stdlib=libc++".into()); | |
5bcae85e | 840 | } |
7cac9316 XL |
841 | |
842 | // Work around an apparently bad MinGW / GCC optimization, | |
843 | // See: http://lists.llvm.org/pipermail/cfe-dev/2016-December/051980.html | |
844 | // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78936 | |
845 | if target == "i686-pc-windows-gnu" { | |
846 | base.push("-fno-omit-frame-pointer".into()); | |
847 | } | |
5bcae85e SL |
848 | return base |
849 | } | |
850 | ||
851 | /// Returns the path to the `ar` archive utility for the target specified. | |
852 | fn ar(&self, target: &str) -> Option<&Path> { | |
853 | self.cc[target].1.as_ref().map(|p| &**p) | |
854 | } | |
855 | ||
856 | /// Returns the path to the C++ compiler for the target specified, may panic | |
857 | /// if no C++ compiler was configured for the target. | |
858 | fn cxx(&self, target: &str) -> &Path { | |
9e0c209e SL |
859 | match self.cxx.get(target) { |
860 | Some(p) => p.path(), | |
861 | None => panic!("\n\ntarget `{}` is not configured as a host, | |
862 | only as a target\n\n", target), | |
863 | } | |
5bcae85e SL |
864 | } |
865 | ||
866 | /// Returns flags to pass to the compiler to generate code for `target`. | |
867 | fn rustc_flags(&self, target: &str) -> Vec<String> { | |
868 | // New flags should be added here with great caution! | |
869 | // | |
870 | // It's quite unfortunate to **require** flags to generate code for a | |
871 | // target, so it should only be passed here if absolutely necessary! | |
872 | // Most default configuration should be done through target specs rather | |
873 | // than an entry here. | |
874 | ||
875 | let mut base = Vec::new(); | |
c30ab7b3 SL |
876 | if target != self.config.build && !target.contains("msvc") && |
877 | !target.contains("emscripten") { | |
5bcae85e SL |
878 | base.push(format!("-Clinker={}", self.cc(target).display())); |
879 | } | |
880 | return base | |
85aaf69f | 881 | } |
9e0c209e SL |
882 | |
883 | /// Returns the "musl root" for this `target`, if defined | |
884 | fn musl_root(&self, target: &str) -> Option<&Path> { | |
c30ab7b3 SL |
885 | self.config.target_config.get(target) |
886 | .and_then(|t| t.musl_root.as_ref()) | |
9e0c209e SL |
887 | .or(self.config.musl_root.as_ref()) |
888 | .map(|p| &**p) | |
889 | } | |
476ff2be | 890 | |
7cac9316 XL |
891 | /// Returns whether the target will be tested using the `remote-test-client` |
892 | /// and `remote-test-server` binaries. | |
893 | fn remote_tested(&self, target: &str) -> bool { | |
894 | self.qemu_rootfs(target).is_some() || target.contains("android") | |
895 | } | |
896 | ||
8bb4bdeb XL |
897 | /// Returns the root of the "rootfs" image that this target will be using, |
898 | /// if one was configured. | |
899 | /// | |
900 | /// If `Some` is returned then that means that tests for this target are | |
901 | /// emulated with QEMU and binaries will need to be shipped to the emulator. | |
902 | fn qemu_rootfs(&self, target: &str) -> Option<&Path> { | |
903 | self.config.target_config.get(target) | |
904 | .and_then(|t| t.qemu_rootfs.as_ref()) | |
905 | .map(|p| &**p) | |
906 | } | |
907 | ||
476ff2be SL |
908 | /// Path to the python interpreter to use |
909 | fn python(&self) -> &Path { | |
910 | self.config.python.as_ref().unwrap() | |
911 | } | |
32a655c1 SL |
912 | |
913 | /// Tests whether the `compiler` compiling for `target` should be forced to | |
914 | /// use a stage1 compiler instead. | |
915 | /// | |
916 | /// Currently, by default, the build system does not perform a "full | |
917 | /// bootstrap" by default where we compile the compiler three times. | |
918 | /// Instead, we compile the compiler two times. The final stage (stage2) | |
919 | /// just copies the libraries from the previous stage, which is what this | |
920 | /// method detects. | |
921 | /// | |
922 | /// Here we return `true` if: | |
923 | /// | |
924 | /// * The build isn't performing a full bootstrap | |
925 | /// * The `compiler` is in the final stage, 2 | |
926 | /// * We're not cross-compiling, so the artifacts are already available in | |
927 | /// stage1 | |
928 | /// | |
929 | /// When all of these conditions are met the build will lift artifacts from | |
930 | /// the previous stage forward. | |
931 | fn force_use_stage1(&self, compiler: &Compiler, target: &str) -> bool { | |
932 | !self.config.full_bootstrap && | |
933 | compiler.stage >= 2 && | |
934 | self.config.host.iter().any(|h| h == target) | |
935 | } | |
8bb4bdeb XL |
936 | |
937 | /// Returns the directory that OpenSSL artifacts are compiled into if | |
938 | /// configured to do so. | |
939 | fn openssl_dir(&self, target: &str) -> Option<PathBuf> { | |
940 | // OpenSSL not used on Windows | |
941 | if target.contains("windows") { | |
942 | None | |
943 | } else if self.config.openssl_static { | |
944 | Some(self.out.join(target).join("openssl")) | |
945 | } else { | |
946 | None | |
947 | } | |
948 | } | |
949 | ||
950 | /// Returns the directory that OpenSSL artifacts are installed into if | |
951 | /// configured as such. | |
952 | fn openssl_install_dir(&self, target: &str) -> Option<PathBuf> { | |
953 | self.openssl_dir(target).map(|p| p.join("install")) | |
954 | } | |
955 | ||
956 | /// Given `num` in the form "a.b.c" return a "release string" which | |
957 | /// describes the release version number. | |
958 | /// | |
959 | /// For example on nightly this returns "a.b.c-nightly", on beta it returns | |
960 | /// "a.b.c-beta.1" and on stable it just returns "a.b.c". | |
961 | fn release(&self, num: &str) -> String { | |
962 | match &self.config.channel[..] { | |
963 | "stable" => num.to_string(), | |
964 | "beta" => format!("{}-beta{}", num, channel::CFG_PRERELEASE_VERSION), | |
965 | "nightly" => format!("{}-nightly", num), | |
966 | _ => format!("{}-dev", num), | |
967 | } | |
968 | } | |
969 | ||
970 | /// Returns the value of `release` above for Rust itself. | |
971 | fn rust_release(&self) -> String { | |
972 | self.release(channel::CFG_RELEASE_NUM) | |
973 | } | |
974 | ||
975 | /// Returns the "package version" for a component given the `num` release | |
976 | /// number. | |
977 | /// | |
978 | /// The package version is typically what shows up in the names of tarballs. | |
979 | /// For channels like beta/nightly it's just the channel name, otherwise | |
980 | /// it's the `num` provided. | |
981 | fn package_vers(&self, num: &str) -> String { | |
982 | match &self.config.channel[..] { | |
983 | "stable" => num.to_string(), | |
984 | "beta" => "beta".to_string(), | |
985 | "nightly" => "nightly".to_string(), | |
986 | _ => format!("{}-dev", num), | |
987 | } | |
988 | } | |
989 | ||
990 | /// Returns the value of `package_vers` above for Rust itself. | |
991 | fn rust_package_vers(&self) -> String { | |
992 | self.package_vers(channel::CFG_RELEASE_NUM) | |
993 | } | |
994 | ||
995 | /// Returns the value of `package_vers` above for Cargo | |
996 | fn cargo_package_vers(&self) -> String { | |
cc61c64b | 997 | self.package_vers(&self.release_num("cargo")) |
8bb4bdeb XL |
998 | } |
999 | ||
7cac9316 XL |
1000 | /// Returns the value of `package_vers` above for rls |
1001 | fn rls_package_vers(&self) -> String { | |
1002 | self.package_vers(&self.release_num("rls")) | |
1003 | } | |
1004 | ||
8bb4bdeb XL |
1005 | /// Returns the `version` string associated with this compiler for Rust |
1006 | /// itself. | |
1007 | /// | |
1008 | /// Note that this is a descriptive string which includes the commit date, | |
1009 | /// sha, version, etc. | |
1010 | fn rust_version(&self) -> String { | |
1011 | self.rust_info.version(self, channel::CFG_RELEASE_NUM) | |
1012 | } | |
1013 | ||
cc61c64b XL |
1014 | /// Returns the `a.b.c` version that the given package is at. |
1015 | fn release_num(&self, package: &str) -> String { | |
8bb4bdeb | 1016 | let mut toml = String::new(); |
7cac9316 | 1017 | let toml_file_name = self.src.join(&format!("src/tools/{}/Cargo.toml", package)); |
cc61c64b | 1018 | t!(t!(File::open(toml_file_name)).read_to_string(&mut toml)); |
8bb4bdeb XL |
1019 | for line in toml.lines() { |
1020 | let prefix = "version = \""; | |
1021 | let suffix = "\""; | |
1022 | if line.starts_with(prefix) && line.ends_with(suffix) { | |
1023 | return line[prefix.len()..line.len() - suffix.len()].to_string() | |
1024 | } | |
1025 | } | |
1026 | ||
cc61c64b | 1027 | panic!("failed to find version in {}'s Cargo.toml", package) |
8bb4bdeb XL |
1028 | } |
1029 | ||
1030 | /// Returns whether unstable features should be enabled for the compiler | |
1031 | /// we're building. | |
1032 | fn unstable_features(&self) -> bool { | |
1033 | match &self.config.channel[..] { | |
1034 | "stable" | "beta" => false, | |
1035 | "nightly" | _ => true, | |
1036 | } | |
1037 | } | |
7cac9316 XL |
1038 | |
1039 | /// Fold the output of the commands after this method into a group. The fold | |
1040 | /// ends when the returned object is dropped. Folding can only be used in | |
1041 | /// the Travis CI environment. | |
1042 | pub fn fold_output<D, F>(&self, name: F) -> Option<OutputFolder> | |
1043 | where D: Into<String>, F: FnOnce() -> D | |
1044 | { | |
1045 | if self.ci_env == CiEnv::Travis { | |
1046 | Some(OutputFolder::new(name().into())) | |
1047 | } else { | |
1048 | None | |
1049 | } | |
1050 | } | |
85aaf69f SL |
1051 | } |
1052 | ||
5bcae85e SL |
1053 | impl<'a> Compiler<'a> { |
1054 | /// Creates a new complier for the specified stage/host | |
1055 | fn new(stage: u32, host: &'a str) -> Compiler<'a> { | |
1056 | Compiler { stage: stage, host: host } | |
1057 | } | |
1058 | ||
1059 | /// Returns whether this is a snapshot compiler for `build`'s configuration | |
1060 | fn is_snapshot(&self, build: &Build) -> bool { | |
1061 | self.stage == 0 && self.host == build.config.build | |
1062 | } | |
32a655c1 SL |
1063 | |
1064 | /// Returns if this compiler should be treated as a final stage one in the | |
1065 | /// current build session. | |
1066 | /// This takes into account whether we're performing a full bootstrap or | |
1067 | /// not; don't directly compare the stage with `2`! | |
1068 | fn is_final_stage(&self, build: &Build) -> bool { | |
1069 | let final_stage = if build.config.full_bootstrap { 2 } else { 1 }; | |
1070 | self.stage >= final_stage | |
1071 | } | |
223e47cc | 1072 | } |