test.rs 81.0 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;
10
use std::iter;
S
Santiago Pastorino 已提交
11
use std::path::{Path, PathBuf};
G
Guillaume Gomez 已提交
12
use std::process::{Command, Stdio};
13

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

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

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

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

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

U
Ulrik Sverdrup 已提交
50 51 52 53 54 55 56 57 58 59 60
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 已提交
61
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
U
Ulrik Sverdrup 已提交
62 63 64 65 66 67 68
        f.write_str(match *self {
            TestKind::Test => "Testing",
            TestKind::Bench => "Benchmarking",
        })
    }
}

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

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

95 96
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Linkcheck {
97
    host: TargetSelection,
98 99
}

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

    /// 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.
M
mark 已提交
109 110
    fn run(self, builder: &Builder<'_>) {
        let host = self.host;
111 112 113 114 115 116 117 118 119 120 121 122 123
        let hosts = &builder.hosts;
        let targets = &builder.targets;

        // if we have different hosts and targets, some things may be built for
        // the host (e.g. rustc) and others for the target (e.g. std). The
        // documentation built for each will contain broken links to
        // docs built for the other platform (e.g. rustc linking to cargo)
        if (hosts != targets) && !hosts.is_empty() && !targets.is_empty() {
            panic!(
                "Linkcheck currently does not support builds with different hosts and targets.
You can skip linkcheck with --exclude src/tools/linkchecker"
            );
        }
124

M
mark 已提交
125
        builder.info(&format!("Linkcheck ({})", host));
126

E
Eric Huss 已提交
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
        // Test the linkchecker itself.
        let bootstrap_host = builder.config.build;
        let compiler = builder.compiler(0, bootstrap_host);
        let cargo = tool::prepare_tool_cargo(
            builder,
            compiler,
            Mode::ToolBootstrap,
            bootstrap_host,
            "test",
            "src/tools/linkchecker",
            SourceType::InTree,
            &[],
        );
        try_run(builder, &mut cargo.into());

        // Build all the default documentation.
143
        builder.default_doc(&[]);
144

E
Eric Huss 已提交
145
        // Run the linkchecker.
M
mark 已提交
146 147 148 149 150
        let _time = util::timeit(&builder);
        try_run(
            builder,
            builder.tool_cmd(Tool::Linkchecker).arg(builder.out.join(host.triple).join("doc")),
        );
151
    }
152

T
Taiki Endo 已提交
153
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
154
        let builder = run.builder;
155 156
        let run = run.path("src/tools/linkchecker");
        run.default_condition(builder.config.docs)
157 158
    }

T
Taiki Endo 已提交
159
    fn make_run(run: RunConfig<'_>) {
160
        run.builder.ensure(Linkcheck { host: run.target });
161
    }
162
}
163

G
Guillaume Gomez 已提交
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
fn check_if_tidy_is_installed() -> bool {
    Command::new("tidy")
        .arg("--version")
        .stdout(Stdio::null())
        .status()
        .map_or(false, |status| status.success())
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct HtmlCheck {
    target: TargetSelection,
}

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

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        let run = run.path("src/tools/html-checker");
        run.lazy_default_condition(Box::new(check_if_tidy_is_installed))
    }

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

    fn run(self, builder: &Builder<'_>) {
        if !check_if_tidy_is_installed() {
            eprintln!("not running HTML-check tool because `tidy` is missing");
            eprintln!(
                "Note that `tidy` is not the in-tree `src/tools/tidy` but needs to be installed"
            );
            panic!("Cannot run html-check tests");
        }
        // Ensure that a few different kinds of documentation are available.
        builder.default_doc(&[]);
        builder.ensure(crate::doc::Rustc { target: self.target, stage: builder.top_stage });

        try_run(builder, builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)));
    }
}

207 208
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Cargotest {
209
    stage: u32,
210
    host: TargetSelection,
211
}
212

213
impl Step for Cargotest {
214
    type Output = ();
215
    const ONLY_HOSTS: bool = true;
216

T
Taiki Endo 已提交
217
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
218
        run.path("src/tools/cargotest")
219 220
    }

T
Taiki Endo 已提交
221
    fn make_run(run: RunConfig<'_>) {
M
Mark Rousskov 已提交
222
        run.builder.ensure(Cargotest { stage: run.builder.top_stage, host: run.target });
223 224
    }

225 226 227 228
    /// 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 已提交
229
    fn run(self, builder: &Builder<'_>) {
230
        let compiler = builder.compiler(self.stage, self.host);
M
Mark Rousskov 已提交
231
        builder.ensure(compile::Rustc { compiler, target: compiler.host });
E
Eric Huss 已提交
232
        let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host });
233 234 235 236

        // 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.
237
        let out_dir = builder.out.join("ct");
238 239
        t!(fs::create_dir_all(&out_dir));

240
        let _time = util::timeit(&builder);
241
        let mut cmd = builder.tool_cmd(Tool::CargoTest);
S
Santiago Pastorino 已提交
242 243
        try_run(
            builder,
E
Eric Huss 已提交
244
            cmd.arg(&cargo)
S
Santiago Pastorino 已提交
245
                .arg(&out_dir)
246
                .args(builder.config.cmd.test_args())
S
Santiago Pastorino 已提交
247
                .env("RUSTC", builder.rustc(compiler))
M
Mark Rousskov 已提交
248
                .env("RUSTDOC", builder.rustdoc(compiler)),
S
Santiago Pastorino 已提交
249
        );
250
    }
251 252
}

253 254
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Cargo {
255
    stage: u32,
256
    host: TargetSelection,
257 258
}

259
impl Step for Cargo {
260
    type Output = ();
261 262
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
263
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
264
        run.path("src/tools/cargo")
265 266
    }

T
Taiki Endo 已提交
267
    fn make_run(run: RunConfig<'_>) {
M
Mark Rousskov 已提交
268
        run.builder.ensure(Cargo { stage: run.builder.top_stage, host: run.target });
269
    }
270 271

    /// Runs `cargo test` for `cargo` packaged with Rust.
272 273
    fn run(self, builder: &Builder<'_>) {
        let compiler = builder.compiler(self.stage, self.host);
274

M
Mark Rousskov 已提交
275 276 277
        builder.ensure(tool::Cargo { compiler, target: self.host });
        let mut cargo = tool::prepare_tool_cargo(
            builder,
S
Santiago Pastorino 已提交
278
            compiler,
M
Mark Rousskov 已提交
279 280 281 282 283 284 285
            Mode::ToolRustc,
            self.host,
            "test",
            "src/tools/cargo",
            SourceType::Submodule,
            &[],
        );
286

287
        if !builder.fail_fast {
288 289
            cargo.arg("--no-fail-fast");
        }
290
        cargo.arg("--").args(builder.config.cmd.test_args());
291

292 293 294
        // Don't run cross-compile tests, we may not have cross-compiled libstd libs
        // available.
        cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
295 296
        // Disable a test that has issues with mingw.
        cargo.env("CARGO_TEST_DISABLE_GIT_CLI", "1");
297 298 299
        // 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");
300

301 302
        cargo.env("PATH", &path_for_cargo(builder, compiler));

303
        try_run(builder, &mut cargo.into());
304
    }
N
Nick Cameron 已提交
305 306
}

M
Mark Simulacrum 已提交
307 308
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rls {
309
    stage: u32,
310
    host: TargetSelection,
311
}
N
Nick Cameron 已提交
312

M
Mark Simulacrum 已提交
313
impl Step for Rls {
314
    type Output = ();
M
Mark Simulacrum 已提交
315 316
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
317
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
318
        run.path("src/tools/rls")
M
Mark Simulacrum 已提交
319 320
    }

T
Taiki Endo 已提交
321
    fn make_run(run: RunConfig<'_>) {
M
Mark Rousskov 已提交
322
        run.builder.ensure(Rls { stage: run.builder.top_stage, host: run.target });
M
Mark Simulacrum 已提交
323
    }
N
Nick Cameron 已提交
324

325
    /// Runs `cargo test` for the rls.
T
Taiki Endo 已提交
326
    fn run(self, builder: &Builder<'_>) {
327 328
        let stage = self.stage;
        let host = self.host;
M
Mark Simulacrum 已提交
329
        let compiler = builder.compiler(stage, host);
N
Nick Cameron 已提交
330

M
Mark Rousskov 已提交
331 332
        let build_result =
            builder.ensure(tool::Rls { compiler, target: self.host, extra_features: Vec::new() });
333 334 335 336 337
        if build_result.is_none() {
            eprintln!("failed to test rls: could not build");
            return;
        }

M
Mark Rousskov 已提交
338 339 340 341 342 343 344 345 346 347
        let mut cargo = tool::prepare_tool_cargo(
            builder,
            compiler,
            Mode::ToolRustc,
            host,
            "test",
            "src/tools/rls",
            SourceType::Submodule,
            &[],
        );
N
Nick Cameron 已提交
348

349
        cargo.add_rustc_lib_path(builder, compiler);
M
Mark Rousskov 已提交
350
        cargo.arg("--").args(builder.config.cmd.test_args());
351

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

N
Nick Cameron 已提交
358 359 360
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustfmt {
    stage: u32,
361
    host: TargetSelection,
N
Nick Cameron 已提交
362 363 364 365 366 367
}

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

T
Taiki Endo 已提交
368
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
N
Nick Cameron 已提交
369 370 371
        run.path("src/tools/rustfmt")
    }

T
Taiki Endo 已提交
372
    fn make_run(run: RunConfig<'_>) {
M
Mark Rousskov 已提交
373
        run.builder.ensure(Rustfmt { stage: run.builder.top_stage, host: run.target });
N
Nick Cameron 已提交
374 375 376
    }

    /// Runs `cargo test` for rustfmt.
