builder.rs 33.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 13 14
use std::any::Any;
use std::cell::RefCell;
use std::collections::BTreeSet;
use std::env;
15
use std::fmt::Debug;
16
use std::fs;
17
use std::hash::Hash;
18
use std::ops::Deref;
19 20 21 22 23 24 25 26
use std::path::{Path, PathBuf};
use std::process::Command;

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

35 36
pub use Compiler;

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

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

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

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

58 59
    const DEFAULT: bool = false;

60
    /// Run this rule for all hosts without cross compiling.
61 62 63 64 65 66 67 68
    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;

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

73 74 75 76
    /// 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.
77
    fn should_run(run: ShouldRun) -> ShouldRun;
78

79 80 81 82 83 84
    /// 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`.
85
    fn make_run(_run: RunConfig) {
86 87 88 89 90 91
        // 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!()
    }
92 93
}

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

101 102 103 104 105 106
struct StepDescription {
    default: bool,
    only_hosts: bool,
    only_build_targets: bool,
    only_build: bool,
    should_run: fn(ShouldRun) -> ShouldRun,
107
    make_run: fn(RunConfig),
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
    name: &'static str,
}

#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
struct PathSet {
    set: BTreeSet<PathBuf>,
}

impl PathSet {
    fn one<P: Into<PathBuf>>(path: P) -> PathSet {
        let mut set = BTreeSet::new();
        set.insert(path.into());
        PathSet { set }
    }

    fn has(&self, needle: &Path) -> bool {
        self.set.iter().any(|p| p.ends_with(needle))
    }

    fn path(&self) -> &Path {
        self.set.iter().next().unwrap()
    }
130 131 132 133 134 135 136 137 138 139 140
}

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,
141
            name: unsafe { ::std::intrinsics::type_name::<S>() },
142 143 144
        }
    }

