test.rs 65.4 KB
Newer Older
1
//! Implementation of the test-related targets of the build system.
2 3 4 5
//!
//! This file implements the various regression test suites that we execute on
//! our CI.

6
use std::env;
7
use std::ffi::OsString;
U
Ulrik Sverdrup 已提交
8
use std::fmt;
9
use std::fs;
S
Santiago Pastorino 已提交
10 11 12
use std::iter;
use std::path::{Path, PathBuf};
use std::process::Command;
13

14
use build_helper::{self, output, t};
15

L
ljedrz 已提交
16 17 18 19 20 21 22 23 24 25
use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
use crate::cache::{Interned, INTERNER};
use crate::compile;
use crate::dist;
use crate::flags::Subcommand;
use crate::native;
use crate::tool::{self, Tool, SourceType};
use crate::toolstate::ToolState;
use crate::util::{self, dylib_path, dylib_path_var};
use crate::Crate as CargoCrate;
26
use crate::{DocTests, Mode, GitRepo, envify};
27

M
Mark Simulacrum 已提交
28
const ADB_TEST_DIR: &str = "/data/tmp/work";
29

U
Ulrik Sverdrup 已提交
30
/// The two modes of the test runner; tests or benchmarks.
K
kennytm 已提交
31
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)]
U
Ulrik Sverdrup 已提交
32
pub enum TestKind {
A
Alexander Regueiro 已提交
33
    /// Run `cargo test`.
U
Ulrik Sverdrup 已提交
34
    Test,
A
Alexander Regueiro 已提交
35
    /// Run `cargo bench`.
U
Ulrik Sverdrup 已提交
36 37 38
    Bench,
}

39 40 41 42 43
impl From<Kind> for TestKind {
    fn from(kind: Kind) -> Self {
        match kind {
            Kind::Test => TestKind::Test,
            Kind::Bench => TestKind::Bench,
S
Santiago Pastorino 已提交
44
            _ => panic!("unexpected kind in crate: {:?}", kind),
45 46 47 48
        }
    }
}

U
Ulrik Sverdrup 已提交
49 50 51 52 53 54 55 56 57 58 59
impl TestKind {
    // Return the cargo subcommand for this test kind
    fn subcommand(self) -> &'static str {
        match self {
            TestKind::Test => "test",
            TestKind::Bench => "bench",
        }
    }
}

impl fmt::Display for TestKind {
T
Taiki Endo 已提交
60
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
U
Ulrik Sverdrup 已提交
61 62 63 64 65 66 67
        f.write_str(match *self {
            TestKind::Test => "Testing",
            TestKind::Bench => "Benchmarking",
        })
    }
}

T
Taiki Endo 已提交
68
fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool {
69 70 71
    if !builder.fail_fast {
        if !builder.try_run(cmd) {
            let mut failures = builder.delayed_failures.borrow_mut();
72
            failures.push(format!("{:?}", cmd));
O
Oliver Schneider 已提交
73
            return false;
74 75
        }
    } else {
76
        builder.run(cmd);
77
    }
O
Oliver Schneider 已提交
78
    true
79 80
}

T
Taiki Endo 已提交
81
fn try_run_quiet(builder: &Builder<'_>, cmd: &mut Command) -> bool {
82 83 84
    if !builder.fail_fast {
        if !builder.try_run_quiet(cmd) {
            let mut failures = builder.delayed_failures.borrow_mut();
85
            failures.push(format!("{:?}", cmd));
86
            return false;
87 88
        }
    } else {
89
        builder.run_quiet(cmd);
90
    }
91
    true
92 93
}

94 95 96
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Linkcheck {
    host: Interned<String>,
97 98
}

99
impl Step for Linkcheck {
100
    type Output = ();
101 102
    const ONLY_HOSTS: bool = true;
    const DEFAULT: bool = true;
103 104 105 106 107

    /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
    ///
    /// This tool in `src/tools` will verify the validity of all our links in the
    /// documentation to ensure we don't have a bunch of dead ones.
T
Taiki Endo 已提交
108
    fn run(self, builder: &Builder<'_>) {
109 110
        let host = self.host;

111
        builder.info(&format!("Linkcheck ({})", host));
112 113

        builder.default_doc(None);
114

115
        let _time = util::timeit(&builder);
S
Santiago Pastorino 已提交
116 117 118 119 120 121
        try_run(
            builder,
            builder
                .tool_cmd(Tool::Linkchecker)
                .arg(builder.out.join(host).join("doc")),
        );
122
    }
123

T
Taiki Endo 已提交
124
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
125
        let builder = run.builder;
S
Santiago Pastorino 已提交
126 127
        run.path("src/tools/linkchecker")
            .default_condition(builder.config.docs)
128 129
    }

T
Taiki Endo 已提交
130
    fn make_run(run: RunConfig<'_>) {
131
        run.builder.ensure(Linkcheck { host: run.target });
132
    }
133
}
134

135 136
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Cargotest {
137
    stage: u32,
138
    host: Interned<String>,
139
}
140

141
impl Step for Cargotest {
142
    type Output = ();
143
    const ONLY_HOSTS: bool = true;
144

T
Taiki Endo 已提交
145
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
146
        run.path("src/tools/cargotest")
147 148
    }

T
Taiki Endo 已提交
149
    fn make_run(run: RunConfig<'_>) {
150 151
        run.builder.ensure(Cargotest {
            stage: run.builder.top_stage,
152
            host: run.target,
153 154 155
        });
    }

156 157 158 159
    /// Runs the `cargotest` tool as compiled in `stage` by the `host` compiler.
    ///
    /// This tool in `src/tools` will check out a few Rust projects and run `cargo
    /// test` to ensure that we don't regress the test suites there.
T
Taiki Endo 已提交
160
    fn run(self, builder: &Builder<'_>) {
161
        let compiler = builder.compiler(self.stage, self.host);
S
Santiago Pastorino 已提交
162 163 164 165
        builder.ensure(compile::Rustc {
            compiler,
            target: compiler.host,
        });
166 167 168 169

        // Note that this is a short, cryptic, and not scoped directory name. This
        // is currently to minimize the length of path on Windows where we otherwise
        // quickly run into path name limit constraints.
170
        let out_dir = builder.out.join("ct");
171 172
        t!(fs::create_dir_all(&out_dir));

173
        let _time = util::timeit(&builder);
174
        let mut cmd = builder.tool_cmd(Tool::CargoTest);
S
Santiago Pastorino 已提交
175 176 177 178 179
        try_run(
            builder,
            cmd.arg(&builder.initial_cargo)
                .arg(&out_dir)
                .env("RUSTC", builder.rustc(compiler))
M
Mark Rousskov 已提交
180
                .env("RUSTDOC", builder.rustdoc(compiler)),
S
Santiago Pastorino 已提交
181
        );
182
    }
183 184
}

185 186
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Cargo {
187
    stage: u32,
188
    host: Interned<String>,
189 190
}

191
impl Step for Cargo {
192
    type Output = ();
193 194
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
195
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
196
        run.path("src/tools/cargo")
197 198
    }

T
Taiki Endo 已提交
199
    fn make_run(run: RunConfig<'_>) {
200 201 202
        run.builder.ensure(Cargo {
            stage: run.builder.top_stage,
            host: run.target,
203 204
        });
    }
205 206

    /// Runs `cargo test` for `cargo` packaged with Rust.
T
Taiki Endo 已提交
207
    fn run(self, builder: &Builder<'_>) {
208
        let compiler = builder.compiler(self.stage, self.host);
209

S
Santiago Pastorino 已提交
210 211 212 213
        builder.ensure(tool::Cargo {
            compiler,
            target: self.host,
        });
214 215 216 217 218 219
        let mut cargo = tool::prepare_tool_cargo(builder,
                                                 compiler,
                                                 Mode::ToolRustc,
                                                 self.host,
                                                 "test",
                                                 "src/tools/cargo",
220 221
                                                 SourceType::Submodule,
                                                 &[]);
222

223
        if !builder.fail_fast {
224 225
            cargo.arg("--no-fail-fast");
        }
226

227 228 229
        // Don't run cross-compile tests, we may not have cross-compiled libstd libs
        // available.
        cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
230 231
        // Disable a test that has issues with mingw.
        cargo.env("CARGO_TEST_DISABLE_GIT_CLI", "1");
232 233 234
        // Forcibly disable tests using nightly features since any changes to
        // those features won't be able to land.
        cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");
235

236 237 238
        cargo.env("PATH", &path_for_cargo(builder, compiler));

        try_run(builder, &mut cargo.into());
239
    }
N
Nick Cameron 已提交
240 241
}

M
Mark Simulacrum 已提交
242 243
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rls {
244
    stage: u32,
M
Mark Simulacrum 已提交
245
    host: Interned<String>,
246
}
N
Nick Cameron 已提交
247

M
Mark Simulacrum 已提交
248
impl Step for Rls {
249
    type Output = ();
M
Mark Simulacrum 已提交
250 251
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
252
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
253
        run.path("src/tools/rls")
M
Mark Simulacrum 已提交
254 255
    }

T
Taiki Endo 已提交
256
    fn make_run(run: RunConfig<'_>) {
257 258 259
        run.builder.ensure(Rls {
            stage: run.builder.top_stage,
            host: run.target,
M
Mark Simulacrum 已提交
260 261
        });
    }
N
Nick Cameron 已提交
262

263
    /// Runs `cargo test` for the rls.