T
Taiki Endo 已提交
377
    fn run(self, builder: &Builder<'_>) {
N
Nick Cameron 已提交
378 379 380 381
        let stage = self.stage;
        let host = self.host;
        let compiler = builder.compiler(stage, host);

382 383 384
        builder
            .ensure(tool::Rustfmt { compiler, target: self.host, extra_features: Vec::new() })
            .expect("in-tree tool");
385

M
Mark Rousskov 已提交
386 387 388 389 390 391 392 393 394 395
        let mut cargo = tool::prepare_tool_cargo(
            builder,
            compiler,
            Mode::ToolRustc,
            host,
            "test",
            "src/tools/rustfmt",
            SourceType::Submodule,
            &[],
        );
N
Nick Cameron 已提交
396

N
Nick Cameron 已提交
397 398 399
        let dir = testdir(builder, compiler.host);
        t!(fs::create_dir_all(&dir));
        cargo.env("RUSTFMT_TEST_DIR", dir);
N
Nick Cameron 已提交
400

401
        cargo.add_rustc_lib_path(builder, compiler);
N
Nick Cameron 已提交
402

403
        builder.run(&mut cargo.into());
N
Nick Cameron 已提交
404 405
    }
}
O
Oliver Schneider 已提交
406

R
Rich Kadel 已提交
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RustDemangler {
    stage: u32,
    host: TargetSelection,
}

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

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.path("src/tools/rust-demangler")
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(RustDemangler { stage: run.builder.top_stage, host: run.target });
    }

    /// Runs `cargo test` for rust-demangler.
    fn run(self, builder: &Builder<'_>) {
        let stage = self.stage;
        let host = self.host;
        let compiler = builder.compiler(stage, host);

        let rust_demangler = builder
            .ensure(tool::RustDemangler { compiler, target: self.host, extra_features: Vec::new() })
            .expect("in-tree tool");
        let mut cargo = tool::prepare_tool_cargo(
            builder,
            compiler,
            Mode::ToolRustc,
            host,
            "test",
            "src/tools/rust-demangler",
            SourceType::InTree,
            &[],
        );

        let dir = testdir(builder, compiler.host);
        t!(fs::create_dir_all(&dir));

        cargo.env("RUST_DEMANGLER_DRIVER_PATH", rust_demangler);
449 450 451

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

R
Rich Kadel 已提交
452 453 454 455 456 457
        cargo.add_rustc_lib_path(builder, compiler);

        builder.run(&mut cargo.into());
    }
}

O
Oliver Schneider 已提交
458
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
459
pub struct Miri {
O
Oliver Schneider 已提交
460
    stage: u32,
461
    host: TargetSelection,
462 463 464 465 466 467
}

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

T
Taiki Endo 已提交
468
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
R
Ralf Jung 已提交
469
        run.path("src/tools/miri")
470 471
    }

T
Taiki Endo 已提交
472
    fn make_run(run: RunConfig<'_>) {
M
Mark Rousskov 已提交
473
        run.builder.ensure(Miri { stage: run.builder.top_stage, host: run.target });
474 475 476
    }

    /// Runs `cargo test` for miri.
T
Taiki Endo 已提交
477
    fn run(self, builder: &Builder<'_>) {
O
Oliver Schneider 已提交
478
        let stage = self.stage;
479
        let host = self.host;
O
Oliver Schneider 已提交
480
        let compiler = builder.compiler(stage, host);
481

M
Mark Rousskov 已提交
482 483
        let miri =
            builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() });
484 485 486 487 488 489
        let cargo_miri = builder.ensure(tool::CargoMiri {
            compiler,
            target: self.host,
            extra_features: Vec::new(),
        });
        if let (Some(miri), Some(_cargo_miri)) = (miri, cargo_miri) {
490 491
            let mut cargo =
                builder.cargo(compiler, Mode::ToolRustc, SourceType::Submodule, host, "install");
492 493 494 495 496 497 498 499 500
            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;
            }

501 502 503 504 505 506 507
            // # Run `cargo miri setup`.
            let mut cargo = tool::prepare_tool_cargo(
                builder,
                compiler,
                Mode::ToolRustc,
                host,
                "run",
508
                "src/tools/miri/cargo-miri",
509 510 511
                SourceType::Submodule,
                &[],
            );
R
Ralf Jung 已提交
512
            cargo.add_rustc_lib_path(builder, compiler);
513
            cargo.arg("--").arg("miri").arg("setup");
514 515

            // Tell `cargo miri setup` where to find the sources.
R
Ralf Jung 已提交
516
            cargo.env("XARGO_RUST_SRC", builder.src.join("library"));
517 518
            // Tell it where to find Miri.
            cargo.env("MIRI", &miri);
519 520
            // Debug things.
            cargo.env("RUST_BACKTRACE", "1");
521
            // Let cargo-miri know where xargo ended up.
522
            cargo.env("XARGO_CHECK", builder.out.join("bin").join("xargo-check"));
523

524
            let mut cargo = Command::from(cargo);
525 526 527 528 529
            if !try_run(builder, &mut cargo) {
                return;
            }

            // # Determine where Miri put its sysroot.
R
Ralf Jung 已提交
530
            // To this end, we run `cargo miri setup --print-sysroot` and capture the output.
531 532 533
            // (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 已提交
534
            cargo.arg("--print-sysroot");
535 536 537 538 539

            // 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 {
540
                builder.verbose(&format!("running: {:?}", cargo));
M
Mark Rousskov 已提交
541 542
                let out = cargo
                    .output()
543 544
                    .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 已提交
545
                // Output is "<sysroot>\n".
546 547
                let stdout = String::from_utf8(out.stdout)
                    .expect("`cargo miri setup` stdout is not valid UTF-8");
R
Ralf Jung 已提交
548 549
                let sysroot = stdout.trim_end();
                builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {:?}", sysroot));
550 551 552 553 554 555 556 557 558 559 560 561 562 563
                sysroot.to_owned()
            };

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

            // miri tests need to know about the stage sysroot
567
            cargo.env("MIRI_SYSROOT", miri_sysroot);
O
Oliver Schneider 已提交
568
            cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
569
            cargo.env("MIRI", miri);
O
Oliver Schneider 已提交
570

571 572
            cargo.arg("--").args(builder.config.cmd.test_args());

573 574 575 576 577 578 579 580
            let mut cargo = Command::from(cargo);
            if !try_run(builder, &mut cargo) {
                return;
            }

            // # Run `cargo test` with `-Zmir-opt-level=4`.
            cargo.env("MIRIFLAGS", "-O -Zmir-opt-level=4");
            if !try_run(builder, &mut cargo) {
581
                return;
O
Oliver Schneider 已提交
582
            }
583 584 585

            // # Done!
            builder.save_toolstate("miri", ToolState::TestPass);
O
Oliver Schneider 已提交
586 587 588
        } else {
            eprintln!("failed to test miri: could not build");
        }
589 590 591
    }
}

592 593
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CompiletestTest {
594
    host: TargetSelection,
595 596 597 598 599
}

impl Step for CompiletestTest {
    type Output = ();

T
Taiki Endo 已提交
600
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
601 602 603
        run.path("src/tools/compiletest")
    }

T
Taiki Endo 已提交
604
    fn make_run(run: RunConfig<'_>) {
M
Mark Rousskov 已提交
605
        run.builder.ensure(CompiletestTest { host: run.target });
606 607 608
    }

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

613 614 615
        // We need `ToolStd` for the locally-built sysroot because
        // compiletest uses unstable features of the `test` crate.
        builder.ensure(compile::Std { compiler, target: host });
M
Mark Rousskov 已提交
616 617 618
        let cargo = tool::prepare_tool_cargo(
            builder,
            compiler,
619
            Mode::ToolStd,
M
Mark Rousskov 已提交
620 621 622 623 624 625
            host,
            "test",
            "src/tools/compiletest",
            SourceType::InTree,
            &[],
        );
626

627
        try_run(builder, &mut cargo.into());
628 629 630
    }
}

631 632
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Clippy {
O
Oliver Schneider 已提交
633
    stage: u32,
634
    host: TargetSelection,
635 636 637 638 639 640 641
}

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

T
Taiki Endo 已提交
642
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
643 644 645
        run.path("src/tools/clippy")
    }

T
Taiki Endo 已提交
646
    fn make_run(run: RunConfig<'_>) {
M
Mark Rousskov 已提交
647
        run.builder.ensure(Clippy { stage: run.builder.top_stage, host: run.target });
648 649 650
    }

    /// Runs `cargo test` for clippy.
T
Taiki Endo 已提交
651
    fn run(self, builder: &Builder<'_>) {
O
Oliver Schneider 已提交
652
        let stage = self.stage;
653
        let host = self.host;
O
Oliver Schneider 已提交
654
        let compiler = builder.compiler(stage, host);
655

M
Mark Rousskov 已提交
656 657 658 659 660
        let clippy = builder
            .ensure(tool::Clippy { compiler, target: self.host, extra_features: Vec::new() })
            .expect("in-tree tool");
        let mut cargo = tool::prepare_tool_cargo(
            builder,
661
            compiler,
M
Mark Rousskov 已提交
662 663 664 665 666 667 668
            Mode::ToolRustc,
            host,
            "test",
            "src/tools/clippy",
            SourceType::InTree,
            &[],
        );
O
Oliver Schneider 已提交
669

M
Mark Rousskov 已提交
670 671 672 673 674
        // 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));
        let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir());
675 676 677 678
        let target_libs = builder
            .stage_out(compiler, Mode::ToolRustc)
            .join(&self.host.triple)
            .join(builder.cargo_dir());
M
Mark Rousskov 已提交
679 680 681 682
        cargo.env("HOST_LIBS", host_libs);
        cargo.env("TARGET_LIBS", target_libs);
        // clippy tests need to find the driver
        cargo.env("CLIPPY_DRIVER_PATH", clippy);
O
Oliver Schneider 已提交
683

M
Mark Rousskov 已提交
684
        cargo.arg("--").args(builder.config.cmd.test_args());
685

686
        cargo.add_rustc_lib_path(builder, compiler);
O
Oliver Schneider 已提交
687

688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
        if builder.try_run(&mut cargo.into()) {
            // The tests succeeded; nothing to do.
            return;
        }

        if !builder.config.cmd.bless() {
            std::process::exit(1);
        }

        let mut cargo = builder.cargo(compiler, Mode::ToolRustc, SourceType::InTree, host, "run");
        cargo.arg("-p").arg("clippy_dev");
        // clippy_dev gets confused if it can't find `clippy/Cargo.toml`
        cargo.current_dir(&builder.src.join("src").join("tools").join("clippy"));
        if builder.config.rust_optimize {
            cargo.env("PROFILE", "release");
        } else {
            cargo.env("PROFILE", "debug");
        }
        cargo.arg("--");
        cargo.arg("bless");
