Only check std in cross-compilation instead of building it
This commit is contained in:
parent
ddf39cabf2
commit
814b8e682c
3 changed files with 153 additions and 57 deletions
|
|
@ -1,7 +1,7 @@
|
|||
//! Implementation of compiling the compiler and standard library, in "check"-based modes.
|
||||
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::core::build_steps::compile::{
|
||||
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
|
||||
|
|
@ -36,7 +36,7 @@ impl Std {
|
|||
}
|
||||
|
||||
impl Step for Std {
|
||||
type Output = ();
|
||||
type Output = BuildStamp;
|
||||
const DEFAULT: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
|
|
@ -70,7 +70,7 @@ impl Step for Std {
|
|||
});
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
fn run(self, builder: &Builder<'_>) -> Self::Output {
|
||||
let build_compiler = self.build_compiler;
|
||||
let target = self.target;
|
||||
|
||||
|
|
@ -101,14 +101,23 @@ impl Step for Std {
|
|||
target,
|
||||
);
|
||||
|
||||
let stamp = build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check");
|
||||
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
|
||||
let check_stamp =
|
||||
build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check");
|
||||
run_cargo(
|
||||
builder,
|
||||
cargo,
|
||||
builder.config.free_args.clone(),
|
||||
&check_stamp,
|
||||
vec![],
|
||||
true,
|
||||
false,
|
||||
);
|
||||
|
||||
drop(_guard);
|
||||
|
||||
// don't check test dependencies if we haven't built libtest
|
||||
if !self.crates.iter().any(|krate| krate == "test") {
|
||||
return;
|
||||
return check_stamp;
|
||||
}
|
||||
|
||||
// Then run cargo again, once we've put the rmeta files for the library
|
||||
|
|
@ -145,6 +154,7 @@ impl Step for Std {
|
|||
target,
|
||||
);
|
||||
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
|
||||
check_stamp
|
||||
}
|
||||
|
||||
fn metadata(&self) -> Option<StepMetadata> {
|
||||
|
|
@ -156,12 +166,28 @@ impl Step for Std {
|
|||
/// Contains directories with .rmeta files generated by checking rustc for a specific
|
||||
/// target.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
struct RustcRmetaSysroot {
|
||||
struct RmetaSysroot {
|
||||
host_dir: PathBuf,
|
||||
target_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl RustcRmetaSysroot {
|
||||
impl RmetaSysroot {
|
||||
/// Copy rmeta artifacts from the given `stamp` into a sysroot located at `directory`.
|
||||
fn from_stamp(
|
||||
builder: &Builder<'_>,
|
||||
stamp: BuildStamp,
|
||||
target: TargetSelection,
|
||||
directory: &Path,
|
||||
) -> Self {
|
||||
let host_dir = directory.join("host");
|
||||
let target_dir = directory.join(target);
|
||||
let _ = fs::remove_dir_all(directory);
|
||||
t!(fs::create_dir_all(directory));
|
||||
add_to_sysroot(builder, &target_dir, &host_dir, &stamp);
|
||||
|
||||
Self { host_dir, target_dir }
|
||||
}
|
||||
|
||||
/// Configure the given cargo invocation so that the compiled crate will be able to use
|
||||
/// rustc .rmeta artifacts that were previously generated.
|
||||
fn configure_cargo(&self, cargo: &mut Cargo) {
|
||||
|
|
@ -180,12 +206,18 @@ impl RustcRmetaSysroot {
|
|||
/// "pollute" it (that is especially problematic for the external stage0 rustc).
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
struct PrepareRustcRmetaSysroot {
|
||||
build_compiler: Compiler,
|
||||
build_compiler: CompilerForCheck,
|
||||
target: TargetSelection,
|
||||
}
|
||||
|
||||
impl PrepareRustcRmetaSysroot {
|
||||
fn new(build_compiler: CompilerForCheck, target: TargetSelection) -> Self {
|
||||
Self { build_compiler, target }
|
||||
}
|
||||
}
|
||||
|
||||
impl Step for PrepareRustcRmetaSysroot {
|
||||
type Output = RustcRmetaSysroot;
|
||||
type Output = RmetaSysroot;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.never()
|
||||
|
|
@ -193,21 +225,63 @@ impl Step for PrepareRustcRmetaSysroot {
|
|||
|
||||
fn run(self, builder: &Builder<'_>) -> Self::Output {
|
||||
// Check rustc
|
||||
let stamp =
|
||||
builder.ensure(Rustc::from_build_compiler(self.build_compiler, self.target, vec![]));
|
||||
let stamp = builder.ensure(Rustc::from_build_compiler(
|
||||
self.build_compiler.clone(),
|
||||
self.target,
|
||||
vec![],
|
||||
));
|
||||
|
||||
let build_compiler = self.build_compiler.build_compiler();
|
||||
|
||||
// Copy the generated rmeta artifacts to a separate directory
|
||||
let dir = builder
|
||||
.out
|
||||
.join(build_compiler.host)
|
||||
.join(format!("stage{}-rustc-rmeta-artifacts", build_compiler.stage + 1));
|
||||
RmetaSysroot::from_stamp(builder, stamp, self.target, &dir)
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks std using the given `build_compiler` for the given `target`, and produces
|
||||
/// a sysroot in the build directory that stores the generated .rmeta files.
|
||||
///
|
||||
/// This step exists so that we can store the generated .rmeta artifacts into a separate
|
||||
/// directory, instead of copying them into the sysroot of `build_compiler`, which would
|
||||
/// "pollute" it (that is especially problematic for the external stage0 rustc).
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
struct PrepareStdRmetaSysroot {
|
||||
build_compiler: Compiler,
|
||||
target: TargetSelection,
|
||||
}
|
||||
|
||||
impl PrepareStdRmetaSysroot {
|
||||
fn new(build_compiler: Compiler, target: TargetSelection) -> Self {
|
||||
Self { build_compiler, target }
|
||||
}
|
||||
}
|
||||
|
||||
impl Step for PrepareStdRmetaSysroot {
|
||||
type Output = RmetaSysroot;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.never()
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) -> Self::Output {
|
||||
// Check std
|
||||
let stamp = builder.ensure(Std {
|
||||
build_compiler: self.build_compiler,
|
||||
target: self.target,
|
||||
crates: vec![],
|
||||
});
|
||||
|
||||
// Copy the generated rmeta artifacts to a separate directory
|
||||
let dir = builder
|
||||
.out
|
||||
.join(self.build_compiler.host)
|
||||
.join(format!("stage{}-rustc-check-artifacts", self.build_compiler.stage + 1));
|
||||
let host_dir = dir.join("host");
|
||||
let target_dir = dir.join(self.target);
|
||||
let _ = fs::remove_dir_all(&dir);
|
||||
t!(fs::create_dir_all(&dir));
|
||||
add_to_sysroot(builder, &target_dir, &host_dir, &stamp);
|
||||
.join(format!("stage{}-std-rmeta-artifacts", self.build_compiler.stage));
|
||||
|
||||
RustcRmetaSysroot { host_dir, target_dir }
|
||||
RmetaSysroot::from_stamp(builder, stamp, self.target, &dir)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -215,7 +289,7 @@ impl Step for PrepareRustcRmetaSysroot {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Rustc {
|
||||
/// Compiler that will check this rustc.
|
||||
pub build_compiler: Compiler,
|
||||
pub build_compiler: CompilerForCheck,
|
||||
pub target: TargetSelection,
|
||||
/// Whether to build only a subset of crates.
|
||||
///
|
||||
|
|
@ -227,13 +301,12 @@ pub struct Rustc {
|
|||
|
||||
impl Rustc {
|
||||
pub fn new(builder: &Builder<'_>, target: TargetSelection, crates: Vec<String>) -> Self {
|
||||
let build_compiler =
|
||||
prepare_compiler_for_check(builder, target, Mode::Rustc).build_compiler;
|
||||
let build_compiler = prepare_compiler_for_check(builder, target, Mode::Rustc);
|
||||
Self::from_build_compiler(build_compiler, target, crates)
|
||||
}
|
||||
|
||||
fn from_build_compiler(
|
||||
build_compiler: Compiler,
|
||||
build_compiler: CompilerForCheck,
|
||||
target: TargetSelection,
|
||||
crates: Vec<String>,
|
||||
) -> Self {
|
||||
|
|
@ -263,7 +336,7 @@ impl Step for Rustc {
|
|||
///
|
||||
/// If we check a stage 2 compiler, we will have to first build a stage 1 compiler to check it.
|
||||
fn run(self, builder: &Builder<'_>) -> Self::Output {
|
||||
let build_compiler = self.build_compiler;
|
||||
let build_compiler = self.build_compiler.build_compiler;
|
||||
let target = self.target;
|
||||
|
||||
let mut cargo = builder::Cargo::new(
|
||||
|
|
@ -276,6 +349,7 @@ impl Step for Rustc {
|
|||
);
|
||||
|
||||
rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
|
||||
self.build_compiler.configure_cargo(&mut cargo);
|
||||
|
||||
// Explicitly pass -p for all compiler crates -- this will force cargo
|
||||
// to also check the tests/benches/examples for these crates, rather
|
||||
|
|
@ -288,7 +362,7 @@ impl Step for Rustc {
|
|||
Kind::Check,
|
||||
format_args!("compiler artifacts{}", crate_description(&self.crates)),
|
||||
Mode::Rustc,
|
||||
self.build_compiler,
|
||||
self.build_compiler.build_compiler(),
|
||||
target,
|
||||
);
|
||||
|
||||
|
|
@ -301,7 +375,8 @@ impl Step for Rustc {
|
|||
}
|
||||
|
||||
fn metadata(&self) -> Option<StepMetadata> {
|
||||
let metadata = StepMetadata::check("rustc", self.target).built_by(self.build_compiler);
|
||||
let metadata = StepMetadata::check("rustc", self.target)
|
||||
.built_by(self.build_compiler.build_compiler());
|
||||
let metadata = if self.crates.is_empty() {
|
||||
metadata
|
||||
} else {
|
||||
|
|
@ -322,7 +397,8 @@ impl Step for Rustc {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct CompilerForCheck {
|
||||
build_compiler: Compiler,
|
||||
rustc_rmeta_sysroot: Option<RustcRmetaSysroot>,
|
||||
rustc_rmeta_sysroot: Option<RmetaSysroot>,
|
||||
std_rmeta_sysroot: Option<RmetaSysroot>,
|
||||
}
|
||||
|
||||
impl CompilerForCheck {
|
||||
|
|
@ -336,6 +412,30 @@ impl CompilerForCheck {
|
|||
if let Some(sysroot) = &self.rustc_rmeta_sysroot {
|
||||
sysroot.configure_cargo(cargo);
|
||||
}
|
||||
if let Some(sysroot) = &self.std_rmeta_sysroot {
|
||||
sysroot.configure_cargo(cargo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepare the standard library for checking something (that requires stdlib) using
|
||||
/// `build_compiler`.
|
||||
fn prepare_std(
|
||||
builder: &Builder<'_>,
|
||||
build_compiler: Compiler,
|
||||
target: TargetSelection,
|
||||
) -> Option<RmetaSysroot> {
|
||||
// We need to build the host stdlib even if we only check, to compile build scripts and proc
|
||||
// macros
|
||||
builder.std(build_compiler, builder.host_target);
|
||||
|
||||
// If we're cross-compiling, we generate the rmeta files for the given target
|
||||
// This check has to be here, because if we generate both .so and .rmeta files, rustc will fail,
|
||||
// as it will have multiple candidates for linking.
|
||||
if builder.host_target != target {
|
||||
Some(builder.ensure(PrepareStdRmetaSysroot::new(build_compiler, target)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -347,9 +447,13 @@ pub fn prepare_compiler_for_check(
|
|||
) -> CompilerForCheck {
|
||||
let host = builder.host_target;
|
||||
|
||||
let mut rmeta_sysroot = None;
|
||||
let mut rustc_rmeta_sysroot = None;
|
||||
let mut std_rmeta_sysroot = None;
|
||||
let build_compiler = match mode {
|
||||
Mode::ToolBootstrap => builder.compiler(0, host),
|
||||
// We could also only check std here and use `prepare_std`, but `ToolTarget` is currently
|
||||
// only used for running in-tree Clippy on bootstrap tools, so it does not seem worth it to
|
||||
// optimize it. Therefore, here we build std for the target, instead of just checking it.
|
||||
Mode::ToolTarget => get_tool_target_compiler(builder, ToolTargetBuildMode::Build(target)),
|
||||
Mode::ToolStd => {
|
||||
if builder.config.compile_time_deps {
|
||||
|
|
@ -360,14 +464,7 @@ pub fn prepare_compiler_for_check(
|
|||
} else {
|
||||
// These tools require the local standard library to be checked
|
||||
let build_compiler = builder.compiler(builder.top_stage, host);
|
||||
|
||||
// We need to build the host stdlib to check the tool itself.
|
||||
// We need to build the target stdlib so that the tool can link to it.
|
||||
builder.std(build_compiler, host);
|
||||
// We could only check this library in theory, but `check::Std` doesn't copy rmetas
|
||||
// into `build_compiler`'s sysroot to avoid clashes with `.rlibs`, so we build it
|
||||
// instead.
|
||||
builder.std(build_compiler, target);
|
||||
std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
|
||||
build_compiler
|
||||
}
|
||||
}
|
||||
|
|
@ -376,11 +473,14 @@ pub fn prepare_compiler_for_check(
|
|||
// return the build compiler that was used to check rustc.
|
||||
// We do not need to check examples/tests/etc. of Rustc for rustc_private, so we pass
|
||||
// an empty set of crates, which will avoid using `cargo -p`.
|
||||
let check = Rustc::new(builder, target, vec![]);
|
||||
let build_compiler = check.build_compiler;
|
||||
builder.ensure(check);
|
||||
rmeta_sysroot =
|
||||
Some(builder.ensure(PrepareRustcRmetaSysroot { build_compiler, target }));
|
||||
let compiler_for_rustc = prepare_compiler_for_check(builder, target, Mode::Rustc);
|
||||
rustc_rmeta_sysroot = Some(
|
||||
builder.ensure(PrepareRustcRmetaSysroot::new(compiler_for_rustc.clone(), target)),
|
||||
);
|
||||
let build_compiler = compiler_for_rustc.build_compiler();
|
||||
|
||||
// To check a rustc_private tool, we also need to check std that it will link to
|
||||
std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
|
||||
build_compiler
|
||||
}
|
||||
Mode::Rustc => {
|
||||
|
|
@ -394,15 +494,8 @@ pub fn prepare_compiler_for_check(
|
|||
let stage = if host == target { builder.top_stage - 1 } else { builder.top_stage };
|
||||
let build_compiler = builder.compiler(stage, host);
|
||||
|
||||
// Build host std for compiling build scripts
|
||||
builder.std(build_compiler, build_compiler.host);
|
||||
|
||||
// Build target std so that the checked rustc can link to it during the check
|
||||
// FIXME: maybe we can a way to only do a check of std here?
|
||||
// But for that we would have to copy the stdlib rmetas to the sysroot of the build
|
||||
// compiler, which conflicts with std rlibs, if we also build std.
|
||||
builder.std(build_compiler, target);
|
||||
|
||||
// To check rustc, we need to check std that it will link to
|
||||
std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
|
||||
build_compiler
|
||||
}
|
||||
Mode::Std => {
|
||||
|
|
@ -412,7 +505,7 @@ pub fn prepare_compiler_for_check(
|
|||
builder.compiler(builder.top_stage, host)
|
||||
}
|
||||
};
|
||||
CompilerForCheck { build_compiler, rustc_rmeta_sysroot: rmeta_sysroot }
|
||||
CompilerForCheck { build_compiler, rustc_rmeta_sysroot, std_rmeta_sysroot }
|
||||
}
|
||||
|
||||
/// Check the Cranelift codegen backend.
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ impl Step for Std {
|
|||
/// in-tree rustc.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Rustc {
|
||||
build_compiler: Compiler,
|
||||
build_compiler: CompilerForCheck,
|
||||
target: TargetSelection,
|
||||
config: LintConfig,
|
||||
/// Whether to lint only a subset of crates.
|
||||
|
|
@ -246,8 +246,7 @@ impl Rustc {
|
|||
crates: Vec<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
build_compiler: prepare_compiler_for_check(builder, target, Mode::Rustc)
|
||||
.build_compiler(),
|
||||
build_compiler: prepare_compiler_for_check(builder, target, Mode::Rustc),
|
||||
target,
|
||||
config,
|
||||
crates,
|
||||
|
|
@ -272,7 +271,7 @@ impl Step for Rustc {
|
|||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
let build_compiler = self.build_compiler;
|
||||
let build_compiler = self.build_compiler.build_compiler();
|
||||
let target = self.target;
|
||||
|
||||
let mut cargo = builder::Cargo::new(
|
||||
|
|
@ -285,6 +284,7 @@ impl Step for Rustc {
|
|||
);
|
||||
|
||||
rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
|
||||
self.build_compiler.configure_cargo(&mut cargo);
|
||||
|
||||
// Explicitly pass -p for all compiler crates -- this will force cargo
|
||||
// to also lint the tests/benches/examples for these crates, rather
|
||||
|
|
@ -313,7 +313,10 @@ impl Step for Rustc {
|
|||
}
|
||||
|
||||
fn metadata(&self) -> Option<StepMetadata> {
|
||||
Some(StepMetadata::clippy("rustc", self.target).built_by(self.build_compiler))
|
||||
Some(
|
||||
StepMetadata::clippy("rustc", self.target)
|
||||
.built_by(self.build_compiler.build_compiler()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1569,7 +1569,7 @@ mod snapshot {
|
|||
[build] llvm <host>
|
||||
[build] rustc 0 <host> -> rustc 1 <host>
|
||||
[build] rustc 1 <host> -> std 1 <host>
|
||||
[build] rustc 1 <host> -> std 1 <target1>
|
||||
[check] rustc 1 <host> -> std 1 <target1>
|
||||
[check] rustc 1 <host> -> rustc 2 <target1> (73 crates)
|
||||
[check] rustc 1 <host> -> rustc 2 <target1>
|
||||
[check] rustc 1 <host> -> Rustdoc 2 <target1>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue