1 // Copyright 2017 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.
12 use std
::cell
::RefCell
;
13 use std
::collections
::BTreeSet
;
19 use std
::path
::{Path, PathBuf}
;
20 use std
::process
::Command
;
25 use util
::{exe, libdir, add_lib_path}
;
27 use cache
::{INTERNER, Interned, Cache}
;
29 use flags
::Subcommand
;
36 pub struct Builder
<'a
> {
41 stack
: RefCell
<Vec
<Box
<Any
>>>,
44 impl<'a
> Deref
for Builder
<'a
> {
47 fn deref(&self) -> &Self::Target
{
52 pub trait Step
: '
static + Clone
+ Debug
+ PartialEq
+ Eq
+ Hash
{
53 /// `PathBuf` when directories are created or to return a `Compiler` once
54 /// it's been assembled.
57 const DEFAULT
: bool
= false;
59 /// Run this rule for all hosts without cross compiling.
60 const ONLY_HOSTS
: bool
= false;
62 /// Run this rule for all targets, but only with the native host.
63 const ONLY_BUILD_TARGETS
: bool
= false;
65 /// Only run this step with the build triple as host and target.
66 const ONLY_BUILD
: bool
= false;
68 /// Primary function to execute this rule. Can call `builder.ensure(...)`
69 /// with other steps to run those.
70 fn run(self, builder
: &Builder
) -> Self::Output
;
72 /// When bootstrap is passed a set of paths, this controls whether this rule
73 /// will execute. However, it does not get called in a "default" context
74 /// when we are not passed any paths; in that case, make_run is called
76 fn should_run(run
: ShouldRun
) -> ShouldRun
;
78 /// Build up a "root" rule, either as a default rule or from a path passed
81 /// When path is `None`, we are executing in a context where no paths were
82 /// passed. When `./x.py build` is run, for example, this rule could get
83 /// called if it is in the correct list below with a path of `None`.
84 fn make_run(_run
: RunConfig
) {
85 // It is reasonable to not have an implementation of make_run for rules
86 // who do not want to get called from the root context. This means that
87 // they are likely dependencies (e.g., sysroot creation) or similar, and
88 // as such calling them from ./x.py isn't logical.
93 pub struct RunConfig
<'a
> {
94 pub builder
: &'a Builder
<'a
>,
95 pub host
: Interned
<String
>,
96 pub target
: Interned
<String
>,
97 pub path
: Option
<&'a Path
>,
100 struct StepDescription
{
103 only_build_targets
: bool
,
105 should_run
: fn(ShouldRun
) -> ShouldRun
,
106 make_run
: fn(RunConfig
),
109 impl StepDescription
{
110 fn from
<S
: Step
>() -> StepDescription
{
113 only_hosts
: S
::ONLY_HOSTS
,
114 only_build_targets
: S
::ONLY_BUILD_TARGETS
,
115 only_build
: S
::ONLY_BUILD
,
116 should_run
: S
::should_run
,
117 make_run
: S
::make_run
,
121 fn maybe_run(&self, builder
: &Builder
, path
: Option
<&Path
>) {
122 let build
= builder
.build
;
123 let hosts
= if self.only_build_targets
|| self.only_build
{
129 // Determine the targets participating in this rule.
130 let targets
= if self.only_hosts
{
131 if build
.config
.run_host_only
{
133 } else if self.only_build
{
143 for target
in targets
{
144 let run
= RunConfig
{
150 (self.make_run
)(run
);
155 fn run(v
: &[StepDescription
], builder
: &Builder
, paths
: &[PathBuf
]) {
156 let should_runs
= v
.iter().map(|desc
| {
157 (desc
.should_run
)(ShouldRun
::new(builder
))
158 }).collect
::<Vec
<_
>>();
159 if paths
.is_empty() {
160 for (desc
, should_run
) in v
.iter().zip(should_runs
) {
161 if desc
.default && should_run
.is_really_default
{
162 desc
.maybe_run(builder
, None
);
167 let mut attempted_run
= false;
168 for (desc
, should_run
) in v
.iter().zip(&should_runs
) {
169 if should_run
.run(path
) {
170 attempted_run
= true;
171 desc
.maybe_run(builder
, Some(path
));
176 eprintln
!("Warning: no rules matched {}.", path
.display());
184 pub struct ShouldRun
<'a
> {
185 pub builder
: &'a Builder
<'a
>,
186 // use a BTreeSet to maintain sort order
187 paths
: BTreeSet
<PathBuf
>,
189 // If this is a default rule, this is an additional constraint placed on
190 // it's run. Generally something like compiler docs being enabled.
191 is_really_default
: bool
,
194 impl<'a
> ShouldRun
<'a
> {
195 fn new(builder
: &'a Builder
) -> ShouldRun
<'a
> {
198 paths
: BTreeSet
::new(),
199 is_really_default
: true, // by default no additional conditions
203 pub fn default_condition(mut self, cond
: bool
) -> Self {
204 self.is_really_default
= cond
;
208 pub fn krate(mut self, name
: &str) -> Self {
209 for (_
, krate_path
) in self.builder
.crates(name
) {
210 self.paths
.insert(PathBuf
::from(krate_path
));
215 pub fn path(mut self, path
: &str) -> Self {
216 self.paths
.insert(PathBuf
::from(path
));
220 // allows being more explicit about why should_run in Step returns the value passed to it
221 pub fn never(self) -> ShouldRun
<'a
> {
225 fn run(&self, path
: &Path
) -> bool
{
226 self.paths
.iter().any(|p
| path
.ends_with(p
))
230 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
240 impl<'a
> Builder
<'a
> {
241 fn get_step_descriptions(kind
: Kind
) -> Vec
<StepDescription
> {
242 macro_rules
! describe
{
243 ($
($rule
:ty
),+ $
(,)*) => {{
244 vec
![$
(StepDescription
::from
::<$rule
>()),+]
248 Kind
::Build
=> describe
!(compile
::Std
, compile
::Test
, compile
::Rustc
,
249 compile
::StartupObjects
, tool
::BuildManifest
, tool
::Rustbook
, tool
::ErrorIndex
,
250 tool
::UnstableBookGen
, tool
::Tidy
, tool
::Linkchecker
, tool
::CargoTest
,
251 tool
::Compiletest
, tool
::RemoteTestServer
, tool
::RemoteTestClient
,
252 tool
::RustInstaller
, tool
::Cargo
, tool
::Rls
, tool
::Rustdoc
, tool
::Clippy
,
253 native
::Llvm
, tool
::Rustfmt
, tool
::Miri
),
254 Kind
::Test
=> describe
!(check
::Tidy
, check
::Bootstrap
, check
::DefaultCompiletest
,
255 check
::HostCompiletest
, check
::Crate
, check
::CrateLibrustc
, check
::Rustdoc
,
256 check
::Linkcheck
, check
::Cargotest
, check
::Cargo
, check
::Rls
, check
::Docs
,
257 check
::ErrorIndex
, check
::Distcheck
, check
::Rustfmt
, check
::Miri
, check
::Clippy
),
258 Kind
::Bench
=> describe
!(check
::Crate
, check
::CrateLibrustc
),
259 Kind
::Doc
=> describe
!(doc
::UnstableBook
, doc
::UnstableBookGen
, doc
::TheBook
,
260 doc
::Standalone
, doc
::Std
, doc
::Test
, doc
::Rustc
, doc
::ErrorIndex
, doc
::Nomicon
,
261 doc
::Reference
, doc
::Rustdoc
, doc
::CargoBook
),
262 Kind
::Dist
=> describe
!(dist
::Docs
, dist
::Mingw
, dist
::Rustc
, dist
::DebuggerScripts
,
263 dist
::Std
, dist
::Analysis
, dist
::Src
, dist
::PlainSourceTarball
, dist
::Cargo
,
264 dist
::Rls
, dist
::Rustfmt
, dist
::Extended
, dist
::HashSign
,
265 dist
::DontDistWithMiriEnabled
),
266 Kind
::Install
=> describe
!(install
::Docs
, install
::Std
, install
::Cargo
, install
::Rls
,
267 install
::Rustfmt
, install
::Analysis
, install
::Src
, install
::Rustc
),
271 pub fn get_help(build
: &Build
, subcommand
: &str) -> Option
<String
> {
272 let kind
= match subcommand
{
273 "build" => Kind
::Build
,
275 "test" => Kind
::Test
,
276 "bench" => Kind
::Bench
,
277 "dist" => Kind
::Dist
,
278 "install" => Kind
::Install
,
282 let builder
= Builder
{
284 top_stage
: build
.config
.stage
.unwrap_or(2),
287 stack
: RefCell
::new(Vec
::new()),
290 let builder
= &builder
;
291 let mut should_run
= ShouldRun
::new(builder
);
292 for desc
in Builder
::get_step_descriptions(builder
.kind
) {
293 should_run
= (desc
.should_run
)(should_run
);
295 let mut help
= String
::from("Available paths:\n");
296 for path
in should_run
.paths
{
297 help
.push_str(format
!(" ./x.py {} {}\n", subcommand
, path
.display()).as_str());
302 pub fn run(build
: &Build
) {
303 let (kind
, paths
) = match build
.config
.cmd
{
304 Subcommand
::Build { ref paths }
=> (Kind
::Build
, &paths
[..]),
305 Subcommand
::Doc { ref paths }
=> (Kind
::Doc
, &paths
[..]),
306 Subcommand
::Test { ref paths, .. }
=> (Kind
::Test
, &paths
[..]),
307 Subcommand
::Bench { ref paths, .. }
=> (Kind
::Bench
, &paths
[..]),
308 Subcommand
::Dist { ref paths }
=> (Kind
::Dist
, &paths
[..]),
309 Subcommand
::Install { ref paths }
=> (Kind
::Install
, &paths
[..]),
310 Subcommand
::Clean { .. }
=> panic
!(),
313 let builder
= Builder
{
315 top_stage
: build
.config
.stage
.unwrap_or(2),
318 stack
: RefCell
::new(Vec
::new()),
321 StepDescription
::run(&Builder
::get_step_descriptions(builder
.kind
), &builder
, paths
);
324 pub fn default_doc(&self, paths
: Option
<&[PathBuf
]>) {
325 let paths
= paths
.unwrap_or(&[]);
326 StepDescription
::run(&Builder
::get_step_descriptions(Kind
::Doc
), self, paths
);
329 /// Obtain a compiler at a given stage and for a given host. Explicitly does
330 /// not take `Compiler` since all `Compiler` instances are meant to be
331 /// obtained through this function, since it ensures that they are valid
332 /// (i.e., built and assembled).
333 pub fn compiler(&self, stage
: u32, host
: Interned
<String
>) -> Compiler
{
334 self.ensure(compile
::Assemble { target_compiler: Compiler { stage, host }
})
337 pub fn sysroot(&self, compiler
: Compiler
) -> Interned
<PathBuf
> {
338 self.ensure(compile
::Sysroot { compiler }
)
341 /// Returns the libdir where the standard library and other artifacts are
342 /// found for a compiler's sysroot.
343 pub fn sysroot_libdir(
344 &self, compiler
: Compiler
, target
: Interned
<String
>
345 ) -> Interned
<PathBuf
> {
346 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
349 target
: Interned
<String
>,
351 impl Step
for Libdir
{
352 type Output
= Interned
<PathBuf
>;
354 fn should_run(run
: ShouldRun
) -> ShouldRun
{
358 fn run(self, builder
: &Builder
) -> Interned
<PathBuf
> {
359 let compiler
= self.compiler
;
360 let lib
= if compiler
.stage
>= 2 && builder
.build
.config
.libdir_relative
.is_some() {
361 builder
.build
.config
.libdir_relative
.clone().unwrap()
365 let sysroot
= builder
.sysroot(self.compiler
).join(lib
)
366 .join("rustlib").join(self.target
).join("lib");
367 let _
= fs
::remove_dir_all(&sysroot
);
368 t
!(fs
::create_dir_all(&sysroot
));
369 INTERNER
.intern_path(sysroot
)
372 self.ensure(Libdir { compiler, target }
)
375 /// Returns the compiler's libdir where it stores the dynamic libraries that
376 /// it itself links against.
378 /// For example this returns `<sysroot>/lib` on Unix and `<sysroot>/bin` on
380 pub fn rustc_libdir(&self, compiler
: Compiler
) -> PathBuf
{
381 if compiler
.is_snapshot(self) {
382 self.build
.rustc_snapshot_libdir()
384 self.sysroot(compiler
).join(libdir(&compiler
.host
))
388 /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic
389 /// library lookup path.
390 pub fn add_rustc_lib_path(&self, compiler
: Compiler
, cmd
: &mut Command
) {
391 // Windows doesn't need dylib path munging because the dlls for the
392 // compiler live next to the compiler and the system will find them
398 add_lib_path(vec
![self.rustc_libdir(compiler
)], cmd
);
401 /// Get a path to the compiler specified.
402 pub fn rustc(&self, compiler
: Compiler
) -> PathBuf
{
403 if compiler
.is_snapshot(self) {
404 self.initial_rustc
.clone()
406 self.sysroot(compiler
).join("bin").join(exe("rustc", &compiler
.host
))
410 pub fn rustdoc(&self, host
: Interned
<String
>) -> PathBuf
{
411 self.ensure(tool
::Rustdoc { host }
)
414 pub fn rustdoc_cmd(&self, host
: Interned
<String
>) -> Command
{
415 let mut cmd
= Command
::new(&self.out
.join("bootstrap/debug/rustdoc"));
416 let compiler
= self.compiler(self.top_stage
, host
);
417 cmd
.env("RUSTC_STAGE", compiler
.stage
.to_string())
418 .env("RUSTC_SYSROOT", self.sysroot(compiler
))
419 .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler
, self.build
.build
))
420 .env("CFG_RELEASE_CHANNEL", &self.build
.config
.channel
)
421 .env("RUSTDOC_REAL", self.rustdoc(host
))
422 .env("RUSTDOC_CRATE_VERSION", self.build
.rust_version())
423 .env("RUSTC_BOOTSTRAP", "1");
424 if let Some(linker
) = self.build
.linker(host
) {
425 cmd
.env("RUSTC_TARGET_LINKER", linker
);
430 /// Prepares an invocation of `cargo` to be run.
432 /// This will create a `Command` that represents a pending execution of
433 /// Cargo. This cargo will be configured to use `compiler` as the actual
434 /// rustc compiler, its output will be scoped by `mode`'s output directory,
435 /// it will pass the `--target` flag for the specified `target`, and will be
436 /// executing the Cargo command `cmd`.
440 target
: Interned
<String
>,
441 cmd
: &str) -> Command
{
442 let mut cargo
= Command
::new(&self.initial_cargo
);
443 let out_dir
= self.stage_out(compiler
, mode
);
444 cargo
.env("CARGO_TARGET_DIR", out_dir
)
446 .arg("--target").arg(target
);
448 // If we were invoked from `make` then that's already got a jobserver
449 // set up for us so no need to tell Cargo about jobs all over again.
450 if env
::var_os("MAKEFLAGS").is_none() && env
::var_os("MFLAGS").is_none() {
451 cargo
.arg("-j").arg(self.jobs().to_string());
454 // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
455 // Force cargo to output binaries with disambiguating hashes in the name
456 cargo
.env("__CARGO_DEFAULT_LIB_METADATA", &self.config
.channel
);
459 if compiler
.stage
== 0 && self.local_rebuild
{
460 // Assume the local-rebuild rustc already has stage1 features.
463 stage
= compiler
.stage
;
466 // Customize the compiler we're running. Specify the compiler to cargo
467 // as our shim and then pass it some various options used to configure
468 // how the actual compiler itself is called.
470 // These variables are primarily all read by
471 // src/bootstrap/bin/{rustc.rs,rustdoc.rs}
472 cargo
.env("RUSTBUILD_NATIVE_DIR", self.native_dir(target
))
473 .env("RUSTC", self.out
.join("bootstrap/debug/rustc"))
474 .env("RUSTC_REAL", self.rustc(compiler
))
475 .env("RUSTC_STAGE", stage
.to_string())
476 .env("RUSTC_DEBUG_ASSERTIONS",
477 self.config
.rust_debug_assertions
.to_string())
478 .env("RUSTC_SYSROOT", self.sysroot(compiler
))
479 .env("RUSTC_LIBDIR", self.rustc_libdir(compiler
))
480 .env("RUSTC_RPATH", self.config
.rust_rpath
.to_string())
481 .env("RUSTDOC", self.out
.join("bootstrap/debug/rustdoc"))
482 .env("RUSTDOC_REAL", if cmd
== "doc" || cmd
== "test" {
483 self.rustdoc(compiler
.host
)
485 PathBuf
::from("/path/to/nowhere/rustdoc/not/required")
487 .env("TEST_MIRI", self.config
.test_miri
.to_string());
489 if let Some(n
) = self.config
.rust_codegen_units
{
490 cargo
.env("RUSTC_CODEGEN_UNITS", n
.to_string());
493 if let Some(host_linker
) = self.build
.linker(compiler
.host
) {
494 cargo
.env("RUSTC_HOST_LINKER", host_linker
);
496 if let Some(target_linker
) = self.build
.linker(target
) {
497 cargo
.env("RUSTC_TARGET_LINKER", target_linker
);
500 if mode
!= Mode
::Tool
{
501 // Tools don't get debuginfo right now, e.g. cargo and rls don't
502 // get compiled with debuginfo.
503 cargo
.env("RUSTC_DEBUGINFO", self.config
.rust_debuginfo
.to_string())
504 .env("RUSTC_DEBUGINFO_LINES", self.config
.rust_debuginfo_lines
.to_string())
505 .env("RUSTC_FORCE_UNSTABLE", "1");
507 // Currently the compiler depends on crates from crates.io, and
508 // then other crates can depend on the compiler (e.g. proc-macro
509 // crates). Let's say, for example that rustc itself depends on the
510 // bitflags crate. If an external crate then depends on the
511 // bitflags crate as well, we need to make sure they don't
512 // conflict, even if they pick the same version of bitflags. We'll
513 // want to make sure that e.g. a plugin and rustc each get their
514 // own copy of bitflags.
516 // Cargo ensures that this works in general through the -C metadata
517 // flag. This flag will frob the symbols in the binary to make sure
518 // they're different, even though the source code is the exact
519 // same. To solve this problem for the compiler we extend Cargo's
520 // already-passed -C metadata flag with our own. Our rustc.rs
521 // wrapper around the actual rustc will detect -C metadata being
522 // passed and frob it with this extra string we're passing in.
523 cargo
.env("RUSTC_METADATA_SUFFIX", "rustc");
526 if let Some(x
) = self.crt_static(target
) {
527 cargo
.env("RUSTC_CRT_STATIC", x
.to_string());
530 // Enable usage of unstable features
531 cargo
.env("RUSTC_BOOTSTRAP", "1");
532 self.add_rust_test_threads(&mut cargo
);
534 // Almost all of the crates that we compile as part of the bootstrap may
535 // have a build script, including the standard library. To compile a
536 // build script, however, it itself needs a standard library! This
537 // introduces a bit of a pickle when we're compiling the standard
540 // To work around this we actually end up using the snapshot compiler
541 // (stage0) for compiling build scripts of the standard library itself.
542 // The stage0 compiler is guaranteed to have a libstd available for use.
544 // For other crates, however, we know that we've already got a standard
545 // library up and running, so we can use the normal compiler to compile
546 // build scripts in that situation.
548 // If LLVM support is disabled we need to use the snapshot compiler to compile
549 // build scripts, as the new compiler doesnt support executables.
550 if mode
== Mode
::Libstd
|| !self.build
.config
.llvm_enabled
{
551 cargo
.env("RUSTC_SNAPSHOT", &self.initial_rustc
)
552 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
554 cargo
.env("RUSTC_SNAPSHOT", self.rustc(compiler
))
555 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler
));
558 // Ignore incremental modes except for stage0, since we're
559 // not guaranteeing correctness across builds if the compiler
560 // is changing under your feet.`
561 if self.config
.incremental
&& compiler
.stage
== 0 {
562 let incr_dir
= self.incremental_dir(compiler
);
563 cargo
.env("RUSTC_INCREMENTAL", incr_dir
);
566 if let Some(ref on_fail
) = self.config
.on_fail
{
567 cargo
.env("RUSTC_ON_FAIL", on_fail
);
570 cargo
.env("RUSTC_VERBOSE", format
!("{}", self.verbosity
));
572 // Throughout the build Cargo can execute a number of build scripts
573 // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
574 // obtained previously to those build scripts.
575 // Build scripts use either the `cc` crate or `configure/make` so we pass
576 // the options through environment variables that are fetched and understood by both.
578 // FIXME: the guard against msvc shouldn't need to be here
579 if !target
.contains("msvc") {
580 let cc
= self.cc(target
);
581 cargo
.env(format
!("CC_{}", target
), cc
)
584 let cflags
= self.cflags(target
).join(" ");
585 cargo
.env(format
!("CFLAGS_{}", target
), cflags
.clone())
586 .env("CFLAGS", cflags
.clone());
588 if let Some(ar
) = self.ar(target
) {
589 let ranlib
= format
!("{} s", ar
.display());
590 cargo
.env(format
!("AR_{}", target
), ar
)
592 .env(format
!("RANLIB_{}", target
), ranlib
.clone())
593 .env("RANLIB", ranlib
);
596 if let Ok(cxx
) = self.cxx(target
) {
597 cargo
.env(format
!("CXX_{}", target
), cxx
)
599 .env(format
!("CXXFLAGS_{}", target
), cflags
.clone())
600 .env("CXXFLAGS", cflags
);
604 if mode
== Mode
::Libstd
&& self.config
.extended
&& compiler
.is_final_stage(self) {
605 cargo
.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
608 // For `cargo doc` invocations, make rustdoc print the Rust version into the docs
609 cargo
.env("RUSTDOC_CRATE_VERSION", self.build
.rust_version());
611 // Environment variables *required* throughout the build
613 // FIXME: should update code to not require this env var
614 cargo
.env("CFG_COMPILER_HOST_TRIPLE", target
);
616 // Set this for all builds to make sure doc builds also get it.
617 cargo
.env("CFG_RELEASE_CHANNEL", &self.build
.config
.channel
);
619 if self.is_very_verbose() {
622 if self.config
.rust_optimize
{
623 // FIXME: cargo bench does not accept `--release`
625 cargo
.arg("--release");
628 if mode
!= Mode
::Libstd
&& // FIXME(#45320)
629 mode
!= Mode
::Libtest
&& // FIXME(#45511)
630 self.config
.rust_codegen_units
.is_none() &&
631 self.build
.is_rust_llvm(compiler
.host
)
633 cargo
.env("RUSTC_THINLTO", "1");
636 if self.config
.locked_deps
{
637 cargo
.arg("--locked");
639 if self.config
.vendor
|| self.is_sudo
{
640 cargo
.arg("--frozen");
643 self.ci_env
.force_coloring_in_ci(&mut cargo
);
648 /// Ensure that a given step is built, returning it's output. This will
649 /// cache the step, so it is safe (and good!) to call this as often as
650 /// needed to ensure that all dependencies are built.
651 pub fn ensure
<S
: Step
>(&'a
self, step
: S
) -> S
::Output
{
653 let mut stack
= self.stack
.borrow_mut();
654 for stack_step
in stack
.iter() {
656 if stack_step
.downcast_ref
::<S
>().map_or(true, |stack_step
| *stack_step
!= step
) {
659 let mut out
= String
::new();
660 out
+= &format
!("\n\nCycle in build detected when adding {:?}\n", step
);
661 for el
in stack
.iter().rev() {
662 out
+= &format
!("\t{:?}\n", el
);
666 if let Some(out
) = self.cache
.get(&step
) {
667 self.build
.verbose(&format
!("{}c {:?}", " ".repeat(stack
.len()), step
));
671 self.build
.verbose(&format
!("{}> {:?}", " ".repeat(stack
.len()), step
));
672 stack
.push(Box
::new(step
.clone()));
674 let out
= step
.clone().run(self);
676 let mut stack
= self.stack
.borrow_mut();
677 let cur_step
= stack
.pop().expect("step stack empty");
678 assert_eq
!(cur_step
.downcast_ref(), Some(&step
));
680 self.build
.verbose(&format
!("{}< {:?}", " ".repeat(self.stack
.borrow().len()), step
));
681 self.cache
.put(step
, out
.clone());