A
Aaron Hill 已提交
708
        builder.run(&mut cargo.into());
709 710
    }
}
N
Nick Cameron 已提交
711

712 713 714 715 716 717 718 719
fn path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString {
    // 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`.
    let path = builder.sysroot(compiler).join("bin");
    let old_path = env::var_os("PATH").unwrap_or_default();
    env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("")
}
720

G
Guillaume Gomez 已提交
721 722 723 724 725 726 727 728 729 730
#[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 已提交
731
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
G
Guillaume Gomez 已提交
732 733 734
        run.path("src/tools/rustdoc-themes")
    }

T
Taiki Endo 已提交
735
    fn make_run(run: RunConfig<'_>) {
736
        let compiler = run.builder.compiler(run.builder.top_stage, run.target);
G
Guillaume Gomez 已提交
737

738
        run.builder.ensure(RustdocTheme { compiler });
G
Guillaume Gomez 已提交
739 740
    }

T
Taiki Endo 已提交
741
    fn run(self, builder: &Builder<'_>) {
742
        let rustdoc = builder.out.join("bootstrap/debug/rustdoc");
G
Guillaume Gomez 已提交
743 744
        let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
        cmd.arg(rustdoc.to_str().unwrap())
G
Guillaume Gomez 已提交
745
            .arg(builder.src.join("src/librustdoc/html/static/css/themes").to_str().unwrap())
S
Santiago Pastorino 已提交
746 747
            .env("RUSTC_STAGE", self.compiler.stage.to_string())
            .env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
M
Mark Rousskov 已提交
748
            .env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host))
S
Santiago Pastorino 已提交
749
            .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
M
Mark Rousskov 已提交
750
            .env("RUSTDOC_REAL", builder.rustdoc(self.compiler))
S
Santiago Pastorino 已提交
751
            .env("RUSTC_BOOTSTRAP", "1");
752
        if let Some(linker) = builder.linker(self.compiler.host) {
753 754
            cmd.env("RUSTDOC_LINKER", linker);
        }
755
        if builder.is_fuse_ld_lld(self.compiler.host) {
756
            cmd.env("RUSTDOC_FUSE_LD_LLD", "1");
G
Guillaume Gomez 已提交
757
        }
758
        try_run(builder, &mut cmd);
G
Guillaume Gomez 已提交
759 760 761
    }
}

G
Guillaume Gomez 已提交
762
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
G
Guillaume Gomez 已提交
763
pub struct RustdocJSStd {
764
    pub target: TargetSelection,
G
Guillaume Gomez 已提交
765 766
}

G
Guillaume Gomez 已提交
767
impl Step for RustdocJSStd {
768
    type Output = ();
G
Guillaume Gomez 已提交
769 770 771
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

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

T
Taiki Endo 已提交
776
    fn make_run(run: RunConfig<'_>) {
777
        run.builder.ensure(RustdocJSStd { target: run.target });
G
Guillaume Gomez 已提交
778 779
    }

T
Taiki Endo 已提交
780
    fn run(self, builder: &Builder<'_>) {
781 782
        if let Some(ref nodejs) = builder.config.nodejs {
            let mut command = Command::new(nodejs);
783
            command
784
                .arg(builder.src.join("src/tools/rustdoc-js/tester.js"))
785 786 787
                .arg("--crate-name")
                .arg("std")
                .arg("--resource-suffix")
788
                .arg(&builder.version)
789
                .arg("--doc-folder")
790
                .arg(builder.doc_out(self.target))
791
                .arg("--test-folder")
792
                .arg(builder.src.join("src/test/rustdoc-js-std"));
M
Mark Rousskov 已提交
793
            builder.ensure(crate::doc::Std { target: self.target, stage: builder.top_stage });
794 795
            builder.run(&mut command);
        } else {
M
Mark Rousskov 已提交
796
            builder.info("No nodejs found, skipping \"src/test/rustdoc-js-std\" tests");
797
        }
G
Guillaume Gomez 已提交
798 799 800
    }
}

G
Guillaume Gomez 已提交
801 802
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustdocJSNotStd {
803
    pub target: TargetSelection,
G
Guillaume Gomez 已提交
804 805 806 807 808 809 810 811
    pub compiler: Compiler,
}

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

G
Guillaume Gomez 已提交
812
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
G
Guillaume Gomez 已提交
813
        run.path("src/test/rustdoc-js")
G
Guillaume Gomez 已提交
814 815
    }

G
Guillaume Gomez 已提交
816
    fn make_run(run: RunConfig<'_>) {
817 818
        let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
        run.builder.ensure(RustdocJSNotStd { target: run.target, compiler });
G
Guillaume Gomez 已提交
819 820
    }

G
Guillaume Gomez 已提交
821
    fn run(self, builder: &Builder<'_>) {
822 823 824
        if builder.config.nodejs.is_some() {
            builder.ensure(Compiletest {
                compiler: self.compiler,
G
Guillaume Gomez 已提交
825
                target: self.target,
826 827
                mode: "js-doc-test",
                suite: "rustdoc-js",
828
                path: "src/test/rustdoc-js",
829
                compare_mode: None,
G
Guillaume Gomez 已提交
830 831
            });
        } else {
M
Mark Rousskov 已提交
832
            builder.info("No nodejs found, skipping \"src/test/rustdoc-js\" tests");
G
Guillaume Gomez 已提交
833 834 835 836
        }
    }
}

837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
fn check_if_browser_ui_test_is_installed_global(npm: &Path, global: bool) -> bool {
    let mut command = Command::new(&npm);
    command.arg("list").arg("--depth=0");
    if global {
        command.arg("--global");
    }
    let lines = command
        .output()
        .map(|output| String::from_utf8_lossy(&output.stdout).into_owned())
        .unwrap_or(String::new());
    lines.contains(&" browser-ui-test@")
}

fn check_if_browser_ui_test_is_installed(npm: &Path) -> bool {
    check_if_browser_ui_test_is_installed_global(npm, false)
        || check_if_browser_ui_test_is_installed_global(npm, true)
}

G
Guillaume Gomez 已提交
855 856 857 858 859 860 861 862 863 864 865 866
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustdocGUI {
    pub target: TargetSelection,
    pub compiler: Compiler,
}

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

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
867
        let builder = run.builder;
868
        let run = run.suite_path("src/test/rustdoc-gui");
869
        run.lazy_default_condition(Box::new(move || {
870 871 872 873 874 875
            builder.config.nodejs.is_some()
                && builder
                    .config
                    .npm
                    .as_ref()
                    .map(|p| check_if_browser_ui_test_is_installed(p))
876 877
                    .unwrap_or(false)
        }))
G
Guillaume Gomez 已提交
878 879 880 881 882 883 884 885
    }

    fn make_run(run: RunConfig<'_>) {
        let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
        run.builder.ensure(RustdocGUI { target: run.target, compiler });
    }

    fn run(self, builder: &Builder<'_>) {
886 887
        let nodejs = builder.config.nodejs.as_ref().expect("nodejs isn't available");
        let npm = builder.config.npm.as_ref().expect("npm isn't available");
G
Guillaume Gomez 已提交
888

889
        builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
890

891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
        // The goal here is to check if the necessary packages are installed, and if not, we
        // panic.
        if !check_if_browser_ui_test_is_installed(&npm) {
            eprintln!(
                "error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \
                 dependency is missing",
            );
            eprintln!(
                "If you want to install the `{0}` dependency, run `npm install {0}`",
                "browser-ui-test",
            );
            panic!("Cannot run rustdoc-gui tests");
        }

        let out_dir = builder.test_out(self.target).join("rustdoc-gui");

        // We remove existing folder to be sure there won't be artifacts remaining.
        let _ = fs::remove_dir_all(&out_dir);

910
        let src_path = "src/test/rustdoc-gui/src";
911
        // We generate docs for the libraries present in the rustdoc-gui's src folder.
912 913 914 915 916 917 918 919 920 921
        let mut cargo = Command::new(&builder.initial_cargo);
        cargo
            .arg("doc")
            .arg("--workspace")
            .arg("--target-dir")
            .arg(&out_dir)
            .env("RUSTDOC", builder.rustdoc(self.compiler))
            .env("RUSTC", builder.rustc(self.compiler))
            .current_dir(&builder.build.src.join(src_path));
        builder.run(&mut cargo);
922 923 924 925 926 927

        // We now run GUI tests.
        let mut command = Command::new(&nodejs);
        command
            .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js"))
            .arg("--doc-folder")
928
            .arg(out_dir.join("doc"))
929 930
            .arg("--tests-folder")
            .arg(builder.build.src.join("src/test/rustdoc-gui"));
931 932 933 934 935 936 937
        for path in &builder.paths {
            if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
                if name.ends_with(".goml") {
                    command.arg("--file").arg(name);
                }
            }
        }
938 939 940
        for test_arg in builder.config.cmd.test_args() {
            command.arg(test_arg);
        }
941
        builder.run(&mut command);
G
Guillaume Gomez 已提交
942 943 944
    }
}

945
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
M
Mark Simulacrum 已提交
946
pub struct Tidy;
947

