1
Fork 0

Auto merge of #135281 - onur-ozkan:build-stamps, r=jieyouxu

centralize build stamp logic

This PR brings all the stamp file handling into one place inside `build_stamp` module, which takes care of everything related to build stamps. By doing this, we cut down on duplicated code and types and keep the codebase easier to maintain and more consistent.

Main goals are:

- Make stamp handling stricter so we don't have to pass `Path`s around and manually `join` on arbitrary directories
- Keep all stamp-related logic in one place
- Make it easier to test and debug
- Avoid duplication
- Keep things simple and well-documented

Resolves #134962
This commit is contained in:
bors 2025-01-12 17:28:00 +00:00
commit 627513a764
21 changed files with 434 additions and 362 deletions

View file

@ -1,7 +1,5 @@
//! Implementation of compiling the compiler and standard library, in "check"-based modes.
use std::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,
};
@ -10,7 +8,8 @@ use crate::core::builder::{
self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, crate_description,
};
use crate::core::config::TargetSelection;
use crate::{Compiler, Mode, Subcommand};
use crate::utils::build_stamp::{self, BuildStamp};
use crate::{Mode, Subcommand};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Std {
@ -83,22 +82,16 @@ impl Step for Std {
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,
);
let stamp = build_stamp::libstd_stamp(builder, compiler, target).with_prefix("check");
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
// We skip populating the sysroot in non-zero stage because that'll lead
// to rlib/rmeta conflicts if std gets built during this session.
if compiler.stage == 0 {
let libdir = builder.sysroot_target_libdir(compiler, target);
let hostdir = builder.sysroot_target_libdir(compiler, compiler.host);
add_to_sysroot(builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
add_to_sysroot(builder, &libdir, &hostdir, &stamp);
}
drop(_guard);
@ -139,16 +132,9 @@ impl Step for Std {
cargo.arg("-p").arg(krate);
}
let stamp = build_stamp::libstd_stamp(builder, compiler, target).with_prefix("check-test");
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,
);
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
}
}
@ -249,19 +235,14 @@ impl Step for Rustc {
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 stamp = build_stamp::librustc_stamp(builder, compiler, target).with_prefix("check");
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
let libdir = builder.sysroot_target_libdir(compiler, target);
let hostdir = builder.sysroot_target_libdir(compiler, compiler.host);
add_to_sysroot(builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target));
add_to_sysroot(builder, &libdir, &hostdir, &stamp);
}
}
@ -315,15 +296,10 @@ impl Step for CodegenBackend {
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,
);
let stamp = build_stamp::codegen_backend_stamp(builder, compiler, target, backend)
.with_prefix("check");
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
}
}
@ -380,22 +356,13 @@ impl Step for RustAnalyzer {
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,
);
// Cargo's output path in a given stage, compiled by a particular
// compiler for the specified target.
let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target))
.with_prefix("rust-analyzer-check");
/// 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) -> PathBuf {
builder.cargo_out(compiler, Mode::ToolRustc, target).join(".rust-analyzer-check.stamp")
}
let _guard = builder.msg_check("rust-analyzer artifacts", target);
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
}
}
@ -469,9 +436,8 @@ fn run_tool_check_step(
cargo.arg("--all-targets");
}
let stamp = builder
.cargo_out(compiler, Mode::ToolRustc, target)
.join(format!(".{}-check.stamp", step_type_name.to_lowercase()));
let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target))
.with_prefix(&format!("{}-check", step_type_name.to_lowercase()));
let _guard = builder.msg_check(format!("{display_name} artifacts"), target);
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
@ -499,38 +465,3 @@ tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", default: f
// Compiletest is implicitly "checked" when it gets built in order to run tests,
// so this is mainly for people working on compiletest to run locally.
tool_check_step!(Compiletest { path: "src/tools/compiletest", default: false });
/// 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 {
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 {
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: &str,
) -> PathBuf {
builder
.cargo_out(compiler, Mode::Codegen, target)
.join(format!(".librustc_codegen_{backend}-check.stamp"))
}

View file

