Make "Assemble stage1 compiler" orders of magnitude faster
This used to take upwards of 5 seconds for me locally. I found that the
culprit was copying the downloaded LLVM shared object:
```
[22:28:03] Install "/home/jnelson/rust-lang/rust/build/x86_64-unknown-linux-gnu/ci-llvm/lib/libLLVM-14-rust-1.62.0-nightly.so" to "/home/jnelson/rust-lang/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/lib/libLLVM-14-rust-1.62.0-nightly.so"
[22:28:09] c Sysroot { compiler: Compiler { stage: 1, host: x86_64-unknown-linux-gnu(x86_64-unknown-linux-gnu) } }
```
It turned out that `install()` used full copies unconditionally. Change
it to use `copy()` internally, which uses hard links instead when
available.
Note that this has a change in behavior: Installing a file will also
change permissions on the source, not just the destination, if hard
links are used.
To avoid changing the behavior on symlinks for existing code, I
introduce a new function `copy_internal` which only dereferences
symlinks when told to do so.
This commit is contained in:
@@ -1873,7 +1873,6 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
|
|||||||
|
|
||||||
/// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
|
/// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
|
||||||
///
|
///
|
||||||
|
|
||||||
/// Returns whether the files were actually copied.
|
/// Returns whether the files were actually copied.
|
||||||
fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool {
|
fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool {
|
||||||
if let Some(config) = builder.config.target_config.get(&target) {
|
if let Some(config) = builder.config.target_config.get(&target) {
|
||||||
@@ -1983,6 +1982,8 @@ impl Step for LlvmTools {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.ensure(crate::native::Llvm { target });
|
||||||
|
|
||||||
let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple);
|
let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple);
|
||||||
tarball.set_overlay(OverlayKind::LLVM);
|
tarball.set_overlay(OverlayKind::LLVM);
|
||||||
tarball.is_preview(true);
|
tarball.is_preview(true);
|
||||||
|
|||||||
@@ -1408,6 +1408,10 @@ impl Build {
|
|||||||
|
|
||||||
/// Copies a file from `src` to `dst`
|
/// Copies a file from `src` to `dst`
|
||||||
pub fn copy(&self, src: &Path, dst: &Path) {
|
pub fn copy(&self, src: &Path, dst: &Path) {
|
||||||
|
self.copy_internal(src, dst, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_internal(&self, src: &Path, dst: &Path, dereference_symlinks: bool) {
|
||||||
if self.config.dry_run {
|
if self.config.dry_run {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1417,15 +1421,22 @@ impl Build {
|
|||||||
}
|
}
|
||||||
let _ = fs::remove_file(&dst);
|
let _ = fs::remove_file(&dst);
|
||||||
let metadata = t!(src.symlink_metadata());
|
let metadata = t!(src.symlink_metadata());
|
||||||
|
let mut src = src.to_path_buf();
|
||||||
if metadata.file_type().is_symlink() {
|
if metadata.file_type().is_symlink() {
|
||||||
|
if dereference_symlinks {
|
||||||
|
src = t!(fs::canonicalize(src));
|
||||||
|
} else {
|
||||||
let link = t!(fs::read_link(src));
|
let link = t!(fs::read_link(src));
|
||||||
t!(symlink_file(link, dst));
|
t!(symlink_file(link, dst));
|
||||||
} else if let Ok(()) = fs::hard_link(src, dst) {
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Ok(()) = fs::hard_link(&src, dst) {
|
||||||
// Attempt to "easy copy" by creating a hard link
|
// Attempt to "easy copy" by creating a hard link
|
||||||
// (symlinks don't work on windows), but if that fails
|
// (symlinks don't work on windows), but if that fails
|
||||||
// just fall back to a slow `copy` operation.
|
// just fall back to a slow `copy` operation.
|
||||||
} else {
|
} else {
|
||||||
if let Err(e) = fs::copy(src, dst) {
|
if let Err(e) = fs::copy(&src, dst) {
|
||||||
panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e)
|
panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e)
|
||||||
}
|
}
|
||||||
t!(fs::set_permissions(dst, metadata.permissions()));
|
t!(fs::set_permissions(dst, metadata.permissions()));
|
||||||
@@ -1497,20 +1508,10 @@ impl Build {
|
|||||||
let dst = dstdir.join(src.file_name().unwrap());
|
let dst = dstdir.join(src.file_name().unwrap());
|
||||||
self.verbose_than(1, &format!("Install {:?} to {:?}", src, dst));
|
self.verbose_than(1, &format!("Install {:?} to {:?}", src, dst));
|
||||||
t!(fs::create_dir_all(dstdir));
|
t!(fs::create_dir_all(dstdir));
|
||||||
drop(fs::remove_file(&dst));
|
|
||||||
{
|
|
||||||
if !src.exists() {
|
if !src.exists() {
|
||||||
panic!("Error: File \"{}\" not found!", src.display());
|
panic!("Error: File \"{}\" not found!", src.display());
|
||||||
}
|
}
|
||||||
let metadata = t!(src.symlink_metadata());
|
self.copy_internal(src, &dst, true);
|
||||||
if let Err(e) = fs::copy(&src, &dst) {
|
|
||||||
panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e)
|
|
||||||
}
|
|
||||||
t!(fs::set_permissions(&dst, metadata.permissions()));
|
|
||||||
let atime = FileTime::from_last_access_time(&metadata);
|
|
||||||
let mtime = FileTime::from_last_modification_time(&metadata);
|
|
||||||
t!(filetime::set_file_times(&dst, atime, mtime));
|
|
||||||
}
|
|
||||||
chmod(&dst, perms);
|
chmod(&dst, perms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user