948
impl Step for Tidy {
949
    type Output = ();
950 951
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;
952

M
Mark Simulacrum 已提交
953
    /// Runs the `tidy` tool.
954 955 956 957
    ///
    /// 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.
958 959 960
    ///
    /// Once tidy passes, this step also runs `fmt --check` if tests are being run
    /// for the `dev` or `nightly` channels.
T
Taiki Endo 已提交
961
    fn run(self, builder: &Builder<'_>) {
962
        let mut cmd = builder.tool_cmd(Tool::Tidy);
M
mark 已提交
963
        cmd.arg(&builder.src);
964
        cmd.arg(&builder.initial_cargo);
965
        cmd.arg(&builder.out);
966
        cmd.arg(builder.jobs().to_string());
M
Mark Rousskov 已提交
967 968
        if builder.is_verbose() {
            cmd.arg("--verbose");
969
        }
970

971
        builder.info("tidy check");
972
        try_run(builder, &mut cmd);
973 974 975

        if builder.config.channel == "dev" || builder.config.channel == "nightly" {
            builder.info("fmt check");
976 977 978 979 980 981 982 983 984 985 986 987 988
            if builder.config.initial_rustfmt.is_none() {
                let inferred_rustfmt_dir = builder.config.initial_rustc.parent().unwrap();
                eprintln!(
                    "\
error: no `rustfmt` binary found in {PATH}
info: `rust.channel` is currently set to \"{CHAN}\"
help: if you are testing a beta branch, set `rust.channel` to \"beta\" in the `config.toml` file
help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy` to `x.py test`",
                    PATH = inferred_rustfmt_dir.display(),
                    CHAN = builder.config.channel,
                );
                std::process::exit(1);
            }
989
            crate::format::format(&builder.build, !builder.config.cmd.bless(), &[]);
990
        }
991
    }
992

T
Taiki Endo 已提交
993
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
994
        run.path("src/tools/tidy")
995 996
    }

T
Taiki Endo 已提交
997
    fn make_run(run: RunConfig<'_>) {
M
Mark Simulacrum 已提交
998
        run.builder.ensure(Tidy);
999
    }
1000
}
1001

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ExpandYamlAnchors;

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

    /// Ensure the `generate-ci-config` tool was run locally.
    ///
    /// The tool in `src/tools` reads the CI definition in `src/ci/builders.yml` and generates the
    /// appropriate configuration for all our CI providers. This step ensures the tool was called
    /// by the user before committing CI changes.
    fn run(self, builder: &Builder<'_>) {
        builder.info("Ensuring the YAML anchors in the GitHub Actions config were expanded");
        try_run(
            builder,
            &mut builder.tool_cmd(Tool::ExpandYamlAnchors).arg("check").arg(&builder.src),
        );
    }

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.path("src/tools/expand-yaml-anchors")
    }

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

1031 1032
fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
    builder.out.join(host.triple).join("test")
1033 1034
}

1035 1036 1037
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 });
M
Mark Rousskov 已提交
1038
    };
1039 1040
}

1041 1042 1043
macro_rules! default_test_with_compare_mode {
    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr,
                   compare_mode: $compare_mode:expr }) => {
M
Mark Rousskov 已提交
1044 1045 1046 1047 1048 1049 1050 1051 1052
        test_with_compare_mode!($name {
            path: $path,
            mode: $mode,
            suite: $suite,
            default: true,
            host: false,
            compare_mode: $compare_mode
        });
    };
1053 1054
}

1055 1056 1057
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 });
M
Mark Rousskov 已提交
1058
    };
1059 1060
}

1061
macro_rules! test {
1062 1063
    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
                   host: $host:expr }) => {
M
Mark Rousskov 已提交
1064 1065 1066 1067 1068 1069 1070 1071 1072
        test_definitions!($name {
            path: $path,
            mode: $mode,
            suite: $suite,
            default: $default,
            host: $host,
            compare_mode: None
        });
    };
1073 1074 1075 1076 1077
}

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 }) => {
M
Mark Rousskov 已提交
1078 1079 1080 1081 1082 1083 1084 1085 1086
        test_definitions!($name {
            path: $path,
            mode: $mode,
            suite: $suite,
            default: $default,
            host: $host,
            compare_mode: Some($compare_mode)
        });
    };
1087 1088 1089
}

macro_rules! test_definitions {
1090 1091 1092 1093 1094
    ($name:ident {
        path: $path:expr,
        mode: $mode:expr,
        suite: $suite:expr,
        default: $default:expr,
1095 1096
        host: $host:expr,
        compare_mode: $compare_mode:expr
1097 1098 1099 1100
    }) => {
        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
        pub struct $name {
            pub compiler: Compiler,
1101
            pub target: TargetSelection,
1102 1103
        }

1104 1105 1106 1107
        impl Step for $name {
            type Output = ();
            const DEFAULT: bool = $default;
            const ONLY_HOSTS: bool = $host;
1108

T
Taiki Endo 已提交
1109
            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1110
                run.suite_path($path)
1111
            }
1112

T
Taiki Endo 已提交
1113
            fn make_run(run: RunConfig<'_>) {
1114
                let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1115

M
Mark Rousskov 已提交
1116
                run.builder.ensure($name { compiler, target: run.target });
1117
            }
1118

T
Taiki Endo 已提交
1119
            fn run(self, builder: &Builder<'_>) {
1120 1121 1122 1123 1124
                builder.ensure(Compiletest {
                    compiler: self.compiler,
                    target: self.target,
                    mode: $mode,
                    suite: $suite,
1125
                    path: $path,
1126
                    compare_mode: $compare_mode,
1127 1128 1129
                })
            }
        }
M
Mark Rousskov 已提交
1130
    };
1131 1132
}

1133
default_test_with_compare_mode!(Ui {
1134 1135
    path: "src/test/ui",
    mode: "ui",
1136 1137
    suite: "ui",
    compare_mode: "nll"
1138 1139 1140 1141 1142 1143 1144 1145
});

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

M
Mark Rousskov 已提交
1146
default_test!(MirOpt { path: "src/test/mir-opt", mode: "mir-opt", suite: "mir-opt" });
1147

M
Mark Rousskov 已提交
1148
default_test!(Codegen { path: "src/test/codegen", mode: "codegen", suite: "codegen" });
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161

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

1162 1163 1164 1165 1166 1167
default_test_with_compare_mode!(Debuginfo {
    path: "src/test/debuginfo",
    mode: "debuginfo",
    suite: "debuginfo",
    compare_mode: "split-dwarf"
});
1168

M
Mark Rousskov 已提交
1169
host_test!(UiFullDeps { path: "src/test/ui-fulldeps", mode: "ui", suite: "ui-fulldeps" });
1170

M
Mark Rousskov 已提交
1171
host_test!(Rustdoc { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" });
1172
host_test!(RustdocUi { path: "src/test/rustdoc-ui", mode: "ui", suite: "rustdoc-ui" });
1173

N
Nixon Enraght-Moony 已提交
1174 1175 1176 1177 1178 1179
host_test!(RustdocJson {
    path: "src/test/rustdoc-json",
    mode: "rustdoc-json",
    suite: "rustdoc-json"
});

M
Mark Rousskov 已提交
1180
host_test!(Pretty { path: "src/test/pretty", mode: "pretty", suite: "pretty" });
1181

M
Mark Rousskov 已提交
1182
default_test!(RunMake { path: "src/test/run-make", mode: "run-make", suite: "run-make" });
1183

1184 1185 1186 1187 1188 1189
host_test!(RunMakeFullDeps {
    path: "src/test/run-make-fulldeps",
    mode: "run-make",
    suite: "run-make-fulldeps"
});

M
Mark Rousskov 已提交
1190
default_test!(Assembly { path: "src/test/assembly", mode: "assembly", suite: "assembly" });
D
Denys Zariaiev 已提交
1191

1192 1193 1194
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
struct Compiletest {
    compiler: Compiler,
1195
    target: TargetSelection,
1196 1197
    mode: &'static str,
    suite: &'static str,
1198
    path: &'static str,
1199
    compare_mode: Option<&'static str>,
1200 1201 1202 1203 1204
}

impl Step for Compiletest {
    type Output = ();

T
Taiki Endo 已提交
1205
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1206 1207 1208
        run.never()
    }

1209 1210 1211 1212 1213
    /// 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 已提交
1214
    fn run(self, builder: &Builder<'_>) {
1215 1216 1217
        if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() {
            eprintln!("\
error: `--stage 0` runs compiletest on the beta compiler, not your local changes, and will almost always cause tests to fail
1218 1219
help: to test the compiler, use `--stage 1` instead
help: to test the standard library, use `--stage 0 library/std` instead
1220 1221 1222 1223 1224
note: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`."
            );
            std::process::exit(1);
        }

1225 1226 1227 1228
        let compiler = self.compiler;
        let target = self.target;
        let mode = self.mode;
        let suite = self.suite;
1229

1230
        // Path for test suite
1231
        let suite_path = self.path;
1232

1233
        // Skip codegen tests if they aren't enabled in configuration.
1234
        if !builder.config.codegen_tests && suite == "codegen" {
1235 1236 1237 1238
            return;
        }

        if suite == "debuginfo" {
M
Mark Rousskov 已提交
1239 1240
            builder
                .ensure(dist::DebuggerScripts { sysroot: builder.sysroot(compiler), host: target });
1241 1242
        }

1243
        if suite.ends_with("fulldeps") {
1244 1245 1246
            builder.ensure(compile::Rustc { compiler, target });
        }

1247 1248 1249
        builder.ensure(compile::Std { compiler, target });
        // ensure that `libproc_macro` is available on the host.
        builder.ensure(compile::Std { compiler, target: compiler.host });
1250

1251 1252
        // Also provide `rust_test_helpers` for the host.
        builder.ensure(native::TestHelpers { target: compiler.host });
1253

1254 1255
        // As well as the target, except for plain wasm32, which can't build it
        if !target.contains("wasm32") || target.contains("emscripten") {
1256 1257
            builder.ensure(native::TestHelpers { target });
        }
1258

1259
        builder.ensure(RemoteCopyLibs { compiler, target });
1260 1261

        let mut cmd = builder.tool_cmd(Tool::Compiletest);
1262 1263 1264 1265

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

M
Mark Rousskov 已提交
1266 1267
        cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(compiler));
        cmd.arg("--run-lib-path").arg(builder.sysroot_libdir(compiler, target));
1268
        cmd.arg("--rustc-path").arg(builder.rustc(compiler));
1269

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

1272
        // Avoid depending on rustdoc when we don't need it.
S
Santiago Pastorino 已提交
1273
        if mode == "rustdoc"
1274
            || mode == "run-make"
1275 1276
            || (mode == "ui" && is_rustdoc)
            || mode == "js-doc-test"
N
Nixon Enraght-Moony 已提交
1277
            || mode == "rustdoc-json"
S
Santiago Pastorino 已提交
1278
        {
M
Mark Rousskov 已提交
1279
            cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler));
1280 1281
        }

