summary refs log tree commit diff
path: root/src/bootstrap
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2017-09-01 20:46:51 -0700
committerAlex Crichton <alex@alexcrichton.com>2017-09-09 21:14:44 -0700
commit38bedfabb936f4c26950033a96d673d996534758 (patch)
tree435727200c9338ae1daf97e92aec60df82e56f89 /src/bootstrap
parent18366f4e8aaec1d46282cf0a6e0fe1a0ab202530 (diff)
downloadrust-38bedfabb936f4c26950033a96d673d996534758.tar.gz
rust-38bedfabb936f4c26950033a96d673d996534758.zip
rustbuild: Switch back to using hard links
The `copy` function historically in rustbuild used hard links to speed up the
copy operations that it does. This logic was backed out, however, in #39518 due
to a bug that only showed up on Windows, described in #39504. The cause
described in #39504 happened because Cargo, on a fresh build, would overwrite
the previous artifacts with new hard links that Cargo itself manages.

This behavior in Cargo was fixed in rust-lang/cargo#4390 where it no longer
should overwrite files on fresh builds, opportunistically leaving the filesystem
intact and not touching it.

Hopefully this can help speed up local builds by doing fewer copies all over the
place!
Diffstat (limited to 'src/bootstrap')
-rw-r--r--src/bootstrap/dist.rs8
-rw-r--r--src/bootstrap/tool.rs20
-rw-r--r--src/bootstrap/util.rs9
3 files changed, 27 insertions, 10 deletions
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 2ca65396b35..e18850b08b1 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -20,7 +20,7 @@
 
 use std::env;
 use std::fs::{self, File};
-use std::io::{Read, Write};
+use std::io::{self, Read, Write};
 use std::path::{PathBuf, Path};
 use std::process::{Command, Stdio};
 
@@ -900,7 +900,11 @@ impl Step for PlainSourceTarball {
 fn install(src: &Path, dstdir: &Path, perms: u32) {
     let dst = dstdir.join(src.file_name().unwrap());
     t!(fs::create_dir_all(dstdir));
-    t!(fs::copy(src, &dst));
+    {
+        let mut s = t!(fs::File::open(&src));
+        let mut d = t!(fs::File::create(&dst));
+        io::copy(&mut s, &mut d).expect("failed to copy");
+    }
     chmod(&dst, perms);
 }
 
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index b129aa113a0..eaa2b124423 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -62,6 +62,7 @@ struct ToolBuild {
     compiler: Compiler,
     target: Interned<String>,
     tool: &'static str,
+    path: &'static str,
     mode: Mode,
 }
 
@@ -81,6 +82,7 @@ impl Step for ToolBuild {
         let compiler = self.compiler;
         let target = self.target;
         let tool = self.tool;
+        let path = self.path;
 
         match self.mode {
             Mode::Libstd => builder.ensure(compile::Std { compiler, target }),
@@ -92,7 +94,7 @@ impl Step for ToolBuild {
         let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
         println!("Building stage{} tool {} ({})", compiler.stage, tool, target);
 
-        let mut cargo = prepare_tool_cargo(builder, compiler, target, tool);
+        let mut cargo = prepare_tool_cargo(builder, compiler, target, path);
         build.run(&mut cargo);
         build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host))
     }
@@ -102,11 +104,11 @@ fn prepare_tool_cargo(
     builder: &Builder,
     compiler: Compiler,
     target: Interned<String>,
-    tool: &'static str,
+    path: &'static str,
 ) -> Command {
     let build = builder.build;
     let mut cargo = builder.cargo(compiler, Mode::Tool, target, "build");
-    let dir = build.src.join("src/tools").join(tool);
+    let dir = build.src.join(path);
     cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
 
     // We don't want to build tools dynamically as they'll be running across
@@ -184,6 +186,7 @@ macro_rules! tool {
                     target: self.target,
                     tool: $tool_name,
                     mode: $mode,
+                    path: $path,
                 })
             }
         }
@@ -201,7 +204,7 @@ tool!(
     Compiletest, "src/tools/compiletest", "compiletest", Mode::Libtest;
     BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::Libstd;
     RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::Libstd;
-    RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::Libstd;
+    RustInstaller, "src/tools/rust-installer", "fabricate", Mode::Libstd;
 );
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
@@ -230,6 +233,7 @@ impl Step for RemoteTestServer {
             target: self.target,
             tool: "remote-test-server",
             mode: Mode::Libstd,
+            path: "src/tools/remote-test-server",
         })
     }
 }
@@ -276,7 +280,10 @@ impl Step for Rustdoc {
         let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage));
         println!("Building rustdoc for stage{} ({})", target_compiler.stage, target_compiler.host);
 
-        let mut cargo = prepare_tool_cargo(builder, build_compiler, target, "rustdoc");
+        let mut cargo = prepare_tool_cargo(builder,
+                                           build_compiler,
+                                           target,
+                                           "src/tools/rustdoc");
         build.run(&mut cargo);
         // Cargo adds a number of paths to the dylib search path on windows, which results in
         // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
@@ -337,6 +344,7 @@ impl Step for Cargo {
             target: self.target,
             tool: "cargo",
             mode: Mode::Librustc,
+            path: "src/tools/cargo",
         })
     }
 }
@@ -375,6 +383,7 @@ impl Step for Clippy {
             target: self.target,
             tool: "clippy",
             mode: Mode::Librustc,
+            path: "src/tools/clippy",
         })
     }
 }
@@ -417,6 +426,7 @@ impl Step for Rls {
             target: self.target,
             tool: "rls",
             mode: Mode::Librustc,
+            path: "src/tools/rls",
         })
     }
 }
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 234d937823f..a521dd09453 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -34,8 +34,12 @@ pub fn staticlib(name: &str, target: &str) -> String {
 /// Copies a file from `src` to `dst`
 pub fn copy(src: &Path, dst: &Path) {
     let _ = fs::remove_file(&dst);
-    let res = fs::copy(src, dst);
-    if let Err(e) = res {
+    // Attempt to "easy copy" by creating a hard link (symlinks don't work on
+    // windows), but if that fails just fall back to a slow `copy` operation.
+    if let Ok(()) = fs::hard_link(src, dst) {
+        return
+    }
+    if let Err(e) = fs::copy(src, dst) {
         panic!("failed to copy `{}` to `{}`: {}", src.display(),
                dst.display(), e)
     }
@@ -44,7 +48,6 @@ pub fn copy(src: &Path, dst: &Path) {
     let atime = FileTime::from_last_access_time(&metadata);
     let mtime = FileTime::from_last_modification_time(&metadata);
     t!(filetime::set_file_times(dst, atime, mtime));
-
 }
 
 /// Copies the `src` directory recursively to `dst`. Both are assumed to exist