test.rs 71.1 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

273
        cargo.add_rustc_lib_path(builder, compiler);
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
        cargo.add_rustc_lib_path(builder, compiler);
N
Nick Cameron 已提交
332

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());

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

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

487 488 489
        // 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 已提交
490 491 492
        let cargo = tool::prepare_tool_cargo(
            builder,
            compiler,
493
            Mode::ToolStd,
M
Mark Rousskov 已提交
494 495 496 497 498 499
            host,
            "test",
            "src/tools/compiletest",
            SourceType::InTree,
            &[],
        );
500

501
        try_run(builder, &mut cargo.into());
502 503 504
    }
}

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

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

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

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

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

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

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

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

560
        cargo.add_rustc_lib_path(builder, compiler);
O
Oliver Schneider 已提交
561

A
Aaron Hill 已提交
562
        builder.run(&mut cargo.into());
563 564
    }
}
N
Nick Cameron 已提交
565

566 567 568 569 570 571 572 573
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("")
}
574

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

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

592
        run.builder.ensure(RustdocTheme { compiler });
G
Guillaume Gomez 已提交
593 594
    }

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

G
Guillaume Gomez 已提交
616
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
G
Guillaume Gomez 已提交
617
pub struct RustdocJSStd {
618
    pub target: TargetSelection,
G
Guillaume Gomez 已提交
619 620
}

G
Guillaume Gomez 已提交
621
impl Step for RustdocJSStd {
622
    type Output = ();
G
Guillaume Gomez 已提交
623 624 625
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

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

T
Taiki Endo 已提交
630
    fn make_run(run: RunConfig<'_>) {
631
        run.builder.ensure(RustdocJSStd { target: run.target });
G
Guillaume Gomez 已提交
632 633
    }

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

G
Guillaume Gomez 已提交
655 656
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustdocJSNotStd {
657
    pub target: TargetSelection,
G
Guillaume Gomez 已提交
658 659 660 661 662 663 664 665
    pub compiler: Compiler,
}

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

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

G
Guillaume Gomez 已提交
670
    fn make_run(run: RunConfig<'_>) {
671 672
        let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
        run.builder.ensure(RustdocJSNotStd { target: run.target, compiler });
G
Guillaume Gomez 已提交
673 674
    }

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

691
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
M
Mark Simulacrum 已提交
692
pub struct Tidy;
693

694
impl Step for Tidy {
695
    type Output = ();
696 697
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;
698

M
Mark Simulacrum 已提交
699
    /// Runs the `tidy` tool.
700 701 702 703
    ///
    /// 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.
704 705 706
    ///
    /// Once tidy passes, this step also runs `fmt --check` if tests are being run
    /// for the `dev` or `nightly` channels.
T
Taiki Endo 已提交
707
    fn run(self, builder: &Builder<'_>) {
708
        let mut cmd = builder.tool_cmd(Tool::Tidy);
M
mark 已提交
709
        cmd.arg(&builder.src);
710
        cmd.arg(&builder.initial_cargo);
711
        cmd.arg(&builder.out);
M
Mark Rousskov 已提交
712 713
        if builder.is_verbose() {
            cmd.arg("--verbose");
714
        }
715

716
        builder.info("tidy check");
717
        try_run(builder, &mut cmd);
718 719 720

        if builder.config.channel == "dev" || builder.config.channel == "nightly" {
            builder.info("fmt check");
721
            crate::format::format(&builder.build, !builder.config.cmd.bless());
722
        }
723
    }
724

T
Taiki Endo 已提交
725
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
726
        run.path("src/tools/tidy")
727 728
    }

T
Taiki Endo 已提交
729
    fn make_run(run: RunConfig<'_>) {
M
Mark Simulacrum 已提交
730
        run.builder.ensure(Tidy);
731
    }
732
}
733

734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
#[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);
    }
}

763 764
fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
    builder.out.join(host.triple).join("test")
765 766
}

767 768 769
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 已提交
770
    };
771 772
}

773 774 775
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 已提交
776 777 778 779 780 781 782 783 784
        test_with_compare_mode!($name {
            path: $path,
            mode: $mode,
            suite: $suite,
            default: true,
            host: false,
            compare_mode: $compare_mode
        });
    };
785 786
}

787 788 789
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 已提交
790
    };
791 792
}

793
macro_rules! test {
794 795
    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
                   host: $host:expr }) => {
M
Mark Rousskov 已提交
796 797 798 799 800 801 802 803 804
        test_definitions!($name {
            path: $path,
            mode: $mode,
            suite: $suite,
            default: $default,
            host: $host,
            compare_mode: None
        });
    };
805 806 807 808 809
}

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 已提交
810 811 812 813 814 815 816 817 818
        test_definitions!($name {
            path: $path,
            mode: $mode,
            suite: $suite,
            default: $default,
            host: $host,
            compare_mode: Some($compare_mode)
        });
    };
819 820 821
}