T
Taiki Endo 已提交
264
    fn run(self, builder: &Builder<'_>) {
265 266
        let stage = self.stage;
        let host = self.host;
M
Mark Simulacrum 已提交
267
        let compiler = builder.compiler(stage, host);
N
Nick Cameron 已提交
268

269 270 271 272 273 274 275 276 277 278
        let build_result = builder.ensure(tool::Rls {
            compiler,
            target: self.host,
            extra_features: Vec::new(),
        });
        if build_result.is_none() {
            eprintln!("failed to test rls: could not build");
            return;
        }

C
Collins Abitekaniza 已提交
279 280
        let mut cargo = tool::prepare_tool_cargo(builder,
                                                 compiler,
281
                                                 Mode::ToolRustc,
C
Collins Abitekaniza 已提交
282 283
                                                 host,
                                                 "test",
284
                                                 "src/tools/rls",
285 286
                                                 SourceType::Submodule,
                                                 &[]);
N
Nick Cameron 已提交
287

M
Mark Simulacrum 已提交
288
        builder.add_rustc_lib_path(compiler, &mut cargo);
A
Alex Crichton 已提交
289 290
        cargo.arg("--")
            .args(builder.config.cmd.test_args());
291

292
        if try_run(builder, &mut cargo.into()) {
293
            builder.save_toolstate("rls", ToolState::TestPass);
O
Oliver Schneider 已提交
294
        }
295
    }
N
Nick Cameron 已提交
296 297
}

N
Nick Cameron 已提交
298 299 300 301 302 303 304 305 306 307
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustfmt {
    stage: u32,
    host: Interned<String>,
}

impl Step for Rustfmt {
    type Output = ();
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
308
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
N
Nick Cameron 已提交
309 310 311
        run.path("src/tools/rustfmt")
    }

T
Taiki Endo 已提交
312
    fn make_run(run: RunConfig<'_>) {
N
Nick Cameron 已提交
313 314 315 316 317 318 319
        run.builder.ensure(Rustfmt {
            stage: run.builder.top_stage,
            host: run.target,
        });
    }

    /// Runs `cargo test` for rustfmt.
T
Taiki Endo 已提交
320
    fn run(self, builder: &Builder<'_>) {
N
Nick Cameron 已提交
321 322 323 324
        let stage = self.stage;
        let host = self.host;
        let compiler = builder.compiler(stage, host);

325 326 327 328 329 330 331 332 333 334
        let build_result = builder.ensure(tool::Rustfmt {
            compiler,
            target: self.host,
            extra_features: Vec::new(),
        });
        if build_result.is_none() {
            eprintln!("failed to test rustfmt: could not build");
            return;
        }

C
Collins Abitekaniza 已提交
335 336
        let mut cargo = tool::prepare_tool_cargo(builder,
                                                 compiler,
337
                                                 Mode::ToolRustc,
C
Collins Abitekaniza 已提交
338 339
                                                 host,
                                                 "test",
340
                                                 "src/tools/rustfmt",
341 342
                                                 SourceType::Submodule,
                                                 &[]);
N
Nick Cameron 已提交
343

N
Nick Cameron 已提交
344 345 346
        let dir = testdir(builder, compiler.host);
        t!(fs::create_dir_all(&dir));
        cargo.env("RUSTFMT_TEST_DIR", dir);
N
Nick Cameron 已提交
347 348 349

        builder.add_rustc_lib_path(compiler, &mut cargo);

350
        if try_run(builder, &mut cargo.into()) {
351
            builder.save_toolstate("rustfmt", ToolState::TestPass);
O
Oliver Schneider 已提交
352
        }
N
Nick Cameron 已提交
353 354
    }
}
O
Oliver Schneider 已提交
355 356

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
357
pub struct Miri {
O
Oliver Schneider 已提交
358
    stage: u32,
359 360 361 362 363 364 365
    host: Interned<String>,
}

impl Step for Miri {
    type Output = ();
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
366
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
R
Ralf Jung 已提交
367
        run.path("src/tools/miri")
368 369
    }

T
Taiki Endo 已提交
370
    fn make_run(run: RunConfig<'_>) {
371
        run.builder.ensure(Miri {
O
Oliver Schneider 已提交
372
            stage: run.builder.top_stage,
373 374 375 376 377
            host: run.target,
        });
    }

    /// Runs `cargo test` for miri.
T
Taiki Endo 已提交
378
    fn run(self, builder: &Builder<'_>) {
O
Oliver Schneider 已提交
379
        let stage = self.stage;
380
        let host = self.host;
O
Oliver Schneider 已提交
381
        let compiler = builder.compiler(stage, host);
382

383 384 385 386 387 388
        let miri = builder.ensure(tool::Miri {
            compiler,
            target: self.host,
            extra_features: Vec::new(),
        });
        if let Some(miri) = miri {
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
            // # Install xargo.
            let mut cargo = tool::prepare_tool_cargo(
                builder,
                compiler,
                Mode::ToolRustc,
                host,
                "install",
                "src/tools/miri",
                SourceType::Submodule,
                &[],
            );
            cargo.arg("xargo");
            // Configure `cargo install` path. cargo adds a `bin/`.
            cargo.env("CARGO_INSTALL_ROOT", &builder.out);

            let mut cargo = Command::from(cargo);
            if !try_run(builder, &mut cargo) {
                return;
            }

409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
            // # Run `cargo miri setup`.
            let mut cargo = tool::prepare_tool_cargo(
                builder,
                compiler,
                Mode::ToolRustc,
                host,
                "run",
                "src/tools/miri",
                SourceType::Submodule,
                &[],
            );
            cargo
                .arg("--bin")
                .arg("cargo-miri")
                .arg("--")
                .arg("miri")
                .arg("setup");

            // Tell `cargo miri` not to worry about the sysroot mismatch (we built with
            // stage1 but run with stage2).
            cargo.env("MIRI_SKIP_SYSROOT_CHECK", "1");
            // Tell `cargo miri setup` where to find the sources.
            cargo.env("XARGO_RUST_SRC", builder.src.join("src"));
432 433
            // Debug things.
            cargo.env("RUST_BACKTRACE", "1");
434
            // Let cargo-miri know where xargo ended up.
435
            cargo.env("XARGO", builder.out.join("bin").join("xargo"));
436

437
            let mut cargo = Command::from(cargo);
438 439 440 441 442 443 444 445 446
            if !try_run(builder, &mut cargo) {
                return;
            }

            // # Determine where Miri put its sysroot.
            // To this end, we run `cargo miri setup --env` and capture the output.
            // (We do this separately from the above so that when the setup actually
            // happens we get some output.)
            // We re-use the `cargo` from above.
R
Ralf Jung 已提交
447
            cargo.arg("--print-sysroot");
448 449 450 451 452

            // FIXME: Is there a way in which we can re-use the usual `run` helpers?
            let miri_sysroot = if builder.config.dry_run {
                String::new()
            } else {
453
                builder.verbose(&format!("running: {:?}", cargo));
454 455 456
                let out = cargo.output()
                    .expect("We already ran `cargo miri setup` before and that worked");
                assert!(out.status.success(), "`cargo miri setup` returned with non-0 exit code");
R
Ralf Jung 已提交
457
                // Output is "<sysroot>\n".
458 459
                let stdout = String::from_utf8(out.stdout)
                    .expect("`cargo miri setup` stdout is not valid UTF-8");
R
Ralf Jung 已提交
460 461
                let sysroot = stdout.trim_end();
                builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {:?}", sysroot));
462 463 464 465 466 467 468 469 470 471 472 473 474 475
                sysroot.to_owned()
            };

            // # Run `cargo test`.
            let mut cargo = tool::prepare_tool_cargo(
                builder,
                compiler,
                Mode::ToolRustc,
                host,
                "test",
                "src/tools/miri",
                SourceType::Submodule,
                &[],
            );
O
Oliver Schneider 已提交
476 477

            // miri tests need to know about the stage sysroot
478
            cargo.env("MIRI_SYSROOT", miri_sysroot);
O
Oliver Schneider 已提交
479 480 481 482 483 484
            cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
            cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
            cargo.env("MIRI_PATH", miri);

            builder.add_rustc_lib_path(compiler, &mut cargo);

485
            if !try_run(builder, &mut cargo.into()) {
486
                return;
O
Oliver Schneider 已提交
487
            }
488 489 490

            // # Done!
            builder.save_toolstate("miri", ToolState::TestPass);
O
Oliver Schneider 已提交
491 492 493
        } else {
            eprintln!("failed to test miri: could not build");
        }
494 495 496
    }
}

497 498 499 500 501 502 503 504
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CompiletestTest {
    host: Interned<String>,
}

impl Step for CompiletestTest {
    type Output = ();

T
Taiki Endo 已提交
505
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
506 507 508
        run.path("src/tools/compiletest")
    }

T
Taiki Endo 已提交
509
    fn make_run(run: RunConfig<'_>) {
510 511 512 513 514 515
        run.builder.ensure(CompiletestTest {
            host: run.target,
        });
    }

    /// Runs `cargo test` for compiletest.
T
Taiki Endo 已提交
516
    fn run(self, builder: &Builder<'_>) {
517
        let host = self.host;
518
        let compiler = builder.compiler(0, host);
519

520 521 522 523 524 525 526 527
        let cargo = tool::prepare_tool_cargo(builder,
                                             compiler,
                                             Mode::ToolBootstrap,
                                             host,
                                             "test",
                                             "src/tools/compiletest",
                                             SourceType::InTree,
                                             &[]);
528

529
        try_run(builder, &mut cargo.into());
530 531 532
    }
}

533 534
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Clippy {
O
Oliver Schneider 已提交
535
    stage: u32,
536 537 538 539 540 541 542 543
    host: Interned<String>,
}

impl Step for Clippy {
    type Output = ();
    const ONLY_HOSTS: bool = true;
    const DEFAULT: bool = false;

T
Taiki Endo 已提交
544
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
545 546 547
        run.path("src/tools/clippy")
    }

T
Taiki Endo 已提交
548
    fn make_run(run: RunConfig<'_>) {
549
        run.builder.ensure(Clippy {
O
Oliver Schneider 已提交
550
            stage: run.builder.top_stage,
551 552 553 554 555
            host: run.target,
        });
    }

    /// Runs `cargo test` for clippy.
