use crate::core::build_steps::compile::{
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo,
};
use crate::core::build_steps::tool::{prepare_tool_cargo, SourceType};
use crate::core::builder::{
self, crate_description, Alias, Builder, Kind, RunConfig, ShouldRun, Step,
};
use crate::core::config::TargetSelection;
use crate::{Compiler, Mode, Subcommand};
use std::path::{Path, PathBuf};
pub fn cargo_subcommand(kind: Kind) -> &'static str {
match kind {
Kind::Check
| Kind::Clippy => "check",
Kind::Fix => "fix",
_ => unreachable!(),
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Std {
pub target: TargetSelection,
crates: Vec<String>,
}
impl Std {
pub fn new(target: TargetSelection) -> Self {
Self { target, crates: vec![] }
}
}
impl Step for Std {
type Output = ();
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.crate_or_deps("sysroot").path("library")
}
fn make_run(run: RunConfig<'_>) {
let crates = run.make_run_crates(Alias::Library);
run.builder.ensure(Std { target: run.target, crates });
}
fn run(self, builder: &Builder<'_>) {
builder.update_submodule(&Path::new("library").join("stdarch"));
let target = self.target;
let compiler = builder.compiler(builder.top_stage, builder.config.build);
let mut cargo = builder::Cargo::new(
builder,
compiler,
Mode::Std,
SourceType::InTree,
target,
cargo_subcommand(builder.kind),
);
std_cargo(builder, target, compiler.stage, &mut cargo);
if matches!(builder.config.cmd, Subcommand::Fix { .. }) {
cargo.arg("--lib");
}
for krate in &*self.crates {
cargo.arg("-p").arg(krate);
}
let _guard = builder.msg_check(
format_args!("library artifacts{}", crate_description(&self.crates)),
target,
);
run_cargo(
builder,
cargo,
builder.config.free_args.clone(),
&libstd_stamp(builder, compiler, target),
vec![],
true,
false,
);
if compiler.stage == 0 {
let libdir = builder.sysroot_libdir(compiler, target);
let hostdir = builder.sysroot_libdir(compiler, compiler.host);
add_to_sysroot(builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
}
drop(_guard);
if builder.kind == Kind::Clippy || !self.crates.iter().any(|krate| krate == "test") {
return;
}
let mut cargo = builder::Cargo::new(
builder,
compiler,
Mode::Std,
SourceType::InTree,
target,
cargo_subcommand(builder.kind),
);
if compiler.stage == 0 {
cargo.arg("--all-targets");
}
std_cargo(builder, target, compiler.stage, &mut cargo);
for krate in &*self.crates {
cargo.arg("-p").arg(krate);
}
let _guard = builder.msg_check("library test/bench/example targets", target);
run_cargo(
builder,
cargo,
builder.config.free_args.clone(),
&libstd_test_stamp(builder, compiler, target),
vec![],
true,
false,
);
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Rustc {
pub target: TargetSelection,
crates: Vec<String>,
}
impl Rustc {
pub fn new(target: TargetSelection, builder: &Builder<'_>) -> Self {
let crates = builder
.in_tree_crates("rustc-main", Some(target))
.into_iter()
.map(|krate| krate.name.to_string())
.collect();
Self { target, crates }
}
}
impl Step for Rustc {
type Output = ();
const ONLY_HOSTS: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.crate_or_deps("rustc-main").path("compiler")
}
fn make_run(run: RunConfig<'_>) {
let crates = run.make_run_crates(Alias::Compiler);
run.builder.ensure(Rustc { target: run.target, crates });
}
fn run(self, builder: &Builder<'_>) {
let compiler = builder.compiler(builder.top_stage, builder.config.build);
let target = self.target;
if compiler.stage != 0 {
builder.ensure(crate::core::build_steps::compile::Std::new(compiler, compiler.host));
builder.ensure(crate::core::build_steps::compile::Std::new(compiler, target));
} else {
builder.ensure(Std::new(target));
}
let mut cargo = builder::Cargo::new(
builder,
compiler,
Mode::Rustc,
SourceType::InTree,
target,
cargo_subcommand(builder.kind),
);
rustc_cargo(builder, &mut cargo, target, &compiler);
if builder.kind != Kind::Clippy {
cargo.arg("--all-targets");
}
for krate in &*self.crates {
cargo.arg("-p").arg(krate);
}
let _guard = builder.msg_check(
format_args!("compiler artifacts{}", crate_description(&self.crates)),
target,
);
run_cargo(
builder,
cargo,
builder.config.free_args.clone(),
&librustc_stamp(builder, compiler, target),
vec![],
true,
false,
);
let libdir = builder.sysroot_libdir(compiler, target);
let hostdir = builder.sysroot_libdir(compiler, compiler.host);
add_to_sysroot(builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target));
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CodegenBackend {
pub target: TargetSelection,
pub backend: &'static str,
}
impl Step for CodegenBackend {
type Output = ();
const ONLY_HOSTS: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.paths(&["compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc"])
}
fn make_run(run: RunConfig<'_>) {
for &backend in &["cranelift", "gcc"] {
run.builder.ensure(CodegenBackend { target: run.target, backend });
}
}
fn run(self, builder: &Builder<'_>) {
if builder.build.config.vendor && self.backend == "gcc" {
println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled.");
return;
}
let compiler = builder.compiler(builder.top_stage, builder.config.build);
let target = self.target;
let backend = self.backend;
builder.ensure(Rustc::new(target, builder));
let mut cargo = builder::Cargo::new(
builder,
compiler,
Mode::Codegen,
SourceType::InTree,
target,
cargo_subcommand(builder.kind),
);
cargo
.arg("--manifest-path")
.arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));
rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
let _guard = builder.msg_check(backend, target);
run_cargo(
builder,
cargo,
builder.config.free_args.clone(),
&codegen_backend_stamp(builder, compiler, target, backend),
vec![],
true,
false,
);
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct RustAnalyzer {
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()
.map_or(true, |tools| tools.iter().any(|tool| tool == "rust-analyzer")),
)
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(RustAnalyzer { target: run.target });
}
fn run(self, builder: &Builder<'_>) {
let compiler = builder.compiler(builder.top_stage, builder.config.build);
let target = self.target;
builder.ensure(Rustc::new(target, builder));
let mut cargo = prepare_tool_cargo(
builder,
compiler,
Mode::ToolRustc,
target,
cargo_subcommand(builder.kind),
"src/tools/rust-analyzer",
SourceType::InTree,
&["in-rust-tree".to_owned()],
);
cargo.allow_features(crate::core::build_steps::tool::RustAnalyzer::ALLOW_FEATURES);
if builder.kind != Kind::Clippy {
cargo.arg("--bins");
cargo.arg("--tests");
cargo.arg("--benches");
}
let _guard = builder.msg_check("rust-analyzer artifacts", target);
run_cargo(
builder,
cargo,
builder.config.free_args.clone(),
&stamp(builder, compiler, target),
vec![],
true,
false,
);
fn stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
builder.cargo_out(compiler, Mode::ToolRustc, target).join(".rust-analyzer-check.stamp")
}
}
}
macro_rules! tool_check_step {
($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct $name {
pub target: TargetSelection,
}
impl Step for $name {
type Output = ();
const ONLY_HOSTS: bool = true;
const DEFAULT: bool = matches!($source_type, SourceType::InTree) $( && $default )?;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.paths(&[ $path, $($alias),* ])
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure($name { target: run.target });
}
fn run(self, builder: &Builder<'_>) {
let compiler = builder.compiler(builder.top_stage, builder.config.build);
let target = self.target;
builder.ensure(Rustc::new(target, builder));
let mut cargo = prepare_tool_cargo(
builder,
compiler,
Mode::ToolRustc,
target,
cargo_subcommand(builder.kind),
$path,
$source_type,
&[],
);
if builder.kind != Kind::Clippy {
cargo.arg("--all-targets");
}
let _guard = builder.msg_check(&concat!(stringify!($name), " artifacts").to_lowercase(), target);
run_cargo(
builder,
cargo,
builder.config.free_args.clone(),
&stamp(builder, compiler, target),
vec![],
true,
false,
);
fn stamp(
builder: &Builder<'_>,
compiler: Compiler,
target: TargetSelection,
) -> PathBuf {
builder
.cargo_out(compiler, Mode::ToolRustc, target)
.join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
}
}
}
};
}
tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree);
tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
tool_check_step!(Miri, "src/tools/miri", SourceType::InTree);
tool_check_step!(CargoMiri, "src/tools/miri/cargo-miri", SourceType::InTree);
tool_check_step!(Rls, "src/tools/rls", SourceType::InTree);
tool_check_step!(Rustfmt, "src/tools/rustfmt", SourceType::InTree);
tool_check_step!(MiroptTestTools, "src/tools/miropt-test-tools", SourceType::InTree);
tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false);
fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
}
fn libstd_test_stamp(
builder: &Builder<'_>,
compiler: Compiler,
target: TargetSelection,
) -> PathBuf {
builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp")
}
fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
}
fn codegen_backend_stamp(
builder: &Builder<'_>,
compiler: Compiler,
target: TargetSelection,
backend: &str,
) -> PathBuf {
builder
.cargo_out(compiler, Mode::Codegen, target)
.join(format!(".librustc_codegen_{backend}-check.stamp"))
}