macro_rules! test_definitions {
822 823 824 825 826
    ($name:ident {
        path: $path:expr,
        mode: $mode:expr,
        suite: $suite:expr,
        default: $default:expr,
827 828
        host: $host:expr,
        compare_mode: $compare_mode:expr
829 830 831 832
    }) => {
        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
        pub struct $name {
            pub compiler: Compiler,
833
            pub target: TargetSelection,
834 835
        }

836 837 838 839
        impl Step for $name {
            type Output = ();
            const DEFAULT: bool = $default;
            const ONLY_HOSTS: bool = $host;
840

T
Taiki Endo 已提交
841
            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
842
                run.suite_path($path)
843
            }
844

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

M
Mark Rousskov 已提交
848
                run.builder.ensure($name { compiler, target: run.target });
849
            }
850

T
Taiki Endo 已提交
851
            fn run(self, builder: &Builder<'_>) {
852 853 854 855 856
                builder.ensure(Compiletest {
                    compiler: self.compiler,
                    target: self.target,
                    mode: $mode,
                    suite: $suite,
857
                    path: $path,
858
                    compare_mode: $compare_mode,
859 860 861
                })
            }
        }
M
Mark Rousskov 已提交
862
    };
863 864
}

865
default_test_with_compare_mode!(Ui {
866 867
    path: "src/test/ui",
    mode: "ui",
868 869
    suite: "ui",
    compare_mode: "nll"
870 871 872 873 874 875 876 877
});

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

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

M
Mark Rousskov 已提交
880
default_test!(Codegen { path: "src/test/codegen", mode: "codegen", suite: "codegen" });
881 882 883 884 885 886 887 888 889 890 891 892 893

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

894 895 896 897 898 899
default_test_with_compare_mode!(Debuginfo {
    path: "src/test/debuginfo",
    mode: "debuginfo",
    suite: "debuginfo",
    compare_mode: "split-dwarf"
});
900

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

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

N
Nixon Enraght-Moony 已提交
906 907 908 909 910 911
host_test!(RustdocJson {
    path: "src/test/rustdoc-json",
    mode: "rustdoc-json",
    suite: "rustdoc-json"
});

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

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

916 917 918 919 920 921
host_test!(RunMakeFullDeps {
    path: "src/test/run-make-fulldeps",
    mode: "run-make",
    suite: "run-make-fulldeps"
});

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

924 925 926
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
struct Compiletest {
    compiler: Compiler,
927
    target: TargetSelection,
928 929
    mode: &'static str,
    suite: &'static str,
930
    path: &'static str,
931
    compare_mode: Option<&'static str>,
932 933 934 935 936
}

impl Step for Compiletest {
    type Output = ();

T
Taiki Endo 已提交
937
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
938 939 940
        run.never()
    }

941 942 943 944 945
    /// 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 已提交
946
    fn run(self, builder: &Builder<'_>) {
947 948 949
        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
950 951
help: to test the compiler, use `--stage 1` instead
help: to test the standard library, use `--stage 0 library/std` instead
952 953 954 955 956
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);
        }

957 958 959 960
        let compiler = self.compiler;
        let target = self.target;
        let mode = self.mode;
        let suite = self.suite;
961

962
        // Path for test suite
963
        let suite_path = self.path;
964

965
        // Skip codegen tests if they aren't enabled in configuration.
966
        if !builder.config.codegen_tests && suite == "codegen" {
967 968 969 970
            return;
        }

        if suite == "debuginfo" {
M
Mark Rousskov 已提交
971 972
            builder
                .ensure(dist::DebuggerScripts { sysroot: builder.sysroot(compiler), host: target });
973 974
        }

975
        if suite.ends_with("fulldeps") {
976 977 978
            builder.ensure(compile::Rustc { compiler, target });
        }

979 980 981
        builder.ensure(compile::Std { compiler, target });
        // ensure that `libproc_macro` is available on the host.
        builder.ensure(compile::Std { compiler, target: compiler.host });
982

983 984
        // Also provide `rust_test_helpers` for the host.
        builder.ensure(native::TestHelpers { target: compiler.host });
985

986 987
        // As well as the target, except for plain wasm32, which can't build it
        if !target.contains("wasm32") || target.contains("emscripten") {
988 989
            builder.ensure(native::TestHelpers { target });
        }
990

991
        builder.ensure(RemoteCopyLibs { compiler, target });
992 993

        let mut cmd = builder.tool_cmd(Tool::Compiletest);
994 995 996 997

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

M
Mark Rousskov 已提交
998 999
        cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(compiler));
        cmd.arg("--run-lib-path").arg(builder.sysroot_libdir(compiler, target));
1000
        cmd.arg("--rustc-path").arg(builder.rustc(compiler));
1001

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

1004
        // Avoid depending on rustdoc when we don't need it.
S
Santiago Pastorino 已提交
1005 1006
        if mode == "rustdoc"
            || (mode == "run-make" && suite.ends_with("fulldeps"))
1007 1008
            || (mode == "ui" && is_rustdoc)
            || mode == "js-doc-test"
N
Nixon Enraght-Moony 已提交
1009
            || mode == "rustdoc-json"