T
Taiki Endo 已提交
556
    fn run(self, builder: &Builder<'_>) {
O
Oliver Schneider 已提交
557
        let stage = self.stage;
558
        let host = self.host;
O
Oliver Schneider 已提交
559
        let compiler = builder.compiler(stage, host);
560

561 562 563 564 565 566
        let clippy = builder.ensure(tool::Clippy {
            compiler,
            target: self.host,
            extra_features: Vec::new(),
        });
        if let Some(clippy) = clippy {
567 568 569 570 571 572
            let mut cargo = tool::prepare_tool_cargo(builder,
                                                 compiler,
                                                 Mode::ToolRustc,
                                                 host,
                                                 "test",
                                                 "src/tools/clippy",
573 574
                                                 SourceType::Submodule,
                                                 &[]);
O
Oliver Schneider 已提交
575 576 577 578 579

            // clippy tests need to know about the stage sysroot
            cargo.env("SYSROOT", builder.sysroot(compiler));
            cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
            cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
S
Santiago Pastorino 已提交
580
            let host_libs = builder
C
Collins Abitekaniza 已提交
581
                .stage_out(compiler, Mode::ToolRustc)
S
Santiago Pastorino 已提交
582
                .join(builder.cargo_dir());
O
Oliver Schneider 已提交
583 584 585 586 587 588
            cargo.env("HOST_LIBS", host_libs);
            // clippy tests need to find the driver
            cargo.env("CLIPPY_DRIVER_PATH", clippy);

            builder.add_rustc_lib_path(compiler, &mut cargo);

589
            if try_run(builder, &mut cargo.into()) {
590
                builder.save_toolstate("clippy-driver", ToolState::TestPass);
O
Oliver Schneider 已提交
591 592 593 594
            }
        } else {
            eprintln!("failed to test clippy: could not build");
        }
595 596
    }
}
N
Nick Cameron 已提交
597

T
Taiki Endo 已提交
598
fn path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString {
N
Nick Cameron 已提交
599 600 601
    // Configure PATH to find the right rustc. NB. we have to use PATH
    // and not RUSTC because the Cargo test suite has tests that will
    // fail if rustc is not spelled `rustc`.
M
Mark Simulacrum 已提交
602
    let path = builder.sysroot(compiler).join("bin");
N
Nick Cameron 已提交
603 604
    let old_path = env::var_os("PATH").unwrap_or_default();
    env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("")
605
}
606

G
Guillaume Gomez 已提交
607 608 609 610 611 612 613 614 615 616
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustdocTheme {
    pub compiler: Compiler,
}

impl Step for RustdocTheme {
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
617
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
G
Guillaume Gomez 已提交
618 619 620
        run.path("src/tools/rustdoc-themes")
    }

T
Taiki Endo 已提交
621
    fn make_run(run: RunConfig<'_>) {
G
Guillaume Gomez 已提交
622 623
        let compiler = run.builder.compiler(run.builder.top_stage, run.host);

624
        run.builder.ensure(RustdocTheme { compiler });
G
Guillaume Gomez 已提交
625 626
    }

T
Taiki Endo 已提交
627
    fn run(self, builder: &Builder<'_>) {
628
        let rustdoc = builder.out.join("bootstrap/debug/rustdoc");
G
Guillaume Gomez 已提交
629 630
        let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
        cmd.arg(rustdoc.to_str().unwrap())
S
Santiago Pastorino 已提交
631 632 633 634 635 636 637 638 639 640 641 642 643 644
            .arg(
                builder
                    .src
                    .join("src/librustdoc/html/static/themes")
                    .to_str()
                    .unwrap(),
            )
            .env("RUSTC_STAGE", self.compiler.stage.to_string())
            .env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
            .env(
                "RUSTDOC_LIBDIR",
                builder.sysroot_libdir(self.compiler, self.compiler.host),
            )
            .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
M
Mark Rousskov 已提交
645
            .env("RUSTDOC_REAL", builder.rustdoc(self.compiler))
S
Santiago Pastorino 已提交
646 647
            .env("RUSTDOC_CRATE_VERSION", builder.rust_version())
            .env("RUSTC_BOOTSTRAP", "1");
648
        if let Some(linker) = builder.linker(self.compiler.host) {
G
Guillaume Gomez 已提交
649 650
            cmd.env("RUSTC_TARGET_LINKER", linker);
        }
651
        try_run(builder, &mut cmd);
G
Guillaume Gomez 已提交
652 653 654
    }
}

G
Guillaume Gomez 已提交
655
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
G
Guillaume Gomez 已提交
656
pub struct RustdocJSStd {
G
Guillaume Gomez 已提交
657
    pub host: Interned<String>,
658
    pub target: Interned<String>,
G
Guillaume Gomez 已提交
659 660
}

G
Guillaume Gomez 已提交
661
impl Step for RustdocJSStd {
662
    type Output = ();
G
Guillaume Gomez 已提交
663 664 665
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
666
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
G
Guillaume Gomez 已提交
667
        run.path("src/test/rustdoc-js-std")
G
Guillaume Gomez 已提交
668 669
    }

T
Taiki Endo 已提交
670
    fn make_run(run: RunConfig<'_>) {
G
Guillaume Gomez 已提交
671
        run.builder.ensure(RustdocJSStd {
G
Guillaume Gomez 已提交
672
            host: run.host,
673
            target: run.target,
G
Guillaume Gomez 已提交
674 675 676
        });
    }

T
Taiki Endo 已提交
677
    fn run(self, builder: &Builder<'_>) {
678 679
        if let Some(ref nodejs) = builder.config.nodejs {
            let mut command = Command::new(nodejs);
G
Guillaume Gomez 已提交
680
            command.args(&["src/tools/rustdoc-js-std/tester.js", &*self.host]);
L
ljedrz 已提交
681
            builder.ensure(crate::doc::Std {
682 683 684 685 686
                target: self.target,
                stage: builder.top_stage,
            });
            builder.run(&mut command);
        } else {
687
            builder.info(
G
Guillaume Gomez 已提交
688
                "No nodejs found, skipping \"src/test/rustdoc-js-std\" tests"
689
            );
690
        }
G
Guillaume Gomez 已提交
691 692 693
    }
}

G
Guillaume Gomez 已提交
694 695 696 697 698 699 700 701 702 703 704 705
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustdocJSNotStd {
    pub host: Interned<String>,
    pub target: Interned<String>,
    pub compiler: Compiler,
}

impl Step for RustdocJSNotStd {
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

G
Guillaume Gomez 已提交
706
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
G
Guillaume Gomez 已提交
707
        run.path("src/test/rustdoc-js")
G
Guillaume Gomez 已提交
708 709
    }

G
Guillaume Gomez 已提交
710
    fn make_run(run: RunConfig<'_>) {
G
Guillaume Gomez 已提交
711 712 713 714 715 716 717 718
        let compiler = run.builder.compiler(run.builder.top_stage, run.host);
        run.builder.ensure(RustdocJSNotStd {
            host: run.host,
            target: run.target,
            compiler,
        });
    }

G
Guillaume Gomez 已提交
719
    fn run(self, builder: &Builder<'_>) {
720 721 722
        if builder.config.nodejs.is_some() {
            builder.ensure(Compiletest {
                compiler: self.compiler,
G
Guillaume Gomez 已提交
723
                target: self.target,
724 725 726 727
                mode: "js-doc-test",
                suite: "rustdoc-js",
                path: None,
                compare_mode: None,
G
Guillaume Gomez 已提交
728 729 730
            });
        } else {
            builder.info(
G
Guillaume Gomez 已提交
731
                "No nodejs found, skipping \"src/test/rustdoc-js\" tests"
G
Guillaume Gomez 已提交
732 733 734 735 736
            );
        }
    }
}

737 738 739 740 741 742 743 744 745 746 747 748
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustdocUi {
    pub host: Interned<String>,
    pub target: Interned<String>,
    pub compiler: Compiler,
}

impl Step for RustdocUi {
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
749
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
750 751 752
        run.path("src/test/rustdoc-ui")
    }

T
Taiki Endo 已提交
753
    fn make_run(run: RunConfig<'_>) {
754 755 756 757 758 759 760 761
        let compiler = run.builder.compiler(run.builder.top_stage, run.host);
        run.builder.ensure(RustdocUi {
            host: run.host,
            target: run.target,
            compiler,
        });
    }

T
Taiki Endo 已提交
762
    fn run(self, builder: &Builder<'_>) {
763 764 765 766 767
        builder.ensure(Compiletest {
            compiler: self.compiler,
            target: self.target,
            mode: "ui",
            suite: "rustdoc-ui",
G
Guillaume Gomez 已提交
768
            path: Some("src/test/rustdoc-ui"),
769
            compare_mode: None,
770 771 772 773
        })
    }
}

774
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
M
Mark Simulacrum 已提交
775
pub struct Tidy;
776

777
impl Step for Tidy {
778
    type Output = ();
779 780
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;
781

M
Mark Simulacrum 已提交
782
    /// Runs the `tidy` tool.
783 784 785 786
    ///
    /// This tool in `src/tools` checks up on various bits and pieces of style and
    /// otherwise just implements a few lint-like checks that are specific to the
    /// compiler itself.
T
Taiki Endo 已提交
787
    fn run(self, builder: &Builder<'_>) {
788
        let mut cmd = builder.tool_cmd(Tool::Tidy);
789 790 791
        cmd.arg(builder.src.join("src"));
        cmd.arg(&builder.initial_cargo);
        if !builder.config.vendor {
792 793
            cmd.arg("--no-vendor");
        }
M
Mark Rousskov 已提交
794 795
        if builder.is_verbose() {
            cmd.arg("--verbose");
796
        }
797

798
        builder.info("tidy check");
799
        try_run(builder, &mut cmd);
800
    }
801

T
Taiki Endo 已提交
802
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
803
        run.path("src/tools/tidy")
804 805
    }