@ -10,6 +10,7 @@ use std::io::{self, ErrorKind};
use std::path::Path;
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step, crate_description};
use crate::utils::build_stamp::BuildStamp;
use crate::utils::helpers::t;
use crate::{Build, Compiler, Kind, Mode, Subcommand};
@ -146,7 +147,7 @@ fn clean_default(build: &Build) {
rm_rf(&build.out.join("dist"));
rm_rf(&build.out.join("bootstrap").join(".last-warned-change-id"));
rm_rf(&build.out.join("bootstrap-shims-dump"));
rm_rf(&build.out.join("rustfmt.stamp"));
rm_rf(BuildStamp::new(&build.out).with_prefix("rustfmt").path());
let mut hosts: Vec<_> = build.hosts.iter().map(|t| build.out.join(t)).collect();
// After cross-compilation, artifacts of the host architecture (which may differ from build.host)

View file

@ -1,12 +1,13 @@
//! Implementation of running clippy on the compiler, standard library and various tools.
use super::compile::{librustc_stamp, libstd_stamp, run_cargo, rustc_cargo, std_cargo};
use super::compile::{run_cargo, rustc_cargo, std_cargo};
use super::tool::{SourceType, prepare_tool_cargo};
use super::{check, compile};
use crate::builder::{Builder, ShouldRun};
use crate::core::build_steps::compile::std_crates_for_run_make;
use crate::core::builder;
use crate::core::builder::{Alias, Kind, RunConfig, Step, crate_description};
use crate::utils::build_stamp::{self, BuildStamp};
use crate::{Mode, Subcommand, TargetSelection};
/// Disable the most spammy clippy lints
@ -167,7 +168,7 @@ impl Step for Std {
builder,
cargo,
lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC),
&libstd_stamp(builder, compiler, target),
&build_stamp::libstd_stamp(builder, compiler, target),
vec![],
true,
false,
@ -243,7 +244,7 @@ impl Step for Rustc {
builder,
cargo,
lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC),
&librustc_stamp(builder, compiler, target),
&build_stamp::librustc_stamp(builder, compiler, target),
vec![],
true,
false,
@ -307,9 +308,9 @@ macro_rules! lint_any {
&target,
);
let stamp = builder
.cargo_out(compiler, Mode::ToolRustc, target)
.join(format!(".{}-check.stamp", stringify!($name).to_lowercase()));
let stringified_name = stringify!($name).to_lowercase();
let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target))
.with_prefix(&format!("{}-check", stringified_name));
run_cargo(
builder,

View file

@ -24,6 +24,8 @@ use crate::core::builder::{
Builder, Cargo, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath, crate_description,
};
use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
use crate::utils::build_stamp;
use crate::utils::build_stamp::BuildStamp;
use crate::utils::exec::command;
use crate::utils::helpers::{
exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
@ -254,7 +256,7 @@ impl Step for Std {
builder,
cargo,
vec![],
&libstd_stamp(builder, compiler, target),
&build_stamp::libstd_stamp(builder, compiler, target),
target_deps,
self.is_for_mir_opt_tests, // is_check
false,
@ -644,7 +646,12 @@ impl Step for StdLink {
(libdir, hostdir)
};
add_to_sysroot(builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
add_to_sysroot(
builder,
&libdir,
&hostdir,
&build_stamp::libstd_stamp(builder, compiler, target),
);
// Special case for stage0, to make `rustup toolchain link` and `x dist --stage 0`
// work for stage0-sysroot. We only do this if the stage0 compiler comes from beta,
@ -973,7 +980,7 @@ impl Step for Rustc {
compiler.host,
target,
);
let stamp = librustc_stamp(builder, compiler, target);
let stamp = build_stamp::librustc_stamp(builder, compiler, target);
run_cargo(
builder,
cargo,
@ -984,7 +991,7 @@ impl Step for Rustc {
true, // Only ship rustc_driver.so and .rmeta files, not all intermediate .rlib files.
);
let target_root_dir = stamp.parent().unwrap();
let target_root_dir = stamp.path().parent().unwrap();
// When building `librustc_driver.so` (like `libLLVM.so`) on linux, it can contain
// unexpected debuginfo from dependencies, for example from the C++ standard library used in
// our LLVM wrapper. Unless we're explicitly requesting `librustc_driver` to be built with
@ -1329,7 +1336,7 @@ impl Step for RustcLink {
builder,
&builder.sysroot_target_libdir(previous_stage_compiler, target),
&builder.sysroot_target_libdir(previous_stage_compiler, compiler.host),
&librustc_stamp(builder, compiler, target),
&build_stamp::librustc_stamp(builder, compiler, target),
);
}
}
@ -1447,7 +1454,7 @@ impl Step for CodegenBackend {
.arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));
rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
let tmp_stamp = out_dir.join(".tmp.stamp");
let tmp_stamp = BuildStamp::new(&out_dir).with_prefix("tmp");
let _guard = builder.msg_build(compiler, format_args!("codegen backend {backend}"), target);
let files = run_cargo(builder, cargo, vec![], &tmp_stamp, vec![], false, false);
@ -1469,9 +1476,9 @@ impl Step for CodegenBackend {
f.display()
);
}
let stamp = codegen_backend_stamp(builder, compiler, target, &backend);
let stamp = build_stamp::codegen_backend_stamp(builder, compiler, target, &backend);
let codegen_backend = codegen_backend.to_str().unwrap();
t!(fs::write(stamp, codegen_backend));
t!(stamp.add_stamp(codegen_backend).write());
}
}
@ -1508,8 +1515,8 @@ fn copy_codegen_backends_to_sysroot(
continue; // Already built as part of rustc
}
let stamp = codegen_backend_stamp(builder, compiler, target, backend);
let dylib = t!(fs::read_to_string(&stamp));
let stamp = build_stamp::codegen_backend_stamp(builder, compiler, target, backend);
let dylib = t!(fs::read_to_string(stamp.path()));
let file = Path::new(&dylib);
let filename = file.file_name().unwrap().to_str().unwrap();
// change `librustc_codegen_cranelift-xxxxxx.so` to
@ -1523,35 +1530,6 @@ fn copy_codegen_backends_to_sysroot(
}
}
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
pub fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
builder.cargo_out(compiler, Mode::Std, target).join(".libstd.stamp")
}
/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn librustc_stamp(
builder: &Builder<'_>,
compiler: Compiler,
target: TargetSelection,
) -> PathBuf {
builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc.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: &str,
) -> PathBuf {
builder
.cargo_out(compiler, Mode::Codegen, target)
.join(format!(".librustc_codegen_{backend}.stamp"))
}
pub fn compiler_file(
builder: &Builder<'_>,
compiler: &Path,
@ -1908,7 +1886,7 @@ impl Step for Assemble {
builder.info(&msg);
// Link in all dylibs to the libdir
let stamp = librustc_stamp(builder, build_compiler, target_compiler.host);
let stamp = build_stamp::librustc_stamp(builder, build_compiler, target_compiler.host);
let proc_macros = builder
.read_stamp_file(&stamp)
.into_iter()
@ -2014,7 +1992,7 @@ pub fn add_to_sysroot(
builder: &Builder<'_>,
sysroot_dst: &Path,
sysroot_host_dst: &Path,
stamp: &Path,
stamp: &BuildStamp,
) {
let self_contained_dst = &sysroot_dst.join("self-contained");
t!(fs::create_dir_all(sysroot_dst));
@ -2034,13 +2012,13 @@ pub fn run_cargo(
builder: &Builder<'_>,
cargo: Cargo,
tail_args: Vec<String>,
stamp: &Path,
stamp: &BuildStamp,
additional_target_deps: Vec<(PathBuf, DependencyType)>,
is_check: bool,
rlib_only_metadata: bool,
) -> Vec<PathBuf> {
// `target_root_dir` looks like $dir/$target/release
let target_root_dir = stamp.parent().unwrap();
let target_root_dir = stamp.path().parent().unwrap();
// `target_deps_dir` looks like $dir/$target/release/deps
let target_deps_dir = target_root_dir.join("deps");
// `host_root_dir` looks like $dir/release
@ -2193,7 +2171,7 @@ pub fn run_cargo(
new_contents.extend(dep.to_str().unwrap().as_bytes());
new_contents.extend(b"\0");
}
t!(fs::write(stamp, &new_contents));
t!(fs::write(stamp.path(), &new_contents));
deps.into_iter().map(|(d, _)| d).collect()
}

View file

@ -23,6 +23,7 @@ use crate::core::build_steps::vendor::default_paths_to_vendor;
use crate::core::build_steps::{compile, llvm};
use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
use crate::core::config::TargetSelection;
use crate::utils::build_stamp::{self, BuildStamp};
use crate::utils::channel::{self, Info};
use crate::utils::exec::{BootstrapCommand, command};
use crate::utils::helpers::{
@ -584,7 +585,7 @@ fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
/// Check that all objects in rlibs for UEFI targets are COFF. This
/// ensures that the C compiler isn't producing ELF objects, which would
/// not link correctly with the COFF objects.
fn verify_uefi_rlib_format(builder: &Builder<'_>, target: TargetSelection, stamp: &Path) {
fn verify_uefi_rlib_format(builder: &Builder<'_>, target: TargetSelection, stamp: &BuildStamp) {
if !target.ends_with("-uefi") {
return;
}
@ -615,7 +616,12 @@ fn verify_uefi_rlib_format(builder: &Builder<'_>, target: TargetSelection, stamp
}
/// Copy stamped files into an image's `target/lib` directory.
fn copy_target_libs(builder: &Builder<'_>, target: TargetSelection, image: &Path, stamp: &Path) {
fn copy_target_libs(
builder: &Builder<'_>,
target: TargetSelection,
image: &Path,
stamp: &BuildStamp,
) {
let dst = image.join("lib/rustlib").join(target).join("lib");
let self_contained_dst = dst.join("self-contained");
t!(fs::create_dir_all(&dst));
@ -668,7 +674,7 @@ impl Step for Std {
tarball.include_target_in_component_name(true);
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
let stamp = compile::libstd_stamp(builder, compiler_to_use, target);
let stamp = build_stamp::libstd_stamp(builder, compiler_to_use, target);
verify_uefi_rlib_format(builder, target, &stamp);
copy_target_libs(builder, target, tarball.image_dir(), &stamp);
@ -718,7 +724,7 @@ impl Step for RustcDev {
let tarball = Tarball::new(builder, "rustc-dev", &target.triple);
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
let stamp = compile::librustc_stamp(builder, compiler_to_use, target);
let stamp = build_stamp::librustc_stamp(builder, compiler_to_use, target);
copy_target_libs(builder, target, tarball.image_dir(), &stamp);
let src_files = &["Cargo.lock"];

View file

@ -11,8 +11,9 @@ use build_helper::git::get_git_modified_files;
use ignore::WalkBuilder;
use crate::core::builder::Builder;
use crate::utils::build_stamp::BuildStamp;
use crate::utils::exec::command;
use crate::utils::helpers::{self, program_out_of_date, t};
use crate::utils::helpers::{self, t};
#[must_use]
enum RustfmtStatus {
@ -55,8 +56,8 @@ fn rustfmt(
}
}
fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, PathBuf)> {
let stamp_file = build.out.join("rustfmt.stamp");
fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, BuildStamp)> {
let stamp_file = BuildStamp::new(&build.out).with_prefix("rustfmt");
let mut cmd = command(build.initial_rustfmt()?);
cmd.arg("--version");
@ -73,7 +74,7 @@ fn verify_rustfmt_version(build: &Builder<'_>) -> bool {
let Some((version, stamp_file)) = get_rustfmt_version(build) else {
return false;
};
!program_out_of_date(&stamp_file, &version)
stamp_file.add_stamp(version).is_up_to_date()
}
/// Updates the last rustfmt version used.
@ -81,7 +82,7 @@ fn update_rustfmt_version(build: &Builder<'_>) {
let Some((version, stamp_file)) = get_rustfmt_version(build) else {
return;
};
t!(std::fs::write(stamp_file, version))
t!(std::fs::write(stamp_file.path(), version))
}
/// Returns the Rust files modified between the `merge-base` of HEAD and

View file

@ -12,14 +12,15 @@ use std::fs;
use std::path::PathBuf;
use std::sync::OnceLock;
use crate::Kind;
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::core::config::TargetSelection;
use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
use crate::utils::exec::command;
use crate::utils::helpers::{self, HashStamp, t};
use crate::{Kind, generate_smart_stamp_hash};
use crate::utils::helpers::{self, t};
pub struct Meta {
stamp: HashStamp,
stamp: BuildStamp,
out_dir: PathBuf,
install_dir: PathBuf,
root: PathBuf,
@ -54,18 +55,17 @@ pub fn prebuilt_gcc_config(builder: &Builder<'_>, target: TargetSelection) -> Gc
)
});
let stamp = out_dir.join("gcc-finished-building");
let stamp = HashStamp::new(stamp, Some(smart_stamp_hash));
let stamp = BuildStamp::new(&out_dir).with_prefix("gcc").add_stamp(smart_stamp_hash);
if stamp.is_done() {
if stamp.hash.is_none() {
if stamp.is_up_to_date() {
if stamp.stamp().is_empty() {
builder.info(
"Could not determine the GCC submodule commit hash. \
Assuming that an GCC rebuild is not necessary.",
);
builder.info(&format!(
"To force GCC to rebuild, remove the file `{}`",
stamp.path.display()
stamp.path().display()
));
}
return GccBuildStatus::AlreadyBuilt;

View file

@ -8,23 +8,23 @@
//! LLVM and compiler-rt are essentially just wired up to everything else to
//! ensure that they're always in place if needed.
use std::env;
use std::env::consts::EXE_EXTENSION;
use std::ffi::{OsStr, OsString};
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::sync::OnceLock;
use std::{env, fs};
use build_helper::ci::CiEnv;
use build_helper::git::get_closest_merge_commit;
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::core::config::{Config, TargetSelection};
use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
use crate::utils::exec::command;
use crate::utils::helpers::{
self, HashStamp, exe, get_clang_cl_resource_dir, t, unhashed_basename, up_to_date,
self, exe, get_clang_cl_resource_dir, t, unhashed_basename, up_to_date,
};
use crate::{CLang, GitRepo, Kind, generate_smart_stamp_hash};
use crate::{CLang, GitRepo, Kind};
#[derive(Clone)]
pub struct LlvmResult {
@ -36,7 +36,7 @@ pub struct LlvmResult {
}
pub struct Meta {
stamp: HashStamp,
stamp: BuildStamp,
res: LlvmResult,
out_dir: PathBuf,
root: String,
@ -135,18 +135,17 @@ pub fn prebuilt_llvm_config(
)
});
let stamp = out_dir.join("llvm-finished-building");
let stamp = HashStamp::new(stamp, Some(smart_stamp_hash));
let stamp = BuildStamp::new(&out_dir).with_prefix("llvm").add_stamp(smart_stamp_hash);
if stamp.is_done() {
if stamp.hash.is_none() {
if stamp.is_up_to_date() {
if stamp.stamp().is_empty() {
builder.info(
"Could not determine the LLVM submodule commit hash. \
Assuming that an LLVM rebuild is not necessary.",
);
builder.info(&format!(
"To force LLVM to rebuild, remove the file `{}`",
stamp.path.display()
stamp.path().display()
));
}
return LlvmBuildStatus::AlreadyBuilt(res);
@ -922,18 +921,17 @@ impl Step for Enzyme {
});
let out_dir = builder.enzyme_out(target);
let stamp = out_dir.join("enzyme-finished-building");
let stamp = HashStamp::new(stamp, Some(smart_stamp_hash));
let stamp = BuildStamp::new(&out_dir).with_prefix("enzyme").add_stamp(smart_stamp_hash);
if stamp.is_done() {
if stamp.hash.is_none() {
if stamp.is_up_to_date() {
if stamp.stamp().is_empty() {
builder.info(
"Could not determine the Enzyme submodule commit hash. \
Assuming that an Enzyme rebuild is not necessary.",
);
builder.info(&format!(
"To force Enzyme to rebuild, remove the file `{}`",
stamp.path.display()
stamp.path().display()
));
}
return out_dir;
@ -1016,8 +1014,9 @@ impl Step for Lld {
}
let out_dir = builder.lld_out(target);
let done_stamp = out_dir.join("lld-finished-building");
if done_stamp.exists() {
let lld_stamp = BuildStamp::new(&out_dir).with_prefix("lld");
if lld_stamp.path().exists() {
return out_dir;
}
@ -1092,7 +1091,7 @@ impl Step for Lld {
cfg.build();
t!(File::create(&done_stamp));
t!(lld_stamp.write());
out_dir
}
}
@ -1122,25 +1121,32 @@ impl Step for Sanitizers {
let out_dir = builder.native_dir(self.target).join("sanitizers");
let runtimes = supported_sanitizers(&out_dir, self.target, &builder.config.channel);
if runtimes.is_empty() {
if builder.config.dry_run() || runtimes.is_empty() {
return runtimes;
}
let LlvmResult { llvm_config, .. } = builder.ensure(Llvm { target: builder.config.build });
if builder.config.dry_run() {
return runtimes;
}
let stamp = out_dir.join("sanitizers-finished-building");
let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha());
static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
generate_smart_stamp_hash(
builder,
&builder.config.src.join("src/llvm-project/compiler-rt"),
builder.in_tree_llvm_info.sha().unwrap_or_default(),
)
});
if stamp.is_done() {
if stamp.hash.is_none() {
let stamp = BuildStamp::new(&out_dir).with_prefix("sanitizers").add_stamp(smart_stamp_hash);
if stamp.is_up_to_date() {
if stamp.stamp().is_empty() {
builder.info(&format!(
"Rebuild sanitizers by removing the file `{}`",
stamp.path.display()
stamp.path().display()
));
}
return runtimes;
}

View file

@ -21,6 +21,7 @@ use crate::core::builder::{
};
use crate::core::config::TargetSelection;
use crate::core::config::flags::{Subcommand, get_completion};
use crate::utils::build_stamp::{self, BuildStamp};
use crate::utils::exec::{BootstrapCommand, command};
use crate::utils::helpers::{
self, LldThreads, add_link_lib_path, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var,
@ -544,7 +545,7 @@ impl Step for Miri {
// The mtime of `miri_sysroot` changes when the sysroot gets rebuilt (also see
// <https://github.com/RalfJung/rustc-build-sysroot/commit/10ebcf60b80fe2c3dc765af0ff19fdc0da4b7466>).
// We can hence use that directly as a signal to clear the ui test dir.
builder.clear_if_dirty(&ui_test_dep_dir, &miri_sysroot);
build_stamp::clear_if_dirty(builder, &ui_test_dep_dir, &miri_sysroot);
}
// Run `cargo test`.
@ -981,7 +982,7 @@ impl Step for RustdocGUI {
let mut cmd = builder.tool_cmd(Tool::RustdocGUITest);
let out_dir = builder.test_out(self.target).join("rustdoc-gui");
builder.clear_if_dirty(&out_dir, &builder.rustdoc(self.compiler));
build_stamp::clear_if_dirty(builder, &out_dir, &builder.rustdoc(self.compiler));
if let Some(src) = builder.config.src.to_str() {
cmd.arg("--rust-src").arg(src);
@ -2261,10 +2262,8 @@ impl BookTest {
&[],
);
let stamp = builder
.cargo_out(compiler, mode, target)
.join(PathBuf::from(dep).file_name().unwrap())
.with_extension("stamp");
let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, target))
.with_prefix(PathBuf::from(dep).file_name().and_then(|v| v.to_str()).unwrap());
let output_paths = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
let directories = output_paths

View file

@ -7,6 +7,7 @@ use crate::core::build_steps::tool::SourceType;
use crate::core::build_steps::{compile, test};
use crate::core::config::SplitDebuginfo;
use crate::core::config::flags::Color;
use crate::utils::build_stamp;
use crate::utils::helpers::{
self, LldThreads, add_link_lib_path, check_cfg_arg, linker_args, linker_flags,
};
@ -454,7 +455,7 @@ impl Builder<'_> {
// 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);
build_stamp::clear_if_dirty(self, &out_dir, &backend);
}
if cmd_kind == Kind::Doc {
@ -471,7 +472,7 @@ impl Builder<'_> {
_ => panic!("doc mode {mode:?} not expected"),
};
let rustdoc = self.rustdoc(compiler);
self.clear_if_dirty(&my_out, &rustdoc);
build_stamp::clear_if_dirty(self, &my_out, &rustdoc);
}
let profile_var = |name: &str| {
@ -763,7 +764,7 @@ impl Builder<'_> {
// Only clear out the directory if we're compiling std; otherwise, we
// should let Cargo take care of things for us (via depdep info)
if !self.config.dry_run() && mode == Mode::Std && cmd_kind == Kind::Build {
self.clear_if_dirty(&out_dir, &self.rustc(compiler));
build_stamp::clear_if_dirty(self, &out_dir, &self.rustc(compiler));
}
let rustdoc_path = match cmd_kind {

View file

@ -10,8 +10,9 @@ use build_helper::ci::CiEnv;
use xz2::bufread::XzDecoder;
use crate::core::config::BUILDER_CONFIG_FILENAME;
use crate::utils::build_stamp::BuildStamp;
use crate::utils::exec::{BootstrapCommand, command};
use crate::utils::helpers::{check_run, exe, hex_encode, move_file, program_out_of_date};
use crate::utils::helpers::{check_run, exe, hex_encode, move_file};
use crate::{Config, t};
static SHOULD_FIX_BINS_AND_DYLIBS: OnceLock<bool> = OnceLock::new();
@ -46,7 +47,7 @@ impl Config {
self.verbose > 0
}
pub(crate) fn create(&self, path: &Path, s: &str) {
pub(crate) fn create<P: AsRef<Path>>(&self, path: P, s: &str) {
if self.dry_run() {
return;
}
@ -426,9 +427,10 @@ impl Config {
let version = &self.stage0_metadata.compiler.version;
let host = self.build;
let clippy_stamp = self.initial_sysroot.join(".clippy-stamp");
let clippy_stamp =
BuildStamp::new(&self.initial_sysroot).with_prefix("clippy").add_stamp(date);
let cargo_clippy = self.initial_sysroot.join("bin").join(exe("cargo-clippy", host));
if cargo_clippy.exists() && !program_out_of_date(&clippy_stamp, date) {
if cargo_clippy.exists() && clippy_stamp.is_up_to_date() {
return cargo_clippy;
}
@ -439,7 +441,7 @@ impl Config {
self.fix_bin_or_dylib(&cargo_clippy.with_file_name(exe("clippy-driver", host)));
}
self.create(&clippy_stamp, date);
t!(clippy_stamp.write());
cargo_clippy
}
@ -460,8 +462,8 @@ impl Config {
let host = self.build;
let bin_root = self.out.join(host).join("rustfmt");
let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host));
let rustfmt_stamp = bin_root.join(".rustfmt-stamp");
if rustfmt_path.exists() && !program_out_of_date(&rustfmt_stamp, &channel) {
let rustfmt_stamp = BuildStamp::new(&bin_root).with_prefix("rustfmt").add_stamp(channel);
if rustfmt_path.exists() && rustfmt_stamp.is_up_to_date() {
return Some(rustfmt_path);
}
@ -492,7 +494,7 @@ impl Config {
}
}
self.create(&rustfmt_stamp, &channel);
t!(rustfmt_stamp.write());
Some(rustfmt_path)
}
@ -567,10 +569,10 @@ impl Config {
) {
let host = self.build.triple;
let bin_root = self.out.join(host).join(sysroot);
let rustc_stamp = bin_root.join(".rustc-stamp");
let rustc_stamp = BuildStamp::new(&bin_root).with_prefix("rustc").add_stamp(stamp_key);
if !bin_root.join("bin").join(exe("rustc", self.build)).exists()
|| program_out_of_date(&rustc_stamp, stamp_key)
|| !rustc_stamp.is_up_to_date()
{
if bin_root.exists() {
t!(fs::remove_dir_all(&bin_root));
@ -601,7 +603,7 @@ impl Config {
}
}
t!(fs::write(rustc_stamp, stamp_key));
t!(rustc_stamp.write());
}
}
@ -728,10 +730,10 @@ download-rustc = false
}
let llvm_root = self.ci_llvm_root();
let llvm_stamp = llvm_root.join(".llvm-stamp");
let llvm_sha = detect_llvm_sha(self, self.rust_info.is_managed_git_subrepository());
let key = format!("{}{}", llvm_sha, self.llvm_assertions);
if program_out_of_date(&llvm_stamp, &key) && !self.dry_run() {
let stamp_key = format!("{}{}", llvm_sha, self.llvm_assertions);
let llvm_stamp = BuildStamp::new(&llvm_root).with_prefix("llvm").add_stamp(stamp_key);
if !llvm_stamp.is_up_to_date() && !self.dry_run() {
self.download_ci_llvm(&llvm_sha);
if self.should_fix_bins_and_dylibs() {
@ -764,7 +766,7 @@ download-rustc = false
}
}
t!(fs::write(llvm_stamp, key));
t!(llvm_stamp.write());
}
if let Some(config_path) = &self.config {

View file

@ -19,27 +19,23 @@
use std::cell::{Cell, RefCell};
use std::collections::{BTreeSet, HashMap, HashSet};
use std::fmt::Display;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::OnceLock;
use std::time::SystemTime;
use std::{env, io, str};
use std::{env, fs, io, str};
use build_helper::ci::gha;
use build_helper::exit;
use sha2::digest::Digest;
use termcolor::{ColorChoice, StandardStream, WriteColor};
use utils::build_stamp::BuildStamp;
use utils::channel::GitInfo;
use utils::helpers::hex_encode;
use crate::core::builder;
use crate::core::builder::{Builder, Kind};
use crate::core::builder::Kind;
use crate::core::config::{DryRun, LldMode, LlvmLibunwind, Target, TargetSelection, flags};
use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode, command};
use crate::utils::helpers::{
self, dir_is_empty, exe, libdir, mtime, output, set_file_times, symlink_dir,
};
use crate::utils::helpers::{self, dir_is_empty, exe, libdir, output, set_file_times, symlink_dir};
mod core;
mod utils;
@ -598,24 +594,6 @@ impl Build {
self.metrics.persist(self);
}
/// Clear out `dir` if `input` is newer.
///
/// After this executes, it will also ensure that `dir` exists.
fn clear_if_dirty(&self, dir: &Path, input: &Path) -> bool {
let stamp = dir.join(".stamp");
let mut cleared = false;
if mtime(&stamp) < mtime(input) {
self.verbose(|| println!("Dirty - {}", dir.display()));
let _ = fs::remove_dir_all(dir);
cleared = true;
} else if stamp.exists() {
return cleared;
}
t!(fs::create_dir_all(dir));
t!(File::create(stamp));
cleared
}
fn rust_info(&self) -> &GitInfo {
&self.config.rust_info
}
@ -1622,21 +1600,21 @@ Executed at: {executed_at}"#,
ret
}
fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, DependencyType)> {
fn read_stamp_file(&self, stamp: &BuildStamp) -> Vec<(PathBuf, DependencyType)> {
if self.config.dry_run() {
return Vec::new();
}
if !stamp.exists() {
if !stamp.path().exists() {
eprintln!(
"ERROR: Unable to find the stamp file {}, did you try to keep a nonexistent build stage?",
stamp.display()
stamp.path().display()
);
crate::exit!(1);
}
let mut paths = Vec::new();
let contents = t!(fs::read(stamp), &stamp);
let contents = t!(fs::read(stamp.path()), stamp.path());
// This is the method we use for extracting paths from the stamp file passed to us. See
// run_cargo for more information (in compile.rs).
for part in contents.split(|b| *b == 0) {
@ -1922,52 +1900,6 @@ fn envify(s: &str) -> String {
.collect()
}
/// Computes a hash representing the state of a repository/submodule and additional input.
///
/// It uses `git diff` for the actual changes, and `git status` for including the untracked
/// files in the specified directory. The additional input is also incorporated into the
/// computation of the hash.
///
/// # Parameters
///
/// - `dir`: A reference to the directory path of the target repository/submodule.
/// - `additional_input`: An additional input to be included in the hash.
///
/// # Panics
///
/// In case of errors during `git` command execution (e.g., in tarball sources), default values
/// are used to prevent panics.
pub fn generate_smart_stamp_hash(
builder: &Builder<'_>,
dir: &Path,
additional_input: &str,
) -> String {
let diff = helpers::git(Some(dir))
.allow_failure()
.arg("diff")
.run_capture_stdout(builder)
.stdout_if_ok()
.unwrap_or_default();
let status = helpers::git(Some(dir))
.allow_failure()
.arg("status")
.arg("--porcelain")
.arg("-z")
.arg("--untracked-files=normal")
.run_capture_stdout(builder)
.stdout_if_ok()
.unwrap_or_default();
let mut hasher = sha2::Sha256::new();
hasher.update(diff);
hasher.update(status);
hasher.update(additional_input);
hex_encode(hasher.finalize().as_slice())
}
/// Ensures that the behavior dump directory is properly initialized.
pub fn prepare_behaviour_dump_dir(build: &Build) {
static INITIALIZED: OnceLock<bool> = OnceLock::new();

View file

@ -0,0 +1,204 @@
//! Module for managing build stamp files.
//!
//! Contains the core implementation of how bootstrap utilizes stamp files on build processes.
use std::path::{Path, PathBuf};
use std::{fs, io};
use sha2::digest::Digest;
use crate::core::builder::Builder;
use crate::core::config::TargetSelection;
use crate::utils::helpers::{hex_encode, mtime};
use crate::{Compiler, Mode, helpers, t};
#[cfg(test)]
mod tests;
/// Manages a stamp file to track build state. The file is created in the given
/// directory and can have custom content and name.
#[derive(Clone)]
pub struct BuildStamp {
path: PathBuf,
stamp: String,
}
impl BuildStamp {
/// Creates a new `BuildStamp` for a given directory.
///
/// By default, stamp will be an empty file named `.stamp` within the specified directory.
pub fn new(dir: &Path) -> Self {
// Avoid using `is_dir()` as the directory may not exist yet.
// It is more appropriate to assert that the path is not a file.
assert!(!dir.is_file(), "can't be a file path");
Self { path: dir.join(".stamp"), stamp: String::new() }
}
/// Returns path of the stamp file.
pub fn path(&self) -> &Path {
&self.path
}
/// Returns the value of the stamp.
///
/// Note that this is empty by default and is populated using `BuildStamp::add_stamp`.
/// It is not read from an actual file, but rather it holds the value that will be used
/// when `BuildStamp::write` is called.
pub fn stamp(&self) -> &str {
&self.stamp
}
/// Adds specified stamp content to the current value.
///
/// This method can be used incrementally e.g., `add_stamp("x").add_stamp("y").add_stamp("z")`.
pub fn add_stamp<S: ToString>(mut self, stamp: S) -> Self {
self.stamp.push_str(&stamp.to_string());
self
}
/// Adds a prefix to stamp's name.
///
/// Prefix cannot start or end with a dot (`.`).
pub fn with_prefix(mut self, prefix: &str) -> Self {
assert!(
!prefix.starts_with('.') && !prefix.ends_with('.'),
"prefix can not start or end with '.'"
);
let stamp_filename = self.path.file_name().unwrap().to_str().unwrap();
let stamp_filename = stamp_filename.strip_prefix('.').unwrap_or(stamp_filename);
self.path.set_file_name(format!(".{prefix}-{stamp_filename}"));
self
}
/// Removes the stamp file if it exists.
pub fn remove(&self) -> io::Result<()> {
match fs::remove_file(&self.path) {
Ok(()) => Ok(()),
Err(e) => {
if e.kind() == io::ErrorKind::NotFound {
Ok(())
} else {
Err(e)
}
}
}
}
/// Creates the stamp file.
pub fn write(&self) -> io::Result<()> {
fs::write(&self.path, &self.stamp)
}
/// Checks if the stamp file is up-to-date.
///
/// It is considered up-to-date if file content matches with the stamp string.
pub fn is_up_to_date(&self) -> bool {
match fs::read(&self.path) {
Ok(h) => self.stamp.as_bytes() == h.as_slice(),
Err(e) if e.kind() == io::ErrorKind::NotFound => false,
Err(e) => {
panic!("failed to read stamp file `{}`: {}", self.path.display(), e);
}
}
}
}
/// Clear out `dir` if `input` is newer.
///
/// After this executes, it will also ensure that `dir` exists.
pub fn clear_if_dirty(builder: &Builder<'_>, dir: &Path, input: &Path) -> bool {
let stamp = BuildStamp::new(dir);
let mut cleared = false;
if mtime(stamp.path()) < mtime(input) {
builder.verbose(|| println!("Dirty - {}", dir.display()));
let _ = fs::remove_dir_all(dir);
cleared = true;
} else if stamp.path().exists() {
return cleared;
}
t!(fs::create_dir_all(dir));
t!(fs::File::create(stamp.path()));
cleared
}
/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
/// compiler for the specified target and backend.
pub fn codegen_backend_stamp(
builder: &Builder<'_>,
compiler: Compiler,
target: TargetSelection,
backend: &str,
) -> BuildStamp {
BuildStamp::new(&builder.cargo_out(compiler, Mode::Codegen, target))
.with_prefix(&format!("librustc_codegen_{backend}"))
}
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
pub fn libstd_stamp(
builder: &Builder<'_>,
compiler: Compiler,
target: TargetSelection,
) -> BuildStamp {
BuildStamp::new(&builder.cargo_out(compiler, Mode::Std, target)).with_prefix("libstd")
}
/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn librustc_stamp(
builder: &Builder<'_>,
compiler: Compiler,
target: TargetSelection,
) -> BuildStamp {
BuildStamp::new(&builder.cargo_out(compiler, Mode::Rustc, target)).with_prefix("librustc")
}
/// Computes a hash representing the state of a repository/submodule and additional input.
///
/// It uses `git diff` for the actual changes, and `git status` for including the untracked
/// files in the specified directory. The additional input is also incorporated into the
/// computation of the hash.
///
/// # Parameters
///
/// - `dir`: A reference to the directory path of the target repository/submodule.
/// - `additional_input`: An additional input to be included in the hash.
///
/// # Panics
///
/// In case of errors during `git` command execution (e.g., in tarball sources), default values
/// are used to prevent panics.
pub fn generate_smart_stamp_hash(
builder: &Builder<'_>,
dir: &Path,
additional_input: &str,
) -> String {
let diff = helpers::git(Some(dir))
.allow_failure()
.arg("diff")
.arg(".")
.run_capture_stdout(builder)
.stdout_if_ok()
.unwrap_or_default();
let status = helpers::git(Some(dir))
.allow_failure()
.arg("status")
.arg(".")
.arg("--porcelain")
.arg("-z")
.arg("--untracked-files=normal")
.run_capture_stdout(builder)
.stdout_if_ok()
.unwrap_or_default();
let mut hasher = sha2::Sha256::new();
hasher.update(diff);
hasher.update(status);
hasher.update(additional_input);
hex_encode(hasher.finalize().as_slice())
}

View file

@ -0,0 +1,60 @@
use std::path::PathBuf;
use crate::{BuildStamp, Config, Flags};
fn temp_dir() -> PathBuf {
let config =
Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
config.tempdir()
}
#[test]
#[should_panic(expected = "prefix can not start or end with '.'")]
fn test_with_invalid_prefix() {
let dir = temp_dir();
BuildStamp::new(&dir).with_prefix(".invalid");
}
#[test]
#[should_panic(expected = "prefix can not start or end with '.'")]
fn test_with_invalid_prefix2() {
let dir = temp_dir();
BuildStamp::new(&dir).with_prefix("invalid.");
}
#[test]
fn test_is_up_to_date() {
let dir = temp_dir();
let mut build_stamp = BuildStamp::new(&dir).add_stamp("v1.0.0");
build_stamp.write().unwrap();
assert!(
build_stamp.is_up_to_date(),
"Expected stamp file to be up-to-date, but contents do not match the expected value."
);
build_stamp.stamp = "dummy value".to_owned();
assert!(
!build_stamp.is_up_to_date(),
"Stamp should no longer be up-to-date as we changed its content right above."
);
build_stamp.remove().unwrap();
}
#[test]
fn test_with_prefix() {
let dir = temp_dir();
let stamp = BuildStamp::new(&dir).add_stamp("v1.0.0");
assert_eq!(stamp.path.file_name().unwrap(), ".stamp");
let stamp = stamp.with_prefix("test");
let expected_filename = ".test-stamp";
assert_eq!(stamp.path.file_name().unwrap(), expected_filename);
let stamp = stamp.with_prefix("extra-prefix");
let expected_filename = ".extra-prefix-test-stamp";
assert_eq!(stamp.path.file_name().unwrap(), expected_filename);
}

View file

@ -330,4 +330,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
severity: ChangeSeverity::Warning,
summary: "It is now possible to configure `optimized-compiler-builtins` for per target.",
},
ChangeInfo {
change_id: 135281,
severity: ChangeSeverity::Warning,
summary: "Some stamp names in the build artifacts may have changed slightly (e.g., from `llvm-finished-building` to `.llvm-stamp`).",
},
];

View file

@ -120,7 +120,7 @@ impl BootstrapCommand {
Self { failure_behavior: BehaviorOnFailure::DelayFail, ..self }
}
#[must_use]
#[allow(dead_code)]
pub fn fail_fast(self) -> Self {
Self { failure_behavior: BehaviorOnFailure::Exit, ..self }
}
@ -275,7 +275,7 @@ impl CommandOutput {
!self.is_success()
}
#[must_use]
#[allow(dead_code)]
pub fn status(&self) -> Option<ExitStatus> {
match self.status {
CommandStatus::Finished(status) => Some(status),

View file

@ -16,6 +16,7 @@ use object::read::archive::ArchiveFile;
use crate::LldMode;
use crate::core::builder::Builder;
use crate::core::config::{Config, TargetSelection};
use crate::utils::exec::{BootstrapCommand, command};
pub use crate::utils::shared_helpers::{dylib_path, dylib_path_var};
#[cfg(test)]
@ -45,10 +46,8 @@ macro_rules! t {
}
};
}
pub use t;
use crate::utils::exec::{BootstrapCommand, command};
pub fn exe(name: &str, target: TargetSelection) -> String {
crate::utils::shared_helpers::exe(name, &target.triple)
}
@ -148,14 +147,6 @@ impl Drop for TimeIt {
}
}
/// Used for download caching
pub(crate) fn program_out_of_date(stamp: &Path, key: &str) -> bool {
if !stamp.exists() {
return true;
}
t!(fs::read_to_string(stamp)) != key
}
/// Symlinks two directories, using junctions on Windows and normal symlinks on
/// Unix.
pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result<()> {
@ -598,41 +589,3 @@ pub fn set_file_times<P: AsRef<Path>>(path: P, times: fs::FileTimes) -> io::Resu
};
f.set_times(times)
}
pub struct HashStamp {
pub path: PathBuf,
pub hash: Option<Vec<u8>>,
}
impl HashStamp {
pub fn new(path: PathBuf, hash: Option<&str>) -> Self {
HashStamp { path, hash: hash.map(|s| s.as_bytes().to_owned()) }
}
pub fn is_done(&self) -> bool {
match fs::read(&self.path) {
Ok(h) => self.hash.as_deref().unwrap_or(b"") == h.as_slice(),
Err(e) if e.kind() == io::ErrorKind::NotFound => false,
Err(e) => {
panic!("failed to read stamp file `{}`: {}", self.path.display(), e);
}
}
}
pub fn remove(&self) -> io::Result<()> {
match fs::remove_file(&self.path) {
Ok(()) => Ok(()),
Err(e) => {
if e.kind() == io::ErrorKind::NotFound {
Ok(())
} else {
Err(e)
}
}
}
}
pub fn write(&self) -> io::Result<()> {
fs::write(&self.path, self.hash.as_deref().unwrap_or(b""))
}
}

View file

@ -1,10 +1,10 @@
use std::fs::{self, File, remove_file};
use std::fs::{self, File};
use std::io::Write;
use std::path::PathBuf;
use crate::utils::helpers::{
check_cfg_arg, extract_beta_rev, hex_encode, make, program_out_of_date, set_file_times,
submodule_path_of, symlink_dir,
check_cfg_arg, extract_beta_rev, hex_encode, make, set_file_times, submodule_path_of,
symlink_dir,
};
use crate::{Config, Flags};
@ -57,22 +57,6 @@ fn test_check_cfg_arg() {
);
}
#[test]
fn test_program_out_of_date() {
let config =
Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
let tempfile = config.tempdir().join(".tmp-stamp-file");
File::create(&tempfile).unwrap().write_all(b"dummy value").unwrap();
assert!(tempfile.exists());
// up-to-date
assert!(!program_out_of_date(&tempfile, "dummy value"));
// out-of-date
assert!(program_out_of_date(&tempfile, ""));
remove_file(tempfile).unwrap();
}
#[test]
fn test_symlink_dir() {
let config =

View file

@ -2,6 +2,7 @@
//! support for a wide range of tasks and operations such as caching, tarballs, release
//! channels, job management, etc.
pub(crate) mod build_stamp;
pub(crate) mod cache;
pub(crate) mod cc_detect;
pub(crate) mod change_tracker;
@ -9,10 +10,12 @@ pub(crate) mod channel;
pub(crate) mod exec;
pub(crate) mod helpers;
pub(crate) mod job;
#[cfg(feature = "build-metrics")]
pub(crate) mod metrics;
pub(crate) mod render_tests;
pub(crate) mod shared_helpers;
pub(crate) mod tarball;
#[cfg(feature = "build-metrics")]
pub(crate) mod metrics;
#[cfg(test)]
mod tests;

View file

@ -56,7 +56,7 @@ These tools include:
By default, the Rust build system does not check for changes to the LLVM source code or
its build configuration settings. So, if you need to rebuild the LLVM that is linked
into `rustc`, first delete the file `llvm-finished-building`, which should be located
into `rustc`, first delete the file `.llvm-stamp`, which should be located
in `build/<host-triple>/llvm/`.
The default rustc compilation pipeline has multiple codegen units, which is

View file

@ -391,6 +391,11 @@ trigger_files = [
"x.ps1"
]
[autolabel."A-bootstrap-stamp"]
trigger_files = [
"src/bootstrap/src/utils/build_stamp.rs",
]
[autolabel."T-infra"]
trigger_files = [
"src/ci",