S
Santiago Pastorino 已提交
1010
        {
M
Mark Rousskov 已提交
1011
            cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler));
1012 1013
        }

1014 1015 1016 1017 1018 1019 1020
        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 已提交
1021 1022 1023 1024
        if mode == "run-make" && suite.ends_with("fulldeps") {
            cmd.arg("--rust-demangler-path").arg(builder.tool_exe(Tool::RustDemangler));
        }

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

1034
        if builder.config.cmd.bless() {
1035 1036 1037
            cmd.arg("--bless");
        }

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

1043 1044 1045 1046 1047
        if let Some(ref pass) = builder.config.cmd.pass() {
            cmd.arg("--pass");
            cmd.arg(pass);
        }

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

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

1062
        if let Some(linker) = builder.linker(target) {
O
Oliver Schneider 已提交
1063 1064 1065
            cmd.arg("--linker").arg(linker);
        }

1066
        let mut hostflags = flags.clone();
M
Mark Rousskov 已提交
1067
        hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
1068
        if builder.is_fuse_ld_lld(compiler.host) {
1069 1070
            hostflags.push("-Clink-args=-fuse-ld=lld".to_string());
        }
1071 1072
        cmd.arg("--host-rustcflags").arg(hostflags.join(" "));

S
Shotaro Yamada 已提交
1073
        let mut targetflags = flags;
M
Mark Rousskov 已提交
1074
        targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
1075
        if builder.is_fuse_ld_lld(target) {
1076 1077
            targetflags.push("-Clink-args=-fuse-ld=lld".to_string());
        }
1078 1079
        cmd.arg("--target-rustcflags").arg(targetflags.join(" "));

1080
        cmd.arg("--docck-python").arg(builder.python());
1081

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

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

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

1118 1119 1120
        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);
1121 1122
        }

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

        // Get test-args by striping suite path
S
Santiago Pastorino 已提交
1130 1131
        let mut test_args: Vec<&str> = paths
            .iter()
M
Mark Rousskov 已提交
1132 1133 1134
            .map(|p| match p.strip_prefix(".") {
                Ok(path) => path,
                Err(_) => p,
1135
            })
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
            .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
            })
1149
            .filter_map(|p| {
V
varkor 已提交
1150 1151 1152 1153 1154 1155
                // 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.
1156
                match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
M
Matthias Krüger 已提交
1157
                    Some(s) if !s.is_empty() => Some(s),
1158 1159 1160
                    _ => None,
                }
            })
S
Santiago Pastorino 已提交
1161
            .collect();
1162 1163 1164 1165

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

        cmd.args(&test_args);
1166

1167
        if builder.is_verbose() {
1168 1169
            cmd.arg("--verbose");
        }
1170

O
Oliver Schneider 已提交
1171
        if !builder.config.verbose_tests {
1172 1173
            cmd.arg("--quiet");
        }
1174

1175 1176
        let mut llvm_components_passed = false;
        let mut copts_passed = false;
B
bjorn3 已提交
1177
        if builder.config.llvm_enabled() {
M
Mark Rousskov 已提交
1178
            let llvm_config = builder.ensure(native::Llvm { target: builder.config.build });
1179
            if !builder.config.dry_run {
1180
                let llvm_version = output(Command::new(&llvm_config).arg("--version"));
1181
                let llvm_components = output(Command::new(&llvm_config).arg("--components"));
1182
                // Remove trailing newline from llvm-config output.
1183 1184 1185 1186 1187
                cmd.arg("--llvm-version")
                    .arg(llvm_version.trim())
                    .arg("--llvm-components")
                    .arg(llvm_components.trim());
                llvm_components_passed = true;
1188
            }
1189
            if !builder.is_rust_llvm(target) {
B
bjorn3 已提交
1190 1191 1192
                cmd.arg("--system-llvm");
            }

1193 1194 1195 1196 1197 1198 1199 1200 1201
            // 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 已提交
1202 1203
            // 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.
1204
            if !builder.config.dry_run && matches!(suite, "run-make" | "run-make-fulldeps") {
1205 1206
                // 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 已提交
1207 1208
                let llvm_bin_path = llvm_config
                    .parent()
1209 1210 1211
                    .expect("Expected llvm-config to be contained in directory");
                assert!(llvm_bin_path.is_dir());
                cmd.arg("--llvm-bin-dir").arg(llvm_bin_path);
1212 1213 1214

                // If LLD is available, add it to the PATH
                if builder.config.lld_enabled {
M
Mark Rousskov 已提交
1215 1216
                    let lld_install_root =
                        builder.ensure(native::Lld { target: builder.config.build });
1217 1218 1219 1220

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

                    let old_path = env::var_os("PATH").unwrap_or_default();
M
Mark Rousskov 已提交
1221 1222 1223 1224
                    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");
1225 1226
                    cmd.env("PATH", new_path);
                }
B
bjorn3 已提交
1227 1228 1229
            }
        }

1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
        // 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);
            }
        }