145 146 147 148 149 150 151
    fn maybe_run(&self, builder: &Builder, pathset: &PathSet) {
        if builder.config.exclude.iter().any(|e| pathset.has(e)) {
            eprintln!("Skipping {:?} because it is excluded", pathset);
            return;
        } else if !builder.config.exclude.is_empty() {
            eprintln!("{:?} not skipped for {:?} -- not in {:?}", pathset,
                self.name, builder.config.exclude);
152
        }
153 154
        let build = builder.build;
        let hosts = if self.only_build_targets || self.only_build {
M
Mark Simulacrum 已提交
155
            build.build_triple()
156 157 158 159
        } else {
            &build.hosts
        };

M
Mark Simulacrum 已提交
160
        // Determine the targets participating in this rule.
161
        let targets = if self.only_hosts {
162
            if build.config.run_host_only {
163 164
                &[]
            } else if self.only_build {
M
Mark Simulacrum 已提交
165
                build.build_triple()
166
            } else {
M
Mark Simulacrum 已提交
167
                &build.hosts
168 169 170 171 172 173 174
            }
        } else {
            &build.targets
        };

        for host in hosts {
            for target in targets {
175 176
                let run = RunConfig {
                    builder,
177
                    path: pathset.path(),
178 179 180 181
                    host: *host,
                    target: *target,
                };
                (self.make_run)(run);
182 183 184 185 186
            }
        }
    }

    fn run(v: &[StepDescription], builder: &Builder, paths: &[PathBuf]) {
187 188 189
        let should_runs = v.iter().map(|desc| {
            (desc.should_run)(ShouldRun::new(builder))
        }).collect::<Vec<_>>();
190 191 192 193 194 195 196

        // sanity checks on rules
        for (desc, should_run) in v.iter().zip(&should_runs) {
            assert!(!should_run.paths.is_empty(),
                "{:?} should have at least one pathset", desc.name);
        }

197
        if paths.is_empty() {
198 199
            for (desc, should_run) in v.iter().zip(should_runs) {
                if desc.default && should_run.is_really_default {
200 201 202
                    for pathset in &should_run.paths {
                        desc.maybe_run(builder, pathset);
                    }
203 204 205 206 207
                }
            }
        } else {
            for path in paths {
                let mut attempted_run = false;
208
                for (desc, should_run) in v.iter().zip(&should_runs) {
209
                    if let Some(pathset) = should_run.pathset_for_path(path) {
210
                        attempted_run = true;
211
                        desc.maybe_run(builder, pathset);
212 213 214 215 216 217 218 219 220 221 222
                    }
                }

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

223 224
#[derive(Clone)]
pub struct ShouldRun<'a> {
225
    pub builder: &'a Builder<'a>,
226
    // use a BTreeSet to maintain sort order
227
    paths: BTreeSet<PathSet>,
228 229 230 231

    // 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,
232 233 234 235 236
}

impl<'a> ShouldRun<'a> {
    fn new(builder: &'a Builder) -> ShouldRun<'a> {
        ShouldRun {
237
            builder,
238
            paths: BTreeSet::new(),
239
            is_really_default: true, // by default no additional conditions
240 241 242
        }
    }

243 244 245 246 247
    pub fn default_condition(mut self, cond: bool) -> Self {
        self.is_really_default = cond;
        self
    }

248 249 250 251 252 253 254 255 256 257 258 259
    // Unlike `krate` this will create just one pathset. As such, it probably shouldn't actually
    // ever be used, but as we transition to having all rules properly handle passing krate(...) by
    // actually doing something different for every crate passed.
    pub fn all_krates(mut self, name: &str) -> Self {
        let mut set = BTreeSet::new();
        for krate in self.builder.in_tree_crates(name) {
            set.insert(PathBuf::from(&krate.path));
        }
        self.paths.insert(PathSet { set });
        self
    }

260
    pub fn krate(mut self, name: &str) -> Self {
261 262
        for krate in self.builder.in_tree_crates(name) {
            self.paths.insert(PathSet::one(&krate.path));
263 264 265 266
        }
        self
    }

267 268 269 270 271 272 273 274 275 276
    // single, non-aliased path
    pub fn path(self, path: &str) -> Self {
        self.paths(&[path])
    }

    // multiple aliases for the same job
    pub fn paths(mut self, paths: &[&str]) -> Self {
        self.paths.insert(PathSet {
            set: paths.iter().map(PathBuf::from).collect(),
        });
277 278 279 280 281 282 283 284
        self
    }

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

285 286
    fn pathset_for_path(&self, path: &Path) -> Option<&PathSet> {
        self.paths.iter().find(|pathset| pathset.has(path))
287 288 289
    }
}

290 291 292
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Kind {
    Build,
293
    Check,
294 295 296 297 298 299 300
    Test,
    Bench,
    Dist,
    Doc,
    Install,
}

301 302 303 304 305 306
impl<'a> Builder<'a> {
    fn get_step_descriptions(kind: Kind) -> Vec<StepDescription> {
        macro_rules! describe {
            ($($rule:ty),+ $(,)*) => {{
                vec![$(StepDescription::from::<$rule>()),+]
            }};
307
        }
308 309 310 311 312
        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,
O
Oliver Schneider 已提交
313
                tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy,
314
                native::Llvm, tool::Rustfmt, tool::Miri),
315
            Kind::Check => describe!(check::Std, check::Test, check::Rustc),
316 317 318 319 320 321 322 323 324 325
            Kind::Test => describe!(test::Tidy, test::Bootstrap, test::Ui, test::RunPass,
                test::CompileFail, test::ParseFail, test::RunFail, test::RunPassValgrind,
                test::MirOpt, test::Codegen, test::CodegenUnits, test::Incremental, test::Debuginfo,
                test::UiFullDeps, test::RunPassFullDeps, test::RunFailFullDeps,
                test::CompileFailFullDeps, test::IncrementalFullDeps, test::Rustdoc, test::Pretty,
                test::RunPassPretty, test::RunFailPretty, test::RunPassValgrindPretty,
                test::RunPassFullDepsPretty, test::RunFailFullDepsPretty, test::RunMake,
                test::Crate, test::CrateLibrustc, test::Rustdoc, test::Linkcheck, test::Cargotest,
                test::Cargo, test::Rls, test::Docs, test::ErrorIndex, test::Distcheck,
                test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme),
326
            Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
327 328
            Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
                doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon,
P
projektir 已提交
329
                doc::Reference, doc::Rustdoc, doc::RustByExample, doc::CargoBook),
330 331
            Kind::Dist => describe!(dist::Docs, dist::Mingw, dist::Rustc, dist::DebuggerScripts,
                dist::Std, dist::Analysis, dist::Src, dist::PlainSourceTarball, dist::Cargo,
332
                dist::Rls, dist::Rustfmt, dist::Extended, dist::HashSign),
333
            Kind::Install => describe!(install::Docs, install::Std, install::Cargo, install::Rls,
O
Oliver Schneider 已提交
334
                install::Rustfmt, install::Analysis, install::Src, install::Rustc),
335 336
        }
    }
337

338 339 340 341 342 343 344 345 346 347 348 349
    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 {
350
            build,
M
Mark Simulacrum 已提交
351
            top_stage: build.config.stage.unwrap_or(2),
352
            kind,
353 354 355 356 357 358
            cache: Cache::new(),
            stack: RefCell::new(Vec::new()),
        };

        let builder = &builder;
        let mut should_run = ShouldRun::new(builder);
359 360
        for desc in Builder::get_step_descriptions(builder.kind) {
            should_run = (desc.should_run)(should_run);
361 362
        }
        let mut help = String::from("Available paths:\n");
363 364 365 366
        for pathset in should_run.paths {
            for path in pathset.set {
                help.push_str(format!("    ./x.py {} {}\n", subcommand, path.display()).as_str());
            }
367 368 369 370
        }
        Some(help)
    }

