builder.rs 24.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11 12
use std::fmt::Debug;
use std::hash::Hash;
13 14 15 16
use std::cell::RefCell;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::fs;
17
use std::ops::Deref;
18
use std::any::Any;
19
use std::collections::BTreeSet;
20 21 22 23 24 25

use compile;
use install;
use dist;
use util::{exe, libdir, add_lib_path};
use {Build, Mode};
26
use cache::{INTERNER, Interned, Cache};
27 28 29
use check;
use flags::Subcommand;
use doc;
M
Mark Simulacrum 已提交
30
use tool;
A
Alex Crichton 已提交
31
use native;
32

33 34
pub use Compiler;

35 36 37 38 39
pub struct Builder<'a> {
    pub build: &'a Build,
    pub top_stage: u32,
    pub kind: Kind,
    cache: Cache,
40
    stack: RefCell<Vec<Box<Any>>>,
41 42 43 44 45 46 47 48 49 50
}

impl<'a> Deref for Builder<'a> {
    type Target = Build;

    fn deref(&self) -> &Self::Target {
        self.build
    }
}

51
pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash {
52 53
    /// `PathBuf` when directories are created or to return a `Compiler` once
    /// it's been assembled.
54
    type Output: Clone;
55

56 57
    const DEFAULT: bool = false;

58
    /// Run this rule for all hosts without cross compiling.
59 60 61 62 63 64 65 66
    const ONLY_HOSTS: bool = false;

    /// Run this rule for all targets, but only with the native host.
    const ONLY_BUILD_TARGETS: bool = false;

    /// Only run this step with the build triple as host and target.
    const ONLY_BUILD: bool = false;

67 68
    /// Primary function to execute this rule. Can call `builder.ensure(...)`
    /// with other steps to run those.
69
    fn run(self, builder: &Builder) -> Self::Output;
70

71 72 73 74
    /// When bootstrap is passed a set of paths, this controls whether this rule
    /// will execute. However, it does not get called in a "default" context
    /// when we are not passed any paths; in that case, make_run is called
    /// directly.
75
    fn should_run(run: ShouldRun) -> ShouldRun;
76

77 78 79 80 81 82
    /// Build up a "root" rule, either as a default rule or from a path passed
    /// to us.
    ///
    /// When path is `None`, we are executing in a context where no paths were
    /// passed. When `./x.py build` is run, for example, this rule could get
    /// called if it is in the correct list below with a path of `None`.
83
    fn make_run(_run: RunConfig) {
84 85 86 87 88 89
        // It is reasonable to not have an implementation of make_run for rules
        // who do not want to get called from the root context. This means that
        // they are likely dependencies (e.g., sysroot creation) or similar, and
        // as such calling them from ./x.py isn't logical.
        unimplemented!()
    }
90 91
}

92 93 94 95 96 97 98
pub struct RunConfig<'a> {
    pub builder: &'a Builder<'a>,
    pub host: Interned<String>,
    pub target: Interned<String>,
    pub path: Option<&'a Path>,
}

99 100 101 102 103 104
struct StepDescription {
    default: bool,
    only_hosts: bool,
    only_build_targets: bool,
    only_build: bool,
    should_run: fn(ShouldRun) -> ShouldRun,
105
    make_run: fn(RunConfig),
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
}

impl StepDescription {
    fn from<S: Step>() -> StepDescription {
        StepDescription {
            default: S::DEFAULT,
            only_hosts: S::ONLY_HOSTS,
            only_build_targets: S::ONLY_BUILD_TARGETS,
            only_build: S::ONLY_BUILD,
            should_run: S::should_run,
            make_run: S::make_run,
        }
    }