1245 1246 1247 1248 1249
        if !llvm_components_passed {
            cmd.arg("--llvm-components").arg("");
        }
        if !copts_passed {
            cmd.arg("--cc").arg("").arg("--cxx").arg("").arg("--cflags").arg("");
1250
        }
1251

1252
        if builder.remote_tested(target) {
M
Mark Rousskov 已提交
1253
            cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
1254
        }
1255

1256 1257 1258 1259 1260 1261
        // 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") {
1262
            for &(ref k, ref v) in builder.cc[&target].env() {
1263 1264 1265
                if k != "PATH" {
                    cmd.env(k, v);
                }
1266 1267
            }
        }
1268
        cmd.env("RUSTC_BOOTSTRAP", "1");
1269
        builder.add_rust_test_threads(&mut cmd);
1270

1271
        if builder.config.sanitizers_enabled(target) {
1272
            cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
1273
        }
1274

1275
        if builder.config.profiler_enabled(target) {
1276
            cmd.env("RUSTC_PROFILER_SUPPORT", "1");
1277
        }
1278

M
Mark Rousskov 已提交
1279 1280 1281 1282
        let tmp = builder.out.join("tmp");
        std::fs::create_dir_all(&tmp).unwrap();
        cmd.env("RUST_TEST_TMPDIR", tmp);

1283 1284 1285 1286 1287
        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 已提交
1288
                .arg(builder.cc(target).parent().unwrap().parent().unwrap());
1289 1290 1291
        } else {
            cmd.arg("--android-cross-path").arg("");
        }
1292

1293 1294 1295 1296
        if builder.config.cmd.rustfix_coverage() {
            cmd.arg("--rustfix-coverage");
        }

1297 1298
        cmd.env("BOOTSTRAP_CARGO", &builder.initial_cargo);

1299
        builder.ci_env.force_coloring_in_ci(&mut cmd);
1300

S
Santiago Pastorino 已提交
1301 1302 1303 1304
        builder.info(&format!(
            "Check compiletest suite={} mode={} ({} -> {})",
            suite, mode, &compiler.host, target
        ));
1305 1306
        let _time = util::timeit(&builder);
        try_run(builder, &mut cmd);
1307 1308 1309

        if let Some(compare_mode) = compare_mode {
            cmd.arg("--compare-mode").arg(compare_mode);
S
Santiago Pastorino 已提交
1310 1311 1312 1313
            builder.info(&format!(
                "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
                suite, mode, compare_mode, &compiler.host, target
            ));
1314 1315 1316
            let _time = util::timeit(&builder);
            try_run(builder, &mut cmd);
        }
1317
    }
1318
}
1319

E
Eric Huss 已提交
1320 1321
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct BookTest {
1322
    compiler: Compiler,
E
Eric Huss 已提交
1323
    path: PathBuf,
1324 1325
    name: &'static str,
    is_ext_doc: bool,
1326 1327
}

E
Eric Huss 已提交
1328
impl Step for BookTest {
1329 1330
    type Output = ();
    const ONLY_HOSTS: bool = true;
1331

T
Taiki Endo 已提交
1332
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1333
        run.never()
1334
    }
M
Mark Simulacrum 已提交
1335

E
Eric Huss 已提交
1336
    /// Runs the documentation tests for a book in `src/doc`.
1337
    ///
E
Eric Huss 已提交
1338
    /// This uses the `rustdoc` that sits next to `compiler`.
T
Taiki Endo 已提交
1339
    fn run(self, builder: &Builder<'_>) {
E
Eric Huss 已提交
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 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
        // 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<'_>) {
1389
        let compiler = self.compiler;
1390

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

1393 1394
        // Do a breadth-first traversal of the `src/doc` directory and just run
        // tests for all files that end in `*.md`
1395 1396
        let mut stack = vec![builder.src.join(self.path)];
        let _time = util::timeit(&builder);
1397
        let mut files = Vec::new();
1398 1399 1400
        while let Some(p) = stack.pop() {
            if p.is_dir() {
                stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
S
Santiago Pastorino 已提交
1401
                continue;
1402 1403 1404 1405 1406 1407
            }

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

1408 1409 1410 1411 1412 1413
            files.push(p);
        }

        files.sort();

        for file in files {
E
Eric Huss 已提交
1414
            markdown_test(builder, compiler, &file);
1415
        }
1416 1417 1418
    }
}

1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431
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 已提交
1432
                fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1433 1434 1435
                    run.path($path)
                }

T
Taiki Endo 已提交
1436
                fn make_run(run: RunConfig<'_>) {
1437
                    run.builder.ensure($name {
1438
                        compiler: run.builder.compiler(run.builder.top_stage, run.target),
1439 1440 1441
                    });
                }

