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
,
156 // Probed tools at runtime
157 lldb_version
: Option
<String
>,
158 lldb_python_dir
: Option
<String
>,
160 // Runtime state filled in later on
161 cc
: HashMap
<String
, (gcc
::Tool
, Option
<PathBuf
>)>,
162 cxx
: HashMap
<String
, gcc
::Tool
>,
163 crates
: HashMap
<String
, Crate
>,
180 /// The various "modes" of invoking Cargo.
182 /// These entries currently correspond to the various output directories of the
183 /// build system, with each mod generating output in a different directory.
184 #[derive(Clone, Copy, PartialEq)]
186 /// This cargo is going to build the standard library, placing output in the
187 /// "stageN-std" directory.
190 /// This cargo is going to build libtest, placing output in the
191 /// "stageN-test" directory.
194 /// This cargo is going to build librustc and compiler libraries, placing
195 /// output in the "stageN-rustc" directory.
198 /// This cargo is going to some build tool, placing output in the
199 /// "stageN-tools" directory.
204 /// Creates a new set of build configuration from the `flags` on the command
205 /// line and the filesystem `config`.
207 /// By default all build output will be placed in the current directory.
208 pub fn new(flags
: Flags
, config
: Config
) -> Build
{
209 let cwd
= t
!(env
::current_dir());
210 let src
= flags
.src
.clone().or_else(|| {
211 env
::var_os("SRC").map(|x
| x
.into())
212 }).unwrap_or(cwd
.clone());
213 let out
= cwd
.join("build");
215 let stage0_root
= out
.join(&config
.build
).join("stage0/bin");
216 let rustc
= match config
.rustc
{
217 Some(ref s
) => PathBuf
::from(s
),
218 None
=> stage0_root
.join(exe("rustc", &config
.build
)),
220 let cargo
= match config
.cargo
{
221 Some(ref s
) => PathBuf
::from(s
),
222 None
=> stage0_root
.join(exe("cargo", &config
.build
)),
224 let local_rebuild
= config
.local_rebuild
;
226 let is_sudo
= match env
::var_os("SUDO_USER") {
228 match env
::var_os("USER") {
229 Some(user
) => user
!= sudo_user
,
235 let rust_info
= channel
::GitInfo
::new(&src
);
236 let cargo_info
= channel
::GitInfo
::new(&src
.join("cargo"));
237 let src_is_git
= src
.join(".git").exists();
247 rust_info
: rust_info
,
248 cargo_info
: cargo_info
,
249 local_rebuild
: local_rebuild
,
252 crates
: HashMap
::new(),
254 lldb_python_dir
: None
,
256 src_is_git
: src_is_git
,
260 /// Executes the entire build, as configured by the flags and configuration.
261 pub fn build(&mut self) {
266 if let Subcommand
::Clean
= self.flags
.cmd
{
267 return clean
::clean(self);
270 self.verbose("finding compilers");
272 self.verbose("running sanity check");
274 // If local-rust is the same major.minor as the current version, then force a local-rebuild
275 let local_version_verbose
= output(
276 Command
::new(&self.rustc
).arg("--version").arg("--verbose"));
277 let local_release
= local_version_verbose
278 .lines().filter(|x
| x
.starts_with("release:"))
279 .next().unwrap().trim_left_matches("release:").trim();
280 let my_version
= channel
::CFG_RELEASE_NUM
;
281 if local_release
.split('
.'
).take(2).eq(my_version
.split('
.'
).take(2)) {
282 self.verbose(&format
!("auto-detected local-rebuild {}", local_release
));
283 self.local_rebuild
= true;
285 self.verbose("updating submodules");
286 self.update_submodules();
287 self.verbose("learning about cargo");
288 metadata
::build(self);
293 /// Updates all git submodules that we have.
295 /// This will detect if any submodules are out of date an run the necessary
296 /// commands to sync them all with upstream.
297 fn update_submodules(&self) {
298 struct Submodule
<'a
> {
304 // The submodule may have staged/unstaged changes
306 // Or could be initialized but never updated
308 // The submodule, itself, has extra commits but those changes haven't been commited to
309 // the (outer) git repository
313 if !self.src_is_git
|| !self.config
.submodules
{
317 let mut cmd
= Command
::new("git");
318 cmd
.current_dir(&self.src
);
321 let git_submodule
= || {
322 let mut cmd
= Command
::new("git");
323 cmd
.current_dir(&self.src
).arg("submodule");
327 // FIXME: this takes a seriously long time to execute on Windows and a
328 // nontrivial amount of time on Unix, we should have a better way
329 // of detecting whether we need to run all the submodule commands
331 let out
= output(git_submodule().arg("status"));
332 let mut submodules
= vec
![];
333 for line
in out
.lines() {
334 // NOTE `git submodule status` output looks like this:
336 // -5066b7dcab7e700844b0e2ba71b8af9dc627a59b src/liblibc
337 // +b37ef24aa82d2be3a3cc0fe89bf82292f4ca181c src/compiler-rt (remotes/origin/..)
338 // e058ca661692a8d01f8cf9d35939dfe3105ce968 src/jemalloc (3.6.0-533-ge058ca6)
340 // The first character can be '-', '+' or ' ' and denotes the `State` of the submodule
341 // Right next to this character is the SHA-1 of the submodule HEAD
342 // And after that comes the path to the submodule
343 let path
= Path
::new(line
[1..].split(' '
).skip(1).next().unwrap());
344 let state
= if line
.starts_with('
-'
) {
345 State
::NotInitialized
346 } else if line
.starts_with('
+'
) {
348 } else if line
.starts_with(' '
) {
351 panic
!("unexpected git submodule state: {:?}", line
.chars().next());
354 submodules
.push(Submodule { path: path, state: state }
)
357 self.run(git_submodule().arg("sync"));
359 for submodule
in submodules
{
360 // If using llvm-root then don't touch the llvm submodule.
361 if submodule
.path
.components().any(|c
| c
== Component
::Normal("llvm".as_ref())) &&
362 self.config
.target_config
.get(&self.config
.build
)
363 .and_then(|c
| c
.llvm_config
.as_ref()).is_some()
368 if submodule
.path
.components().any(|c
| c
== Component
::Normal("jemalloc".as_ref())) &&
369 !self.config
.use_jemalloc
374 // `submodule.path` is the relative path to a submodule (from the repository root)
375 // `submodule_path` is the path to a submodule from the cwd
377 // use `submodule.path` when e.g. executing a submodule specific command from the
379 // use `submodule_path` when e.g. executing a normal git command for the submodule
380 // (set via `current_dir`)
381 let submodule_path
= self.src
.join(submodule
.path
);
383 match submodule
.state
{
384 State
::MaybeDirty
=> {
385 // drop staged changes
386 self.run(git().current_dir(&submodule_path
)
387 .args(&["reset", "--hard"]));
388 // drops unstaged changes
389 self.run(git().current_dir(&submodule_path
)
390 .args(&["clean", "-fdx"]));
392 State
::NotInitialized
=> {
393 self.run(git_submodule().arg("init").arg(submodule
.path
));
394 self.run(git_submodule().arg("update").arg(submodule
.path
));
396 State
::OutOfSync
=> {
397 // drops submodule commits that weren't reported to the (outer) git repository
398 self.run(git_submodule().arg("update").arg(submodule
.path
));
399 self.run(git().current_dir(&submodule_path
)
400 .args(&["reset", "--hard"]));
401 self.run(git().current_dir(&submodule_path
)
402 .args(&["clean", "-fdx"]));
408 /// Clear out `dir` if `input` is newer.
410 /// After this executes, it will also ensure that `dir` exists.
411 fn clear_if_dirty(&self, dir
: &Path
, input
: &Path
) {
412 let stamp
= dir
.join(".stamp");
413 if mtime(&stamp
) < mtime(input
) {
414 self.verbose(&format
!("Dirty - {}", dir
.display()));
415 let _
= fs
::remove_dir_all(dir
);
416 } else if stamp
.exists() {
419 t
!(fs
::create_dir_all(dir
));
420 t
!(File
::create(stamp
));
423 /// Prepares an invocation of `cargo` to be run.
425 /// This will create a `Command` that represents a pending execution of
426 /// Cargo. This cargo will be configured to use `compiler` as the actual
427 /// rustc compiler, its output will be scoped by `mode`'s output directory,
428 /// it will pass the `--target` flag for the specified `target`, and will be
429 /// executing the Cargo command `cmd`.
434 cmd
: &str) -> Command
{
435 let mut cargo
= Command
::new(&self.cargo
);
436 let out_dir
= self.stage_out(compiler
, mode
);
437 cargo
.env("CARGO_TARGET_DIR", out_dir
)
439 .arg("-j").arg(self.jobs().to_string())
440 .arg("--target").arg(target
);
442 // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
443 // Force cargo to output binaries with disambiguating hashes in the name
444 cargo
.env("__CARGO_DEFAULT_LIB_METADATA", "1");
447 if compiler
.stage
== 0 && self.local_rebuild
{
448 // Assume the local-rebuild rustc already has stage1 features.
451 stage
= compiler
.stage
;
454 // Customize the compiler we're running. Specify the compiler to cargo
455 // as our shim and then pass it some various options used to configure
456 // how the actual compiler itself is called.
458 // These variables are primarily all read by
459 // src/bootstrap/bin/{rustc.rs,rustdoc.rs}
460 cargo
.env("RUSTBUILD_NATIVE_DIR", self.native_dir(target
))
461 .env("RUSTC", self.out
.join("bootstrap/debug/rustc"))
462 .env("RUSTC_REAL", self.compiler_path(compiler
))
463 .env("RUSTC_STAGE", stage
.to_string())
464 .env("RUSTC_CODEGEN_UNITS",
465 self.config
.rust_codegen_units
.to_string())
466 .env("RUSTC_DEBUG_ASSERTIONS",
467 self.config
.rust_debug_assertions
.to_string())
468 .env("RUSTC_SYSROOT", self.sysroot(compiler
))
469 .env("RUSTC_LIBDIR", self.rustc_libdir(compiler
))
470 .env("RUSTC_RPATH", self.config
.rust_rpath
.to_string())
471 .env("RUSTDOC", self.out
.join("bootstrap/debug/rustdoc"))
472 .env("RUSTDOC_REAL", self.rustdoc(compiler
))
473 .env("RUSTC_FLAGS", self.rustc_flags(target
).join(" "));
475 // Tools don't get debuginfo right now, e.g. cargo and rls don't get
476 // compiled with debuginfo.
477 if mode
!= Mode
::Tool
{
478 cargo
.env("RUSTC_DEBUGINFO", self.config
.rust_debuginfo
.to_string())
479 .env("RUSTC_DEBUGINFO_LINES", self.config
.rust_debuginfo_lines
.to_string());
482 // Enable usage of unstable features
483 cargo
.env("RUSTC_BOOTSTRAP", "1");
484 self.add_rust_test_threads(&mut cargo
);
486 // Almost all of the crates that we compile as part of the bootstrap may
487 // have a build script, including the standard library. To compile a
488 // build script, however, it itself needs a standard library! This
489 // introduces a bit of a pickle when we're compiling the standard
492 // To work around this we actually end up using the snapshot compiler
493 // (stage0) for compiling build scripts of the standard library itself.
494 // The stage0 compiler is guaranteed to have a libstd available for use.
496 // For other crates, however, we know that we've already got a standard
497 // library up and running, so we can use the normal compiler to compile
498 // build scripts in that situation.
499 if let Mode
::Libstd
= mode
{
500 cargo
.env("RUSTC_SNAPSHOT", &self.rustc
)
501 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
503 cargo
.env("RUSTC_SNAPSHOT", self.compiler_path(compiler
))
504 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler
));
507 // Ignore incremental modes except for stage0, since we're
508 // not guaranteeing correctness acros builds if the compiler
509 // is changing under your feet.`
510 if self.flags
.incremental
&& compiler
.stage
== 0 {
511 let incr_dir
= self.incremental_dir(compiler
);
512 cargo
.env("RUSTC_INCREMENTAL", incr_dir
);
515 if let Some(ref on_fail
) = self.flags
.on_fail
{
516 cargo
.env("RUSTC_ON_FAIL", on_fail
);
519 let verbose
= cmp
::max(self.config
.verbose
, self.flags
.verbose
);
520 cargo
.env("RUSTC_VERBOSE", format
!("{}", verbose
));
522 // Specify some various options for build scripts used throughout
525 // FIXME: the guard against msvc shouldn't need to be here
526 if !target
.contains("msvc") {
527 cargo
.env(format
!("CC_{}", target
), self.cc(target
))
528 .env(format
!("AR_{}", target
), self.ar(target
).unwrap()) // only msvc is None
529 .env(format
!("CFLAGS_{}", target
), self.cflags(target
).join(" "));
532 if self.config
.channel
== "nightly" && compiler
.is_final_stage(self) {
533 cargo
.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
536 // Environment variables *required* needed throughout the build
538 // FIXME: should update code to not require this env var
539 cargo
.env("CFG_COMPILER_HOST_TRIPLE", target
);
541 if self.config
.verbose() || self.flags
.verbose() {
544 // FIXME: cargo bench does not accept `--release`
545 if self.config
.rust_optimize
&& cmd
!= "bench" {
546 cargo
.arg("--release");
548 if self.config
.locked_deps
{
549 cargo
.arg("--locked");
551 if self.config
.vendor
|| self.is_sudo
{
552 cargo
.arg("--frozen");
557 /// Get a path to the compiler specified.
558 fn compiler_path(&self, compiler
: &Compiler
) -> PathBuf
{
559 if compiler
.is_snapshot(self) {
562 self.sysroot(compiler
).join("bin").join(exe("rustc", compiler
.host
))
566 /// Get the specified tool built by the specified compiler
567 fn tool(&self, compiler
: &Compiler
, tool
: &str) -> PathBuf
{
568 self.cargo_out(compiler
, Mode
::Tool
, compiler
.host
)
569 .join(exe(tool
, compiler
.host
))
572 /// Get the `rustdoc` executable next to the specified compiler
573 fn rustdoc(&self, compiler
: &Compiler
) -> PathBuf
{
574 let mut rustdoc
= self.compiler_path(compiler
);
576 rustdoc
.push(exe("rustdoc", compiler
.host
));
580 /// Get a `Command` which is ready to run `tool` in `stage` built for
582 fn tool_cmd(&self, compiler
: &Compiler
, tool
: &str) -> Command
{
583 let mut cmd
= Command
::new(self.tool(&compiler
, tool
));
584 self.prepare_tool_cmd(compiler
, &mut cmd
);
588 /// Prepares the `cmd` provided to be able to run the `compiler` provided.
590 /// Notably this munges the dynamic library lookup path to point to the
591 /// right location to run `compiler`.
592 fn prepare_tool_cmd(&self, compiler
: &Compiler
, cmd
: &mut Command
) {
593 let host
= compiler
.host
;
594 let mut paths
= vec
![
595 self.sysroot_libdir(compiler
, compiler
.host
),
596 self.cargo_out(compiler
, Mode
::Tool
, host
).join("deps"),
599 // On MSVC a tool may invoke a C compiler (e.g. compiletest in run-make
600 // mode) and that C compiler may need some extra PATH modification. Do
602 if compiler
.host
.contains("msvc") {
603 let curpaths
= env
::var_os("PATH").unwrap_or(OsString
::new());
604 let curpaths
= env
::split_paths(&curpaths
).collect
::<Vec
<_
>>();
605 for &(ref k
, ref v
) in self.cc
[compiler
.host
].0.env() {
609 for path
in env
::split_paths(v
) {
610 if !curpaths
.contains(&path
) {
616 add_lib_path(paths
, cmd
);
619 /// Get the space-separated set of activated features for the standard
621 fn std_features(&self) -> String
{
622 let mut features
= "panic-unwind".to_string();
624 if self.config
.debug_jemalloc
{
625 features
.push_str(" debug-jemalloc");
627 if self.config
.use_jemalloc
{
628 features
.push_str(" jemalloc");
630 if self.config
.backtrace
{
631 features
.push_str(" backtrace");
636 /// Get the space-separated set of activated features for the compiler.
637 fn rustc_features(&self) -> String
{
638 let mut features
= String
::new();
639 if self.config
.use_jemalloc
{
640 features
.push_str(" jemalloc");
645 /// Component directory that Cargo will produce output into (e.g.
647 fn cargo_dir(&self) -> &'
static str {
648 if self.config
.rust_optimize {"release"}
else {"debug"}
651 /// Returns the sysroot for the `compiler` specified that *this build system
654 /// That is, the sysroot for the stage0 compiler is not what the compiler
655 /// thinks it is by default, but it's the same as the default for stages
657 fn sysroot(&self, compiler
: &Compiler
) -> PathBuf
{
658 if compiler
.stage
== 0 {
659 self.out
.join(compiler
.host
).join("stage0-sysroot")
661 self.out
.join(compiler
.host
).join(format
!("stage{}", compiler
.stage
))
665 /// Get the directory for incremental by-products when using the
667 fn incremental_dir(&self, compiler
: &Compiler
) -> PathBuf
{
668 self.out
.join(compiler
.host
).join(format
!("stage{}-incremental", compiler
.stage
))
671 /// Returns the libdir where the standard library and other artifacts are
672 /// found for a compiler's sysroot.
673 fn sysroot_libdir(&self, compiler
: &Compiler
, target
: &str) -> PathBuf
{
674 self.sysroot(compiler
).join("lib").join("rustlib")
675 .join(target
).join("lib")
678 /// Returns the root directory for all output generated in a particular
679 /// stage when running with a particular host compiler.
681 /// The mode indicates what the root directory is for.
682 fn stage_out(&self, compiler
: &Compiler
, mode
: Mode
) -> PathBuf
{
683 let suffix
= match mode
{
684 Mode
::Libstd
=> "-std",
685 Mode
::Libtest
=> "-test",
686 Mode
::Tool
=> "-tools",
687 Mode
::Librustc
=> "-rustc",
689 self.out
.join(compiler
.host
)
690 .join(format
!("stage{}{}", compiler
.stage
, suffix
))
693 /// Returns the root output directory for all Cargo output in a given stage,
694 /// running a particular comipler, wehther or not we're building the
695 /// standard library, and targeting the specified architecture.
699 target
: &str) -> PathBuf
{
700 self.stage_out(compiler
, mode
).join(target
).join(self.cargo_dir())
703 /// Root output directory for LLVM compiled for `target`
705 /// Note that if LLVM is configured externally then the directory returned
706 /// will likely be empty.
707 fn llvm_out(&self, target
: &str) -> PathBuf
{
708 self.out
.join(target
).join("llvm")
711 /// Output directory for all documentation for a target
712 fn doc_out(&self, target
: &str) -> PathBuf
{
713 self.out
.join(target
).join("doc")
716 /// Output directory for all crate documentation for a target (temporary)
718 /// The artifacts here are then copied into `doc_out` above.
719 fn crate_doc_out(&self, target
: &str) -> PathBuf
{
720 self.out
.join(target
).join("crate-docs")
723 /// Returns true if no custom `llvm-config` is set for the specified target.
725 /// If no custom `llvm-config` was specified then Rust's llvm will be used.
726 fn is_rust_llvm(&self, target
: &str) -> bool
{
727 match self.config
.target_config
.get(target
) {
728 Some(ref c
) => c
.llvm_config
.is_none(),
733 /// Returns the path to `llvm-config` for the specified target.
735 /// If a custom `llvm-config` was specified for target then that's returned
737 fn llvm_config(&self, target
: &str) -> PathBuf
{
738 let target_config
= self.config
.target_config
.get(target
);
739 if let Some(s
) = target_config
.and_then(|c
| c
.llvm_config
.as_ref()) {
742 self.llvm_out(&self.config
.build
).join("bin")
743 .join(exe("llvm-config", target
))
747 /// Returns the path to `FileCheck` binary for the specified target
748 fn llvm_filecheck(&self, target
: &str) -> PathBuf
{
749 let target_config
= self.config
.target_config
.get(target
);
750 if let Some(s
) = target_config
.and_then(|c
| c
.llvm_config
.as_ref()) {
751 let llvm_bindir
= output(Command
::new(s
).arg("--bindir"));
752 Path
::new(llvm_bindir
.trim()).join(exe("FileCheck", target
))
754 let base
= self.llvm_out(&self.config
.build
).join("build");
755 let exe
= exe("FileCheck", target
);
756 if !self.config
.ninja
&& self.config
.build
.contains("msvc") {
757 base
.join("Release/bin").join(exe
)
759 base
.join("bin").join(exe
)
764 /// Directory for libraries built from C/C++ code and shared between stages.
765 fn native_dir(&self, target
: &str) -> PathBuf
{
766 self.out
.join(target
).join("native")
769 /// Root output directory for rust_test_helpers library compiled for
771 fn test_helpers_out(&self, target
: &str) -> PathBuf
{
772 self.native_dir(target
).join("rust-test-helpers")
775 /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic
776 /// library lookup path.
777 fn add_rustc_lib_path(&self, compiler
: &Compiler
, cmd
: &mut Command
) {
778 // Windows doesn't need dylib path munging because the dlls for the
779 // compiler live next to the compiler and the system will find them
785 add_lib_path(vec
![self.rustc_libdir(compiler
)], cmd
);
788 /// Adds the `RUST_TEST_THREADS` env var if necessary
789 fn add_rust_test_threads(&self, cmd
: &mut Command
) {
790 if env
::var_os("RUST_TEST_THREADS").is_none() {
791 cmd
.env("RUST_TEST_THREADS", self.jobs().to_string());
795 /// Returns the compiler's libdir where it stores the dynamic libraries that
796 /// it itself links against.
798 /// For example this returns `<sysroot>/lib` on Unix and `<sysroot>/bin` on
800 fn rustc_libdir(&self, compiler
: &Compiler
) -> PathBuf
{
801 if compiler
.is_snapshot(self) {
802 self.rustc_snapshot_libdir()
804 self.sysroot(compiler
).join(libdir(compiler
.host
))
808 /// Returns the libdir of the snapshot compiler.
809 fn rustc_snapshot_libdir(&self) -> PathBuf
{
810 self.rustc
.parent().unwrap().parent().unwrap()
811 .join(libdir(&self.config
.build
))
814 /// Runs a command, printing out nice contextual information if it fails.
815 fn run(&self, cmd
: &mut Command
) {
816 self.verbose(&format
!("running: {:?}", cmd
));
820 /// Runs a command, printing out nice contextual information if it fails.
821 fn run_quiet(&self, cmd
: &mut Command
) {
822 self.verbose(&format
!("running: {:?}", cmd
));
826 /// Prints a message if this build is configured in verbose mode.
827 fn verbose(&self, msg
: &str) {
828 if self.flags
.verbose() || self.config
.verbose() {
833 /// Returns the number of parallel jobs that have been configured for this
835 fn jobs(&self) -> u32 {
836 self.flags
.jobs
.unwrap_or(num_cpus
::get() as u32)
839 /// Returns the path to the C compiler for the target specified.
840 fn cc(&self, target
: &str) -> &Path
{
841 self.cc
[target
].0.path()
844 /// Returns a list of flags to pass to the C compiler for the target
846 fn cflags(&self, target
: &str) -> Vec
<String
> {
847 // Filter out -O and /O (the optimization flags) that we picked up from
848 // gcc-rs because the build scripts will determine that for themselves.
849 let mut base
= self.cc
[target
].0.args().iter()
850 .map(|s
| s
.to_string_lossy().into_owned())
851 .filter(|s
| !s
.starts_with("-O") && !s
.starts_with("/O"))
852 .collect
::<Vec
<_
>>();
854 // If we're compiling on OSX then we add a few unconditional flags
855 // indicating that we want libc++ (more filled out than libstdc++) and
856 // we want to compile for 10.7. This way we can ensure that
857 // LLVM/jemalloc/etc are all properly compiled.
858 if target
.contains("apple-darwin") {
859 base
.push("-stdlib=libc++".into());
864 /// Returns the path to the `ar` archive utility for the target specified.
865 fn ar(&self, target
: &str) -> Option
<&Path
> {
866 self.cc
[target
].1.as_ref().map(|p
| &**p
)
869 /// Returns the path to the C++ compiler for the target specified, may panic
870 /// if no C++ compiler was configured for the target.
871 fn cxx(&self, target
: &str) -> &Path
{
872 match self.cxx
.get(target
) {
874 None
=> panic
!("\n\ntarget `{}` is not configured as a host,
875 only as a target\n\n", target
),
879 /// Returns flags to pass to the compiler to generate code for `target`.
880 fn rustc_flags(&self, target
: &str) -> Vec
<String
> {
881 // New flags should be added here with great caution!
883 // It's quite unfortunate to **require** flags to generate code for a
884 // target, so it should only be passed here if absolutely necessary!
885 // Most default configuration should be done through target specs rather
886 // than an entry here.
888 let mut base
= Vec
::new();
889 if target
!= self.config
.build
&& !target
.contains("msvc") &&
890 !target
.contains("emscripten") {
891 base
.push(format
!("-Clinker={}", self.cc(target
).display()));
896 /// Returns the "musl root" for this `target`, if defined
897 fn musl_root(&self, target
: &str) -> Option
<&Path
> {
898 self.config
.target_config
.get(target
)
899 .and_then(|t
| t
.musl_root
.as_ref())
900 .or(self.config
.musl_root
.as_ref())
904 /// Returns the root of the "rootfs" image that this target will be using,
905 /// if one was configured.
907 /// If `Some` is returned then that means that tests for this target are
908 /// emulated with QEMU and binaries will need to be shipped to the emulator.
909 fn qemu_rootfs(&self, target
: &str) -> Option
<&Path
> {
910 self.config
.target_config
.get(target
)
911 .and_then(|t
| t
.qemu_rootfs
.as_ref())
915 /// Path to the python interpreter to use
916 fn python(&self) -> &Path
{
917 self.config
.python
.as_ref().unwrap()
920 /// Tests whether the `compiler` compiling for `target` should be forced to
921 /// use a stage1 compiler instead.
923 /// Currently, by default, the build system does not perform a "full
924 /// bootstrap" by default where we compile the compiler three times.
925 /// Instead, we compile the compiler two times. The final stage (stage2)
926 /// just copies the libraries from the previous stage, which is what this
929 /// Here we return `true` if:
931 /// * The build isn't performing a full bootstrap
932 /// * The `compiler` is in the final stage, 2
933 /// * We're not cross-compiling, so the artifacts are already available in
936 /// When all of these conditions are met the build will lift artifacts from
937 /// the previous stage forward.
938 fn force_use_stage1(&self, compiler
: &Compiler
, target
: &str) -> bool
{
939 !self.config
.full_bootstrap
&&
940 compiler
.stage
>= 2 &&
941 self.config
.host
.iter().any(|h
| h
== target
)
944 /// Returns the directory that OpenSSL artifacts are compiled into if
945 /// configured to do so.
946 fn openssl_dir(&self, target
: &str) -> Option
<PathBuf
> {
947 // OpenSSL not used on Windows
948 if target
.contains("windows") {
950 } else if self.config
.openssl_static
{
951 Some(self.out
.join(target
).join("openssl"))
957 /// Returns the directory that OpenSSL artifacts are installed into if
958 /// configured as such.
959 fn openssl_install_dir(&self, target
: &str) -> Option
<PathBuf
> {
960 self.openssl_dir(target
).map(|p
| p
.join("install"))
963 /// Given `num` in the form "a.b.c" return a "release string" which
964 /// describes the release version number.
966 /// For example on nightly this returns "a.b.c-nightly", on beta it returns
967 /// "a.b.c-beta.1" and on stable it just returns "a.b.c".
968 fn release(&self, num
: &str) -> String
{
969 match &self.config
.channel
[..] {
970 "stable" => num
.to_string(),
971 "beta" => format
!("{}-beta{}", num
, channel
::CFG_PRERELEASE_VERSION
),
972 "nightly" => format
!("{}-nightly", num
),
973 _
=> format
!("{}-dev", num
),
977 /// Returns the value of `release` above for Rust itself.
978 fn rust_release(&self) -> String
{
979 self.release(channel
::CFG_RELEASE_NUM
)
982 /// Returns the "package version" for a component given the `num` release
985 /// The package version is typically what shows up in the names of tarballs.
986 /// For channels like beta/nightly it's just the channel name, otherwise
987 /// it's the `num` provided.
988 fn package_vers(&self, num
: &str) -> String
{
989 match &self.config
.channel
[..] {
990 "stable" => num
.to_string(),
991 "beta" => "beta".to_string(),
992 "nightly" => "nightly".to_string(),
993 _
=> format
!("{}-dev", num
),
997 /// Returns the value of `package_vers` above for Rust itself.
998 fn rust_package_vers(&self) -> String
{
999 self.package_vers(channel
::CFG_RELEASE_NUM
)
1002 /// Returns the value of `package_vers` above for Cargo
1003 fn cargo_package_vers(&self) -> String
{
1004 self.package_vers(&self.cargo_release_num())
1007 /// Returns the `version` string associated with this compiler for Rust
1010 /// Note that this is a descriptive string which includes the commit date,
1011 /// sha, version, etc.
1012 fn rust_version(&self) -> String
{
1013 self.rust_info
.version(self, channel
::CFG_RELEASE_NUM
)
1016 /// Returns the `a.b.c` version that Cargo is at.
1017 fn cargo_release_num(&self) -> String
{
1018 let mut toml
= String
::new();
1019 t
!(t
!(File
::open(self.src
.join("cargo/Cargo.toml"))).read_to_string(&mut toml
));
1020 for line
in toml
.lines() {
1021 let prefix
= "version = \"";
1023 if line
.starts_with(prefix
) && line
.ends_with(suffix
) {
1024 return line
[prefix
.len()..line
.len() - suffix
.len()].to_string()
1028 panic
!("failed to find version in cargo's Cargo.toml")
1031 /// Returns whether unstable features should be enabled for the compiler
1033 fn unstable_features(&self) -> bool
{
1034 match &self.config
.channel
[..] {
1035 "stable" | "beta" => false,
1036 "nightly" | _
=> true,
1041 impl<'a
> Compiler
<'a
> {
1042 /// Creates a new complier for the specified stage/host
1043 fn new(stage
: u32, host
: &'a
str) -> Compiler
<'a
> {
1044 Compiler { stage: stage, host: host }
1047 /// Returns whether this is a snapshot compiler for `build`'s configuration
1048 fn is_snapshot(&self, build
: &Build
) -> bool
{
1049 self.stage
== 0 && self.host
== build
.config
.build
1052 /// Returns if this compiler should be treated as a final stage one in the
1053 /// current build session.
1054 /// This takes into account whether we're performing a full bootstrap or
1055 /// not; don't directly compare the stage with `2`!
1056 fn is_final_stage(&self, build
: &Build
) -> bool
{
1057 let final_stage
= if build
.config
.full_bootstrap { 2 }
else { 1 }
;
1058 self.stage
>= final_stage