    fn maybe_run(&self, builder: &Builder, path: Option<&Path>) {
        let build = builder.build;
        let hosts = if self.only_build_targets || self.only_build {
            &build.config.host[..1]
        } else {
            &build.hosts
        };

        // Determine the actual targets participating in this rule.
        // NOTE: We should keep the full projection from build triple to
        // the hosts for the dist steps, now that the hosts array above is
        // truncated to avoid duplication of work in that case. Therefore
        // the original non-shadowed hosts array is used below.
        let targets = if self.only_hosts {
            // If --target was specified but --host wasn't specified,
            // don't run any host-only tests. Also, respect any `--host`
            // overrides as done for `hosts`.
            if build.flags.host.len() > 0 {
                &build.flags.host[..]
            } else if build.flags.target.len() > 0 {
                &[]
            } else if self.only_build {
                &build.config.host[..1]
            } else {
                &build.config.host[..]
            }
        } else {
            &build.targets
        };

        for host in hosts {
            for target in targets {
152 153 154 155 156 157 158
                let run = RunConfig {
                    builder,
                    path,
                    host: *host,
                    target: *target,
                };
                (self.make_run)(run);
159 160 161 162 163
            }
        }
    }

    fn run(v: &[StepDescription], builder: &Builder, paths: &[PathBuf]) {
164 165 166
        let should_runs = v.iter().map(|desc| {
            (desc.should_run)(ShouldRun::new(builder))
        }).collect::<Vec<_>>();
167
        if paths.is_empty() {
168 169
            for (desc, should_run) in v.iter().zip(should_runs) {
                if desc.default && should_run.is_really_default {
170 171 172 173 174 175
                    desc.maybe_run(builder, None);
                }
            }
        } else {
            for path in paths {
                let mut attempted_run = false;
176 177
                for (desc, should_run) in v.iter().zip(&should_runs) {
                    if should_run.run(path) {
178 179 180 181 182 183 184 185 186 187 188 189 190
                        attempted_run = true;
                        desc.maybe_run(builder, Some(path));
                    }
                }

                if !attempted_run {
                    eprintln!("Warning: no rules matched {}.", path.display());
                }
            }
        }
    }
}

191 192
#[derive(Clone)]
pub struct ShouldRun<'a> {
193
    pub builder: &'a Builder<'a>,
194 195
    // use a BTreeSet to maintain sort order
    paths: BTreeSet<PathBuf>,
196 197 198 199

    // If this is a default rule, this is an additional constraint placed on
    // it's run. Generally something like compiler docs being enabled.
    is_really_default: bool,
200 201 202 203 204 205 206
}

impl<'a> ShouldRun<'a> {
    fn new(builder: &'a Builder) -> ShouldRun<'a> {
        ShouldRun {
            builder: builder,
            paths: BTreeSet::new(),
207
            is_really_default: true, // by default no additional conditions
208 209 210
        }
    }

211 212 213 214 215
    pub fn default_condition(mut self, cond: bool) -> Self {
        self.is_really_default = cond;
        self
    }

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
    pub fn krate(mut self, name: &str) -> Self {
        for (_, krate_path) in self.builder.crates(name) {
            self.paths.insert(PathBuf::from(krate_path));
        }
        self
    }

    pub fn path(mut self, path: &str) -> Self {
        self.paths.insert(PathBuf::from(path));
        self
    }

    // allows being more explicit about why should_run in Step returns the value passed to it
    pub fn never(self) -> ShouldRun<'a> {
        self
    }

    fn run(&self, path: &Path) -> bool {
        self.paths.iter().any(|p| path.ends_with(p))
    }
}

238 239 240 241 242 243 244 245 246 247
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Kind {
    Build,
    Test,
    Bench,
    Dist,
    Doc,
    Install,
}

248 249 250 251 252 253
impl<'a> Builder<'a> {
    fn get_step_descriptions(kind: Kind) -> Vec<StepDescription> {
        macro_rules! describe {
            ($($rule:ty),+ $(,)*) => {{
                vec![$(StepDescription::from::<$rule>()),+]
            }};
254
        }
255 256 257 258 259
        match kind {
            Kind::Build => describe!(compile::Std, compile::Test, compile::Rustc,
                compile::StartupObjects, tool::BuildManifest, tool::Rustbook, tool::ErrorIndex,
                tool::UnstableBookGen, tool::Tidy, tool::Linkchecker, tool::CargoTest,
                tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient,
A
Alex Crichton 已提交
260 261
                tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc,
                native::Llvm),
262 263
            Kind::Test => describe!(check::Tidy, check::Bootstrap, check::DefaultCompiletest,
                check::HostCompiletest, check::Crate, check::CrateLibrustc, check::Linkcheck,
M
Mark Simulacrum 已提交
264 265
                check::Cargotest, check::Cargo, check::Rls, check::Docs, check::ErrorIndex,
                check::Distcheck),
266 267 268 269 270 271 272 273 274 275 276
            Kind::Bench => describe!(check::Crate, check::CrateLibrustc),
            Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
                doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon,
                doc::Reference),
            Kind::Dist => describe!(dist::Docs, dist::Mingw, dist::Rustc, dist::DebuggerScripts,
                dist::Std, dist::Analysis, dist::Src, dist::PlainSourceTarball, dist::Cargo,
                dist::Rls, dist::Extended, dist::HashSign),
            Kind::Install => describe!(install::Docs, install::Std, install::Cargo, install::Rls,
                install::Analysis, install::Src, install::Rustc),
        }
    }