T
Taiki Endo 已提交
1442
                fn run(self, builder: &Builder<'_>) {
E
Eric Huss 已提交
1443
                    builder.ensure(BookTest {
1444
                        compiler: self.compiler,
E
Eric Huss 已提交
1445
                        path: PathBuf::from($path),
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458
                        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;
1459
    RustcBook, "src/doc/rustc", "rustc", default=true;
1460
    RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false;
1461
    EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false;
1462 1463
    TheBook, "src/doc/book", "book", default=false;
    UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
E
Eric Huss 已提交
1464
    EditionGuide, "src/doc/edition-guide", "edition-guide", default=false;
1465 1466
);

1467 1468 1469
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ErrorIndex {
    compiler: Compiler,
1470
}
1471

1472
impl Step for ErrorIndex {
1473
    type Output = ();
1474 1475 1476
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
1477
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1478
        run.path("src/tools/error_index_generator")
1479 1480
    }

T
Taiki Endo 已提交
1481
    fn make_run(run: RunConfig<'_>) {
E
Eric Huss 已提交
1482 1483 1484
        // 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.
1485
        let compiler = run.builder.compiler_for(run.builder.top_stage, run.target, run.target);
E
Eric Huss 已提交
1486
        run.builder.ensure(ErrorIndex { compiler });
1487
    }
1488

A
Alexander Regueiro 已提交
1489
    /// Runs the error index generator tool to execute the tests located in the error
1490 1491 1492 1493 1494
    /// 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 已提交
1495
    fn run(self, builder: &Builder<'_>) {
1496 1497
        let compiler = self.compiler;

1498
        let dir = testdir(builder, compiler.host);
1499 1500 1501
        t!(fs::create_dir_all(&dir));
        let output = dir.join("error-index.md");

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

E
Eric Huss 已提交
1505 1506 1507 1508 1509 1510
        // 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));
1511
        let _time = util::timeit(&builder);
1512
        builder.run_quiet(&mut tool);
E
Eric Huss 已提交
1513 1514
        builder.ensure(compile::Std { compiler: rustdoc_compiler, target: rustdoc_compiler.host });
        markdown_test(builder, rustdoc_compiler, &output);
1515
    }
1516 1517
}

T
Taiki Endo 已提交
1518
fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
1519 1520 1521
    if let Ok(contents) = fs::read_to_string(markdown) {
        if !contents.contains("```") {
            return true;
1522
        }
1523 1524
    }

1525
    builder.info(&format!("doc tests for: {}", markdown.display()));
M
Mark Rousskov 已提交
1526
    let mut cmd = builder.rustdoc_cmd(compiler);
1527
    builder.add_rust_test_threads(&mut cmd);
1528 1529
    cmd.arg("--test");
    cmd.arg(markdown);
1530
    cmd.env("RUSTC_BOOTSTRAP", "1");
1531

1532
    let test_args = builder.config.cmd.test_args().join(" ");
1533 1534
    cmd.arg("--test-args").arg(test_args);

O
Oliver Schneider 已提交
1535
    if builder.config.verbose_tests {
1536
        try_run(builder, &mut cmd)
O
Oliver Schneider 已提交
1537 1538
    } else {
        try_run_quiet(builder, &mut cmd)
1539
    }
1540
}
1541

1542 1543 1544 1545 1546 1547 1548 1549 1550
#[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<'_> {
1551
        run.path("src/doc/rustc-dev-guide")
1552 1553 1554 1555 1556 1557 1558
    }

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

    fn run(self, builder: &Builder<'_>) {
1559
        let src = builder.src.join("src/doc/rustc-dev-guide");
1560
        let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
E
Eric Huss 已提交
1561 1562 1563 1564 1565
        let toolstate = if try_run(builder, rustbook_cmd.arg("linkcheck").arg(&src)) {
            ToolState::TestPass
        } else {
            ToolState::TestFail
        };
1566
        builder.save_toolstate("rustc-dev-guide", toolstate);
1567 1568 1569
    }
}

1570
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
M
Mark Simulacrum 已提交
1571
pub struct CrateLibrustc {
1572
    compiler: Compiler,
1573
    target: TargetSelection,
1574
    test_kind: TestKind,
1575
    krate: Interned<String>,
1576 1577
}

M
Mark Simulacrum 已提交
1578
impl Step for CrateLibrustc {
1579 1580 1581 1582
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

T
Taiki Endo 已提交
1583
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1584
        run.krate("rustc-main")
1585 1586
    }

T
Taiki Endo 已提交
1587
    fn make_run(run: RunConfig<'_>) {
1588
        let builder = run.builder;
1589
        let compiler = builder.compiler(builder.top_stage, run.build_triple());
1590

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

1595 1596 1597 1598 1599 1600
                builder.ensure(CrateLibrustc {
                    compiler,
                    target: run.target,
                    test_kind,
                    krate: krate.name,
                });
1601 1602 1603 1604
            }
        }
    }

T
Taiki Endo 已提交
1605
    fn run(self, builder: &Builder<'_>) {
M
Mark Simulacrum 已提交
1606
        builder.ensure(Crate {
1607 1608
            compiler: self.compiler,
            target: self.target,
C
Collins Abitekaniza 已提交
1609
            mode: Mode::Rustc,
1610 1611 1612 1613 1614 1615
            test_kind: self.test_kind,
            krate: self.krate,
        });
    }
}

