test.rs 67.3 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 12
use std::path::{Path, PathBuf};
use std::process::Command;
13

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

L
ljedrz 已提交
16 17 18
use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
use crate::cache::{Interned, INTERNER};
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

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

M
mark 已提交
114
        builder.default_doc(None);
115

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

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

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

133 134
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Cargotest {
135
    stage: u32,
136
    host: TargetSelection,
137
}
138

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

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

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

151 152 153 154
    /// 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 已提交
155
    fn run(self, builder: &Builder<'_>) {
156
        let compiler = builder.compiler(self.stage, self.host);
M
Mark Rousskov 已提交
157
        builder.ensure(compile::Rustc { compiler, target: compiler.host });
E
Eric Huss 已提交
158
        let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host });
159 160 161 162

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

166
        let _time = util::timeit(&builder);
167
        let mut cmd = builder.tool_cmd(Tool::CargoTest);
S
Santiago Pastorino 已提交
168 169
        try_run(
            builder,
E
Eric Huss 已提交
170
            cmd.arg(&cargo)
S
Santiago Pastorino 已提交
171 172
                .arg(&out_dir)
                .env("RUSTC", builder.rustc(compiler))
M
Mark Rousskov 已提交
173
                .env("RUSTDOC", builder.rustdoc(compiler)),
S
Santiago Pastorino 已提交
174
        );
175
    }
176 177
}

178 179
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Cargo {
180
    stage: u32,
181
    host: TargetSelection,
182 183
}

184
impl Step for Cargo {
185
    type Output = ();
186 187
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
188
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
189
        run.path("src/tools/cargo")
190 191
    }

T
Taiki Endo 已提交
192
    fn make_run(run: RunConfig<'_>) {
M
Mark Rousskov 已提交
193
        run.builder.ensure(Cargo { stage: run.builder.top_stage, host: run.target });
194
    }
195 196

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

M
Mark Rousskov 已提交
200 201 202
        builder.ensure(tool::Cargo { compiler, target: self.host });
        let mut cargo = tool::prepare_tool_cargo(
            builder,
S
Santiago Pastorino 已提交
203
            compiler,
M
Mark Rousskov 已提交
204 205 206 207 208 209 210
            Mode::ToolRustc,
            self.host,
            "test",
            "src/tools/cargo",
            SourceType::Submodule,
            &[],
        );
211

212
        if !builder.fail_fast {
213 214
            cargo.arg("--no-fail-fast");
        }
215

216 217 218
        // Don't run cross-compile tests, we may not have cross-compiled libstd libs
        // available.
        cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
219 220
        // Disable a test that has issues with mingw.
        cargo.env("CARGO_TEST_DISABLE_GIT_CLI", "1");
221 222 223
        // 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");
224

225 226
        cargo.env("PATH", &path_for_cargo(builder, compiler));

227
        try_run(builder, &mut cargo.into());
228
    }
N
Nick Cameron 已提交
229 230
}

M
Mark Simulacrum 已提交
231 232
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rls {
233
    stage: u32,
234
    host: TargetSelection,
235
}
N
Nick Cameron 已提交
236

M
Mark Simulacrum 已提交
237
impl Step for Rls {
238
    type Output = ();
M
Mark Simulacrum 已提交
239 240
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
241
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
242
        run.path("src/tools/rls")
M
Mark Simulacrum 已提交
243 244
    }

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

249
    /// Runs `cargo test` for the rls.
T
Taiki Endo 已提交
250
    fn run(self, builder: &Builder<'_>) {
251 252
        let stage = self.stage;
        let host = self.host;
M
Mark Simulacrum 已提交
253
        let compiler = builder.compiler(stage, host);
N
Nick Cameron 已提交
254

M
Mark Rousskov 已提交
255 256
        let build_result =
            builder.ensure(tool::Rls { compiler, target: self.host, extra_features: Vec::new() });
257 258 259 260 261
        if build_result.is_none() {
            eprintln!("failed to test rls: could not build");
            return;
        }

M
Mark Rousskov 已提交
262 263 264 265 266 267 268 269 270 271
        let mut cargo = tool::prepare_tool_cargo(
            builder,
            compiler,
            Mode::ToolRustc,
            host,
            "test",
            "src/tools/rls",
            SourceType::Submodule,
            &[],
        );
N
Nick Cameron 已提交
272

M
Mark Simulacrum 已提交
273
        builder.add_rustc_lib_path(compiler, &mut cargo);
M
Mark Rousskov 已提交
274
        cargo.arg("--").args(builder.config.cmd.test_args());
275

276
        if try_run(builder, &mut cargo.into()) {
277
            builder.save_toolstate("rls", ToolState::TestPass);
O
Oliver Schneider 已提交
278
        }
279
    }
N
Nick Cameron 已提交
280 281
}

N
Nick Cameron 已提交
282 283 284
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustfmt {
    stage: u32,
285
    host: TargetSelection,
N
Nick Cameron 已提交
286 287 288 289 290 291
}

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

T
Taiki Endo 已提交
292
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
N
Nick Cameron 已提交
293 294 295
        run.path("src/tools/rustfmt")
    }

T
Taiki Endo 已提交
296
    fn make_run(run: RunConfig<'_>) {
M
Mark Rousskov 已提交
297
        run.builder.ensure(Rustfmt { stage: run.builder.top_stage, host: run.target });
N
Nick Cameron 已提交
298 299 300
    }

    /// Runs `cargo test` for rustfmt.
T
Taiki Endo 已提交
301
    fn run(self, builder: &Builder<'_>) {
N
Nick Cameron 已提交
302 303 304 305
        let stage = self.stage;
        let host = self.host;
        let compiler = builder.compiler(stage, host);

306 307 308 309 310 311 312 313 314 315
        let build_result = builder.ensure(tool::Rustfmt {
            compiler,
            target: self.host,
            extra_features: Vec::new(),
        });
        if build_result.is_none() {
            eprintln!("failed to test rustfmt: could not build");
            return;
        }

M
Mark Rousskov 已提交
316 317 318 319 320 321 322 323 324 325
        let mut cargo = tool::prepare_tool_cargo(
            builder,
            compiler,
            Mode::ToolRustc,
            host,
            "test",
            "src/tools/rustfmt",
            SourceType::Submodule,
            &[],
        );
N
Nick Cameron 已提交
326

N
Nick Cameron 已提交
327 328 329
        let dir = testdir(builder, compiler.host);
        t!(fs::create_dir_all(&dir));
        cargo.env("RUSTFMT_TEST_DIR", dir);
N
Nick Cameron 已提交
330 331 332

        builder.add_rustc_lib_path(compiler, &mut cargo);

333
        if try_run(builder, &mut cargo.into()) {
334
            builder.save_toolstate("rustfmt", ToolState::TestPass);
O
Oliver Schneider 已提交
335
        }
N
Nick Cameron 已提交
336 337
    }
}
O
Oliver Schneider 已提交
338 339

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
340
pub struct Miri {
O
Oliver Schneider 已提交
341
    stage: u32,
342
    host: TargetSelection,
343 344 345 346 347 348
}

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

T
Taiki Endo 已提交
349
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
R
Ralf Jung 已提交
350
        run.path("src/tools/miri")
351 352
    }

T
Taiki Endo 已提交
353
    fn make_run(run: RunConfig<'_>) {
M
Mark Rousskov 已提交
354
        run.builder.ensure(Miri { stage: run.builder.top_stage, host: run.target });
355 356 357
    }

    /// Runs `cargo test` for miri.
