Skip to content

Implement check for compiletest and RA using tool macro #143816

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/bootstrap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ build/
debuginfo/
...

# Bootstrap host tools (which are always compiled with the stage0 compiler)
# Host tools (which are always compiled with the stage0 compiler)
# are stored here.
bootstrap-tools/

Expand Down
202 changes: 65 additions & 137 deletions src/bootstrap/src/core/build_steps/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use crate::core::build_steps::compile::{
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
};
use crate::core::build_steps::tool;
use crate::core::build_steps::tool::{COMPILETEST_ALLOW_FEATURES, SourceType, prepare_tool_cargo};
use crate::core::build_steps::tool::{
COMPILETEST_ALLOW_FEATURES, SourceType, ToolTargetBuildMode, get_tool_target_compiler,
prepare_tool_cargo,
};
use crate::core::builder::{
self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description,
};
Expand Down Expand Up @@ -247,8 +250,10 @@ fn prepare_compiler_for_check(
mode: Mode,
) -> Compiler {
let host = builder.host_target;

match mode {
Mode::ToolBootstrap => builder.compiler(0, host),
Mode::ToolTarget => get_tool_target_compiler(builder, ToolTargetBuildMode::Build(target)),
Mode::ToolStd => {
// These tools require the local standard library to be checked
let build_compiler = builder.compiler(builder.top_stage, host);
Expand Down Expand Up @@ -353,132 +358,18 @@ impl Step for CodegenBackend {
}
}

/// Checks Rust analyzer that links to .rmetas from a checked rustc.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct RustAnalyzer {
pub build_compiler: Compiler,
pub target: TargetSelection,
}

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

fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
run.path("src/tools/rust-analyzer").default_condition(
builder
.config
.tools
.as_ref()
.is_none_or(|tools| tools.iter().any(|tool| tool == "rust-analyzer")),
)
}

fn make_run(run: RunConfig<'_>) {
let build_compiler = prepare_compiler_for_check(run.builder, run.target, Mode::ToolRustc);
run.builder.ensure(RustAnalyzer { build_compiler, target: run.target });
}

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

let mut cargo = prepare_tool_cargo(
builder,
build_compiler,
Mode::ToolRustc,
target,
builder.kind,
"src/tools/rust-analyzer",
SourceType::InTree,
&["in-rust-tree".to_owned()],
);

cargo.allow_features(crate::core::build_steps::tool::RustAnalyzer::ALLOW_FEATURES);

cargo.arg("--bins");
cargo.arg("--tests");
cargo.arg("--benches");

// Cargo's output path in a given stage, compiled by a particular
// compiler for the specified target.
let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, Mode::ToolRustc, target))
.with_prefix("rust-analyzer-check");

let _guard = builder.msg_check("rust-analyzer artifacts", target, None);
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
}

fn metadata(&self) -> Option<StepMetadata> {
Some(StepMetadata::check("rust-analyzer", self.target).built_by(self.build_compiler))
}
}

/// Compiletest is implicitly "checked" when it gets built in order to run tests,
/// so this is mainly for people working on compiletest to run locally.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Compiletest {
pub target: TargetSelection,
}

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

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

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

fn run(self, builder: &Builder<'_>) {
let mode = if builder.config.compiletest_use_stage0_libtest {
Mode::ToolBootstrap
} else {
Mode::ToolStd
};
let build_compiler = prepare_compiler_for_check(builder, self.target, mode);

let mut cargo = prepare_tool_cargo(
builder,
build_compiler,
mode,
self.target,
builder.kind,
"src/tools/compiletest",
SourceType::InTree,
&[],
);

cargo.allow_features(COMPILETEST_ALLOW_FEATURES);

cargo.arg("--all-targets");

let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, mode, self.target))
.with_prefix("compiletest-check");

let _guard = builder.msg_check("compiletest artifacts", self.target, None);
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
}

fn metadata(&self) -> Option<StepMetadata> {
Some(StepMetadata::check("compiletest", self.target))
}
}