1616 1617 1618
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CrateNotDefault {
    compiler: Compiler,
1619
    target: TargetSelection,
1620 1621 1622 1623 1624 1625 1626
    test_kind: TestKind,
    krate: &'static str,
}

impl Step for CrateNotDefault {
    type Output = ();

T
Taiki Endo 已提交
1627
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1628
        run.path("src/librustc_asan")
1629 1630 1631 1632 1633
            .path("src/librustc_lsan")
            .path("src/librustc_msan")
            .path("src/librustc_tsan")
    }

T
Taiki Endo 已提交
1634
    fn make_run(run: RunConfig<'_>) {
1635
        let builder = run.builder;
1636
        let compiler = builder.compiler(builder.top_stage, run.build_triple());
1637

1638
        let test_kind = builder.kind.into();
1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653

        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 已提交
1654
    fn run(self, builder: &Builder<'_>) {
1655 1656 1657
        builder.ensure(Crate {
            compiler: self.compiler,
            target: self.target,
C
Collins Abitekaniza 已提交
1658
            mode: Mode::Std,
1659 1660 1661 1662 1663 1664
            test_kind: self.test_kind,
            krate: INTERNER.intern_str(self.krate),
        });
    }
}

K
kennytm 已提交
1665
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
M
Mark Simulacrum 已提交
1666
pub struct Crate {
K
kennytm 已提交
1667
    pub compiler: Compiler,
1668
    pub target: TargetSelection,
K
kennytm 已提交
1669 1670 1671
    pub mode: Mode,
    pub test_kind: TestKind,
    pub krate: Interned<String>,
1672
}
1673

M
Mark Simulacrum 已提交
1674
impl Step for Crate {
1675
    type Output = ();
1676 1677
    const DEFAULT: bool = true;

1678 1679
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.krate("test")
1680 1681
    }

T
Taiki Endo 已提交
1682
    fn make_run(run: RunConfig<'_>) {
1683
        let builder = run.builder;
1684
        let compiler = builder.compiler(builder.top_stage, run.build_triple());
1685

1686
        let make = |mode: Mode, krate: &CargoCrate| {
1687
            let test_kind = builder.kind.into();
1688

M
Mark Simulacrum 已提交
1689
            builder.ensure(Crate {
1690 1691
                compiler,
                target: run.target,
1692 1693
                mode,
                test_kind,
1694
                krate: krate.name,
1695 1696 1697
            });
        };

1698
        for krate in builder.in_tree_crates("test", Some(run.target)) {
E
Eric Huss 已提交
1699
            if krate.path.ends_with(&run.path) {
1700
                make(Mode::Std, krate);
1701 1702 1703
            }
        }
    }
1704

A
Alexander Regueiro 已提交
1705
    /// Runs all unit tests plus documentation tests for a given crate defined
1706
    /// by a `Cargo.toml` (single manifest)
1707 1708 1709 1710 1711 1712
    ///
    /// 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 已提交
1713
    fn run(self, builder: &Builder<'_>) {
1714 1715 1716 1717 1718 1719
        let compiler = self.compiler;
        let target = self.target;
        let mode = self.mode;
        let test_kind = self.test_kind;
        let krate = self.krate;

1720
        builder.ensure(compile::Std { compiler, target });
1721
        builder.ensure(RemoteCopyLibs { compiler, target });
A
Alex Crichton 已提交
1722

1723 1724 1725 1726 1727
        // 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 已提交
1728

1729 1730
        let mut cargo =
            builder.cargo(compiler, mode, SourceType::InTree, target, test_kind.subcommand());
1731
        match mode {
C
Collins Abitekaniza 已提交
1732
            Mode::Std => {
1733
                compile::std_cargo(builder, target, compiler.stage, &mut cargo);
1734
            }
C
Collins Abitekaniza 已提交
1735
            Mode::Rustc => {
1736
                builder.ensure(compile::Rustc { compiler, target });
1737
                compile::rustc_cargo(builder, &mut cargo, target);
1738 1739 1740 1741 1742 1743 1744 1745 1746
            }
            _ => 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.
1747
        if test_kind.subcommand() == "test" && !builder.fail_fast {
1748 1749
            cargo.arg("--no-fail-fast");
        }
K
kennytm 已提交
1750
        match builder.doc_tests {
K
kennytm 已提交
1751
            DocTests::Only => {
K
kennytm 已提交
1752 1753
                cargo.arg("--doc");
            }
K
kennytm 已提交
1754
            DocTests::No => {
K
kennytm 已提交
1755 1756
                cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
            }
K
kennytm 已提交
1757
            DocTests::Yes => {}
1758
        }
1759

1760
        cargo.arg("-p").arg(krate);
1761

1762 1763 1764 1765 1766 1767
        // 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();
1768
        dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
1769 1770 1771
        cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());

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

O
Oliver Schneider 已提交
1774
        if !builder.config.verbose_tests {
1775 1776
            cargo.arg("--quiet");
        }
1777

1778
        if target.contains("emscripten") {
S
Santiago Pastorino 已提交
1779
            cargo.env(
1780
                format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
M
Mark Rousskov 已提交
1781
                builder.config.nodejs.as_ref().expect("nodejs not configured"),
S
Santiago Pastorino 已提交
1782
            );
O
Oliver Schneider 已提交
1783
        } else if target.starts_with("wasm32") {
M
Mark Rousskov 已提交
1784 1785 1786
            let node = builder.config.nodejs.as_ref().expect("nodejs not configured");
            let runner =
                format!("{} {}/src/etc/wasm32-shim.js", node.display(), builder.src.display());
1787
            cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), &runner);