T
Taiki Endo 已提交
358
    fn run(self, builder: &Builder<'_>) {
O
Oliver Schneider 已提交
359
        let stage = self.stage;
360
        let host = self.host;
O
Oliver Schneider 已提交
361
        let compiler = builder.compiler(stage, host);
362

M
Mark Rousskov 已提交
363 364
        let miri =
            builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() });
365 366 367 368 369 370
        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) {
371 372
            let mut cargo =
                builder.cargo(compiler, Mode::ToolRustc, SourceType::Submodule, host, "install");
373 374 375 376 377 378 379 380 381
            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;
            }

382 383 384 385 386 387 388
            // # Run `cargo miri setup`.
            let mut cargo = tool::prepare_tool_cargo(
                builder,
                compiler,
                Mode::ToolRustc,
                host,
                "run",
389
                "src/tools/miri/cargo-miri",
390 391 392
                SourceType::Submodule,
                &[],
            );
393
            cargo.arg("--").arg("miri").arg("setup");
394 395

            // Tell `cargo miri setup` where to find the sources.
R
Ralf Jung 已提交
396
            cargo.env("XARGO_RUST_SRC", builder.src.join("library"));
397 398
            // Tell it where to find Miri.
            cargo.env("MIRI", &miri);
399 400
            // Debug things.
            cargo.env("RUST_BACKTRACE", "1");
401
            // Let cargo-miri know where xargo ended up.
402
            cargo.env("XARGO_CHECK", builder.out.join("bin").join("xargo-check"));
403

404
            let mut cargo = Command::from(cargo);
405 406 407 408 409
            if !try_run(builder, &mut cargo) {
                return;
            }

            // # Determine where Miri put its sysroot.
R
Ralf Jung 已提交
410
            // To this end, we run `cargo miri setup --print-sysroot` and capture the output.
411 412 413
            // (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 已提交
414
            cargo.arg("--print-sysroot");
415 416 417 418 419

            // 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 {
420
                builder.verbose(&format!("running: {:?}", cargo));
M
Mark Rousskov 已提交
421 422
                let out = cargo
                    .output()
423 424
                    .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 已提交
425
                // Output is "<sysroot>\n".
426 427
                let stdout = String::from_utf8(out.stdout)
                    .expect("`cargo miri setup` stdout is not valid UTF-8");
R
Ralf Jung 已提交
428 429
                let sysroot = stdout.trim_end();
                builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {:?}", sysroot));
430 431 432 433 434 435 436 437 438 439 440 441 442 443
                sysroot.to_owned()
            };

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

            // miri tests need to know about the stage sysroot
446
            cargo.env("MIRI_SYSROOT", miri_sysroot);
O
Oliver Schneider 已提交
447
            cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
448
            cargo.env("MIRI", miri);
O
Oliver Schneider 已提交
449

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

O
Oliver Schneider 已提交
452 453
            builder.add_rustc_lib_path(compiler, &mut cargo);

454
            if !try_run(builder, &mut cargo.into()) {
455
                return;
O
Oliver Schneider 已提交
456
            }
457 458 459

            // # Done!
            builder.save_toolstate("miri", ToolState::TestPass);
O
Oliver Schneider 已提交
460 461 462
        } else {
            eprintln!("failed to test miri: could not build");
        }
463 464 465
    }
}

466 467
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CompiletestTest {
468
    host: TargetSelection,
469 470 471 472 473
}

impl Step for CompiletestTest {
    type Output = ();

T
Taiki Endo 已提交
474
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
475 476 477
        run.path("src/tools/compiletest")
    }

T
Taiki Endo 已提交
478
    fn make_run(run: RunConfig<'_>) {
M
Mark Rousskov 已提交
479
        run.builder.ensure(CompiletestTest { host: run.target });
480 481 482
    }

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

M
Mark Rousskov 已提交
487 488 489 490 491 492 493 494 495 496
        let cargo = tool::prepare_tool_cargo(
            builder,
            compiler,
            Mode::ToolBootstrap,
            host,
            "test",
            "src/tools/compiletest",
            SourceType::InTree,
            &[],
        );
497

498
        try_run(builder, &mut cargo.into());
499 500 501
    }
}

502 503
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Clippy {
O
Oliver Schneider 已提交
504
    stage: u32,
505
    host: TargetSelection,
506 507 508 509 510 511 512
}

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

T
Taiki Endo 已提交
513
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
514 515 516
        run.path("src/tools/clippy")
    }

T
Taiki Endo 已提交
517
    fn make_run(run: RunConfig<'_>) {
M
Mark Rousskov 已提交
518
        run.builder.ensure(Clippy { stage: run.builder.top_stage, host: run.target });
519 520 521
    }

    /// Runs `cargo test` for clippy.
T
Taiki Endo 已提交
522
    fn run(self, builder: &Builder<'_>) {
O
Oliver Schneider 已提交
523
        let stage = self.stage;
524
        let host = self.host;
O
Oliver Schneider 已提交
525
        let compiler = builder.compiler(stage, host);
526

M
Mark Rousskov 已提交
527 528 529 530 531
        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,
532
            compiler,
M
Mark Rousskov 已提交
533 534 535 536 537 538 539
            Mode::ToolRustc,
            host,
            "test",
            "src/tools/clippy",
            SourceType::InTree,
            &[],
        );
O
Oliver Schneider 已提交
540

M
Mark Rousskov 已提交
541 542 543 544 545
        // 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());
546 547 548 549
        let target_libs = builder
            .stage_out(compiler, Mode::ToolRustc)
            .join(&self.host.triple)
            .join(builder.cargo_dir());
M
Mark Rousskov 已提交
550 551 552 553
        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 已提交
554

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

M
Mark Rousskov 已提交
557
        builder.add_rustc_lib_path(compiler, &mut cargo);
O
Oliver Schneider 已提交
558

A
Aaron Hill 已提交
559
        builder.run(&mut cargo.into());
560 561
    }
}
N
Nick Cameron 已提交
562

563 564 565 566 567 568 569 570
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("")
}
571

G
Guillaume Gomez 已提交
572 573 574 575 576 577 578 579 580 581
#[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 已提交
582
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
G
Guillaume Gomez 已提交
583 584 585
        run.path("src/tools/rustdoc-themes")
    }

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

589
        run.builder.ensure(RustdocTheme { compiler });
G
Guillaume Gomez 已提交
590 591
    }

T
Taiki Endo 已提交
592
    fn run(self, builder: &Builder<'_>) {
593
        let rustdoc = builder.out.join("bootstrap/debug/rustdoc");
G
Guillaume Gomez 已提交
594 595
        let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
        cmd.arg(rustdoc.to_str().unwrap())
M
Mark Rousskov 已提交
596
            .arg(builder.src.join("src/librustdoc/html/static/themes").to_str().unwrap())
S
Santiago Pastorino 已提交
597 598
            .env("RUSTC_STAGE", self.compiler.stage.to_string())
            .env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
M
Mark Rousskov 已提交
599
            .env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host))
S
Santiago Pastorino 已提交
600
            .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
M
Mark Rousskov 已提交
601
            .env("RUSTDOC_REAL", builder.rustdoc(self.compiler))
S
Santiago Pastorino 已提交
602 603
            .env("RUSTDOC_CRATE_VERSION", builder.rust_version())
            .env("RUSTC_BOOTSTRAP", "1");
