builder.rs 49.1 KB
Newer Older
1
use std::any::Any;
2
use std::cell::{Cell, RefCell};
3
use std::collections::BTreeSet;
S
Santiago Pastorino 已提交
4
use std::collections::HashMap;
5
use std::env;
6
use std::fmt::Debug;
7
use std::fs;
8
use std::hash::Hash;
9
use std::ops::Deref;
10 11
use std::path::{Path, PathBuf};
use std::process::Command;
S
Santiago Pastorino 已提交
12
use std::time::{Duration, Instant};
13

14 15
use build_helper::t;

L
ljedrz 已提交
16 17 18 19 20 21 22 23 24 25
use crate::cache::{Cache, Interned, INTERNER};
use crate::check;
use crate::compile;
use crate::dist;
use crate::doc;
use crate::flags::Subcommand;
use crate::install;
use crate::native;
use crate::test;
use crate::tool;
26
use crate::util::{self, add_lib_path, exe, libdir};
L
ljedrz 已提交
27 28 29
use crate::{Build, DocTests, Mode, GitRepo};

pub use crate::Compiler;
30

31
use petgraph::graph::NodeIndex;
S
Santiago Pastorino 已提交
32
use petgraph::Graph;
33

34 35 36 37 38
pub struct Builder<'a> {
    pub build: &'a Build,
    pub top_stage: u32,
    pub kind: Kind,
    cache: Cache,
39
    stack: RefCell<Vec<Box<dyn Any>>>,
40
    time_spent_on_dependencies: Cell<Duration>,
41
    pub paths: Vec<PathBuf>,
42 43 44
    graph_nodes: RefCell<HashMap<String, NodeIndex>>,
    graph: RefCell<Graph<String, bool>>,
    parent: Cell<Option<NodeIndex>>,
45 46 47 48 49 50 51 52 53 54
}

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

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

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

60 61
    const DEFAULT: bool = false;

62
    /// If true, then this rule should be skipped if --target was specified, but --host was not
63 64
    const ONLY_HOSTS: bool = false;

A
Alexander Regueiro 已提交
65
    /// Primary function to execute this rule. Can call `builder.ensure()`
66
    /// with other steps to run those.
T
Taiki Endo 已提交
67
    fn run(self, builder: &Builder<'_>) -> Self::Output;
68

69 70
    /// 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
A
Alexander Regueiro 已提交
71
    /// when we are not passed any paths; in that case, `make_run` is called
72
    /// directly.
T
Taiki Endo 已提交
73
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_>;
74

A
Alexander Regueiro 已提交
75
    /// Builds up a "root" rule, either as a default rule or from a path passed
76 77 78 79 80
    /// 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`.
T
Taiki Endo 已提交
81
    fn make_run(_run: RunConfig<'_>) {
82 83 84 85 86 87
        // 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!()
    }
88 89
}

90 91 92 93
pub struct RunConfig<'a> {
    pub builder: &'a Builder<'a>,
    pub host: Interned<String>,
    pub target: Interned<String>,
94
    pub path: PathBuf,
95 96
}

97 98 99
struct StepDescription {
    default: bool,
    only_hosts: bool,
T
Taiki Endo 已提交
100 101
    should_run: fn(ShouldRun<'_>) -> ShouldRun<'_>,
    make_run: fn(RunConfig<'_>),
102 103 104 105
    name: &'static str,
}

#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
106
pub enum PathSet {
S
Santiago Pastorino 已提交
107 108
    Set(BTreeSet<PathBuf>),
    Suite(PathBuf),
109 110 111
}

impl PathSet {
112
    fn empty() -> PathSet {
113
        PathSet::Set(BTreeSet::new())
114 115
    }

116 117 118
    fn one<P: Into<PathBuf>>(path: P) -> PathSet {
        let mut set = BTreeSet::new();
        set.insert(path.into());
119
        PathSet::Set(set)
120 121 122
    }

    fn has(&self, needle: &Path) -> bool {
123 124
        match self {
            PathSet::Set(set) => set.iter().any(|p| p.ends_with(needle)),
125
            PathSet::Suite(suite) => suite.ends_with(needle),
126
        }
127 128
    }

T
Taiki Endo 已提交
129
    fn path(&self, builder: &Builder<'_>) -> PathBuf {
130
        match self {
S
Santiago Pastorino 已提交
131 132 133 134 135 136
            PathSet::Set(set) => set
                .iter()
                .next()
                .unwrap_or(&builder.build.src)
                .to_path_buf(),
            PathSet::Suite(path) => PathBuf::from(path),
137
        }
138
    }
139 140 141 142 143 144 145 146 147
}

impl StepDescription {
    fn from<S: Step>() -> StepDescription {
        StepDescription {
            default: S::DEFAULT,
            only_hosts: S::ONLY_HOSTS,
            should_run: S::should_run,
            make_run: S::make_run,
M
Mark Rousskov 已提交
148
            name: std::any::type_name::<S>(),
149 150 151
        }
    }

T
Taiki Endo 已提交
152
    fn maybe_run(&self, builder: &Builder<'_>, pathset: &PathSet) {
153 154 155 156
        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() {
S
Santiago Pastorino 已提交
157 158 159 160
            eprintln!(
                "{:?} not skipped for {:?} -- not in {:?}",
                pathset, self.name, builder.config.exclude
            );
161
        }
162
        let hosts = &builder.hosts;
163

M
Mark Simulacrum 已提交
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
168
            } else {
169
                &builder.hosts
170 171
            }
        } else {
172
            &builder.targets
173 174 175 176
        };

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

T
Taiki Endo 已提交
188
    fn run(v: &[StepDescription], builder: &Builder<'_>, paths: &[PathBuf]) {
S
Santiago Pastorino 已提交
189 190 191 192
        let should_runs = v
            .iter()
            .map(|desc| (desc.should_run)(ShouldRun::new(builder)))
            .collect::<Vec<_>>();
193 194 195

        // sanity checks on rules
        for (desc, should_run) in v.iter().zip(&should_runs) {
S
Santiago Pastorino 已提交
196 197 198 199 200
            assert!(
                !should_run.paths.is_empty(),
                "{:?} should have at least one pathset",
                desc.name
            );
201 202
        }

203
        if paths.is_empty() {
204 205
            for (desc, should_run) in v.iter().zip(should_runs) {
                if desc.default && should_run.is_really_default {
206 207 208
                    for pathset in &should_run.paths {
                        desc.maybe_run(builder, pathset);
                    }
209 210 211 212
                }
            }
        } else {
            for path in paths {
213 214 215 216 217 218
                // strip CurDir prefix if present
                let path = match path.strip_prefix(".") {
                    Ok(p) => p,
                    Err(_) => path,
                };

219
                let mut attempted_run = false;
220
                for (desc, should_run) in v.iter().zip(&should_runs) {
221 222 223 224
                    if let Some(suite) = should_run.is_suite_path(path) {
                        attempted_run = true;
                        desc.maybe_run(builder, suite);
                    } else if let Some(pathset) = should_run.pathset_for_path(path) {
225
                        attempted_run = true;
226
                        desc.maybe_run(builder, pathset);
227 228 229 230
                    }
                }

                if !attempted_run {
231
                    panic!("Error: no rules matched {}.", path.display());
232 233 234 235 236 237
                }
            }
        }
    }
}

238 239
#[derive(Clone)]
pub struct ShouldRun<'a> {
240
    pub builder: &'a Builder<'a>,
241
    // use a BTreeSet to maintain sort order
242
    paths: BTreeSet<PathSet>,
243 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,
247 248 249
}