277

278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
    pub fn get_help(build: &Build, subcommand: &str) -> Option<String> {
        let kind = match subcommand {
            "build" => Kind::Build,
            "doc" => Kind::Doc,
            "test" => Kind::Test,
            "bench" => Kind::Bench,
            "dist" => Kind::Dist,
            "install" => Kind::Install,
            _ => return None,
        };

        let builder = Builder {
            build: build,
            top_stage: build.flags.stage.unwrap_or(2),
            kind: kind,
            cache: Cache::new(),
            stack: RefCell::new(Vec::new()),
        };

        let builder = &builder;
        let mut should_run = ShouldRun::new(builder);
299 300
        for desc in Builder::get_step_descriptions(builder.kind) {
            should_run = (desc.should_run)(should_run);
301 302 303 304 305 306 307 308
        }
        let mut help = String::from("Available paths:\n");
        for path in should_run.paths {
            help.push_str(format!("    ./x.py {} {}\n", subcommand, path.display()).as_str());
        }
        Some(help)
    }

309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    pub fn run(build: &Build) {
        let (kind, paths) = match build.flags.cmd {
            Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
            Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
            Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]),
            Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
            Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
            Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
            Subcommand::Clean => panic!(),
        };

        let builder = Builder {
            build: build,
            top_stage: build.flags.stage.unwrap_or(2),
            kind: kind,
            cache: Cache::new(),
            stack: RefCell::new(Vec::new()),
        };

328
        StepDescription::run(&Builder::get_step_descriptions(builder.kind), &builder, paths);
329 330 331 332
    }

    pub fn default_doc(&self, paths: Option<&[PathBuf]>) {
        let paths = paths.unwrap_or(&[]);
333
        StepDescription::run(&Builder::get_step_descriptions(Kind::Doc), self, paths);
334 335
    }

336 337 338 339
    /// Obtain a compiler at a given stage and for a given host. Explictly does
    /// not take `Compiler` since all `Compiler` instances are meant to be
    /// obtained through this function, since it ensures that they are valid
    /// (i.e., built and assembled).
340
    pub fn compiler(&self, stage: u32, host: Interned<String>) -> Compiler {
341 342 343
        self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } })
    }

344
    pub fn sysroot(&self, compiler: Compiler) -> Interned<PathBuf> {
345 346 347 348 349
        self.ensure(compile::Sysroot { compiler })
    }

    /// Returns the libdir where the standard library and other artifacts are
    /// found for a compiler's sysroot.
350 351 352 353 354 355 356
    pub fn sysroot_libdir(
        &self, compiler: Compiler, target: Interned<String>
    ) -> Interned<PathBuf> {
        #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        struct Libdir {
            compiler: Compiler,
            target: Interned<String>,
357
        }