604
        if let Some(linker) = builder.linker(self.compiler.host, true) {
G
Guillaume Gomez 已提交
605 606
            cmd.env("RUSTC_TARGET_LINKER", linker);
        }
607
        try_run(builder, &mut cmd);
G
Guillaume Gomez 已提交
608 609 610
    }
}

G
Guillaume Gomez 已提交
611
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
G
Guillaume Gomez 已提交
612
pub struct RustdocJSStd {
613
    pub target: TargetSelection,
G
Guillaume Gomez 已提交
614 615
}

G
Guillaume Gomez 已提交
616
impl Step for RustdocJSStd {
617
    type Output = ();
G
Guillaume Gomez 已提交
618 619 620
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

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

T
Taiki Endo 已提交
625
    fn make_run(run: RunConfig<'_>) {
626
        run.builder.ensure(RustdocJSStd { target: run.target });
G
Guillaume Gomez 已提交
627 628
    }

T
Taiki Endo 已提交
629
    fn run(self, builder: &Builder<'_>) {
630 631
        if let Some(ref nodejs) = builder.config.nodejs {
            let mut command = Command::new(nodejs);
632
            command
633
                .arg(builder.src.join("src/tools/rustdoc-js/tester.js"))
634 635 636
                .arg("--crate-name")
                .arg("std")
                .arg("--resource-suffix")
637 638
                .arg(crate::channel::CFG_RELEASE_NUM)
                .arg("--doc-folder")
639
                .arg(builder.doc_out(self.target))
640
                .arg("--test-folder")
641
                .arg(builder.src.join("src/test/rustdoc-js-std"));
M
Mark Rousskov 已提交
642
            builder.ensure(crate::doc::Std { target: self.target, stage: builder.top_stage });
643 644
            builder.run(&mut command);
        } else {
M
Mark Rousskov 已提交
645
            builder.info("No nodejs found, skipping \"src/test/rustdoc-js-std\" tests");
646
        }
G
Guillaume Gomez 已提交
647 648 649
    }
}

G
Guillaume Gomez 已提交
650 651
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustdocJSNotStd {
652 653
    pub host: TargetSelection,
    pub target: TargetSelection,
G
Guillaume Gomez 已提交
654 655 656 657 658 659 660 661
    pub compiler: Compiler,
}

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

G
Guillaume Gomez 已提交
662
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
G
Guillaume Gomez 已提交
663
        run.path("src/test/rustdoc-js")
G
Guillaume Gomez 已提交
664 665
    }

G
Guillaume Gomez 已提交
666
    fn make_run(run: RunConfig<'_>) {
G
Guillaume Gomez 已提交
667
        let compiler = run.builder.compiler(run.builder.top_stage, run.host);
M
Mark Rousskov 已提交
668
        run.builder.ensure(RustdocJSNotStd { host: run.host, target: run.target, compiler });
G
Guillaume Gomez 已提交
669 670
    }

G
Guillaume Gomez 已提交
671
    fn run(self, builder: &Builder<'_>) {
672 673 674
        if builder.config.nodejs.is_some() {
            builder.ensure(Compiletest {
                compiler: self.compiler,
G
Guillaume Gomez 已提交
675
                target: self.target,
676 677
                mode: "js-doc-test",
                suite: "rustdoc-js",
678
                path: "src/test/rustdoc-js",
679
                compare_mode: None,
G
Guillaume Gomez 已提交
680 681
            });
        } else {
M
Mark Rousskov 已提交
682
            builder.info("No nodejs found, skipping \"src/test/rustdoc-js\" tests");
G
Guillaume Gomez 已提交
683 684 685 686
        }
    }
}

687 688
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustdocUi {
689 690
    pub host: TargetSelection,
    pub target: TargetSelection,
691 692 693 694 695 696 697 698
    pub compiler: Compiler,
}

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

T
Taiki Endo 已提交
699
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
700 701 702
        run.path("src/test/rustdoc-ui")
    }

T
Taiki Endo 已提交
703
    fn make_run(run: RunConfig<'_>) {
704
        let compiler = run.builder.compiler(run.builder.top_stage, run.host);
M
Mark Rousskov 已提交
705
        run.builder.ensure(RustdocUi { host: run.host, target: run.target, compiler });
706 707
    }

T
Taiki Endo 已提交
708
    fn run(self, builder: &Builder<'_>) {
709 710 711 712 713
        builder.ensure(Compiletest {
            compiler: self.compiler,
            target: self.target,
            mode: "ui",
            suite: "rustdoc-ui",
714
            path: "src/test/rustdoc-ui",
715
            compare_mode: None,
716 717 718 719
        })
    }
}

720
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
M
Mark Simulacrum 已提交
721
pub struct Tidy;
722

723
impl Step for Tidy {
724
    type Output = ();
725 726
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;
727

M
Mark Simulacrum 已提交
728
    /// Runs the `tidy` tool.
729 730 731 732
    ///
    /// 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.
733 734 735
    ///
    /// Once tidy passes, this step also runs `fmt --check` if tests are being run
    /// for the `dev` or `nightly` channels.
T
Taiki Endo 已提交
736
    fn run(self, builder: &Builder<'_>) {
737
        let mut cmd = builder.tool_cmd(Tool::Tidy);
738 739
        cmd.arg(builder.src.join("src"));
        cmd.arg(&builder.initial_cargo);
M
Mark Rousskov 已提交
740 741
        if builder.is_verbose() {
            cmd.arg("--verbose");
742
        }
743

744
        builder.info("tidy check");
745
        try_run(builder, &mut cmd);
746 747 748

        if builder.config.channel == "dev" || builder.config.channel == "nightly" {
            builder.info("fmt check");
749
            crate::format::format(&builder.build, !builder.config.cmd.bless());
750
        }
751
    }
752

T
Taiki Endo 已提交
753
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
754
        run.path("src/tools/tidy")
755 756
    }

T
Taiki Endo 已提交
757
    fn make_run(run: RunConfig<'_>) {
M
Mark Simulacrum 已提交
758
        run.builder.ensure(Tidy);
759
    }
760
}
761

762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
#[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);
    }
}

791 792
fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
    builder.out.join(host.triple).join("test")
793 794
}

795 796 797
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 已提交
798
    };
799 800
}

801 802 803
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 已提交
804 805 806 807 808 809 810 811 812
        test_with_compare_mode!($name {
            path: $path,
            mode: $mode,
            suite: $suite,
            default: true,
            host: false,
            compare_mode: $compare_mode
        });
    };
813 814
}

815 816 817
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 已提交
818
    };
819 820
}

821
macro_rules! test {
822 823
    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
                   host: $host:expr }) => {
M
Mark Rousskov 已提交
824 825 826 827 828 829 830 831 832
        test_definitions!($name {
            path: $path,
            mode: $mode,
            suite: $suite,
            default: $default,
            host: $host,
            compare_mode: None
        });
    };
833 834 835 836 837
}

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 已提交
838 839 840 841 842 843 844 845 846
        test_definitions!($name {
            path: $path,
            mode: $mode,
            suite: $suite,
            default: $default,
            host: $host,
            compare_mode: Some($compare_mode)
        });
    };
847 848 849
}

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

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

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

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

M
Mark Rousskov 已提交
876
                run.builder.ensure($name { compiler, target: run.target });
877
            }
878