impl<'a> ShouldRun<'a> {
T
Taiki Endo 已提交
250
    fn new(builder: &'a Builder<'_>) -> ShouldRun<'a> {
251
        ShouldRun {
252
            builder,
253
            paths: BTreeSet::new(),
254
            is_really_default: true, // by default no additional conditions
255 256 257
        }
    }

258 259 260 261 262
    pub fn default_condition(mut self, cond: bool) -> Self {
        self.is_really_default = cond;
        self
    }

263 264 265 266 267 268 269 270
    // 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));
        }
271
        self.paths.insert(PathSet::Set(set));
272 273 274
        self
    }

275
    pub fn krate(mut self, name: &str) -> Self {
276 277
        for krate in self.builder.in_tree_crates(name) {
            self.paths.insert(PathSet::one(&krate.path));
278 279 280 281
        }
        self
    }

282 283 284 285 286 287 288
    // 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 {
S
Santiago Pastorino 已提交
289 290
        self.paths
            .insert(PathSet::Set(paths.iter().map(PathBuf::from).collect()));
291 292 293 294
        self
    }

    pub fn is_suite_path(&self, path: &Path) -> Option<&PathSet> {
S
Santiago Pastorino 已提交
295 296 297
        self.paths.iter().find(|pathset| match pathset {
            PathSet::Suite(p) => path.starts_with(p),
            PathSet::Set(_) => false,
298 299 300 301 302
        })
    }

    pub fn suite_path(mut self, suite: &str) -> Self {
        self.paths.insert(PathSet::Suite(PathBuf::from(suite)));
303 304 305 306
        self
    }

    // allows being more explicit about why should_run in Step returns the value passed to it
307 308
    pub fn never(mut self) -> ShouldRun<'a> {
        self.paths.insert(PathSet::empty());
309 310 311
        self
    }

312 313
    fn pathset_for_path(&self, path: &Path) -> Option<&PathSet> {
        self.paths.iter().find(|pathset| pathset.has(path))
314 315 316
    }
}

317 318 319
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Kind {
    Build,
320
    Check,
L
ljedrz 已提交
321 322
    Clippy,
    Fix,
323 324 325 326 327 328 329
    Test,
    Bench,
    Dist,
    Doc,
    Install,
}