358 359
        impl Step for Libdir {
            type Output = Interned<PathBuf>;
360

361 362
            fn should_run(run: ShouldRun) -> ShouldRun {
                run.never()
363 364
            }

365
            fn run(self, builder: &Builder) -> Interned<PathBuf> {
366
                let compiler = self.compiler;
367
                let lib = if compiler.stage >= 2 && builder.build.config.libdir_relative.is_some() {
368
                    builder.build.config.libdir_relative.clone().unwrap()
369 370 371 372 373
                } else {
                    PathBuf::from("lib")
                };
                let sysroot = builder.sysroot(self.compiler).join(lib)
                    .join("rustlib").join(self.target).join("lib");
374 375
                let _ = fs::remove_dir_all(&sysroot);
                t!(fs::create_dir_all(&sysroot));
376
                INTERNER.intern_path(sysroot)
377 378 379 380 381 382 383 384 385 386 387 388 389 390
            }
        }
        self.ensure(Libdir { compiler, target })
    }

    /// Returns the compiler's libdir where it stores the dynamic libraries that
    /// it itself links against.
    ///
    /// For example this returns `<sysroot>/lib` on Unix and `<sysroot>/bin` on
    /// Windows.
    pub fn rustc_libdir(&self, compiler: Compiler) -> PathBuf {
        if compiler.is_snapshot(self) {
            self.build.rustc_snapshot_libdir()
        } else {
391
            self.sysroot(compiler).join(libdir(&compiler.host))
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
        }
    }

    /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic
    /// library lookup path.
    pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) {
        // Windows doesn't need dylib path munging because the dlls for the
        // compiler live next to the compiler and the system will find them
        // automatically.
        if cfg!(windows) {
            return
        }

        add_lib_path(vec![self.rustc_libdir(compiler)], cmd);
    }

408 409 410 411 412
    /// Get a path to the compiler specified.
    pub fn rustc(&self, compiler: Compiler) -> PathBuf {
        if compiler.is_snapshot(self) {
            self.initial_rustc.clone()
        } else {
413
            self.sysroot(compiler).join("bin").join(exe("rustc", &compiler.host))
414 415 416 417
        }
    }

    pub fn rustdoc(&self, compiler: Compiler) -> PathBuf {
M
Mark Simulacrum 已提交
418 419 420 421 422 423 424 425 426 427 428 429
        self.ensure(tool::Rustdoc { target_compiler: compiler })
    }

    pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
        let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc"));
        cmd
            .env("RUSTC_STAGE", compiler.stage.to_string())
            .env("RUSTC_SYSROOT", if compiler.is_snapshot(&self.build) {
                INTERNER.intern_path(self.build.rustc_snapshot_libdir())
            } else {
                self.sysroot(compiler)
            })
430
            .env("RUSTC_LIBDIR", self.rustc_libdir(compiler))
431
            .env("CFG_RELEASE_CHANNEL", &self.build.config.channel)
M
Mark Simulacrum 已提交
432 433
            .env("RUSTDOC_REAL", self.rustdoc(compiler));
        cmd
434 435
    }

436 437 438 439 440 441 442
    /// Prepares an invocation of `cargo` to be run.
    ///
    /// This will create a `Command` that represents a pending execution of
    /// Cargo. This cargo will be configured to use `compiler` as the actual
    /// rustc compiler, its output will be scoped by `mode`'s output directory,
    /// it will pass the `--target` flag for the specified `target`, and will be
    /// executing the Cargo command `cmd`.