371
    pub fn run(build: &Build) {
M
Mark Simulacrum 已提交
372
        let (kind, paths) = match build.config.cmd {
373
            Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
374
            Subcommand::Check { ref paths } => (Kind::Check, &paths[..]),
375 376 377 378 379
            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[..]),
O
Oliver Schneider 已提交
380
            Subcommand::Clean { .. } => panic!(),
381 382 383
        };

        let builder = Builder {
384
            build,
M
Mark Simulacrum 已提交
385
            top_stage: build.config.stage.unwrap_or(2),
386
            kind,
387 388 389 390
            cache: Cache::new(),
            stack: RefCell::new(Vec::new()),
        };

391 392 393 394 395 396
        if kind == Kind::Dist {
            assert!(!build.config.test_miri, "Do not distribute with miri enabled.\n\
                The distributed libraries would include all MIR (increasing binary size).
                The distributed MIR would include validation statements.");
        }

397
        StepDescription::run(&Builder::get_step_descriptions(builder.kind), &builder, paths);
398 399 400 401
    }

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

B
Bastien Orivel 已提交
405
    /// Obtain a compiler at a given stage and for a given host. Explicitly does
406 407 408
    /// 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).
409
    pub fn compiler(&self, stage: u32, host: Interned<String>) -> Compiler {
410 411 412
        self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } })
    }

413
    pub fn sysroot(&self, compiler: Compiler) -> Interned<PathBuf> {
414 415 416 417 418
        self.ensure(compile::Sysroot { compiler })
    }

    /// Returns the libdir where the standard library and other artifacts are
    /// found for a compiler's sysroot.
419 420 421 422 423 424 425
    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>,
426
        }
427 428
        impl Step for Libdir {
            type Output = Interned<PathBuf>;
429

430 431
            fn should_run(run: ShouldRun) -> ShouldRun {
                run.never()
432 433
            }

434
            fn run(self, builder: &Builder) -> Interned<PathBuf> {
435
                let compiler = self.compiler;
436 437
                let lib = if compiler.stage >= 1 && builder.build.config.libdir.is_some() {
                    builder.build.config.libdir.clone().unwrap()
438 439 440 441 442
                } else {
                    PathBuf::from("lib")
                };
                let sysroot = builder.sysroot(self.compiler).join(lib)
                    .join("rustlib").join(self.target).join("lib");
443 444
                let _ = fs::remove_dir_all(&sysroot);
                t!(fs::create_dir_all(&sysroot));
445
                INTERNER.intern_path(sysroot)
446 447 448 449 450
            }
        }
        self.ensure(Libdir { compiler, target })
    }

