2 use std
::cell
::{Cell, RefCell}
;
3 use std
::collections
::BTreeSet
;
4 use std
::collections
::HashMap
;
10 use std
::path
::{Path, PathBuf}
;
11 use std
::process
::Command
;
12 use std
::time
::{Duration, Instant}
;
16 use crate::cache
::{Cache, Interned, INTERNER}
;
21 use crate::flags
::Subcommand
;
26 use crate::util
::{self, add_lib_path, exe, libdir}
;
27 use crate::{Build, DocTests, Mode, GitRepo}
;
29 pub use crate::Compiler
;
31 use petgraph
::graph
::NodeIndex
;
34 pub struct Builder
<'a
> {
39 stack
: RefCell
<Vec
<Box
<dyn Any
>>>,
40 time_spent_on_dependencies
: Cell
<Duration
>,
41 pub paths
: Vec
<PathBuf
>,
42 graph_nodes
: RefCell
<HashMap
<String
, NodeIndex
>>,
43 graph
: RefCell
<Graph
<String
, bool
>>,
44 parent
: Cell
<Option
<NodeIndex
>>,
47 impl<'a
> Deref
for Builder
<'a
> {
50 fn deref(&self) -> &Self::Target
{
55 pub trait Step
: '
static + Clone
+ Debug
+ PartialEq
+ Eq
+ Hash
{
56 /// `PathBuf` when directories are created or to return a `Compiler` once
57 /// it's been assembled.
60 const DEFAULT
: bool
= false;
62 /// If true, then this rule should be skipped if --target was specified, but --host was not
63 const ONLY_HOSTS
: bool
= false;
65 /// Primary function to execute this rule. Can call `builder.ensure()`
66 /// with other steps to run those.
67 fn run(self, builder
: &Builder
<'_
>) -> Self::Output
;
69 /// When bootstrap is passed a set of paths, this controls whether this rule
70 /// will execute. However, it does not get called in a "default" context
71 /// when we are not passed any paths; in that case, `make_run` is called
73 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
>;
75 /// Builds up a "root" rule, either as a default rule or from a path passed
78 /// When path is `None`, we are executing in a context where no paths were
79 /// passed. When `./x.py build` is run, for example, this rule could get
80 /// called if it is in the correct list below with a path of `None`.
81 fn make_run(_run
: RunConfig
<'_
>) {
82 // It is reasonable to not have an implementation of make_run for rules
83 // who do not want to get called from the root context. This means that
84 // they are likely dependencies (e.g., sysroot creation) or similar, and
85 // as such calling them from ./x.py isn't logical.
90 pub struct RunConfig
<'a
> {
91 pub builder
: &'a Builder
<'a
>,
92 pub host
: Interned
<String
>,
93 pub target
: Interned
<String
>,
97 struct StepDescription
{
100 should_run
: fn(ShouldRun
<'_
>) -> ShouldRun
<'_
>,
101 make_run
: fn(RunConfig
<'_
>),
105 #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
107 Set(BTreeSet
<PathBuf
>),
112 fn empty() -> PathSet
{
113 PathSet
::Set(BTreeSet
::new())
116 fn one
<P
: Into
<PathBuf
>>(path
: P
) -> PathSet
{
117 let mut set
= BTreeSet
::new();
118 set
.insert(path
.into());
122 fn has(&self, needle
: &Path
) -> bool
{
124 PathSet
::Set(set
) => set
.iter().any(|p
| p
.ends_with(needle
)),
125 PathSet
::Suite(suite
) => suite
.ends_with(needle
),
129 fn path(&self, builder
: &Builder
<'_
>) -> PathBuf
{
131 PathSet
::Set(set
) => set
134 .unwrap_or(&builder
.build
.src
)
136 PathSet
::Suite(path
) => PathBuf
::from(path
),
141 impl StepDescription
{
142 fn from
<S
: Step
>() -> StepDescription
{
145 only_hosts
: S
::ONLY_HOSTS
,
146 should_run
: S
::should_run
,
147 make_run
: S
::make_run
,
148 name
: unsafe { ::std::intrinsics::type_name::<S>() }
,
152 fn maybe_run(&self, builder
: &Builder
<'_
>, pathset
: &PathSet
) {
153 if builder
.config
.exclude
.iter().any(|e
| pathset
.has(e
)) {
154 eprintln
!("Skipping {:?} because it is excluded", pathset
);
156 } else if !builder
.config
.exclude
.is_empty() {
158 "{:?} not skipped for {:?} -- not in {:?}",
159 pathset
, self.name
, builder
.config
.exclude
162 let hosts
= &builder
.hosts
;
164 // Determine the targets participating in this rule.
165 let targets
= if self.only_hosts
{
166 if builder
.config
.skip_only_host_steps
{
167 return; // don't run anything
176 for target
in targets
{
177 let run
= RunConfig
{
179 path
: pathset
.path(builder
),
183 (self.make_run
)(run
);
188 fn run(v
: &[StepDescription
], builder
: &Builder
<'_
>, paths
: &[PathBuf
]) {
191 .map(|desc
| (desc
.should_run
)(ShouldRun
::new(builder
)))
192 .collect
::<Vec
<_
>>();
194 // sanity checks on rules
195 for (desc
, should_run
) in v
.iter().zip(&should_runs
) {
197 !should_run
.paths
.is_empty(),
198 "{:?} should have at least one pathset",
203 if paths
.is_empty() {
204 for (desc
, should_run
) in v
.iter().zip(should_runs
) {
205 if desc
.default && should_run
.is_really_default
{
206 for pathset
in &should_run
.paths
{
207 desc
.maybe_run(builder
, pathset
);
213 // strip CurDir prefix if present
214 let path
= match path
.strip_prefix(".") {
219 let mut attempted_run
= false;
220 for (desc
, should_run
) in v
.iter().zip(&should_runs
) {
221 if let Some(suite
) = should_run
.is_suite_path(path
) {
222 attempted_run
= true;
223 desc
.maybe_run(builder
, suite
);
224 } else if let Some(pathset
) = should_run
.pathset_for_path(path
) {
225 attempted_run
= true;
226 desc
.maybe_run(builder
, pathset
);
231 panic
!("Error: no rules matched {}.", path
.display());
239 pub struct ShouldRun
<'a
> {
240 pub builder
: &'a Builder
<'a
>,
241 // use a BTreeSet to maintain sort order
242 paths
: BTreeSet
<PathSet
>,
244 // If this is a default rule, this is an additional constraint placed on
245 // its run. Generally something like compiler docs being enabled.
246 is_really_default
: bool
,
249 impl<'a
> ShouldRun
<'a
> {
250 fn new(builder
: &'a Builder
<'_
>) -> ShouldRun
<'a
> {
253 paths
: BTreeSet
::new(),
254 is_really_default
: true, // by default no additional conditions
258 pub fn default_condition(mut self, cond
: bool
) -> Self {
259 self.is_really_default
= cond
;
263 // Unlike `krate` this will create just one pathset. As such, it probably shouldn't actually
264 // ever be used, but as we transition to having all rules properly handle passing krate(...) by
265 // actually doing something different for every crate passed.
266 pub fn all_krates(mut self, name
: &str) -> Self {
267 let mut set
= BTreeSet
::new();
268 for krate
in self.builder
.in_tree_crates(name
) {
269 set
.insert(PathBuf
::from(&krate
.path
));
271 self.paths
.insert(PathSet
::Set(set
));
275 pub fn krate(mut self, name
: &str) -> Self {
276 for krate
in self.builder
.in_tree_crates(name
) {
277 self.paths
.insert(PathSet
::one(&krate
.path
));
282 // single, non-aliased path
283 pub fn path(self, path
: &str) -> Self {
287 // multiple aliases for the same job
288 pub fn paths(mut self, paths
: &[&str]) -> Self {
290 .insert(PathSet
::Set(paths
.iter().map(PathBuf
::from
).collect()));
294 pub fn is_suite_path(&self, path
: &Path
) -> Option
<&PathSet
> {
295 self.paths
.iter().find(|pathset
| match pathset
{
296 PathSet
::Suite(p
) => path
.starts_with(p
),
297 PathSet
::Set(_
) => false,
301 pub fn suite_path(mut self, suite
: &str) -> Self {
302 self.paths
.insert(PathSet
::Suite(PathBuf
::from(suite
)));
306 // allows being more explicit about why should_run in Step returns the value passed to it
307 pub fn never(mut self) -> ShouldRun
<'a
> {
308 self.paths
.insert(PathSet
::empty());
312 fn pathset_for_path(&self, path
: &Path
) -> Option
<&PathSet
> {
313 self.paths
.iter().find(|pathset
| pathset
.has(path
))
317 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
330 impl<'a
> Builder
<'a
> {
331 fn get_step_descriptions(kind
: Kind
) -> Vec
<StepDescription
> {
332 macro_rules
! describe
{
333 ($
($rule
:ty
),+ $
(,)?
) => {{
334 vec
![$
(StepDescription
::from
::<$rule
>()),+]
338 Kind
::Build
=> describe
!(
342 compile
::CodegenBackend
,
343 compile
::StartupObjects
,
347 tool
::UnstableBookGen
,
352 tool
::RemoteTestServer
,
353 tool
::RemoteTestClient
,
364 Kind
::Check
| Kind
::Clippy
| Kind
::Fix
=> describe
!(
368 check
::CodegenBackend
,
371 Kind
::Test
=> describe
!(
376 test
::RunPassValgrind
,
387 test
::RunPassValgrindPretty
,
397 test
::RunMakeFullDeps
,
411 test
::CompiletestTest
,
413 test
::RustdocJSNotStd
,
416 // Run bootstrap close to the end as it's unlikely to fail
418 // Run run-make last, since these won't pass without make on Windows
421 Kind
::Bench
=> describe
!(test
::Crate
, test
::CrateLibrustc
),
422 Kind
::Doc
=> describe
!(
424 doc
::UnstableBookGen
,
429 doc
::WhitelistedRustc
,
442 Kind
::Dist
=> describe
!(
447 dist
::DebuggerScripts
,
451 dist
::PlainSourceTarball
,
462 Kind
::Install
=> describe
!(
477 pub fn get_help(build
: &Build
, subcommand
: &str) -> Option
<String
> {
478 let kind
= match subcommand
{
479 "build" => Kind
::Build
,
481 "test" => Kind
::Test
,
482 "bench" => Kind
::Bench
,
483 "dist" => Kind
::Dist
,
484 "install" => Kind
::Install
,
488 let builder
= Builder
{
490 top_stage
: build
.config
.stage
.unwrap_or(2),
493 stack
: RefCell
::new(Vec
::new()),
494 time_spent_on_dependencies
: Cell
::new(Duration
::new(0, 0)),
496 graph_nodes
: RefCell
::new(HashMap
::new()),
497 graph
: RefCell
::new(Graph
::new()),
498 parent
: Cell
::new(None
),
501 let builder
= &builder
;
502 let mut should_run
= ShouldRun
::new(builder
);
503 for desc
in Builder
::get_step_descriptions(builder
.kind
) {
504 should_run
= (desc
.should_run
)(should_run
);
506 let mut help
= String
::from("Available paths:\n");
507 for pathset
in should_run
.paths
{
508 if let PathSet
::Set(set
) = pathset
{
509 set
.iter().for_each(|path
| {
511 format
!(" ./x.py {} {}\n", subcommand
, path
.display()).as_str(),
519 pub fn new(build
: &Build
) -> Builder
<'_
> {
520 let (kind
, paths
) = match build
.config
.cmd
{
521 Subcommand
::Build { ref paths }
=> (Kind
::Build
, &paths
[..]),
522 Subcommand
::Check { ref paths }
=> (Kind
::Check
, &paths
[..]),
523 Subcommand
::Clippy { ref paths }
=> (Kind
::Clippy
, &paths
[..]),
524 Subcommand
::Fix { ref paths }
=> (Kind
::Fix
, &paths
[..]),
525 Subcommand
::Doc { ref paths }
=> (Kind
::Doc
, &paths
[..]),
526 Subcommand
::Test { ref paths, .. }
=> (Kind
::Test
, &paths
[..]),
527 Subcommand
::Bench { ref paths, .. }
=> (Kind
::Bench
, &paths
[..]),
528 Subcommand
::Dist { ref paths }
=> (Kind
::Dist
, &paths
[..]),
529 Subcommand
::Install { ref paths }
=> (Kind
::Install
, &paths
[..]),
530 Subcommand
::Clean { .. }
=> panic
!(),
533 let builder
= Builder
{
535 top_stage
: build
.config
.stage
.unwrap_or(2),
538 stack
: RefCell
::new(Vec
::new()),
539 time_spent_on_dependencies
: Cell
::new(Duration
::new(0, 0)),
540 paths
: paths
.to_owned(),
541 graph_nodes
: RefCell
::new(HashMap
::new()),
542 graph
: RefCell
::new(Graph
::new()),
543 parent
: Cell
::new(None
),
549 pub fn execute_cli(&self) -> Graph
<String
, bool
> {
550 self.run_step_descriptions(&Builder
::get_step_descriptions(self.kind
), &self.paths
);
551 self.graph
.borrow().clone()
554 pub fn default_doc(&self, paths
: Option
<&[PathBuf
]>) {
555 let paths
= paths
.unwrap_or(&[]);
556 self.run_step_descriptions(&Builder
::get_step_descriptions(Kind
::Doc
), paths
);
559 fn run_step_descriptions(&self, v
: &[StepDescription
], paths
: &[PathBuf
]) {
560 StepDescription
::run(v
, self, paths
);
563 /// Obtain a compiler at a given stage and for a given host. Explicitly does
564 /// not take `Compiler` since all `Compiler` instances are meant to be
565 /// obtained through this function, since it ensures that they are valid
566 /// (i.e., built and assembled).
567 pub fn compiler(&self, stage
: u32, host
: Interned
<String
>) -> Compiler
{
568 self.ensure(compile
::Assemble
{
569 target_compiler
: Compiler { stage, host }
,
573 /// Similar to `compiler`, except handles the full-bootstrap option to
574 /// silently use the stage1 compiler instead of a stage2 compiler if one is
577 /// Note that this does *not* have the side effect of creating
578 /// `compiler(stage, host)`, unlike `compiler` above which does have such
579 /// a side effect. The returned compiler here can only be used to compile
580 /// new artifacts, it can't be used to rely on the presence of a particular
583 /// See `force_use_stage1` for documentation on what each argument is.
587 host
: Interned
<String
>,
588 target
: Interned
<String
>,
590 if self.build
.force_use_stage1(Compiler { stage, host }
, target
) {
591 self.compiler(1, self.config
.build
)
593 self.compiler(stage
, host
)
597 pub fn sysroot(&self, compiler
: Compiler
) -> Interned
<PathBuf
> {
598 self.ensure(compile
::Sysroot { compiler }
)
601 /// Returns the libdir where the standard library and other artifacts are
602 /// found for a compiler's sysroot.
603 pub fn sysroot_libdir(
606 target
: Interned
<String
>,
607 ) -> Interned
<PathBuf
> {
608 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
611 target
: Interned
<String
>,
613 impl Step
for Libdir
{
614 type Output
= Interned
<PathBuf
>;
616 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
620 fn run(self, builder
: &Builder
<'_
>) -> Interned
<PathBuf
> {
621 let compiler
= self.compiler
;
622 let config
= &builder
.build
.config
;
623 let lib
= if compiler
.stage
>= 1 && config
.libdir_relative().is_some() {
624 builder
.build
.config
.libdir_relative().unwrap()
628 let sysroot
= builder
629 .sysroot(self.compiler
)
634 let _
= fs
::remove_dir_all(&sysroot
);
635 t
!(fs
::create_dir_all(&sysroot
));
636 INTERNER
.intern_path(sysroot
)
639 self.ensure(Libdir { compiler, target }
)
642 pub fn sysroot_codegen_backends(&self, compiler
: Compiler
) -> PathBuf
{
643 self.sysroot_libdir(compiler
, compiler
.host
)
644 .with_file_name(self.config
.rust_codegen_backends_dir
.clone())
647 /// Returns the compiler's libdir where it stores the dynamic libraries that
648 /// it itself links against.
650 /// For example this returns `<sysroot>/lib` on Unix and `<sysroot>/bin` on
652 pub fn rustc_libdir(&self, compiler
: Compiler
) -> PathBuf
{
653 if compiler
.is_snapshot(self) {
654 self.rustc_snapshot_libdir()
656 match self.config
.libdir_relative() {
657 Some(relative_libdir
) if compiler
.stage
>= 1
658 => self.sysroot(compiler
).join(relative_libdir
),
659 _
=> self.sysroot(compiler
).join(libdir(&compiler
.host
))
664 /// Returns the compiler's relative libdir where it stores the dynamic libraries that
665 /// it itself links against.
667 /// For example this returns `lib` on Unix and `bin` on
669 pub fn libdir_relative(&self, compiler
: Compiler
) -> &Path
{
670 if compiler
.is_snapshot(self) {
671 libdir(&self.config
.build
).as_ref()
673 match self.config
.libdir_relative() {
674 Some(relative_libdir
) if compiler
.stage
>= 1
676 _
=> libdir(&compiler
.host
).as_ref()
681 /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic
682 /// library lookup path.
683 pub fn add_rustc_lib_path(&self, compiler
: Compiler
, cmd
: &mut Command
) {
684 // Windows doesn't need dylib path munging because the dlls for the
685 // compiler live next to the compiler and the system will find them
691 add_lib_path(vec
![self.rustc_libdir(compiler
)], cmd
);
694 /// Gets a path to the compiler specified.
695 pub fn rustc(&self, compiler
: Compiler
) -> PathBuf
{
696 if compiler
.is_snapshot(self) {
697 self.initial_rustc
.clone()
699 self.sysroot(compiler
)
701 .join(exe("rustc", &compiler
.host
))
705 /// Gets the paths to all of the compiler's codegen backends.
706 fn codegen_backends(&self, compiler
: Compiler
) -> impl Iterator
<Item
= PathBuf
> {
707 fs
::read_dir(self.sysroot_codegen_backends(compiler
))
710 .filter_map(Result
::ok
)
711 .map(|entry
| entry
.path())
714 pub fn rustdoc(&self, compiler
: Compiler
) -> PathBuf
{
715 self.ensure(tool
::Rustdoc { compiler }
)
718 pub fn rustdoc_cmd(&self, compiler
: Compiler
) -> Command
{
719 let mut cmd
= Command
::new(&self.out
.join("bootstrap/debug/rustdoc"));
720 cmd
.env("RUSTC_STAGE", compiler
.stage
.to_string())
721 .env("RUSTC_SYSROOT", self.sysroot(compiler
))
722 // Note that this is *not* the sysroot_libdir because rustdoc must be linked
723 // equivalently to rustc.
724 .env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler
))
725 .env("CFG_RELEASE_CHANNEL", &self.config
.channel
)
726 .env("RUSTDOC_REAL", self.rustdoc(compiler
))
727 .env("RUSTDOC_CRATE_VERSION", self.rust_version())
728 .env("RUSTC_BOOTSTRAP", "1");
730 // Remove make-related flags that can cause jobserver problems.
731 cmd
.env_remove("MAKEFLAGS");
732 cmd
.env_remove("MFLAGS");
734 if let Some(linker
) = self.linker(compiler
.host
) {
735 cmd
.env("RUSTC_TARGET_LINKER", linker
);
740 /// Prepares an invocation of `cargo` to be run.
742 /// This will create a `Command` that represents a pending execution of
743 /// Cargo. This cargo will be configured to use `compiler` as the actual
744 /// rustc compiler, its output will be scoped by `mode`'s output directory,
745 /// it will pass the `--target` flag for the specified `target`, and will be
746 /// executing the Cargo command `cmd`.
751 target
: Interned
<String
>,
754 let mut cargo
= Command
::new(&self.initial_cargo
);
755 let out_dir
= self.stage_out(compiler
, mode
);
757 // command specific path, we call clear_if_dirty with this
758 let mut my_out
= match cmd
{
759 "build" => self.cargo_out(compiler
, mode
, target
),
761 // This is the intended out directory for crate documentation.
762 "doc" | "rustdoc" => self.crate_doc_out(target
),
764 _
=> self.stage_out(compiler
, mode
),
767 // This is for the original compiler, but if we're forced to use stage 1, then
768 // std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since
769 // we copy the libs forward.
770 let cmp
= self.compiler_for(compiler
.stage
, compiler
.host
, target
);
772 let libstd_stamp
= match cmd
{
773 "check" | "clippy" | "fix" => check
::libstd_stamp(self, cmp
, target
),
774 _
=> compile
::libstd_stamp(self, cmp
, target
),
777 let libtest_stamp
= match cmd
{
778 "check" | "clippy" | "fix" => check
::libtest_stamp(self, cmp
, target
),
779 _
=> compile
::libtest_stamp(self, cmp
, target
),
782 let librustc_stamp
= match cmd
{
783 "check" | "clippy" | "fix" => check
::librustc_stamp(self, cmp
, target
),
784 _
=> compile
::librustc_stamp(self, cmp
, target
),
787 if cmd
== "doc" || cmd
== "rustdoc" {
788 if mode
== Mode
::Rustc
|| mode
== Mode
::ToolRustc
|| mode
== Mode
::Codegen
{
789 // This is the intended out directory for compiler documentation.
790 my_out
= self.compiler_doc_out(target
);
792 let rustdoc
= self.rustdoc(compiler
);
793 self.clear_if_dirty(&my_out
, &rustdoc
);
794 } else if cmd
!= "test" {
797 self.clear_if_dirty(&my_out
, &self.rustc(compiler
));
798 for backend
in self.codegen_backends(compiler
) {
799 self.clear_if_dirty(&my_out
, &backend
);
803 self.clear_if_dirty(&my_out
, &libstd_stamp
);
806 self.clear_if_dirty(&my_out
, &self.rustc(compiler
));
807 self.clear_if_dirty(&my_out
, &libstd_stamp
);
808 self.clear_if_dirty(&my_out
, &libtest_stamp
);
811 self.clear_if_dirty(&my_out
, &librustc_stamp
);
813 Mode
::ToolBootstrap
=> { }
,
815 self.clear_if_dirty(&my_out
, &libstd_stamp
);
818 self.clear_if_dirty(&my_out
, &libstd_stamp
);
819 self.clear_if_dirty(&my_out
, &libtest_stamp
);
822 self.clear_if_dirty(&my_out
, &libstd_stamp
);
823 self.clear_if_dirty(&my_out
, &libtest_stamp
);
824 self.clear_if_dirty(&my_out
, &librustc_stamp
);
830 .env("CARGO_TARGET_DIR", out_dir
)
833 // See comment in librustc_llvm/build.rs for why this is necessary, largely llvm-config
834 // needs to not accidentally link to libLLVM in stage0/lib.
835 cargo
.env("REAL_LIBRARY_PATH_VAR", &util
::dylib_path_var());
836 if let Some(e
) = env
::var_os(util
::dylib_path_var()) {
837 cargo
.env("REAL_LIBRARY_PATH", e
);
840 if cmd
!= "install" {
841 cargo
.arg("--target")
844 assert_eq
!(target
, compiler
.host
);
847 // Set a flag for `check`/`clippy`/`fix`, so that certain build
848 // scripts can do less work (e.g. not building/requiring LLVM).
849 if cmd
== "check" || cmd
== "clippy" || cmd
== "fix" {
850 cargo
.env("RUST_CHECK", "1");
854 Mode
::Std
| Mode
::Test
| Mode
::ToolBootstrap
| Mode
::ToolStd
| Mode
::ToolTest
=> {}
,
855 Mode
::Rustc
| Mode
::Codegen
| Mode
::ToolRustc
=> {
856 // Build proc macros both for the host and the target
857 if target
!= compiler
.host
&& cmd
!= "check" {
858 cargo
.arg("-Zdual-proc-macros");
859 cargo
.env("RUST_DUAL_PROC_MACROS", "1");
864 cargo
.arg("-j").arg(self.jobs().to_string());
865 // Remove make-related flags to ensure Cargo can correctly set things up
866 cargo
.env_remove("MAKEFLAGS");
867 cargo
.env_remove("MFLAGS");
869 // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
870 // Force cargo to output binaries with disambiguating hashes in the name
871 let mut metadata
= if compiler
.stage
== 0 {
872 // Treat stage0 like a special channel, whether it's a normal prior-
873 // release rustc or a local rebuild with the same version, so we
874 // never mix these libraries by accident.
875 "bootstrap".to_string()
877 self.config
.channel
.to_string()
879 // We want to make sure that none of the dependencies between
880 // std/test/rustc unify with one another. This is done for weird linkage
881 // reasons but the gist of the problem is that if librustc, libtest, and
882 // libstd all depend on libc from crates.io (which they actually do) we
883 // want to make sure they all get distinct versions. Things get really
884 // weird if we try to unify all these dependencies right now, namely
885 // around how many times the library is linked in dynamic libraries and
886 // such. If rustc were a static executable or if we didn't ship dylibs
887 // this wouldn't be a problem, but we do, so it is. This is in general
888 // just here to make sure things build right. If you can remove this and
889 // things still build right, please do!
891 Mode
::Std
=> metadata
.push_str("std"),
892 Mode
::Test
=> metadata
.push_str("test"),
895 cargo
.env("__CARGO_DEFAULT_LIB_METADATA", &metadata
);
898 if compiler
.stage
== 0 && self.local_rebuild
{
899 // Assume the local-rebuild rustc already has stage1 features.
902 stage
= compiler
.stage
;
905 let mut extra_args
= env
::var(&format
!("RUSTFLAGS_STAGE_{}", stage
)).unwrap_or_default();
907 let s
= env
::var("RUSTFLAGS_STAGE_NOT_0").unwrap_or_default();
908 if !extra_args
.is_empty() {
909 extra_args
.push_str(" ");
911 extra_args
.push_str(&s
);
915 extra_args
.push_str("-Zforce-unstable-if-unmarked -Zunstable-options \
916 --json-rendered=termcolor");
919 if !extra_args
.is_empty() {
924 env
::var("RUSTFLAGS").unwrap_or_default(),
930 let want_rustdoc
= self.doc_tests
!= DocTests
::No
;
932 // We synthetically interpret a stage0 compiler used to build tools as a
933 // "raw" compiler in that it's the exact snapshot we download. Normally
934 // the stage0 build means it uses libraries build by the stage0
935 // compiler, but for tools we just use the precompiled libraries that
937 let use_snapshot
= mode
== Mode
::ToolBootstrap
;
938 assert
!(!use_snapshot
|| stage
== 0 || self.local_rebuild
);
940 let maybe_sysroot
= self.sysroot(compiler
);
941 let sysroot
= if use_snapshot
{
942 self.rustc_snapshot_sysroot()
946 let libdir
= self.rustc_libdir(compiler
);
948 // Customize the compiler we're running. Specify the compiler to cargo
949 // as our shim and then pass it some various options used to configure
950 // how the actual compiler itself is called.
952 // These variables are primarily all read by
953 // src/bootstrap/bin/{rustc.rs,rustdoc.rs}
955 .env("RUSTBUILD_NATIVE_DIR", self.native_dir(target
))
956 .env("RUSTC", self.out
.join("bootstrap/debug/rustc"))
957 .env("RUSTC_REAL", self.rustc(compiler
))
958 .env("RUSTC_STAGE", stage
.to_string())
960 "RUSTC_DEBUG_ASSERTIONS",
961 self.config
.rust_debug_assertions
.to_string(),
963 .env("RUSTC_SYSROOT", &sysroot
)
964 .env("RUSTC_LIBDIR", &libdir
)
965 .env("RUSTC_RPATH", self.config
.rust_rpath
.to_string())
966 .env("RUSTDOC", self.out
.join("bootstrap/debug/rustdoc"))
969 if cmd
== "doc" || cmd
== "rustdoc" || (cmd
== "test" && want_rustdoc
) {
970 self.rustdoc(compiler
)
972 PathBuf
::from("/path/to/nowhere/rustdoc/not/required")
975 .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir());
977 if let Some(host_linker
) = self.linker(compiler
.host
) {
978 cargo
.env("RUSTC_HOST_LINKER", host_linker
);
980 if let Some(target_linker
) = self.linker(target
) {
981 cargo
.env("RUSTC_TARGET_LINKER", target_linker
);
983 if let Some(ref error_format
) = self.config
.rustc_error_format
{
984 cargo
.env("RUSTC_ERROR_FORMAT", error_format
);
986 if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd
)) && want_rustdoc
{
987 cargo
.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler
));
990 let debuginfo_level
= match mode
{
991 Mode
::Rustc
| Mode
::Codegen
=> self.config
.rust_debuginfo_level_rustc
,
992 Mode
::Std
| Mode
::Test
=> self.config
.rust_debuginfo_level_std
,
993 Mode
::ToolBootstrap
| Mode
::ToolStd
|
994 Mode
::ToolTest
| Mode
::ToolRustc
=> self.config
.rust_debuginfo_level_tools
,
996 cargo
.env("RUSTC_DEBUGINFO_LEVEL", debuginfo_level
.to_string());
999 cargo
.env("RUSTC_FORCE_UNSTABLE", "1");
1001 // Currently the compiler depends on crates from crates.io, and
1002 // then other crates can depend on the compiler (e.g., proc-macro
1003 // crates). Let's say, for example that rustc itself depends on the
1004 // bitflags crate. If an external crate then depends on the
1005 // bitflags crate as well, we need to make sure they don't
1006 // conflict, even if they pick the same version of bitflags. We'll
1007 // want to make sure that e.g., a plugin and rustc each get their
1008 // own copy of bitflags.
1010 // Cargo ensures that this works in general through the -C metadata
1011 // flag. This flag will frob the symbols in the binary to make sure
1012 // they're different, even though the source code is the exact
1013 // same. To solve this problem for the compiler we extend Cargo's
1014 // already-passed -C metadata flag with our own. Our rustc.rs
1015 // wrapper around the actual rustc will detect -C metadata being
1016 // passed and frob it with this extra string we're passing in.
1017 cargo
.env("RUSTC_METADATA_SUFFIX", "rustc");
1020 if let Some(x
) = self.crt_static(target
) {
1021 cargo
.env("RUSTC_CRT_STATIC", x
.to_string());
1024 if let Some(x
) = self.crt_static(compiler
.host
) {
1025 cargo
.env("RUSTC_HOST_CRT_STATIC", x
.to_string());
1028 if let Some(map
) = self.build
.debuginfo_map(GitRepo
::Rustc
) {
1029 cargo
.env("RUSTC_DEBUGINFO_MAP", map
);
1032 // Enable usage of unstable features
1033 cargo
.env("RUSTC_BOOTSTRAP", "1");
1034 self.add_rust_test_threads(&mut cargo
);
1036 // Almost all of the crates that we compile as part of the bootstrap may
1037 // have a build script, including the standard library. To compile a
1038 // build script, however, it itself needs a standard library! This
1039 // introduces a bit of a pickle when we're compiling the standard
1042 // To work around this we actually end up using the snapshot compiler
1043 // (stage0) for compiling build scripts of the standard library itself.
1044 // The stage0 compiler is guaranteed to have a libstd available for use.
1046 // For other crates, however, we know that we've already got a standard
1047 // library up and running, so we can use the normal compiler to compile
1048 // build scripts in that situation.
1049 if mode
== Mode
::Std
{
1051 .env("RUSTC_SNAPSHOT", &self.initial_rustc
)
1052 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
1055 .env("RUSTC_SNAPSHOT", self.rustc(compiler
))
1056 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler
));
1059 if self.config
.incremental
{
1060 cargo
.env("CARGO_INCREMENTAL", "1");
1062 // Don't rely on any default setting for incr. comp. in Cargo
1063 cargo
.env("CARGO_INCREMENTAL", "0");
1066 if let Some(ref on_fail
) = self.config
.on_fail
{
1067 cargo
.env("RUSTC_ON_FAIL", on_fail
);
1070 if self.config
.print_step_timings
{
1071 cargo
.env("RUSTC_PRINT_STEP_TIMINGS", "1");
1074 if self.config
.backtrace_on_ice
{
1075 cargo
.env("RUSTC_BACKTRACE_ON_ICE", "1");
1078 cargo
.env("RUSTC_VERBOSE", self.verbosity
.to_string());
1080 if self.config
.deny_warnings
{
1081 cargo
.env("RUSTC_DENY_WARNINGS", "1");
1084 // Throughout the build Cargo can execute a number of build scripts
1085 // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
1086 // obtained previously to those build scripts.
1087 // Build scripts use either the `cc` crate or `configure/make` so we pass
1088 // the options through environment variables that are fetched and understood by both.
1090 // FIXME: the guard against msvc shouldn't need to be here
1091 if target
.contains("msvc") {
1092 if let Some(ref cl
) = self.config
.llvm_clang_cl
{
1093 cargo
.env("CC", cl
).env("CXX", cl
);
1096 let ccache
= self.config
.ccache
.as_ref();
1097 let ccacheify
= |s
: &Path
| {
1098 let ccache
= match ccache
{
1100 None
=> return s
.display().to_string(),
1102 // FIXME: the cc-rs crate only recognizes the literal strings
1103 // `ccache` and `sccache` when doing caching compilations, so we
1104 // mirror that here. It should probably be fixed upstream to
1105 // accept a new env var or otherwise work with custom ccache
1108 "ccache" | "sccache" => format
!("{} {}", ccache
, s
.display()),
1109 _
=> s
.display().to_string(),
1112 let cc
= ccacheify(&self.cc(target
));
1113 cargo
.env(format
!("CC_{}", target
), &cc
);
1115 let cflags
= self.cflags(target
, GitRepo
::Rustc
).join(" ");
1117 .env(format
!("CFLAGS_{}", target
), cflags
.clone());
1119 if let Some(ar
) = self.ar(target
) {
1120 let ranlib
= format
!("{} s", ar
.display());
1122 .env(format
!("AR_{}", target
), ar
)
1123 .env(format
!("RANLIB_{}", target
), ranlib
);
1126 if let Ok(cxx
) = self.cxx(target
) {
1127 let cxx
= ccacheify(&cxx
);
1129 .env(format
!("CXX_{}", target
), &cxx
)
1130 .env(format
!("CXXFLAGS_{}", target
), cflags
);
1134 if (cmd
== "build" || cmd
== "rustc")
1135 && mode
== Mode
::Std
1136 && self.config
.extended
1137 && compiler
.is_final_stage(self)
1139 cargo
.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
1142 // For `cargo doc` invocations, make rustdoc print the Rust version into the docs
1143 cargo
.env("RUSTDOC_CRATE_VERSION", self.rust_version());
1145 // Environment variables *required* throughout the build
1147 // FIXME: should update code to not require this env var
1148 cargo
.env("CFG_COMPILER_HOST_TRIPLE", target
);
1150 // Set this for all builds to make sure doc builds also get it.
1151 cargo
.env("CFG_RELEASE_CHANNEL", &self.config
.channel
);
1153 // This one's a bit tricky. As of the time of this writing the compiler
1154 // links to the `winapi` crate on crates.io. This crate provides raw
1155 // bindings to Windows system functions, sort of like libc does for
1156 // Unix. This crate also, however, provides "import libraries" for the
1157 // MinGW targets. There's an import library per dll in the windows
1158 // distribution which is what's linked to. These custom import libraries
1159 // are used because the winapi crate can reference Windows functions not
1160 // present in the MinGW import libraries.
1162 // For example MinGW may ship libdbghelp.a, but it may not have
1163 // references to all the functions in the dbghelp dll. Instead the
1164 // custom import library for dbghelp in the winapi crates has all this
1167 // Unfortunately for us though the import libraries are linked by
1168 // default via `-ldylib=winapi_foo`. That is, they're linked with the
1169 // `dylib` type with a `winapi_` prefix (so the winapi ones don't
1170 // conflict with the system MinGW ones). This consequently means that
1171 // the binaries we ship of things like rustc_codegen_llvm (aka the rustc_codegen_llvm
1172 // DLL) when linked against *again*, for example with procedural macros
1173 // or plugins, will trigger the propagation logic of `-ldylib`, passing
1174 // `-lwinapi_foo` to the linker again. This isn't actually available in
1175 // our distribution, however, so the link fails.
1177 // To solve this problem we tell winapi to not use its bundled import
1178 // libraries. This means that it will link to the system MinGW import
1179 // libraries by default, and the `-ldylib=foo` directives will still get
1180 // passed to the final linker, but they'll look like `-lfoo` which can
1181 // be resolved because MinGW has the import library. The downside is we
1182 // don't get newer functions from Windows, but we don't use any of them
1184 if !mode
.is_tool() {
1185 cargo
.env("WINAPI_NO_BUNDLED_LIBRARIES", "1");
1188 for _
in 1..self.verbosity
{
1192 match (mode
, self.config
.rust_codegen_units_std
, self.config
.rust_codegen_units
) {
1193 (Mode
::Std
, Some(n
), _
) |
1194 (Mode
::Test
, Some(n
), _
) |
1195 (_
, _
, Some(n
)) => {
1196 cargo
.env("RUSTC_CODEGEN_UNITS", n
.to_string());
1199 // Don't set anything
1203 if self.config
.rust_optimize
{
1204 // FIXME: cargo bench/install do not accept `--release`
1205 if cmd
!= "bench" && cmd
!= "install" {
1206 cargo
.arg("--release");
1210 if self.config
.locked_deps
{
1211 cargo
.arg("--locked");
1213 if self.config
.vendor
|| self.is_sudo
{
1214 cargo
.arg("--frozen");
1217 self.ci_env
.force_coloring_in_ci(&mut cargo
);
1222 /// Ensure that a given step is built, returning its output. This will
1223 /// cache the step, so it is safe (and good!) to call this as often as
1224 /// needed to ensure that all dependencies are built.
1225 pub fn ensure
<S
: Step
>(&'a
self, step
: S
) -> S
::Output
{
1227 let mut stack
= self.stack
.borrow_mut();
1228 for stack_step
in stack
.iter() {
1231 .downcast_ref
::<S
>()
1232 .map_or(true, |stack_step
| *stack_step
!= step
)
1236 let mut out
= String
::new();
1237 out
+= &format
!("\n\nCycle in build detected when adding {:?}\n", step
);
1238 for el
in stack
.iter().rev() {
1239 out
+= &format
!("\t{:?}\n", el
);
1243 if let Some(out
) = self.cache
.get(&step
) {
1244 self.verbose(&format
!("{}c {:?}", " ".repeat(stack
.len()), step
));
1247 let mut graph
= self.graph
.borrow_mut();
1248 let parent
= self.parent
.get();
1252 .entry(format
!("{:?}", step
))
1253 .or_insert_with(|| graph
.add_node(format
!("{:?}", step
)));
1254 if let Some(parent
) = parent
{
1255 graph
.add_edge(parent
, us
, false);
1261 self.verbose(&format
!("{}> {:?}", " ".repeat(stack
.len()), step
));
1262 stack
.push(Box
::new(step
.clone()));
1265 let prev_parent
= self.parent
.get();
1268 let mut graph
= self.graph
.borrow_mut();
1269 let parent
= self.parent
.get();
1273 .entry(format
!("{:?}", step
))
1274 .or_insert_with(|| graph
.add_node(format
!("{:?}", step
)));
1275 self.parent
.set(Some(us
));
1276 if let Some(parent
) = parent
{
1277 graph
.add_edge(parent
, us
, true);
1282 let start
= Instant
::now();
1283 let zero
= Duration
::new(0, 0);
1284 let parent
= self.time_spent_on_dependencies
.replace(zero
);
1285 let out
= step
.clone().run(self);
1286 let dur
= start
.elapsed();
1287 let deps
= self.time_spent_on_dependencies
.replace(parent
+ dur
);
1291 self.parent
.set(prev_parent
);
1293 if self.config
.print_step_timings
&& dur
> Duration
::from_millis(100) {
1295 "[TIMING] {:?} -- {}.{:03}",
1298 dur
.subsec_nanos() / 1_000_000
1303 let mut stack
= self.stack
.borrow_mut();
1304 let cur_step
= stack
.pop().expect("step stack empty");
1305 assert_eq
!(cur_step
.downcast_ref(), Some(&step
));
1307 self.verbose(&format
!(
1309 " ".repeat(self.stack
.borrow().len()),
1312 self.cache
.put(step
, out
.clone());