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.
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.
11 //! Implementation of rustbuild, the Rust build system.
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
16 //! builds, building artifacts like LLVM, etc. The goals of rustbuild are:
18 //! * To be an easily understandable, easily extensible, and maintainable build
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
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.
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.
40 //! When you execute `x.py build`, the steps which are executed are:
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.
47 //! * Rustbuild takes over, performs sanity checks, probes the environment,
48 //! reads configuration, builds up a list of steps, and then starts executing
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
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.
62 //! ## Further information
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.
70 extern crate build_helper
;
72 extern crate filetime
;
75 extern crate num_cpus
;
76 extern crate rustc_serialize
;
80 use std
::collections
::HashMap
;
82 use std
::ffi
::OsString
;
83 use std
::fs
::{self, File}
;
85 use std
::path
::{Component, PathBuf, Path}
;
86 use std
::process
::Command
;
88 use build_helper
::{run_silent, run_suppressed, output, mtime}
;
90 use util
::{exe, libdir, add_lib_path}
;
113 pub unsafe fn setup() {}
116 pub use config
::Config
;
117 pub use flags
::{Flags, Subcommand}
;
119 /// A structure representing a Rust compiler.
121 /// Each compiler has a `stage` that it is associated with and a `host` that
122 /// corresponds to the platform the compiler runs on. This structure is used as
123 /// a parameter to many methods below.
124 #[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
125 pub struct Compiler
<'a
> {
130 /// Global configuration for the build system.
132 /// This structure transitively contains all configuration for the build system.
133 /// All filesystem-encoded configuration is in `config`, all flags are in
134 /// `flags`, and then parsed or probed information is listed in the keys below.
136 /// This structure is a parameter of almost all methods in the build system,
137 /// although most functions are implemented as free functions rather than
138 /// methods specifically on this structure itself (to make it easier to
141 // User-specified configuration via config.toml
144 // User-specified configuration via CLI flags
147 // Derived properties from the above two configurations
152 rust_info
: channel
::GitInfo
,
153 cargo_info
: channel
::GitInfo
,
154 rls_info
: channel
::GitInfo
,
157 // Probed tools at runtime
158 lldb_version
: Option
<String
>,
159 lldb_python_dir
: Option
<String
>,
161 // Runtime state filled in later on
162 cc
: HashMap
<String
, (gcc
::Tool
, Option
<PathBuf
>)>,
163 cxx
: HashMap
<String
, gcc
::Tool
>,
164 crates
: HashMap
<String
, Crate
>,
181 /// The various "modes" of invoking Cargo.
183 /// These entries currently correspond to the various output directories of the
184 /// build system, with each mod generating output in a different directory.
185 #[derive(Clone, Copy, PartialEq, Eq)]
187 /// This cargo is going to build the standard library, placing output in the
188 /// "stageN-std" directory.
191 /// This cargo is going to build libtest, placing output in the
192 /// "stageN-test" directory.
195 /// This cargo is going to build librustc and compiler libraries, placing
196 /// output in the "stageN-rustc" directory.
199 /// This cargo is going to some build tool, placing output in the
200 /// "stageN-tools" directory.
205 /// Creates a new set of build configuration from the `flags` on the command
206 /// line and the filesystem `config`.
208 /// By default all build output will be placed in the current directory.
209 pub fn new(flags
: Flags
, config
: Config
) -> Build
{
210 let cwd
= t
!(env
::current_dir());
211 let src
= flags
.src
.clone().or_else(|| {
212 env
::var_os("SRC").map(|x
| x
.into())
213 }).unwrap_or(cwd
.clone());
214 let out
= cwd
.join("build");
216 let stage0_root
= out
.join(&config
.build
).join("stage0/bin");
217 let rustc
= match config
.rustc
{
218 Some(ref s
) => PathBuf
::from(s
),
219 None
=> stage0_root
.join(exe("rustc", &config
.build
)),
221 let cargo
= match config
.cargo
{
222 Some(ref s
) => PathBuf
::from(s
),
223 None
=> stage0_root
.join(exe("cargo", &config
.build
)),
225 let local_rebuild
= config
.local_rebuild
;
227 let is_sudo
= match env
::var_os("SUDO_USER") {
229 match env
::var_os("USER") {
230 Some(user
) => user
!= sudo_user
,
236 let rust_info
= channel
::GitInfo
::new(&src
);
237 let cargo_info
= channel
::GitInfo
::new(&src
.join("cargo"));
238 let rls_info
= channel
::GitInfo
::new(&src
.join("rls"));
239 let src_is_git
= src
.join(".git").exists();
249 rust_info
: rust_info
,
250 cargo_info
: cargo_info
,
252 local_rebuild
: local_rebuild
,
255 crates
: HashMap
::new(),
257 lldb_python_dir
: None
,
259 src_is_git
: src_is_git
,
263 /// Executes the entire build, as configured by the flags and configuration.
264 pub fn build(&mut self) {
269 if let Subcommand
::Clean
= self.flags
.cmd
{
270 return clean
::clean(self);
273 self.verbose("finding compilers");
275 self.verbose("running sanity check");
277 // If local-rust is the same major.minor as the current version, then force a local-rebuild
278 let local_version_verbose
= output(
279 Command
::new(&self.rustc
).arg("--version").arg("--verbose"));
280 let local_release
= local_version_verbose
281 .lines().filter(|x
| x
.starts_with("release:"))
282 .next().unwrap().trim_left_matches("release:").trim();
283 let my_version
= channel
::CFG_RELEASE_NUM
;
284 if local_release
.split('
.'
).take(2).eq(my_version
.split('
.'
).take(2)) {
285 self.verbose(&format
!("auto-detected local-rebuild {}", local_release
));
286 self.local_rebuild
= true;
288 self.verbose("updating submodules");
289 self.update_submodules();
290 self.verbose("learning about cargo");
291 metadata
::build(self);
296 /// Updates all git submodules that we have.
298 /// This will detect if any submodules are out of date an run the necessary
299 /// commands to sync them all with upstream.
300 fn update_submodules(&self) {
301 struct Submodule
<'a
> {
307 // The submodule may have staged/unstaged changes
309 // Or could be initialized but never updated
311 // The submodule, itself, has extra commits but those changes haven't been commited to
312 // the (outer) git repository
316 if !self.src_is_git
|| !self.config
.submodules
{
320 let mut cmd
= Command
::new("git");
321 cmd
.current_dir(&self.src
);
324 let git_submodule
= || {
325 let mut cmd
= Command
::new("git");
326 cmd
.current_dir(&self.src
).arg("submodule");
330 // FIXME: this takes a seriously long time to execute on Windows and a
331 // nontrivial amount of time on Unix, we should have a better way
332 // of detecting whether we need to run all the submodule commands
334 let out
= output(git_submodule().arg("status"));
335 let mut submodules
= vec
![];
336 for line
in out
.lines() {
337 // NOTE `git submodule status` output looks like this:
339 // -5066b7dcab7e700844b0e2ba71b8af9dc627a59b src/liblibc
340 // +b37ef24aa82d2be3a3cc0fe89bf82292f4ca181c src/compiler-rt (remotes/origin/..)
341 // e058ca661692a8d01f8cf9d35939dfe3105ce968 src/jemalloc (3.6.0-533-ge058ca6)
343 // The first character can be '-', '+' or ' ' and denotes the `State` of the submodule
344 // Right next to this character is the SHA-1 of the submodule HEAD
345 // And after that comes the path to the submodule
346 let path
= Path
::new(line
[1..].split(' '
).skip(1).next().unwrap());
347 let state
= if line
.starts_with('
-'
) {
348 State
::NotInitialized
349 } else if line
.starts_with('
+'
) {
351 } else if line
.starts_with(' '
) {
354 panic
!("unexpected git submodule state: {:?}", line
.chars().next());
357 submodules
.push(Submodule { path: path, state: state }
)
360 self.run(git_submodule().arg("sync"));
362 for submodule
in submodules
{
363 // If using llvm-root then don't touch the llvm submodule.
364 if submodule
.path
.components().any(|c
| c
== Component
::Normal("llvm".as_ref())) &&
365 self.config
.target_config
.get(&self.config
.build
)
366 .and_then(|c
| c
.llvm_config
.as_ref()).is_some()
371 if submodule
.path
.components().any(|c
| c
== Component
::Normal("jemalloc".as_ref())) &&
372 !self.config
.use_jemalloc
377 // `submodule.path` is the relative path to a submodule (from the repository root)
378 // `submodule_path` is the path to a submodule from the cwd
380 // use `submodule.path` when e.g. executing a submodule specific command from the
382 // use `submodule_path` when e.g. executing a normal git command for the submodule
383 // (set via `current_dir`)
384 let submodule_path
= self.src
.join(submodule
.path
);
386 match submodule
.state
{
387 State
::MaybeDirty
=> {
388 // drop staged changes
389 self.run(git().current_dir(&submodule_path
)
390 .args(&["reset", "--hard"]));
391 // drops unstaged changes
392 self.run(git().current_dir(&submodule_path
)
393 .args(&["clean", "-fdx"]));
395 State
::NotInitialized
=> {
396 self.run(git_submodule().arg("init").arg(submodule
.path
));
397 self.run(git_submodule().arg("update").arg(submodule
.path
));
399 State
::OutOfSync
=> {
400 // drops submodule commits that weren't reported to the (outer) git repository
401 self.run(git_submodule().arg("update").arg(submodule
.path
));
402 self.run(git().current_dir(&submodule_path
)
403 .args(&["reset", "--hard"]));
404 self.run(git().current_dir(&submodule_path
)
405 .args(&["clean", "-fdx"]));
411 /// Clear out `dir` if `input` is newer.
413 /// After this executes, it will also ensure that `dir` exists.
414 fn clear_if_dirty(&self, dir
: &Path
, input
: &Path
) {
415 let stamp
= dir
.join(".stamp");
416 if mtime(&stamp
) < mtime(input
) {
417 self.verbose(&format
!("Dirty - {}", dir
.display()));
418 let _
= fs
::remove_dir_all(dir
);
419 } else if stamp
.exists() {
422 t
!(fs
::create_dir_all(dir
));
423 t
!(File
::create(stamp
));
426 /// Prepares an invocation of `cargo` to be run.
428 /// This will create a `Command` that represents a pending execution of
429 /// Cargo. This cargo will be configured to use `compiler` as the actual
430 /// rustc compiler, its output will be scoped by `mode`'s output directory,
431 /// it will pass the `--target` flag for the specified `target`, and will be
432 /// executing the Cargo command `cmd`.
437 cmd
: &str) -> Command
{
438 let mut cargo
= Command
::new(&self.cargo
);
439 let out_dir
= self.stage_out(compiler
, mode
);
440 cargo
.env("CARGO_TARGET_DIR", out_dir
)
442 .arg("-j").arg(self.jobs().to_string())
443 .arg("--target").arg(target
);
445 // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
446 // Force cargo to output binaries with disambiguating hashes in the name
447 cargo
.env("__CARGO_DEFAULT_LIB_METADATA", "1");
450 if compiler
.stage
== 0 && self.local_rebuild
{
451 // Assume the local-rebuild rustc already has stage1 features.
454 stage
= compiler
.stage
;
457 // Customize the compiler we're running. Specify the compiler to cargo
458 // as our shim and then pass it some various options used to configure
459 // how the actual compiler itself is called.
461 // These variables are primarily all read by
462 // src/bootstrap/bin/{rustc.rs,rustdoc.rs}
463 cargo
.env("RUSTBUILD_NATIVE_DIR", self.native_dir(target
))
464 .env("RUSTC", self.out
.join("bootstrap/debug/rustc"))
465 .env("RUSTC_REAL", self.compiler_path(compiler
))
466 .env("RUSTC_STAGE", stage
.to_string())
467 .env("RUSTC_CODEGEN_UNITS",
468 self.config
.rust_codegen_units
.to_string())
469 .env("RUSTC_DEBUG_ASSERTIONS",
470 self.config
.rust_debug_assertions
.to_string())
471 .env("RUSTC_SYSROOT", self.sysroot(compiler
))
472 .env("RUSTC_LIBDIR", self.rustc_libdir(compiler
))
473 .env("RUSTC_RPATH", self.config
.rust_rpath
.to_string())
474 .env("RUSTDOC", self.out
.join("bootstrap/debug/rustdoc"))
475 .env("RUSTDOC_REAL", self.rustdoc(compiler
))
476 .env("RUSTC_FLAGS", self.rustc_flags(target
).join(" "));
478 // Tools don't get debuginfo right now, e.g. cargo and rls don't get
479 // compiled with debuginfo.
480 if mode
!= Mode
::Tool
{
481 cargo
.env("RUSTC_DEBUGINFO", self.config
.rust_debuginfo
.to_string())
482 .env("RUSTC_DEBUGINFO_LINES", self.config
.rust_debuginfo_lines
.to_string());
485 // Enable usage of unstable features
486 cargo
.env("RUSTC_BOOTSTRAP", "1");
487 self.add_rust_test_threads(&mut cargo
);
489 // Almost all of the crates that we compile as part of the bootstrap may
490 // have a build script, including the standard library. To compile a
491 // build script, however, it itself needs a standard library! This
492 // introduces a bit of a pickle when we're compiling the standard
495 // To work around this we actually end up using the snapshot compiler
496 // (stage0) for compiling build scripts of the standard library itself.
497 // The stage0 compiler is guaranteed to have a libstd available for use.
499 // For other crates, however, we know that we've already got a standard
500 // library up and running, so we can use the normal compiler to compile
501 // build scripts in that situation.
502 if mode
== Mode
::Libstd
{
503 cargo
.env("RUSTC_SNAPSHOT", &self.rustc
)
504 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
506 cargo
.env("RUSTC_SNAPSHOT", self.compiler_path(compiler
))
507 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler
));
510 // There are two invariants we try must maintain:
511 // * stable crates cannot depend on unstable crates (general Rust rule),
512 // * crates that end up in the sysroot must be unstable (rustbuild rule).
514 // In order to do enforce the latter, we pass the env var
515 // `RUSTBUILD_UNSTABLE` down the line for any crates which will end up
516 // in the sysroot. We read this in bootstrap/bin/rustc.rs and if it is
517 // set, then we pass the `rustbuild` feature to rustc when building the
520 // In turn, crates that can be used here should recognise the `rustbuild`
521 // feature and opt-in to `rustc_private`.
523 // We can't always pass `rustbuild` because crates which are outside of
524 // the comipiler, libs, and tests are stable and we don't want to make
525 // their deps unstable (since this would break the first invariant
527 if mode
!= Mode
::Tool
{
528 cargo
.env("RUSTBUILD_UNSTABLE", "1");
531 // Ignore incremental modes except for stage0, since we're
532 // not guaranteeing correctness acros builds if the compiler
533 // is changing under your feet.`
534 if self.flags
.incremental
&& compiler
.stage
== 0 {
535 let incr_dir
= self.incremental_dir(compiler
);
536 cargo
.env("RUSTC_INCREMENTAL", incr_dir
);
539 if let Some(ref on_fail
) = self.flags
.on_fail
{
540 cargo
.env("RUSTC_ON_FAIL", on_fail
);
543 let verbose
= cmp
::max(self.config
.verbose
, self.flags
.verbose
);
544 cargo
.env("RUSTC_VERBOSE", format
!("{}", verbose
));
546 // Specify some various options for build scripts used throughout
549 // FIXME: the guard against msvc shouldn't need to be here
550 if !target
.contains("msvc") {
551 cargo
.env(format
!("CC_{}", target
), self.cc(target
))
552 .env(format
!("AR_{}", target
), self.ar(target
).unwrap()) // only msvc is None
553 .env(format
!("CFLAGS_{}", target
), self.cflags(target
).join(" "));
556 if self.config
.extended
&& compiler
.is_final_stage(self) {
557 cargo
.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
560 // Environment variables *required* needed throughout the build
562 // FIXME: should update code to not require this env var
563 cargo
.env("CFG_COMPILER_HOST_TRIPLE", target
);
565 if self.config
.verbose() || self.flags
.verbose() {
568 // FIXME: cargo bench does not accept `--release`
569 if self.config
.rust_optimize
&& cmd
!= "bench" {
570 cargo
.arg("--release");
572 if self.config
.locked_deps
{
573 cargo
.arg("--locked");
575 if self.config
.vendor
|| self.is_sudo
{
576 cargo
.arg("--frozen");
581 /// Get a path to the compiler specified.
582 fn compiler_path(&self, compiler
: &Compiler
) -> PathBuf
{
583 if compiler
.is_snapshot(self) {
586 self.sysroot(compiler
).join("bin").join(exe("rustc", compiler
.host
))
590 /// Get the specified tool built by the specified compiler
591 fn tool(&self, compiler
: &Compiler
, tool
: &str) -> PathBuf
{
592 self.cargo_out(compiler
, Mode
::Tool
, compiler
.host
)
593 .join(exe(tool
, compiler
.host
))
596 /// Get the `rustdoc` executable next to the specified compiler
597 fn rustdoc(&self, compiler
: &Compiler
) -> PathBuf
{
598 let mut rustdoc
= self.compiler_path(compiler
);
600 rustdoc
.push(exe("rustdoc", compiler
.host
));
604 /// Get a `Command` which is ready to run `tool` in `stage` built for
606 fn tool_cmd(&self, compiler
: &Compiler
, tool
: &str) -> Command
{
607 let mut cmd
= Command
::new(self.tool(&compiler
, tool
));
608 self.prepare_tool_cmd(compiler
, &mut cmd
);
612 /// Prepares the `cmd` provided to be able to run the `compiler` provided.
614 /// Notably this munges the dynamic library lookup path to point to the
615 /// right location to run `compiler`.
616 fn prepare_tool_cmd(&self, compiler
: &Compiler
, cmd
: &mut Command
) {
617 let host
= compiler
.host
;
618 let mut paths
= vec
![
619 self.sysroot_libdir(compiler
, compiler
.host
),
620 self.cargo_out(compiler
, Mode
::Tool
, host
).join("deps"),
623 // On MSVC a tool may invoke a C compiler (e.g. compiletest in run-make
624 // mode) and that C compiler may need some extra PATH modification. Do
626 if compiler
.host
.contains("msvc") {
627 let curpaths
= env
::var_os("PATH").unwrap_or(OsString
::new());
628 let curpaths
= env
::split_paths(&curpaths
).collect
::<Vec
<_
>>();
629 for &(ref k
, ref v
) in self.cc
[compiler
.host
].0.env() {
633 for path
in env
::split_paths(v
) {
634 if !curpaths
.contains(&path
) {
640 add_lib_path(paths
, cmd
);
643 /// Get the space-separated set of activated features for the standard
645 fn std_features(&self) -> String
{
646 let mut features
= "panic-unwind".to_string();
648 if self.config
.debug_jemalloc
{
649 features
.push_str(" debug-jemalloc");
651 if self.config
.use_jemalloc
{
652 features
.push_str(" jemalloc");
654 if self.config
.backtrace
{
655 features
.push_str(" backtrace");
660 /// Get the space-separated set of activated features for the compiler.
661 fn rustc_features(&self) -> String
{
662 let mut features
= String
::new();
663 if self.config
.use_jemalloc
{
664 features
.push_str(" jemalloc");
669 /// Component directory that Cargo will produce output into (e.g.
671 fn cargo_dir(&self) -> &'
static str {
672 if self.config
.rust_optimize {"release"}
else {"debug"}
675 /// Returns the sysroot for the `compiler` specified that *this build system
678 /// That is, the sysroot for the stage0 compiler is not what the compiler
679 /// thinks it is by default, but it's the same as the default for stages
681 fn sysroot(&self, compiler
: &Compiler
) -> PathBuf
{
682 if compiler
.stage
== 0 {
683 self.out
.join(compiler
.host
).join("stage0-sysroot")
685 self.out
.join(compiler
.host
).join(format
!("stage{}", compiler
.stage
))
689 /// Get the directory for incremental by-products when using the
691 fn incremental_dir(&self, compiler
: &Compiler
) -> PathBuf
{
692 self.out
.join(compiler
.host
).join(format
!("stage{}-incremental", compiler
.stage
))
695 /// Returns the libdir where the standard library and other artifacts are
696 /// found for a compiler's sysroot.
697 fn sysroot_libdir(&self, compiler
: &Compiler
, target
: &str) -> PathBuf
{
698 self.sysroot(compiler
).join("lib").join("rustlib")
699 .join(target
).join("lib")
702 /// Returns the root directory for all output generated in a particular
703 /// stage when running with a particular host compiler.
705 /// The mode indicates what the root directory is for.
706 fn stage_out(&self, compiler
: &Compiler
, mode
: Mode
) -> PathBuf
{
707 let suffix
= match mode
{
708 Mode
::Libstd
=> "-std",
709 Mode
::Libtest
=> "-test",
710 Mode
::Tool
=> "-tools",
711 Mode
::Librustc
=> "-rustc",
713 self.out
.join(compiler
.host
)
714 .join(format
!("stage{}{}", compiler
.stage
, suffix
))
717 /// Returns the root output directory for all Cargo output in a given stage,
718 /// running a particular comipler, wehther or not we're building the
719 /// standard library, and targeting the specified architecture.
723 target
: &str) -> PathBuf
{
724 self.stage_out(compiler
, mode
).join(target
).join(self.cargo_dir())
727 /// Root output directory for LLVM compiled for `target`
729 /// Note that if LLVM is configured externally then the directory returned
730 /// will likely be empty.
731 fn llvm_out(&self, target
: &str) -> PathBuf
{
732 self.out
.join(target
).join("llvm")
735 /// Output directory for all documentation for a target
736 fn doc_out(&self, target
: &str) -> PathBuf
{
737 self.out
.join(target
).join("doc")
740 /// Output directory for all crate documentation for a target (temporary)
742 /// The artifacts here are then copied into `doc_out` above.
743 fn crate_doc_out(&self, target
: &str) -> PathBuf
{
744 self.out
.join(target
).join("crate-docs")
747 /// Returns true if no custom `llvm-config` is set for the specified target.
749 /// If no custom `llvm-config` was specified then Rust's llvm will be used.
750 fn is_rust_llvm(&self, target
: &str) -> bool
{
751 match self.config
.target_config
.get(target
) {
752 Some(ref c
) => c
.llvm_config
.is_none(),
757 /// Returns the path to `llvm-config` for the specified target.
759 /// If a custom `llvm-config` was specified for target then that's returned
761 fn llvm_config(&self, target
: &str) -> PathBuf
{
762 let target_config
= self.config
.target_config
.get(target
);
763 if let Some(s
) = target_config
.and_then(|c
| c
.llvm_config
.as_ref()) {
766 self.llvm_out(&self.config
.build
).join("bin")
767 .join(exe("llvm-config", target
))
771 /// Returns the path to `FileCheck` binary for the specified target
772 fn llvm_filecheck(&self, target
: &str) -> PathBuf
{
773 let target_config
= self.config
.target_config
.get(target
);
774 if let Some(s
) = target_config
.and_then(|c
| c
.llvm_config
.as_ref()) {
775 let llvm_bindir
= output(Command
::new(s
).arg("--bindir"));
776 Path
::new(llvm_bindir
.trim()).join(exe("FileCheck", target
))
778 let base
= self.llvm_out(&self.config
.build
).join("build");
779 let exe
= exe("FileCheck", target
);
780 if !self.config
.ninja
&& self.config
.build
.contains("msvc") {
781 base
.join("Release/bin").join(exe
)
783 base
.join("bin").join(exe
)
788 /// Directory for libraries built from C/C++ code and shared between stages.
789 fn native_dir(&self, target
: &str) -> PathBuf
{
790 self.out
.join(target
).join("native")
793 /// Root output directory for rust_test_helpers library compiled for
795 fn test_helpers_out(&self, target
: &str) -> PathBuf
{
796 self.native_dir(target
).join("rust-test-helpers")
799 /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic
800 /// library lookup path.
801 fn add_rustc_lib_path(&self, compiler
: &Compiler
, cmd
: &mut Command
) {
802 // Windows doesn't need dylib path munging because the dlls for the
803 // compiler live next to the compiler and the system will find them
809 add_lib_path(vec
![self.rustc_libdir(compiler
)], cmd
);
812 /// Adds the `RUST_TEST_THREADS` env var if necessary
813 fn add_rust_test_threads(&self, cmd
: &mut Command
) {
814 if env
::var_os("RUST_TEST_THREADS").is_none() {
815 cmd
.env("RUST_TEST_THREADS", self.jobs().to_string());
819 /// Returns the compiler's libdir where it stores the dynamic libraries that
820 /// it itself links against.
822 /// For example this returns `<sysroot>/lib` on Unix and `<sysroot>/bin` on
824 fn rustc_libdir(&self, compiler
: &Compiler
) -> PathBuf
{
825 if compiler
.is_snapshot(self) {
826 self.rustc_snapshot_libdir()
828 self.sysroot(compiler
).join(libdir(compiler
.host
))
832 /// Returns the libdir of the snapshot compiler.
833 fn rustc_snapshot_libdir(&self) -> PathBuf
{
834 self.rustc
.parent().unwrap().parent().unwrap()
835 .join(libdir(&self.config
.build
))
838 /// Runs a command, printing out nice contextual information if it fails.
839 fn run(&self, cmd
: &mut Command
) {
840 self.verbose(&format
!("running: {:?}", cmd
));
844 /// Runs a command, printing out nice contextual information if it fails.
845 fn run_quiet(&self, cmd
: &mut Command
) {
846 self.verbose(&format
!("running: {:?}", cmd
));
850 /// Prints a message if this build is configured in verbose mode.
851 fn verbose(&self, msg
: &str) {
852 if self.flags
.verbose() || self.config
.verbose() {
857 /// Returns the number of parallel jobs that have been configured for this
859 fn jobs(&self) -> u32 {
860 self.flags
.jobs
.unwrap_or(num_cpus
::get() as u32)
863 /// Returns the path to the C compiler for the target specified.
864 fn cc(&self, target
: &str) -> &Path
{
865 self.cc
[target
].0.path()
868 /// Returns a list of flags to pass to the C compiler for the target
870 fn cflags(&self, target
: &str) -> Vec
<String
> {
871 // Filter out -O and /O (the optimization flags) that we picked up from
872 // gcc-rs because the build scripts will determine that for themselves.
873 let mut base
= self.cc
[target
].0.args().iter()
874 .map(|s
| s
.to_string_lossy().into_owned())
875 .filter(|s
| !s
.starts_with("-O") && !s
.starts_with("/O"))
876 .collect
::<Vec
<_
>>();
878 // If we're compiling on macOS then we add a few unconditional flags
879 // indicating that we want libc++ (more filled out than libstdc++) and
880 // we want to compile for 10.7. This way we can ensure that
881 // LLVM/jemalloc/etc are all properly compiled.
882 if target
.contains("apple-darwin") {
883 base
.push("-stdlib=libc++".into());
888 /// Returns the path to the `ar` archive utility for the target specified.
889 fn ar(&self, target
: &str) -> Option
<&Path
> {
890 self.cc
[target
].1.as_ref().map(|p
| &**p
)
893 /// Returns the path to the C++ compiler for the target specified, may panic
894 /// if no C++ compiler was configured for the target.
895 fn cxx(&self, target
: &str) -> &Path
{
896 match self.cxx
.get(target
) {
898 None
=> panic
!("\n\ntarget `{}` is not configured as a host,
899 only as a target\n\n", target
),
903 /// Returns flags to pass to the compiler to generate code for `target`.
904 fn rustc_flags(&self, target
: &str) -> Vec
<String
> {
905 // New flags should be added here with great caution!
907 // It's quite unfortunate to **require** flags to generate code for a
908 // target, so it should only be passed here if absolutely necessary!
909 // Most default configuration should be done through target specs rather
910 // than an entry here.
912 let mut base
= Vec
::new();
913 if target
!= self.config
.build
&& !target
.contains("msvc") &&
914 !target
.contains("emscripten") {
915 base
.push(format
!("-Clinker={}", self.cc(target
).display()));
920 /// Returns the "musl root" for this `target`, if defined
921 fn musl_root(&self, target
: &str) -> Option
<&Path
> {
922 self.config
.target_config
.get(target
)
923 .and_then(|t
| t
.musl_root
.as_ref())
924 .or(self.config
.musl_root
.as_ref())
928 /// Returns the root of the "rootfs" image that this target will be using,
929 /// if one was configured.
931 /// If `Some` is returned then that means that tests for this target are
932 /// emulated with QEMU and binaries will need to be shipped to the emulator.
933 fn qemu_rootfs(&self, target
: &str) -> Option
<&Path
> {
934 self.config
.target_config
.get(target
)
935 .and_then(|t
| t
.qemu_rootfs
.as_ref())
939 /// Path to the python interpreter to use
940 fn python(&self) -> &Path
{
941 self.config
.python
.as_ref().unwrap()
944 /// Tests whether the `compiler` compiling for `target` should be forced to
945 /// use a stage1 compiler instead.
947 /// Currently, by default, the build system does not perform a "full
948 /// bootstrap" by default where we compile the compiler three times.
949 /// Instead, we compile the compiler two times. The final stage (stage2)
950 /// just copies the libraries from the previous stage, which is what this
953 /// Here we return `true` if:
955 /// * The build isn't performing a full bootstrap
956 /// * The `compiler` is in the final stage, 2
957 /// * We're not cross-compiling, so the artifacts are already available in
960 /// When all of these conditions are met the build will lift artifacts from
961 /// the previous stage forward.
962 fn force_use_stage1(&self, compiler
: &Compiler
, target
: &str) -> bool
{
963 !self.config
.full_bootstrap
&&
964 compiler
.stage
>= 2 &&
965 self.config
.host
.iter().any(|h
| h
== target
)
968 /// Returns the directory that OpenSSL artifacts are compiled into if
969 /// configured to do so.
970 fn openssl_dir(&self, target
: &str) -> Option
<PathBuf
> {
971 // OpenSSL not used on Windows
972 if target
.contains("windows") {
974 } else if self.config
.openssl_static
{
975 Some(self.out
.join(target
).join("openssl"))
981 /// Returns the directory that OpenSSL artifacts are installed into if
982 /// configured as such.
983 fn openssl_install_dir(&self, target
: &str) -> Option
<PathBuf
> {
984 self.openssl_dir(target
).map(|p
| p
.join("install"))
987 /// Given `num` in the form "a.b.c" return a "release string" which
988 /// describes the release version number.
990 /// For example on nightly this returns "a.b.c-nightly", on beta it returns
991 /// "a.b.c-beta.1" and on stable it just returns "a.b.c".
992 fn release(&self, num
: &str) -> String
{
993 match &self.config
.channel
[..] {
994 "stable" => num
.to_string(),
995 "beta" => format
!("{}-beta{}", num
, channel
::CFG_PRERELEASE_VERSION
),
996 "nightly" => format
!("{}-nightly", num
),
997 _
=> format
!("{}-dev", num
),
1001 /// Returns the value of `release` above for Rust itself.
1002 fn rust_release(&self) -> String
{
1003 self.release(channel
::CFG_RELEASE_NUM
)
1006 /// Returns the "package version" for a component given the `num` release
1009 /// The package version is typically what shows up in the names of tarballs.
1010 /// For channels like beta/nightly it's just the channel name, otherwise
1011 /// it's the `num` provided.
1012 fn package_vers(&self, num
: &str) -> String
{
1013 match &self.config
.channel
[..] {
1014 "stable" => num
.to_string(),
1015 "beta" => "beta".to_string(),
1016 "nightly" => "nightly".to_string(),
1017 _
=> format
!("{}-dev", num
),
1021 /// Returns the value of `package_vers` above for Rust itself.
1022 fn rust_package_vers(&self) -> String
{
1023 self.package_vers(channel
::CFG_RELEASE_NUM
)
1026 /// Returns the value of `package_vers` above for Cargo
1027 fn cargo_package_vers(&self) -> String
{
1028 self.package_vers(&self.release_num("cargo"))
1031 /// Returns the `version` string associated with this compiler for Rust
1034 /// Note that this is a descriptive string which includes the commit date,
1035 /// sha, version, etc.
1036 fn rust_version(&self) -> String
{
1037 self.rust_info
.version(self, channel
::CFG_RELEASE_NUM
)
1040 /// Returns the `a.b.c` version that the given package is at.
1041 fn release_num(&self, package
: &str) -> String
{
1042 let mut toml
= String
::new();
1043 let toml_file_name
= self.src
.join(&format
!("{}/Cargo.toml", package
));
1044 t
!(t
!(File
::open(toml_file_name
)).read_to_string(&mut toml
));
1045 for line
in toml
.lines() {
1046 let prefix
= "version = \"";
1048 if line
.starts_with(prefix
) && line
.ends_with(suffix
) {
1049 return line
[prefix
.len()..line
.len() - suffix
.len()].to_string()
1053 panic
!("failed to find version in {}'s Cargo.toml", package
)
1056 /// Returns whether unstable features should be enabled for the compiler
1058 fn unstable_features(&self) -> bool
{
1059 match &self.config
.channel
[..] {
1060 "stable" | "beta" => false,
1061 "nightly" | _
=> true,
1066 impl<'a
> Compiler
<'a
> {
1067 /// Creates a new complier for the specified stage/host
1068 fn new(stage
: u32, host
: &'a
str) -> Compiler
<'a
> {
1069 Compiler { stage: stage, host: host }
1072 /// Returns whether this is a snapshot compiler for `build`'s configuration
1073 fn is_snapshot(&self, build
: &Build
) -> bool
{
1074 self.stage
== 0 && self.host
== build
.config
.build
1077 /// Returns if this compiler should be treated as a final stage one in the
1078 /// current build session.
1079 /// This takes into account whether we're performing a full bootstrap or
1080 /// not; don't directly compare the stage with `2`!
1081 fn is_final_stage(&self, build
: &Build
) -> bool
{
1082 let final_stage
= if build
.config
.full_bootstrap { 2 }
else { 1 }
;
1083 self.stage
>= final_stage