T
Taiki Endo 已提交
806
    fn make_run(run: RunConfig<'_>) {
M
Mark Simulacrum 已提交
807
        run.builder.ensure(Tidy);
808
    }
809
}
810

T
Taiki Endo 已提交
811
fn testdir(builder: &Builder<'_>, host: Interned<String>) -> PathBuf {
812
    builder.out.join(host).join("test")
813 814
}

815 816 817 818
macro_rules! default_test {
    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => {
        test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: false });
    }
819 820
}

821 822 823 824 825 826 827 828
macro_rules! default_test_with_compare_mode {
    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr,
                   compare_mode: $compare_mode:expr }) => {
        test_with_compare_mode!($name { path: $path, mode: $mode, suite: $suite, default: true,
                                        host: false, compare_mode: $compare_mode });
    }
}

829 830 831 832
macro_rules! host_test {
    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => {
        test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: true });
    }
833 834
}

835
macro_rules! test {
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
                   host: $host:expr }) => {
        test_definitions!($name { path: $path, mode: $mode, suite: $suite, default: $default,
                                  host: $host, compare_mode: None });
    }
}

macro_rules! test_with_compare_mode {
    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
                   host: $host:expr, compare_mode: $compare_mode:expr }) => {
        test_definitions!($name { path: $path, mode: $mode, suite: $suite, default: $default,
                                  host: $host, compare_mode: Some($compare_mode) });
    }
}

macro_rules! test_definitions {
852 853 854 855 856
    ($name:ident {
        path: $path:expr,
        mode: $mode:expr,
        suite: $suite:expr,
        default: $default:expr,
857 858
        host: $host:expr,
        compare_mode: $compare_mode:expr
859 860 861 862 863
    }) => {
        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
        pub struct $name {
            pub compiler: Compiler,
            pub target: Interned<String>,
864 865
        }

866 867 868 869
        impl Step for $name {
            type Output = ();
            const DEFAULT: bool = $default;
            const ONLY_HOSTS: bool = $host;
870

T
Taiki Endo 已提交
871
            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
872
                run.suite_path($path)
873
            }
874

T
Taiki Endo 已提交
875
            fn make_run(run: RunConfig<'_>) {
876
                let compiler = run.builder.compiler(run.builder.top_stage, run.host);
877

878
                run.builder.ensure($name {
879
                    compiler,
880
                    target: run.target,
881 882
                });
            }
883

T
Taiki Endo 已提交
884
            fn run(self, builder: &Builder<'_>) {
885 886 887 888 889
                builder.ensure(Compiletest {
                    compiler: self.compiler,
                    target: self.target,
                    mode: $mode,
                    suite: $suite,
890
                    path: Some($path),
891
                    compare_mode: $compare_mode,
892 893 894
                })
            }
        }
895 896 897
    }
}

898
default_test_with_compare_mode!(Ui {
899 900
    path: "src/test/ui",
    mode: "ui",
901 902
    suite: "ui",
    compare_mode: "nll"
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 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
});

default_test!(CompileFail {
    path: "src/test/compile-fail",
    mode: "compile-fail",
    suite: "compile-fail"
});

default_test!(RunFail {
    path: "src/test/run-fail",
    mode: "run-fail",
    suite: "run-fail"
});

default_test!(RunPassValgrind {
    path: "src/test/run-pass-valgrind",
    mode: "run-pass-valgrind",
    suite: "run-pass-valgrind"
});

default_test!(MirOpt {
    path: "src/test/mir-opt",
    mode: "mir-opt",
    suite: "mir-opt"
});

default_test!(Codegen {
    path: "src/test/codegen",
    mode: "codegen",
    suite: "codegen"
});

default_test!(CodegenUnits {
    path: "src/test/codegen-units",
    mode: "codegen-units",
    suite: "codegen-units"
});

default_test!(Incremental {
    path: "src/test/incremental",
    mode: "incremental",
    suite: "incremental"
});

default_test!(Debuginfo {
    path: "src/test/debuginfo",
T
Tom Tromey 已提交
949
    mode: "debuginfo",
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
    suite: "debuginfo"
});

host_test!(UiFullDeps {
    path: "src/test/ui-fulldeps",
    mode: "ui",
    suite: "ui-fulldeps"
});

host_test!(Rustdoc {
    path: "src/test/rustdoc",
    mode: "rustdoc",
    suite: "rustdoc"
});

965
host_test!(Pretty {
966 967
    path: "src/test/pretty",
    mode: "pretty",
968
    suite: "pretty"
969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984
});
test!(RunFailPretty {
    path: "src/test/run-fail/pretty",
    mode: "pretty",
    suite: "run-fail",
    default: false,
    host: true
});
test!(RunPassValgrindPretty {
    path: "src/test/run-pass-valgrind/pretty",
    mode: "pretty",
    suite: "run-pass-valgrind",
    default: false,
    host: true
});

E
Eric Huss 已提交
985
default_test!(RunMake {
986 987 988 989 990
    path: "src/test/run-make",
    mode: "run-make",
    suite: "run-make"
});

991 992 993 994 995 996
host_test!(RunMakeFullDeps {
    path: "src/test/run-make-fulldeps",
    mode: "run-make",
    suite: "run-make-fulldeps"
});

D
Denys Zariaiev 已提交
997 998 999 1000 1001 1002
default_test!(Assembly {
    path: "src/test/assembly",
    mode: "assembly",
    suite: "assembly"
});

1003 1004 1005 1006 1007 1008
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
struct Compiletest {
    compiler: Compiler,
    target: Interned<String>,
    mode: &'static str,
    suite: &'static str,
1009
    path: Option<&'static str>,
1010
    compare_mode: Option<&'static str>,
1011 1012 1013 1014 1015
}

impl Step for Compiletest {
    type Output = ();

T
Taiki Endo 已提交
1016
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1017 1018 1019
        run.never()
    }

1020 1021 1022 1023 1024
    /// Executes the `compiletest` tool to run a suite of tests.
    ///
    /// Compiles all tests with `compiler` for `target` with the specified
    /// compiletest `mode` and `suite` arguments. For example `mode` can be
    /// "run-pass" or `suite` can be something like `debuginfo`.