330 331 332
impl<'a> Builder<'a> {
    fn get_step_descriptions(kind: Kind) -> Vec<StepDescription> {
        macro_rules! describe {
T
Taiki Endo 已提交
333
            ($($rule:ty),+ $(,)?) => {{
334 335
                vec![$(StepDescription::from::<$rule>()),+]
            }};
336
        }
337
        match kind {
S
Santiago Pastorino 已提交
338 339 340
            Kind::Build => describe!(
                compile::Std,
                compile::Rustc,
341
                compile::CodegenBackend,
S
Santiago Pastorino 已提交
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
                compile::StartupObjects,
                tool::BuildManifest,
                tool::Rustbook,
                tool::ErrorIndex,
                tool::UnstableBookGen,
                tool::Tidy,
                tool::Linkchecker,
                tool::CargoTest,
                tool::Compiletest,
                tool::RemoteTestServer,
                tool::RemoteTestClient,
                tool::RustInstaller,
                tool::Cargo,
                tool::Rls,
                tool::Rustdoc,
                tool::Clippy,
                native::Llvm,
                tool::Rustfmt,
                tool::Miri,
                native::Lld
            ),
L
ljedrz 已提交
363
            Kind::Check | Kind::Clippy | Kind::Fix => describe!(
S
Santiago Pastorino 已提交
364 365 366 367 368 369 370 371 372 373 374 375 376 377
                check::Std,
                check::Rustc,
                check::CodegenBackend,
                check::Rustdoc
            ),
            Kind::Test => describe!(
                test::Tidy,
                test::Ui,
                test::CompileFail,
                test::RunFail,
                test::RunPassValgrind,
                test::MirOpt,
                test::Codegen,
                test::CodegenUnits,
378
                test::Assembly,
S
Santiago Pastorino 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
                test::Incremental,
                test::Debuginfo,
                test::UiFullDeps,
                test::Rustdoc,
                test::Pretty,
                test::RunFailPretty,
                test::RunPassValgrindPretty,
                test::Crate,
                test::CrateLibrustc,
                test::CrateRustdoc,
                test::Linkcheck,
                test::Cargotest,
                test::Cargo,
                test::Rls,
                test::ErrorIndex,
                test::Distcheck,
395
                test::RunMakeFullDeps,
S
Santiago Pastorino 已提交
396 397 398 399 400 401 402
                test::Nomicon,
                test::Reference,
                test::RustdocBook,
                test::RustByExample,
                test::TheBook,
                test::UnstableBook,
                test::RustcBook,
403
                test::RustcGuide,
404
                test::EmbeddedBook,
E
Eric Huss 已提交
405
                test::EditionGuide,
S
Santiago Pastorino 已提交
406 407 408
                test::Rustfmt,
                test::Miri,
                test::Clippy,
409
                test::CompiletestTest,
G
Guillaume Gomez 已提交
410
                test::RustdocJSStd,
G
Guillaume Gomez 已提交
411
                test::RustdocJSNotStd,
S
Santiago Pastorino 已提交
412
                test::RustdocTheme,
J
John Kåre Alsaker 已提交
413
                test::RustdocUi,
414 415
                // Run bootstrap close to the end as it's unlikely to fail
                test::Bootstrap,
416
                // Run run-make last, since these won't pass without make on Windows
S
Santiago Pastorino 已提交
417 418
                test::RunMake,
            ),
419
            Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
S
Santiago Pastorino 已提交
420 421 422 423 424 425 426 427 428 429 430 431 432 433
            Kind::Doc => describe!(
                doc::UnstableBook,
                doc::UnstableBookGen,
                doc::TheBook,
                doc::Standalone,
                doc::Std,
                doc::Rustc,
                doc::Rustdoc,
                doc::ErrorIndex,
                doc::Nomicon,
                doc::Reference,
                doc::RustdocBook,
                doc::RustByExample,
                doc::RustcBook,
S
Steve Klabnik 已提交
434
                doc::CargoBook,
J
James Munns 已提交
435
                doc::EmbeddedBook,
S
Steve Klabnik 已提交
436
                doc::EditionGuide,
S
Santiago Pastorino 已提交
437 438 439 440 441 442 443 444 445 446 447 448 449 450
            ),
            Kind::Dist => describe!(
                dist::Docs,
                dist::RustcDocs,
                dist::Mingw,
                dist::Rustc,
                dist::DebuggerScripts,
                dist::Std,
                dist::Analysis,
                dist::Src,
                dist::PlainSourceTarball,
                dist::Cargo,
                dist::Rls,
                dist::Rustfmt,
451
                dist::Clippy,
452
                dist::Miri,
453
                dist::LlvmTools,
T
Tom Tromey 已提交
454
                dist::Lldb,
S
Santiago Pastorino 已提交
455 456 457 458 459 460 461 462 463
                dist::Extended,
                dist::HashSign
            ),
            Kind::Install => describe!(
                install::Docs,
                install::Std,
                install::Cargo,
                install::Rls,
                install::Rustfmt,
464
                install::Clippy,
465
                install::Miri,
S
Santiago Pastorino 已提交
466 467 468 469
                install::Analysis,
                install::Src,
                install::Rustc
            ),
470 471
        }
    }
472

473 474 475 476 477 478 479 480 481 482 483 484
    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 {
485
            build,
M
Mark Simulacrum 已提交
486
            top_stage: build.config.stage.unwrap_or(2),
487
            kind,
488 489
            cache: Cache::new(),
            stack: RefCell::new(Vec::new()),
490
            time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
491
            paths: vec![],
492 493 494
            graph_nodes: RefCell::new(HashMap::new()),
            graph: RefCell::new(Graph::new()),
            parent: Cell::new(None),
495 496 497 498
        };

        let builder = &builder;
        let mut should_run = ShouldRun::new(builder);
499 500
        for desc in Builder::get_step_descriptions(builder.kind) {
            should_run = (desc.should_run)(should_run);
501 502
        }
        let mut help = String::from("Available paths:\n");
503
        for pathset in should_run.paths {
S
Santiago Pastorino 已提交
504 505 506 507 508 509
            if let PathSet::Set(set) = pathset {
                set.iter().for_each(|path| {
                    help.push_str(
                        format!("    ./x.py {} {}\n", subcommand, path.display()).as_str(),
                    )
                })
510
            }
511 512 513 514
        }
        Some(help)
    }

T
Taiki Endo 已提交
515
    pub fn new(build: &Build) -> Builder<'_> {
M
Mark Simulacrum 已提交
516
        let (kind, paths) = match build.config.cmd {
517
            Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
518
            Subcommand::Check { ref paths } => (Kind::Check, &paths[..]),
L
ljedrz 已提交
519 520
            Subcommand::Clippy { ref paths } => (Kind::Clippy, &paths[..]),
            Subcommand::Fix { ref paths } => (Kind::Fix, &paths[..]),
521 522 523 524 525
            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 已提交
526
            Subcommand::Clean { .. } => panic!(),
527 528 529
        };

        let builder = Builder {
530
            build,
M
Mark Simulacrum 已提交
531
            top_stage: build.config.stage.unwrap_or(2),
532
            kind,
533 534
            cache: Cache::new(),
            stack: RefCell::new(Vec::new()),
535
            time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
536
            paths: paths.to_owned(),
537 538 539
            graph_nodes: RefCell::new(HashMap::new()),
            graph: RefCell::new(Graph::new()),
            parent: Cell::new(None),
540 541
        };

542 543 544
        builder
    }

545
    pub fn execute_cli(&self) -> Graph<String, bool> {
M
Mark Simulacrum 已提交
546
        self.run_step_descriptions(&Builder::get_step_descriptions(self.kind), &self.paths);
547
        self.graph.borrow().clone()
548 549 550 551
    }

    pub fn default_doc(&self, paths: Option<&[PathBuf]>) {
        let paths = paths.unwrap_or(&[]);
M
Mark Simulacrum 已提交
552 553 554 555 556
        self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths);
    }

    fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) {
        StepDescription::run(v, self, paths);
557 558
    }

B
Bastien Orivel 已提交
559
    /// Obtain a compiler at a given stage and for a given host. Explicitly does
560 561 562
    /// 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).
563
    pub fn compiler(&self, stage: u32, host: Interned<String>) -> Compiler {
S
Santiago Pastorino 已提交
564 565 566
        self.ensure(compile::Assemble {
            target_compiler: Compiler { stage, host },
        })
567 568
    }