1282 1283 1284 1285 1286 1287 1288
        if mode == "rustdoc-json" {
            // Use the beta compiler for jsondocck
            let json_compiler = compiler.with_stage(0);
            cmd.arg("--jsondocck-path")
                .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }));
        }

R
Rich Kadel 已提交
1289
        if mode == "run-make" && suite.ends_with("fulldeps") {
R
Rich Kadel 已提交
1290 1291 1292 1293
            let rust_demangler = builder
                .ensure(tool::RustDemangler { compiler, target, extra_features: Vec::new() })
                .expect("in-tree tool");
            cmd.arg("--rust-demangler-path").arg(rust_demangler);
R
Rich Kadel 已提交
1294 1295
        }

M
Mark Rousskov 已提交
1296 1297 1298
        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));
1299
        cmd.arg("--suite").arg(suite);
1300
        cmd.arg("--mode").arg(mode);
1301 1302
        cmd.arg("--target").arg(target.rustc_target_arg());
        cmd.arg("--host").arg(&*compiler.host.triple);
M
Mark Rousskov 已提交
1303
        cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
1304

1305
        if builder.config.cmd.bless() {
1306 1307 1308
            cmd.arg("--bless");
        }

M
Mark Rousskov 已提交
1309 1310 1311 1312
        let compare_mode =
            builder.config.cmd.compare_mode().or_else(|| {
                if builder.config.test_compare_mode { self.compare_mode } else { None }
            });
S
Santiago Pastorino 已提交
1313

1314 1315 1316 1317 1318
        if let Some(ref pass) = builder.config.cmd.pass() {
            cmd.arg("--pass");
            cmd.arg(pass);
        }

T
Tyler Mandry 已提交
1319 1320 1321 1322 1323
        if let Some(ref run) = builder.config.cmd.run() {
            cmd.arg("--run");
            cmd.arg(run);
        }

1324
        if let Some(ref nodejs) = builder.config.nodejs {
1325 1326
            cmd.arg("--nodejs").arg(nodejs);
        }
G
Guillaume Gomez 已提交
1327 1328 1329
        if let Some(ref npm) = builder.config.npm {
            cmd.arg("--npm").arg(npm);
        }
1330

M
Mark Rousskov 已提交
1331
        let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
1332
        if !is_rustdoc {
1333
            if builder.config.rust_optimize_tests {
G
Guillaume Gomez 已提交
1334 1335
                flags.push("-O".to_string());
            }
1336
        }
1337
        flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
1338
        flags.push(builder.config.cmd.rustc_args().join(" "));
1339

1340
        if let Some(linker) = builder.linker(target) {
O
Oliver Schneider 已提交
1341 1342 1343
            cmd.arg("--linker").arg(linker);
        }

1344
        let mut hostflags = flags.clone();
M
Mark Rousskov 已提交
1345
        hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
1346
        hostflags.extend(builder.lld_flags(compiler.host));
1347 1348
        cmd.arg("--host-rustcflags").arg(hostflags.join(" "));

S
Shotaro Yamada 已提交
1349
        let mut targetflags = flags;
M
Mark Rousskov 已提交
1350
        targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
1351
        targetflags.extend(builder.lld_flags(target));
1352 1353
        cmd.arg("--target-rustcflags").arg(targetflags.join(" "));

1354
        cmd.arg("--docck-python").arg(builder.python());
1355

1356
        if builder.config.build.ends_with("apple-darwin") {
1357
            // Force /usr/bin/python3 on macOS for LLDB tests because we're loading the
1358 1359
            // LLDB plugin's compiled module which only works with the system python
            // (namely not Homebrew-installed python)
1360
            cmd.arg("--lldb-python").arg("/usr/bin/python3");
1361
        } else {
1362
            cmd.arg("--lldb-python").arg(builder.python());
1363
        }
1364

1365
        if let Some(ref gdb) = builder.config.gdb {
1366 1367
            cmd.arg("--gdb").arg(gdb);
        }
1368 1369 1370 1371

        let run = |cmd: &mut Command| {
            cmd.output().map(|output| {
                String::from_utf8_lossy(&output.stdout)
M
Mark Rousskov 已提交
1372 1373 1374 1375
                    .lines()
                    .next()
                    .unwrap_or_else(|| panic!("{:?} failed {:?}", cmd, output))
                    .to_string()
1376 1377
            })
        };
1378 1379
        let lldb_exe = "lldb";
        let lldb_version = Command::new(lldb_exe)
1380 1381
            .arg("--version")
            .output()
M
Mark Rousskov 已提交
1382
            .map(|output| String::from_utf8_lossy(&output.stdout).to_string())
1383 1384
            .ok();
        if let Some(ref vers) = lldb_version {
1385
            cmd.arg("--lldb-version").arg(vers);
1386
            let lldb_python_dir = run(Command::new(lldb_exe).arg("-P")).ok();
1387 1388 1389
            if let Some(ref dir) = lldb_python_dir {
                cmd.arg("--lldb-python-dir").arg(dir);
            }
1390
        }
1391

1392 1393 1394
        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);
1395 1396
        }

1397 1398
        // Get paths from cmd args
        let paths = match &builder.config.cmd {
S
Santiago Pastorino 已提交
1399 1400
            Subcommand::Test { ref paths, .. } => &paths[..],
            _ => &[],
1401 1402 1403
        };

        // Get test-args by striping suite path
S
Santiago Pastorino 已提交
1404 1405
        let mut test_args: Vec<&str> = paths
            .iter()
M
Mark Rousskov 已提交
1406 1407 1408
            .map(|p| match p.strip_prefix(".") {
                Ok(path) => path,
                Err(_) => p,
1409
            })
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422
            .filter(|p| p.starts_with(suite_path))
            .filter(|p| {
                let exists = p.is_dir() || p.is_file();
                if !exists {
                    if let Some(p) = p.to_str() {
                        builder.info(&format!(
                            "Warning: Skipping \"{}\": not a regular file or directory",
                            p
                        ));
                    }
                }
                exists
            })
1423
            .filter_map(|p| {
V
varkor 已提交
1424 1425 1426 1427 1428 1429
                // 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.
1430
                match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
M
Matthias Krüger 已提交
1431
                    Some(s) if !s.is_empty() => Some(s),
1432 1433 1434
                    _ => None,
                }
            })
S
Santiago Pastorino 已提交
1435
            .collect();
1436 1437 1438 1439

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

        cmd.args(&test_args);
1440

1441
        if builder.is_verbose() {
1442 1443
            cmd.arg("--verbose");
        }
1444

O
Oliver Schneider 已提交
1445
        if !builder.config.verbose_tests {
1446 1447
            cmd.arg("--quiet");
        }
1448

1449 1450
        let mut llvm_components_passed = false;
        let mut copts_passed = false;
B
bjorn3 已提交
1451
        if builder.config.llvm_enabled() {
M
Mark Rousskov 已提交
1452
            let llvm_config = builder.ensure(native::Llvm { target: builder.config.build });
1453
            if !builder.config.dry_run {
1454
                let llvm_version = output(Command::new(&llvm_config).arg("--version"));
1455
                let llvm_components = output(Command::new(&llvm_config).arg("--components"));
1456
                // Remove trailing newline from llvm-config output.
1457 1458 1459 1460 1461
                cmd.arg("--llvm-version")
                    .arg(llvm_version.trim())
                    .arg("--llvm-components")
                    .arg(llvm_components.trim());
                llvm_components_passed = true;
1462
            }
1463
            if !builder.is_rust_llvm(target) {
B
bjorn3 已提交
1464 1465 1466
                cmd.arg("--system-llvm");
            }

1467 1468 1469 1470 1471 1472 1473 1474 1475
            // Tests that use compiler libraries may inherit the `-lLLVM` link
            // requirement, but the `-L` library path is not propagated across
            // separate compilations. We can add LLVM's library path to the
            // platform-specific environment variable as a workaround.
            if !builder.config.dry_run && suite.ends_with("fulldeps") {
                let llvm_libdir = output(Command::new(&llvm_config).arg("--libdir"));
                add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cmd);
            }

B
bjorn3 已提交
1476 1477
            // 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.
1478
            if !builder.config.dry_run && matches!(suite, "run-make" | "run-make-fulldeps") {
1479 1480
                // The llvm/bin directory contains many useful cross-platform
                // tools. Pass the path to run-make tests so they can use them.
M
Mark Rousskov 已提交
1481 1482
                let llvm_bin_path = llvm_config
                    .parent()
1483 1484 1485
                    .expect("Expected llvm-config to be contained in directory");
                assert!(llvm_bin_path.is_dir());
                cmd.arg("--llvm-bin-dir").arg(llvm_bin_path);
1486 1487 1488

                // If LLD is available, add it to the PATH
                if builder.config.lld_enabled {
M
Mark Rousskov 已提交
1489 1490
                    let lld_install_root =
                        builder.ensure(native::Lld { target: builder.config.build });
1491 1492 1493 1494

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

                    let old_path = env::var_os("PATH").unwrap_or_default();
M
Mark Rousskov 已提交
1495 1496 1497 1498
                    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");
1499 1500
                    cmd.env("PATH", new_path);
                }
B
bjorn3 已提交
1501 1502 1503
            }
        }

1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
        // 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.
        if !builder.config.dry_run && matches!(suite, "run-make" | "run-make-fulldeps") {
            cmd.arg("--cc")
                .arg(builder.cc(target))
                .arg("--cxx")
                .arg(builder.cxx(target).unwrap())
                .arg("--cflags")
                .arg(builder.cflags(target, GitRepo::Rustc).join(" "));
            copts_passed = true;
            if let Some(ar) = builder.ar(target) {
                cmd.arg("--ar").arg(ar);
            }
        }

1519 1520 1521 1522 1523
        if !llvm_components_passed {
            cmd.arg("--llvm-components").arg("");
        }
        if !copts_passed {
            cmd.arg("--cc").arg("").arg("--cxx").arg("").arg("--cflags").arg("");
1524
        }
1525

1526
        if builder.remote_tested(target) {
M
Mark Rousskov 已提交
1527
            cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
1528
        }