macro_rules! tool_check_step {
(
$name:ident {
// The part of this path after the final '/' is also used as a display name.
path: $path:literal
$(, alt_path: $alt_path:literal )*
, mode: $mode:path
// Closure that returns `Mode` based on the passed `&Builder<'_>`
, mode: $mode:expr
// Subset of nightly features that are allowed to be used when checking
$(, allow_features: $allow_features:expr )?
// Features that should be enabled when checking
$(, enable_features: [$($enable_features:expr),*] )?
$(, default: $default:literal )?
$( , )?
}
Expand All @@ -501,10 +392,13 @@ macro_rules! tool_check_step {

fn make_run(run: RunConfig<'_>) {
let target = run.target;
let build_compiler = prepare_compiler_for_check(run.builder, target, $mode);
let builder = run.builder;
let mode = $mode(builder);

let build_compiler = prepare_compiler_for_check(run.builder, target, mode);

// It doesn't make sense to cross-check bootstrap tools
if $mode == Mode::ToolBootstrap && target != run.builder.host_target {
if mode == Mode::ToolBootstrap && target != run.builder.host_target {
println!("WARNING: not checking bootstrap tool {} for target {target} as it is a bootstrap (host-only) tool", stringify!($path));
return;
};
Expand All @@ -519,7 +413,9 @@ macro_rules! tool_check_step {
$( _value = $allow_features; )?
_value
};
run_tool_check_step(builder, build_compiler, target, $path, $mode, allow_features);
let extra_features: &[&str] = &[$($($enable_features),*)?];
let mode = $mode(builder);
run_tool_check_step(builder, build_compiler, target, $path, mode, allow_features, extra_features);
}

fn metadata(&self) -> Option<StepMetadata> {
Expand All @@ -537,9 +433,11 @@ fn run_tool_check_step(
path: &str,
mode: Mode,
allow_features: &str,
extra_features: &[&str],
) {
let display_name = path.rsplit('/').next().unwrap();

let extra_features = extra_features.iter().map(|f| f.to_string()).collect::<Vec<String>>();
let mut cargo = prepare_tool_cargo(
builder,
build_compiler,
Expand All @@ -552,12 +450,19 @@ fn run_tool_check_step(
// steps should probably be marked non-default so that the default
// checks aren't affected by toolstate being broken.
SourceType::InTree,
&[],
&extra_features,
);
cargo.allow_features(allow_features);

// FIXME: check bootstrap doesn't currently work with --all-targets
cargo.arg("--all-targets");
// FIXME: check bootstrap doesn't currently work when multiple targets are checked
// FIXME: rust-analyzer does not work with --all-targets
if display_name == "rust-analyzer" {
cargo.arg("--bins");
cargo.arg("--tests");
cargo.arg("--benches");
} else {
cargo.arg("--all-targets");
}

let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, mode, target))
.with_prefix(&format!("{display_name}-check"));
Expand All @@ -576,43 +481,66 @@ fn run_tool_check_step(
tool_check_step!(Rustdoc {
path: "src/tools/rustdoc",
alt_path: "src/librustdoc",
mode: Mode::ToolRustc
mode: |_builder| Mode::ToolRustc
});
// Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead
// of a submodule. Since the SourceType only drives the deny-warnings
// behavior, treat it as in-tree so that any new warnings in clippy will be
// rejected.
tool_check_step!(Clippy { path: "src/tools/clippy", mode: Mode::ToolRustc });
tool_check_step!(Miri { path: "src/tools/miri", mode: Mode::ToolRustc });
tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: Mode::ToolRustc });
tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: Mode::ToolRustc });
tool_check_step!(Clippy { path: "src/tools/clippy", mode: |_builder| Mode::ToolRustc });
tool_check_step!(Miri { path: "src/tools/miri", mode: |_builder| Mode::ToolRustc });
tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: |_builder| Mode::ToolRustc });
tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: |_builder| Mode::ToolRustc });
tool_check_step!(RustAnalyzer {
path: "src/tools/rust-analyzer",
mode: |_builder| Mode::ToolRustc,
allow_features: tool::RustAnalyzer::ALLOW_FEATURES,
enable_features: ["in-rust-tree"],
});
tool_check_step!(MiroptTestTools {
path: "src/tools/miropt-test-tools",
mode: Mode::ToolBootstrap
mode: |_builder| Mode::ToolBootstrap
});
// We want to test the local std
tool_check_step!(TestFloatParse {
path: "src/tools/test-float-parse",
mode: Mode::ToolStd,
mode: |_builder| Mode::ToolStd,
allow_features: tool::TestFloatParse::ALLOW_FEATURES
});
tool_check_step!(FeaturesStatusDump {
path: "src/tools/features-status-dump",
mode: Mode::ToolBootstrap
mode: |_builder| Mode::ToolBootstrap
});

tool_check_step!(Bootstrap { path: "src/bootstrap", mode: Mode::ToolBootstrap, default: false });
tool_check_step!(Bootstrap {
path: "src/bootstrap",
mode: |_builder| Mode::ToolBootstrap,
default: false
});

// `run-make-support` will be built as part of suitable run-make compiletest test steps, but support
// check to make it easier to work on.
tool_check_step!(RunMakeSupport {
path: "src/tools/run-make-support",
mode: Mode::ToolBootstrap,
mode: |_builder| Mode::ToolBootstrap,
default: false
});

tool_check_step!(CoverageDump {
path: "src/tools/coverage-dump",
mode: Mode::ToolBootstrap,
mode: |_builder| Mode::ToolBootstrap,
default: false
});

// Compiletest is implicitly "checked" when it gets built in order to run tests,
// so this is mainly for people working on compiletest to run locally.
tool_check_step!(Compiletest {
path: "src/tools/compiletest",
mode: |builder: &Builder<'_>| if builder.config.compiletest_use_stage0_libtest {
Mode::ToolBootstrap
} else {
Mode::ToolStd
},
allow_features: COMPILETEST_ALLOW_FEATURES,
default: false,
});
Loading
Loading