569 570 571 572 573 574 575 576 577 578 579
    /// Similar to `compiler`, except handles the full-bootstrap option to
    /// silently use the stage1 compiler instead of a stage2 compiler if one is
    /// requested.
    ///
    /// Note that this does *not* have the side effect of creating
    /// `compiler(stage, host)`, unlike `compiler` above which does have such
    /// a side effect. The returned compiler here can only be used to compile
    /// new artifacts, it can't be used to rely on the presence of a particular
    /// sysroot.
    ///
    /// See `force_use_stage1` for documentation on what each argument is.
A
Alex Crichton 已提交
580 581 582 583 584 585
    pub fn compiler_for(
        &self,
        stage: u32,
        host: Interned<String>,
        target: Interned<String>,
    ) -> Compiler {
586 587 588 589 590 591 592
        if self.build.force_use_stage1(Compiler { stage, host }, target) {
            self.compiler(1, self.config.build)
        } else {
            self.compiler(stage, host)
        }
    }

593
    pub fn sysroot(&self, compiler: Compiler) -> Interned<PathBuf> {
594 595 596 597 598
        self.ensure(compile::Sysroot { compiler })
    }

    /// Returns the libdir where the standard library and other artifacts are
    /// found for a compiler's sysroot.
599
    pub fn sysroot_libdir(
S
Santiago Pastorino 已提交
600 601 602
        &self,
        compiler: Compiler,
        target: Interned<String>,
603 604 605 606 607
    ) -> Interned<PathBuf> {
        #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        struct Libdir {
            compiler: Compiler,
            target: Interned<String>,
608
        }
609 610
        impl Step for Libdir {
            type Output = Interned<PathBuf>;
611

T
Taiki Endo 已提交
612
            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
613
                run.never()
614 615
            }

T
Taiki Endo 已提交
616
            fn run(self, builder: &Builder<'_>) -> Interned<PathBuf> {
O
O01eg 已提交
617
                let lib = builder.sysroot_libdir_relative(self.compiler);
S
Santiago Pastorino 已提交
618 619 620 621 622 623
                let sysroot = builder
                    .sysroot(self.compiler)
                    .join(lib)
                    .join("rustlib")
                    .join(self.target)
                    .join("lib");
624 625
                let _ = fs::remove_dir_all(&sysroot);
                t!(fs::create_dir_all(&sysroot));
626
                INTERNER.intern_path(sysroot)
627 628 629 630 631
            }
        }
        self.ensure(Libdir { compiler, target })
    }

632 633
    pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf {
        self.sysroot_libdir(compiler, compiler.host)
634
            .with_file_name(self.config.rust_codegen_backends_dir.clone())
635 636
    }

637 638 639 640 641 642 643
    /// 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) {
644
            self.rustc_snapshot_libdir()
645
        } else {
O
O01eg 已提交
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
            match self.config.libdir_relative() {
                Some(relative_libdir) if compiler.stage >= 1
                    => self.sysroot(compiler).join(relative_libdir),
                _ => self.sysroot(compiler).join(libdir(&compiler.host))
            }
        }
    }

    /// Returns the compiler's relative libdir where it stores the dynamic libraries that
    /// it itself links against.
    ///
    /// For example this returns `lib` on Unix and `bin` on
    /// Windows.
    pub fn libdir_relative(&self, compiler: Compiler) -> &Path {
        if compiler.is_snapshot(self) {
            libdir(&self.config.build).as_ref()
        } else {
            match self.config.libdir_relative() {
                Some(relative_libdir) if compiler.stage >= 1
                    => relative_libdir,
                _ => libdir(&compiler.host).as_ref()
            }
668 669 670
        }
    }

O
O01eg 已提交
671 672 673 674 675 676 677 678 679 680 681 682
    /// Returns the compiler's relative libdir where the standard library and other artifacts are
    /// found for a compiler's sysroot.
    ///
    /// For example this returns `lib` on Unix and Windows.
    pub fn sysroot_libdir_relative(&self, compiler: Compiler) -> &Path {
        match self.config.libdir_relative() {
            Some(relative_libdir) if compiler.stage >= 1
                => relative_libdir,
            _ => Path::new("lib")
        }
    }

683 684 685 686 687 688 689
    /// 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) {
S
Santiago Pastorino 已提交
690
            return;
691 692 693 694 695
        }

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

A
Alexander Regueiro 已提交
696
    /// Gets a path to the compiler specified.
697 698 699 700
    pub fn rustc(&self, compiler: Compiler) -> PathBuf {
        if compiler.is_snapshot(self) {
            self.initial_rustc.clone()
        } else {
S
Santiago Pastorino 已提交
701 702 703
            self.sysroot(compiler)
                .join("bin")
                .join(exe("rustc", &compiler.host))
704 705 706
        }
    }

A
Alexander Regueiro 已提交
707
    /// Gets the paths to all of the compiler's codegen backends.
708 709 710 711 712 713 714 715
    fn codegen_backends(&self, compiler: Compiler) -> impl Iterator<Item = PathBuf> {
        fs::read_dir(self.sysroot_codegen_backends(compiler))
            .into_iter()
            .flatten()
            .filter_map(Result::ok)
            .map(|entry| entry.path())
    }

M
Mark Rousskov 已提交
716 717
    pub fn rustdoc(&self, compiler: Compiler) -> PathBuf {
        self.ensure(tool::Rustdoc { compiler })
M
Mark Simulacrum 已提交
718 719
    }

M
Mark Rousskov 已提交
720
    pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
M
Mark Simulacrum 已提交
721
        let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc"));
O
Oliver Schneider 已提交
722
        cmd.env("RUSTC_STAGE", compiler.stage.to_string())
S
Santiago Pastorino 已提交
723
            .env("RUSTC_SYSROOT", self.sysroot(compiler))
M
Mark Rousskov 已提交
724 725 726
            // Note that this is *not* the sysroot_libdir because rustdoc must be linked
            // equivalently to rustc.
            .env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler))
S
Santiago Pastorino 已提交
727
            .env("CFG_RELEASE_CHANNEL", &self.config.channel)
