mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 06:51:58 +00:00
Allow cleaning individual crates
As a bonus, this stops special casing `clean` in `Builder`.
This commit is contained in:
parent
88c58e3c2c
commit
6d388a4ee3
@ -13,7 +13,6 @@ use std::time::{Duration, Instant};
|
||||
|
||||
use crate::cache::{Cache, Interned, INTERNER};
|
||||
use crate::config::{SplitDebuginfo, TargetSelection};
|
||||
use crate::dist;
|
||||
use crate::doc;
|
||||
use crate::flags::{Color, Subcommand};
|
||||
use crate::install;
|
||||
@ -25,6 +24,7 @@ use crate::tool::{self, SourceType};
|
||||
use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
|
||||
use crate::EXTRA_CHECK_CFGS;
|
||||
use crate::{check, compile, Crate};
|
||||
use crate::{clean, dist};
|
||||
use crate::{Build, CLang, DocTests, GitRepo, Mode};
|
||||
|
||||
pub use crate::Compiler;
|
||||
@ -96,6 +96,17 @@ impl RunConfig<'_> {
|
||||
pub fn build_triple(&self) -> TargetSelection {
|
||||
self.builder.build.build
|
||||
}
|
||||
|
||||
/// Return a `-p=x -p=y` string suitable for passing to a cargo invocation.
|
||||
pub fn cargo_crates_in_set(&self) -> Interned<Vec<String>> {
|
||||
let mut crates = Vec::new();
|
||||
for krate in &self.paths {
|
||||
let path = krate.assert_single_path();
|
||||
let crate_name = self.builder.crate_paths[&path.path];
|
||||
crates.push(format!("-p={crate_name}"));
|
||||
}
|
||||
INTERNER.intern_list(crates)
|
||||
}
|
||||
}
|
||||
|
||||
struct StepDescription {
|
||||
@ -764,8 +775,9 @@ impl<'a> Builder<'a> {
|
||||
run::GenerateCopyright,
|
||||
),
|
||||
Kind::Setup => describe!(setup::Profile),
|
||||
// These commands either don't use paths, or they're special-cased in Build::build()
|
||||
Kind::Clean | Kind::Format => vec![],
|
||||
Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std),
|
||||
// special-cased in Build::build()
|
||||
Kind::Format => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
@ -827,14 +839,12 @@ impl<'a> Builder<'a> {
|
||||
Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
|
||||
Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
|
||||
Subcommand::Run { ref paths, .. } => (Kind::Run, &paths[..]),
|
||||
Subcommand::Clean { ref paths, .. } => (Kind::Clean, &paths[..]),
|
||||
Subcommand::Format { .. } => (Kind::Format, &[][..]),
|
||||
Subcommand::Setup { profile: ref path } => (
|
||||
Kind::Setup,
|
||||
path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)),
|
||||
),
|
||||
Subcommand::Clean { .. } => {
|
||||
panic!()
|
||||
}
|
||||
};
|
||||
|
||||
Self::new_internal(build, kind, paths.to_owned())
|
||||
@ -1077,64 +1087,22 @@ impl<'a> Builder<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Prepares an invocation of `cargo` to be run.
|
||||
///
|
||||
/// This will create a `Command` that represents a pending execution of
|
||||
/// Cargo. This cargo will be configured to use `compiler` as the actual
|
||||
/// rustc compiler, its output will be scoped by `mode`'s output directory,
|
||||
/// it will pass the `--target` flag for the specified `target`, and will be
|
||||
/// executing the Cargo command `cmd`.
|
||||
pub fn cargo(
|
||||
/// Like `cargo`, but only passes flags that are valid for all commands.
|
||||
pub fn bare_cargo(
|
||||
&self,
|
||||
compiler: Compiler,
|
||||
mode: Mode,
|
||||
source_type: SourceType,
|
||||
target: TargetSelection,
|
||||
cmd: &str,
|
||||
) -> Cargo {
|
||||
) -> Command {
|
||||
let mut cargo = Command::new(&self.initial_cargo);
|
||||
let out_dir = self.stage_out(compiler, mode);
|
||||
// Run cargo from the source root so it can find .cargo/config.
|
||||
// This matters when using vendoring and the working directory is outside the repository.
|
||||
cargo.current_dir(&self.src);
|
||||
|
||||
// Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
|
||||
// so we need to explicitly clear out if they've been updated.
|
||||
for backend in self.codegen_backends(compiler) {
|
||||
self.clear_if_dirty(&out_dir, &backend);
|
||||
}
|
||||
|
||||
if cmd == "doc" || cmd == "rustdoc" {
|
||||
let my_out = match mode {
|
||||
// This is the intended out directory for compiler documentation.
|
||||
Mode::Rustc | Mode::ToolRustc => self.compiler_doc_out(target),
|
||||
Mode::Std => {
|
||||
if self.config.cmd.json() {
|
||||
out_dir.join(target.triple).join("json-doc")
|
||||
} else {
|
||||
out_dir.join(target.triple).join("doc")
|
||||
}
|
||||
}
|
||||
_ => panic!("doc mode {:?} not expected", mode),
|
||||
};
|
||||
let rustdoc = self.rustdoc(compiler);
|
||||
self.clear_if_dirty(&my_out, &rustdoc);
|
||||
}
|
||||
|
||||
let out_dir = self.stage_out(compiler, mode);
|
||||
cargo.env("CARGO_TARGET_DIR", &out_dir).arg(cmd);
|
||||
|
||||
let profile_var = |name: &str| {
|
||||
let profile = if self.config.rust_optimize { "RELEASE" } else { "DEV" };
|
||||
format!("CARGO_PROFILE_{}_{}", profile, name)
|
||||
};
|
||||
|
||||
// See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config
|
||||
// needs to not accidentally link to libLLVM in stage0/lib.
|
||||
cargo.env("REAL_LIBRARY_PATH_VAR", &util::dylib_path_var());
|
||||
if let Some(e) = env::var_os(util::dylib_path_var()) {
|
||||
cargo.env("REAL_LIBRARY_PATH", e);
|
||||
}
|
||||
|
||||
// Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger`
|
||||
// from out of tree it shouldn't matter, since x.py is only used for
|
||||
// building in-tree.
|
||||
@ -1161,6 +1129,73 @@ impl<'a> Builder<'a> {
|
||||
assert_eq!(target, compiler.host);
|
||||
}
|
||||
|
||||
if self.config.rust_optimize {
|
||||
// FIXME: cargo bench/install do not accept `--release`
|
||||
if cmd != "bench" && cmd != "install" {
|
||||
cargo.arg("--release");
|
||||
}
|
||||
}
|
||||
|
||||
// Remove make-related flags to ensure Cargo can correctly set things up
|
||||
cargo.env_remove("MAKEFLAGS");
|
||||
cargo.env_remove("MFLAGS");
|
||||
|
||||
cargo
|
||||
}
|
||||
|
||||
/// Prepares an invocation of `cargo` to be run.
|
||||
///
|
||||
/// This will create a `Command` that represents a pending execution of
|
||||
/// Cargo. This cargo will be configured to use `compiler` as the actual
|
||||
/// rustc compiler, its output will be scoped by `mode`'s output directory,
|
||||
/// it will pass the `--target` flag for the specified `target`, and will be
|
||||
/// executing the Cargo command `cmd`.
|
||||
pub fn cargo(
|
||||
&self,
|
||||
compiler: Compiler,
|
||||
mode: Mode,
|
||||
source_type: SourceType,
|
||||
target: TargetSelection,
|
||||
cmd: &str,
|
||||
) -> Cargo {
|
||||
let mut cargo = self.bare_cargo(compiler, mode, target, cmd);
|
||||
let out_dir = self.stage_out(compiler, mode);
|
||||
|
||||
// Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
|
||||
// so we need to explicitly clear out if they've been updated.
|
||||
for backend in self.codegen_backends(compiler) {
|
||||
self.clear_if_dirty(&out_dir, &backend);
|
||||
}
|
||||
|
||||
if cmd == "doc" || cmd == "rustdoc" {
|
||||
let my_out = match mode {
|
||||
// This is the intended out directory for compiler documentation.
|
||||
Mode::Rustc | Mode::ToolRustc => self.compiler_doc_out(target),
|
||||
Mode::Std => {
|
||||
if self.config.cmd.json() {
|
||||
out_dir.join(target.triple).join("json-doc")
|
||||
} else {
|
||||
out_dir.join(target.triple).join("doc")
|
||||
}
|
||||
}
|
||||
_ => panic!("doc mode {:?} not expected", mode),
|
||||
};
|
||||
let rustdoc = self.rustdoc(compiler);
|
||||
self.clear_if_dirty(&my_out, &rustdoc);
|
||||
}
|
||||
|
||||
let profile_var = |name: &str| {
|
||||
let profile = if self.config.rust_optimize { "RELEASE" } else { "DEV" };
|
||||
format!("CARGO_PROFILE_{}_{}", profile, name)
|
||||
};
|
||||
|
||||
// See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config
|
||||
// needs to not accidentally link to libLLVM in stage0/lib.
|
||||
cargo.env("REAL_LIBRARY_PATH_VAR", &util::dylib_path_var());
|
||||
if let Some(e) = env::var_os(util::dylib_path_var()) {
|
||||
cargo.env("REAL_LIBRARY_PATH", e);
|
||||
}
|
||||
|
||||
// Set a flag for `check`/`clippy`/`fix`, so that certain build
|
||||
// scripts can do less work (i.e. not building/requiring LLVM).
|
||||
if cmd == "check" || cmd == "clippy" || cmd == "fix" {
|
||||
@ -1341,9 +1376,6 @@ impl<'a> Builder<'a> {
|
||||
}
|
||||
|
||||
cargo.arg("-j").arg(self.jobs().to_string());
|
||||
// Remove make-related flags to ensure Cargo can correctly set things up
|
||||
cargo.env_remove("MAKEFLAGS");
|
||||
cargo.env_remove("MFLAGS");
|
||||
|
||||
// FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
|
||||
// Force cargo to output binaries with disambiguating hashes in the name
|
||||
@ -1827,13 +1859,6 @@ impl<'a> Builder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if self.config.rust_optimize {
|
||||
// FIXME: cargo bench/install do not accept `--release`
|
||||
if cmd != "bench" && cmd != "install" {
|
||||
cargo.arg("--release");
|
||||
}
|
||||
}
|
||||
|
||||
if self.config.locked_deps {
|
||||
cargo.arg("--locked");
|
||||
}
|
||||
|
@ -9,10 +9,83 @@ use std::fs;
|
||||
use std::io::{self, ErrorKind};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
|
||||
use crate::cache::Interned;
|
||||
use crate::config::TargetSelection;
|
||||
use crate::util::t;
|
||||
use crate::Build;
|
||||
use crate::{Build, Mode, Subcommand};
|
||||
|
||||
pub fn clean(build: &Build, all: bool) {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct CleanAll {}
|
||||
|
||||
impl Step for CleanAll {
|
||||
const DEFAULT: bool = true;
|
||||
type Output = ();
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(CleanAll {})
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) -> Self::Output {
|
||||
let Subcommand::Clean { all, .. } = builder.config.cmd else { unreachable!("wrong subcommand?") };
|
||||
clean_default(builder.build, all)
|
||||
}
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.never() // handled by DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! clean_crate_tree {
|
||||
( $( $name:ident, $mode:path, $root_crate:literal);+ $(;)? ) => { $(
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct $name {
|
||||
target: TargetSelection,
|
||||
crates: Interned<Vec<String>>,
|
||||
}
|
||||
|
||||
impl Step for $name {
|
||||
type Output = ();
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
let crates = run.builder.in_tree_crates($root_crate, None);
|
||||
run.crates(crates)
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
let builder = run.builder;
|
||||
if builder.top_stage != 0 {
|
||||
panic!("non-stage-0 clean not supported for individual crates");
|
||||
}
|
||||
builder.ensure(Self { crates: run.cargo_crates_in_set(), target: run.target });
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) -> Self::Output {
|
||||
let compiler = builder.compiler(0, self.target);
|
||||
let mut cargo = builder.bare_cargo(compiler, $mode, self.target, "clean");
|
||||
for krate in &*self.crates {
|
||||
cargo.arg(krate);
|
||||
}
|
||||
|
||||
builder.info(&format!(
|
||||
"Cleaning stage{} {} artifacts ({} -> {})",
|
||||
compiler.stage, stringify!($name).to_lowercase(), &compiler.host, self.target
|
||||
));
|
||||
|
||||
// NOTE: doesn't use `run_cargo` because we don't want to save a stamp file,
|
||||
// and doesn't use `stream_cargo` to avoid passing `--message-format` which `clean` doesn't accept.
|
||||
builder.run(&mut cargo);
|
||||
}
|
||||
}
|
||||
)+ }
|
||||
}
|
||||
|
||||
clean_crate_tree! {
|
||||
Rustc, Mode::Rustc, "rustc-main";
|
||||
Std, Mode::Std, "test";
|
||||
}
|
||||
|
||||
fn clean_default(build: &Build, all: bool) {
|
||||
rm_rf("tmp".as_ref());
|
||||
|
||||
if all {
|
||||
|
@ -46,17 +46,6 @@ impl Std {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a `-p=x -p=y` string suitable for passing to a cargo invocation.
|
||||
fn build_crates_in_set(run: &RunConfig<'_>) -> Interned<Vec<String>> {
|
||||
let mut crates = Vec::new();
|
||||
for krate in &run.paths {
|
||||
let path = krate.assert_single_path();
|
||||
let crate_name = run.builder.crate_paths[&path.path];
|
||||
crates.push(format!("-p={crate_name}"));
|
||||
}
|
||||
INTERNER.intern_list(crates)
|
||||
}
|
||||
|
||||
impl Step for Std {
|
||||
type Output = ();
|
||||
const DEFAULT: bool = true;
|
||||
@ -76,7 +65,7 @@ impl Step for Std {
|
||||
// Build all crates anyway, as if they hadn't passed the other args.
|
||||
let has_library =
|
||||
run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library"));
|
||||
let crates = if has_library { Default::default() } else { build_crates_in_set(&run) };
|
||||
let crates = if has_library { Default::default() } else { run.cargo_crates_in_set() };
|
||||
run.builder.ensure(Std {
|
||||
compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
|
||||
target: run.target,
|
||||
@ -603,7 +592,7 @@ impl Step for Rustc {
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
let crates = build_crates_in_set(&run);
|
||||
let crates = run.cargo_crates_in_set();
|
||||
run.builder.ensure(Rustc {
|
||||
compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
|
||||
target: run.target,
|
||||
|
@ -130,6 +130,7 @@ pub enum Subcommand {
|
||||
test_args: Vec<String>,
|
||||
},
|
||||
Clean {
|
||||
paths: Vec<PathBuf>,
|
||||
all: bool,
|
||||
},
|
||||
Dist {
|
||||
@ -601,14 +602,7 @@ Arguments:
|
||||
open: matches.opt_present("open"),
|
||||
json: matches.opt_present("json"),
|
||||
},
|
||||
Kind::Clean => {
|
||||
if !paths.is_empty() {
|
||||
println!("\nclean does not take a path argument\n");
|
||||
usage(1, &opts, verbose, &subcommand_help);
|
||||
}
|
||||
|
||||
Subcommand::Clean { all: matches.opt_present("all") }
|
||||
}
|
||||
Kind::Clean => Subcommand::Clean { all: matches.opt_present("all"), paths },
|
||||
Kind::Format => Subcommand::Format { check: matches.opt_present("check"), paths },
|
||||
Kind::Dist => Subcommand::Dist { paths },
|
||||
Kind::Install => Subcommand::Install { paths },
|
||||
|
@ -727,10 +727,6 @@ impl Build {
|
||||
return format::format(&builder::Builder::new(&self), *check, &paths);
|
||||
}
|
||||
|
||||
if let Subcommand::Clean { all } = self.config.cmd {
|
||||
return clean::clean(self, all);
|
||||
}
|
||||
|
||||
// Download rustfmt early so that it can be used in rust-analyzer configs.
|
||||
let _ = &builder::Builder::new(&self).initial_rustfmt();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user