1529

1530 1531 1532 1533 1534 1535
        // 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") {
1536
            for &(ref k, ref v) in builder.cc[&target].env() {
1537 1538 1539
                if k != "PATH" {
                    cmd.env(k, v);
                }
1540 1541
            }
        }
1542
        cmd.env("RUSTC_BOOTSTRAP", "1");
1543
        cmd.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
1544
        builder.add_rust_test_threads(&mut cmd);
1545

1546
        if builder.config.sanitizers_enabled(target) {
1547
            cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
1548
        }
1549

1550
        if builder.config.profiler_enabled(target) {
1551
            cmd.env("RUSTC_PROFILER_SUPPORT", "1");
1552
        }
1553

M
Mark Rousskov 已提交
1554 1555 1556 1557
        let tmp = builder.out.join("tmp");
        std::fs::create_dir_all(&tmp).unwrap();
        cmd.env("RUST_TEST_TMPDIR", tmp);

1558 1559 1560 1561 1562
        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 已提交
1563
                .arg(builder.cc(target).parent().unwrap().parent().unwrap());
1564 1565 1566
        } else {
            cmd.arg("--android-cross-path").arg("");
        }
1567

1568 1569 1570 1571
        if builder.config.cmd.rustfix_coverage() {
            cmd.arg("--rustfix-coverage");
        }

1572 1573
        cmd.env("BOOTSTRAP_CARGO", &builder.initial_cargo);

1574 1575
        cmd.arg("--channel").arg(&builder.config.channel);

1576
        builder.ci_env.force_coloring_in_ci(&mut cmd);
1577

S
Santiago Pastorino 已提交
1578 1579 1580 1581
        builder.info(&format!(
            "Check compiletest suite={} mode={} ({} -> {})",
            suite, mode, &compiler.host, target
        ));
1582 1583
        let _time = util::timeit(&builder);
        try_run(builder, &mut cmd);
1584 1585 1586

        if let Some(compare_mode) = compare_mode {
            cmd.arg("--compare-mode").arg(compare_mode);
S
Santiago Pastorino 已提交
1587 1588 1589 1590
            builder.info(&format!(
                "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
                suite, mode, compare_mode, &compiler.host, target
            ));
1591 1592 1593
            let _time = util::timeit(&builder);
            try_run(builder, &mut cmd);
        }
1594
    }
1595
}
1596

E
Eric Huss 已提交
1597 1598
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct BookTest {
1599
    compiler: Compiler,
E
Eric Huss 已提交
1600
    path: PathBuf,
1601 1602
    name: &'static str,
    is_ext_doc: bool,
1603 1604
}

E
Eric Huss 已提交
1605
impl Step for BookTest {
1606 1607
    type Output = ();
    const ONLY_HOSTS: bool = true;
1608

T
Taiki Endo 已提交
1609
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1610
        run.never()
1611
    }
M
Mark Simulacrum 已提交
1612

E
Eric Huss 已提交
1613
    /// Runs the documentation tests for a book in `src/doc`.
1614
    ///
E
Eric Huss 已提交
1615
    /// This uses the `rustdoc` that sits next to `compiler`.
T
Taiki Endo 已提交
1616
    fn run(self, builder: &Builder<'_>) {
E
Eric Huss 已提交
1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665
        // External docs are different from local because:
        // - Some books need pre-processing by mdbook before being tested.
        // - They need to save their state to toolstate.
        // - They are only tested on the "checktools" builders.
        //
        // The local docs are tested by default, and we don't want to pay the
        // cost of building mdbook, so they use `rustdoc --test` directly.
        // Also, the unstable book is special because SUMMARY.md is generated,
        // so it is easier to just run `rustdoc` on its files.
        if self.is_ext_doc {
            self.run_ext_doc(builder);
        } else {
            self.run_local_doc(builder);
        }
    }
}

impl BookTest {
    /// This runs the equivalent of `mdbook test` (via the rustbook wrapper)
    /// which in turn runs `rustdoc --test` on each file in the book.
    fn run_ext_doc(self, builder: &Builder<'_>) {
        let compiler = self.compiler;

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

        // mdbook just executes a binary named "rustdoc", so we need to update
        // PATH so that it points to our rustdoc.
        let mut rustdoc_path = builder.rustdoc(compiler);
        rustdoc_path.pop();
        let old_path = env::var_os("PATH").unwrap_or_default();
        let new_path = env::join_paths(iter::once(rustdoc_path).chain(env::split_paths(&old_path)))
            .expect("could not add rustdoc to PATH");

        let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
        let path = builder.src.join(&self.path);
        rustbook_cmd.env("PATH", new_path).arg("test").arg(path);
        builder.add_rust_test_threads(&mut rustbook_cmd);
        builder.info(&format!("Testing rustbook {}", self.path.display()));
        let _time = util::timeit(&builder);
        let toolstate = if try_run(builder, &mut rustbook_cmd) {
            ToolState::TestPass
        } else {
            ToolState::TestFail
        };
        builder.save_toolstate(self.name, toolstate);
    }

    /// This runs `rustdoc --test` on all `.md` files in the path.
    fn run_local_doc(self, builder: &Builder<'_>) {
1666
        let compiler = self.compiler;
1667

M
Mark Rousskov 已提交
1668
        builder.ensure(compile::Std { compiler, target: compiler.host });
1669

1670 1671
        // Do a breadth-first traversal of the `src/doc` directory and just run
        // tests for all files that end in `*.md`
1672 1673
        let mut stack = vec![builder.src.join(self.path)];
        let _time = util::timeit(&builder);
1674
        let mut files = Vec::new();
1675 1676 1677
        while let Some(p) = stack.pop() {
            if p.is_dir() {
                stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
S
Santiago Pastorino 已提交
1678
                continue;
1679 1680 1681 1682 1683 1684
            }

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

1685 1686 1687 1688 1689 1690
            files.push(p);
        }

        files.sort();

        for file in files {
E
Eric Huss 已提交
1691
            markdown_test(builder, compiler, &file);
1692
        }
1693 1694 1695
    }
}

1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708
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 已提交
1709
                fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1710 1711 1712
                    run.path($path)
                }

T
Taiki Endo 已提交
1713
                fn make_run(run: RunConfig<'_>) {
1714
                    run.builder.ensure($name {
1715
                        compiler: run.builder.compiler(run.builder.top_stage, run.target),
1716 1717 1718
                    });
                }

T
Taiki Endo 已提交
1719
                fn run(self, builder: &Builder<'_>) {
E
Eric Huss 已提交
1720
                    builder.ensure(BookTest {
1721
                        compiler: self.compiler,
E
Eric Huss 已提交
1722
                        path: PathBuf::from($path),
1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735
                        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;
1736
    RustcBook, "src/doc/rustc", "rustc", default=true;
1737
    RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false;
1738
    EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false;
1739 1740
    TheBook, "src/doc/book", "book", default=false;
    UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
E
Eric Huss 已提交
1741
    EditionGuide, "src/doc/edition-guide", "edition-guide", default=false;
1742 1743
);

1744 1745 1746
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ErrorIndex {
    compiler: Compiler,
1747
}
1748

1749
impl Step for ErrorIndex {
1750
    type Output = ();
1751 1752 1753
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
1754
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1755
        run.path("src/tools/error_index_generator")
1756 1757
    }

T
Taiki Endo 已提交
1758
    fn make_run(run: RunConfig<'_>) {
E
Eric Huss 已提交
1759 1760 1761
        // error_index_generator depends on librustdoc. Use the compiler that
        // is normally used to build rustdoc for other tests (like compiletest
        // tests in src/test/rustdoc) so that it shares the same artifacts.
1762
        let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.build);
E
Eric Huss 已提交
1763
        run.builder.ensure(ErrorIndex { compiler });
1764
    }
1765

A
Alexander Regueiro 已提交
1766
    /// Runs the error index generator tool to execute the tests located in the error
1767 1768 1769 1770 1771
    /// 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 已提交
1772
    fn run(self, builder: &Builder<'_>) {
1773 1774
        let compiler = self.compiler;

1775
        let dir = testdir(builder, compiler.host);
1776 1777 1778
        t!(fs::create_dir_all(&dir));
        let output = dir.join("error-index.md");

1779
        let mut tool = tool::ErrorIndex::command(builder);
E
Eric Huss 已提交
1780
        tool.arg("markdown").arg(&output);
1781

1782
        builder.info(&format!("Testing error-index stage{}", compiler.stage));
1783
        let _time = util::timeit(&builder);
1784
        builder.run_quiet(&mut tool);
1785 1786 1787 1788
        // The tests themselves need to link to std, so make sure it is
        // available.
        builder.ensure(compile::Std { compiler, target: compiler.host });
        markdown_test(builder, compiler, &output);
1789
    }
1790 1791
}

T
Taiki Endo 已提交
1792
fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
1793 1794 1795
    if let Ok(contents) = fs::read_to_string(markdown) {
        if !contents.contains("```") {
            return true;
1796
        }
1797 1798
    }

1799
    builder.info(&format!("doc tests for: {}", markdown.display()));
M
Mark Rousskov 已提交
1800
    let mut cmd = builder.rustdoc_cmd(compiler);
1801
    builder.add_rust_test_threads(&mut cmd);
1802 1803 1804
    // allow for unstable options such as new editions
    cmd.arg("-Z");
    cmd.arg("unstable-options");
1805 1806
    cmd.arg("--test");
    cmd.arg(markdown);
1807
    cmd.env("RUSTC_BOOTSTRAP", "1");
1808

1809
    let test_args = builder.config.cmd.test_args().join(" ");
1810 1811
    cmd.arg("--test-args").arg(test_args);

O
Oliver Schneider 已提交
1812
    if builder.config.verbose_tests {
1813
        try_run(builder, &mut cmd)
O
Oliver Schneider 已提交
1814 1815
    } else {
        try_run_quiet(builder, &mut cmd)
1816
    }
1817
}
1818

1819 1820 1821 1822 1823 1824 1825 1826 1827
#[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<'_> {
1828
        run.path("src/doc/rustc-dev-guide")