M
Mark Rousskov 已提交
728
            .env("RUSTDOC_REAL", self.rustdoc(compiler))
S
Santiago Pastorino 已提交
729 730
            .env("RUSTDOC_CRATE_VERSION", self.rust_version())
            .env("RUSTC_BOOTSTRAP", "1");
731 732 733 734 735

        // Remove make-related flags that can cause jobserver problems.
        cmd.env_remove("MAKEFLAGS");
        cmd.env_remove("MFLAGS");

M
Mark Rousskov 已提交
736
        if let Some(linker) = self.linker(compiler.host) {
O
Oliver Schneider 已提交
737 738
            cmd.env("RUSTC_TARGET_LINKER", linker);
        }
M
Mark Simulacrum 已提交
739
        cmd
740 741
    }

742 743 744 745 746 747 748
    /// 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`.
S
Santiago Pastorino 已提交
749 750 751 752 753 754 755
    pub fn cargo(
        &self,
        compiler: Compiler,
        mode: Mode,
        target: Interned<String>,
        cmd: &str,
    ) -> Command {
M
Mark Simulacrum 已提交
756 757
        let mut cargo = Command::new(&self.initial_cargo);
        let out_dir = self.stage_out(compiler, mode);
758

759 760 761 762 763
        // Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
        // so we need to explicitly clear out if they've been updated.
        for backend in self.codegen_backends(compiler) {
            self.clear_if_dirty(&out_dir, &backend);
        }
764

765
        if cmd == "doc" || cmd == "rustdoc" {
766
            let my_out = match mode {
767
                // This is the intended out directory for compiler documentation.
768 769 770
                Mode::Rustc | Mode::ToolRustc | Mode::Codegen => self.compiler_doc_out(target),
                _ => self.crate_doc_out(target),
            };
M
Mark Rousskov 已提交
771
            let rustdoc = self.rustdoc(compiler);
772 773 774
            self.clear_if_dirty(&my_out, &rustdoc);
        }

S
Santiago Pastorino 已提交
775 776
        cargo
            .env("CARGO_TARGET_DIR", out_dir)
777 778
            .arg(cmd);

779 780 781 782 783 784 785
        // See comment in librustc_llvm/build.rs for why this is necessary, largely llvm-config
        // needs to not accidentally link to libLLVM in stage0/lib.
        cargo.env("REAL_LIBRARY_PATH_VAR", &util::dylib_path_var());
        if let Some(e) = env::var_os(util::dylib_path_var()) {
            cargo.env("REAL_LIBRARY_PATH", e);
        }

786 787 788 789 790 791
        if cmd != "install" {
            cargo.arg("--target")
                 .arg(target);
        } else {
            assert_eq!(target, compiler.host);
        }
792

L
ljedrz 已提交
793 794 795
        // Set a flag for `check`/`clippy`/`fix`, so that certain build
        // scripts can do less work (e.g. not building/requiring LLVM).
        if cmd == "check" || cmd == "clippy" || cmd == "fix" {
V
varkor 已提交
796 797 798
            cargo.env("RUST_CHECK", "1");
        }

799 800 801 802 803 804 805 806
        let stage;
        if compiler.stage == 0 && self.local_rebuild {
            // Assume the local-rebuild rustc already has stage1 features.
            stage = 1;
        } else {
            stage = compiler.stage;
        }

807
        let mut rustflags = Rustflags::new(&target, &mut cargo);
808 809 810 811 812 813
        if stage != 0 {
            rustflags.env("RUSTFLAGS_NOT_BOOTSTRAP");
        } else {
            rustflags.env("RUSTFLAGS_BOOTSTRAP");
        }

J
John Kåre Alsaker 已提交
814
        match mode {
815
            Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {},
J
John Kåre Alsaker 已提交
816 817 818 819
            Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {
                // Build proc macros both for the host and the target
                if target != compiler.host && cmd != "check" {
                    cargo.arg("-Zdual-proc-macros");
820
                    rustflags.arg("-Zdual-proc-macros");
J
John Kåre Alsaker 已提交
821 822 823 824
                }
            },
        }

825 826 827 828 829 830 831 832 833 834 835 836 837
        // This tells Cargo (and in turn, rustc) to output more complete
        // dependency information.  Most importantly for rustbuild, this
        // includes sysroot artifacts, like libstd, which means that we don't
        // need to track those in rustbuild (an error prone process!). This
        // feature is currently unstable as there may be some bugs and such, but
        // it represents a big improvement in rustbuild's reliability on
        // rebuilds, so we're using it here.
        //
        // For some additional context, see #63470 (the PR originally adding
        // this), as well as #63012 which is the tracking issue for this
        // feature on the rustc side.
        cargo.arg("-Zbinary-dep-depinfo");

838 839 840 841
        cargo.arg("-j").arg(self.jobs().to_string());
        // Remove make-related flags to ensure Cargo can correctly set things up
        cargo.env_remove("MAKEFLAGS");
        cargo.env_remove("MFLAGS");
842

843 844
        // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
        // Force cargo to output binaries with disambiguating hashes in the name
845 846
        let mut metadata = if compiler.stage == 0 {
            // Treat stage0 like a special channel, whether it's a normal prior-
847 848
            // release rustc or a local rebuild with the same version, so we
            // never mix these libraries by accident.
849
            "bootstrap".to_string()
850
        } else {
851
            self.config.channel.to_string()
852
        };
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867
        // We want to make sure that none of the dependencies between
        // std/test/rustc unify with one another. This is done for weird linkage
        // reasons but the gist of the problem is that if librustc, libtest, and
        // libstd all depend on libc from crates.io (which they actually do) we
        // want to make sure they all get distinct versions. Things get really
        // weird if we try to unify all these dependencies right now, namely
        // around how many times the library is linked in dynamic libraries and
        // such. If rustc were a static executable or if we didn't ship dylibs
        // this wouldn't be a problem, but we do, so it is. This is in general
        // just here to make sure things build right. If you can remove this and
        // things still build right, please do!
        match mode {
            Mode::Std => metadata.push_str("std"),
            _ => {},
        }
868
        cargo.env("__CARGO_DEFAULT_LIB_METADATA", &metadata);
869

L
ljedrz 已提交
870
        if cmd == "clippy" {
871
            rustflags.arg("-Zforce-unstable-if-unmarked");
872 873
        }

874 875
        rustflags.arg("-Zexternal-macro-backtrace");

K
kennytm 已提交
876
        let want_rustdoc = self.doc_tests != DocTests::No;
K
kennytm 已提交
877

878 879 880 881 882 883
        // We synthetically interpret a stage0 compiler used to build tools as a
        // "raw" compiler in that it's the exact snapshot we download. Normally
        // the stage0 build means it uses libraries build by the stage0
        // compiler, but for tools we just use the precompiled libraries that
        // we've downloaded
        let use_snapshot = mode == Mode::ToolBootstrap;
884
        assert!(!use_snapshot || stage == 0 || self.local_rebuild);
885 886 887 888 889 890 891

        let maybe_sysroot = self.sysroot(compiler);
        let sysroot = if use_snapshot {
            self.rustc_snapshot_sysroot()
        } else {
            &maybe_sysroot
        };
M
Mark Rousskov 已提交
892
        let libdir = self.rustc_libdir(compiler);
893

894 895
        // 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 已提交
896
        // how the actual compiler itself is called.
897 898 899
        //
        // These variables are primarily all read by
        // src/bootstrap/bin/{rustc.rs,rustdoc.rs}
S
Santiago Pastorino 已提交
900 901 902 903 904 905 906 907 908
        cargo
            .env("RUSTBUILD_NATIVE_DIR", self.native_dir(target))
            .env("RUSTC", self.out.join("bootstrap/debug/rustc"))
            .env("RUSTC_REAL", self.rustc(compiler))
            .env("RUSTC_STAGE", stage.to_string())
            .env(
                "RUSTC_DEBUG_ASSERTIONS",
                self.config.rust_debug_assertions.to_string(),
            )
909 910
            .env("RUSTC_SYSROOT", &sysroot)
            .env("RUSTC_LIBDIR", &libdir)
S
Santiago Pastorino 已提交
911 912 913
            .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
            .env(
                "RUSTDOC_REAL",
914
                if cmd == "doc" || cmd == "rustdoc" || (cmd == "test" && want_rustdoc) {
M
Mark Rousskov 已提交
915
                    self.rustdoc(compiler)
S
Santiago Pastorino 已提交
916 917 918 919
                } else {
                    PathBuf::from("/path/to/nowhere/rustdoc/not/required")
                },
            )
920 921
            .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir())
            .env("RUSTC_BREAK_ON_ICE", "1");