T
Taiki Endo 已提交
879
            fn run(self, builder: &Builder<'_>) {
880 881 882 883 884
                builder.ensure(Compiletest {
                    compiler: self.compiler,
                    target: self.target,
                    mode: $mode,
                    suite: $suite,
885
                    path: $path,
886
                    compare_mode: $compare_mode,
887 888 889
                })
            }
        }
M
Mark Rousskov 已提交
890
    };
891 892
}

893
default_test_with_compare_mode!(Ui {
894 895
    path: "src/test/ui",
    mode: "ui",
896 897
    suite: "ui",
    compare_mode: "nll"
898 899 900 901 902 903 904 905 906 907 908 909 910 911
});

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

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

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

M
Mark Rousskov 已提交
914
default_test!(Codegen { path: "src/test/codegen", mode: "codegen", suite: "codegen" });
915 916 917 918 919 920 921 922 923 924 925 926 927

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

M
Mark Rousskov 已提交
928
default_test!(Debuginfo { path: "src/test/debuginfo", mode: "debuginfo", suite: "debuginfo" });
929

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

M
Mark Rousskov 已提交
932
host_test!(Rustdoc { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" });
933

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

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

938 939 940 941 942 943
host_test!(RunMakeFullDeps {
    path: "src/test/run-make-fulldeps",
    mode: "run-make",
    suite: "run-make-fulldeps"
});

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

946 947 948
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
struct Compiletest {
    compiler: Compiler,
949
    target: TargetSelection,
950 951
    mode: &'static str,
    suite: &'static str,
952
    path: &'static str,
953
    compare_mode: Option<&'static str>,
954 955 956 957 958
}

impl Step for Compiletest {
    type Output = ();

T
Taiki Endo 已提交
959
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
960 961 962
        run.never()
    }

963 964 965 966 967
    /// 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 已提交
968
    fn run(self, builder: &Builder<'_>) {
969 970 971 972
        let compiler = self.compiler;
        let target = self.target;
        let mode = self.mode;
        let suite = self.suite;
973

974
        // Path for test suite
975
        let suite_path = self.path;
976

977
        // Skip codegen tests if they aren't enabled in configuration.
978
        if !builder.config.codegen_tests && suite == "codegen" {
979 980 981 982
            return;
        }

        if suite == "debuginfo" {
M
Mark Rousskov 已提交
983 984
            builder
                .ensure(dist::DebuggerScripts { sysroot: builder.sysroot(compiler), host: target });
985 986
        }

987
        if suite.ends_with("fulldeps") {
988 989 990
            builder.ensure(compile::Rustc { compiler, target });
        }

991 992 993
        builder.ensure(compile::Std { compiler, target });
        // ensure that `libproc_macro` is available on the host.
        builder.ensure(compile::Std { compiler, target: compiler.host });
994

995 996
        // Also provide `rust_test_helpers` for the host.
        builder.ensure(native::TestHelpers { target: compiler.host });
997

998 999
        // As well as the target, except for plain wasm32, which can't build it
        if !target.contains("wasm32") || target.contains("emscripten") {
1000 1001
            builder.ensure(native::TestHelpers { target });
        }
1002

1003
        builder.ensure(RemoteCopyLibs { compiler, target });
1004 1005

        let mut cmd = builder.tool_cmd(Tool::Compiletest);
1006 1007 1008 1009

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

M
Mark Rousskov 已提交
1010 1011
        cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(compiler));
        cmd.arg("--run-lib-path").arg(builder.sysroot_libdir(compiler, target));
1012
        cmd.arg("--rustc-path").arg(builder.rustc(compiler));
1013

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

1016
        // Avoid depending on rustdoc when we don't need it.
S
Santiago Pastorino 已提交
1017 1018
        if mode == "rustdoc"
            || (mode == "run-make" && suite.ends_with("fulldeps"))
1019 1020
            || (mode == "ui" && is_rustdoc)
            || mode == "js-doc-test"
S
Santiago Pastorino 已提交
1021
        {
M
Mark Rousskov 已提交
1022
            cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler));
1023 1024
        }

R
Rich Kadel 已提交
1025 1026 1027 1028
        if mode == "run-make" && suite.ends_with("fulldeps") {
            cmd.arg("--rust-demangler-path").arg(builder.tool_exe(Tool::RustDemangler));
        }

M
Mark Rousskov 已提交
1029 1030 1031
        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));
1032
        cmd.arg("--mode").arg(mode);
1033 1034
        cmd.arg("--target").arg(target.rustc_target_arg());
        cmd.arg("--host").arg(&*compiler.host.triple);
M
Mark Rousskov 已提交
1035
        cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
1036

1037
        if builder.config.cmd.bless() {
1038 1039 1040
            cmd.arg("--bless");
        }

M
Mark Rousskov 已提交
1041 1042 1043 1044
        let compare_mode =
            builder.config.cmd.compare_mode().or_else(|| {
                if builder.config.test_compare_mode { self.compare_mode } else { None }
            });
S
Santiago Pastorino 已提交
1045

1046 1047 1048 1049 1050
        if let Some(ref pass) = builder.config.cmd.pass() {
            cmd.arg("--pass");
            cmd.arg(pass);
        }

1051
        if let Some(ref nodejs) = builder.config.nodejs {
1052 1053
            cmd.arg("--nodejs").arg(nodejs);
        }
1054

M
Mark Rousskov 已提交
1055
        let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
1056
        if !is_rustdoc {
1057
            if builder.config.rust_optimize_tests {
G
Guillaume Gomez 已提交
1058 1059
                flags.push("-O".to_string());
            }
1060
        }
1061
        flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
G
Guillaume Gomez 已提交
1062
        flags.push("-Zunstable-options".to_string());
1063
        flags.push(builder.config.cmd.rustc_args().join(" "));
1064

J
John Kåre Alsaker 已提交
1065
        // Don't use LLD here since we want to test that rustc finds and uses a linker by itself.
1066
        if let Some(linker) = builder.linker(target, false) {
O
Oliver Schneider 已提交
1067 1068 1069
            cmd.arg("--linker").arg(linker);
        }

1070
        let mut hostflags = flags.clone();
M
Mark Rousskov 已提交
1071
        hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
1072 1073
        cmd.arg("--host-rustcflags").arg(hostflags.join(" "));

S
Shotaro Yamada 已提交
1074
        let mut targetflags = flags;
M
Mark Rousskov 已提交
1075
        targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
1076 1077
        cmd.arg("--target-rustcflags").arg(targetflags.join(" "));

1078
        cmd.arg("--docck-python").arg(builder.python());
1079

1080
        if builder.config.build.ends_with("apple-darwin") {
1081
            // Force /usr/bin/python3 on macOS for LLDB tests because we're loading the
1082 1083
            // LLDB plugin's compiled module which only works with the system python
            // (namely not Homebrew-installed python)
1084
            cmd.arg("--lldb-python").arg("/usr/bin/python3");
1085
        } else {
1086
            cmd.arg("--lldb-python").arg(builder.python());
1087
        }
1088

1089
        if let Some(ref gdb) = builder.config.gdb {
1090 1091
            cmd.arg("--gdb").arg(gdb);
        }
1092 1093 1094 1095

        let run = |cmd: &mut Command| {
            cmd.output().map(|output| {
                String::from_utf8_lossy(&output.stdout)
M
Mark Rousskov 已提交
1096 1097 1098 1099
                    .lines()
                    .next()
                    .unwrap_or_else(|| panic!("{:?} failed {:?}", cmd, output))
                    .to_string()
1100 1101
            })
        };