1788
        } else if builder.remote_tested(target) {
S
Santiago Pastorino 已提交
1789
            cargo.env(
1790
                format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
1791
                format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
S
Santiago Pastorino 已提交
1792
            );
1793
        }
1794

S
Santiago Pastorino 已提交
1795 1796 1797 1798
        builder.info(&format!(
            "{} {} stage{} ({} -> {})",
            test_kind, krate, compiler.stage, &compiler.host, target
        ));
1799
        let _time = util::timeit(&builder);
1800
        try_run(builder, &mut cargo.into());
1801 1802
    }
}
1803

M
Mark Simulacrum 已提交
1804
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1805
pub struct CrateRustdoc {
1806
    host: TargetSelection,
M
Mark Simulacrum 已提交
1807 1808 1809
    test_kind: TestKind,
}

1810
impl Step for CrateRustdoc {
M
Mark Simulacrum 已提交
1811 1812 1813 1814
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

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

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

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

1824
        builder.ensure(CrateRustdoc { host: run.target, test_kind });
M
Mark Simulacrum 已提交
1825 1826
    }

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

E
Eric Huss 已提交
1831 1832 1833 1834 1835
        // 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);
1836
        builder.ensure(compile::Rustc { compiler, target });
M
Mark Simulacrum 已提交
1837

M
Mark Rousskov 已提交
1838 1839 1840 1841 1842 1843 1844 1845 1846 1847
        let mut cargo = tool::prepare_tool_cargo(
            builder,
            compiler,
            Mode::ToolRustc,
            target,
            test_kind.subcommand(),
            "src/tools/rustdoc",
            SourceType::InTree,
            &[],
        );
1848
        if test_kind.subcommand() == "test" && !builder.fail_fast {
M
Mark Simulacrum 已提交
1849 1850 1851 1852 1853 1854
            cargo.arg("--no-fail-fast");
        }

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

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

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

E
Eric Huss 已提交
1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886
        // 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 已提交
1887
        if !builder.config.verbose_tests {
M
Mark Simulacrum 已提交
1888 1889 1890
            cargo.arg("--quiet");
        }

S
Santiago Pastorino 已提交
1891 1892 1893 1894
        builder.info(&format!(
            "{} rustdoc stage{} ({} -> {})",
            test_kind, compiler.stage, &compiler.host, target
        ));
1895
        let _time = util::timeit(&builder);
M
Mark Simulacrum 已提交
1896

1897
        try_run(builder, &mut cargo.into());
M
Mark Simulacrum 已提交
1898 1899 1900
    }
}

1901 1902 1903 1904 1905
/// 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 已提交
1906
/// Most of the time this is a no-op. For some steps such as shipping data to
1907 1908 1909
/// 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.
1910 1911 1912
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RemoteCopyLibs {
    compiler: Compiler,
1913
    target: TargetSelection,
1914
}
1915

1916
impl Step for RemoteCopyLibs {
1917
    type Output = ();
1918

T
Taiki Endo 已提交
1919
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1920
        run.never()
1921 1922
    }

T
Taiki Endo 已提交
1923
    fn run(self, builder: &Builder<'_>) {
1924 1925
        let compiler = self.compiler;
        let target = self.target;
1926
        if !builder.remote_tested(target) {
S
Santiago Pastorino 已提交
1927
            return;
1928 1929
        }

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

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

M
Mark Rousskov 已提交
1935 1936
        let server =
            builder.ensure(tool::RemoteTestServer { compiler: compiler.with_stage(0), target });
1937 1938

        // Spawn the emulator and wait for it to come online
1939
        let tool = builder.tool_exe(Tool::RemoteTestClient);
1940
        let mut cmd = Command::new(&tool);
1941
        cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.out.join("tmp"));
1942
        if let Some(rootfs) = builder.qemu_rootfs(target) {
1943 1944
            cmd.arg(rootfs);
        }
1945
        builder.run(&mut cmd);
1946 1947

        // Push all our dylibs to the emulator
1948
        for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) {
1949 1950 1951
            let f = t!(f);
            let name = f.file_name().into_string().unwrap();
            if util::is_dylib(&name) {
S
Santiago Pastorino 已提交
1952
                builder.run(Command::new(&tool).arg("push").arg(f.path()));
1953
            }
1954 1955 1956 1957
        }
    }
}

1958
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1959
pub struct Distcheck;
A
Alex Crichton 已提交
1960

1961
impl Step for Distcheck {
1962 1963
    type Output = ();

T
Taiki Endo 已提交
1964
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1965
        run.path("distcheck")
1966 1967
    }