922

923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970
        // Dealing with rpath here is a little special, so let's go into some
        // detail. First off, `-rpath` is a linker option on Unix platforms
        // which adds to the runtime dynamic loader path when looking for
        // dynamic libraries. We use this by default on Unix platforms to ensure
        // that our nightlies behave the same on Windows, that is they work out
        // of the box. This can be disabled, of course, but basically that's why
        // we're gated on RUSTC_RPATH here.
        //
        // Ok, so the astute might be wondering "why isn't `-C rpath` used
        // here?" and that is indeed a good question to task. This codegen
        // option is the compiler's current interface to generating an rpath.
        // Unfortunately it doesn't quite suffice for us. The flag currently
        // takes no value as an argument, so the compiler calculates what it
        // should pass to the linker as `-rpath`. This unfortunately is based on
        // the **compile time** directory structure which when building with
        // Cargo will be very different than the runtime directory structure.
        //
        // All that's a really long winded way of saying that if we use
        // `-Crpath` then the executables generated have the wrong rpath of
        // something like `$ORIGIN/deps` when in fact the way we distribute
        // rustc requires the rpath to be `$ORIGIN/../lib`.
        //
        // So, all in all, to set up the correct rpath we pass the linker
        // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
        // fun to pass a flag to a tool to pass a flag to pass a flag to a tool
        // to change a flag in a binary?
        if self.config.rust_rpath {
            let rpath = if target.contains("apple") {

                // Note that we need to take one extra step on macOS to also pass
                // `-Wl,-instal_name,@rpath/...` to get things to work right. To
                // do that we pass a weird flag to the compiler to get it to do
                // so. Note that this is definitely a hack, and we should likely
                // flesh out rpath support more fully in the future.
                rustflags.arg("-Zosx-rpath-install-name");
                Some("-Wl,-rpath,@loader_path/../lib")
            } else if !target.contains("windows") &&
                      !target.contains("wasm32") &&
                      !target.contains("fuchsia") {
                Some("-Wl,-rpath,$ORIGIN/../lib")
            } else {
                None
            };
            if let Some(rpath) = rpath {
                rustflags.arg(&format!("-Clink-args={}", rpath));
            }
        }

971
        if let Some(host_linker) = self.linker(compiler.host) {
O
Oliver Schneider 已提交
972 973
            cargo.env("RUSTC_HOST_LINKER", host_linker);
        }
974
        if let Some(target_linker) = self.linker(target) {
975 976
            let target = crate::envify(&target);
            cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker);
O
Oliver Schneider 已提交
977
        }
L
ljedrz 已提交
978
        if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc {
M
Mark Rousskov 已提交
979
            cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
980
        }
981

982 983
        let debuginfo_level = match mode {
            Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc,
984
            Mode::Std => self.config.rust_debuginfo_level_std,
985
            Mode::ToolBootstrap | Mode::ToolStd |
986
            Mode::ToolRustc => self.config.rust_debuginfo_level_tools,
987 988 989 990
        };
        cargo.env("RUSTC_DEBUGINFO_LEVEL", debuginfo_level.to_string());

        if !mode.is_tool() {
O
Oliver Schneider 已提交
991
            cargo.env("RUSTC_FORCE_UNSTABLE", "1");
992 993
        }

994
        if let Some(x) = self.crt_static(target) {
995 996 997 998 999
            if x {
                rustflags.arg("-Ctarget-feature=+crt-static");
            } else {
                rustflags.arg("-Ctarget-feature=-crt-static");
            }
1000 1001
        }

1002 1003 1004 1005
        if let Some(x) = self.crt_static(compiler.host) {
            cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string());
        }