1829 1830 1831 1832 1833 1834 1835
    }

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

    fn run(self, builder: &Builder<'_>) {
1836
        let src = builder.src.join("src/doc/rustc-dev-guide");
1837
        let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
E
Eric Huss 已提交
1838 1839 1840 1841 1842
        let toolstate = if try_run(builder, rustbook_cmd.arg("linkcheck").arg(&src)) {
            ToolState::TestPass
        } else {
            ToolState::TestFail
        };
1843
        builder.save_toolstate("rustc-dev-guide", toolstate);
1844 1845 1846
    }
}

1847
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
M
Mark Simulacrum 已提交
1848
pub struct CrateLibrustc {
1849
    compiler: Compiler,
1850
    target: TargetSelection,
1851
    test_kind: TestKind,
1852
    krate: Interned<String>,
1853 1854
}

M
Mark Simulacrum 已提交
1855
impl Step for CrateLibrustc {
1856 1857 1858 1859
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
1860
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1861
        run.krate("rustc-main")
1862 1863
    }

T
Taiki Endo 已提交
1864
    fn make_run(run: RunConfig<'_>) {
1865
        let builder = run.builder;
1866
        let compiler = builder.compiler(builder.top_stage, run.build_triple());
1867

1868
        for krate in builder.in_tree_crates("rustc-main", Some(run.target)) {
E
Eric Huss 已提交
1869
            if krate.path.ends_with(&run.path) {
1870
                let test_kind = builder.kind.into();
1871

1872 1873 1874 1875 1876 1877
                builder.ensure(CrateLibrustc {
                    compiler,
                    target: run.target,
                    test_kind,
                    krate: krate.name,
                });
1878 1879 1880 1881
            }
        }
    }

T
Taiki Endo 已提交
1882
    fn run(self, builder: &Builder<'_>) {
M
Mark Simulacrum 已提交
1883
        builder.ensure(Crate {
1884 1885
            compiler: self.compiler,
            target: self.target,
C
Collins Abitekaniza 已提交
1886
            mode: Mode::Rustc,
1887 1888 1889 1890 1891 1892
            test_kind: self.test_kind,
            krate: self.krate,
        });
    }
}

K
kennytm 已提交
1893
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
M
Mark Simulacrum 已提交
1894
pub struct Crate {
K
kennytm 已提交
1895
    pub compiler: Compiler,
1896
    pub target: TargetSelection,
K
kennytm 已提交
1897 1898 1899
    pub mode: Mode,
    pub test_kind: TestKind,
    pub krate: Interned<String>,
1900
}
1901

M
Mark Simulacrum 已提交
1902
impl Step for Crate {
1903
    type Output = ();
1904 1905
    const DEFAULT: bool = true;

1906 1907
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.krate("test")
1908 1909
    }

T
Taiki Endo 已提交
1910
    fn make_run(run: RunConfig<'_>) {
1911
        let builder = run.builder;
1912
        let compiler = builder.compiler(builder.top_stage, run.build_triple());
1913

1914
        let make = |mode: Mode, krate: &CargoCrate| {
1915
            let test_kind = builder.kind.into();
1916

M
Mark Simulacrum 已提交
1917
            builder.ensure(Crate {
1918 1919
                compiler,
                target: run.target,
1920 1921
                mode,
                test_kind,
1922
                krate: krate.name,
1923 1924 1925
            });
        };

1926
        for krate in builder.in_tree_crates("test", Some(run.target)) {
E
Eric Huss 已提交
1927
            if krate.path.ends_with(&run.path) {
1928
                make(Mode::Std, krate);
1929 1930 1931
            }
        }
    }
1932

A
Alexander Regueiro 已提交
1933
    /// Runs all unit tests plus documentation tests for a given crate defined
1934
    /// by a `Cargo.toml` (single manifest)
1935 1936 1937 1938 1939 1940
    ///
    /// 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 已提交
1941
    fn run(self, builder: &Builder<'_>) {
1942 1943 1944 1945 1946 1947
        let compiler = self.compiler;
        let target = self.target;
        let mode = self.mode;
        let test_kind = self.test_kind;
        let krate = self.krate;

1948
        builder.ensure(compile::Std { compiler, target });
1949
        builder.ensure(RemoteCopyLibs { compiler, target });
A
Alex Crichton 已提交
1950

1951 1952 1953 1954 1955
        // 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 已提交
1956

1957 1958
        let mut cargo =
            builder.cargo(compiler, mode, SourceType::InTree, target, test_kind.subcommand());
1959
        match mode {
C
Collins Abitekaniza 已提交
1960
            Mode::Std => {
1961
                compile::std_cargo(builder, target, compiler.stage, &mut cargo);
1962
            }
C
Collins Abitekaniza 已提交
1963
            Mode::Rustc => {
1964
                builder.ensure(compile::Rustc { compiler, target });
1965
                compile::rustc_cargo(builder, &mut cargo, target);
1966 1967 1968 1969 1970 1971 1972 1973 1974
            }
            _ => 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.
1975
        if test_kind.subcommand() == "test" && !builder.fail_fast {
1976 1977
            cargo.arg("--no-fail-fast");
        }
K
kennytm 已提交
1978
        match builder.doc_tests {
K
kennytm 已提交
1979
            DocTests::Only => {
K
kennytm 已提交
1980 1981
                cargo.arg("--doc");
            }
K
kennytm 已提交
1982
            DocTests::No => {
K
kennytm 已提交
1983 1984
                cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
            }
K
kennytm 已提交
1985
            DocTests::Yes => {}
1986
        }
1987

1988
        cargo.arg("-p").arg(krate);
1989

1990 1991 1992 1993 1994 1995
        // 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();
1996
        dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
1997 1998 1999
        cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());

        cargo.arg("--");
2000
        cargo.args(&builder.config.cmd.test_args());
2001

O
Oliver Schneider 已提交
2002
        if !builder.config.verbose_tests {
2003 2004
            cargo.arg("--quiet");
        }
2005

2006
        if target.contains("emscripten") {
S
Santiago Pastorino 已提交
2007
            cargo.env(
2008
                format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
M
Mark Rousskov 已提交
2009
                builder.config.nodejs.as_ref().expect("nodejs not configured"),
S
Santiago Pastorino 已提交
2010
            );
O
Oliver Schneider 已提交
2011
        } else if target.starts_with("wasm32") {
M
Mark Rousskov 已提交
2012 2013 2014
            let node = builder.config.nodejs.as_ref().expect("nodejs not configured");
            let runner =
                format!("{} {}/src/etc/wasm32-shim.js", node.display(), builder.src.display());
2015
            cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), &runner);
2016
        } else if builder.remote_tested(target) {
S
Santiago Pastorino 已提交
2017
            cargo.env(
2018
                format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
2019
                format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
S
Santiago Pastorino 已提交
2020
            );
2021
        }
2022

S
Santiago Pastorino 已提交
2023 2024 2025 2026
        builder.info(&format!(
            "{} {} stage{} ({} -> {})",
            test_kind, krate, compiler.stage, &compiler.host, target
        ));
2027
        let _time = util::timeit(&builder);
2028
        try_run(builder, &mut cargo.into());
2029 2030
    }
}
2031

M
Mark Simulacrum 已提交
2032
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2033
pub struct CrateRustdoc {
2034
    host: TargetSelection,
M
Mark Simulacrum 已提交
2035 2036 2037
    test_kind: TestKind,
}

2038
impl Step for CrateRustdoc {
M
Mark Simulacrum 已提交
2039 2040 2041 2042
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

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

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

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

2052
        builder.ensure(CrateRustdoc { host: run.target, test_kind });
M
Mark Simulacrum 已提交
2053 2054
    }

T
Taiki Endo 已提交
2055
    fn run(self, builder: &Builder<'_>) {
M
Mark Simulacrum 已提交
2056
        let test_kind = self.test_kind;
E
Eric Huss 已提交
2057
        let target = self.host;
M
Mark Simulacrum 已提交
2058

E
Eric Huss 已提交
2059 2060 2061 2062 2063
        // Use the previous stage compiler to reuse the artifacts that are
        // created when running compiletest for src/test/rustdoc. If this used
        // `compiler`, then it would cause rustdoc to be built *again*, which
        // isn't really necessary.
        let compiler = builder.compiler_for(builder.top_stage, target, target);
2064
        builder.ensure(compile::Rustc { compiler, target });
M
Mark Simulacrum 已提交
2065

M
Mark Rousskov 已提交
2066 2067 2068 2069 2070 2071 2072 2073 2074 2075
        let mut cargo = tool::prepare_tool_cargo(
            builder,
            compiler,
            Mode::ToolRustc,
            target,
            test_kind.subcommand(),
            "src/tools/rustdoc",
            SourceType::InTree,
            &[],
        );
2076
        if test_kind.subcommand() == "test" && !builder.fail_fast {
M
Mark Simulacrum 已提交
2077 2078 2079 2080 2081 2082
            cargo.arg("--no-fail-fast");
        }

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

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

2085 2086 2087 2088
        if self.host.contains("musl") {
            cargo.arg("'-Ctarget-feature=-crt-static'");
        }

E
Eric Huss 已提交
2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114
        // This is needed for running doctests on librustdoc. This is a bit of
        // an unfortunate interaction with how bootstrap works and how cargo
        // sets up the dylib path, and the fact that the doctest (in
        // html/markdown.rs) links to rustc-private libs. For stage1, the
        // compiler host dylibs (in stage1/lib) are not the same as the target
        // dylibs (in stage1/lib/rustlib/...). This is different from a normal
        // rust distribution where they are the same.
        //
        // On the cargo side, normal tests use `target_process` which handles
        // setting up the dylib for a *target* (stage1/lib/rustlib/... in this
        // case). However, for doctests it uses `rustdoc_process` which only
        // sets up the dylib path for the *host* (stage1/lib), which is the
        // wrong directory.
        //
        // It should be considered to just stop running doctests on
        // librustdoc. There is only one test, and it doesn't look too
        // important. There might be other ways to avoid this, but it seems
        // pretty convoluted.
        //
        // See also https://github.com/rust-lang/rust/issues/13983 where the
        // host vs target dylibs for rustdoc are consistently tricky to deal
        // with.
        let mut dylib_path = dylib_path();
        dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
        cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());