1102 1103
        let lldb_exe = "lldb";
        let lldb_version = Command::new(lldb_exe)
1104 1105
            .arg("--version")
            .output()
M
Mark Rousskov 已提交
1106
            .map(|output| String::from_utf8_lossy(&output.stdout).to_string())
1107 1108
            .ok();
        if let Some(ref vers) = lldb_version {
1109
            cmd.arg("--lldb-version").arg(vers);
1110
            let lldb_python_dir = run(Command::new(lldb_exe).arg("-P")).ok();
1111 1112 1113
            if let Some(ref dir) = lldb_python_dir {
                cmd.arg("--lldb-python-dir").arg(dir);
            }
1114
        }
1115

1116 1117 1118
        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);
1119 1120
        }

1121 1122
        // Get paths from cmd args
        let paths = match &builder.config.cmd {
S
Santiago Pastorino 已提交
1123 1124
            Subcommand::Test { ref paths, .. } => &paths[..],
            _ => &[],
1125 1126 1127
        };

        // Get test-args by striping suite path
S
Santiago Pastorino 已提交
1128 1129
        let mut test_args: Vec<&str> = paths
            .iter()
M
Mark Rousskov 已提交
1130 1131 1132
            .map(|p| match p.strip_prefix(".") {
                Ok(path) => path,
                Err(_) => p,
1133
            })
1134 1135
            .filter(|p| p.starts_with(suite_path) && (p.is_dir() || p.is_file()))
            .filter_map(|p| {
V
varkor 已提交
1136 1137 1138 1139 1140 1141
                // 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.
1142 1143 1144 1145 1146
                match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
                    Some(s) if s != "" => Some(s),
                    _ => None,
                }
            })
S
Santiago Pastorino 已提交
1147
            .collect();
1148 1149 1150 1151

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

        cmd.args(&test_args);
1152

1153
        if builder.is_verbose() {
1154 1155
            cmd.arg("--verbose");
        }
1156

O
Oliver Schneider 已提交
1157
        if !builder.config.verbose_tests {
1158 1159
            cmd.arg("--quiet");
        }
1160

B
bjorn3 已提交
1161
        if builder.config.llvm_enabled() {
M
Mark Rousskov 已提交
1162
            let llvm_config = builder.ensure(native::Llvm { target: builder.config.build });
1163
            if !builder.config.dry_run {
1164
                let llvm_version = output(Command::new(&llvm_config).arg("--version"));
1165 1166
                // Remove trailing newline from llvm-config output.
                let llvm_version = llvm_version.trim_end();
1167 1168
                cmd.arg("--llvm-version").arg(llvm_version);
            }
1169
            if !builder.is_rust_llvm(target) {
B
bjorn3 已提交
1170 1171 1172
                cmd.arg("--system-llvm");
            }

1173 1174 1175 1176 1177 1178 1179 1180 1181
            // 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 已提交
1182 1183
            // Only pass correct values for these flags for the `run-make` suite as it
            // requires that a C++ compiler was configured which isn't always the case.
E
Eric Huss 已提交
1184
            if !builder.config.dry_run && suite == "run-make-fulldeps" {
B
bjorn3 已提交
1185
                let llvm_components = output(Command::new(&llvm_config).arg("--components"));
S
Santiago Pastorino 已提交
1186 1187 1188 1189 1190
                cmd.arg("--cc")
                    .arg(builder.cc(target))
                    .arg("--cxx")
                    .arg(builder.cxx(target).unwrap())
                    .arg("--cflags")
1191
                    .arg(builder.cflags(target, GitRepo::Rustc).join(" "))
S
Santiago Pastorino 已提交
1192
                    .arg("--llvm-components")
1193
                    .arg(llvm_components.trim());
1194
                if let Some(ar) = builder.ar(target) {
O
Oliver Schneider 已提交
1195 1196
                    cmd.arg("--ar").arg(ar);
                }
1197 1198 1199

                // 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 已提交
1200 1201
                let llvm_bin_path = llvm_config
                    .parent()
1202 1203 1204
                    .expect("Expected llvm-config to be contained in directory");
                assert!(llvm_bin_path.is_dir());
                cmd.arg("--llvm-bin-dir").arg(llvm_bin_path);
1205 1206 1207

                // If LLD is available, add it to the PATH
                if builder.config.lld_enabled {
M
Mark Rousskov 已提交
1208 1209
                    let lld_install_root =
                        builder.ensure(native::Lld { target: builder.config.build });
1210 1211 1212 1213

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

                    let old_path = env::var_os("PATH").unwrap_or_default();
M
Mark Rousskov 已提交
1214 1215 1216 1217
                    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");
1218 1219
                    cmd.env("PATH", new_path);
                }
B
bjorn3 已提交
1220 1221 1222
            }
        }

E
Eric Huss 已提交
1223
        if suite != "run-make-fulldeps" {
S
Santiago Pastorino 已提交
1224 1225 1226 1227 1228 1229 1230 1231
            cmd.arg("--cc")
                .arg("")
                .arg("--cxx")
                .arg("")
                .arg("--cflags")
                .arg("")
                .arg("--llvm-components")
                .arg("");
1232
        }
1233

1234
        if builder.remote_tested(target) {
M
Mark Rousskov 已提交
1235
            cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
1236
        }
1237

1238 1239 1240 1241 1242 1243
        // 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") {
1244
            for &(ref k, ref v) in builder.cc[&target].env() {
1245 1246 1247
                if k != "PATH" {
                    cmd.env(k, v);
                }
1248 1249
            }
        }
1250
        cmd.env("RUSTC_BOOTSTRAP", "1");
1251
        builder.add_rust_test_threads(&mut cmd);
1252

1253
        if builder.config.sanitizers {
1254
            cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
1255
        }
1256

1257
        if builder.config.profiler {
1258
            cmd.env("RUSTC_PROFILER_SUPPORT", "1");
1259
        }
1260

M
Mark Rousskov 已提交
1261 1262 1263 1264
        let tmp = builder.out.join("tmp");
        std::fs::create_dir_all(&tmp).unwrap();
        cmd.env("RUST_TEST_TMPDIR", tmp);

1265 1266 1267 1268 1269
        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 已提交
1270
                .arg(builder.cc(target).parent().unwrap().parent().unwrap());
1271 1272 1273
        } else {
            cmd.arg("--android-cross-path").arg("");
        }
1274

1275 1276 1277 1278
        if builder.config.cmd.rustfix_coverage() {
            cmd.arg("--rustfix-coverage");
        }

1279
        builder.ci_env.force_coloring_in_ci(&mut cmd);
1280

S
Santiago Pastorino 已提交
1281 1282 1283 1284
        builder.info(&format!(
            "Check compiletest suite={} mode={} ({} -> {})",
            suite, mode, &compiler.host, target
        ));
1285 1286
        let _time = util::timeit(&builder);
        try_run(builder, &mut cmd);
1287 1288 1289

        if let Some(compare_mode) = compare_mode {
            cmd.arg("--compare-mode").arg(compare_mode);
S
Santiago Pastorino 已提交
1290 1291 1292 1293
            builder.info(&format!(
                "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
                suite, mode, compare_mode, &compiler.host, target
            ));
1294 1295 1296
            let _time = util::timeit(&builder);
            try_run(builder, &mut cmd);
        }
