use std::env;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fs;
use std::iter;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use clap_complete::shells;
use crate::builder::crate_description;
use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::cache::INTERNER;
use crate::compile;
use crate::config::TargetSelection;
use crate::dist;
use crate::doc::DocumentationFormat;
use crate::flags::Subcommand;
use crate::llvm;
use crate::render_tests::add_flags_and_try_run_tests;
use crate::synthetic_targets::MirOptPanicAbortSyntheticTarget;
use crate::tool::{self, SourceType, Tool};
use crate::toolstate::ToolState;
use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t, up_to_date};
use crate::{envify, CLang, DocTests, GitRepo, Mode};
const ADB_TEST_DIR: &str = "/data/local/tmp/work";
const MIR_OPT_BLESS_TARGET_MAPPING: &[(&str, &str)] = &[
("i686-unknown-linux-gnu", "x86_64-unknown-linux-gnu"),
("i686-unknown-linux-musl", "x86_64-unknown-linux-musl"),
("i686-pc-windows-msvc", "x86_64-pc-windows-msvc"),
("i686-pc-windows-gnu", "x86_64-pc-windows-gnu"),
("i686-apple-darwin", "x86_64-apple-darwin"),
];
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CrateBootstrap {
path: Interned<PathBuf>,
host: TargetSelection,
}
impl Step for CrateBootstrap {
type Output = ();
const ONLY_HOSTS: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/jsondoclint")
.path("src/tools/suggest-tests")
.path("src/tools/replace-version-placeholder")
.alias("tidyselftest")
}
fn make_run(run: RunConfig<'_>) {
for path in run.paths {
let path = INTERNER.intern_path(path.assert_single_path().path.clone());
run.builder.ensure(CrateBootstrap { host: run.target, path });
}
}
fn run(self, builder: &Builder<'_>) {
let bootstrap_host = builder.config.build;
let compiler = builder.compiler(0, bootstrap_host);
let mut path = self.path.to_str().unwrap();
if path == "tidyselftest" {
path = "src/tools/tidy";
}
let cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolBootstrap,
bootstrap_host,
"test",
path,
SourceType::InTree,
&[],
);
let crate_name = path.rsplit_once('/').unwrap().1;
run_cargo_test(cargo, &[], &[], crate_name, crate_name, compiler, bootstrap_host, builder);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Linkcheck {
host: TargetSelection,
}
impl Step for Linkcheck {
type Output = ();
const ONLY_HOSTS: bool = true;
const DEFAULT: bool = true;
fn run(self, builder: &Builder<'_>) {
let host = self.host;
let hosts = &builder.hosts;
let targets = &builder.targets;
if (hosts != targets) && !hosts.is_empty() && !targets.is_empty() {
panic!(
"Linkcheck currently does not support builds with different hosts and targets.
You can skip linkcheck with --skip src/tools/linkchecker"
);
}
builder.info(&format!("Linkcheck ({host})"));
let bootstrap_host = builder.config.build;
let compiler = builder.compiler(0, bootstrap_host);
let cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolBootstrap,
bootstrap_host,
"test",
"src/tools/linkchecker",
SourceType::InTree,
&[],
);
run_cargo_test(
cargo,
&[],
&[],
"linkchecker",
"linkchecker self tests",
compiler,
bootstrap_host,
builder,
);
if builder.doc_tests == DocTests::No {
return;
}
builder.default_doc(&[]);
let mut linkchecker = builder.tool_cmd(Tool::Linkchecker);
let _guard =
builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host);
let _time = util::timeit(&builder);
builder.run_delaying_failure(linkchecker.arg(builder.out.join(host.triple).join("doc")));
}
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
let run = run.path("src/tools/linkchecker");
run.default_condition(builder.config.docs)
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Linkcheck { host: run.target });
}
}
fn check_if_tidy_is_installed() -> bool {
Command::new("tidy")
.arg("--version")
.stdout(Stdio::null())
.status()
.map_or(false, |status| status.success())
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct HtmlCheck {
target: TargetSelection,
}
impl Step for HtmlCheck {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let run = run.path("src/tools/html-checker");
run.lazy_default_condition(Box::new(check_if_tidy_is_installed))
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(HtmlCheck { target: run.target });
}
fn run(self, builder: &Builder<'_>) {
if !check_if_tidy_is_installed() {
eprintln!("not running HTML-check tool because `tidy` is missing");
eprintln!(
"Note that `tidy` is not the in-tree `src/tools/tidy` but needs to be installed"
);
panic!("Cannot run html-check tests");
}
builder.default_doc(&[]);
builder.ensure(crate::doc::Rustc::new(builder.top_stage, self.target, builder));
builder.run_delaying_failure(
builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)),
);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Cargotest {
stage: u32,
host: TargetSelection,
}
impl Step for Cargotest {
type Output = ();
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/cargotest")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Cargotest { stage: run.builder.top_stage, host: run.target });
}
fn run(self, builder: &Builder<'_>) {
let compiler = builder.compiler(self.stage, self.host);
builder.ensure(compile::Rustc::new(compiler, compiler.host));
let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host });
let out_dir = builder.out.join("ct");
t!(fs::create_dir_all(&out_dir));
let _time = util::timeit(&builder);
let mut cmd = builder.tool_cmd(Tool::CargoTest);
builder.run_delaying_failure(
cmd.arg(&cargo)
.arg(&out_dir)
.args(builder.config.test_args())
.env("RUSTC", builder.rustc(compiler))
.env("RUSTDOC", builder.rustdoc(compiler)),
);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Cargo {
stage: u32,
host: TargetSelection,
}
impl Step for Cargo {
type Output = ();
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/cargo")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Cargo { stage: run.builder.top_stage, host: run.target });
}
fn run(self, builder: &Builder<'_>) {
let compiler = builder.compiler(self.stage, self.host);
builder.ensure(tool::Cargo { compiler, target: self.host });
let cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolRustc,
self.host,
"test",
"src/tools/cargo",
SourceType::Submodule,
&[],
);
let mut cargo = prepare_cargo_test(cargo, &[], &[], "cargo", compiler, self.host, builder);
cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");
cargo.env("PATH", &path_for_cargo(builder, compiler));
#[cfg(feature = "build-metrics")]
builder.metrics.begin_test_suite(
build_helper::metrics::TestSuiteMetadata::CargoPackage {
crates: vec!["cargo".into()],
target: self.host.triple.to_string(),
host: self.host.triple.to_string(),
stage: self.stage,
},
builder,
);
let _time = util::timeit(&builder);
add_flags_and_try_run_tests(builder, &mut cargo);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RustAnalyzer {
stage: u32,
host: TargetSelection,
}
impl Step for RustAnalyzer {
type Output = ();
const ONLY_HOSTS: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/rust-analyzer")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Self { stage: run.builder.top_stage, host: run.target });
}
fn run(self, builder: &Builder<'_>) {
let stage = self.stage;
let host = self.host;
let compiler = builder.compiler(stage, host);
builder.ensure(compile::Std::new(compiler, host));
let workspace_path = "src/tools/rust-analyzer";
let crate_path = "src/tools/rust-analyzer/crates/proc-macro-srv";
let mut cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolStd,
host,
"test",
crate_path,
SourceType::InTree,
&["sysroot-abi".to_owned()],
);
cargo.allow_features(tool::RustAnalyzer::ALLOW_FEATURES);
let dir = builder.src.join(workspace_path);
cargo.env("CARGO_WORKSPACE_DIR", &dir);
cargo.env("SKIP_SLOW_TESTS", "1");
cargo.add_rustc_lib_path(builder, compiler);
run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", compiler, host, builder);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustfmt {
stage: u32,
host: TargetSelection,
}
impl Step for Rustfmt {
type Output = ();
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/rustfmt")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Rustfmt { stage: run.builder.top_stage, host: run.target });
}
fn run(self, builder: &Builder<'_>) {
let stage = self.stage;
let host = self.host;
let compiler = builder.compiler(stage, host);
builder
.ensure(tool::Rustfmt { compiler, target: self.host, extra_features: Vec::new() })
.expect("in-tree tool");
let mut cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolRustc,
host,
"test",
"src/tools/rustfmt",
SourceType::InTree,
&[],
);
let dir = testdir(builder, compiler.host);
t!(fs::create_dir_all(&dir));
cargo.env("RUSTFMT_TEST_DIR", dir);
cargo.add_rustc_lib_path(builder, compiler);
run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", compiler, host, builder);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RustDemangler {
stage: u32,
host: TargetSelection,
}
impl Step for RustDemangler {
type Output = ();
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/rust-demangler")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(RustDemangler { stage: run.builder.top_stage, host: run.target });
}
fn run(self, builder: &Builder<'_>) {
let stage = self.stage;
let host = self.host;
let compiler = builder.compiler(stage, host);
let rust_demangler = builder
.ensure(tool::RustDemangler { compiler, target: self.host, extra_features: Vec::new() })
.expect("in-tree tool");
let mut cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolRustc,
host,
"test",
"src/tools/rust-demangler",
SourceType::InTree,
&[],
);
let dir = testdir(builder, compiler.host);
t!(fs::create_dir_all(&dir));
cargo.env("RUST_DEMANGLER_DRIVER_PATH", rust_demangler);
cargo.add_rustc_lib_path(builder, compiler);
run_cargo_test(
cargo,
&[],
&[],
"rust-demangler",
"rust-demangler",
compiler,
host,
builder,
);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Miri {
stage: u32,
host: TargetSelection,
target: TargetSelection,
}
impl Miri {
pub fn build_miri_sysroot(
builder: &Builder<'_>,
compiler: Compiler,
miri: &Path,
target: TargetSelection,
) -> String {
let miri_sysroot = builder.out.join(compiler.host.triple).join("miri-sysroot");
let mut cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolRustc,
compiler.host,
"run",
"src/tools/miri/cargo-miri",
SourceType::InTree,
&[],
);
cargo.add_rustc_lib_path(builder, compiler);
cargo.arg("--").arg("miri").arg("setup");
cargo.arg("--target").arg(target.rustc_target_arg());
cargo.env("MIRI_LIB_SRC", builder.src.join("library"));
cargo.env("MIRI", &miri);
cargo.env("MIRI_SYSROOT", &miri_sysroot);
cargo.env("RUST_BACKTRACE", "1");
let mut cargo = Command::from(cargo);
let _guard = builder.msg(
Kind::Build,
compiler.stage + 1,
"miri sysroot",
compiler.host,
compiler.host,
);
builder.run(&mut cargo);
cargo.arg("--print-sysroot");
if builder.config.dry_run() {
String::new()
} else {
builder.verbose(&format!("running: {cargo:?}"));
let out =
cargo.output().expect("We already ran `cargo miri setup` before and that worked");
assert!(out.status.success(), "`cargo miri setup` returned with non-0 exit code");
let stdout = String::from_utf8(out.stdout)
.expect("`cargo miri setup` stdout is not valid UTF-8");
let sysroot = stdout.trim_end();
builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
sysroot.to_owned()
}
}
}
impl Step for Miri {
type Output = ();
const ONLY_HOSTS: bool = false;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/miri")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Miri {
stage: run.builder.top_stage,
host: run.build_triple(),
target: run.target,
});
}
fn run(self, builder: &Builder<'_>) {
let stage = self.stage;
let host = self.host;
let target = self.target;
let compiler = builder.compiler(stage, host);
let compiler_std = builder.compiler(if stage < 2 { stage + 1 } else { stage }, host);
let miri = builder
.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() })
.expect("in-tree tool");
let _cargo_miri = builder
.ensure(tool::CargoMiri { compiler, target: self.host, extra_features: Vec::new() })
.expect("in-tree tool");
builder.ensure(compile::Std::new(compiler_std, host));
let sysroot = builder.sysroot(compiler_std);
let miri_sysroot = Miri::build_miri_sysroot(builder, compiler, &miri, target);
let mut cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolRustc,
host,
"test",
"src/tools/miri",
SourceType::InTree,
&[],
);
let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "miri", host, host);
cargo.add_rustc_lib_path(builder, compiler);
cargo.env("MIRI_SYSROOT", &miri_sysroot);
cargo.env("MIRI_HOST_SYSROOT", sysroot);
cargo.env("MIRI", &miri);
if builder.config.locked_deps {
cargo.env("CARGO_EXTRA_FLAGS", "--locked");
}
cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());
let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder);
{
let _time = util::timeit(&builder);
builder.run(&mut cargo);
}
if builder.config.test_args().is_empty() {
cargo.env("MIRIFLAGS", "-O -Zmir-opt-level=4 -Cdebug-assertions=yes");
cargo.env("MIRI_SKIP_UI_CHECKS", "1");
cargo.env_remove("RUSTC_BLESS");
cargo.args(&["tests/pass", "tests/panic"]);
let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder);
{
let _time = util::timeit(&builder);
builder.run(&mut cargo);
}
}
let mut cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolRustc,
host,
"run",
"src/tools/miri/cargo-miri",
SourceType::Submodule,
&[],
);
cargo.add_rustc_lib_path(builder, compiler);
cargo.arg("--").arg("miri").arg("test");
if builder.config.locked_deps {
cargo.arg("--locked");
}
cargo
.arg("--manifest-path")
.arg(builder.src.join("src/tools/miri/test-cargo-miri/Cargo.toml"));
cargo.arg("--target").arg(target.rustc_target_arg());
cargo.arg("--tests"); cargo.arg("--").args(builder.config.test_args());
cargo.env("MIRI_SYSROOT", &miri_sysroot);
cargo.env("MIRI_HOST_SYSROOT", sysroot);
cargo.env("MIRI", &miri);
cargo.env("RUST_BACKTRACE", "1");
let mut cargo = Command::from(cargo);
{
let _time = util::timeit(&builder);
builder.run(&mut cargo);
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CompiletestTest {
host: TargetSelection,
}
impl Step for CompiletestTest {
type Output = ();
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/compiletest")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(CompiletestTest { host: run.target });
}
fn run(self, builder: &Builder<'_>) {
let host = self.host;
let compiler = builder.compiler(builder.top_stage, host);
builder.ensure(compile::Std::new(compiler, host));
let mut cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolStd,
host,
"test",
"src/tools/compiletest",
SourceType::InTree,
&[],
);
cargo.allow_features("test");
run_cargo_test(
cargo,
&[],
&[],
"compiletest",
"compiletest self test",
compiler,
host,
builder,
);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Clippy {
stage: u32,
host: TargetSelection,
}
impl Step for Clippy {
type Output = ();
const ONLY_HOSTS: bool = true;
const DEFAULT: bool = false;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/clippy")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Clippy { stage: run.builder.top_stage, host: run.target });
}
fn run(self, builder: &Builder<'_>) {
let stage = self.stage;
let host = self.host;
let compiler = builder.compiler(stage, host);
builder
.ensure(tool::Clippy { compiler, target: self.host, extra_features: Vec::new() })
.expect("in-tree tool");
let mut cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolRustc,
host,
"test",
"src/tools/clippy",
SourceType::InTree,
&[],
);
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());
cargo.env("HOST_LIBS", host_libs);
cargo.add_rustc_lib_path(builder, compiler);
let mut cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder);
let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host);
#[allow(deprecated)] if builder.config.try_run(&mut cargo).is_ok() {
return;
}
if !builder.config.cmd.bless() {
crate::exit!(1);
}
}
}
fn path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString {
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("")
}
#[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;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/rustdoc-themes")
}
fn make_run(run: RunConfig<'_>) {
let compiler = run.builder.compiler(run.builder.top_stage, run.target);
run.builder.ensure(RustdocTheme { compiler });
}
fn run(self, builder: &Builder<'_>) {
let rustdoc = builder.bootstrap_out.join("rustdoc");
let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
cmd.arg(rustdoc.to_str().unwrap())
.arg(builder.src.join("src/librustdoc/html/static/css/rustdoc.css").to_str().unwrap())
.env("RUSTC_STAGE", self.compiler.stage.to_string())
.env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
.env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host))
.env("CFG_RELEASE_CHANNEL", &builder.config.channel)
.env("RUSTDOC_REAL", builder.rustdoc(self.compiler))
.env("RUSTC_BOOTSTRAP", "1");
if let Some(linker) = builder.linker(self.compiler.host) {
cmd.env("RUSTDOC_LINKER", linker);
}
if builder.is_fuse_ld_lld(self.compiler.host) {
cmd.env(
"RUSTDOC_LLD_NO_THREADS",
util::lld_flag_no_threads(self.compiler.host.contains("windows")),
);
}
builder.run_delaying_failure(&mut cmd);
}
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustdocJSStd {
pub target: TargetSelection,
}
impl Step for RustdocJSStd {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = run.builder.config.nodejs.is_some();
run.suite_path("tests/rustdoc-js-std").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(RustdocJSStd { target: run.target });
}
fn run(self, builder: &Builder<'_>) {
let nodejs =
builder.config.nodejs.as_ref().expect("need nodejs to run rustdoc-js-std tests");
let mut command = Command::new(nodejs);
command
.arg(builder.src.join("src/tools/rustdoc-js/tester.js"))
.arg("--crate-name")
.arg("std")
.arg("--resource-suffix")
.arg(&builder.version)
.arg("--doc-folder")
.arg(builder.doc_out(self.target))
.arg("--test-folder")
.arg(builder.src.join("tests/rustdoc-js-std"));
for path in &builder.paths {
if let Some(p) = util::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder) {
if !p.ends_with(".js") {
eprintln!("A non-js file was given: `{}`", path.display());
panic!("Cannot run rustdoc-js-std tests");
}
command.arg("--test-file").arg(path);
}
}
builder.ensure(crate::doc::Std::new(
builder.top_stage,
self.target,
builder,
DocumentationFormat::HTML,
));
let _guard = builder.msg(
Kind::Test,
builder.top_stage,
"rustdoc-js-std",
builder.config.build,
self.target,
);
builder.run(&mut command);
}
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustdocJSNotStd {
pub target: TargetSelection,
pub compiler: Compiler,
}
impl Step for RustdocJSNotStd {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = run.builder.config.nodejs.is_some();
run.suite_path("tests/rustdoc-js").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
run.builder.ensure(RustdocJSNotStd { target: run.target, compiler });
}
fn run(self, builder: &Builder<'_>) {
builder.ensure(Compiletest {
compiler: self.compiler,
target: self.target,
mode: "js-doc-test",
suite: "rustdoc-js",
path: "tests/rustdoc-js",
compare_mode: None,
});
}
}
fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String> {
let mut command = Command::new(&npm);
command.arg("list").arg("--parseable").arg("--long").arg("--depth=0");
if global {
command.arg("--global");
}
let lines = command
.output()
.map(|output| String::from_utf8_lossy(&output.stdout).into_owned())
.unwrap_or(String::new());
lines
.lines()
.find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))
.map(|v| v.to_owned())
}
fn get_browser_ui_test_version(npm: &Path) -> Option<String> {
get_browser_ui_test_version_inner(npm, false)
.or_else(|| get_browser_ui_test_version_inner(npm, true))
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustdocGUI {
pub target: TargetSelection,
pub compiler: Compiler,
}
impl Step for RustdocGUI {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
let run = run.suite_path("tests/rustdoc-gui");
run.lazy_default_condition(Box::new(move || {
builder.config.nodejs.is_some()
&& builder
.config
.npm
.as_ref()
.map(|p| get_browser_ui_test_version(p).is_some())
.unwrap_or(false)
}))
}
fn make_run(run: RunConfig<'_>) {
let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
run.builder.ensure(RustdocGUI { target: run.target, compiler });
}
fn run(self, builder: &Builder<'_>) {
builder.ensure(compile::Std::new(self.compiler, self.target));
let mut cmd = builder.tool_cmd(Tool::RustdocGUITest);
let out_dir = builder.test_out(self.target).join("rustdoc-gui");
builder.clear_if_dirty(&out_dir, &builder.rustdoc(self.compiler));
if let Some(src) = builder.config.src.to_str() {
cmd.arg("--rust-src").arg(src);
}
if let Some(out_dir) = out_dir.to_str() {
cmd.arg("--out-dir").arg(out_dir);
}
if let Some(initial_cargo) = builder.config.initial_cargo.to_str() {
cmd.arg("--initial-cargo").arg(initial_cargo);
}
cmd.arg("--jobs").arg(builder.jobs().to_string());
cmd.env("RUSTDOC", builder.rustdoc(self.compiler))
.env("RUSTC", builder.rustc(self.compiler));
for path in &builder.paths {
if let Some(p) = util::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) {
if !p.ends_with(".goml") {
eprintln!("A non-goml file was given: `{}`", path.display());
panic!("Cannot run rustdoc-gui tests");
}
if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
cmd.arg("--goml-file").arg(name);
}
}
}
for test_arg in builder.config.test_args() {
cmd.arg("--test-arg").arg(test_arg);
}
if let Some(ref nodejs) = builder.config.nodejs {
cmd.arg("--nodejs").arg(nodejs);
}
if let Some(ref npm) = builder.config.npm {
cmd.arg("--npm").arg(npm);
}
let _time = util::timeit(&builder);
let _guard = builder.msg_sysroot_tool(
Kind::Test,
self.compiler.stage,
"rustdoc-gui",
self.compiler.host,
self.target,
);
crate::render_tests::try_run_tests(builder, &mut cmd, true);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Tidy;
impl Step for Tidy {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn run(self, builder: &Builder<'_>) {
let mut cmd = builder.tool_cmd(Tool::Tidy);
cmd.arg(&builder.src);
cmd.arg(&builder.initial_cargo);
cmd.arg(&builder.out);
let jobs = builder.config.jobs.unwrap_or_else(|| {
8 * std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32
});
cmd.arg(jobs.to_string());
if builder.is_verbose() {
cmd.arg("--verbose");
}
if builder.config.cmd.bless() {
cmd.arg("--bless");
}
if let Some(s) = builder.config.cmd.extra_checks() {
cmd.arg(format!("--extra-checks={s}"));
}
let mut args = std::env::args_os();
if let Some(_) = args.find(|arg| arg == OsStr::new("--")) {
cmd.arg("--");
cmd.args(args);
}
if builder.config.channel == "dev" || builder.config.channel == "nightly" {
builder.info("fmt check");
if builder.initial_rustfmt().is_none() {
let inferred_rustfmt_dir = builder.initial_rustc.parent().unwrap();
eprintln!(
"\
error: no `rustfmt` binary found in {PATH}
info: `rust.channel` is currently set to \"{CHAN}\"
help: if you are testing a beta branch, set `rust.channel` to \"beta\" in the `config.toml` file
help: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to `x.py test`",
PATH = inferred_rustfmt_dir.display(),
CHAN = builder.config.channel,
);
crate::exit!(1);
}
crate::format::format(&builder, !builder.config.cmd.bless(), &[]);
}
builder.info("tidy check");
builder.run_delaying_failure(&mut cmd);
builder.ensure(ExpandYamlAnchors);
builder.info("x.py completions check");
let [bash, fish, powershell] = ["x.py.sh", "x.py.fish", "x.py.ps1"]
.map(|filename| builder.src.join("src/etc/completions").join(filename));
if builder.config.cmd.bless() {
builder.ensure(crate::run::GenerateCompletions);
} else if crate::flags::get_completion(shells::Bash, &bash).is_some()
|| crate::flags::get_completion(shells::Fish, &fish).is_some()
|| crate::flags::get_completion(shells::PowerShell, &powershell).is_some()
{
eprintln!(
"x.py completions were changed; run `x.py run generate-completions` to update them"
);
crate::exit!(1);
}
}
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/tidy")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Tidy);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ExpandYamlAnchors;
impl Step for ExpandYamlAnchors {
type Output = ();
const ONLY_HOSTS: bool = true;
fn run(self, builder: &Builder<'_>) {
if !builder.src.join(".github/workflows/ci.yml").exists() {
builder.info("Skipping YAML anchors check: GitHub Actions config not found");
return;
}
builder.info("Ensuring the YAML anchors in the GitHub Actions config were expanded");
builder.run_delaying_failure(
&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);
}
}
fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
builder.out.join(host.triple).join("test")
}
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 });
};
}
macro_rules! default_test_with_compare_mode {
($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr,
compare_mode: $compare_mode:expr }) => {
test_with_compare_mode!($name {
path: $path,
mode: $mode,
suite: $suite,
default: true,
host: false,
compare_mode: $compare_mode
});
};
}
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 });
};
}
macro_rules! test {
($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
host: $host:expr }) => {
test_definitions!($name {
path: $path,
mode: $mode,
suite: $suite,
default: $default,
host: $host,
compare_mode: None
});
};
}
macro_rules! test_with_compare_mode {
($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
host: $host:expr, compare_mode: $compare_mode:expr }) => {
test_definitions!($name {
path: $path,
mode: $mode,
suite: $suite,
default: $default,
host: $host,
compare_mode: Some($compare_mode)
});
};
}
macro_rules! test_definitions {
($name:ident {
path: $path:expr,
mode: $mode:expr,
suite: $suite:expr,
default: $default:expr,
host: $host:expr,
compare_mode: $compare_mode:expr
}) => {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct $name {
pub compiler: Compiler,
pub target: TargetSelection,
}
impl Step for $name {
type Output = ();
const DEFAULT: bool = $default;
const ONLY_HOSTS: bool = $host;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.suite_path($path)
}
fn make_run(run: RunConfig<'_>) {
let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
run.builder.ensure($name { compiler, target: run.target });
}
fn run(self, builder: &Builder<'_>) {
builder.ensure(Compiletest {
compiler: self.compiler,
target: self.target,
mode: $mode,
suite: $suite,
path: $path,
compare_mode: $compare_mode,
})
}
}
};
}
default_test!(Ui { path: "tests/ui", mode: "ui", suite: "ui" });
default_test!(RunPassValgrind {
path: "tests/run-pass-valgrind",
mode: "run-pass-valgrind",
suite: "run-pass-valgrind"
});
default_test!(Codegen { path: "tests/codegen", mode: "codegen", suite: "codegen" });
default_test!(CodegenUnits {
path: "tests/codegen-units",
mode: "codegen-units",
suite: "codegen-units"
});
default_test!(Incremental { path: "tests/incremental", mode: "incremental", suite: "incremental" });
default_test_with_compare_mode!(Debuginfo {
path: "tests/debuginfo",
mode: "debuginfo",
suite: "debuginfo",
compare_mode: "split-dwarf"
});
host_test!(UiFullDeps { path: "tests/ui-fulldeps", mode: "ui", suite: "ui-fulldeps" });
host_test!(Rustdoc { path: "tests/rustdoc", mode: "rustdoc", suite: "rustdoc" });
host_test!(RustdocUi { path: "tests/rustdoc-ui", mode: "ui", suite: "rustdoc-ui" });
host_test!(RustdocJson { path: "tests/rustdoc-json", mode: "rustdoc-json", suite: "rustdoc-json" });
host_test!(Pretty { path: "tests/pretty", mode: "pretty", suite: "pretty" });
default_test!(RunMake { path: "tests/run-make", mode: "run-make", suite: "run-make" });
host_test!(RunMakeFullDeps {
path: "tests/run-make-fulldeps",
mode: "run-make",
suite: "run-make-fulldeps"
});
default_test!(Assembly { path: "tests/assembly", mode: "assembly", suite: "assembly" });
default_test!(CoverageMap {
path: "tests/coverage-map",
mode: "coverage-map",
suite: "coverage-map"
});
host_test!(RunCoverage { path: "tests/run-coverage", mode: "run-coverage", suite: "run-coverage" });
host_test!(RunCoverageRustdoc {
path: "tests/run-coverage-rustdoc",
mode: "run-coverage",
suite: "run-coverage-rustdoc"
});
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct MirOpt {
pub compiler: Compiler,
pub target: TargetSelection,
}
impl Step for MirOpt {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = false;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.suite_path("tests/mir-opt")
}
fn make_run(run: RunConfig<'_>) {
let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
run.builder.ensure(MirOpt { compiler, target: run.target });
}
fn run(self, builder: &Builder<'_>) {
let run = |target| {
builder.ensure(Compiletest {
compiler: self.compiler,
target,
mode: "mir-opt",
suite: "mir-opt",
path: "tests/mir-opt",
compare_mode: None,
})
};
if builder.config.cmd.bless() {
let targets = MIR_OPT_BLESS_TARGET_MAPPING
.iter()
.filter(|(target_32bit, target_64bit)| {
*target_32bit == &*self.target.triple || *target_64bit == &*self.target.triple
})
.next()
.map(|(target_32bit, target_64bit)| {
let target_32bit = TargetSelection::from_user(target_32bit);
let target_64bit = TargetSelection::from_user(target_64bit);
if !builder.cc.borrow().contains_key(&target_32bit) {
crate::cc_detect::find_target(builder, target_32bit);
}
if !builder.cc.borrow().contains_key(&target_64bit) {
crate::cc_detect::find_target(builder, target_64bit);
}
vec![target_32bit, target_64bit]
})
.unwrap_or_else(|| {
eprintln!(
"\
Note that not all variants of mir-opt tests are going to be blessed, as no mapping between
a 32bit and a 64bit target was found for {target}.
You can add that mapping by changing MIR_OPT_BLESS_TARGET_MAPPING in src/bootstrap/test.rs",
target = self.target,
);
vec![self.target]
});
for target in targets {
run(target);
let panic_abort_target = builder.ensure(MirOptPanicAbortSyntheticTarget {
compiler: self.compiler,
base: target,
});
run(panic_abort_target);
}
} else {
run(self.target);
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
struct Compiletest {
compiler: Compiler,
target: TargetSelection,
mode: &'static str,
suite: &'static str,
path: &'static str,
compare_mode: Option<&'static str>,
}
impl Step for Compiletest {
type Output = ();
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.never()
}
fn run(self, builder: &Builder<'_>) {
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
help: to test the compiler, use `--stage 1` instead
help: to test the standard library, use `--stage 0 library/std` instead
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`."
);
crate::exit!(1);
}
let mut compiler = self.compiler;
let target = self.target;
let mode = self.mode;
let suite = self.suite;
let suite_path = self.path;
if !builder.config.codegen_tests && suite == "codegen" {
return;
}
let stage_id = if suite == "ui-fulldeps" && compiler.stage == 1 {
compiler = builder.compiler(compiler.stage - 1, target);
format!("stage{}-{}", compiler.stage + 1, target)
} else {
format!("stage{}-{}", compiler.stage, target)
};
if suite.ends_with("fulldeps") {
builder.ensure(compile::Rustc::new(compiler, target));
}
if suite == "debuginfo" {
builder
.ensure(dist::DebuggerScripts { sysroot: builder.sysroot(compiler), host: target });
}
builder.ensure(compile::Std::new(compiler, target));
builder.ensure(compile::Std::new(compiler, compiler.host));
builder.ensure(TestHelpers { target: compiler.host });
if !target.contains("wasm") || target.contains("emscripten") {
builder.ensure(TestHelpers { target });
}
builder.ensure(RemoteCopyLibs { compiler, target });
let mut cmd = builder.tool_cmd(Tool::Compiletest);
cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(compiler));
cmd.arg("--run-lib-path").arg(builder.sysroot_libdir(compiler, target));
cmd.arg("--rustc-path").arg(builder.rustc(compiler));
let is_rustdoc = suite.ends_with("rustdoc-ui") || suite.ends_with("rustdoc-js");
if mode == "rustdoc"
|| mode == "run-make"
|| (mode == "ui" && is_rustdoc)
|| mode == "js-doc-test"
|| mode == "rustdoc-json"
|| suite == "run-coverage-rustdoc"
{
cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler));
}
if mode == "rustdoc-json" {
let json_compiler = compiler.with_stage(0);
cmd.arg("--jsondocck-path")
.arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }));
cmd.arg("--jsondoclint-path")
.arg(builder.ensure(tool::JsonDocLint { compiler: json_compiler, target }));
}
if mode == "coverage-map" {
let coverage_dump = builder.ensure(tool::CoverageDump {
compiler: compiler.with_stage(0),
target: compiler.host,
});
cmd.arg("--coverage-dump-path").arg(coverage_dump);
}
if mode == "run-make" || mode == "run-coverage" {
let rust_demangler = builder
.ensure(tool::RustDemangler {
compiler,
target: compiler.host,
extra_features: Vec::new(),
})
.expect("in-tree tool");
cmd.arg("--rust-demangler-path").arg(rust_demangler);
}
cmd.arg("--src-base").arg(builder.src.join("tests").join(suite));
cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite));
let sysroot = if builder.top_stage == 0 {
builder.initial_sysroot.clone()
} else {
builder.sysroot(compiler).to_path_buf()
};
cmd.arg("--sysroot-base").arg(sysroot);
cmd.arg("--stage-id").arg(stage_id);
cmd.arg("--suite").arg(suite);
cmd.arg("--mode").arg(mode);
cmd.arg("--target").arg(target.rustc_target_arg());
cmd.arg("--host").arg(&*compiler.host.triple);
cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
if builder.config.cmd.bless() {
cmd.arg("--bless");
}
if builder.config.cmd.force_rerun() {
cmd.arg("--force-rerun");
}
let compare_mode =
builder.config.cmd.compare_mode().or_else(|| {
if builder.config.test_compare_mode { self.compare_mode } else { None }
});
if let Some(ref pass) = builder.config.cmd.pass() {
cmd.arg("--pass");
cmd.arg(pass);
}
if let Some(ref run) = builder.config.cmd.run() {
cmd.arg("--run");
cmd.arg(run);
}
if let Some(ref nodejs) = builder.config.nodejs {
cmd.arg("--nodejs").arg(nodejs);
} else if mode == "js-doc-test" {
panic!("need nodejs to run js-doc-test suite");
}
if let Some(ref npm) = builder.config.npm {
cmd.arg("--npm").arg(npm);
}
if builder.config.rust_optimize_tests {
cmd.arg("--optimize-tests");
}
if builder.config.cmd.only_modified() {
cmd.arg("--only-modified");
}
let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
flags.extend(builder.config.cmd.rustc_args().iter().map(|s| s.to_string()));
if let Some(linker) = builder.linker(target) {
cmd.arg("--target-linker").arg(linker);
}
if let Some(linker) = builder.linker(compiler.host) {
cmd.arg("--host-linker").arg(linker);
}
let mut hostflags = flags.clone();
hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
hostflags.extend(builder.lld_flags(compiler.host));
for flag in hostflags {
cmd.arg("--host-rustcflags").arg(flag);
}
let mut targetflags = flags;
targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
targetflags.extend(builder.lld_flags(target));
for flag in targetflags {
cmd.arg("--target-rustcflags").arg(flag);
}
cmd.arg("--python").arg(builder.python());
if let Some(ref gdb) = builder.config.gdb {
cmd.arg("--gdb").arg(gdb);
}
let run = |cmd: &mut Command| {
cmd.output().map(|output| {
String::from_utf8_lossy(&output.stdout)
.lines()
.next()
.unwrap_or_else(|| panic!("{:?} failed {:?}", cmd, output))
.to_string()
})
};
let lldb_exe = "lldb";
let lldb_version = Command::new(lldb_exe)
.arg("--version")
.output()
.map(|output| String::from_utf8_lossy(&output.stdout).to_string())
.ok();
if let Some(ref vers) = lldb_version {
cmd.arg("--lldb-version").arg(vers);
let lldb_python_dir = run(Command::new(lldb_exe).arg("-P")).ok();
if let Some(ref dir) = lldb_python_dir {
cmd.arg("--lldb-python-dir").arg(dir);
}
}
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);
}
for exclude in &builder.config.skip {
cmd.arg("--skip");
cmd.arg(&exclude);
}
let paths = match &builder.config.cmd {
Subcommand::Test { .. } => &builder.config.paths[..],
_ => &[],
};
let mut test_args: Vec<&str> = paths
.iter()
.filter_map(|p| util::is_valid_test_suite_arg(p, suite_path, builder))
.collect();
test_args.append(&mut builder.config.test_args());
if cfg!(windows) {
let test_args_win: Vec<String> =
test_args.iter().map(|s| s.replace("/", "\\")).collect();
cmd.args(&test_args_win);
} else {
cmd.args(&test_args);
}
if builder.is_verbose() {
cmd.arg("--verbose");
}
cmd.arg("--json");
let mut llvm_components_passed = false;
let mut copts_passed = false;
if builder.config.llvm_enabled() {
let llvm::LlvmResult { llvm_config, .. } =
builder.ensure(llvm::Llvm { target: builder.config.build });
if !builder.config.dry_run() {
let llvm_version = output(Command::new(&llvm_config).arg("--version"));
let llvm_components = output(Command::new(&llvm_config).arg("--components"));
cmd.arg("--llvm-version")
.arg(llvm_version.trim())
.arg("--llvm-components")
.arg(llvm_components.trim());
llvm_components_passed = true;
}
if !builder.is_rust_llvm(target) {
cmd.arg("--system-llvm");
}
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);
}
if !builder.config.dry_run()
&& (matches!(suite, "run-make" | "run-make-fulldeps") || mode == "run-coverage")
{
let llvm_bin_path = llvm_config
.parent()
.expect("Expected llvm-config to be contained in directory");
assert!(llvm_bin_path.is_dir());
cmd.arg("--llvm-bin-dir").arg(llvm_bin_path);
}
if !builder.config.dry_run() && matches!(suite, "run-make" | "run-make-fulldeps") {
if builder.config.lld_enabled {
let lld_install_root =
builder.ensure(llvm::Lld { target: builder.config.build });
let lld_bin_path = lld_install_root.join("bin");
let old_path = env::var_os("PATH").unwrap_or_default();
let new_path = env::join_paths(
std::iter::once(lld_bin_path).chain(env::split_paths(&old_path)),
)
.expect("Could not add LLD bin path to PATH");
cmd.env("PATH", new_path);
}
}
}
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, CLang::C).join(" "))
.arg("--cxxflags")
.arg(builder.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" "));
copts_passed = true;
if let Some(ar) = builder.ar(target) {
cmd.arg("--ar").arg(ar);
}
}
if !llvm_components_passed {
cmd.arg("--llvm-components").arg("");
}
if !copts_passed {
cmd.arg("--cc")
.arg("")
.arg("--cxx")
.arg("")
.arg("--cflags")
.arg("")
.arg("--cxxflags")
.arg("");
}
if builder.remote_tested(target) {
cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
}
if !builder.config.dry_run() && target.contains("msvc") {
for &(ref k, ref v) in builder.cc.borrow()[&target].env() {
if k != "PATH" {
cmd.env(k, v);
}
}
}
cmd.env("RUSTC_BOOTSTRAP", "1");
cmd.env("RUSTC_FORCE_RUSTC_VERSION", "compiletest");
cmd.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
builder.add_rust_test_threads(&mut cmd);
if builder.config.sanitizers_enabled(target) {
cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
}
if builder.config.profiler_enabled(target) {
cmd.env("RUSTC_PROFILER_SUPPORT", "1");
}
cmd.env("RUST_TEST_TMPDIR", builder.tempdir());
cmd.arg("--adb-path").arg("adb");
cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
if target.contains("android") && !builder.config.dry_run() {
cmd.arg("--android-cross-path")
.arg(builder.cc(target).parent().unwrap().parent().unwrap());
} else {
cmd.arg("--android-cross-path").arg("");
}
if builder.config.cmd.rustfix_coverage() {
cmd.arg("--rustfix-coverage");
}
cmd.env("BOOTSTRAP_CARGO", &builder.initial_cargo);
cmd.arg("--channel").arg(&builder.config.channel);
if !builder.config.omit_git_hash {
cmd.arg("--git-hash");
}
builder.ci_env.force_coloring_in_ci(&mut cmd);
#[cfg(feature = "build-metrics")]
builder.metrics.begin_test_suite(
build_helper::metrics::TestSuiteMetadata::Compiletest {
suite: suite.into(),
mode: mode.into(),
compare_mode: None,
target: self.target.triple.to_string(),
host: self.compiler.host.triple.to_string(),
stage: self.compiler.stage,
},
builder,
);
let _group = builder.msg(
Kind::Test,
compiler.stage,
&format!("compiletest suite={suite} mode={mode}"),
compiler.host,
target,
);
crate::render_tests::try_run_tests(builder, &mut cmd, false);
if let Some(compare_mode) = compare_mode {
cmd.arg("--compare-mode").arg(compare_mode);
#[cfg(feature = "build-metrics")]
builder.metrics.begin_test_suite(
build_helper::metrics::TestSuiteMetadata::Compiletest {
suite: suite.into(),
mode: mode.into(),
compare_mode: Some(compare_mode.into()),
target: self.target.triple.to_string(),
host: self.compiler.host.triple.to_string(),
stage: self.compiler.stage,
},
builder,
);
builder.info(&format!(
"Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
suite, mode, compare_mode, &compiler.host, target
));
let _time = util::timeit(&builder);
crate::render_tests::try_run_tests(builder, &mut cmd, false);
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct BookTest {
compiler: Compiler,
path: PathBuf,
name: &'static str,
is_ext_doc: bool,
}
impl Step for BookTest {
type Output = ();
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.never()
}
fn run(self, builder: &Builder<'_>) {
if self.is_ext_doc {
self.run_ext_doc(builder);
} else {
self.run_local_doc(builder);
}
}
}
impl BookTest {
fn run_ext_doc(self, builder: &Builder<'_>) {
let compiler = self.compiler;
builder.ensure(compile::Std::new(compiler, compiler.host));
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("RUSTC_BOOTSTRAP", "1");
rustbook_cmd.env("PATH", new_path).arg("test").arg(path);
builder.add_rust_test_threads(&mut rustbook_cmd);
let _guard = builder.msg(
Kind::Test,
compiler.stage,
format_args!("mdbook {}", self.path.display()),
compiler.host,
compiler.host,
);
let _time = util::timeit(&builder);
let toolstate = if builder.run_delaying_failure(&mut rustbook_cmd) {
ToolState::TestPass
} else {
ToolState::TestFail
};
builder.save_toolstate(self.name, toolstate);
}
fn run_local_doc(self, builder: &Builder<'_>) {
let compiler = self.compiler;
let host = self.compiler.host;
builder.ensure(compile::Std::new(compiler, host));
let _guard =
builder.msg(Kind::Test, compiler.stage, &format!("book {}", self.name), host, host);
let mut stack = vec![builder.src.join(self.path)];
let _time = util::timeit(&builder);
let mut files = Vec::new();
while let Some(p) = stack.pop() {
if p.is_dir() {
stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
continue;
}
if p.extension().and_then(|s| s.to_str()) != Some("md") {
continue;
}
files.push(p);
}
files.sort();
for file in files {
markdown_test(builder, compiler, &file);
}
}
}
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;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path($path)
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure($name {
compiler: run.builder.compiler(run.builder.top_stage, run.target),
});
}
fn run(self, builder: &Builder<'_>) {
builder.ensure(BookTest {
compiler: self.compiler,
path: PathBuf::from($path),
name: $book_name,
is_ext_doc: !$default,
});
}
}
)+
}
}
test_book!(
Nomicon, "src/doc/nomicon", "nomicon", default=false;
Reference, "src/doc/reference", "reference", default=false;
RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
RustcBook, "src/doc/rustc", "rustc", default=true;
RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false;
EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false;
TheBook, "src/doc/book", "book", default=false;
UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
EditionGuide, "src/doc/edition-guide", "edition-guide", default=false;
);
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ErrorIndex {
compiler: Compiler,
}
impl Step for ErrorIndex {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/error_index_generator")
}
fn make_run(run: RunConfig<'_>) {
let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.build);
run.builder.ensure(ErrorIndex { compiler });
}
fn run(self, builder: &Builder<'_>) {
let compiler = self.compiler;
let dir = testdir(builder, compiler.host);
t!(fs::create_dir_all(&dir));
let output = dir.join("error-index.md");
let mut tool = tool::ErrorIndex::command(builder);
tool.arg("markdown").arg(&output);
let guard =
builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host);
let _time = util::timeit(&builder);
builder.run_quiet(&mut tool);
drop(guard);
builder.ensure(compile::Std::new(compiler, compiler.host));
markdown_test(builder, compiler, &output);
}
}
fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
if let Ok(contents) = fs::read_to_string(markdown) {
if !contents.contains("```") {
return true;
}
}
builder.verbose(&format!("doc tests for: {}", markdown.display()));
let mut cmd = builder.rustdoc_cmd(compiler);
builder.add_rust_test_threads(&mut cmd);
cmd.arg("-Z");
cmd.arg("unstable-options");
cmd.arg("--test");
cmd.arg(markdown);
cmd.env("RUSTC_BOOTSTRAP", "1");
let test_args = builder.config.test_args().join(" ");
cmd.arg("--test-args").arg(test_args);
if builder.config.verbose_tests {
builder.run_delaying_failure(&mut cmd)
} else {
builder.run_quiet_delaying_failure(&mut cmd)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RustcGuide;
impl Step for RustcGuide {
type Output = ();
const DEFAULT: bool = false;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/doc/rustc-dev-guide")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(RustcGuide);
}
fn run(self, builder: &Builder<'_>) {
let relative_path = Path::new("src").join("doc").join("rustc-dev-guide");
builder.update_submodule(&relative_path);
let src = builder.src.join(relative_path);
let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
let toolstate = if builder.run_delaying_failure(rustbook_cmd.arg("linkcheck").arg(&src)) {
ToolState::TestPass
} else {
ToolState::TestFail
};
builder.save_toolstate("rustc-dev-guide", toolstate);
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CrateLibrustc {
compiler: Compiler,
target: TargetSelection,
crates: Vec<Interned<String>>,
}
impl Step for CrateLibrustc {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.crate_or_deps("rustc-main")
}
fn make_run(run: RunConfig<'_>) {
let builder = run.builder;
let host = run.build_triple();
let compiler = builder.compiler_for(builder.top_stage, host, host);
let crates = run
.paths
.iter()
.map(|p| builder.crate_paths[&p.assert_single_path().path].clone())
.collect();
builder.ensure(CrateLibrustc { compiler, target: run.target, crates });
}
fn run(self, builder: &Builder<'_>) {
builder.ensure(Crate {
compiler: self.compiler,
target: self.target,
mode: Mode::Rustc,
crates: self.crates,
});
}
}
fn run_cargo_test<'a>(
cargo: impl Into<Command>,
libtest_args: &[&str],
crates: &[Interned<String>],
primary_crate: &str,
description: impl Into<Option<&'a str>>,
compiler: Compiler,
target: TargetSelection,
builder: &Builder<'_>,
) -> bool {
let mut cargo =
prepare_cargo_test(cargo, libtest_args, crates, primary_crate, compiler, target, builder);
let _time = util::timeit(&builder);
let _group = description.into().and_then(|what| {
builder.msg_sysroot_tool(Kind::Test, compiler.stage, what, compiler.host, target)
});
#[cfg(feature = "build-metrics")]
builder.metrics.begin_test_suite(
build_helper::metrics::TestSuiteMetadata::CargoPackage {
crates: crates.iter().map(|c| c.to_string()).collect(),
target: target.triple.to_string(),
host: compiler.host.triple.to_string(),
stage: compiler.stage,
},
builder,
);
add_flags_and_try_run_tests(builder, &mut cargo)
}
fn prepare_cargo_test(
cargo: impl Into<Command>,
libtest_args: &[&str],
crates: &[Interned<String>],
primary_crate: &str,
compiler: Compiler,
target: TargetSelection,
builder: &Builder<'_>,
) -> Command {
let mut cargo = cargo.into();
if builder.config.cmd.bless() && !cargo.get_envs().any(|v| v.0 == "RUSTC_BLESS") {
cargo.env("RUSTC_BLESS", "Gesundheit");
}
if builder.kind == Kind::Test && !builder.fail_fast {
cargo.arg("--no-fail-fast");
}
match builder.doc_tests {
DocTests::Only => {
cargo.arg("--doc");
}
DocTests::No => {
let krate = &builder
.crates
.get(&INTERNER.intern_str(primary_crate))
.unwrap_or_else(|| panic!("missing crate {primary_crate}"));
if krate.has_lib {
cargo.arg("--lib");
}
cargo.args(&["--bins", "--examples", "--tests", "--benches"]);
}
DocTests::Yes => {}
}
for &krate in crates {
cargo.arg("-p").arg(krate);
}
cargo.arg("--").args(&builder.config.test_args()).args(libtest_args);
if !builder.config.verbose_tests {
cargo.arg("--quiet");
}
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());
if target.contains("emscripten") {
cargo.env(
format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
builder.config.nodejs.as_ref().expect("nodejs not configured"),
);
} else if target.starts_with("wasm32") {
let node = builder.config.nodejs.as_ref().expect("nodejs not configured");
let runner = format!("{} {}/src/etc/wasm32-shim.js", node.display(), builder.src.display());
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), &runner);
} else if builder.remote_tested(target) {
cargo.env(
format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
);
}
cargo
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Crate {
pub compiler: Compiler,
pub target: TargetSelection,
pub mode: Mode,
pub crates: Vec<Interned<String>>,
}
impl Step for Crate {
type Output = ();
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.crate_or_deps("sysroot")
}
fn make_run(run: RunConfig<'_>) {
let builder = run.builder;
let host = run.build_triple();
let compiler = builder.compiler_for(builder.top_stage, host, host);
let crates = run
.paths
.iter()
.map(|p| builder.crate_paths[&p.assert_single_path().path].clone())
.collect();
builder.ensure(Crate { compiler, target: run.target, mode: Mode::Std, crates });
}
fn run(self, builder: &Builder<'_>) {
let compiler = self.compiler;
let target = self.target;
let mode = self.mode;
builder.ensure(compile::Std::force_recompile(compiler, target));
builder.ensure(RemoteCopyLibs { compiler, target });
let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
let mut cargo =
builder.cargo(compiler, mode, SourceType::InTree, target, builder.kind.as_str());
match mode {
Mode::Std => {
compile::std_cargo(builder, target, compiler.stage, &mut cargo);
if builder.download_rustc() && compiler.stage > 0 {
let sysroot = builder
.out
.join(compiler.host.triple)
.join(format!("stage{}-test-sysroot", compiler.stage));
cargo.env("RUSTC_SYSROOT", sysroot);
}
}
Mode::Rustc => {
compile::rustc_cargo(builder, &mut cargo, target, compiler.stage);
}
_ => panic!("can only test libraries"),
};
run_cargo_test(
cargo,
&[],
&self.crates,
&self.crates[0],
&*crate_description(&self.crates),
compiler,
target,
builder,
);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CrateRustdoc {
host: TargetSelection,
}
impl Step for CrateRustdoc {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.paths(&["src/librustdoc", "src/tools/rustdoc"])
}
fn make_run(run: RunConfig<'_>) {
let builder = run.builder;
builder.ensure(CrateRustdoc { host: run.target });
}
fn run(self, builder: &Builder<'_>) {
let target = self.host;
let compiler = if builder.download_rustc() {
builder.compiler(builder.top_stage, target)
} else {
builder.compiler_for(builder.top_stage, target, target)
};
builder.ensure(compile::Std::new(compiler, target));
builder.ensure(compile::Rustc::new(compiler, target));
let mut cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolRustc,
target,
builder.kind.as_str(),
"src/tools/rustdoc",
SourceType::InTree,
&[],
);
if self.host.contains("musl") {
cargo.arg("'-Ctarget-feature=-crt-static'");
}
let libdir = if builder.download_rustc() {
builder.rustc_libdir(compiler)
} else {
builder.sysroot_libdir(compiler, target).to_path_buf()
};
let mut dylib_path = dylib_path();
dylib_path.insert(0, PathBuf::from(&*libdir));
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
run_cargo_test(
cargo,
&[],
&[INTERNER.intern_str("rustdoc:0.0.0")],
"rustdoc",
"rustdoc",
compiler,
target,
builder,
);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CrateRustdocJsonTypes {
host: TargetSelection,
}
impl Step for CrateRustdocJsonTypes {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/rustdoc-json-types")
}
fn make_run(run: RunConfig<'_>) {
let builder = run.builder;
builder.ensure(CrateRustdocJsonTypes { host: run.target });
}
fn run(self, builder: &Builder<'_>) {
let target = self.host;
let compiler = builder.compiler_for(builder.top_stage, target, target);
builder.ensure(compile::Rustc::new(compiler, target));
let cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolRustc,
target,
builder.kind.as_str(),
"src/rustdoc-json-types",
SourceType::InTree,
&[],
);
let libtest_args = if self.host.contains("musl") {
["'-Ctarget-feature=-crt-static'"].as_slice()
} else {
&[]
};
run_cargo_test(
cargo,
libtest_args,
&[INTERNER.intern_str("rustdoc-json-types")],
"rustdoc-json-types",
"rustdoc-json-types",
compiler,
target,
builder,
);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RemoteCopyLibs {
compiler: Compiler,
target: TargetSelection,
}
impl Step for RemoteCopyLibs {
type Output = ();
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.never()
}
fn run(self, builder: &Builder<'_>) {
let compiler = self.compiler;
let target = self.target;
if !builder.remote_tested(target) {
return;
}
builder.ensure(compile::Std::new(compiler, target));
builder.info(&format!("REMOTE copy libs to emulator ({target})"));
let server = builder.ensure(tool::RemoteTestServer { compiler, target });
let tool = builder.tool_exe(Tool::RemoteTestClient);
let mut cmd = Command::new(&tool);
cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.tempdir());
if let Some(rootfs) = builder.qemu_rootfs(target) {
cmd.arg(rootfs);
}
builder.run(&mut cmd);
for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) {
let f = t!(f);
let name = f.file_name().into_string().unwrap();
if util::is_dylib(&name) {
builder.run(Command::new(&tool).arg("push").arg(f.path()));
}
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Distcheck;
impl Step for Distcheck {
type Output = ();
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("distcheck")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Distcheck);
}
fn run(self, builder: &Builder<'_>) {
builder.info("Distcheck");
let dir = builder.tempdir().join("distcheck");
let _ = fs::remove_dir_all(&dir);
t!(fs::create_dir_all(&dir));
builder.ensure(dist::PlainSourceTarball);
builder.ensure(dist::Src);
let mut cmd = Command::new("tar");
cmd.arg("-xf")
.arg(builder.ensure(dist::PlainSourceTarball).tarball())
.arg("--strip-components=1")
.current_dir(&dir);
builder.run(&mut cmd);
builder.run(
Command::new("./configure")
.args(&builder.config.configure_args)
.arg("--enable-vendor")
.current_dir(&dir),
);
builder.run(
Command::new(util::make(&builder.config.build.triple)).arg("check").current_dir(&dir),
);
builder.info("Distcheck rust-src");
let dir = builder.tempdir().join("distcheck-src");
let _ = fs::remove_dir_all(&dir);
t!(fs::create_dir_all(&dir));
let mut cmd = Command::new("tar");
cmd.arg("-xf")
.arg(builder.ensure(dist::Src).tarball())
.arg("--strip-components=1")
.current_dir(&dir);
builder.run(&mut cmd);
let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
builder.run(
Command::new(&builder.initial_cargo)
.env("RUSTC_BOOTSTRAP", "1")
.arg("generate-lockfile")
.arg("--manifest-path")
.arg(&toml)
.current_dir(&dir),
);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Bootstrap;
impl Step for Bootstrap {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn run(self, builder: &Builder<'_>) {
let host = builder.config.build;
let compiler = builder.compiler(0, host);
let _guard = builder.msg(Kind::Test, 0, "bootstrap", host, host);
let mut check_bootstrap = Command::new(&builder.python());
check_bootstrap
.args(["-m", "unittest", "bootstrap_test.py"])
.env("BUILD_DIR", &builder.out)
.env("BUILD_PLATFORM", &builder.build.build.triple)
.current_dir(builder.src.join("src/bootstrap/"));
builder.run_delaying_failure(&mut check_bootstrap);
let mut cmd = Command::new(&builder.initial_cargo);
cmd.arg("test")
.current_dir(builder.src.join("src/bootstrap"))
.env("RUSTFLAGS", "-Cdebuginfo=2")
.env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
.env("RUSTC_BOOTSTRAP", "1")
.env("RUSTDOC", builder.rustdoc(compiler))
.env("RUSTC", &builder.initial_rustc);
if let Some(flags) = option_env!("RUSTFLAGS") {
cmd.env("RUSTFLAGS", flags);
}
run_cargo_test(cmd, &["--test-threads=1"], &[], "bootstrap", None, compiler, host, builder);
}
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/bootstrap")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Bootstrap);
}
}
#[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<'_>) {
let compiler =
run.builder.compiler_for(run.builder.top_stage, run.builder.build.build, run.target);
run.builder.ensure(TierCheck { compiler });
}
fn run(self, builder: &Builder<'_>) {
builder.ensure(compile::Std::new(self.compiler, self.compiler.host));
let mut cargo = tool::prepare_tool_cargo(
builder,
self.compiler,
Mode::ToolStd,
self.compiler.host,
"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");
}
let _guard = builder.msg(
Kind::Test,
self.compiler.stage,
"platform support check",
self.compiler.host,
self.compiler.host,
);
builder.run_delaying_failure(&mut cargo.into());
}
}
#[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,
});
}
fn run(self, builder: &Builder<'_>) {
builder.ensure(crate::doc::RustcBook {
compiler: self.compiler,
target: self.target,
validate: true,
});
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RustInstaller;
impl Step for RustInstaller {
type Output = ();
const ONLY_HOSTS: bool = true;
const DEFAULT: bool = true;
fn run(self, builder: &Builder<'_>) {
let bootstrap_host = builder.config.build;
let compiler = builder.compiler(0, bootstrap_host);
let cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolBootstrap,
bootstrap_host,
"test",
"src/tools/rust-installer",
SourceType::InTree,
&[],
);
let _guard = builder.msg(
Kind::Test,
compiler.stage,
"rust-installer",
bootstrap_host,
bootstrap_host,
);
run_cargo_test(cargo, &[], &[], "installer", None, compiler, bootstrap_host, builder);
if bootstrap_host != "x86_64-unknown-linux-gnu" {
return;
}
let mut cmd =
std::process::Command::new(builder.src.join("src/tools/rust-installer/test.sh"));
let tmpdir = testdir(builder, compiler.host).join("rust-installer");
let _ = std::fs::remove_dir_all(&tmpdir);
let _ = std::fs::create_dir_all(&tmpdir);
cmd.current_dir(&tmpdir);
cmd.env("CARGO_TARGET_DIR", tmpdir.join("cargo-target"));
cmd.env("CARGO", &builder.initial_cargo);
cmd.env("RUSTC", &builder.initial_rustc);
cmd.env("TMP_DIR", &tmpdir);
builder.run_delaying_failure(&mut cmd);
}
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/rust-installer")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Self);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct TestHelpers {
pub target: TargetSelection,
}
impl Step for TestHelpers {
type Output = ();
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("tests/auxiliary/rust_test_helpers.c")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(TestHelpers { target: run.target })
}
fn run(self, builder: &Builder<'_>) {
if builder.config.dry_run() {
return;
}
let target = if self.target == "x86_64-fortanix-unknown-sgx" {
TargetSelection::from_user("x86_64-unknown-linux-gnu")
} else {
self.target
};
let dst = builder.test_helpers_out(target);
let src = builder.src.join("tests/auxiliary/rust_test_helpers.c");
if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
return;
}
let _guard = builder.msg_unstaged(Kind::Build, "test helpers", target);
t!(fs::create_dir_all(&dst));
let mut cfg = cc::Build::new();
if target.contains("emscripten") {
cfg.pic(false);
}
if !target.contains("msvc") {
if let Some(ar) = builder.ar(target) {
cfg.archiver(ar);
}
cfg.compiler(builder.cc(target));
}
cfg.cargo_metadata(false)
.out_dir(&dst)
.target(&target.triple)
.host(&builder.config.build.triple)
.opt_level(0)
.warnings(false)
.debug(false)
.file(builder.src.join("tests/auxiliary/rust_test_helpers.c"))
.compile("rust_test_helpers");
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CodegenCranelift {
compiler: Compiler,
target: TargetSelection,
}
impl Step for CodegenCranelift {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.paths(&["compiler/rustc_codegen_cranelift"])
}
fn make_run(run: RunConfig<'_>) {
let builder = run.builder;
let host = run.build_triple();
let compiler = run.builder.compiler_for(run.builder.top_stage, host, host);
if builder.doc_tests == DocTests::Only {
return;
}
let triple = run.target.triple;
let target_supported = if triple.contains("linux") {
triple.contains("x86_64") || triple.contains("aarch64") || triple.contains("s390x")
} else if triple.contains("darwin") || triple.contains("windows") {
triple.contains("x86_64")
} else {
false
};
if !target_supported {
builder.info("target not supported by rustc_codegen_cranelift. skipping");
return;
}
if builder.remote_tested(run.target) {
builder.info("remote testing is not supported by rustc_codegen_cranelift. skipping");
return;
}
if !builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("cranelift")) {
builder.info("cranelift not in rust.codegen-backends. skipping");
return;
}
builder.ensure(CodegenCranelift { compiler, target: run.target });
}
fn run(self, builder: &Builder<'_>) {
let compiler = self.compiler;
let target = self.target;
builder.ensure(compile::Std::new(compiler, target));
let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
let build_cargo = || {
let mut cargo = builder.cargo(
compiler,
Mode::Codegen, SourceType::InTree,
target,
"run",
);
cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift"));
cargo
.arg("--manifest-path")
.arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml"));
compile::rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
cargo.env("CARGO_BUILD_INCREMENTAL", "false");
cargo
};
builder.info(&format!(
"{} cranelift stage{} ({} -> {})",
Kind::Test.description(),
compiler.stage,
&compiler.host,
target
));
let _time = util::timeit(&builder);
let download_dir = builder.out.join("cg_clif_download");
let mut cargo = build_cargo();
cargo
.arg("--")
.arg("test")
.arg("--download-dir")
.arg(&download_dir)
.arg("--out-dir")
.arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_clif"))
.arg("--no-unstable-features")
.arg("--use-backend")
.arg("cranelift")
.arg("--sysroot")
.arg("llvm")
.arg("--skip-test")
.arg("testsuite.extended_sysroot");
cargo.args(builder.config.test_args());
#[allow(deprecated)]
builder.config.try_run(&mut cargo.into()).unwrap();
}
}