use crate::builder::{crate_description, Alias, Builder, Kind, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo};
use crate::config::TargetSelection;
use crate::tool::{prepare_tool_cargo, SourceType};
use crate::INTERNER;
use crate::{Compiler, Mode, Subcommand};
use std::path::{Path, PathBuf};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Std {
pub target: TargetSelection,
crates: Interned<Vec<String>>,
}
fn args(builder: &Builder<'_>) -> Vec<String> {
fn strings<'a>(arr: &'a [&str]) -> impl Iterator<Item = String> + 'a {
arr.iter().copied().map(String::from)
}
if let Subcommand::Clippy { fix, allow, deny, warn, forbid, .. } = &builder.config.cmd {
let ignored_lints = vec![
"many_single_char_names", "collapsible_if",
"type_complexity",
"missing_safety_doc", "too_many_arguments",
"needless_lifetimes", "wrong_self_convention",
];
let mut args = vec![];
if *fix {
#[rustfmt::skip]
args.extend(strings(&[
"--fix", "-Zunstable-options",
"--lib", "--bins", "--examples",
]));
}
args.extend(strings(&["--", "--cap-lints", "warn"]));
args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint)));
let mut clippy_lint_levels: Vec<String> = Vec::new();
allow.iter().for_each(|v| clippy_lint_levels.push(format!("-A{}", v)));
deny.iter().for_each(|v| clippy_lint_levels.push(format!("-D{}", v)));
warn.iter().for_each(|v| clippy_lint_levels.push(format!("-W{}", v)));
forbid.iter().for_each(|v| clippy_lint_levels.push(format!("-F{}", v)));
args.extend(clippy_lint_levels);
args.extend(builder.config.free_args.clone());
args
} else {
builder.config.free_args.clone()
}
}
fn cargo_subcommand(kind: Kind) -> &'static str {
match kind {
Kind::Check => "check",
Kind::Clippy => "clippy",
Kind::Fix => "fix",
_ => unreachable!(),
}
}
impl Std {
pub fn new(target: TargetSelection) -> Self {
Self { target, crates: INTERNER.intern_list(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(
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,
args(builder),
&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(
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,
args(builder),
&libstd_test_stamp(builder, compiler, target),
vec![],
true,
false,
);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustc {
pub target: TargetSelection,
crates: Interned<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: INTERNER.intern_list(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::compile::Std::new(compiler, compiler.host));
builder.ensure(crate::compile::Std::new(compiler, target));
} else {
builder.ensure(Std::new(target));
}
let mut cargo = builder.cargo(
compiler,
Mode::Rustc,
SourceType::InTree,
target,
cargo_subcommand(builder.kind),
);
rustc_cargo(builder, &mut cargo, target, compiler.stage);
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,
args(builder),
&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, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CodegenBackend {
pub target: TargetSelection,
pub backend: Interned<String>,
}
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 &[INTERNER.intern_str("cranelift"), INTERNER.intern_str("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(
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,
args(builder),
&codegen_backend_stamp(builder, compiler, target, backend),
vec![],
true,
false,
);
}
}
#[derive(Debug, Copy, 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(Std::new(target));
let mut cargo = prepare_tool_cargo(
builder,
compiler,
Mode::ToolStd,
target,
cargo_subcommand(builder.kind),
"src/tools/rust-analyzer",
SourceType::InTree,
&["rust-analyzer/in-rust-tree".to_owned()],
);
cargo.allow_features(crate::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,
args(builder),
&stamp(builder, compiler, target),
vec![],
true,
false,
);
fn stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
builder.cargo_out(compiler, Mode::ToolStd, target).join(".rust-analyzer-check.stamp")
}
}
}
macro_rules! tool_check_step {
($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => {
#[derive(Debug, Copy, 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");
}
cargo.rustflag("-Zunstable-options");
let _guard = builder.msg_check(&concat!(stringify!($name), " artifacts").to_lowercase(), target);
run_cargo(
builder,
cargo,
args(builder),
&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: Interned<String>,
) -> PathBuf {
builder
.cargo_out(compiler, Mode::Codegen, target)
.join(format!(".librustc_codegen_{backend}-check.stamp"))
}