]> git.lizzy.rs Git - rust.git/blobdiff - src/bootstrap/dist.rs
Utilize interning to allow Copy/Clone steps
[rust.git] / src / bootstrap / dist.rs
index da513b1f2f66929d812599df6afc74188f9c99a5..e9a2fc7fc1a92f352218e3abf9481bc2700771a0 100644 (file)
 use {Build, Compiler, Mode};
 use channel;
 use util::{cp_r, libdir, is_dylib, cp_filtered, copy, exe};
+use builder::{Builder, Step};
+use compile;
+use tool::{self, Tool};
+use cache::{INTERNER, Interned};
 
 pub fn pkgname(build: &Build, component: &str) -> String {
     if component == "cargo" {
@@ -57,8 +61,8 @@ pub fn tmpdir(build: &Build) -> PathBuf {
     build.out.join("tmp/dist")
 }
 
-fn rust_installer(build: &Build) -> Command {
-    build.tool_cmd(&Compiler::new(0, &build.build), "rust-installer")
+fn rust_installer(builder: &Builder) -> Command {
+    builder.tool_cmd(Tool::RustInstaller)
 }
 
 // rules.dist("dist-docs", "src/doc")
@@ -68,14 +72,14 @@ fn rust_installer(build: &Build) -> Command {
 //      .dep(move |s| tool_rust_installer(build, s))
 //      .run(move |s| dist::docs(build, s.stage, s.target));
 
-#[derive(Serialize)]
-pub struct Docs<'a> {
-    stage: u32,
-    host: &'a str,
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct Docs {
+    pub stage: u32,
+    pub target: Interned<String>,
 }
 
-impl<'a> Step<'a> for Docs<'a> {
-    type Output = ();
+impl Step for Docs {
+    type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
     const ONLY_BUILD_TARGETS: bool = true;
 
@@ -83,39 +87,41 @@ fn should_run(_builder: &Builder, path: &Path) -> bool {
         path.ends_with("src/doc")
     }
 
-    fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, target: &str) {
+    fn make_run(
+        builder: &Builder, _path: Option<&Path>, _host: Interned<String>, target: Interned<String>,
+    ) {
         builder.ensure(Docs {
             stage: builder.top_stage,
-            host: target,
+            target: target,
         });
     }
 
     /// Builds the `rust-docs` installer component.
     ///
-    /// Slurps up documentation from the `stage`'s `host`.
-    fn run(self, builder: &Builder) {
+    /// Slurps up documentation from the `stage`'s `target`.
+    fn run(self, builder: &Builder) -> Option<PathBuf> {
         let build = builder.build;
         let stage = self.stage;
-        let host = self.host;
+        let target = self.target;
 
         builder.default_doc(None);
 
-        println!("Dist docs stage{} ({})", stage, host);
+        println!("Dist docs stage{} ({})", stage, target);
         if !build.config.docs {
             println!("\tskipping - docs disabled");
-            return
+            return None;
         }
 
         let name = pkgname(build, "rust-docs");
-        let image = tmpdir(build).join(format!("{}-{}-image", name, host));
+        let image = tmpdir(build).join(format!("{}-{}-image", name, target));
         let _ = fs::remove_dir_all(&image);
 
         let dst = image.join("share/doc/rust/html");
         t!(fs::create_dir_all(&dst));
-        let src = build.out.join(host).join("doc");
+        let src = build.out.join(target).join("doc");
         cp_r(&src, &dst);
 
-        let mut cmd = rust_installer(build);
+        let mut cmd = rust_installer(builder);
         cmd.arg("generate")
            .arg("--product-name=Rust-Documentation")
            .arg("--rel-manifest-dir=rustlib")
@@ -123,7 +129,7 @@ fn run(self, builder: &Builder) {
            .arg("--image-dir").arg(&image)
            .arg("--work-dir").arg(&tmpdir(build))
            .arg("--output-dir").arg(&distdir(build))
-           .arg(format!("--package-name={}-{}", name, host))
+           .arg(format!("--package-name={}-{}", name, target))
            .arg("--component-name=rust-docs")
            .arg("--legacy-manifest-dirs=rustlib,cargo")
            .arg("--bulk-dirs=share/doc/rust/html");
@@ -132,11 +138,13 @@ fn run(self, builder: &Builder) {
 
         // As part of this step, *also* copy the docs directory to a directory which
         // buildbot typically uploads.
-        if host == build.build {
+        if target == build.build {
             let dst = distdir(build).join("doc").join(build.rust_package_vers());
             t!(fs::create_dir_all(&dst));
             cp_r(&src, &dst);
         }
+
+        Some(distdir(build).join(format!("{}-{}.tar.gz", name, target)))
     }
 }
 
@@ -159,7 +167,9 @@ fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
     found
 }
 
-fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build: &Build) {
+fn make_win_dist(
+    rust_root: &Path, plat_root: &Path, target_triple: Interned<String>, build: &Build
+) {
     //Ask gcc where it keeps its stuff
     let mut cmd = Command::new(build.cc(target_triple));
     cmd.arg("-print-search-dirs");
@@ -276,13 +286,13 @@ fn copy_to_folder(src: &Path, dest_folder: &Path) {
 //          }
 //      });
 
-#[derive(Serialize)]
-pub struct Mingw<'a> {
-    host: &'a str,
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct Mingw {
+    target: Interned<String>,
 }
 
-impl<'a> Step<'a> for Mingw<'a> {
-    type Output = ();
+impl Step for Mingw {
+    type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
     const ONLY_BUILD_TARGETS: bool = true;
 
@@ -290,27 +300,27 @@ fn should_run(_builder: &Builder, _path: &Path) -> bool {
         false
     }
 
-    fn make_run(builder: &Builder, _path: Option<&Path>, host: &str, _target: &str) {
-        builder.ensure(Mingw {
-            host: host,
-        });
+    fn make_run(
+        builder: &Builder, _path: Option<&Path>, _host: Interned<String>, target: Interned<String>
+    ) {
+        builder.ensure(Mingw { target });
     }
 
     /// Build the `rust-mingw` installer component.
     ///
     /// This contains all the bits and pieces to run the MinGW Windows targets
     /// without any extra installed software (e.g. we bundle gcc, libraries, etc).
-    fn run(self, builder: &Builder) {
+    fn run(self, builder: &Builder) -> Option<PathBuf> {
         let build = builder.build;
-        let host = self.host;
+        let target = self.target;
 
-        if !host.contains("pc-windows-gnu") {
-            return;
+        if !target.contains("pc-windows-gnu") {
+            return None;
         }
 
-        println!("Dist mingw ({})", host);
+        println!("Dist mingw ({})", target);
         let name = pkgname(build, "rust-mingw");
-        let image = tmpdir(build).join(format!("{}-{}-image", name, host));
+        let image = tmpdir(build).join(format!("{}-{}-image", name, target));
         let _ = fs::remove_dir_all(&image);
         t!(fs::create_dir_all(&image));
 
@@ -318,9 +328,9 @@ fn run(self, builder: &Builder) {
         // thrown away (this contains the runtime DLLs included in the rustc package
         // above) and the second argument is where to place all the MinGW components
         // (which is what we want).
-        make_win_dist(&tmpdir(build), &image, host, &build);
+        make_win_dist(&tmpdir(build), &image, target, &build);
 
-        let mut cmd = rust_installer(build);
+        let mut cmd = rust_installer(builder);
         cmd.arg("generate")
            .arg("--product-name=Rust-MinGW")
            .arg("--rel-manifest-dir=rustlib")
@@ -328,11 +338,12 @@ fn run(self, builder: &Builder) {
            .arg("--image-dir").arg(&image)
            .arg("--work-dir").arg(&tmpdir(build))
            .arg("--output-dir").arg(&distdir(build))
-           .arg(format!("--package-name={}-{}", name, host))
+           .arg(format!("--package-name={}-{}", name, target))
            .arg("--component-name=rust-mingw")
            .arg("--legacy-manifest-dirs=rustlib,cargo");
         build.run(&mut cmd);
         t!(fs::remove_dir_all(&image));
+        Some(distdir(build).join(format!("{}-{}.tar.gz", name, target)))
     }
 }
 
@@ -344,14 +355,14 @@ fn run(self, builder: &Builder) {
 //      .dep(move |s| tool_rust_installer(build, s))
 //      .run(move |s| dist::rustc(build, s.stage, s.target));
 
-#[derive(Serialize)]
-pub struct Rustc<'a> {
-    stage: u32,
-    host: &'a str,
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct Rustc {
+    pub stage: u32,
+    pub target: Interned<String>,
 }
 
-impl<'a> Step<'a> for Rustc<'a> {
-    type Output = ();
+impl Step for Rustc {
+    type Output = PathBuf;
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
     const ONLY_BUILD_TARGETS: bool = true;
@@ -360,27 +371,34 @@ fn should_run(_builder: &Builder, path: &Path) -> bool {
         path.ends_with("src/librustc")
     }
 
-    fn make_run(builder: &Builder, _path: Option<&Path>, host: &str, _target: &str) {
+    fn make_run(
+        builder: &Builder, _path: Option<&Path>, _host: Interned<String>, target: Interned<String>
+    ) {
         builder.ensure(Rustc {
             stage: builder.top_stage,
-            host: host,
+            target: target,
         });
     }
 
     /// Creates the `rustc` installer component.
-    fn run(self, builder: &builder) {
+    fn run(self, builder: &Builder) -> PathBuf {
         let build = builder.build;
         let stage = self.stage;
-        let host = self.host;
-        println!("Dist rustc stage{} ({})", stage, host);
+        let target = self.target;
+
+        let compiler = builder.ensure(compile::Assemble {
+            target_compiler: builder.compiler(stage, build.build),
+        });
+
+        println!("Dist rustc stage{} ({})", stage, target);
         let name = pkgname(build, "rustc");
-        let image = tmpdir(build).join(format!("{}-{}-image", name, host));
+        let image = tmpdir(build).join(format!("{}-{}-image", name, target));
         let _ = fs::remove_dir_all(&image);
-        let overlay = tmpdir(build).join(format!("{}-{}-overlay", name, host));
+        let overlay = tmpdir(build).join(format!("{}-{}-overlay", name, target));
         let _ = fs::remove_dir_all(&overlay);
 
         // Prepare the rustc "image", what will actually end up getting installed
-        prepare_image(builder, stage, host, &image);
+        prepare_image(builder, compiler, target, &image);
 
         // Prepare the overlay which is part of the tarball but won't actually be
         // installed
@@ -405,8 +423,8 @@ fn run(self, builder: &builder) {
         // anything requiring us to distribute a license, but it's likely the
         // install will *also* include the rust-mingw package, which also needs
         // licenses, so to be safe we just include it here in all MinGW packages.
-        if host.contains("pc-windows-gnu") {
-            make_win_dist(&image, &tmpdir(build), host, build);
+        if target.contains("pc-windows-gnu") {
+            make_win_dist(&image, &tmpdir(build), target, build);
 
             let dst = image.join("share/doc");
             t!(fs::create_dir_all(&dst));
@@ -414,7 +432,7 @@ fn run(self, builder: &builder) {
         }
 
         // Finally, wrap everything up in a nice tarball!
-        let mut cmd = rust_installer(build);
+        let mut cmd = rust_installer(builder);
         cmd.arg("generate")
            .arg("--product-name=Rust")
            .arg("--rel-manifest-dir=rustlib")
@@ -423,17 +441,21 @@ fn run(self, builder: &builder) {
            .arg("--work-dir").arg(&tmpdir(build))
            .arg("--output-dir").arg(&distdir(build))
            .arg("--non-installed-overlay").arg(&overlay)
-           .arg(format!("--package-name={}-{}", name, host))
+           .arg(format!("--package-name={}-{}", name, target))
            .arg("--component-name=rustc")
            .arg("--legacy-manifest-dirs=rustlib,cargo");
         build.run(&mut cmd);
         t!(fs::remove_dir_all(&image));
         t!(fs::remove_dir_all(&overlay));
 
-        fn prepare_image(builder: &Builder, stage: u32, host: &str, image: &Path) {
+        return distdir(build).join(format!("{}-{}.tar.gz", name, target));
+
+        fn prepare_image(
+            builder: &Builder, compiler: Compiler, target: Interned<String>, image: &Path
+        ) {
             let build = builder.build;
-            let src = build.sysroot(builder.compiler(stage, host));
-            let libdir = libdir(host);
+            let src = builder.sysroot(compiler);
+            let libdir = libdir(&target);
 
             // Copy rustc/rustdoc binaries
             t!(fs::create_dir_all(image.join("bin")));
@@ -457,8 +479,8 @@ fn prepare_image(builder: &Builder, stage: u32, host: &str, image: &Path) {
 
             // Debugger scripts
             builder.ensure(DebuggerScripts {
-                sysroot: &image,
-                host: host,
+                sysroot: INTERNER.intern_path(image.to_owned()),
+                target: target,
             });
 
             // Misc license info
@@ -474,41 +496,42 @@ fn prepare_image(builder: &Builder, stage: u32, host: &str, image: &Path) {
 }
 
 //rules.test("debugger-scripts", "src/etc/lldb_batchmode.py")
-//     .run(move |s| dist::debugger_scripts(build, &build.sysroot(&s.compiler()),
+//     .run(move |s| dist::debugger_scripts(build, &builder.sysroot(&s.compiler()),
 //                                     s.target));
 
-#[derive(Serialize)]
-pub struct DebuggerScripts<'a> {
-    sysroot: &'a Path,
-    host: &'a str,
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct DebuggerScripts {
+    pub sysroot: Interned<PathBuf>,
+    pub target: Interned<String>,
 }
 
-impl<'a> Step<'a> for DebuggerScripts<'a> {
+impl Step for DebuggerScripts {
     type Output = ();
 
     fn should_run(_builder: &Builder, path: &Path) -> bool {
         path.ends_with("src/etc/lldb_batchmode.py")
     }
 
-    fn make_run(builder: &Builder, _path: Option<&Path>, host: &str, _target: &str) {
+    fn make_run(
+        builder: &Builder, _path: Option<&Path>, host: Interned<String>, target: Interned<String>
+    ) {
         builder.ensure(DebuggerScripts {
-            // FIXME: builder.top_stage is likely wrong in some cases.
-            sysroot: &builder.sysroot(builder.compiler(builder.top_stage, host)),
-            host: host,
+            sysroot: builder.sysroot(builder.compiler(builder.top_stage, host)),
+            target: target,
         });
     }
 
-    /// Copies debugger scripts for `host` into the `sysroot` specified.
+    /// Copies debugger scripts for `target` into the `sysroot` specified.
     fn run(self, builder: &Builder) {
         let build = builder.build;
-        let host = self.host;
+        let target = self.target;
         let sysroot = self.sysroot;
         let dst = sysroot.join("lib/rustlib/etc");
         t!(fs::create_dir_all(&dst));
         let cp_debugger_script = |file: &str| {
             install(&build.src.join("src/etc/").join(file), &dst, 0o644);
         };
-        if host.contains("windows-msvc") {
+        if target.contains("windows-msvc") {
             // windbg debugger scripts
             install(&build.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"),
                 0o755);
@@ -550,41 +573,79 @@ fn run(self, builder: &Builder) {
 //      .dep(move |s| tool_rust_installer(build, s))
 //      .run(move |s| dist::std(build, &s.compiler(), s.target));
 
-    let name = pkgname(build, "rust-std");
-    let image = tmpdir(build).join(format!("{}-{}-image", name, target));
-    let _ = fs::remove_dir_all(&image);
-
-    let dst = image.join("lib/rustlib").join(target);
-    t!(fs::create_dir_all(&dst));
-    let mut src = build.sysroot_libdir(compiler, target);
-    src.pop(); // Remove the trailing /lib folder from the sysroot_libdir
-    cp_r(&src, &dst);
-
-    let mut cmd = rust_installer(build);
-    cmd.arg("generate")
-       .arg("--product-name=Rust")
-       .arg("--rel-manifest-dir=rustlib")
-       .arg("--success-message=std-is-standing-at-the-ready.")
-       .arg("--image-dir").arg(&image)
-       .arg("--work-dir").arg(&tmpdir(build))
-       .arg("--output-dir").arg(&distdir(build))
-       .arg(format!("--package-name={}-{}", name, target))
-       .arg(format!("--component-name=rust-std-{}", target))
-       .arg("--legacy-manifest-dirs=rustlib,cargo");
-    build.run(&mut cmd);
-    t!(fs::remove_dir_all(&image));
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct Std {
+    pub compiler: Compiler,
+    pub target: Interned<String>,
 }
 
-/// The path to the complete rustc-src tarball
-pub fn rust_src_location(build: &Build) -> PathBuf {
-    let plain_name = format!("rustc-{}-src", build.rust_package_vers());
-    distdir(build).join(&format!("{}.tar.gz", plain_name))
-}
+impl Step for Std {
+    type Output = Option<PathBuf>;
+    const DEFAULT: bool = true;
+    const ONLY_BUILD_TARGETS: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/libstd")
+    }
+
+    fn make_run(
+        builder: &Builder, _path: Option<&Path>, host: Interned<String>, target: Interned<String>
+    ) {
+        builder.ensure(Std {
+            compiler: builder.compiler(builder.top_stage, host),
+            target: target,
+        });
+    }
+
+    fn run(self, builder: &Builder) -> Option<PathBuf> {
+        let build = builder.build;
+        let compiler = self.compiler;
+        let target = self.target;
 
-/// The path to the rust-src component installer
-pub fn rust_src_installer(build: &Build) -> PathBuf {
-    let name = pkgname(build, "rust-src");
-    distdir(build).join(&format!("{}.tar.gz", name))
+        println!("Dist std stage{} ({} -> {})", compiler.stage, &compiler.host,
+                 target);
+
+        // The only true set of target libraries came from the build triple, so
+        // let's reduce redundant work by only producing archives from that host.
+        if compiler.host != build.build {
+            println!("\tskipping, not a build host");
+            return None;
+        }
+
+        // We want to package up as many target libraries as possible
+        // for the `rust-std` package, so if this is a host target we
+        // depend on librustc and otherwise we just depend on libtest.
+        if build.config.host.iter().any(|t| t == target) {
+            builder.ensure(compile::Rustc { compiler, target });
+        } else {
+            builder.ensure(compile::Test { compiler, target });
+        }
+
+        let name = pkgname(build, "rust-std");
+        let image = tmpdir(build).join(format!("{}-{}-image", name, target));
+        let _ = fs::remove_dir_all(&image);
+
+        let dst = image.join("lib/rustlib").join(target);
+        t!(fs::create_dir_all(&dst));
+        let mut src = builder.sysroot_libdir(compiler, target).to_path_buf();
+        src.pop(); // Remove the trailing /lib folder from the sysroot_libdir
+        cp_r(&src, &dst);
+
+        let mut cmd = rust_installer(builder);
+        cmd.arg("generate")
+           .arg("--product-name=Rust")
+           .arg("--rel-manifest-dir=rustlib")
+           .arg("--success-message=std-is-standing-at-the-ready.")
+           .arg("--image-dir").arg(&image)
+           .arg("--work-dir").arg(&tmpdir(build))
+           .arg("--output-dir").arg(&distdir(build))
+           .arg(format!("--package-name={}-{}", name, target))
+           .arg(format!("--component-name=rust-std-{}", target))
+           .arg("--legacy-manifest-dirs=rustlib,cargo");
+        build.run(&mut cmd);
+        t!(fs::remove_dir_all(&image));
+        Some(distdir(build).join(format!("{}-{}.tar.gz", name, target)))
+    }
 }
 
 // rules.dist("dist-analysis", "analysis")
@@ -594,14 +655,14 @@ pub fn rust_src_installer(build: &Build) -> PathBuf {
 //      .dep(move |s| tool_rust_installer(build, s))
 //      .run(move |s| dist::analysis(build, &s.compiler(), s.target));
 
-#[derive(Serialize)]
-pub struct Analysis<'a> {
-    compiler: Compiler<'a>,
-    target: &'a str,
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct Analysis {
+    pub compiler: Compiler,
+    pub target: Interned<String>,
 }
 
-impl<'a> Step<'a> for Analysis<'a> {
-    type Output = ();
+impl Step for Analysis {
+    type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
     const ONLY_BUILD_TARGETS: bool = true;
 
@@ -609,7 +670,12 @@ fn should_run(_builder: &Builder, path: &Path) -> bool {
         path.ends_with("analysis")
     }
 
-    fn make_run(builder: &Builder, path: Option<&Path>, host: &str, target: &str) {
+    fn make_run(
+        builder: &Builder,
+        path: Option<&Path>,
+        host: Interned<String>,
+        target: Interned<String>
+    ) {
         if path.is_none() && !builder.build.config.extended {
             return;
         }
@@ -620,16 +686,16 @@ fn make_run(builder: &Builder, path: Option<&Path>, host: &str, target: &str) {
     }
 
     /// Creates a tarball of save-analysis metadata, if available.
-    fn run(self, builder: &Builder) {
+    fn run(self, builder: &Builder) -> Option<PathBuf> {
         let build = builder.build;
         let compiler = self.compiler;
         let target = self.target;
         assert!(build.config.extended);
         println!("Dist analysis");
 
-        if compiler.host != build.build {
+        if &compiler.host != build.build {
             println!("\tskipping, not a build host");
-            return;
+            return None;
         }
 
         // Package save-analysis from stage1 if not doing a full bootstrap, as the
@@ -652,7 +718,7 @@ fn run(self, builder: &Builder) {
         println!("image_src: {:?}, dst: {:?}", image_src, dst);
         cp_r(&image_src, &dst);
 
-        let mut cmd = rust_installer(build);
+        let mut cmd = rust_installer(builder);
         cmd.arg("generate")
            .arg("--product-name=Rust")
            .arg("--rel-manifest-dir=rustlib")
@@ -665,6 +731,7 @@ fn run(self, builder: &Builder) {
            .arg("--legacy-manifest-dirs=rustlib,cargo");
         build.run(&mut cmd);
         t!(fs::remove_dir_all(&image));
+        Some(distdir(build).join(format!("{}-{}.tar.gz", name, target)))
     }
 }
 
@@ -716,11 +783,12 @@ fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
 //      .dep(move |s| tool_rust_installer(build, s))
 //      .run(move |_| dist::rust_src(build));
 
-#[derive(Serialize)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Src;
 
-impl<'a> Step<'a> for Src {
-    type Output = ();
+impl Step for Src {
+    /// The output path of the src installer tarball
+    type Output = PathBuf;
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
     const ONLY_BUILD_TARGETS: bool = true;
@@ -730,12 +798,14 @@ fn should_run(_builder: &Builder, path: &Path) -> bool {
         path.ends_with("src")
     }
 
-    fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, _target: &str) {
+    fn make_run(
+        builder: &Builder, _path: Option<&Path>, _host: Interned<String>, _target: Interned<String>
+    ) {
         builder.ensure(Src);
     }
 
     /// Creates the `rust-src` installer component
-    fn run(self, builder: &Builder) {
+    fn run(self, builder: &Builder) -> PathBuf {
         let build = builder.build;
         println!("Dist src");
 
@@ -784,7 +854,7 @@ fn run(self, builder: &Builder) {
         copy_src_dirs(build, &std_src_dirs[..], &std_src_dirs_exclude[..], &dst_src);
 
         // Create source tarball in rust-installer format
-        let mut cmd = rust_installer(build);
+        let mut cmd = rust_installer(builder);
         cmd.arg("generate")
            .arg("--product-name=Rust")
            .arg("--rel-manifest-dir=rustlib")
@@ -798,6 +868,7 @@ fn run(self, builder: &Builder) {
         build.run(&mut cmd);
 
         t!(fs::remove_dir_all(&image));
+        distdir(build).join(&format!("{}.tar.gz", name))
     }
 }
 
@@ -811,11 +882,12 @@ fn run(self, builder: &Builder) {
 //      .dep(move |s| tool_rust_installer(build, s))
 //      .run(move |_| dist::plain_source_tarball(build));
 
-#[derive(Serialize)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct PlainSourceTarball;
 
-impl<'a> Step<'a> for PlainSourceTarball {
-    type Output = ();
+impl Step for PlainSourceTarball {
+    /// Produces the location of the tarball generated
+    type Output = PathBuf;
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
     const ONLY_BUILD_TARGETS: bool = true;
@@ -825,7 +897,9 @@ fn should_run(_builder: &Builder, path: &Path) -> bool {
         path.ends_with("src")
     }
 
-    fn make_run(builder: &Builder, path: Option<&Path>, _host: &str, _target: &str) {
+    fn make_run(
+        builder: &Builder, path: Option<&Path>, _host: Interned<String>, _target: Interned<String>
+    ) {
         if path.is_none() && !builder.build.config.rust_dist_src {
             return;
         }
@@ -834,7 +908,7 @@ fn make_run(builder: &Builder, path: Option<&Path>, _host: &str, _target: &str)
     }
 
     /// Creates the plain source tarball
-    fn run(self, builder: &Builder) {
+    fn run(self, builder: &Builder) -> PathBuf {
         let build = builder.build;
         println!("Create plain source tarball");
 
@@ -897,19 +971,21 @@ fn run(self, builder: &Builder) {
         }
 
         // Create plain source tarball
-        let mut tarball = rust_src_location(build);
+        let plain_name = format!("rustc-{}-src", build.rust_package_vers());
+        let mut tarball = distdir(build).join(&format!("{}.tar.gz", plain_name));
         tarball.set_extension(""); // strip .gz
         tarball.set_extension(""); // strip .tar
-        if let Some(dir) = tarball.parent() {
+        if let Some(dir) = distdir(build).parent() {
             t!(fs::create_dir_all(dir));
         }
-        let mut cmd = rust_installer(build);
+        let mut cmd = rust_installer(builder);
         cmd.arg("tarball")
            .arg("--input").arg(&plain_name)
            .arg("--output").arg(&tarball)
            .arg("--work-dir=.")
            .current_dir(tmpdir(build));
         build.run(&mut cmd);
+        distdir(build).join(&format!("{}.tar.gz", plain_name))
     }
 }
 
@@ -959,14 +1035,14 @@ fn write_file(path: &Path, data: &[u8]) {
 //      .dep(move |s| tool_rust_installer(build, s))
 //      .run(move |s| dist::cargo(build, s.stage, s.target));
 
-#[derive(Serialize)]
-pub struct Cargo<'a> {
-    stage: u32,
-    target: &'a str,
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct Cargo {
+    pub stage: u32,
+    pub target: Interned<String>,
 }
 
-impl<'a> Step<'a> for Cargo<'a> {
-    type Output = ();
+impl Step for Cargo {
+    type Output = PathBuf;
     const ONLY_BUILD_TARGETS: bool = true;
     const ONLY_HOSTS: bool = true;
 
@@ -974,14 +1050,16 @@ fn should_run(_builder: &Builder, path: &Path) -> bool {
         path.ends_with("cargo")
     }
 
-    fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, target: &str) {
+    fn make_run(
+        builder: &Builder, _path: Option<&Path>, _host: Interned<String>, target: Interned<String>
+    ) {
         builder.ensure(Cargo {
             stage: builder.top_stage,
             target: target,
         });
     }
 
-    fn run(self, builder: &Builder) {
+    fn run(self, builder: &Builder) -> PathBuf {
         let build = builder.build;
         let stage = self.stage;
         let target = self.target;
@@ -989,13 +1067,13 @@ fn run(self, builder: &Builder) {
         builder.ensure(tool::Cargo { stage, target });
 
         println!("Dist cargo stage{} ({})", stage, target);
-        let compiler = builder.compiler(stage, &build.build);
+        let compiler = builder.compiler(stage, build.build);
 
         let src = build.src.join("src/tools/cargo");
         let etc = src.join("src/etc");
         let release_num = build.release_num("cargo");
         let name = pkgname(build, "cargo");
-        let version = build.cargo_info.version(build, &release_num);
+        let version = builder.cargo_info.version(build, &release_num);
 
         let tmp = tmpdir(build);
         let image = tmp.join("cargo-image");
@@ -1005,8 +1083,8 @@ fn run(self, builder: &Builder) {
         // Prepare the image directory
         t!(fs::create_dir_all(image.join("share/zsh/site-functions")));
         t!(fs::create_dir_all(image.join("etc/bash_completion.d")));
-        let cargo = build.cargo_out(&compiler, Mode::Tool, target)
-                         .join(exe("cargo", target));
+        let cargo = build.cargo_out(compiler, Mode::Tool, target)
+                         .join(exe("cargo", &target));
         install(&cargo, &image.join("bin"), 0o755);
         for man in t!(etc.join("man").read_dir()) {
             let man = t!(man);
@@ -1032,7 +1110,7 @@ fn run(self, builder: &Builder) {
         t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
 
         // Generate the installer tarball
-        let mut cmd = rust_installer(build);
+        let mut cmd = rust_installer(builder);
         cmd.arg("generate")
            .arg("--product-name=Rust")
            .arg("--rel-manifest-dir=rustlib")
@@ -1045,6 +1123,7 @@ fn run(self, builder: &Builder) {
            .arg("--component-name=cargo")
            .arg("--legacy-manifest-dirs=rustlib,cargo");
         build.run(&mut cmd);
+        distdir(build).join(format!("{}-{}.tar.gz", name, target))
     }
 }
 
@@ -1054,14 +1133,14 @@ fn run(self, builder: &Builder) {
 //      .dep(|s| s.name("tool-rls"))
 //      .dep(move |s| tool_rust_installer(build, s))
 //      .run(move |s| dist::rls(build, s.stage, s.target));
-#[derive(Serialize)]
-pub struct Rls<'a> {
-    stage: u32,
-    target: &'a str,
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct Rls {
+    pub stage: u32,
+    pub target: Interned<String>,
 }
 
-impl<'a> Step<'a> for Rls<'a> {
-    type Output = ();
+impl Step for Rls {
+    type Output = PathBuf;
     const ONLY_BUILD_TARGETS: bool = true;
     const ONLY_HOSTS: bool = true;
 
@@ -1069,14 +1148,16 @@ fn should_run(_builder: &Builder, path: &Path) -> bool {
         path.ends_with("rls")
     }
 
-    fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, target: &str) {
+    fn make_run(
+        builder: &Builder, _path: Option<&Path>, _host: Interned<String>, target: Interned<String>
+    ) {
         builder.ensure(Rls {
             stage: builder.top_stage,
             target: target,
         });
     }
 
-    fn run(self, builder: &Builder) {
+    fn run(self, builder: &Builder) -> PathBuf {
         let build = builder.build;
         let stage = self.stage;
         let target = self.target;
@@ -1085,7 +1166,7 @@ fn run(self, builder: &Builder) {
         builder.ensure(tool::Rls { stage, target });
 
         println!("Dist RLS stage{} ({})", stage, target);
-        let compiler = builder.compiler(stage, &build.build);
+        let compiler = builder.compiler(stage, build.build);
 
         let src = build.src.join("src/tools/rls");
         let release_num = build.release_num("rls");
@@ -1098,8 +1179,8 @@ fn run(self, builder: &Builder) {
         t!(fs::create_dir_all(&image));
 
         // Prepare the image directory
-        let rls = build.cargo_out(&compiler, Mode::Tool, target)
-                         .join(exe("rls", target));
+        let rls = build.cargo_out(compiler, Mode::Tool, target)
+                         .join(exe("rls", &target));
         install(&rls, &image.join("bin"), 0o755);
         let doc = image.join("share/doc/rls");
         install(&src.join("README.md"), &doc, 0o644);
@@ -1116,7 +1197,7 @@ fn run(self, builder: &Builder) {
         t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
 
         // Generate the installer tarball
-        let mut cmd = rust_installer(build);
+        let mut cmd = rust_installer(builder);
         cmd.arg("generate")
            .arg("--product-name=Rust")
            .arg("--rel-manifest-dir=rustlib")
@@ -1129,6 +1210,7 @@ fn run(self, builder: &Builder) {
            .arg("--component-name=rls")
            .arg("--legacy-manifest-dirs=rustlib,cargo");
         build.run(&mut cmd);
+        distdir(build).join(format!("{}-{}.tar.gz", name, target))
     }
 }
 
@@ -1146,13 +1228,13 @@ fn run(self, builder: &Builder) {
 //      .dep(move |s| tool_rust_installer(build, s))
 //      .run(move |s| dist::extended(build, s.stage, s.target));
 
-#[derive(Serialize)]
-pub struct Extended<'a> {
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct Extended {
     stage: u32,
-    target: &'a str,
+    target: Interned<String>,
 }
 
-impl<'a> Step<'a> for Extended<'a> {
+impl Step for Extended {
     type Output = ();
     const DEFAULT: bool = true;
     const ONLY_BUILD_TARGETS: bool = true;
@@ -1162,12 +1244,14 @@ fn should_run(_builder: &Builder, path: &Path) -> bool {
         path.ends_with("cargo")
     }
 
-    fn make_run(builder: &Builder, path: Option<&Path>, host: &str, target: &str) {
+    fn make_run(
+        builder: &Builder, path: Option<&Path>, _host: Interned<String>, target: Interned<String>
+    ) {
         if path.is_none() && !builder.build.config.extended {
             return;
         }
         builder.ensure(Extended {
-            compiler: builder.compiler(builder.top_stage, host),
+            stage: builder.top_stage,
             target: target,
         });
     }
@@ -1177,40 +1261,17 @@ fn run(self, builder: &Builder) {
         let build = builder.build;
         let stage = self.stage;
         let target = self.target;
-        let compiler = builder.compiler(stage, &build.build);
-
-        builder.ensure(Std { compiler, target });
-        builder.ensure(Rustc { stage, host });
-        builder.ensure(Mingw { host });
-        builder.ensure(Docs { stage, host });
-        builder.ensure(Cargo { stage, target });
-        builder.ensure(Rls { stage, target });
-        builder.ensure(Analysis { compiler, target });
+        let compiler = builder.compiler(stage, build.build);
 
         println!("Dist extended stage{} ({})", stage, target);
 
-        let dist = distdir(build);
-        let rustc_installer = dist.join(format!("{}-{}.tar.gz",
-                                                pkgname(build, "rustc"),
-                                                target));
-        let cargo_installer = dist.join(format!("{}-{}.tar.gz",
-                                                pkgname(build, "cargo"),
-                                                target));
-        let rls_installer = dist.join(format!("{}-{}.tar.gz",
-                                                pkgname(build, "rls"),
-                                                target));
-        let analysis_installer = dist.join(format!("{}-{}.tar.gz",
-                                                    pkgname(build, "rust-analysis"),
-                                                    target));
-        let docs_installer = dist.join(format!("{}-{}.tar.gz",
-                                                pkgname(build, "rust-docs"),
-                                                target));
-        let mingw_installer = dist.join(format!("{}-{}.tar.gz",
-                                                pkgname(build, "rust-mingw"),
-                                                target));
-        let std_installer = dist.join(format!("{}-{}.tar.gz",
-                                                pkgname(build, "rust-std"),
-                                                target));
+        let rustc_installer = builder.ensure(Rustc { stage, target });
+        let cargo_installer = builder.ensure(Cargo { stage, target });
+        let rls_installer = builder.ensure(Rls { stage, target });
+        let analysis_installer = builder.ensure(Analysis { compiler, target }).unwrap();
+        let docs_installer = builder.ensure(Docs { stage, target }).unwrap();
+        let mingw_installer = builder.ensure(Mingw { target });
+        let std_installer = builder.ensure(Std { compiler, target }).unwrap();
 
         let tmp = tmpdir(build);
         let overlay = tmp.join("extended-overlay");
@@ -1232,7 +1293,7 @@ fn run(self, builder: &Builder) {
         let mut tarballs = vec![rustc_installer, cargo_installer, rls_installer,
                                 analysis_installer, docs_installer, std_installer];
         if target.contains("pc-windows-gnu") {
-            tarballs.push(mingw_installer);
+            tarballs.push(mingw_installer.unwrap());
         }
         let mut input_tarballs = tarballs[0].as_os_str().to_owned();
         for tarball in &tarballs[1..] {
@@ -1240,7 +1301,7 @@ fn run(self, builder: &Builder) {
             input_tarballs.push(tarball);
         }
 
-        let mut cmd = rust_installer(build);
+        let mut cmd = rust_installer(builder);
         cmd.arg("combine")
             .arg("--product-name=Rust")
             .arg("--rel-manifest-dir=rustlib")
@@ -1541,7 +1602,7 @@ fn run(self, builder: &Builder) {
     }
 }
 
-fn add_env(build: &Build, cmd: &mut Command, target: &str) {
+fn add_env(build: &Build, cmd: &mut Command, target: Interned<String>) {
     let mut parts = channel::CFG_RELEASE_NUM.split('.');
     cmd.env("CFG_RELEASE_INFO", build.rust_version())
        .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
@@ -1578,10 +1639,10 @@ fn add_env(build: &Build, cmd: &mut Command, target: &str) {
 //      .dep(move |s| s.name("tool-build-manifest").target(&build.build).stage(0))
 //      .run(move |_| dist::hash_and_sign(build));
 
-#[derive(Serialize)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct HashSign;
 
-impl<'a> Step<'a> for HashSign {
+impl Step for HashSign {
     type Output = ();
     const ONLY_BUILD_TARGETS: bool = true;
     const ONLY_HOSTS: bool = true;
@@ -1591,7 +1652,9 @@ fn should_run(_builder: &Builder, path: &Path) -> bool {
         path.ends_with("hash-and-sign")
     }
 
-    fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, _target: &str) {
+    fn make_run(
+        builder: &Builder, _path: Option<&Path>, _host: Interned<String>, _target: Interned<String>
+    ) {
         builder.ensure(HashSign);
     }