443
    pub fn cargo(&self,
M
Mark Simulacrum 已提交
444 445
             compiler: Compiler,
             mode: Mode,
446
             target: Interned<String>,
M
Mark Simulacrum 已提交
447 448 449
             cmd: &str) -> Command {
        let mut cargo = Command::new(&self.initial_cargo);
        let out_dir = self.stage_out(compiler, mode);
450 451
        cargo.env("CARGO_TARGET_DIR", out_dir)
             .arg(cmd)
M
Mark Simulacrum 已提交
452
             .arg("-j").arg(self.jobs().to_string())
453 454 455 456
             .arg("--target").arg(target);

        // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
        // Force cargo to output binaries with disambiguating hashes in the name
M
Mark Simulacrum 已提交
457
        cargo.env("__CARGO_DEFAULT_LIB_METADATA", &self.config.channel);
458 459

        let stage;
M
Mark Simulacrum 已提交
460
        if compiler.stage == 0 && self.local_rebuild {
461 462 463 464 465 466 467 468
            // Assume the local-rebuild rustc already has stage1 features.
            stage = 1;
        } else {
            stage = compiler.stage;
        }

        // Customize the compiler we're running. Specify the compiler to cargo
        // as our shim and then pass it some various options used to configure
M
Mark Simulacrum 已提交
469
        // how the actual compiler itself is called.
470 471 472
        //
        // These variables are primarily all read by
        // src/bootstrap/bin/{rustc.rs,rustdoc.rs}
M
Mark Simulacrum 已提交
473 474
        cargo.env("RUSTBUILD_NATIVE_DIR", self.native_dir(target))
             .env("RUSTC", self.out.join("bootstrap/debug/rustc"))
475
             .env("RUSTC_REAL", self.rustc(compiler))
476 477
             .env("RUSTC_STAGE", stage.to_string())
             .env("RUSTC_CODEGEN_UNITS",
M
Mark Simulacrum 已提交
478
                  self.config.rust_codegen_units.to_string())
479
             .env("RUSTC_DEBUG_ASSERTIONS",
M
Mark Simulacrum 已提交
480
                  self.config.rust_debug_assertions.to_string())
481 482
             .env("RUSTC_SYSROOT", self.sysroot(compiler))
             .env("RUSTC_LIBDIR", self.rustc_libdir(compiler))
M
Mark Simulacrum 已提交
483 484
             .env("RUSTC_RPATH", self.config.rust_rpath.to_string())
             .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
M
Mark Simulacrum 已提交
485 486 487 488 489
             .env("RUSTDOC_REAL", if cmd == "doc" || cmd == "test" {
                 self.rustdoc(compiler)
             } else {
                 PathBuf::from("/path/to/nowhere/rustdoc/not/required")
             })
M
Mark Simulacrum 已提交
490
             .env("RUSTC_FLAGS", self.rustc_flags(target).join(" "));
491 492 493 494

        if mode != Mode::Tool {
            // Tools don't get debuginfo right now, e.g. cargo and rls don't
            // get compiled with debuginfo.
M
Mark Simulacrum 已提交
495 496
            cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string())
                 .env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string())
497 498 499 500
                 .env("RUSTC_FORCE_UNSTABLE", "1");

            // Currently the compiler depends on crates from crates.io, and
            // then other crates can depend on the compiler (e.g. proc-macro
M
Mark Simulacrum 已提交
501
            // crates). Let's say, for example that rustc itself depends on the
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
            // bitflags crate. If an external crate then depends on the
            // bitflags crate as well, we need to make sure they don't
            // conflict, even if they pick the same verison of bitflags. We'll
            // want to make sure that e.g. a plugin and rustc each get their
            // own copy of bitflags.

            // Cargo ensures that this works in general through the -C metadata
            // flag. This flag will frob the symbols in the binary to make sure
            // they're different, even though the source code is the exact
            // same. To solve this problem for the compiler we extend Cargo's
            // already-passed -C metadata flag with our own. Our rustc.rs
            // wrapper around the actual rustc will detect -C metadata being
            // passed and frob it with this extra string we're passing in.
            cargo.env("RUSTC_METADATA_SUFFIX", "rustc");
        }

        // Enable usage of unstable features
        cargo.env("RUSTC_BOOTSTRAP", "1");
M
Mark Simulacrum 已提交
520
        self.add_rust_test_threads(&mut cargo);
521 522 523

        // Almost all of the crates that we compile as part of the bootstrap may
        // have a build script, including the standard library. To compile a
M
Mark Simulacrum 已提交
524
        // build script, however, it itself needs a standard library! This
525
        // introduces a bit of a pickle when we're compiling the standard
M
Mark Simulacrum 已提交
526
        // library itself.
527 528
        //
        // To work around this we actually end up using the snapshot compiler
M
Mark Simulacrum 已提交
529
        // (stage0) for compiling build scripts of the standard library itself.
530 531 532 533 534 535
        // The stage0 compiler is guaranteed to have a libstd available for use.
        //
        // For other crates, however, we know that we've already got a standard
        // library up and running, so we can use the normal compiler to compile
        // build scripts in that situation.
        if mode == Mode::Libstd {
M
Mark Simulacrum 已提交
536 537
            cargo.env("RUSTC_SNAPSHOT", &self.initial_rustc)
                 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
538
        } else {
539
            cargo.env("RUSTC_SNAPSHOT", self.rustc(compiler))
540 541 542 543 544 545
                 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler));
        }

        // Ignore incremental modes except for stage0, since we're
        // not guaranteeing correctness across builds if the compiler
        // is changing under your feet.`