T
Taiki Endo 已提交
1025
    fn run(self, builder: &Builder<'_>) {
1026 1027 1028 1029
        let compiler = self.compiler;
        let target = self.target;
        let mode = self.mode;
        let suite = self.suite;
1030

1031 1032 1033
        // Path for test suite
        let suite_path = self.path.unwrap_or("");

1034
        // Skip codegen tests if they aren't enabled in configuration.
1035
        if !builder.config.codegen_tests && suite == "codegen" {
1036 1037 1038 1039
            return;
        }

        if suite == "debuginfo" {
1040
            let msvc = builder.config.build.contains("msvc");
T
Tom Tromey 已提交
1041 1042
            if mode == "debuginfo" {
                return builder.ensure(Compiletest {
1043
                    mode: if msvc { "debuginfo-cdb" } else { "debuginfo-gdb+lldb" },
T
Tom Tromey 已提交
1044 1045
                    ..self
                });
1046 1047 1048
            }

            builder.ensure(dist::DebuggerScripts {
1049
                sysroot: builder.sysroot(compiler),
S
Santiago Pastorino 已提交
1050
                host: target,
1051 1052 1053
            });
        }

1054
        if suite.ends_with("fulldeps") {
1055 1056 1057
            builder.ensure(compile::Rustc { compiler, target });
        }

1058 1059 1060
        builder.ensure(compile::Std { compiler, target });
        // ensure that `libproc_macro` is available on the host.
        builder.ensure(compile::Std { compiler, target: compiler.host });
1061

1062 1063
        // Also provide `rust_test_helpers` for the host.
        builder.ensure(native::TestHelpers { target: compiler.host });
1064

1065 1066
        // As well as the target, except for plain wasm32, which can't build it
        if !target.contains("wasm32") || target.contains("emscripten") {
1067 1068
            builder.ensure(native::TestHelpers { target });
        }
1069

1070
        builder.ensure(RemoteCopyLibs { compiler, target });
1071 1072

        let mut cmd = builder.tool_cmd(Tool::Compiletest);
1073 1074 1075 1076

        // compiletest currently has... a lot of arguments, so let's just pass all
        // of them!

S
Santiago Pastorino 已提交
1077 1078 1079 1080
        cmd.arg("--compile-lib-path")
            .arg(builder.rustc_libdir(compiler));
        cmd.arg("--run-lib-path")
            .arg(builder.sysroot_libdir(compiler, target));
1081
        cmd.arg("--rustc-path").arg(builder.rustc(compiler));
1082

1083
        let is_rustdoc = suite.ends_with("rustdoc-ui") || suite.ends_with("rustdoc-js");
G
Guillaume Gomez 已提交
1084

1085
        // Avoid depending on rustdoc when we don't need it.
S
Santiago Pastorino 已提交
1086 1087
        if mode == "rustdoc"
            || (mode == "run-make" && suite.ends_with("fulldeps"))
1088 1089
            || (mode == "ui" && is_rustdoc)
            || mode == "js-doc-test"
S
Santiago Pastorino 已提交
1090 1091
        {
            cmd.arg("--rustdoc-path")
M
Mark Rousskov 已提交
1092
                .arg(builder.rustdoc(compiler));
1093 1094
        }

S
Santiago Pastorino 已提交
1095 1096 1097 1098 1099 1100
        cmd.arg("--src-base")
            .arg(builder.src.join("src/test").join(suite));
        cmd.arg("--build-base")
            .arg(testdir(builder, compiler.host).join(suite));
        cmd.arg("--stage-id")
            .arg(format!("stage{}-{}", compiler.stage, target));
1101 1102
        cmd.arg("--mode").arg(mode);
        cmd.arg("--target").arg(target);
1103
        cmd.arg("--host").arg(&*compiler.host);
S
Santiago Pastorino 已提交
1104 1105
        cmd.arg("--llvm-filecheck")
            .arg(builder.llvm_filecheck(builder.config.build));
1106

1107
        if builder.config.cmd.bless() {
1108 1109 1110
            cmd.arg("--bless");
        }

1111 1112 1113 1114 1115 1116 1117
        let compare_mode = builder.config.cmd.compare_mode().or_else(|| {
            if builder.config.test_compare_mode {
                self.compare_mode
            } else {
                None
            }
        });
S
Santiago Pastorino 已提交
1118

1119 1120 1121 1122 1123
        if let Some(ref pass) = builder.config.cmd.pass() {
            cmd.arg("--pass");
            cmd.arg(pass);
        }

1124
        if let Some(ref nodejs) = builder.config.nodejs {
1125 1126
            cmd.arg("--nodejs").arg(nodejs);
        }
1127

1128
        let mut flags = if is_rustdoc {
G
Guillaume Gomez 已提交
1129 1130 1131 1132
            Vec::new()
        } else {
            vec!["-Crpath".to_string()]
        };
1133
        if !is_rustdoc {
1134
            if builder.config.rust_optimize_tests {
G
Guillaume Gomez 已提交
1135 1136
                flags.push("-O".to_string());
            }
1137
        }
1138
        flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
G
Guillaume Gomez 已提交
1139
        flags.push("-Zunstable-options".to_string());
1140
        flags.push(builder.config.cmd.rustc_args().join(" "));
1141

1142
        if let Some(linker) = builder.linker(target) {
O
Oliver Schneider 已提交
1143 1144 1145
            cmd.arg("--linker").arg(linker);
        }

1146 1147 1148 1149 1150
        let mut hostflags = flags.clone();
        hostflags.push(format!(
            "-Lnative={}",
            builder.test_helpers_out(compiler.host).display()
        ));
1151 1152
        cmd.arg("--host-rustcflags").arg(hostflags.join(" "));

S
Shotaro Yamada 已提交
1153
        let mut targetflags = flags;
S
Santiago Pastorino 已提交
1154 1155 1156 1157
        targetflags.push(format!(
            "-Lnative={}",
            builder.test_helpers_out(target).display()
        ));
1158 1159
        cmd.arg("--target-rustcflags").arg(targetflags.join(" "));

1160
        cmd.arg("--docck-python").arg(builder.python());
1161

1162
        if builder.config.build.ends_with("apple-darwin") {
1163 1164 1165 1166 1167
            // Force /usr/bin/python on macOS for LLDB tests because we're loading the
            // LLDB plugin's compiled module which only works with the system python
            // (namely not Homebrew-installed python)
            cmd.arg("--lldb-python").arg("/usr/bin/python");
        } else {
1168
            cmd.arg("--lldb-python").arg(builder.python());
1169
        }
1170

1171
        if let Some(ref gdb) = builder.config.gdb {
1172 1173
            cmd.arg("--gdb").arg(gdb);
        }
1174 1175 1176 1177 1178 1179 1180 1181 1182

        let run = |cmd: &mut Command| {
            cmd.output().map(|output| {
                String::from_utf8_lossy(&output.stdout)
                    .lines().next().unwrap_or_else(|| {
                        panic!("{:?} failed {:?}", cmd, output)
                    }).to_string()
            })
        };
1183
        let lldb_exe = if builder.config.lldb_enabled {
1184
            // Test against the lldb that was just built.
1185
            builder.llvm_out(target).join("bin").join("lldb")
1186 1187 1188 1189 1190 1191 1192 1193 1194
        } else {
            PathBuf::from("lldb")
        };
        let lldb_version = Command::new(&lldb_exe)
            .arg("--version")
            .output()
            .map(|output| { String::from_utf8_lossy(&output.stdout).to_string() })
            .ok();
        if let Some(ref vers) = lldb_version {
1195
            cmd.arg("--lldb-version").arg(vers);
1196 1197 1198 1199
            let lldb_python_dir = run(Command::new(&lldb_exe).arg("-P")).ok();
            if let Some(ref dir) = lldb_python_dir {
                cmd.arg("--lldb-python-dir").arg(dir);
            }
1200
        }
1201

1202 1203 1204
        if util::forcing_clang_based_tests() {
            let clang_exe = builder.llvm_out(target).join("bin").join("clang");
            cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
1205 1206
        }

1207 1208
        // Get paths from cmd args
        let paths = match &builder.config.cmd {
S
Santiago Pastorino 已提交
1209 1210
            Subcommand::Test { ref paths, .. } => &paths[..],
            _ => &[],
1211 1212 1213
        };

        // Get test-args by striping suite path
S
Santiago Pastorino 已提交
1214 1215
        let mut test_args: Vec<&str> = paths
            .iter()
1216 1217 1218 1219 1220 1221
            .map(|p| {
                match p.strip_prefix(".") {
                    Ok(path) => path,
                    Err(_) => p,
                }
            })
1222 1223
            .filter(|p| p.starts_with(suite_path) && (p.is_dir() || p.is_file()))
            .filter_map(|p| {
V
varkor 已提交
1224 1225 1226 1227 1228 1229
                // Since test suite paths are themselves directories, if we don't
                // specify a directory or file, we'll get an empty string here
                // (the result of the test suite directory without its suite prefix).
                // Therefore, we need to filter these out, as only the first --test-args
                // flag is respected, so providing an empty --test-args conflicts with
                // any following it.
1230 1231 1232 1233 1234
                match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
                    Some(s) if s != "" => Some(s),
                    _ => None,
                }
            })
S
Santiago Pastorino 已提交
1235
            .collect();
1236 1237 1238 1239

        test_args.append(&mut builder.config.cmd.test_args());

        cmd.args(&test_args);
1240

1241
        if builder.is_verbose() {
1242 1243
            cmd.arg("--verbose");
        }
1244

O
Oliver Schneider 已提交
1245
        if !builder.config.verbose_tests {
1246 1247
            cmd.arg("--quiet");
        }
1248

B
bjorn3 已提交
1249
        if builder.config.llvm_enabled() {
1250
            let llvm_config = builder.ensure(native::Llvm {
1251
                target: builder.config.build,
1252
            });
1253
            if !builder.config.dry_run {
1254 1255 1256
                let llvm_version = output(Command::new(&llvm_config).arg("--version"));
                cmd.arg("--llvm-version").arg(llvm_version);
            }
1257
            if !builder.is_rust_llvm(target) {
B
bjorn3 已提交
1258 1259 1260 1261 1262
                cmd.arg("--system-llvm");
            }

            // Only pass correct values for these flags for the `run-make` suite as it
            // requires that a C++ compiler was configured which isn't always the case.
E
Eric Huss 已提交
1263
            if !builder.config.dry_run && suite == "run-make-fulldeps" {
B
bjorn3 已提交
1264 1265
                let llvm_components = output(Command::new(&llvm_config).arg("--components"));
                let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
S
Santiago Pastorino 已提交
1266 1267 1268 1269 1270
                cmd.arg("--cc")
                    .arg(builder.cc(target))
                    .arg("--cxx")
                    .arg(builder.cxx(target).unwrap())
                    .arg("--cflags")
1271
                    .arg(builder.cflags(target, GitRepo::Rustc).join(" "))
S
Santiago Pastorino 已提交
1272 1273 1274 1275
                    .arg("--llvm-components")
                    .arg(llvm_components.trim())
                    .arg("--llvm-cxxflags")
                    .arg(llvm_cxxflags.trim());
1276
                if let Some(ar) = builder.ar(target) {
O
Oliver Schneider 已提交
1277 1278
                    cmd.arg("--ar").arg(ar);
                }
1279 1280 1281 1282 1283 1284 1285

                // The llvm/bin directory contains many useful cross-platform
                // tools. Pass the path to run-make tests so they can use them.
                let llvm_bin_path = llvm_config.parent()
                    .expect("Expected llvm-config to be contained in directory");
                assert!(llvm_bin_path.is_dir());
                cmd.arg("--llvm-bin-dir").arg(llvm_bin_path);
1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300

                // If LLD is available, add it to the PATH
                if builder.config.lld_enabled {
                    let lld_install_root = builder.ensure(native::Lld {
                        target: builder.config.build,
                    });

                    let lld_bin_path = lld_install_root.join("bin");

                    let old_path = env::var_os("PATH").unwrap_or_default();
                    let new_path = env::join_paths(std::iter::once(lld_bin_path)
                        .chain(env::split_paths(&old_path)))
                        .expect("Could not add LLD bin path to PATH");
                    cmd.env("PATH", new_path);
                }
B
bjorn3 已提交
1301 1302 1303
            }
        }

E
Eric Huss 已提交
1304
        if suite != "run-make-fulldeps" {
S
Santiago Pastorino 已提交
1305 1306 1307 1308 1309 1310 1311 1312 1313 1314
            cmd.arg("--cc")
                .arg("")
                .arg("--cxx")
                .arg("")
                .arg("--cflags")
                .arg("")
                .arg("--llvm-components")
                .arg("")
                .arg("--llvm-cxxflags")
                .arg("");
1315
        }
1316

1317
        if builder.remote_tested(target) {
S
Santiago Pastorino 已提交
1318 1319
            cmd.arg("--remote-test-client")
                .arg(builder.tool_exe(Tool::RemoteTestClient));
1320
        }
1321