451 452 453 454 455
    pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf {
        self.sysroot_libdir(compiler, compiler.host)
            .with_file_name("codegen-backends")
    }

456 457 458 459 460 461 462 463 464
    /// 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 {
465
            self.sysroot(compiler).join(libdir(&compiler.host))
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
        }
    }

    /// 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);
    }

482 483 484 485 486
    /// Get a path to the compiler specified.
    pub fn rustc(&self, compiler: Compiler) -> PathBuf {
        if compiler.is_snapshot(self) {
            self.initial_rustc.clone()
        } else {
487
            self.sysroot(compiler).join("bin").join(exe("rustc", &compiler.host))
488 489 490
        }
    }

491 492
    pub fn rustdoc(&self, host: Interned<String>) -> PathBuf {
        self.ensure(tool::Rustdoc { host })
M
Mark Simulacrum 已提交
493 494
    }

495
    pub fn rustdoc_cmd(&self, host: Interned<String>) -> Command {
M
Mark Simulacrum 已提交
496
        let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc"));
497
        let compiler = self.compiler(self.top_stage, host);
O
Oliver Schneider 已提交
498 499
        cmd.env("RUSTC_STAGE", compiler.stage.to_string())
           .env("RUSTC_SYSROOT", self.sysroot(compiler))
500
           .env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.build.build))
O
Oliver Schneider 已提交
501 502
           .env("CFG_RELEASE_CHANNEL", &self.build.config.channel)
           .env("RUSTDOC_REAL", self.rustdoc(host))
A
Alex Crichton 已提交
503 504
           .env("RUSTDOC_CRATE_VERSION", self.build.rust_version())
           .env("RUSTC_BOOTSTRAP", "1");
O
Oliver Schneider 已提交
505 506 507
        if let Some(linker) = self.build.linker(host) {
            cmd.env("RUSTC_TARGET_LINKER", linker);
        }
M
Mark Simulacrum 已提交
508
        cmd
509 510
    }

511 512 513 514 515 516 517
    /// 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`.