1006 1007 1008 1009
        if let Some(map) = self.build.debuginfo_map(GitRepo::Rustc) {
            cargo.env("RUSTC_DEBUGINFO_MAP", map);
        }

1010 1011
        // Enable usage of unstable features
        cargo.env("RUSTC_BOOTSTRAP", "1");
M
Mark Simulacrum 已提交
1012
        self.add_rust_test_threads(&mut cargo);
1013 1014 1015

        // 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 已提交
1016
        // build script, however, it itself needs a standard library! This
1017
        // introduces a bit of a pickle when we're compiling the standard
M
Mark Simulacrum 已提交
1018
        // library itself.
1019 1020
        //
        // To work around this we actually end up using the snapshot compiler
M
Mark Simulacrum 已提交
1021
        // (stage0) for compiling build scripts of the standard library itself.
1022 1023 1024 1025 1026
        // 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.
B
bjorn3 已提交
1027
        if mode == Mode::Std {
S
Santiago Pastorino 已提交
1028 1029 1030
            cargo
                .env("RUSTC_SNAPSHOT", &self.initial_rustc)
                .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
1031
        } else {
S
Santiago Pastorino 已提交
1032 1033 1034
            cargo
                .env("RUSTC_SNAPSHOT", self.rustc(compiler))
                .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler));
1035 1036
        }

1037
        if self.config.incremental {
1038
            cargo.env("CARGO_INCREMENTAL", "1");
1039 1040 1041
        } else {
            // Don't rely on any default setting for incr. comp. in Cargo
            cargo.env("CARGO_INCREMENTAL", "0");
1042 1043
        }

M
Mark Simulacrum 已提交
1044
        if let Some(ref on_fail) = self.config.on_fail {
1045 1046 1047
            cargo.env("RUSTC_ON_FAIL", on_fail);
        }

1048 1049 1050 1051
        if self.config.print_step_timings {
            cargo.env("RUSTC_PRINT_STEP_TIMINGS", "1");
        }

J
John Kåre Alsaker 已提交
1052 1053 1054 1055
        if self.config.backtrace_on_ice {
            cargo.env("RUSTC_BACKTRACE_ON_ICE", "1");
        }

L
ljedrz 已提交
1056
        cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
1057

1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
        if !mode.is_tool() {
            // When extending this list, add the new lints to the RUSTFLAGS of the
            // build_bootstrap function of src/bootstrap/bootstrap.py as well as
            // some code doesn't go through this `rustc` wrapper.
            rustflags.arg("-Wrust_2018_idioms");
            rustflags.arg("-Wunused_lifetimes");

            if self.config.deny_warnings {
                rustflags.arg("-Dwarnings");
            }
1068 1069
        }

1070 1071 1072 1073 1074 1075 1076 1077
        match mode {
            Mode::Rustc | Mode::Codegen => {
                rustflags.arg("-Zunstable-options");
                rustflags.arg("-Wrustc::internal");
            }
            _ => {}
        }

O
Oliver Schneider 已提交
1078 1079 1080 1081 1082
        // 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.
1083 1084
        //
        // FIXME: the guard against msvc shouldn't need to be here
1085 1086 1087 1088 1089
        if target.contains("msvc") {
            if let Some(ref cl) = self.config.llvm_clang_cl {
                cargo.env("CC", cl).env("CXX", cl);
            }
        } else {
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
            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));
1107
            cargo.env(format!("CC_{}", target), &cc);
O
Oliver Schneider 已提交
1108

1109
            let cflags = self.cflags(target, GitRepo::Rustc).join(" ");
S
Santiago Pastorino 已提交
1110
            cargo
1111
                .env(format!("CFLAGS_{}", target), cflags.clone());
O
Oliver Schneider 已提交
1112 1113 1114

            if let Some(ar) = self.ar(target) {
                let ranlib = format!("{} s", ar.display());
S
Santiago Pastorino 已提交
1115 1116
                cargo
                    .env(format!("AR_{}", target), ar)
1117
                    .env(format!("RANLIB_{}", target), ranlib);
O
Oliver Schneider 已提交
1118
            }
1119

M
Mark Simulacrum 已提交
1120
            if let Ok(cxx) = self.cxx(target) {
1121
                let cxx = ccacheify(&cxx);
S
Santiago Pastorino 已提交
1122 1123
                cargo
                    .env(format!("CXX_{}", target), &cxx)
1124
                    .env(format!("CXXFLAGS_{}", target), cflags);
1125 1126 1127
            }
        }

1128
        if (cmd == "build" || cmd == "rustc")
C
Collins Abitekaniza 已提交
1129
            && mode == Mode::Std
S
Santiago Pastorino 已提交
1130 1131
            && self.config.extended
            && compiler.is_final_stage(self)
1132
        {
1133 1134 1135 1136 1137
            rustflags.arg("-Zsave-analysis");
            cargo.env("RUST_SAVE_ANALYSIS_CONFIG",
                      "{\"output_file\": null,\"full_docs\": false,\
                       \"pub_only\": true,\"reachable_only\": false,\
                       \"distro_crate\": true,\"signatures\": false,\"borrow_data\": false}");
1138 1139
        }

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

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

1148
        // Set this for all builds to make sure doc builds also get it.
1149
        cargo.env("CFG_RELEASE_CHANNEL", &self.config.channel);
1150

1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168
        // 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
I
Irina Popa 已提交
1169
        // the binaries we ship of things like rustc_codegen_llvm (aka the rustc_codegen_llvm
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
        // 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.
C
Collins Abitekaniza 已提交
1182
        if !mode.is_tool() {
A
Alex Crichton 已提交
1183 1184
            cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1");
        }
1185

C
comex 已提交
1186
        for _ in 1..self.verbosity {
1187 1188
            cargo.arg("-v");
        }
1189

1190 1191 1192 1193 1194 1195 1196 1197
        match (mode, self.config.rust_codegen_units_std, self.config.rust_codegen_units) {
            (Mode::Std, Some(n), _) |
            (_, _, Some(n)) => {
                cargo.env("RUSTC_CODEGEN_UNITS", n.to_string());
            }
            _ => {
                // Don't set anything
            }
1198 1199
        }