1297
    }
1298
}
1299

E
Eric Huss 已提交
1300 1301
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct BookTest {
1302
    compiler: Compiler,
E
Eric Huss 已提交
1303
    path: PathBuf,
1304 1305
    name: &'static str,
    is_ext_doc: bool,
1306 1307
}

E
Eric Huss 已提交
1308
impl Step for BookTest {
1309 1310
    type Output = ();
    const ONLY_HOSTS: bool = true;
1311

T
Taiki Endo 已提交
1312
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1313
        run.never()
1314
    }
M
Mark Simulacrum 已提交
1315

E
Eric Huss 已提交
1316
    /// Runs the documentation tests for a book in `src/doc`.
1317
    ///
E
Eric Huss 已提交
1318
    /// This uses the `rustdoc` that sits next to `compiler`.
T
Taiki Endo 已提交
1319
    fn run(self, builder: &Builder<'_>) {
E
Eric Huss 已提交
1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368
        // 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<'_>) {
1369
        let compiler = self.compiler;
1370

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

1373 1374
        // Do a breadth-first traversal of the `src/doc` directory and just run
        // tests for all files that end in `*.md`
1375 1376
        let mut stack = vec![builder.src.join(self.path)];
        let _time = util::timeit(&builder);
1377
        let mut files = Vec::new();
1378 1379 1380
        while let Some(p) = stack.pop() {
            if p.is_dir() {
                stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
S
Santiago Pastorino 已提交
1381
                continue;
1382 1383 1384 1385 1386 1387
            }

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

1388 1389 1390 1391 1392 1393
            files.push(p);
        }

        files.sort();

        for file in files {
E
Eric Huss 已提交
1394
            markdown_test(builder, compiler, &file);
1395
        }
1396 1397 1398
    }
}

1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
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 已提交
1412
                fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1413 1414 1415
                    run.path($path)
                }

T
Taiki Endo 已提交
1416
                fn make_run(run: RunConfig<'_>) {
1417 1418 1419 1420 1421
                    run.builder.ensure($name {
                        compiler: run.builder.compiler(run.builder.top_stage, run.host),
                    });
                }

T
Taiki Endo 已提交
1422
                fn run(self, builder: &Builder<'_>) {
E
Eric Huss 已提交
1423
                    builder.ensure(BookTest {
1424
                        compiler: self.compiler,
E
Eric Huss 已提交
1425
                        path: PathBuf::from($path),
1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438
                        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;
1439
    RustcBook, "src/doc/rustc", "rustc", default=true;
1440
    RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false;
1441
    EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false;
1442 1443
    TheBook, "src/doc/book", "book", default=false;
    UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
E
Eric Huss 已提交
1444
    EditionGuide, "src/doc/edition-guide", "edition-guide", default=false;
1445 1446
);

1447 1448 1449
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ErrorIndex {
    compiler: Compiler,
1450
}
1451

1452
impl Step for ErrorIndex {
1453
    type Output = ();
1454 1455 1456
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
1457
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1458
        run.path("src/tools/error_index_generator")
1459 1460
    }

T
Taiki Endo 已提交
1461
    fn make_run(run: RunConfig<'_>) {
E
Eric Huss 已提交
1462 1463 1464 1465 1466
        // 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.
        let compiler = run.builder.compiler_for(run.builder.top_stage, run.host, run.host);
        run.builder.ensure(ErrorIndex { compiler });
1467
    }
1468

A
Alexander Regueiro 已提交
1469
    /// Runs the error index generator tool to execute the tests located in the error
1470 1471 1472 1473 1474
    /// 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 已提交
1475
    fn run(self, builder: &Builder<'_>) {
1476 1477
        let compiler = self.compiler;

1478
        let dir = testdir(builder, compiler.host);
1479 1480 1481
        t!(fs::create_dir_all(&dir));
        let output = dir.join("error-index.md");

E
Eric Huss 已提交
1482 1483
        let mut tool = tool::ErrorIndex::command(builder, compiler);
        tool.arg("markdown").arg(&output);
1484

E
Eric Huss 已提交
1485 1486 1487 1488 1489 1490
        // Use the rustdoc that was built by self.compiler. This copy of
        // rustdoc is shared with other tests (like compiletest tests in
        // src/test/rustdoc). This helps avoid building rustdoc multiple
        // times.
        let rustdoc_compiler = builder.compiler(builder.top_stage, builder.config.build);
        builder.info(&format!("Testing error-index stage{}", rustdoc_compiler.stage));
1491
        let _time = util::timeit(&builder);
1492
        builder.run_quiet(&mut tool);
E
Eric Huss 已提交
1493 1494
        builder.ensure(compile::Std { compiler: rustdoc_compiler, target: rustdoc_compiler.host });
        markdown_test(builder, rustdoc_compiler, &output);
1495
    }
1496 1497
}

T
Taiki Endo 已提交
1498
fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
1499 1500 1501
    if let Ok(contents) = fs::read_to_string(markdown) {
        if !contents.contains("```") {
            return true;
1502
        }
1503 1504
    }

1505
    builder.info(&format!("doc tests for: {}", markdown.display()));
M
Mark Rousskov 已提交
1506
    let mut cmd = builder.rustdoc_cmd(compiler);
1507
    builder.add_rust_test_threads(&mut cmd);
1508 1509
    cmd.arg("--test");
    cmd.arg(markdown);
1510
    cmd.env("RUSTC_BOOTSTRAP", "1");
1511

1512
    let test_args = builder.config.cmd.test_args().join(" ");
1513 1514
    cmd.arg("--test-args").arg(test_args);

O
Oliver Schneider 已提交
1515
    if builder.config.verbose_tests {
1516
        try_run(builder, &mut cmd)
O
Oliver Schneider 已提交
1517 1518
    } else {
        try_run_quiet(builder, &mut cmd)
1519
    }
1520
}
1521

1522 1523 1524 1525 1526 1527 1528 1529 1530
#[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<'_> {
1531
        run.path("src/doc/rustc-dev-guide")
1532 1533 1534 1535 1536 1537 1538
    }

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

    fn run(self, builder: &Builder<'_>) {
1539
        let src = builder.src.join("src/doc/rustc-dev-guide");
1540
        let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
E
Eric Huss 已提交
1541 1542 1543 1544 1545
        let toolstate = if try_run(builder, rustbook_cmd.arg("linkcheck").arg(&src)) {
            ToolState::TestPass
        } else {
            ToolState::TestFail
        };
1546
        builder.save_toolstate("rustc-dev-guide", toolstate);
1547 1548 1549
    }
}

1550
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
M
Mark Simulacrum 已提交
1551
pub struct CrateLibrustc {
1552
    compiler: Compiler,
1553
    target: TargetSelection,
1554
    test_kind: TestKind,
1555
    krate: Interned<String>,
1556 1557
}

M
Mark Simulacrum 已提交
1558
impl Step for CrateLibrustc {
1559 1560 1561 1562
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
1563
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1564
        run.krate("rustc-main")
1565 1566
    }

T
Taiki Endo 已提交
1567
    fn make_run(run: RunConfig<'_>) {
1568 1569
        let builder = run.builder;
        let compiler = builder.compiler(builder.top_stage, run.host);
1570

1571
        for krate in builder.in_tree_crates("rustc-main") {
E
Eric Huss 已提交
1572
            if krate.path.ends_with(&run.path) {
1573
                let test_kind = builder.kind.into();
1574

1575 1576 1577 1578 1579 1580
                builder.ensure(CrateLibrustc {
                    compiler,
                    target: run.target,
                    test_kind,
                    krate: krate.name,
                });
1581 1582 1583 1584
            }
        }
    }