1322 1323 1324 1325 1326 1327
        // Running a C compiler on MSVC requires a few env vars to be set, to be
        // sure to set them here.
        //
        // Note that if we encounter `PATH` we make sure to append to our own `PATH`
        // rather than stomp over it.
        if target.contains("msvc") {
1328
            for &(ref k, ref v) in builder.cc[&target].env() {
1329 1330 1331
                if k != "PATH" {
                    cmd.env(k, v);
                }
1332 1333
            }
        }
1334
        cmd.env("RUSTC_BOOTSTRAP", "1");
1335
        builder.add_rust_test_threads(&mut cmd);
1336

1337
        if builder.config.sanitizers {
1338
            cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
1339
        }
1340

1341
        if builder.config.profiler {
1342
            cmd.env("RUSTC_PROFILER_SUPPORT", "1");
1343
        }
1344

M
Mark Rousskov 已提交
1345 1346 1347 1348
        let tmp = builder.out.join("tmp");
        std::fs::create_dir_all(&tmp).unwrap();
        cmd.env("RUST_TEST_TMPDIR", tmp);

1349

1350 1351 1352 1353 1354
        cmd.arg("--adb-path").arg("adb");
        cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
        if target.contains("android") {
            // Assume that cc for this target comes from the android sysroot
            cmd.arg("--android-cross-path")
S
Santiago Pastorino 已提交
1355
                .arg(builder.cc(target).parent().unwrap().parent().unwrap());
1356 1357 1358
        } else {
            cmd.arg("--android-cross-path").arg("");
        }
1359

1360 1361 1362 1363
        if builder.config.cmd.rustfix_coverage() {
            cmd.arg("--rustfix-coverage");
        }

1364
        builder.ci_env.force_coloring_in_ci(&mut cmd);
1365

S
Santiago Pastorino 已提交
1366 1367 1368 1369
        builder.info(&format!(
            "Check compiletest suite={} mode={} ({} -> {})",
            suite, mode, &compiler.host, target
        ));
1370 1371
        let _time = util::timeit(&builder);
        try_run(builder, &mut cmd);
1372 1373 1374

        if let Some(compare_mode) = compare_mode {
            cmd.arg("--compare-mode").arg(compare_mode);
S
Santiago Pastorino 已提交
1375 1376 1377 1378
            builder.info(&format!(
                "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
                suite, mode, compare_mode, &compiler.host, target
            ));
1379 1380 1381
            let _time = util::timeit(&builder);
            try_run(builder, &mut cmd);
        }
1382
    }
1383
}
1384

1385
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1386
struct DocTest {
1387
    compiler: Compiler,
1388 1389 1390
    path: &'static str,
    name: &'static str,
    is_ext_doc: bool,
1391 1392
}

1393
impl Step for DocTest {
1394 1395
    type Output = ();
    const ONLY_HOSTS: bool = true;
1396

T
Taiki Endo 已提交
1397
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1398
        run.never()
1399
    }
M
Mark Simulacrum 已提交
1400

A
Alexander Regueiro 已提交
1401
    /// Runs `rustdoc --test` for all documentation in `src/doc`.
1402
    ///
1403
    /// This will run all tests in our markdown documentation (e.g., the book)
1404 1405
    /// located in `src/doc`. The `rustdoc` that's run is the one that sits next to
    /// `compiler`.
T
Taiki Endo 已提交
1406
    fn run(self, builder: &Builder<'_>) {
1407
        let compiler = self.compiler;
1408

1409
        builder.ensure(compile::Std {
S
Santiago Pastorino 已提交
1410 1411 1412
            compiler,
            target: compiler.host,
        });
1413

1414 1415
        // Do a breadth-first traversal of the `src/doc` directory and just run
        // tests for all files that end in `*.md`
1416 1417
        let mut stack = vec![builder.src.join(self.path)];
        let _time = util::timeit(&builder);
1418

1419
        let mut files = Vec::new();
1420 1421 1422
        while let Some(p) = stack.pop() {
            if p.is_dir() {
                stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
S
Santiago Pastorino 已提交
1423
                continue;
1424 1425 1426 1427 1428 1429 1430
            }

            if p.extension().and_then(|s| s.to_str()) != Some("md") {
                continue;
            }

            // The nostarch directory in the book is for no starch, and so isn't
1431
            // guaranteed to builder. We don't care if it doesn't build, so skip it.
1432 1433 1434 1435
            if p.to_str().map_or(false, |p| p.contains("nostarch")) {
                continue;
            }

1436 1437 1438 1439 1440
            files.push(p);
        }

        files.sort();

1441
        let mut toolstate = ToolState::TestPass;
1442
        for file in files {
1443 1444
            if !markdown_test(builder, compiler, &file) {
                toolstate = ToolState::TestFail;
1445
            }
1446
        }
1447 1448 1449
        if self.is_ext_doc {
            builder.save_toolstate(self.name, toolstate);
        }
1450 1451 1452
    }
}

1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465
macro_rules! test_book {
    ($($name:ident, $path:expr, $book_name:expr, default=$default:expr;)+) => {
        $(
            #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
            pub struct $name {
                compiler: Compiler,
            }

            impl Step for $name {
                type Output = ();
                const DEFAULT: bool = $default;
                const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
1466
                fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1467 1468 1469
                    run.path($path)
                }

T
Taiki Endo 已提交
1470
                fn make_run(run: RunConfig<'_>) {
1471 1472 1473 1474 1475
                    run.builder.ensure($name {
                        compiler: run.builder.compiler(run.builder.top_stage, run.host),
                    });
                }

T
Taiki Endo 已提交
1476
                fn run(self, builder: &Builder<'_>) {
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492
                    builder.ensure(DocTest {
                        compiler: self.compiler,
                        path: $path,
                        name: $book_name,
                        is_ext_doc: !$default,
                    });
                }
            }
        )+
    }
}

test_book!(
    Nomicon, "src/doc/nomicon", "nomicon", default=false;
    Reference, "src/doc/reference", "reference", default=false;
    RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
1493
    RustcBook, "src/doc/rustc", "rustc", default=true;
1494
    RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false;
1495
    EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false;
1496 1497
    TheBook, "src/doc/book", "book", default=false;
    UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
E
Eric Huss 已提交
1498
    EditionGuide, "src/doc/edition-guide", "edition-guide", default=false;
1499 1500
);

1501 1502 1503
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ErrorIndex {
    compiler: Compiler,
1504
}
1505

1506
impl Step for ErrorIndex {
1507
    type Output = ();
1508 1509 1510
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
1511
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1512
        run.path("src/tools/error_index_generator")
1513 1514
    }

T
Taiki Endo 已提交
1515
    fn make_run(run: RunConfig<'_>) {
1516 1517
        run.builder.ensure(ErrorIndex {
            compiler: run.builder.compiler(run.builder.top_stage, run.host),
1518 1519
        });
    }
1520

A
Alexander Regueiro 已提交
1521
    /// Runs the error index generator tool to execute the tests located in the error
1522 1523 1524 1525 1526
    /// index.
    ///
    /// The `error_index_generator` tool lives in `src/tools` and is used to
    /// generate a markdown file from the error indexes of the code base which is
    /// then passed to `rustdoc --test`.
T
Taiki Endo 已提交
1527
    fn run(self, builder: &Builder<'_>) {
1528 1529
        let compiler = self.compiler;

S
Santiago Pastorino 已提交
1530 1531 1532 1533
        builder.ensure(compile::Std {
            compiler,
            target: compiler.host,
        });
1534

1535
        let dir = testdir(builder, compiler.host);
1536 1537 1538
        t!(fs::create_dir_all(&dir));
        let output = dir.join("error-index.md");

1539 1540 1541 1542
        let mut tool = tool::ErrorIndex::command(
            builder,
            builder.compiler(compiler.stage, builder.config.build),
        );
1543 1544
        tool.arg("markdown")
            .arg(&output)
1545
            .env("CFG_BUILD", &builder.config.build);
1546

1547 1548
        builder.info(&format!("Testing error-index stage{}", compiler.stage));
        let _time = util::timeit(&builder);
1549
        builder.run_quiet(&mut tool);
1550
        markdown_test(builder, compiler, &output);
1551
    }
1552 1553
}

T
Taiki Endo 已提交
1554
fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
1555 1556
    match fs::read_to_string(markdown) {
        Ok(contents) => {
1557 1558 1559 1560
            if !contents.contains("```") {
                return true;
            }
        }
S
Santiago Pastorino 已提交
1561
        Err(_) => {}
1562 1563
    }

1564
    builder.info(&format!("doc tests for: {}", markdown.display()));
M
Mark Rousskov 已提交
1565
    let mut cmd = builder.rustdoc_cmd(compiler);
1566
    builder.add_rust_test_threads(&mut cmd);
1567 1568
    cmd.arg("--test");
    cmd.arg(markdown);
1569
    cmd.env("RUSTC_BOOTSTRAP", "1");
1570

1571
    let test_args = builder.config.cmd.test_args().join(" ");
1572 1573
    cmd.arg("--test-args").arg(test_args);

O
Oliver Schneider 已提交
1574
    if builder.config.verbose_tests {
1575
        try_run(builder, &mut cmd)
O
Oliver Schneider 已提交
1576 1577
    } else {
        try_run_quiet(builder, &mut cmd)
1578
    }
1579
}
1580

1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RustcGuide;

impl Step for RustcGuide {
    type Output = ();
    const DEFAULT: bool = false;
    const ONLY_HOSTS: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.path("src/doc/rustc-guide")
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(RustcGuide);
    }

    fn run(self, builder: &Builder<'_>) {
        let src = builder.src.join("src/doc/rustc-guide");
        let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
E
Eric Huss 已提交
1600 1601 1602 1603 1604 1605
        let toolstate = if try_run(builder, rustbook_cmd.arg("linkcheck").arg(&src)) {
            ToolState::TestPass
        } else {
            ToolState::TestFail
        };
        builder.save_toolstate("rustc-guide", toolstate);
1606 1607 1608
    }
}