O
Oliver Schneider 已提交
1200
        if self.config.rust_optimize {
1201 1202
            // FIXME: cargo bench/install do not accept `--release`
            if cmd != "bench" && cmd != "install" {
O
Oliver Schneider 已提交
1203 1204
                cargo.arg("--release");
            }
1205
        }
1206

M
Mark Simulacrum 已提交
1207
        if self.config.locked_deps {
1208 1209
            cargo.arg("--locked");
        }
M
Mark Simulacrum 已提交
1210
        if self.config.vendor || self.is_sudo {
1211 1212 1213
            cargo.arg("--frozen");
        }

1214 1215
        cargo.env("RUSTC_INSTALL_BINDIR", &self.config.bindir);

M
Mark Simulacrum 已提交
1216
        self.ci_env.force_coloring_in_ci(&mut cargo);
1217

1218 1219
        cargo.env("RUSTFLAGS", &rustflags.0);

1220 1221 1222
        cargo
    }

V
varkor 已提交
1223
    /// Ensure that a given step is built, returning its output. This will
1224 1225
    /// cache the step, so it is safe (and good!) to call this as often as
    /// needed to ensure that all dependencies are built.
1226
    pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
1227 1228
        {
            let mut stack = self.stack.borrow_mut();
1229 1230
            for stack_step in stack.iter() {
                // should skip
S
Santiago Pastorino 已提交
1231 1232 1233 1234
                if stack_step
                    .downcast_ref::<S>()
                    .map_or(true, |stack_step| *stack_step != step)
                {
1235
                    continue;
1236
                }
1237
                let mut out = String::new();
1238
                out += &format!("\n\nCycle in build detected when adding {:?}\n", step);
1239 1240 1241 1242 1243
                for el in stack.iter().rev() {
                    out += &format!("\t{:?}\n", el);
                }
                panic!(out);
            }
1244
            if let Some(out) = self.cache.get(&step) {
1245
                self.verbose(&format!("{}c {:?}", "  ".repeat(stack.len()), step));
1246

1247 1248 1249
                {
                    let mut graph = self.graph.borrow_mut();
                    let parent = self.parent.get();
S
Santiago Pastorino 已提交
1250 1251 1252
                    let us = *self
                        .graph_nodes
                        .borrow_mut()
1253 1254 1255 1256 1257 1258 1259
                        .entry(format!("{:?}", step))
                        .or_insert_with(|| graph.add_node(format!("{:?}", step)));
                    if let Some(parent) = parent {
                        graph.add_edge(parent, us, false);
                    }
                }

1260 1261
                return out;
            }
1262
            self.verbose(&format!("{}> {:?}", "  ".repeat(stack.len()), step));
1263
            stack.push(Box::new(step.clone()));
1264
        }
1265

1266 1267 1268 1269 1270
        let prev_parent = self.parent.get();

        {
            let mut graph = self.graph.borrow_mut();
            let parent = self.parent.get();
S
Santiago Pastorino 已提交
1271 1272 1273
            let us = *self
                .graph_nodes
                .borrow_mut()
1274 1275 1276 1277 1278 1279 1280 1281
                .entry(format!("{:?}", step))
                .or_insert_with(|| graph.add_node(format!("{:?}", step)));
            self.parent.set(Some(us));
            if let Some(parent) = parent {
                graph.add_edge(parent, us, true);
            }
        }

1282 1283 1284 1285 1286 1287 1288 1289 1290 1291
        let (out, dur) = {
            let start = Instant::now();
            let zero = Duration::new(0, 0);
            let parent = self.time_spent_on_dependencies.replace(zero);
            let out = step.clone().run(self);
            let dur = start.elapsed();
            let deps = self.time_spent_on_dependencies.replace(parent + dur);
            (out, dur - deps)
        };

1292 1293
        self.parent.set(prev_parent);

1294
        if self.config.print_step_timings && dur > Duration::from_millis(100) {
S
Santiago Pastorino 已提交
1295 1296 1297 1298 1299 1300
            println!(
                "[TIMING] {:?} -- {}.{:03}",
                step,
                dur.as_secs(),
                dur.subsec_nanos() / 1_000_000
            );
1301 1302
        }

1303 1304
        {
            let mut stack = self.stack.borrow_mut();
1305 1306
            let cur_step = stack.pop().expect("step stack empty");
            assert_eq!(cur_step.downcast_ref(), Some(&step));
1307
        }
S
Santiago Pastorino 已提交
1308 1309 1310 1311 1312
        self.verbose(&format!(
            "{}< {:?}",
            "  ".repeat(self.stack.borrow().len()),
            step
        ));
1313 1314
        self.cache.put(step, out.clone());
        out
1315 1316
    }
}
M
Mark Simulacrum 已提交
1317 1318

#[cfg(test)]
C
chansuke 已提交
1319
mod tests;
1320 1321 1322 1323

struct Rustflags(String);

impl Rustflags {
1324
    fn new(target: &str, cmd: &mut Command) -> Rustflags {
1325
        let mut ret = Rustflags(String::new());
1326 1327

        // Inherit `RUSTFLAGS` by default
1328
        ret.env("RUSTFLAGS");
1329 1330 1331 1332 1333 1334 1335 1336

        // ... and also handle target-specific env RUSTFLAGS if they're
        // configured. If this is configured we also remove it from the
        // environment because Cargo will prefer it over RUSTFLAGS.
        let target_specific = format!("CARGO_TARGET_{}_RUSTFLAGS", crate::envify(target));
        ret.env(&target_specific);
        cmd.env_remove(&target_specific);

1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356
        return ret;
    }

    fn env(&mut self, env: &str) {
        if let Ok(s) = env::var(env) {
            for part in s.split_whitespace() {
                self.arg(part);
            }
        }
    }

    fn arg(&mut self, arg: &str) -> &mut Self {
        assert_eq!(arg.split_whitespace().count(), 1);
        if self.0.len() > 0 {
            self.0.push_str(" ");
        }
        self.0.push_str(arg);
        self
    }
}