518
    pub fn cargo(&self,
M
Mark Simulacrum 已提交
519 520
             compiler: Compiler,
             mode: Mode,
521
             target: Interned<String>,
M
Mark Simulacrum 已提交
522 523 524
             cmd: &str) -> Command {
        let mut cargo = Command::new(&self.initial_cargo);
        let out_dir = self.stage_out(compiler, mode);
525 526
        cargo.env("CARGO_TARGET_DIR", out_dir)
             .arg(cmd)
527 528
             .arg("--target")
             .arg(target);
529

530 531 532 533 534 535
        // If we were invoked from `make` then that's already got a jobserver
        // set up for us so no need to tell Cargo about jobs all over again.
        if env::var_os("MAKEFLAGS").is_none() && env::var_os("MFLAGS").is_none() {
             cargo.arg("-j").arg(self.jobs().to_string());
        }

536 537
        // 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 已提交
538
        cargo.env("__CARGO_DEFAULT_LIB_METADATA", &self.config.channel);
539 540

        let stage;
M
Mark Simulacrum 已提交
541
        if compiler.stage == 0 && self.local_rebuild {
542 543 544 545 546 547
            // Assume the local-rebuild rustc already has stage1 features.
            stage = 1;
        } else {
            stage = compiler.stage;
        }

548 549 550 551 552 553 554 555 556 557 558 559
        let mut extra_args = env::var(&format!("RUSTFLAGS_STAGE_{}", stage)).unwrap_or_default();
        if stage != 0 {
            let s = env::var("RUSTFLAGS_STAGE_NOT_0").unwrap_or_default();
            extra_args.push_str(" ");
            extra_args.push_str(&s);
        }

        if !extra_args.is_empty() {
            cargo.env("RUSTFLAGS",
                format!("{} {}", env::var("RUSTFLAGS").unwrap_or_default(), extra_args));
        }

560 561
        // 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 已提交
562
        // how the actual compiler itself is called.
563 564 565
        //
        // These variables are primarily all read by
        // src/bootstrap/bin/{rustc.rs,rustdoc.rs}
M
Mark Simulacrum 已提交
566 567
        cargo.env("RUSTBUILD_NATIVE_DIR", self.native_dir(target))
             .env("RUSTC", self.out.join("bootstrap/debug/rustc"))
568
             .env("RUSTC_REAL", self.rustc(compiler))
569 570
             .env("RUSTC_STAGE", stage.to_string())
             .env("RUSTC_DEBUG_ASSERTIONS",
M
Mark Simulacrum 已提交
571
                  self.config.rust_debug_assertions.to_string())
572 573
             .env("RUSTC_SYSROOT", self.sysroot(compiler))
             .env("RUSTC_LIBDIR", self.rustc_libdir(compiler))
M
Mark Simulacrum 已提交
574 575
             .env("RUSTC_RPATH", self.config.rust_rpath.to_string())
             .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
M
Mark Simulacrum 已提交
576
             .env("RUSTDOC_REAL", if cmd == "doc" || cmd == "test" {
577
                 self.rustdoc(compiler.host)
M
Mark Simulacrum 已提交
578 579 580
             } else {
                 PathBuf::from("/path/to/nowhere/rustdoc/not/required")
             })
581 582
             .env("TEST_MIRI", self.config.test_miri.to_string())
             .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir());
583

O
Oliver Schneider 已提交
584 585 586 587 588 589
        if let Some(host_linker) = self.build.linker(compiler.host) {
            cargo.env("RUSTC_HOST_LINKER", host_linker);
        }
        if let Some(target_linker) = self.build.linker(target) {
            cargo.env("RUSTC_TARGET_LINKER", target_linker);
        }
590
        if cmd != "build" && cmd != "check" {
591 592
            cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.build.build)));
        }
593 594

        if mode != Mode::Tool {
595 596 597 598 599
            // Tools don't get debuginfo right now, e.g. cargo and rls don't
            // get compiled with debuginfo.
            // Adding debuginfo increases their sizes by a factor of 3-4.
            cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string());
            cargo.env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string());
O
Oliver Schneider 已提交
600
            cargo.env("RUSTC_FORCE_UNSTABLE", "1");
601 602 603

            // 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 已提交
604
            // crates). Let's say, for example that rustc itself depends on the
605 606
            // bitflags crate. If an external crate then depends on the
            // bitflags crate as well, we need to make sure they don't
B
Bastien Orivel 已提交
607
            // conflict, even if they pick the same version of bitflags. We'll
608 609 610 611 612 613 614 615 616 617 618 619 620
            // 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");
        }

621 622 623 624
        if let Some(x) = self.crt_static(target) {
            cargo.env("RUSTC_CRT_STATIC", x.to_string());
        }

625 626
        // Enable usage of unstable features
        cargo.env("RUSTC_BOOTSTRAP", "1");
M
Mark Simulacrum 已提交
627
        self.add_rust_test_threads(&mut cargo);
628 629 630

        // 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 已提交
631
        // build script, however, it itself needs a standard library! This
632
        // introduces a bit of a pickle when we're compiling the standard
M
Mark Simulacrum 已提交
633
        // library itself.
634 635
        //
        // To work around this we actually end up using the snapshot compiler
M
Mark Simulacrum 已提交
636
        // (stage0) for compiling build scripts of the standard library itself.
637 638 639 640 641
        // 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.
642 643
        //
        // If LLVM support is disabled we need to use the snapshot compiler to compile
644
        // build scripts, as the new compiler doesn't support executables.