1609
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
M
Mark Simulacrum 已提交
1610
pub struct CrateLibrustc {
1611 1612
    compiler: Compiler,
    target: Interned<String>,
1613
    test_kind: TestKind,
1614
    krate: Interned<String>,
1615 1616
}

M
Mark Simulacrum 已提交
1617
impl Step for CrateLibrustc {
1618 1619 1620 1621
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
1622
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1623
        run.krate("rustc-main")
1624 1625
    }

T
Taiki Endo 已提交
1626
    fn make_run(run: RunConfig<'_>) {
1627 1628
        let builder = run.builder;
        let compiler = builder.compiler(builder.top_stage, run.host);
1629

1630 1631
        for krate in builder.in_tree_crates("rustc-main") {
            if run.path.ends_with(&krate.path) {
1632
                let test_kind = builder.kind.into();
1633

1634 1635 1636 1637 1638 1639
                builder.ensure(CrateLibrustc {
                    compiler,
                    target: run.target,
                    test_kind,
                    krate: krate.name,
                });
1640 1641 1642 1643
            }
        }
    }

T
Taiki Endo 已提交
1644
    fn run(self, builder: &Builder<'_>) {
M
Mark Simulacrum 已提交
1645
        builder.ensure(Crate {
1646 1647
            compiler: self.compiler,
            target: self.target,
C
Collins Abitekaniza 已提交
1648
            mode: Mode::Rustc,
1649 1650 1651 1652 1653 1654
            test_kind: self.test_kind,
            krate: self.krate,
        });
    }
}

1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CrateNotDefault {
    compiler: Compiler,
    target: Interned<String>,
    test_kind: TestKind,
    krate: &'static str,
}

impl Step for CrateNotDefault {
    type Output = ();

T
Taiki Endo 已提交
1666
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1667
        run.path("src/librustc_asan")
1668 1669 1670 1671 1672
            .path("src/librustc_lsan")
            .path("src/librustc_msan")
            .path("src/librustc_tsan")
    }

T
Taiki Endo 已提交
1673
    fn make_run(run: RunConfig<'_>) {
1674 1675 1676
        let builder = run.builder;
        let compiler = builder.compiler(builder.top_stage, run.host);

1677
        let test_kind = builder.kind.into();
1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692

        builder.ensure(CrateNotDefault {
            compiler,
            target: run.target,
            test_kind,
            krate: match run.path {
                _ if run.path.ends_with("src/librustc_asan") => "rustc_asan",
                _ if run.path.ends_with("src/librustc_lsan") => "rustc_lsan",
                _ if run.path.ends_with("src/librustc_msan") => "rustc_msan",
                _ if run.path.ends_with("src/librustc_tsan") => "rustc_tsan",
                _ => panic!("unexpected path {:?}", run.path),
            },
        });
    }

T
Taiki Endo 已提交
1693
    fn run(self, builder: &Builder<'_>) {
1694 1695 1696
        builder.ensure(Crate {
            compiler: self.compiler,
            target: self.target,
C
Collins Abitekaniza 已提交
1697
            mode: Mode::Std,
1698 1699 1700 1701 1702 1703
            test_kind: self.test_kind,
            krate: INTERNER.intern_str(self.krate),
        });
    }
}

K
kennytm 已提交
1704
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
M
Mark Simulacrum 已提交
1705
pub struct Crate {
K
kennytm 已提交
1706 1707 1708 1709 1710
    pub compiler: Compiler,
    pub target: Interned<String>,
    pub mode: Mode,
    pub test_kind: TestKind,
    pub krate: Interned<String>,
1711
}
1712

M
Mark Simulacrum 已提交
1713
impl Step for Crate {
1714
    type Output = ();
1715 1716
    const DEFAULT: bool = true;

T
Taiki Endo 已提交
1717
    fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
1718
        let builder = run.builder;
1719
        for krate in run.builder.in_tree_crates("test") {
1720
            if !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) {
1721 1722 1723 1724
                run = run.path(krate.local_path(&builder).to_str().unwrap());
            }
        }
        run
1725 1726
    }

T
Taiki Endo 已提交
1727
    fn make_run(run: RunConfig<'_>) {
1728 1729
        let builder = run.builder;
        let compiler = builder.compiler(builder.top_stage, run.host);
1730

1731
        let make = |mode: Mode, krate: &CargoCrate| {
1732
            let test_kind = builder.kind.into();
1733

M
Mark Simulacrum 已提交
1734
            builder.ensure(Crate {
1735 1736
                compiler,
                target: run.target,
1737 1738
                mode,
                test_kind,
1739
                krate: krate.name,
1740 1741 1742
            });
        };

1743 1744
        for krate in builder.in_tree_crates("test") {
            if run.path.ends_with(&krate.local_path(&builder)) {
1745
                make(Mode::Std, krate);
1746 1747 1748
            }
        }
    }
1749

A
Alexander Regueiro 已提交
1750
    /// Runs all unit tests plus documentation tests for a given crate defined
1751
    /// by a `Cargo.toml` (single manifest)
1752 1753 1754 1755 1756 1757
    ///
    /// This is what runs tests for crates like the standard library, compiler, etc.
    /// It essentially is the driver for running `cargo test`.
    ///
    /// Currently this runs all tests for a DAG by passing a bunch of `-p foo`
    /// arguments, and those arguments are discovered from `cargo metadata`.
T
Taiki Endo 已提交
1758
    fn run(self, builder: &Builder<'_>) {
1759 1760 1761 1762 1763 1764
        let compiler = self.compiler;
        let target = self.target;
        let mode = self.mode;
        let test_kind = self.test_kind;
        let krate = self.krate;

1765
        builder.ensure(compile::Std { compiler, target });
1766
        builder.ensure(RemoteCopyLibs { compiler, target });
A
Alex Crichton 已提交
1767

1768 1769 1770 1771 1772
        // If we're not doing a full bootstrap but we're testing a stage2
        // version of libstd, then what we're actually testing is the libstd
        // produced in stage1. Reflect that here by updating the compiler that
        // we're working with automatically.
        let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
A
Alex Crichton 已提交
1773 1774

        let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand());
1775
        match mode {
C
Collins Abitekaniza 已提交
1776
            Mode::Std => {
1777
                compile::std_cargo(builder, &compiler, target, &mut cargo);
1778
            }
C
Collins Abitekaniza 已提交
1779
            Mode::Rustc => {
1780
                builder.ensure(compile::Rustc { compiler, target });
1781
                compile::rustc_cargo(builder, &mut cargo);
1782 1783 1784 1785 1786 1787 1788 1789 1790
            }
            _ => panic!("can only test libraries"),
        };

        // Build up the base `cargo test` command.
        //
        // Pass in some standard flags then iterate over the graph we've discovered
        // in `cargo metadata` with the maps above and figure out what `-p`
        // arguments need to get passed.
1791
        if test_kind.subcommand() == "test" && !builder.fail_fast {
1792 1793
            cargo.arg("--no-fail-fast");
        }
K
kennytm 已提交
1794
        match builder.doc_tests {
K
kennytm 已提交
1795
            DocTests::Only => {
K
kennytm 已提交
1796 1797
                cargo.arg("--doc");
            }
K
kennytm 已提交
1798
            DocTests::No => {
K
kennytm 已提交
1799 1800
                cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
            }
K
kennytm 已提交
1801
            DocTests::Yes => {}
1802
        }
1803

1804
        cargo.arg("-p").arg(krate);
1805

1806 1807 1808 1809 1810 1811
        // The tests are going to run with the *target* libraries, so we need to
        // ensure that those libraries show up in the LD_LIBRARY_PATH equivalent.
        //
        // Note that to run the compiler we need to run with the *host* libraries,
        // but our wrapper scripts arrange for that to be the case anyway.
        let mut dylib_path = dylib_path();
1812
        dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
1813 1814 1815
        cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());

        cargo.arg("--");
1816
        cargo.args(&builder.config.cmd.test_args());
1817

O
Oliver Schneider 已提交
1818
        if !builder.config.verbose_tests {
1819 1820
            cargo.arg("--quiet");
        }
1821

1822
        if target.contains("emscripten") {
S
Santiago Pastorino 已提交
1823 1824 1825 1826 1827 1828 1829 1830
            cargo.env(
                format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
                builder
                    .config
                    .nodejs
                    .as_ref()
                    .expect("nodejs not configured"),
            );
O
Oliver Schneider 已提交
1831
        } else if target.starts_with("wasm32") {
S
Santiago Pastorino 已提交
1832 1833 1834 1835
            let node = builder
                .config
                .nodejs
                .as_ref()
O
Oliver Schneider 已提交
1836
                .expect("nodejs not configured");
S
Santiago Pastorino 已提交
1837 1838 1839 1840 1841
            let runner = format!(
                "{} {}/src/etc/wasm32-shim.js",
                node.display(),
                builder.src.display()
            );
O
Oliver Schneider 已提交
1842
            cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner);
1843
        } else if builder.remote_tested(target) {
S
Santiago Pastorino 已提交
1844 1845 1846 1847
            cargo.env(
                format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
                format!("{} run", builder.tool_exe(Tool::RemoteTestClient).display()),
            );
1848
        }
1849

S
Santiago Pastorino 已提交
1850 1851 1852 1853
        builder.info(&format!(
            "{} {} stage{} ({} -> {})",
            test_kind, krate, compiler.stage, &compiler.host, target
        ));
1854
        let _time = util::timeit(&builder);
1855
        try_run(builder, &mut cargo.into());
1856 1857
    }
}
1858

M
Mark Simulacrum 已提交
1859
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1860
pub struct CrateRustdoc {
M
Mark Simulacrum 已提交
1861 1862 1863 1864
    host: Interned<String>,
    test_kind: TestKind,
}

