Files
rust/src/bootstrap/check.rs

365 lines
12 KiB
Rust
Raw Normal View History

2018-12-04 19:26:54 +01:00
//! Implementation of compiling the compiler and standard library, in "check"-based modes.
2020-10-10 00:47:15 -04:00
use crate::builder::{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;
2018-12-07 13:21:05 +01:00
use crate::tool::{prepare_tool_cargo, SourceType};
use crate::INTERNER;
2020-09-29 20:24:14 -04:00
use crate::{Compiler, Mode, Subcommand};
use std::path::PathBuf;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Std {
pub target: TargetSelection,
}
2020-09-29 20:24:14 -04:00
/// Returns args for the subcommand itself (not for cargo)
fn args(builder: &Builder<'_>) -> Vec<String> {
fn strings<'a>(arr: &'a [&str]) -> impl Iterator<Item = String> + 'a {
arr.iter().copied().map(String::from)
}
2020-09-29 20:24:14 -04:00
if let Subcommand::Clippy { fix, .. } = builder.config.cmd {
let mut args = vec![];
2020-09-29 20:24:14 -04:00
if fix {
#[rustfmt::skip]
args.extend(strings(&[
"--fix", "-Zunstable-options",
// FIXME: currently, `--fix` gives an error while checking tests for libtest,
// possibly because libtest is not yet built in the sysroot.
// As a workaround, avoid checking tests and benches when passed --fix.
"--lib", "--bins", "--examples",
]));
2020-09-29 20:24:14 -04:00
}
args.extend(strings(&["--", "--cap-lints", "warn"]));
2020-09-29 20:24:14 -04:00
args
} else {
vec![]
2018-12-04 19:26:54 +01:00
}
}
fn cargo_subcommand(kind: Kind) -> &'static str {
match kind {
Kind::Check => "check",
Kind::Clippy => "clippy",
Kind::Fix => "fix",
2019-12-22 17:42:04 -05:00
_ => unreachable!(),
2018-12-04 19:26:54 +01:00
}
}
impl Step for Std {
type Output = ();
const DEFAULT: bool = true;
2019-02-25 19:30:32 +09:00
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2019-08-28 00:32:21 +09:00
run.all_krates("test")
}
2019-02-25 19:30:32 +09:00
fn make_run(run: RunConfig<'_>) {
2019-12-22 17:42:04 -05:00
run.builder.ensure(Std { target: run.target });
}
2019-02-25 19:30:32 +09:00
fn run(self, builder: &Builder<'_>) {
let target = self.target;
let compiler = builder.compiler(0, 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);
builder.info(&format!("Checking std artifacts ({} -> {})", &compiler.host, target));
2019-12-22 17:42:04 -05:00
run_cargo(
builder,
cargo,
2020-09-29 20:24:14 -04:00
args(builder),
2019-12-22 17:42:04 -05:00
&libstd_stamp(builder, compiler, target),
vec![],
true,
);
let libdir = builder.sysroot_libdir(compiler, target);
2018-12-02 21:47:41 +01:00
let hostdir = builder.sysroot_libdir(compiler, compiler.host);
add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
// Then run cargo again, once we've put the rmeta files for the library
// crates into the sysroot. This is needed because e.g., core's tests
// depend on `libtest` -- Cargo presumes it will exist, but it doesn't
// since we initialize with an empty sysroot.
//
// Currently only the "libtest" tree of crates does this.
if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
let mut cargo = builder.cargo(
compiler,
Mode::Std,
SourceType::InTree,
target,
cargo_subcommand(builder.kind),
);
std_cargo(builder, target, compiler.stage, &mut cargo);
cargo.arg("--all-targets");
// Explicitly pass -p for all dependencies krates -- this will force cargo
// to also check the tests/benches/examples for these crates, rather
// than just the leaf crate.
for krate in builder.in_tree_crates("test", Some(target)) {
cargo.arg("-p").arg(krate.name);
}
builder.info(&format!(
"Checking std test/bench/example targets ({} -> {})",
&compiler.host, target
));
run_cargo(
builder,
cargo,
2020-09-29 20:24:14 -04:00
args(builder),
&libstd_test_stamp(builder, compiler, target),
vec![],
true,
);
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustc {
pub target: TargetSelection,
}
impl Step for Rustc {
type Output = ();
const ONLY_HOSTS: bool = true;
const DEFAULT: bool = true;
2019-02-25 19:30:32 +09:00
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2018-02-11 09:51:58 -07:00
run.all_krates("rustc-main")
}
2019-02-25 19:30:32 +09:00
fn make_run(run: RunConfig<'_>) {
2019-12-22 17:42:04 -05:00
run.builder.ensure(Rustc { target: run.target });
}
2019-02-08 14:53:55 +01:00
/// Builds the compiler.
///
/// This will build the compiler for a particular stage of the build using
/// the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
2019-02-25 19:30:32 +09:00
fn run(self, builder: &Builder<'_>) {
let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
bootstrap: Merge the libtest build step with libstd Since its inception rustbuild has always worked in three stages: one for libstd, one for libtest, and one for rustc. These three stages were architected around crates.io dependencies, where rustc wants to depend on crates.io crates but said crates don't explicitly depend on libstd, requiring a sysroot assembly step in the middle. This same logic was applied for libtest where libtest wants to depend on crates.io crates (`getopts`) but `getopts` didn't say that it depended on std, so it needed `std` built ahead of time. Lots of time has passed since the inception of rustbuild, however, and we've since gotten to the point where even `std` itself is depending on crates.io crates (albeit with some wonky configuration). This commit applies the same logic to the two dependencies that the `test` crate pulls in from crates.io, `getopts` and `unicode-width`. Over the many years since rustbuild's inception `unicode-width` was the only dependency picked up by the `test` crate, so the extra configuration necessary to get crates building in this crate graph is unlikely to be too much of a burden on developers. After this patch it means that there are now only two build phasese of rustbuild, one for libstd and one for rustc. The libtest/libproc_macro build phase is all lumped into one now with `std`. This was originally motivated by rust-lang/cargo#7216 where Cargo was having to deal with synthesizing dependency edges but this commit makes them explicit in this repository.
2019-08-16 08:29:08 -07:00
builder.ensure(Std { target });
2018-08-02 12:01:04 -06:00
let mut cargo = builder.cargo(
compiler,
Mode::Rustc,
SourceType::InTree,
target,
cargo_subcommand(builder.kind),
);
rustc: Link LLVM directly into rustc again This commit builds on #65501 continue to simplify the build system and compiler now that we no longer have multiple LLVM backends to ship by default. Here this switches the compiler back to what it once was long long ago, which is linking LLVM directly to the compiler rather than dynamically loading it at runtime. The `codegen-backends` directory of the sysroot no longer exists and all relevant support in the build system is removed. Note that `rustc` still supports a dynamically loaded codegen backend as it did previously, it just no longer supports dynamically loaded codegen backends in its own sysroot. Additionally as part of this the `librustc_codegen_llvm` crate now once again explicitly depends on all of its crates instead of implicitly loading them through the sysroot. This involved filling out its `Cargo.toml` and deleting all the now-unnecessary `extern crate` annotations in the header of the crate. (this in turn required adding a number of imports for names of macros too). The end results of this change are: * Rustbuild's build process for the compiler as all the "oh don't forget the codegen backend" checks can be easily removed. * Building `rustc_codegen_llvm` is much simpler since it's simply another compiler crate. * Managing the dependencies of `rustc_codegen_llvm` is much simpler since it's "just another `Cargo.toml` to edit" * The build process should be a smidge faster because there's more parallelism in the main rustc build step rather than splitting `librustc_codegen_llvm` out to its own step. * The compiler is expected to be slightly faster by default because the codegen backend does not need to be dynamically loaded. * Disabling LLVM as part of rustbuild is still supported, supporting multiple codegen backends is still supported, and dynamic loading of a codegen backend is still supported.
2019-10-22 08:51:35 -07:00
rustc_cargo(builder, &mut cargo, target);
if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
cargo.arg("--all-targets");
}
// Explicitly pass -p for all compiler krates -- this will force cargo
// to also check the tests/benches/examples for these crates, rather
// than just the leaf crate.
for krate in builder.in_tree_crates("rustc-main", Some(target)) {
cargo.arg("-p").arg(krate.name);
}
builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target));
2019-12-22 17:42:04 -05:00
run_cargo(
builder,
cargo,
2020-09-29 20:24:14 -04:00
args(builder),
2019-12-22 17:42:04 -05:00
&librustc_stamp(builder, compiler, target),
vec![],
true,
);
let libdir = builder.sysroot_libdir(compiler, target);
2018-12-02 21:47:41 +01:00
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", "rustc_codegen_cranelift"])
}
fn make_run(run: RunConfig<'_>) {
for &backend in &[INTERNER.intern_str("cranelift")] {
run.builder.ensure(CodegenBackend { target: run.target, backend });
}
}
fn run(self, builder: &Builder<'_>) {
let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
let backend = self.backend;
builder.ensure(Rustc { target });
let mut cargo = builder.cargo(
compiler,
Mode::Codegen,
SourceType::Submodule,
target,
cargo_subcommand(builder.kind),
);
cargo
.arg("--manifest-path")
.arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
rustc_cargo_env(builder, &mut cargo, target);
run_cargo(
builder,
cargo,
2020-09-29 20:24:14 -04:00
args(builder),
&codegen_backend_stamp(builder, compiler, target, backend),
vec![],
true,
);
}
}
2020-04-01 15:57:48 +02:00
macro_rules! tool_check_step {
($name:ident, $path:expr, $source_type:expr) => {
2020-04-01 15:57:48 +02:00
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct $name {
pub target: TargetSelection,
2020-04-01 15:57:48 +02:00
}
impl Step for $name {
type Output = ();
const ONLY_HOSTS: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path($path)
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure($name { target: run.target });
}
fn run(self, builder: &Builder<'_>) {
let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
builder.ensure(Rustc { target });
let mut cargo = prepare_tool_cargo(
2020-04-01 15:57:48 +02:00
builder,
compiler,
Mode::ToolRustc,
target,
cargo_subcommand(builder.kind),
$path,
$source_type,
2020-04-01 15:57:48 +02:00
&[],
);
if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
cargo.arg("--all-targets");
}
builder.info(&format!(
2020-04-01 15:57:48 +02:00
"Checking {} artifacts ({} -> {})",
stringify!($name).to_lowercase(),
&compiler.host.triple,
target.triple
));
2020-04-01 15:57:48 +02:00
run_cargo(
builder,
cargo,
2020-09-29 20:24:14 -04:00
args(builder),
2020-04-01 15:57:48 +02:00
&stamp(builder, compiler, target),
vec![],
true,
);
let libdir = builder.sysroot_libdir(compiler, target);
let hostdir = builder.sysroot_libdir(compiler, compiler.host);
add_to_sysroot(&builder, &libdir, &hostdir, &stamp(builder, compiler, target));
/// Cargo's output path in a given stage, compiled by a particular
/// compiler for the specified target.
fn stamp(
builder: &Builder<'_>,
compiler: Compiler,
target: TargetSelection,
2020-04-01 15:57:48 +02:00
) -> PathBuf {
builder
.cargo_out(compiler, Mode::ToolRustc, target)
.join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
}
}
}
};
}
tool_check_step!(Rustdoc, "src/tools/rustdoc", SourceType::InTree);
// Clippy is a hybrid. It is an external tool, but uses 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, "src/tools/clippy", SourceType::InTree);
tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree);
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
2018-05-19 23:04:41 +03:00
builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
}
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
fn libstd_test_stamp(
builder: &Builder<'_>,
compiler: Compiler,
target: TargetSelection,
) -> PathBuf {
builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp")
}
/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
2018-05-19 23:04:41 +03:00
builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
}
/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
/// compiler for the specified target and backend.
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_{}-check.stamp", backend))
}