645
        if mode == Mode::Libstd || !self.build.config.llvm_enabled {
M
Mark Simulacrum 已提交
646 647
            cargo.env("RUSTC_SNAPSHOT", &self.initial_rustc)
                 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
648
        } else {
649
            cargo.env("RUSTC_SNAPSHOT", self.rustc(compiler))
650 651 652 653 654 655
                 .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 已提交
656
        if self.config.incremental && compiler.stage == 0 {
657
            cargo.env("CARGO_INCREMENTAL", "1");
658 659
        }

M
Mark Simulacrum 已提交
660
        if let Some(ref on_fail) = self.config.on_fail {
661 662 663
            cargo.env("RUSTC_ON_FAIL", on_fail);
        }

M
Mark Simulacrum 已提交
664
        cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity));
665

O
Oliver Schneider 已提交
666 667 668 669 670
        // Throughout the build Cargo can execute a number of build scripts
        // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
        // obtained previously to those build scripts.
        // Build scripts use either the `cc` crate or `configure/make` so we pass
        // the options through environment variables that are fetched and understood by both.
671 672 673
        //
        // FIXME: the guard against msvc shouldn't need to be here
        if !target.contains("msvc") {
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
            let ccache = self.config.ccache.as_ref();
            let ccacheify = |s: &Path| {
                let ccache = match ccache {
                    Some(ref s) => s,
                    None => return s.display().to_string(),
                };
                // FIXME: the cc-rs crate only recognizes the literal strings
                // `ccache` and `sccache` when doing caching compilations, so we
                // mirror that here. It should probably be fixed upstream to
                // accept a new env var or otherwise work with custom ccache
                // vars.
                match &ccache[..] {
                    "ccache" | "sccache" => format!("{} {}", ccache, s.display()),
                    _ => s.display().to_string(),
                }
            };
            let cc = ccacheify(&self.cc(target));
            cargo.env(format!("CC_{}", target), &cc)
                 .env("CC", &cc);
O
Oliver Schneider 已提交
693 694 695 696 697 698 699 700 701 702 703 704

            let cflags = self.cflags(target).join(" ");
            cargo.env(format!("CFLAGS_{}", target), cflags.clone())
                 .env("CFLAGS", cflags.clone());

            if let Some(ar) = self.ar(target) {
                let ranlib = format!("{} s", ar.display());
                cargo.env(format!("AR_{}", target), ar)
                     .env("AR", ar)
                     .env(format!("RANLIB_{}", target), ranlib.clone())
                     .env("RANLIB", ranlib);
            }
705

M
Mark Simulacrum 已提交
706
            if let Ok(cxx) = self.cxx(target) {
707 708 709
                let cxx = ccacheify(&cxx);
                cargo.env(format!("CXX_{}", target), &cxx)
                     .env("CXX", &cxx)
O
Oliver Schneider 已提交
710 711
                     .env(format!("CXXFLAGS_{}", target), cflags.clone())
                     .env("CXXFLAGS", cflags);
712 713 714
            }
        }

M
Mark Simulacrum 已提交
715
        if mode == Mode::Libstd && self.config.extended && compiler.is_final_stage(self) {
716 717 718
            cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
        }

O
Oliver Schneider 已提交
719 720 721
        // For `cargo doc` invocations, make rustdoc print the Rust version into the docs
        cargo.env("RUSTDOC_CRATE_VERSION", self.build.rust_version());

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

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

