Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bootstrap: Use hash to determine if sanitizers needs to be rebuilt #69735

Merged
merged 1 commit into from
Mar 17, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 67 additions & 31 deletions src/bootstrap/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use std::env;
use std::ffi::OsString;
use std::fs::{self, File};
use std::io;
use std::path::{Path, PathBuf};
use std::process::Command;

Expand Down Expand Up @@ -54,7 +55,6 @@ impl Step for Llvm {
}
}

let llvm_info = &builder.in_tree_llvm_info;
let root = "src/llvm-project/llvm";
let out_dir = builder.llvm_out(target);
let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build);
Expand All @@ -65,40 +65,35 @@ impl Step for Llvm {

let build_llvm_config =
llvm_config_ret_dir.join(exe("llvm-config", &*builder.config.build));
let done_stamp = out_dir.join("llvm-finished-building");

if done_stamp.exists() {
if builder.config.llvm_skip_rebuild {
builder.info(
"Warning: \
Using a potentially stale build of LLVM; \
This may not behave well.",
);
return build_llvm_config;
}
let stamp = out_dir.join("llvm-finished-building");
let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha());

if let Some(llvm_commit) = llvm_info.sha() {
let done_contents = t!(fs::read(&done_stamp));
if builder.config.llvm_skip_rebuild && stamp.path.exists() {
builder.info(
"Warning: \
Using a potentially stale build of LLVM; \
This may not behave well.",
);
return build_llvm_config;
}

// If LLVM was already built previously and the submodule's commit didn't change
// from the previous build, then no action is required.
if done_contents == llvm_commit.as_bytes() {
return build_llvm_config;
}
} else {
if stamp.is_done() {
if stamp.hash.is_none() {
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 `{}`",
done_stamp.display()
stamp.path.display()
));
return build_llvm_config;
}
return build_llvm_config;
}

builder.info(&format!("Building LLVM for {}", target));
t!(stamp.remove());
let _time = util::timeit(&builder);
t!(fs::create_dir_all(&out_dir));

Expand Down Expand Up @@ -271,7 +266,7 @@ impl Step for Llvm {

cfg.build();

t!(fs::write(&done_stamp, llvm_info.sha().unwrap_or("")));
t!(stamp.write());

build_llvm_config
}
Expand Down Expand Up @@ -584,17 +579,21 @@ impl Step for Sanitizers {
return runtimes;
}

let done_stamp = out_dir.join("sanitizers-finished-building");
if done_stamp.exists() {
builder.info(&format!(
"Assuming that sanitizers rebuild is not necessary. \
To force a rebuild, remove the file `{}`",
done_stamp.display()
));
let stamp = out_dir.join("sanitizers-finished-building");
let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha());

if stamp.is_done() {
if stamp.hash.is_none() {
builder.info(&format!(
"Rebuild sanitizers by removing the file `{}`",
stamp.path.display()
));
}
return runtimes;
}

builder.info(&format!("Building sanitizers for {}", self.target));
t!(stamp.remove());
let _time = util::timeit(&builder);

let mut cfg = cmake::Config::new(&compiler_rt_dir);
Expand Down Expand Up @@ -623,8 +622,7 @@ impl Step for Sanitizers {
cfg.build_target(&runtime.cmake_target);
cfg.build();
}

t!(fs::write(&done_stamp, b""));
t!(stamp.write());

runtimes
}
Expand Down Expand Up @@ -689,3 +687,41 @@ fn supported_sanitizers(
}
result
}

struct HashStamp {
path: PathBuf,
hash: Option<Vec<u8>>,
}

impl HashStamp {
fn new(path: PathBuf, hash: Option<&str>) -> Self {
HashStamp { path, hash: hash.map(|s| s.as_bytes().to_owned()) }
}

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);
}
}
}

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)
}
}
}
}

fn write(&self) -> io::Result<()> {
fs::write(&self.path, self.hash.as_deref().unwrap_or(b""))
}
}