1865
impl Step for CrateRustdoc {
M
Mark Simulacrum 已提交
1866 1867 1868 1869
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
1870
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1871
        run.paths(&["src/librustdoc", "src/tools/rustdoc"])
M
Mark Simulacrum 已提交
1872 1873
    }

T
Taiki Endo 已提交
1874
    fn make_run(run: RunConfig<'_>) {
M
Mark Simulacrum 已提交
1875 1876
        let builder = run.builder;

1877
        let test_kind = builder.kind.into();
M
Mark Simulacrum 已提交
1878

1879
        builder.ensure(CrateRustdoc {
M
Mark Simulacrum 已提交
1880 1881 1882 1883 1884
            host: run.host,
            test_kind,
        });
    }

T
Taiki Endo 已提交
1885
    fn run(self, builder: &Builder<'_>) {
M
Mark Simulacrum 已提交
1886 1887 1888 1889
        let test_kind = self.test_kind;

        let compiler = builder.compiler(builder.top_stage, self.host);
        let target = compiler.host;
1890
        builder.ensure(compile::Rustc { compiler, target });
M
Mark Simulacrum 已提交
1891

C
Collins Abitekaniza 已提交
1892 1893
        let mut cargo = tool::prepare_tool_cargo(builder,
                                                 compiler,
C
Collins Abitekaniza 已提交
1894
                                                 Mode::ToolRustc,
C
Collins Abitekaniza 已提交
1895 1896
                                                 target,
                                                 test_kind.subcommand(),
1897
                                                 "src/tools/rustdoc",
1898 1899
                                                 SourceType::InTree,
                                                 &[]);
1900
        if test_kind.subcommand() == "test" && !builder.fail_fast {
M
Mark Simulacrum 已提交
1901 1902 1903 1904 1905 1906
            cargo.arg("--no-fail-fast");
        }

        cargo.arg("-p").arg("rustdoc:0.0.0");

        cargo.arg("--");
1907
        cargo.args(&builder.config.cmd.test_args());
M
Mark Simulacrum 已提交
1908

1909 1910 1911 1912
        if self.host.contains("musl") {
            cargo.arg("'-Ctarget-feature=-crt-static'");
        }

O
Oliver Schneider 已提交
1913
        if !builder.config.verbose_tests {
M
Mark Simulacrum 已提交
1914 1915 1916
            cargo.arg("--quiet");
        }

S
Santiago Pastorino 已提交
1917 1918 1919 1920
        builder.info(&format!(
            "{} rustdoc stage{} ({} -> {})",
            test_kind, compiler.stage, &compiler.host, target
        ));
1921
        let _time = util::timeit(&builder);
M
Mark Simulacrum 已提交
1922

1923
        try_run(builder, &mut cargo.into());
M
Mark Simulacrum 已提交
1924 1925 1926
    }
}

1927 1928 1929 1930 1931
/// Some test suites are run inside emulators or on remote devices, and most
/// of our test binaries are linked dynamically which means we need to ship
/// the standard library and such to the emulator ahead of time. This step
/// represents this and is a dependency of all test suites.
///
A
Alexander Regueiro 已提交
1932
/// Most of the time this is a no-op. For some steps such as shipping data to
1933 1934 1935
/// QEMU we have to build our own tools so we've got conditional dependencies
/// on those programs as well. Note that the remote test client is built for
/// the build target (us) and the server is built for the target.
1936 1937 1938 1939
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RemoteCopyLibs {
    compiler: Compiler,
    target: Interned<String>,
1940
}
1941

1942
impl Step for RemoteCopyLibs {
1943
    type Output = ();
1944

T
Taiki Endo 已提交
1945
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1946
        run.never()
1947 1948
    }

T
Taiki Endo 已提交
1949
    fn run(self, builder: &Builder<'_>) {
1950 1951
        let compiler = self.compiler;
        let target = self.target;
1952
        if !builder.remote_tested(target) {
S
Santiago Pastorino 已提交
1953
            return;
1954 1955
        }

1956
        builder.ensure(compile::Std { compiler, target });
1957

1958 1959
        builder.info(&format!("REMOTE copy libs to emulator ({})", target));
        t!(fs::create_dir_all(builder.out.join("tmp")));
1960

1961 1962 1963 1964
        let server = builder.ensure(tool::RemoteTestServer {
            compiler: compiler.with_stage(0),
            target,
        });
1965 1966

        // Spawn the emulator and wait for it to come online
1967
        let tool = builder.tool_exe(Tool::RemoteTestClient);
1968 1969
        let mut cmd = Command::new(&tool);
        cmd.arg("spawn-emulator")
S
Santiago Pastorino 已提交
1970 1971 1972
            .arg(target)
            .arg(&server)
            .arg(builder.out.join("tmp"));
1973
        if let Some(rootfs) = builder.qemu_rootfs(target) {
1974 1975
            cmd.arg(rootfs);
        }
1976
        builder.run(&mut cmd);
1977 1978

        // Push all our dylibs to the emulator
1979
        for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) {
1980 1981 1982
            let f = t!(f);
            let name = f.file_name().into_string().unwrap();
            if util::is_dylib(&name) {
S
Santiago Pastorino 已提交
1983
                builder.run(Command::new(&tool).arg("push").arg(f.path()));
1984
            }
1985 1986 1987 1988
        }
    }
}

1989
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1990
pub struct Distcheck;
A
Alex Crichton 已提交
1991

1992
impl Step for Distcheck {
1993 1994
    type Output = ();

T
Taiki Endo 已提交
1995
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1996
        run.path("distcheck")
1997 1998
    }

T
Taiki Endo 已提交
1999
    fn make_run(run: RunConfig<'_>) {
M
Mark Simulacrum 已提交
2000 2001 2002
        run.builder.ensure(Distcheck);
    }

A
Alexander Regueiro 已提交
2003
    /// Runs "distcheck", a 'make check' from a tarball
T
Taiki Endo 已提交
2004
    fn run(self, builder: &Builder<'_>) {
2005
        builder.info("Distcheck");
2006
        let dir = builder.out.join("tmp").join("distcheck");
2007 2008 2009
        let _ = fs::remove_dir_all(&dir);
        t!(fs::create_dir_all(&dir));

M
Mark Simulacrum 已提交
2010 2011 2012 2013
        // Guarantee that these are built before we begin running.
        builder.ensure(dist::PlainSourceTarball);
        builder.ensure(dist::Src);

2014 2015
        let mut cmd = Command::new("tar");
        cmd.arg("-xzf")
S
Santiago Pastorino 已提交
2016 2017 2018
            .arg(builder.ensure(dist::PlainSourceTarball))
            .arg("--strip-components=1")
            .current_dir(&dir);
2019
        builder.run(&mut cmd);
S
Santiago Pastorino 已提交
2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030
        builder.run(
            Command::new("./configure")
                .args(&builder.config.configure_args)
                .arg("--enable-vendor")
                .current_dir(&dir),
        );
        builder.run(
            Command::new(build_helper::make(&builder.config.build))
                .arg("check")
                .current_dir(&dir),
        );
2031 2032

        // Now make sure that rust-src has all of libstd's dependencies
2033
        builder.info("Distcheck rust-src");
2034
        let dir = builder.out.join("tmp").join("distcheck-src");
2035 2036 2037 2038 2039
        let _ = fs::remove_dir_all(&dir);
        t!(fs::create_dir_all(&dir));

        let mut cmd = Command::new("tar");
        cmd.arg("-xzf")
S
Santiago Pastorino 已提交
2040 2041 2042
            .arg(builder.ensure(dist::Src))
            .arg("--strip-components=1")
            .current_dir(&dir);
2043
        builder.run(&mut cmd);
2044 2045

        let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml");
S
Santiago Pastorino 已提交
2046 2047 2048 2049 2050 2051 2052
        builder.run(
            Command::new(&builder.initial_cargo)
                .arg("generate-lockfile")
                .arg("--manifest-path")
                .arg(&toml)
                .current_dir(&dir),
        );
2053
    }
A
Alex Crichton 已提交
2054
}
2055

2056
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2057 2058
pub struct Bootstrap;

2059
impl Step for Bootstrap {
2060
    type Output = ();
2061 2062
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;
2063

A
Alexander Regueiro 已提交
2064
    /// Tests the build system itself.
T
Taiki Endo 已提交
2065
    fn run(self, builder: &Builder<'_>) {
2066
        let mut cmd = Command::new(&builder.initial_cargo);
2067
        cmd.arg("test")
S
Santiago Pastorino 已提交
2068 2069 2070 2071 2072
            .current_dir(builder.src.join("src/bootstrap"))
            .env("RUSTFLAGS", "-Cdebuginfo=2")
            .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
            .env("RUSTC_BOOTSTRAP", "1")
            .env("RUSTC", &builder.initial_rustc);
2073 2074 2075 2076 2077 2078
        if let Some(flags) = option_env!("RUSTFLAGS") {
            // Use the same rustc flags for testing as for "normal" compilation,
            // so that Cargo doesn’t recompile the entire dependency graph every time:
            // https://github.com/rust-lang/rust/issues/49215
            cmd.env("RUSTFLAGS", flags);
        }
2079
        if !builder.fail_fast {
2080 2081
            cmd.arg("--no-fail-fast");
        }
2082
        cmd.arg("--").args(&builder.config.cmd.test_args());
2083 2084 2085
        // rustbuild tests are racy on directory creation so just run them one at a time.
        // Since there's not many this shouldn't be a problem.
        cmd.arg("--test-threads=1");
2086
        try_run(builder, &mut cmd);
2087
    }
2088

T
Taiki Endo 已提交
2089
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2090
        run.path("src/bootstrap")
2091 2092
    }

T
Taiki Endo 已提交
2093
    fn make_run(run: RunConfig<'_>) {
2094
        run.builder.ensure(Bootstrap);
2095
    }
2096
}