O
Oliver Schneider 已提交
2115
        if !builder.config.verbose_tests {
M
Mark Simulacrum 已提交
2116 2117 2118
            cargo.arg("--quiet");
        }

S
Santiago Pastorino 已提交
2119 2120 2121 2122
        builder.info(&format!(
            "{} rustdoc stage{} ({} -> {})",
            test_kind, compiler.stage, &compiler.host, target
        ));
2123
        let _time = util::timeit(&builder);
2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194

        try_run(builder, &mut cargo.into());
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CrateRustdocJsonTypes {
    host: TargetSelection,
    test_kind: TestKind,
}

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

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.path("src/rustdoc-json-types")
    }

    fn make_run(run: RunConfig<'_>) {
        let builder = run.builder;

        let test_kind = builder.kind.into();

        builder.ensure(CrateRustdocJsonTypes { host: run.target, test_kind });
    }

    fn run(self, builder: &Builder<'_>) {
        let test_kind = self.test_kind;
        let target = self.host;

        // Use the previous stage compiler to reuse the artifacts that are
        // created when running compiletest for src/test/rustdoc. If this used
        // `compiler`, then it would cause rustdoc to be built *again*, which
        // isn't really necessary.
        let compiler = builder.compiler_for(builder.top_stage, target, target);
        builder.ensure(compile::Rustc { compiler, target });

        let mut cargo = tool::prepare_tool_cargo(
            builder,
            compiler,
            Mode::ToolRustc,
            target,
            test_kind.subcommand(),
            "src/rustdoc-json-types",
            SourceType::InTree,
            &[],
        );
        if test_kind.subcommand() == "test" && !builder.fail_fast {
            cargo.arg("--no-fail-fast");
        }

        cargo.arg("-p").arg("rustdoc-json-types");

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

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

        if !builder.config.verbose_tests {
            cargo.arg("--quiet");
        }

        builder.info(&format!(
            "{} rustdoc-json-types stage{} ({} -> {})",
            test_kind, compiler.stage, &compiler.host, target
        ));
        let _time = util::timeit(&builder);
M
Mark Simulacrum 已提交
2195

2196
        try_run(builder, &mut cargo.into());
M
Mark Simulacrum 已提交
2197 2198 2199
    }
}

2200 2201 2202 2203 2204
/// 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 已提交
2205
/// Most of the time this is a no-op. For some steps such as shipping data to
2206 2207 2208
/// 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.
2209 2210 2211
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RemoteCopyLibs {
    compiler: Compiler,
2212
    target: TargetSelection,
2213
}
2214

2215
impl Step for RemoteCopyLibs {
2216
    type Output = ();
2217

T
Taiki Endo 已提交
2218
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2219
        run.never()
2220 2221
    }

T
Taiki Endo 已提交
2222
    fn run(self, builder: &Builder<'_>) {
2223 2224
        let compiler = self.compiler;
        let target = self.target;
2225
        if !builder.remote_tested(target) {
S
Santiago Pastorino 已提交
2226
            return;
2227 2228
        }

2229
        builder.ensure(compile::Std { compiler, target });
2230

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

2234
        let server = builder.ensure(tool::RemoteTestServer { compiler, target });
2235 2236

        // Spawn the emulator and wait for it to come online
2237
        let tool = builder.tool_exe(Tool::RemoteTestClient);
2238
        let mut cmd = Command::new(&tool);
2239
        cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.out.join("tmp"));
2240
        if let Some(rootfs) = builder.qemu_rootfs(target) {
2241 2242
            cmd.arg(rootfs);
        }
2243
        builder.run(&mut cmd);
2244 2245

        // Push all our dylibs to the emulator
2246
        for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) {
2247 2248 2249
            let f = t!(f);
            let name = f.file_name().into_string().unwrap();
            if util::is_dylib(&name) {
S
Santiago Pastorino 已提交
2250
                builder.run(Command::new(&tool).arg("push").arg(f.path()));
2251
            }
2252 2253 2254 2255
        }
    }
}

2256
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2257
pub struct Distcheck;
A
Alex Crichton 已提交
2258

2259
impl Step for Distcheck {
2260 2261
    type Output = ();

T
Taiki Endo 已提交
2262
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2263
        run.path("distcheck")
2264 2265
    }

T
Taiki Endo 已提交
2266
    fn make_run(run: RunConfig<'_>) {
M
Mark Simulacrum 已提交
2267 2268 2269
        run.builder.ensure(Distcheck);
    }

A
Alexander Regueiro 已提交
2270
    /// Runs "distcheck", a 'make check' from a tarball
T
Taiki Endo 已提交
2271
    fn run(self, builder: &Builder<'_>) {
2272
        builder.info("Distcheck");
2273
        let dir = builder.out.join("tmp").join("distcheck");
2274 2275 2276
        let _ = fs::remove_dir_all(&dir);
        t!(fs::create_dir_all(&dir));

M
Mark Simulacrum 已提交
2277 2278 2279 2280
        // Guarantee that these are built before we begin running.
        builder.ensure(dist::PlainSourceTarball);
        builder.ensure(dist::Src);

2281
        let mut cmd = Command::new("tar");
2282
        cmd.arg("-xf")
2283
            .arg(builder.ensure(dist::PlainSourceTarball).tarball())
S
Santiago Pastorino 已提交
2284 2285
            .arg("--strip-components=1")
            .current_dir(&dir);
2286
        builder.run(&mut cmd);
S
Santiago Pastorino 已提交
2287 2288 2289 2290 2291 2292 2293
        builder.run(
            Command::new("./configure")
                .args(&builder.config.configure_args)
                .arg("--enable-vendor")
                .current_dir(&dir),
        );
        builder.run(
2294 2295 2296
            Command::new(build_helper::make(&builder.config.build.triple))
                .arg("check")
                .current_dir(&dir),
S
Santiago Pastorino 已提交
2297
        );
2298 2299

        // Now make sure that rust-src has all of libstd's dependencies
2300
        builder.info("Distcheck rust-src");
2301
        let dir = builder.out.join("tmp").join("distcheck-src");
2302 2303 2304 2305
        let _ = fs::remove_dir_all(&dir);
        t!(fs::create_dir_all(&dir));

        let mut cmd = Command::new("tar");
2306 2307 2308 2309
        cmd.arg("-xf")
            .arg(builder.ensure(dist::Src).tarball())
            .arg("--strip-components=1")
            .current_dir(&dir);
2310
        builder.run(&mut cmd);
2311

M
mark 已提交
2312
        let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
S
Santiago Pastorino 已提交
2313 2314 2315 2316 2317 2318 2319
        builder.run(
            Command::new(&builder.initial_cargo)
                .arg("generate-lockfile")
                .arg("--manifest-path")
                .arg(&toml)
                .current_dir(&dir),
        );
2320
    }
A
Alex Crichton 已提交
2321
}
2322

2323
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2324 2325
pub struct Bootstrap;

2326
impl Step for Bootstrap {
2327
    type Output = ();
2328 2329
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;
2330

A
Alexander Regueiro 已提交
2331
    /// Tests the build system itself.
T
Taiki Endo 已提交
2332
    fn run(self, builder: &Builder<'_>) {
2333
        let mut cmd = Command::new(&builder.initial_cargo);
2334
        cmd.arg("test")
S
Santiago Pastorino 已提交
2335 2336 2337
            .current_dir(builder.src.join("src/bootstrap"))
            .env("RUSTFLAGS", "-Cdebuginfo=2")
            .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
2338 2339
            .env("BOOTSTRAP_OUTPUT_DIRECTORY", &builder.config.out)
            .env("BOOTSTRAP_INITIAL_CARGO", &builder.config.initial_cargo)
S
Santiago Pastorino 已提交
2340 2341
            .env("RUSTC_BOOTSTRAP", "1")
            .env("RUSTC", &builder.initial_rustc);
2342 2343 2344 2345 2346 2347
        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);
        }
2348
        if !builder.fail_fast {
2349 2350
            cmd.arg("--no-fail-fast");
        }
2351
        cmd.arg("--").args(&builder.config.cmd.test_args());
2352 2353 2354
        // 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");
2355
        try_run(builder, &mut cmd);
2356
    }
2357

T
Taiki Endo 已提交
2358
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2359
        run.path("src/bootstrap")
2360 2361
    }

T
Taiki Endo 已提交
2362
    fn make_run(run: RunConfig<'_>) {
2363
        run.builder.ensure(Bootstrap);
2364
    }
2365
}
2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct TierCheck {
    pub compiler: Compiler,
}

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

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.path("src/tools/tier-check")
    }

    fn make_run(run: RunConfig<'_>) {
2382 2383 2384
        let compiler =
            run.builder.compiler_for(run.builder.top_stage, run.builder.build.build, run.target);
        run.builder.ensure(TierCheck { compiler });
2385 2386 2387 2388
    }

    /// Tests the Platform Support page in the rustc book.
    fn run(self, builder: &Builder<'_>) {
2389
        builder.ensure(compile::Std { compiler: self.compiler, target: self.compiler.host });
2390 2391 2392
        let mut cargo = tool::prepare_tool_cargo(
            builder,
            self.compiler,
2393 2394
            Mode::ToolStd,
            self.compiler.host,
2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409
            "run",
            "src/tools/tier-check",
            SourceType::InTree,
            &[],
        );
        cargo.arg(builder.src.join("src/doc/rustc/src/platform-support.md"));
        cargo.arg(&builder.rustc(self.compiler));
        if builder.is_verbose() {
            cargo.arg("--verbose");
        }

        builder.info("platform support check");
        try_run(builder, &mut cargo.into());
    }
}
2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct LintDocs {
    pub compiler: Compiler,
    pub target: TargetSelection,
}

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

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.path("src/tools/lint-docs")
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(LintDocs {
            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
            target: run.target,
        });
    }

    /// Tests that the lint examples in the rustc book generate the correct
    /// lints and have the expected format.
    fn run(self, builder: &Builder<'_>) {
        builder.ensure(crate::doc::RustcBook {
            compiler: self.compiler,
            target: self.target,
            validate: true,
        });
    }
}