730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
        // This one's a bit tricky. As of the time of this writing the compiler
        // links to the `winapi` crate on crates.io. This crate provides raw
        // bindings to Windows system functions, sort of like libc does for
        // Unix. This crate also, however, provides "import libraries" for the
        // MinGW targets. There's an import library per dll in the windows
        // distribution which is what's linked to. These custom import libraries
        // are used because the winapi crate can reference Windows functions not
        // present in the MinGW import libraries.
        //
        // For example MinGW may ship libdbghelp.a, but it may not have
        // references to all the functions in the dbghelp dll. Instead the
        // custom import library for dbghelp in the winapi crates has all this
        // information.
        //
        // Unfortunately for us though the import libraries are linked by
        // default via `-ldylib=winapi_foo`. That is, they're linked with the
        // `dylib` type with a `winapi_` prefix (so the winapi ones don't
        // conflict with the system MinGW ones). This consequently means that
        // the binaries we ship of things like rustc_trans (aka the rustc_trans
        // DLL) when linked against *again*, for example with procedural macros
        // or plugins, will trigger the propagation logic of `-ldylib`, passing
        // `-lwinapi_foo` to the linker again. This isn't actually available in
        // our distribution, however, so the link fails.
        //
        // To solve this problem we tell winapi to not use its bundled import
        // libraries. This means that it will link to the system MinGW import
        // libraries by default, and the `-ldylib=foo` directives will still get
        // passed to the final linker, but they'll look like `-lfoo` which can
        // be resolved because MinGW has the import library. The downside is we
        // don't get newer functions from Windows, but we don't use any of them
        // anyway.
        cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1");

O
Oliver Schneider 已提交
763
        if self.is_very_verbose() {
764 765
            cargo.arg("-v");
        }
766 767 768 769 770 771 772

        // This must be kept before the thinlto check, as we set codegen units
        // to 1 forcibly there.
        if let Some(n) = self.config.rust_codegen_units {
            cargo.env("RUSTC_CODEGEN_UNITS", n.to_string());
        }

O
Oliver Schneider 已提交
773 774 775 776 777 778 779
        if self.config.rust_optimize {
            // FIXME: cargo bench does not accept `--release`
            if cmd != "bench" {
                cargo.arg("--release");
            }

            if self.config.rust_codegen_units.is_none() &&
780 781
               self.build.is_rust_llvm(compiler.host) &&
               self.config.rust_thinlto {
O
Oliver Schneider 已提交
782
                cargo.env("RUSTC_THINLTO", "1");
783 784 785 786 787
            } else if self.config.rust_codegen_units.is_none() {
                // Generally, if ThinLTO has been disabled for some reason, we
                // want to set the codegen units to 1. However, we shouldn't do
                // this if the option was specifically set by the user.
                cargo.env("RUSTC_CODEGEN_UNITS", "1");
O
Oliver Schneider 已提交
788
            }
789
        }
790

M
Mark Simulacrum 已提交
791
        if self.config.locked_deps {
792 793
            cargo.arg("--locked");
        }
M
Mark Simulacrum 已提交
794
        if self.config.vendor || self.is_sudo {
795 796 797
            cargo.arg("--frozen");
        }

M
Mark Simulacrum 已提交
798
        self.ci_env.force_coloring_in_ci(&mut cargo);
799 800 801 802

        cargo
    }

803 804 805
    /// 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.
806
    pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
807 808
        {
            let mut stack = self.stack.borrow_mut();
809 810 811 812
            for stack_step in stack.iter() {
                // should skip
                if stack_step.downcast_ref::<S>().map_or(true, |stack_step| *stack_step != step) {
                    continue;
813
                }
814
                let mut out = String::new();
815
                out += &format!("\n\nCycle in build detected when adding {:?}\n", step);
816 817 818 819 820
                for el in stack.iter().rev() {
                    out += &format!("\t{:?}\n", el);
                }
                panic!(out);
            }
821 822
            if let Some(out) = self.cache.get(&step) {
                self.build.verbose(&format!("{}c {:?}", "  ".repeat(stack.len()), step));
823 824 825

                return out;
            }
826
            self.build.verbose(&format!("{}> {:?}", "  ".repeat(stack.len()), step));
827
            stack.push(Box::new(step.clone()));
828
        }
829
        let out = step.clone().run(self);
830 831
        {
            let mut stack = self.stack.borrow_mut();
832 833
            let cur_step = stack.pop().expect("step stack empty");
            assert_eq!(cur_step.downcast_ref(), Some(&step));
834
        }
835 836 837
        self.build.verbose(&format!("{}< {:?}", "  ".repeat(self.stack.borrow().len()), step));
        self.cache.put(step, out.clone());
        out
838 839
    }
}