T
Taiki Endo 已提交
1585
    fn run(self, builder: &Builder<'_>) {
M
Mark Simulacrum 已提交
1586
        builder.ensure(Crate {
1587 1588
            compiler: self.compiler,
            target: self.target,
C
Collins Abitekaniza 已提交
1589
            mode: Mode::Rustc,
1590 1591 1592 1593 1594 1595
            test_kind: self.test_kind,
            krate: self.krate,
        });
    }
}

1596 1597 1598
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CrateNotDefault {
    compiler: Compiler,
1599
    target: TargetSelection,
1600 1601 1602 1603 1604 1605 1606
    test_kind: TestKind,
    krate: &'static str,
}

impl Step for CrateNotDefault {
    type Output = ();

T
Taiki Endo 已提交
1607
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1608
        run.path("src/librustc_asan")
1609 1610 1611 1612 1613
            .path("src/librustc_lsan")
            .path("src/librustc_msan")
            .path("src/librustc_tsan")
    }

T
Taiki Endo 已提交
1614
    fn make_run(run: RunConfig<'_>) {
1615 1616 1617
        let builder = run.builder;
        let compiler = builder.compiler(builder.top_stage, run.host);

1618
        let test_kind = builder.kind.into();
1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633

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

T
Taiki Endo 已提交
1634
    fn run(self, builder: &Builder<'_>) {
1635 1636 1637
        builder.ensure(Crate {
            compiler: self.compiler,
            target: self.target,
C
Collins Abitekaniza 已提交
1638
            mode: Mode::Std,
1639 1640 1641 1642 1643 1644
            test_kind: self.test_kind,
            krate: INTERNER.intern_str(self.krate),
        });
    }
}

K
kennytm 已提交
1645
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
M
Mark Simulacrum 已提交
1646
pub struct Crate {
K
kennytm 已提交
1647
    pub compiler: Compiler,
1648
    pub target: TargetSelection,
K
kennytm 已提交
1649 1650 1651
    pub mode: Mode,
    pub test_kind: TestKind,
    pub krate: Interned<String>,
1652
}
1653

M
Mark Simulacrum 已提交
1654
impl Step for Crate {
1655
    type Output = ();
1656 1657
    const DEFAULT: bool = true;

1658 1659
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.krate("test")
1660 1661
    }

T
Taiki Endo 已提交
1662
    fn make_run(run: RunConfig<'_>) {
1663 1664
        let builder = run.builder;
        let compiler = builder.compiler(builder.top_stage, run.host);
1665

1666
        let make = |mode: Mode, krate: &CargoCrate| {
1667
            let test_kind = builder.kind.into();
1668

M
Mark Simulacrum 已提交
1669
            builder.ensure(Crate {
1670 1671
                compiler,
                target: run.target,
1672 1673
                mode,
                test_kind,
1674
                krate: krate.name,
1675 1676 1677
            });
        };

1678
        for krate in builder.in_tree_crates("test") {
E
Eric Huss 已提交
1679
            if krate.path.ends_with(&run.path) {
1680
                make(Mode::Std, krate);
1681 1682 1683
            }
        }
    }
1684

A
Alexander Regueiro 已提交
1685
    /// Runs all unit tests plus documentation tests for a given crate defined
1686
    /// by a `Cargo.toml` (single manifest)
1687 1688 1689 1690 1691 1692
    ///
    /// 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 已提交
1693
    fn run(self, builder: &Builder<'_>) {
1694 1695 1696 1697 1698 1699
        let compiler = self.compiler;
        let target = self.target;
        let mode = self.mode;
        let test_kind = self.test_kind;
        let krate = self.krate;

1700
        builder.ensure(compile::Std { compiler, target });
1701
        builder.ensure(RemoteCopyLibs { compiler, target });
A
Alex Crichton 已提交
1702

1703 1704 1705 1706 1707
        // 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 已提交
1708

1709 1710
        let mut cargo =
            builder.cargo(compiler, mode, SourceType::InTree, target, test_kind.subcommand());
1711
        match mode {
C
Collins Abitekaniza 已提交
1712
            Mode::Std => {
1713
                compile::std_cargo(builder, target, compiler.stage, &mut cargo);
1714
            }
C
Collins Abitekaniza 已提交
1715
            Mode::Rustc => {
1716
                builder.ensure(compile::Rustc { compiler, target });
1717
                compile::rustc_cargo(builder, &mut cargo, target);
1718 1719 1720 1721 1722 1723 1724 1725 1726
            }
            _ => 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.
1727
        if test_kind.subcommand() == "test" && !builder.fail_fast {
1728 1729
            cargo.arg("--no-fail-fast");
        }
K
kennytm 已提交
1730
        match builder.doc_tests {
K
kennytm 已提交
1731
            DocTests::Only => {
K
kennytm 已提交
1732 1733
                cargo.arg("--doc");
            }
K
kennytm 已提交
1734
            DocTests::No => {
K
kennytm 已提交
1735 1736
                cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
            }
K
kennytm 已提交
1737
            DocTests::Yes => {}
1738
        }
1739

1740
        cargo.arg("-p").arg(krate);
1741

1742 1743 1744 1745 1746 1747
        // 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();
1748
        dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
1749 1750 1751
        cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());

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

O
Oliver Schneider 已提交
1754
        if !builder.config.verbose_tests {
1755 1756
            cargo.arg("--quiet");
        }
1757

1758
        if target.contains("emscripten") {
S
Santiago Pastorino 已提交
1759
            cargo.env(
1760
                format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
M
Mark Rousskov 已提交
1761
                builder.config.nodejs.as_ref().expect("nodejs not configured"),
S
Santiago Pastorino 已提交
1762
            );
O
Oliver Schneider 已提交
1763
        } else if target.starts_with("wasm32") {
M
Mark Rousskov 已提交
1764 1765 1766
            let node = builder.config.nodejs.as_ref().expect("nodejs not configured");
            let runner =
                format!("{} {}/src/etc/wasm32-shim.js", node.display(), builder.src.display());
1767
            cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), &runner);
1768
        } else if builder.remote_tested(target) {
S
Santiago Pastorino 已提交
1769
            cargo.env(
1770
                format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
1771
                format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
S
Santiago Pastorino 已提交
1772
            );
1773
        }
1774

S
Santiago Pastorino 已提交
1775 1776 1777 1778
        builder.info(&format!(
            "{} {} stage{} ({} -> {})",
            test_kind, krate, compiler.stage, &compiler.host, target
        ));
1779
        let _time = util::timeit(&builder);
1780
        try_run(builder, &mut cargo.into());
1781 1782
    }
}
1783

M
Mark Simulacrum 已提交
1784
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1785
pub struct CrateRustdoc {
1786
    host: TargetSelection,
M
Mark Simulacrum 已提交
1787 1788 1789
    test_kind: TestKind,
}

1790
impl Step for CrateRustdoc {
M
Mark Simulacrum 已提交
1791 1792 1793 1794
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

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

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

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

M
Mark Rousskov 已提交
1804
        builder.ensure(CrateRustdoc { host: run.host, test_kind });
M
Mark Simulacrum 已提交
1805 1806
    }

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