T
Taiki Endo 已提交
1968
    fn make_run(run: RunConfig<'_>) {
M
Mark Simulacrum 已提交
1969 1970 1971
        run.builder.ensure(Distcheck);
    }

A
Alexander Regueiro 已提交
1972
    /// Runs "distcheck", a 'make check' from a tarball
T
Taiki Endo 已提交
1973
    fn run(self, builder: &Builder<'_>) {
1974
        builder.info("Distcheck");
1975
        let dir = builder.out.join("tmp").join("distcheck");
1976 1977 1978
        let _ = fs::remove_dir_all(&dir);
        t!(fs::create_dir_all(&dir));

M
Mark Simulacrum 已提交
1979 1980 1981 1982
        // Guarantee that these are built before we begin running.
        builder.ensure(dist::PlainSourceTarball);
        builder.ensure(dist::Src);

1983
        let mut cmd = Command::new("tar");
1984
        cmd.arg("-xf")
1985
            .arg(builder.ensure(dist::PlainSourceTarball).tarball())
S
Santiago Pastorino 已提交
1986 1987
            .arg("--strip-components=1")
            .current_dir(&dir);
1988
        builder.run(&mut cmd);
S
Santiago Pastorino 已提交
1989 1990 1991 1992 1993 1994 1995
        builder.run(
            Command::new("./configure")
                .args(&builder.config.configure_args)
                .arg("--enable-vendor")
                .current_dir(&dir),
        );
        builder.run(
1996 1997 1998
            Command::new(build_helper::make(&builder.config.build.triple))
                .arg("check")
                .current_dir(&dir),
S
Santiago Pastorino 已提交
1999
        );
2000 2001

        // Now make sure that rust-src has all of libstd's dependencies
2002
        builder.info("Distcheck rust-src");
2003
        let dir = builder.out.join("tmp").join("distcheck-src");
2004 2005 2006 2007
        let _ = fs::remove_dir_all(&dir);
        t!(fs::create_dir_all(&dir));

        let mut cmd = Command::new("tar");
2008 2009 2010 2011
        cmd.arg("-xf")
            .arg(builder.ensure(dist::Src).tarball())
            .arg("--strip-components=1")
            .current_dir(&dir);
2012
        builder.run(&mut cmd);
2013

M
mark 已提交
2014
        let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
S
Santiago Pastorino 已提交
2015 2016 2017 2018 2019 2020 2021
        builder.run(
            Command::new(&builder.initial_cargo)
                .arg("generate-lockfile")
                .arg("--manifest-path")
                .arg(&toml)
                .current_dir(&dir),
        );
2022
    }
A
Alex Crichton 已提交
2023
}
2024

2025
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2026 2027
pub struct Bootstrap;

2028
impl Step for Bootstrap {
2029
    type Output = ();
2030 2031
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;
2032

A
Alexander Regueiro 已提交
2033
    /// Tests the build system itself.
T
Taiki Endo 已提交
2034
    fn run(self, builder: &Builder<'_>) {
2035
        let mut cmd = Command::new(&builder.initial_cargo);
2036
        cmd.arg("test")
S
Santiago Pastorino 已提交
2037 2038 2039
            .current_dir(builder.src.join("src/bootstrap"))
            .env("RUSTFLAGS", "-Cdebuginfo=2")
            .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
2040 2041
            .env("BOOTSTRAP_OUTPUT_DIRECTORY", &builder.config.out)
            .env("BOOTSTRAP_INITIAL_CARGO", &builder.config.initial_cargo)
S
Santiago Pastorino 已提交
2042 2043
            .env("RUSTC_BOOTSTRAP", "1")
            .env("RUSTC", &builder.initial_rustc);
2044 2045 2046 2047 2048 2049
        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);
        }
2050
        if !builder.fail_fast {
2051 2052
            cmd.arg("--no-fail-fast");
        }
2053
        cmd.arg("--").args(&builder.config.cmd.test_args());
2054 2055 2056
        // 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");
2057
        try_run(builder, &mut cmd);
2058
    }
2059

T
Taiki Endo 已提交
2060
    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2061
        run.path("src/bootstrap")
2062 2063
    }

T
Taiki Endo 已提交
2064
    fn make_run(run: RunConfig<'_>) {
2065
        run.builder.ensure(Bootstrap);
2066
    }
2067
}
2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083

#[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<'_>) {
2084 2085 2086
        let compiler =
            run.builder.compiler_for(run.builder.top_stage, run.builder.build.build, run.target);
        run.builder.ensure(TierCheck { compiler });
2087 2088 2089 2090
    }

    /// Tests the Platform Support page in the rustc book.
    fn run(self, builder: &Builder<'_>) {
2091
        builder.ensure(compile::Std { compiler: self.compiler, target: self.compiler.host });
2092 2093 2094
        let mut cargo = tool::prepare_tool_cargo(
            builder,
            self.compiler,
2095 2096
            Mode::ToolStd,
            self.compiler.host,
2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111
            "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());
    }
}
2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144

#[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,
        });
    }
}