M
Mark Simulacrum 已提交
546 547
        if self.flags.incremental && compiler.stage == 0 {
            let incr_dir = self.incremental_dir(compiler);
548 549 550
            cargo.env("RUSTC_INCREMENTAL", incr_dir);
        }

M
Mark Simulacrum 已提交
551
        if let Some(ref on_fail) = self.flags.on_fail {
552 553 554
            cargo.env("RUSTC_ON_FAIL", on_fail);
        }

M
Mark Simulacrum 已提交
555
        cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity));
556 557 558 559 560 561

        // Specify some various options for build scripts used throughout
        // the build.
        //
        // FIXME: the guard against msvc shouldn't need to be here
        if !target.contains("msvc") {
M
Mark Simulacrum 已提交
562 563 564
            cargo.env(format!("CC_{}", target), self.cc(target))
                 .env(format!("AR_{}", target), self.ar(target).unwrap()) // only msvc is None
                 .env(format!("CFLAGS_{}", target), self.cflags(target).join(" "));
565

M
Mark Simulacrum 已提交
566
            if let Ok(cxx) = self.cxx(target) {
567 568 569 570
                 cargo.env(format!("CXX_{}", target), cxx);
            }
        }

M
Mark Simulacrum 已提交
571
        if mode == Mode::Libstd && self.config.extended && compiler.is_final_stage(self) {
572 573 574 575 576 577 578 579
            cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
        }

        // Environment variables *required* throughout the build
        //
        // FIXME: should update code to not require this env var
        cargo.env("CFG_COMPILER_HOST_TRIPLE", target);

580 581 582
        // Set this for all builds to make sure doc builds also get it.
        cargo.env("CFG_RELEASE_CHANNEL", &self.build.config.channel);

M
Mark Simulacrum 已提交
583
        if self.is_verbose() {
584 585 586
            cargo.arg("-v");
        }
        // FIXME: cargo bench does not accept `--release`
M
Mark Simulacrum 已提交
587
        if self.config.rust_optimize && cmd != "bench" {
588 589
            cargo.arg("--release");
        }
M
Mark Simulacrum 已提交
590
        if self.config.locked_deps {
591 592
            cargo.arg("--locked");
        }
M
Mark Simulacrum 已提交
593
        if self.config.vendor || self.is_sudo {
594 595 596
            cargo.arg("--frozen");
        }

M
Mark Simulacrum 已提交
597
        self.ci_env.force_coloring_in_ci(&mut cargo);
598 599 600 601

        cargo
    }

602 603 604
    /// Ensure that a given step is built, returning it's output. This will
    /// cache the step, so it is safe (and good!) to call this as often as
    /// needed to ensure that all dependencies are built.
605
    pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
606 607
        {
            let mut stack = self.stack.borrow_mut();
608 609 610 611
            for stack_step in stack.iter() {
                // should skip
                if stack_step.downcast_ref::<S>().map_or(true, |stack_step| *stack_step != step) {
                    continue;
612
                }
613
                let mut out = String::new();
614
                out += &format!("\n\nCycle in build detected when adding {:?}\n", step);
615 616 617 618 619
                for el in stack.iter().rev() {
                    out += &format!("\t{:?}\n", el);
                }
                panic!(out);
            }
620 621
            if let Some(out) = self.cache.get(&step) {
                self.build.verbose(&format!("{}c {:?}", "  ".repeat(stack.len()), step));
622 623 624

                return out;
            }
625
            self.build.verbose(&format!("{}> {:?}", "  ".repeat(stack.len()), step));
626
            stack.push(Box::new(step.clone()));
627
        }
628
        let out = step.clone().run(self);
629 630
        {
            let mut stack = self.stack.borrow_mut();
631 632
            let cur_step = stack.pop().expect("step stack empty");
            assert_eq!(cur_step.downcast_ref(), Some(&step));
633
        }
634 635 636
        self.build.verbose(&format!("{}< {:?}", "  ".repeat(self.stack.borrow().len()), step));
        self.cache.put(step, out.clone());
        out
637 638
    }
}