E
Eric Huss 已提交
1811 1812 1813 1814 1815
        // 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);
1816
        builder.ensure(compile::Rustc { compiler, target });
M
Mark Simulacrum 已提交
1817

M
Mark Rousskov 已提交
1818 1819 1820 1821 1822 1823 1824 1825 1826 1827
        let mut cargo = tool::prepare_tool_cargo(
            builder,
            compiler,
            Mode::ToolRustc,
            target,
            test_kind.subcommand(),
            "src/tools/rustdoc",
            SourceType::InTree,
            &[],
        );
1828
        if test_kind.subcommand() == "test" && !builder.fail_fast {
M
Mark Simulacrum 已提交
1829 1830 1831 1832 1833 1834
            cargo.arg("--no-fail-fast");
        }

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

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

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

E
Eric Huss 已提交
1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866
        // 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 已提交
1867
        if !builder.config.verbose_tests {
M
Mark Simulacrum 已提交
1868 1869 1870
            cargo.arg("--quiet");
        }

S
Santiago Pastorino 已提交
1871 1872 1873 1874
        builder.info(&format!(
            "{} rustdoc stage{} ({} -> {})",
            test_kind, compiler.stage, &compiler.host, target
        ));
1875
        let _time = util::timeit(&builder);
M
Mark Simulacrum 已提交
1876

1877
        try_run(builder, &mut cargo.into());
M
Mark Simulacrum 已提交
1878 1879 1880
    }
}

1881 1882 1883 1884 1885
/// 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 已提交
1886
/// Most of the time this is a no-op. For some steps such as shipping data to
1887 1888 1889
/// 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.
1890 1891 1892
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RemoteCopyLibs {
    compiler: Compiler,
1893
    target: TargetSelection,
1894
}
1895

1896
impl Step for RemoteCopyLibs {
1897
    type Output = ();
1898

T
Taiki Endo 已提交
1899
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1900
        run.never()
1901 1902
    }

T
Taiki Endo 已提交
1903
    fn run(self, builder: &Builder<'_>) {
1904 1905
        let compiler = self.compiler;
        let target = self.target;
1906
        if !builder.remote_tested(target) {
S
Santiago Pastorino 已提交
1907
            return;
1908 1909
        }

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

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

M
Mark Rousskov 已提交
1915 1916
        let server =
            builder.ensure(tool::RemoteTestServer { compiler: compiler.with_stage(0), target });
1917 1918

        // Spawn the emulator and wait for it to come online
1919
        let tool = builder.tool_exe(Tool::RemoteTestClient);
1920
        let mut cmd = Command::new(&tool);
1921
        cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.out.join("tmp"));
1922
        if let Some(rootfs) = builder.qemu_rootfs(target) {
1923 1924
            cmd.arg(rootfs);
        }
1925
        builder.run(&mut cmd);
1926 1927

        // Push all our dylibs to the emulator
1928
        for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) {
1929 1930 1931
            let f = t!(f);
            let name = f.file_name().into_string().unwrap();
            if util::is_dylib(&name) {
S
Santiago Pastorino 已提交
1932
                builder.run(Command::new(&tool).arg("push").arg(f.path()));
1933
            }
1934 1935 1936 1937
        }
    }
}

1938
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1939
pub struct Distcheck;
A
Alex Crichton 已提交
1940

1941
impl Step for Distcheck {
1942 1943
    type Output = ();

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

T
Taiki Endo 已提交
1948
    fn make_run(run: RunConfig<'_>) {
M
Mark Simulacrum 已提交
1949 1950 1951
        run.builder.ensure(Distcheck);
    }

A
Alexander Regueiro 已提交
1952
    /// Runs "distcheck", a 'make check' from a tarball
T
Taiki Endo 已提交
1953
    fn run(self, builder: &Builder<'_>) {
1954
        builder.info("Distcheck");
1955
        let dir = builder.out.join("tmp").join("distcheck");
1956 1957 1958
        let _ = fs::remove_dir_all(&dir);
        t!(fs::create_dir_all(&dir));

M
Mark Simulacrum 已提交
1959 1960 1961 1962
        // Guarantee that these are built before we begin running.
        builder.ensure(dist::PlainSourceTarball);
        builder.ensure(dist::Src);

1963 1964
        let mut cmd = Command::new("tar");
        cmd.arg("-xzf")
S
Santiago Pastorino 已提交
1965 1966 1967
            .arg(builder.ensure(dist::PlainSourceTarball))
            .arg("--strip-components=1")
            .current_dir(&dir);
1968
        builder.run(&mut cmd);
S
Santiago Pastorino 已提交
1969 1970 1971 1972 1973 1974 1975
        builder.run(
            Command::new("./configure")
                .args(&builder.config.configure_args)
                .arg("--enable-vendor")
                .current_dir(&dir),
        );
        builder.run(
1976 1977 1978
            Command::new(build_helper::make(&builder.config.build.triple))
                .arg("check")
                .current_dir(&dir),
S
Santiago Pastorino 已提交
1979
        );
1980 1981

        // Now make sure that rust-src has all of libstd's dependencies
1982
        builder.info("Distcheck rust-src");
1983
        let dir = builder.out.join("tmp").join("distcheck-src");
1984 1985 1986 1987 1988
        let _ = fs::remove_dir_all(&dir);
        t!(fs::create_dir_all(&dir));

        let mut cmd = Command::new("tar");
        cmd.arg("-xzf")
S
Santiago Pastorino 已提交
1989 1990 1991
            .arg(builder.ensure(dist::Src))
            .arg("--strip-components=1")
            .current_dir(&dir);
1992
        builder.run(&mut cmd);
1993

M
mark 已提交
1994
        let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
S
Santiago Pastorino 已提交
1995 1996 1997 1998 1999 2000 2001
        builder.run(
            Command::new(&builder.initial_cargo)
                .arg("generate-lockfile")
                .arg("--manifest-path")
                .arg(&toml)
                .current_dir(&dir),
        );
2002
    }
A
Alex Crichton 已提交
2003
}
2004

2005
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2006 2007
pub struct Bootstrap;

2008
impl Step for Bootstrap {
2009
    type Output = ();
2010 2011
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;
2012

A
Alexander Regueiro 已提交
2013
    /// Tests the build system itself.
T
Taiki Endo 已提交
2014
    fn run(self, builder: &Builder<'_>) {
2015
        let mut cmd = Command::new(&builder.initial_cargo);
2016
        cmd.arg("test")
S
Santiago Pastorino 已提交
2017 2018 2019 2020 2021
            .current_dir(builder.src.join("src/bootstrap"))
            .env("RUSTFLAGS", "-Cdebuginfo=2")
            .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
            .env("RUSTC_BOOTSTRAP", "1")
            .env("RUSTC", &builder.initial_rustc);
2022 2023 2024 2025 2026 2027
        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);
        }
2028
        if !builder.fail_fast {
2029 2030
            cmd.arg("--no-fail-fast");
        }
2031
        cmd.arg("--").args(&builder.config.cmd.test_args());
2032 2033 2034
        // 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");
2035
        try_run(builder, &mut cmd);
2036
    }
2037

T
Taiki Endo 已提交
2038
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2039
        run.path("src/bootstrap")
2040 2041
    }

T
Taiki Endo 已提交
2042
    fn make_run(run: RunConfig<'_>) {
2043
        run.builder.ensure(Bootstrap);
2044
    }
2045
}