]> git.lizzy.rs Git - rust.git/commitdiff
Change code to work with the new system
authorMark Simulacrum <mark.simulacrum@gmail.com>
Wed, 5 Jul 2017 12:41:27 +0000 (06:41 -0600)
committerMark Simulacrum <mark.simulacrum@gmail.com>
Thu, 20 Jul 2017 17:23:57 +0000 (11:23 -0600)
src/bootstrap/check.rs
src/bootstrap/compile.rs
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/install.rs
src/bootstrap/native.rs
src/bootstrap/tool.rs

index 0278b8d5dbf2b3bc9de4c576e94af3ae7385acfe..2fd02d3d7c48f6d2ab18ee233923a7a99eb46766 100644 (file)
@@ -100,6 +100,8 @@ pub struct Linkcheck<'a> {
 
 impl<'a> Step<'a> for Linkcheck<'a> {
     type Output = ();
+    const ONLY_HOSTS: bool = true;
+    const DEFAULT: bool = true;
 
     /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
     ///
@@ -110,12 +112,27 @@ fn run(self, builder: &Builder) {
         let host = self.host;
 
         println!("Linkcheck ({})", host);
-        let compiler = Compiler::new(0, host);
+
+        builder.default_doc(None);
 
         let _time = util::timeit();
-        try_run(build, build.tool_cmd(&compiler, "linkchecker")
+        try_run(build, builder.tool_cmd(Tool::Linkchecker)
                             .arg(build.out.join(host).join("doc")));
     }
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/tools/linkchecker")
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, host: &str, _target: &str) {
+        if path.is_some() {
+            builder.ensure(Linkcheck { host });
+        } else {
+            if builder.build.config.docs {
+                builder.ensure(Linkcheck { host });
+            }
+        }
+    }
 }
 
 // rules.test("check-cargotest", "src/tools/cargotest")
@@ -132,6 +149,7 @@ pub struct Cargotest<'a> {
 
 impl<'a> Step<'a> for Cargotest<'a> {
     type Output = ();
+    const ONLY_HOSTS: bool = true;
 
     /// Runs the `cargotest` tool as compiled in `stage` by the `host` compiler.
     ///
@@ -139,9 +157,8 @@ impl<'a> Step<'a> for Cargotest<'a> {
     /// test` to ensure that we don't regress the test suites there.
     fn run(self, builder: &Builder) {
         let build = builder.build;
-        let stage = self.stage;
-        let host = self.host;
-        let compiler = Compiler::new(stage, host);
+        let compiler = builder.compiler(self.stage, host);
+        builder.ensure(compile::Rustc { compiler, target: compiler.host });
 
         // Note that this is a short, cryptic, and not scoped directory name. This
         // is currently to minimize the length of path on Windows where we otherwise
@@ -150,8 +167,7 @@ fn run(self, builder: &Builder) {
         t!(fs::create_dir_all(&out_dir));
 
         let _time = util::timeit();
-        let mut cmd = Command::new(build.tool(&Compiler::new(0, host), "cargotest"));
-        build.prepare_tool_cmd(&compiler, &mut cmd);
+        let mut cmd = builder.tool_cmd(Tool::CargoTest);
         try_run(build, cmd.arg(&build.initial_cargo)
                           .arg(&out_dir)
                           .env("RUSTC", build.compiler_path(&compiler))
@@ -172,21 +188,34 @@ pub struct Cargo<'a> {
 
 impl<'a> Step<'a> for Cargo<'a> {
     type Output = ();
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("cargo") // FIXME: Why is this not src/tools/cargo?
+    }
+
+    fn make_run(builder: &Builder, _path: Option<&Path>, host: &str, target: &str) {
+        builder.ensure(TestCargo {
+            compiler: builder.compiler(builder.top_stage, host),
+            target,
+        });
+    }
 
     /// Runs `cargo test` for `cargo` packaged with Rust.
     fn run(self, builder: &Builder) {
         let build = builder.build;
-        let stage = self.stage;
-        let ref compiler = Compiler::new(stage, host);
+        let compiler = builder.compiler(self.stage, self.host);
 
         // Configure PATH to find the right rustc. NB. we have to use PATH
         // and not RUSTC because the Cargo test suite has tests that will
         // fail if rustc is not spelled `rustc`.
         let path = build.sysroot(compiler).join("bin");
         let old_path = env::var_os("PATH").unwrap_or_default();
-        let newpath = env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("");
+        let newpath = env::join_paths(
+            iter::once(path).chain(env::split_paths(&old_path))
+        ).expect("");
 
-        let mut cargo = build.cargo(compiler, Mode::Tool, host, "test");
+        let mut cargo = build.cargo(compiler, Mode::Tool, self.host, "test");
         cargo.arg("--manifest-path").arg(build.src.join("src/tools/cargo/Cargo.toml"));
         if !build.fail_fast {
             cargo.arg("--no-fail-fast");
@@ -250,7 +279,6 @@ fn path_for_cargo(build: &Build, compiler: &Compiler) -> OsString {
     try_run(build, cargo.env("PATH", newpath));
 =======
         try_run(build, cargo.env("PATH", newpath));
-        let host = self.host;
     }
 >>>>>>> adabe3889e... Move code into Step trait implementations.
 }
@@ -269,6 +297,9 @@ pub struct Tidy<'a> {
 
 impl<'a> Step<'a> for Tidy<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+    const ONLY_BUILD: bool = true;
 
     /// Runs the `tidy` tool as compiled in `stage` by the `host` compiler.
     ///
@@ -281,8 +312,7 @@ fn run(self, builder: &Builder) {
 
         let _folder = build.fold_output(|| "tidy");
         println!("tidy check ({})", host);
-        let compiler = Compiler::new(0, host);
-        let mut cmd = build.tool_cmd(&compiler, "tidy");
+        let mut cmd = build.tool_cmd(Tool::Tidy);
         cmd.arg(build.src.join("src"));
         if !build.config.vendor {
             cmd.arg("--no-vendor");
@@ -292,6 +322,16 @@ fn run(self, builder: &Builder) {
         }
         try_run(build, &mut cmd);
     }
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/tools/tidy")
+    }
+
+    fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, _target: &str) {
+        builder.ensure(Tidy {
+            host: &builder.build.build,
+        });
+    }
 }
 
 fn testdir(build: &Build, host: &str) -> PathBuf {
@@ -404,8 +444,78 @@ pub struct Compiletest<'a> {
     suite: &'a str,
 }
 
+static COMPILETESTS: &[(bool, &str, &str, &str)] = &[
+    // default, path, mode, suite
+    (true, "src/test/codegen", "codegen", "codegen"),
+    (true, "src/test/codegen-units", "codegen-units", "codegen-units"),
+    (true, "src/test/compile-fail", "compile-fail", "compile-fail"),
+    (true, "src/test/incremental", "incremental", "incremental"),
+    (true, "src/test/mir-opt", "mir-opt", "mir-opt"),
+    (true, "src/test/parse-fail", "parse-fail", "parse-fail"),
+    (true, "src/test/run-fail", "run-fail", "run-fail"),
+    (true, "src/test/run-pass", "run-pass", "run-pass"),
+    (true, "src/test/run-pass-valgrind", "run-pass-valgrind", "run-pass-valgrind"),
+    (true, "src/test/ui", "ui", "ui"),
+    (false, "src/test/debuginfo-lldb", "debuginfo-lldb", "debuginfo"),
+    (false, "src/test/debuginfo-gdb", "debuginfo-gdb", "debuginfo"),
+
+    // FIXME: What this runs varies depending on the native platform being apple
+    (true, "src/test/debuginfo", "debuginfo-XXX", "debuginfo"),
+
+    (true, "src/test/ui-fulldeps", "ui", "ui-fulldeps"),
+    (true, "src/test/run-pass-fulldeps", "run-pass", "run-pass-fulldeps"),
+    (true, "src/test/run-fail-fulldeps", "run-fail", "run-fail-fulldeps"),
+    (true, "src/test/compile-fail-fulldeps", "compile-fail", "compile-fail-fulldeps"),
+    (true, "src/test/run-make", "run-make", "run-make"),
+    (true, "src/test/rustdoc", "rustdoc", "rustdoc"),
+
+    (false, "src/test/pretty", "pretty", "pretty"),
+    (false, "src/test/run-pass/pretty", "pretty", "run-pass"),
+    (false, "src/test/run-fail/pretty", "pretty", "run-fail"),
+    (false, "src/test/run-pass-valgrind/pretty", "pretty", "run-pass-valgrind"),
+    (false, "src/test/run-pass-fulldeps/pretty", "pretty", "run-pass-fulldeps"),
+    (false, "src/test/run-fail-fulldeps/pretty", "pretty", "run-fail-fulldeps"),
+];
+
+
 impl<'a> Step<'a> for Compiletest<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        // Note that this is general, while a few more cases are skipped inside
+        // run() itself. This is to avoid duplication across should_run and
+        // make_run.
+        COMPILETESTS.iter().any(|&(_, test_path, _, _)| {
+            path.ends_with(test_path)
+        })
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, host: &str, target: &str) {
+        let compiler = builder.compiler(builder.top_stage, host);
+
+        let test = path.map(|path| {
+            COMPILETESTS.iter().find(|&&(_, test_path, _, _)| {
+                path.ends_with(test_path)
+            }).unwrap_or_else(|| {
+                panic!("make_run in compile test to receive test path, received {:?}", path);
+            })
+        });
+
+        if let Some(test) = test { // specific test
+            builder.ensure(Compiletest {
+                compiler, target, mode: test.2, suite: test.3
+            });
+        } else { // default tests
+            for &(default, _, mode, suite) in COMPILETESTS {
+                if default {
+                    builder.ensure(Compiletest {
+                        compiler, target, mode, suite
+                    });
+                }
+            }
+        }
+    }
 
     /// Executes the `compiletest` tool to run a suite of tests.
     ///
@@ -418,12 +528,58 @@ fn run(self, builder: &Builder) {
         let target = self.target;
         let mode = self.mode;
         let suite = self.suite;
+
+        // Skip codegen tests if they aren't enabled in configuration.
+        if !build.config.codegen_tests && suite == "codegen" {
+            return;
+        }
+
+        if suite == "debuginfo" {
+            if mode == "debuginfo-XXX" {
+                return if build.build.contains("apple") {
+                    builder.ensure(Compiletest {
+                        mode: "debuginfo-lldb",
+                        ..self
+                    })
+                } else {
+                    builder.ensure(Compiletest {
+                        mode: "debuginfo-gdb",
+                        ..self
+                    })
+                };
+            }
+
+            // Skip debuginfo tests on MSVC
+            if build.build.contains("msvc") {
+                return;
+            }
+
+            builder.ensure(dist::DebuggerScripts {
+                sysroot: &builder.sysroot(compiler),
+                host: compiler.host
+            });
+        }
+
+        if suite.ends_with("fulldeps") ||
+            // FIXME: Does pretty need librustc compiled? Note that there are
+            // fulldeps test suites with mode = pretty as well.
+            mode == "pretty" ||
+            mode == "rustdoc" ||
+            mode == "run-make" {
+            builder.ensure(compile::Rustc { compiler, target });
+        }
+
+        builder.ensure(compile::Test { compiler, target });
+        builder.ensure(native::TestHelpers { target });
+
+        if mode == "debuginfo-gdb" {
+            builder.ensure(RemoteCopyLibs { compiler, target });
+        }
+
         let _folder = build.fold_output(|| format!("test_{}", suite));
         println!("Check compiletest suite={} mode={} ({} -> {})",
                  suite, mode, compiler.host, target);
-        let mut cmd = Command::new(build.tool(&Compiler::new(0, compiler.host),
-                                              "compiletest"));
-        build.prepare_tool_cmd(compiler, &mut cmd);
+        let mut cmd = builder.tool_cmd(Tool::Compiletest);
 
         // compiletest currently has... a lot of arguments, so let's just pass all
         // of them!
@@ -518,9 +674,7 @@ fn run(self, builder: &Builder) {
         }
 
         if build.remote_tested(target) {
-            cmd.arg("--remote-test-client")
-               .arg(build.tool(&Compiler::new(0, &build.build),
-                               "remote-test-client"));
+            cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
         }
 
         // Running a C compiler on MSVC requires a few env vars to be set, to be
@@ -614,6 +768,18 @@ pub struct ErrorIndex<'a> {
 
 impl<'a> Step<'a> for ErrorIndex<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/tools/error_index_generator")
+    }
+
+    fn make_run(builder: &Builder, _path: Option<&Path>, host: &str, _target: &str) {
+        builder.ensure(ErrorIndex {
+            compiler: builder.compiler(builder.top_stage, host),
+        });
+    }
 
     /// Run the error index generator tool to execute the tests located in the error
     /// index.
@@ -625,6 +791,8 @@ fn run(self, builder: &Builder) {
         let build = builder.build;
         let compiler = self.compiler;
 
+        builder.ensure(compile::Std { compiler, target: compiler.host });
+
         let _folder = build.fold_output(|| "test_error_index");
         println!("Testing error-index stage{}", compiler.stage);
 
@@ -633,8 +801,7 @@ fn run(self, builder: &Builder) {
         let output = dir.join("error-index.md");
 
         let _time = util::timeit();
-        build.run(build.tool_cmd(&Compiler::new(0, compiler.host),
-                                "error_index_generator")
+        build.run(build.tool_cmd(Tool::ErrorIndex)
                     .arg("markdown")
                     .arg(&output)
                     .env("CFG_BUILD", &build.build));
@@ -669,6 +836,86 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
     }
 }
 
+//    for (krate, path, _default) in krates("rustc-main") {
+//        rules.test(&krate.test_step, path)
+//             .dep(|s| s.name("librustc"))
+//             .dep(|s| s.name("remote-copy-libs"))
+//             .host(true)
+//             .run(move |s| check::krate(build, &s.compiler(), s.target,
+//                                        Mode::Librustc, TestKind::Test,
+//                                        Some(&krate.name)));
+//    }
+//    rules.test("check-rustc-all", "path/to/nowhere")
+//         .dep(|s| s.name("librustc"))
+//         .dep(|s| s.name("remote-copy-libs"))
+//         .default(true)
+//         .host(true)
+//         .run(move |s| check::krate(build, &s.compiler(), s.target,
+//                                    Mode::Librustc, TestKind::Test, None));
+#[derive(Serialize)]
+pub struct KrateLibrustc<'a> {
+    compiler: Compiler<'a>,
+    target: &'a str,
+    test_kind: TestKind,
+    krate: Option<&'a str>,
+}
+
+impl<'a> Step<'a> for KrateLibrustc<'a> {
+    type Output = ();
+    const NAME: &'static str = "check librustc";
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(builder: &Builder, path: &Path) -> bool {
+        builder.crates("rustc-main").into_iter().any(|(_, krate_path)| {
+            path.ends_with(krate_path)
+        })
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, host: &str, target: &str) {
+        let compiler = builder.compiler(builder.top_stage, host);
+
+        let run = |name: Option<&str>| {
+            let test_kind = if builder.kind == Kind::Test {
+                TestKind::Test
+            } else if builder.kind == Kind::Bench {
+                TestKind::Bench
+            } else {
+                panic!("unexpected builder.kind in Krate: {:?}", builder.kind);
+            };
+
+            builder.ensure(KrateLibrustc {
+                compiler,
+                target,
+                test_kind: test_kind,
+                krate: name,
+            });
+        };
+
+        if let Some(path) = path {
+            for (name, krate_path) in builder.crates("rustc-main") {
+                if path.ends_with(krate_path) {
+                    run(Some(name));
+                }
+            }
+        } else {
+            run(None);
+        }
+    }
+
+
+    fn run(self, builder: &Builder) {
+        builder.ensure(Krate {
+            compiler: self.compiler,
+            target: self.target,
+            mode: Mode::Librustc,
+            test_kind: self.test_kind,
+            krate: self.krate,
+        });
+    }
+}
+
+
 //    for (krate, path, _default) in krates("std") {
 //        rules.test(&krate.test_step, path)
 //             .dep(|s| s.name("libtest"))
@@ -714,22 +961,6 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
 //         .default(true)
 //         .run(move |s| check::krate(build, &s.compiler(), s.target,
 //                                    Mode::Libtest, TestKind::Test, None));
-//    for (krate, path, _default) in krates("rustc-main") {
-//        rules.test(&krate.test_step, path)
-//             .dep(|s| s.name("librustc"))
-//             .dep(|s| s.name("remote-copy-libs"))
-//             .host(true)
-//             .run(move |s| check::krate(build, &s.compiler(), s.target,
-//                                        Mode::Librustc, TestKind::Test,
-//                                        Some(&krate.name)));
-//    }
-//    rules.test("check-rustc-all", "path/to/nowhere")
-//         .dep(|s| s.name("librustc"))
-//         .dep(|s| s.name("remote-copy-libs"))
-//         .default(true)
-//         .host(true)
-//         .run(move |s| check::krate(build, &s.compiler(), s.target,
-//                                    Mode::Librustc, TestKind::Test, None));
 
 #[derive(Serialize)]
 pub struct Krate<'a> {
@@ -742,6 +973,53 @@ pub struct Krate<'a> {
 
 impl<'a> Step<'a> for Krate<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+
+    fn should_run(builder: &Builder, path: &Path) -> bool {
+        builder.crates("std").into_iter().any(|(_, krate_path)| {
+            path.ends_with(krate_path)
+        }) ||
+        builder.crates("test").into_iter().any(|(_, krate_path)| {
+            path.ends_with(krate_path)
+        })
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, host: &str, target: &str) {
+        let compiler = builder.compiler(builder.top_stage, host);
+
+        let run = |mode: Mode, name: Option<&str>| {
+            let test_kind = if builder.kind == Kind::Test {
+                TestKind::Test
+            } else if builder.kind == Kind::Bench {
+                TestKind::Bench
+            } else {
+                panic!("unexpected builder.kind in Krate: {:?}", builder.kind);
+            };
+
+            builder.ensure(Krate {
+                compiler, target,
+                mode: mode,
+                test_kind: test_kind,
+                krate: name,
+            });
+        };
+
+        if let Some(path) = path {
+            for (name, krate_path) in builder.crates("std") {
+                if path.ends_with(krate_path) {
+                    run(Mode::Libstd, Some(name));
+                }
+            }
+            for (name, krate_path) in builder.crates("test") {
+                if path.ends_with(krate_path) {
+                    run(Mode::Libtest, Some(name));
+                }
+            }
+        } else {
+            run(Mode::Libstd, None);
+            run(Mode::Libtest, None);
+        }
+    }
 
     /// Run all unit tests plus documentation tests for an entire crate DAG defined
     /// by a `Cargo.toml`
@@ -759,6 +1037,8 @@ fn run(self, builder: &Builder) {
         let test_kind = self.test_kind;
         let krate = self.krate;
 
+        builder.ensure(compile::Test { compiler, target });
+        builder.ensure(RemoteCopyLibs { compiler, target });
         let (name, path, features, root) = match mode {
             Mode::Libstd => {
                 ("libstd", "src/libstd", build.std_features(), "std")
@@ -782,7 +1062,7 @@ fn run(self, builder: &Builder) {
         // stage1. Reflect that here by updating the compiler that we're working
         // with automatically.
         let compiler = if build.force_use_stage1(compiler, target) {
-            Compiler::new(1, compiler.host)
+            builder.compiler(1, compiler.host)
         } else {
             compiler.clone()
         };
@@ -855,7 +1135,7 @@ fn run(self, builder: &Builder) {
             krate_emscripten(build, &compiler, target, mode);
         } else if build.remote_tested(target) {
             build.run(&mut cargo);
-            krate_remote(build, &compiler, target, mode);
+            krate_remote(builder, &compiler, target, mode);
         } else {
             cargo.args(&build.flags.cmd.test_args());
             try_run(build, &mut cargo);
@@ -882,15 +1162,14 @@ fn krate_emscripten(build: &Build,
     }
 }
 
-fn krate_remote(build: &Build,
+fn krate_remote(build: &Builder,
                 compiler: &Compiler,
                 target: &str,
                 mode: Mode) {
     let out_dir = build.cargo_out(compiler, mode, target);
     let tests = find_tests(&out_dir.join("deps"), target);
 
-    let tool = build.tool(&Compiler::new(0, &build.build),
-                          "remote-test-client");
+    let tool = builder.tool_exe(Tool::RemoteTestClient);
     for test in tests {
         let mut cmd = Command::new(&tool);
         cmd.arg("run")
@@ -968,15 +1247,17 @@ fn run(self, builder: &Builder) {
             return
         }
 
+        builder.ensure(compile::Test { compiler, target });
+
         println!("REMOTE copy libs to emulator ({})", target);
         t!(fs::create_dir_all(build.out.join("tmp")));
 
-        let server = build.cargo_out(compiler, Mode::Tool, target)
-                          .join(exe("remote-test-server", target));
+        // FIXME: This builds the tool for the native build triple
+        // (build.build); that is probably wrong. Should build for target.
+        let server = builder.tool_exe(Tool::RemoteTestServer);
 
         // Spawn the emulator and wait for it to come online
-        let tool = build.tool(&Compiler::new(0, &build.build),
-                              "remote-test-client");
+        let tool = builder.tool_exe(Tool::RemoteTestClient);
         let mut cmd = Command::new(&tool);
         cmd.arg("spawn-emulator")
            .arg(target)
@@ -1025,6 +1306,9 @@ fn run(self, builder: &Builder) {
             return
         }
 
+        builder.ensure(dist::PlainSourceTarball);
+        builder.ensure(dist::Src);
+
         println!("Distcheck");
         let dir = build.out.join("tmp").join("distcheck");
         let _ = fs::remove_dir_all(&dir);
@@ -1077,6 +1361,9 @@ fn run(self, builder: &Builder) {
 
 impl<'a> for Step<'a> Bootstrap {
     type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+    const ONLY_BUILD: bool = true;
 
     /// Test the build system itself
     fn run(self, builder: &Builder) {
@@ -1093,4 +1380,12 @@ fn run(self, builder: &Builder) {
         cmd.arg("--").args(&build.flags.cmd.test_args());
         try_run(build, &mut cmd);
     }
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/bootstrap")
+    }
+
+    fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, _target: &str) {
+        builder.ensure(Bootstrap);
+    }
 }
index cf1e11f7ac8205f943c48d2749f61a5756939130..07a0f63e6cb9230b3891b99b0da70f7558169cb6 100644 (file)
@@ -129,6 +129,9 @@ fn crate_rule<'a, 'b>(build: &'a Build,
         rule
 }
 
+//        rules.build("libstd", "src/libstd")
+//             .dep(|s| s.name("rustc").target(s.host))
+//             .dep(|s| s.name("libstd-link"));
 //    for (krate, path, _default) in krates("std") {
 //        rules.build(&krate.build_step, path)
 //             .dep(|s| s.name("startup-objects"))
@@ -143,6 +146,21 @@ pub struct Std<'a> {
 
 impl<'a> Step<'a> for Std<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+
+    fn should_run(builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/libstd") ||
+        builder.crates("std").into_iter().any(|(_, krate_path)| {
+            path.ends_with(krate_path)
+        })
+    }
+
+    fn make_run(builder: &Builder, _path: Option<&Path>, host: &str, target: &str) {
+        builder.ensure(Std {
+            compiler: builder.compiler(builder.top_stage, host),
+            target,
+        })
+    }
 
     /// Build the standard library.
     ///
@@ -153,8 +171,23 @@ fn run(self, builder: &Builder) {
         let build = builder.build;
         let target = self.target;
         let compiler = self.compiler;
-        let libdir = build.sysroot_libdir(compiler, target);
-        t!(fs::create_dir_all(&libdir));
+
+        builder.ensure(StartupObjects { compiler, target });
+
+        if build.force_use_stage1(compiler, target) {
+            let from = builder.compiler(1, &build.build);
+            builder.ensure(Std {
+                compiler: from,
+                target: target,
+            });
+            println!("Uplifting stage1 std ({} -> {})", from.host, target);
+            builder.ensure(StdLink {
+                compiler: from,
+                target_compiler: compiler,
+                target: target,
+            });
+            return;
+        }
 
         let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
         println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
@@ -162,7 +195,7 @@ fn run(self, builder: &Builder) {
 
         let out_dir = build.cargo_out(compiler, Mode::Libstd, target);
         build.clear_if_dirty(&out_dir, &build.compiler_path(compiler));
-        let mut cargo = build.cargo(compiler, Mode::Libstd, target, "build");
+        let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "build");
         let mut features = build.std_features();
 
         if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
@@ -188,6 +221,7 @@ fn run(self, builder: &Builder) {
             // config.toml equivalent) is used
             cargo.env("LLVM_CONFIG", build.llvm_config(target));
         }
+
         cargo.arg("--features").arg(features)
             .arg("--manifest-path")
             .arg(build.src.join("src/libstd/Cargo.toml"));
@@ -206,6 +240,12 @@ fn run(self, builder: &Builder) {
         run_cargo(build,
                 &mut cargo,
                 &libstd_stamp(build, &compiler, target));
+
+        builder.ensure(StdLink {
+            compiler: builder.compiler(compiler.stage, &build.build),
+            target_compiler: compiler,
+            target: target,
+        });
     }
 }
 
@@ -219,7 +259,7 @@ fn run(self, builder: &Builder) {
 //     .dep(|s| s.name("create-sysroot").target(s.host));
 
 #[derive(Serialize)]
-pub struct StdLink<'a> {
+struct StdLink<'a> {
     pub compiler: Compiler<'a>,
     pub target_compiler: Compiler<'a>,
     pub target: &'a str,
@@ -297,6 +337,17 @@ pub struct StartupObjects<'a> {
 impl<'a> Step<'a> for StartupObjects<'a> {
     type Output = ();
 
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/rtstartup")
+    }
+
+    fn make_run(builder: &Builder, _path: Option<&Path>, host: &str, target: &str) {
+        builder.ensure(StartupObjects {
+            compiler: builder.compiler(builder.top_stage, host),
+            target,
+        })
+    }
+
     /// Build and prepare startup objects like rsbegin.o and rsend.o
     ///
     /// These are primarily used on Windows right now for linking executables/dlls.
@@ -354,6 +405,21 @@ pub struct Test<'a> {
 
 impl<'a> Step<'a> for Test<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+
+    fn should_run(builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/libtest") ||
+        builder.crates("test").into_iter().any(|(_, krate_path)| {
+            path.ends_with(krate_path)
+        })
+    }
+
+    fn make_run(builder: &Builder, _path: Option<&Path>, host: &str, target: &str) {
+        builder.ensure(Test {
+            compiler: builder.compiler(builder.top_stage, host),
+            target,
+        })
+    }
 
     /// Build libtest.
     ///
@@ -364,6 +430,23 @@ fn run(self, builder: &Builder) {
         let build = builder.build;
         let target = self.target;
         let compiler = self.compiler;
+
+        builder.ensure(Std { compiler, target });
+
+        if build.force_use_stage1(compiler, target) {
+            builder.ensure(Test {
+                compiler: builder.compiler(1, &build.build),
+                target: target,
+            });
+            println!("Uplifting stage1 test ({} -> {})", &build.build, target);
+            builder.ensure(TestLink {
+                compiler: builder.compiler(1, &build.build),
+                target_compiler: compiler,
+                target: target,
+            });
+            return;
+        }
+
         let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
         println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
                 compiler.host, target);
@@ -378,6 +461,12 @@ fn run(self, builder: &Builder) {
         run_cargo(build,
                 &mut cargo,
                 &libtest_stamp(build, compiler, target));
+
+        builder.ensure(TestLink {
+            compiler: builder.compiler(1, &build.build),
+            target_compiler: compiler,
+            target: target,
+        });
     }
 }
 
@@ -432,6 +521,22 @@ pub struct Rustc<'a> {
 
 impl<'a> Step<'a> for Rustc<'a> {
     type Output = ();
+    const ONLY_HOSTS: bool = true;
+    const DEFAULT: bool = true;
+
+    fn should_run(builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/librustc") ||
+        builder.crates("rustc-main").into_iter().any(|(_, krate_path)| {
+            path.ends_with(krate_path)
+        })
+    }
+
+    fn make_run(builder: &Builder, _path: Option<&Path>, host: &str, target: &str) {
+        builder.ensure(Rustc {
+            compiler: builder.compiler(builder.top_stage, host),
+            target,
+        })
+    }
 
     /// Build the compiler.
     ///
@@ -442,6 +547,33 @@ fn run(self, builder: &Builder) {
         let build = builder.build;
         let compiler = self.compiler;
         let target = self.target;
+
+        builder.ensure(Test { compiler, target });
+
+        // Build LLVM for our target. This will implicitly build the host LLVM
+        // if necessary.
+        builder.ensure(native::Llvm { target });
+
+        if build.force_use_stage1(compiler, target) {
+            builder.ensure(Rustc {
+                compiler: builder.compiler(1, &build.build),
+                target: target,
+            });
+            println!("Uplifting stage1 rustc ({} -> {})", &build.build, target);
+            builder.ensure(RustcLink {
+                compiler: builder.compiler(1, &build.build),
+                target_compiler: compiler,
+                target,
+            });
+            return;
+        }
+
+        // Ensure that build scripts have a std to link against.
+        builder.ensure(Std {
+            compiler: builder.compiler(self.compiler.stage, &build.build),
+            target: &build.build,
+        });
+
         let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
         println!("Building stage{} compiler artifacts ({} -> {})",
                  compiler.stage, compiler.host, target);
@@ -513,6 +645,12 @@ fn run(self, builder: &Builder) {
         run_cargo(build,
                   &mut cargo,
                   &librustc_stamp(build, compiler, target));
+
+        builder.ensure(RustcLink {
+            compiler: builder.compiler(compiler.stage, &build.build),
+            target_compiler: compiler,
+            target,
+        });
     }
 }
 
@@ -523,7 +661,7 @@ fn run(self, builder: &Builder) {
 //            compile::rustc_link)
 //     .dep(|s| s.name("libtest-link"));
 #[derive(Serialize)]
-pub struct RustcLink<'a> {
+struct RustcLink<'a> {
     pub compiler: Compiler<'a>,
     pub target_compiler: Compiler<'a>,
     pub target: &'a str,
@@ -551,19 +689,19 @@ fn run(self, builder: &Builder) {
 
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
-fn libstd_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
+pub fn libstd_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
     build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp")
 }
 
 /// Cargo's output path for libtest in a given stage, compiled by a particular
 /// compiler for the specified target.
-fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
+pub fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
     build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp")
 }
 
 /// Cargo's output path for librustc in a given stage, compiled by a particular
 /// compiler for the specified target.
-fn librustc_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
+pub fn librustc_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
     build.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp")
 }
 
@@ -582,7 +720,7 @@ pub struct Sysroot<'a> {
 }
 
 impl<'a> Step<'a> for Sysroot<'a> {
-    type Output = ();
+    type Output = PathBuf;
 
     /// Returns the sysroot for the `compiler` specified that *this build system
     /// generates*.
@@ -590,12 +728,17 @@ impl<'a> Step<'a> for Sysroot<'a> {
     /// That is, the sysroot for the stage0 compiler is not what the compiler
     /// thinks it is by default, but it's the same as the default for stages
     /// 1-3.
-    fn run(self, builder: &Builder) {
+    fn run(self, builder: &Builder) -> PathBuf {
         let build = builder.build;
         let compiler = self.compiler;
-        let sysroot = build.sysroot(compiler);
+        let sysroot = if compiler.stage == 0 {
+            build.out.join(compiler.host).join("stage0-sysroot")
+        } else {
+            build.out.join(compiler.host).join(format!("stage{}", compiler.stage))
+        };
         let _ = fs::remove_dir_all(&sysroot);
         t!(fs::create_dir_all(&sysroot));
+        sysroot
     }
 }
 
@@ -615,8 +758,11 @@ fn run(self, builder: &Builder) {
 
 #[derive(Serialize)]
 pub struct Assemble<'a> {
-    pub stage: u32,
-    pub host: &'a str,
+    /// The compiler which we will produce in this step. Assemble itself will
+    /// take care of ensuring that the necessary prerequisites to do so exist,
+    /// that is, this target can be a stage2 compiler and Assemble will build
+    /// previous stages for you.
+    pub target_compiler: Compiler<'a>,
 }
 
 impl<'a> Step<'a> for Assemble<'a> {
@@ -629,20 +775,48 @@ impl<'a> Step<'a> for Assemble<'a> {
     /// compiler.
     fn run(self, builder: &Builder) {
         let build = builder.build;
-        let stage = self.stage;
-        let host = self.host;
-        // nothing to do in stage0
-        if stage == 0 {
-            return
+        let target_compiler = self.target_compiler;
+
+        if target_compiler.stage == 0 {
+            assert_eq!(build.build, target_compiler.host,
+                "Cannot obtain compiler for non-native build triple at stage 0");
+            // The stage 0 compiler for the build triple is always pre-built.
+            return target_compiler;
         }
 
-        println!("Copying stage{} compiler ({})", stage, host);
+        // Get the compiler that we'll use to bootstrap ourselves.
+        let build_compiler = if target_compiler.host != build.build {
+            // Build a compiler for the host platform. We cannot use the stage0
+            // compiler for the host platform for this because it doesn't have
+            // the libraries we need.  FIXME: Perhaps we should download those
+            // libraries? It would make builds faster...
+            builder.ensure(Assemble {
+                target_compiler: Compiler {
+                    // FIXME: It may be faster if we build just a stage 1
+                    // compiler and then use that to bootstrap this compiler
+                    // forward.
+                    stage: target_compiler.stage - 1,
+                    host: &build.build
+                },
+            })
+        } else {
+            // Build the compiler we'll use to build the stage requested. This
+            // may build more than one compiler (going down to stage 0).
+            builder.ensure(Assemble {
+                target_compiler: target_compiler.with_stage(target_compiler.stage - 1),
+            })
+        };
 
-        // The compiler that we're assembling
-        let target_compiler = Compiler::new(stage, host);
+        // Build the libraries for this compiler to link to (i.e., the libraries
+        // it uses at runtime). NOTE: Crates the target compiler compiles don't
+        // link to these. (FIXME: Is that correct? It seems to be correct most
+        // of the time but I think we do link to these for stage2/bin compilers
+        // when not performing a full bootstrap).
+        builder.ensure(Rustc { compiler: build_compiler, target: target_compiler.host });
 
-        // The compiler that compiled the compiler we're assembling
-        let build_compiler = Compiler::new(stage - 1, &build.build);
+        let stage = target_compiler.stage;
+        let host = target_compiler.host;
+        println!("Assembling stage{} compiler ({})", stage, host);
 
         // Link in all dylibs to the libdir
         let sysroot = build.sysroot(&target_compiler);
index 8aa9ad7021e6f632511b02a6e8b77ea00232fd2c..da513b1f2f66929d812599df6afc74188f9c99a5 100644 (file)
@@ -76,6 +76,19 @@ pub struct Docs<'a> {
 
 impl<'a> Step<'a> for Docs<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_BUILD_TARGETS: bool = true;
+
+    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) {
+        builder.ensure(Docs {
+            stage: builder.top_stage,
+            host: target,
+        });
+    }
 
     /// Builds the `rust-docs` installer component.
     ///
@@ -85,6 +98,8 @@ fn run(self, builder: &Builder) {
         let stage = self.stage;
         let host = self.host;
 
+        builder.default_doc(None);
+
         println!("Dist docs stage{} ({})", stage, host);
         if !build.config.docs {
             println!("\tskipping - docs disabled");
@@ -268,6 +283,18 @@ pub struct Mingw<'a> {
 
 impl<'a> Step<'a> for Mingw<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_BUILD_TARGETS: bool = true;
+
+    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,
+        });
+    }
 
     /// Build the `rust-mingw` installer component.
     ///
@@ -276,6 +303,11 @@ impl<'a> Step<'a> for Mingw<'a> {
     fn run(self, builder: &Builder) {
         let build = builder.build;
         let host = self.host;
+
+        if !host.contains("pc-windows-gnu") {
+            return;
+        }
+
         println!("Dist mingw ({})", host);
         let name = pkgname(build, "rust-mingw");
         let image = tmpdir(build).join(format!("{}-{}-image", name, host));
@@ -320,6 +352,20 @@ pub struct Rustc<'a> {
 
 impl<'a> Step<'a> for Rustc<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+    const ONLY_BUILD_TARGETS: bool = true;
+
+    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) {
+        builder.ensure(Rustc {
+            stage: builder.top_stage,
+            host: host,
+        });
+    }
 
     /// Creates the `rustc` installer component.
     fn run(self, builder: &builder) {
@@ -334,7 +380,7 @@ fn run(self, builder: &builder) {
         let _ = fs::remove_dir_all(&overlay);
 
         // Prepare the rustc "image", what will actually end up getting installed
-        prepare_image(build, stage, host, &image);
+        prepare_image(builder, stage, host, &image);
 
         // Prepare the overlay which is part of the tarball but won't actually be
         // installed
@@ -384,8 +430,9 @@ fn run(self, builder: &builder) {
         t!(fs::remove_dir_all(&image));
         t!(fs::remove_dir_all(&overlay));
 
-        fn prepare_image(build: &Build, stage: u32, host: &str, image: &Path) {
-            let src = build.sysroot(&Compiler::new(stage, host));
+        fn prepare_image(builder: &Builder, stage: u32, host: &str, image: &Path) {
+            let build = builder.build;
+            let src = build.sysroot(builder.compiler(stage, host));
             let libdir = libdir(host);
 
             // Copy rustc/rustdoc binaries
@@ -409,7 +456,10 @@ fn prepare_image(build: &Build, stage: u32, host: &str, image: &Path) {
             cp_r(&build.src.join("man"), &image.join("share/man/man1"));
 
             // Debugger scripts
-            debugger_scripts(build, &image, host);
+            builder.ensure(DebuggerScripts {
+                sysroot: &image,
+                host: host,
+            });
 
             // Misc license info
             let cp = |file: &str| {
@@ -423,8 +473,6 @@ fn prepare_image(build: &Build, 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()),
 //                                     s.target));
@@ -438,6 +486,18 @@ pub struct DebuggerScripts<'a> {
 impl<'a> Step<'a> for DebuggerScripts<'a> {
     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) {
+        builder.ensure(DebuggerScripts {
+            // FIXME: builder.top_stage is likely wrong in some cases.
+            sysroot: &builder.sysroot(builder.compiler(builder.top_stage, host)),
+            host: host,
+        });
+    }
+
     /// Copies debugger scripts for `host` into the `sysroot` specified.
     fn run(self, builder: &Builder) {
         let build = builder.build;
@@ -542,6 +602,22 @@ pub struct Analysis<'a> {
 
 impl<'a> Step<'a> for Analysis<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_BUILD_TARGETS: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("analysis")
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, host: &str, target: &str) {
+        if path.is_none() && !builder.build.config.extended {
+            return;
+        }
+        builder.ensure(Analysis {
+            compiler: builder.compiler(builder.top_stage, host),
+            target: target,
+        });
+    }
 
     /// Creates a tarball of save-analysis metadata, if available.
     fn run(self, builder: &Builder) {
@@ -559,7 +635,7 @@ fn run(self, builder: &Builder) {
         // Package save-analysis from stage1 if not doing a full bootstrap, as the
         // stage2 artifacts is simply copied from stage1 in that case.
         let compiler = if build.force_use_stage1(compiler, target) {
-            Compiler::new(1, compiler.host)
+            builder.compiler(1, compiler.host)
         } else {
             compiler.clone()
         };
@@ -567,7 +643,8 @@ fn run(self, builder: &Builder) {
         let name = pkgname(build, "rust-analysis");
         let image = tmpdir(build).join(format!("{}-{}-image", name, target));
 
-        let src = build.stage_out(&compiler, Mode::Libstd).join(target).join("release").join("deps");
+        let src = build.stage_out(compiler, Mode::Libstd)
+            .join(target).join("release").join("deps");
 
         let image_src = src.join("save-analysis");
         let dst = image.join("lib/rustlib").join(target).join("analysis");
@@ -644,6 +721,18 @@ fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
 
 impl<'a> Step<'a> for Src {
     type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+    const ONLY_BUILD_TARGETS: bool = true;
+    const ONLY_BUILD: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src")
+    }
+
+    fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, _target: &str) {
+        builder.ensure(Src);
+    }
 
     /// Creates the `rust-src` installer component
     fn run(self, builder: &Builder) {
@@ -727,6 +816,22 @@ fn run(self, builder: &Builder) {
 
 impl<'a> Step<'a> for PlainSourceTarball {
     type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+    const ONLY_BUILD_TARGETS: bool = true;
+    const ONLY_BUILD: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src")
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, _host: &str, _target: &str) {
+        if path.is_none() && !builder.build.config.rust_dist_src {
+            return;
+        }
+
+        builder.ensure(PlainSourceTarball);
+    }
 
     /// Creates the plain source tarball
     fn run(self, builder: &Builder) {
@@ -862,13 +967,29 @@ pub struct Cargo<'a> {
 
 impl<'a> Step<'a> for Cargo<'a> {
     type Output = ();
+    const ONLY_BUILD_TARGETS: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("cargo")
+    }
+
+    fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, target: &str) {
+        builder.ensure(Cargo {
+            stage: builder.top_stage,
+            target: target,
+        });
+    }
 
     fn run(self, builder: &Builder) {
         let build = builder.build;
         let stage = self.stage;
         let target = self.target;
+
+        builder.ensure(tool::Cargo { stage, target });
+
         println!("Dist cargo stage{} ({})", stage, target);
-        let compiler = Compiler::new(stage, &build.build);
+        let compiler = builder.compiler(stage, &build.build);
 
         let src = build.src.join("src/tools/cargo");
         let etc = src.join("src/etc");
@@ -941,14 +1062,30 @@ pub struct Rls<'a> {
 
 impl<'a> Step<'a> for Rls<'a> {
     type Output = ();
+    const ONLY_BUILD_TARGETS: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("rls")
+    }
+
+    fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, target: &str) {
+        builder.ensure(Rls {
+            stage: builder.top_stage,
+            target: target,
+        });
+    }
 
     fn run(self, builder: &Builder) {
         let build = builder.build;
         let stage = self.stage;
         let target = self.target;
         assert!(build.config.extended);
+
+        builder.ensure(tool::Rls { stage, target });
+
         println!("Dist RLS stage{} ({})", stage, target);
-        let compiler = Compiler::new(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");
@@ -1017,12 +1154,38 @@ pub struct Extended<'a> {
 
 impl<'a> Step<'a> for Extended<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_BUILD_TARGETS: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("cargo")
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, host: &str, target: &str) {
+        if path.is_none() && !builder.build.config.extended {
+            return;
+        }
+        builder.ensure(Extended {
+            compiler: builder.compiler(builder.top_stage, host),
+            target: target,
+        });
+    }
 
     /// Creates a combined installer for the specified target in the provided stage.
     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 });
 
         println!("Dist extended stage{} ({})", stage, target);
 
@@ -1420,11 +1583,21 @@ fn add_env(build: &Build, cmd: &mut Command, target: &str) {
 
 impl<'a> Step<'a> for HashSign {
     type Output = ();
+    const ONLY_BUILD_TARGETS: bool = true;
+    const ONLY_HOSTS: bool = true;
+    const ONLY_BUILD: bool = true;
+
+    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) {
+        builder.ensure(HashSign);
+    }
 
     fn run(self, builder: &Builder) {
         let build = builder.build;
-        let compiler = Compiler::new(0, &build.build);
-        let mut cmd = build.tool_cmd(&compiler, "build-manifest");
+        let mut cmd = builder.tool_cmd(Tool::BuildManifest);
         let sign = build.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
             panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")
         });
index 466d63a15acbdd6ce23d2970aa114ccf0f58cd4b..11edee6234459342262fa54d1955c269691f4e85 100644 (file)
 use util::{cp_r, symlink_dir};
 use build_helper::up_to_date;
 
-// rules.doc("doc-nomicon", "src/doc/nomicon")
-//      .dep(move |s| {
-//          s.name("tool-rustbook")
-//           .host(&build.build)
-//           .target(&build.build)
-//           .stage(0)
-//      })
-//      .default(build.config.docs)
-//      .run(move |s| doc::rustbook(build, s.target, "nomicon"));
-// rules.doc("doc-reference", "src/doc/reference")
-//      .dep(move |s| {
-//          s.name("tool-rustbook")
-//           .host(&build.build)
-//           .target(&build.build)
-//           .stage(0)
-//      })
-//      .default(build.config.docs)
-//      .run(move |s| doc::rustbook(build, s.target, "reference"));
+macro_rules! book {
+    ($($name:ident, $path:expr, $book_name:expr;)+) => {
+        $(
+        #[derive(Serialize)]
+        pub struct $name<'a> {
+            target: &'a str,
+        }
+
+        impl<'a> Step<'a> for $name<'a> {
+            type Output = ();
+            const NAME: &'static str = concat!(stringify!($book_name), " - book");
+            const DEFAULT: bool = true;
+
+            fn should_run(_builder: &Builder, path: &Path) -> bool {
+                path.ends_with($path)
+            }
+
+            fn make_run(builder: &Builder, path: Option<&Path>, _host: &str, target: &str) {
+                if path.is_none() && !builder.build.config.docs {
+                    // Not a default rule if docs are disabled.
+                    return;
+                }
+
+                builder.ensure($name {
+                    target,
+                });
+            }
+
+            fn run(self, builder: &Builder) {
+                builder.ensure(Rustbook {
+                    target: self.target,
+                    name: $book_name,
+                })
+            }
+        }
+        )+
+    }
+}
+
+book!(
+    // rules.doc("doc-nomicon", "src/doc/nomicon")
+    //      .dep(move |s| {
+    //          s.name("tool-rustbook")
+    //           .host(&build.build)
+    //           .target(&build.build)
+    //           .stage(0)
+    //      })
+    //      .default(build.config.docs)
+    //      .run(move |s| doc::rustbook(build, s.target, "nomicon"));
+    Nomicon, "src/doc/book", "nomicon";
+    // rules.doc("doc-reference", "src/doc/reference")
+    //      .dep(move |s| {
+    //          s.name("tool-rustbook")
+    //           .host(&build.build)
+    //           .target(&build.build)
+    //           .stage(0)
+    //      })
+    //      .default(build.config.docs)
+    //      .run(move |s| doc::rustbook(build, s.target, "reference"));
+    Reference, "src/doc/reference", "reference";
+);
 
 #[derive(Serialize)]
-pub struct Rustbook<'a> {
+struct Rustbook<'a> {
     target: &'a str,
     name: &'a str,
 }
@@ -60,11 +103,12 @@ impl<'a> Step<'a> for Rustbook<'a> {
     /// This will not actually generate any documentation if the documentation has
     /// already been generated.
     fn run(self, builder: &Builder) {
-        let build = builder.build;
-        let target = self.target;
-        let name = self.name;
-        let src = build.src.join("src/doc");
-        rustbook_src(build, target, name, &src);
+        let src = builder.build.src.join("src/doc");
+        builder.ensure(RustbookSrc {
+            target: self.target,
+            name: self.name,
+            src: &src,
+        });
     }
 }
 
@@ -81,6 +125,42 @@ fn run(self, builder: &Builder) {
 //                                     s.target,
 //                                     "unstable-book",
 //                                     &build.md_doc_out(s.target)));
+#[derive(Serialize)]
+pub struct UnstableBook<'a> {
+    target: &'a str,
+}
+
+impl<'a> Step<'a> for UnstableBook<'a> {
+    type Output = ();
+    const NAME: &'static str = "unstable book documentation";
+    const DEFAULT: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/doc/unstable-book")
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, _host: &str, target: &str) {
+        if path.is_none() && !builder.build.config.docs {
+            // Not a default rule if docs are disabled.
+            return;
+        }
+
+        builder.ensure(UnstableBook {
+            target,
+        });
+    }
+
+    fn run(self, builder: &Builder) {
+        builder.ensure(UnstableBookGen {
+            target: self.target,
+        });
+        builder.ensure(RustbookSrc {
+            target: self.target,
+            name: "unstable-book",
+            src: &builder.build.md_doc_out(self.target),
+        })
+    }
+}
 
 #[derive(Serialize)]
 pub struct RustbookSrc<'a> {
@@ -105,16 +185,15 @@ fn run(self, builder: &Builder) {
         t!(fs::create_dir_all(&out));
 
         let out = out.join(name);
-        let compiler = Compiler::new(0, &build.build);
         let src = src.join(name);
         let index = out.join("index.html");
-        let rustbook = build.tool(&compiler, "rustbook");
+        let rustbook = builder.tool_exe(Tool::Rustbook);
         if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
             return
         }
         println!("Rustbook ({}) - {}", target, name);
         let _ = fs::remove_dir_all(&out);
-        build.run(build.tool_cmd(&compiler, "rustbook")
+        build.run(builder.tool_cmd(Tool::Rustbook)
                        .arg("build")
                        .arg(&src)
                        .arg("-d")
@@ -154,10 +233,16 @@ fn run(self, builder: &Builder) {
         let target = self.target;
         let name = self.name;
         // build book first edition
-        rustbook(build, target, &format!("{}/first-edition", name));
+        builder.ensure(Rustbook {
+            target: target,
+            name: &format!("{}/first-edition", name),
+        });
 
         // build book second edition
-        rustbook(build, target, &format!("{}/second-edition", name));
+        builder.ensure(Rustbook {
+            target: target,
+            name: &format!("{}/second-edition", name),
+        });
 
         // build the index page
         let index = format!("{}/index.md", name);
@@ -238,6 +323,22 @@ pub struct Standalone<'a> {
 
 impl<'a> Step<'a> for Standalone<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+
+    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) {
+        if path.is_none() && !builder.build.config.docs {
+            // Not a default rule if docs are disabled.
+            return;
+        }
+
+        builder.ensure(Standalone {
+            target,
+        });
+    }
 
     /// Generates all standalone documentation as compiled by the rustdoc in `stage`
     /// for the `target` into `out`.
@@ -254,7 +355,7 @@ fn run(self, builder: &Builder) {
         let out = build.doc_out(target);
         t!(fs::create_dir_all(&out));
 
-        let compiler = Compiler::new(0, &build.build);
+        let compiler = builder.compiler(0, &build.build);
 
         let favicon = build.src.join("src/doc/favicon.inc");
         let footer = build.src.join("src/doc/footer.inc");
@@ -329,6 +430,34 @@ pub struct Std<'a> {
 
 impl<'a> Step<'a> for Std<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+
+    fn should_run(builder: &Builder, path: &Path) -> bool {
+        builder.crates("std").into_iter().any(|(_, krate_path)| {
+            path.ends_with(krate_path)
+        })
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, _host: &str, target: &str) {
+        let run = || {
+            builder.ensure(Std {
+                stage: builder.top_stage,
+                target
+            });
+        };
+
+        if let Some(path) = path {
+            for (_, krate_path) in builder.crates("std") {
+                if path.ends_with(krate_path) {
+                    run();
+                }
+            }
+        } else {
+            if builder.build.config.docs {
+                run();
+            }
+        }
+    }
 
     /// Compile all standard library documentation.
     ///
@@ -341,12 +470,14 @@ fn run(self, builder: &Builder) {
         println!("Documenting stage{} std ({})", stage, target);
         let out = build.doc_out(target);
         t!(fs::create_dir_all(&out));
-        let compiler = Compiler::new(stage, &build.build);
-        let compiler = if build.force_use_stage1(&compiler, target) {
-            Compiler::new(1, compiler.host)
+        let compiler = builder.compiler(stage, &build.build);
+        let compiler = if build.force_use_stage1(compiler, target) {
+            builder.compiler(1, compiler.host)
         } else {
             compiler
         };
+
+        builder.ensure(compile::Std { compiler, target });
         let out_dir = build.stage_out(&compiler, Mode::Libstd)
                            .join(target).join("doc");
         let rustdoc = build.rustdoc(&compiler);
@@ -410,6 +541,34 @@ pub struct Test<'a> {
 
 impl<'a> Step<'a> for Test<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+
+    fn should_run(builder: &Builder, path: &Path) -> bool {
+        builder.crates("test").into_iter().any(|(_, krate_path)| {
+            path.ends_with(krate_path)
+        })
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, _host: &str, target: &str) {
+        let run = || {
+            builder.ensure(Test {
+                stage: builder.top_stage,
+                target
+            });
+        };
+
+        if let Some(path) = path {
+            for (_, krate_path) in builder.crates("test") {
+                if path.ends_with(krate_path) {
+                    run();
+                }
+            }
+        } else {
+            if builder.build.config.docs {
+                run();
+            }
+        }
+    }
 
     /// Compile all libtest documentation.
     ///
@@ -422,12 +581,17 @@ fn run(self, builder: &Builder) {
         println!("Documenting stage{} test ({})", stage, target);
         let out = build.doc_out(target);
         t!(fs::create_dir_all(&out));
-        let compiler = Compiler::new(stage, &build.build);
-        let compiler = if build.force_use_stage1(&compiler, target) {
-            Compiler::new(1, compiler.host)
+        let compiler = builder.compiler(stage, &build.build);
+        let compiler = if build.force_use_stage1(compiler, target) {
+            builder.compiler(1, compiler.host)
         } else {
             compiler
         };
+
+        // Build libstd docs so that we generate relative links
+        builder.ensure(Std { stage, target });
+
+        builder.ensure(compile::Test { compiler, target });
         let out_dir = build.stage_out(&compiler, Mode::Libtest)
                            .join(target).join("doc");
         let rustdoc = build.rustdoc(&compiler);
@@ -464,6 +628,35 @@ pub struct Rustc<'a> {
 
 impl<'a> Step<'a> for Rustc<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(builder: &Builder, path: &Path) -> bool {
+        builder.crates("rustc-main").into_iter().any(|(_, krate_path)| {
+            path.ends_with(krate_path)
+        })
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, _host: &str, target: &str) {
+        let run = || {
+            builder.ensure(Rustc {
+                stage: builder.top_stage,
+                target
+            });
+        };
+
+        if let Some(path) = path {
+            for (_, krate_path) in builder.crates("rustc-main") {
+                if path.ends_with(krate_path) {
+                    run();
+                }
+            }
+        } else {
+            if builder.build.config.compiler_docs {
+                run();
+            }
+        }
+    }
 
     /// Generate all compiler documentation.
     ///
@@ -476,12 +669,17 @@ fn run(self, builder: &Builder) {
         println!("Documenting stage{} compiler ({})", stage, target);
         let out = build.doc_out(target);
         t!(fs::create_dir_all(&out));
-        let compiler = Compiler::new(stage, &build.build);
-        let compiler = if build.force_use_stage1(&compiler, target) {
-            Compiler::new(1, compiler.host)
+        let compiler = builder.compiler(stage, &build.build);
+        let compiler = if build.force_use_stage1(compiler, target) {
+            builder.compiler(1, compiler.host)
         } else {
             compiler
         };
+
+        // Build libstd docs so that we generate relative links
+        builder.ensure(Std { stage, target });
+
+        builder.ensure(compile::Rustc { compiler, target });
         let out_dir = build.stage_out(&compiler, Mode::Librustc)
                            .join(target).join("doc");
         let rustdoc = build.rustdoc(&compiler);
@@ -530,17 +728,40 @@ pub struct ErrorIndex<'a> {
 
 impl<'a> Step<'a> for ErrorIndex<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/tools/error_index_generator")
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, _host: &str, target: &str) {
+        if path.is_none() && !builder.build.config.docs {
+            // Not a default rule if docs are disabled.
+            return;
+        }
+
+        builder.ensure(ErrorIndex {
+            target,
+        });
+    }
 
     /// Generates the HTML rendered error-index by running the
     /// `error_index_generator` tool.
     fn run(self, builder: &Builder) {
         let builder = builder.build;
         let target = self.target;
+
+        builder.ensure(compile::Rustc {
+            compiler: builder.compiler(0, &build.build),
+            target,
+        });
+
         println!("Documenting error index ({})", target);
         let out = build.doc_out(target);
         t!(fs::create_dir_all(&out));
         let compiler = Compiler::new(0, &build.build);
-        let mut index = build.tool_cmd(&compiler, "error_index_generator");
+        let mut index = builder.tool_cmd(Tool::ErrorIndex);
         index.arg("html");
         index.arg(out.join("error-index.html"));
 
@@ -570,10 +791,33 @@ pub struct UnstableBookGen<'a> {
 
 impl<'a> Step<'a> for UnstableBookGen<'a> {
     type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/doc/unstable-book")
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, _host: &str, target: &str) {
+        if path.is_none() && !builder.build.config.docs {
+            // Not a default rule if docs are disabled.
+            return;
+        }
+
+        builder.ensure(UnstableBookGen {
+            target,
+        });
+    }
 
     fn run(self, builder: &Builder) {
         let build = builder.build;
         let target = self.target;
+
+        builder.ensure(compile::Std {
+            compiler: builder.compiler(builder.top_stage, &build.build),
+            target,
+        });
+
         println!("Generating unstable book md files ({})", target);
         let out = build.md_doc_out(target).join("unstable-book");
         t!(fs::create_dir_all(&out));
index 638b0613bf2ccf6c5b50e340ccdf0d9809130752..3e895bbe90017f587bd291616155a2058b35e541 100644 (file)
@@ -148,45 +148,124 @@ fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
     }
     ret
 }
-/*
-rules.install("install-docs", "src/doc")
-     .default(build.config.docs)
-     .only_host_build(true)
-     .dep(|s| s.name("dist-docs"))
-     .run(move |s| install::Installer::new(build).install_docs(s.stage, s.target));
-rules.install("install-std", "src/libstd")
-     .default(true)
-     .only_host_build(true)
-     .dep(|s| s.name("dist-std"))
-     .run(move |s| install::Installer::new(build).install_std(s.stage));
-rules.install("install-cargo", "cargo")
-     .default(build.config.extended)
-     .host(true)
-     .only_host_build(true)
-     .dep(|s| s.name("dist-cargo"))
-     .run(move |s| install::Installer::new(build).install_cargo(s.stage, s.target));
-rules.install("install-rls", "rls")
-     .default(build.config.extended)
-     .host(true)
-     .only_host_build(true)
-     .dep(|s| s.name("dist-rls"))
-     .run(move |s| install::Installer::new(build).install_rls(s.stage, s.target));
-rules.install("install-analysis", "analysis")
-     .default(build.config.extended)
-     .only_host_build(true)
-     .dep(|s| s.name("dist-analysis"))
-     .run(move |s| install::Installer::new(build).install_analysis(s.stage, s.target));
-rules.install("install-src", "src")
-     .default(build.config.extended)
-     .host(true)
-     .only_build(true)
-     .only_host_build(true)
-     .dep(|s| s.name("dist-src"))
-     .run(move |s| install::Installer::new(build).install_src(s.stage));
-rules.install("install-rustc", "src/librustc")
-     .default(true)
-     .host(true)
-     .only_host_build(true)
-     .dep(|s| s.name("dist-rustc"))
-     .run(move |s| install::Installer::new(build).install_rustc(s.stage, s.target));
-*/
+
+macro_rules! install {
+    ($($name:ident,
+       $path:expr,
+       $default_cond:expr,
+       only_hosts: $only_hosts:expr,
+       ($sel:ident, $builder:ident),
+       $run_item:block $(, $c:ident)*;)+) => {
+        $(#[derive(Serialize)]
+        pub struct $name<'a> {
+            pub stage: u32,
+            pub target: &'a str,
+            pub host: &'a str,
+        }
+
+        impl<'a> Step<'a> for $name<'a> {
+            type Output = ();
+            const NAME: &'static str = concat!("install ", stringify!($name));
+            const DEFAULT: bool = true;
+            const ONLY_BUILD_TARGETS: bool = true;
+            const ONLY_HOSTS: bool = $only_hosts;
+            $(const $c: bool = true;)*
+
+            fn should_run(_builder: &Builder, path: &Path) -> bool {
+                path.ends_with($path)
+            }
+
+            fn make_run($builder: &Builder, path: Option<&Path>, host: &str, target: &str) {
+                if path.is_none() && !($default_cond) {
+                    return;
+                }
+                $builder.ensure($name {
+                    stage: $builder.top_stage,
+                    target,
+                    host,
+                });
+            }
+
+            fn run($sel, $builder: &Builder) {
+                $run_item
+            }
+        })+
+    }
+}
+
+install!(
+    // rules.install("install-docs", "src/doc")
+    //      .default(build.config.docs)
+    //      .only_host_build(true)
+    //      .dep(|s| s.name("dist-docs"))
+    //      .run(move |s| install::Installer::new(build).install_docs(s.stage, s.target));
+    Docs, "src/doc", builder.build.config.docs, only_hosts: false, (self, builder), {
+        builder.ensure(dist::Docs { stage: self.stage, host: self.host });
+        Installer::new(builder.build).install_docs(self.stage, self.target);
+    };
+    // rules.install("install-std", "src/libstd")
+    //      .default(true)
+    //      .only_host_build(true)
+    //      .dep(|s| s.name("dist-std"))
+    //      .run(move |s| install::Installer::new(build).install_std(s.stage));
+    Std, "src/libstd", true, only_hosts: true, (self, builder), {
+        builder.ensure(dist::Std {
+            compiler: builder.compiler(self.stage, self.host),
+            target: self.target
+        });
+        Installer::new(builder.build).install_std(self.stage);
+    };
+    // rules.install("install-cargo", "cargo")
+    //      .default(build.config.extended)
+    //      .host(true)
+    //      .only_host_build(true)
+    //      .dep(|s| s.name("dist-cargo"))
+    //      .run(move |s| install::Installer::new(build).install_cargo(s.stage, s.target));
+    Cargo, "cargo", builder.build.config.extended, only_hosts: true, (self, builder), {
+        builder.ensure(dist::Cargo { stage: self.stage, target: self.target });
+        Installer::new(builder.build).install_cargo(self.stage, self.target);
+    };
+    // rules.install("install-rls", "rls")
+    //      .default(build.config.extended)
+    //      .host(true)
+    //      .only_host_build(true)
+    //      .dep(|s| s.name("dist-rls"))
+    //      .run(move |s| install::Installer::new(build).install_rls(s.stage, s.target));
+    Rls, "rls", builder.build.config.extended, only_hosts: true, (self, builder), {
+        builder.ensure(dist::Rls { stage: self.stage, target: self.target });
+        Installer::new(builder.build).install_rls(self.stage, self.target);
+    };
+    // rules.install("install-analysis", "analysis")
+    //      .default(build.config.extended)
+    //      .only_host_build(true)
+    //      .dep(|s| s.name("dist-analysis"))
+    //      .run(move |s| install::Installer::new(build).install_analysis(s.stage, s.target));
+    Analysis, "analysis", builder.build.config.extended, only_hosts: false, (self, builder), {
+        builder.ensure(dist::Analysis {
+            compiler: builder.compiler(self.stage, self.host),
+            target: self.target
+        });
+        Installer::new(builder.build).install_analysis(self.stage, self.target);
+    };
+    // rules.install("install-src", "src")
+    //      .default(build.config.extended)
+    //      .host(true)
+    //      .only_build(true)
+    //      .only_host_build(true)
+    //      .dep(|s| s.name("dist-src"))
+    //      .run(move |s| install::Installer::new(build).install_src(s.stage));
+    Src, "src", builder.build.config.extended, only_hosts: true, (self, builder), {
+        builder.ensure(dist::Src);
+        Installer::new(builder.build).install_src(self.stage);
+    }, ONLY_BUILD;
+    // rules.install("install-rustc", "src/librustc")
+    //      .default(true)
+    //      .host(true)
+    //      .only_host_build(true)
+    //      .dep(|s| s.name("dist-rustc"))
+    //      .run(move |s| install::Installer::new(build).install_rustc(s.stage, s.target));
+    Rustc, "src/librustc", builder.build.config.extended, only_hosts: true, (self, builder), {
+        builder.ensure(dist::Rustc { stage: self.stage, host: self.host });
+        Installer::new(builder.build).install_rustc(self.stage, self.target);
+    };
+);
index 6ae5c03bfeb4c8b86a039f99d4c641fcee659ee2..2b44f33db8e182c3f821617f51eada8b6a935564 100644 (file)
@@ -33,7 +33,7 @@
 use util;
 use build_helper::up_to_date;
 
-/j/ rules.build("llvm", "src/llvm")
+// rules.build("llvm", "src/llvm")
 //      .host(true)
 //      .dep(move |s| {
 //          if s.target == build.build {
@@ -51,6 +51,7 @@ pub struct Llvm<'a> {
 
 impl<'a> Step<'a> for Llvm<'a> {
     type Output = ();
+    const ONLY_HOSTS: bool = true;
 
     /// Compile LLVM for `target`.
     fn run(self, builder: &Builder) {
@@ -151,6 +152,7 @@ fn run(self, builder: &Builder) {
 
         // http://llvm.org/docs/HowToCrossCompileLLVM.html
         if target != build.build {
+            builder.ensure(Llvm { target: &build.build });
             // FIXME: if the llvm root for the build triple is overridden then we
             //        should use llvm-tblgen from there, also should verify that it
             //        actually exists most of the time in normal installs of LLVM.
@@ -249,6 +251,14 @@ pub struct TestHelpers<'a> {
 impl<'a> Step<'a> for TestHelpers<'a> {
     type Output = ();
 
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/rt/rust_test_helpers.c")
+    }
+
+    fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, target: &str) {
+        builder.ensure(TestHelpers { target })
+    }
+
     /// Compiles the `rust_test_helpers.c` library which we used in various
     /// `run-pass` test suites for ABI testing.
     fn run(self, builder: &Builder) {
@@ -295,12 +305,16 @@ fn run(self, builder: &Builder) {
 
 #[derive(Serialize)]
 pub struct Openssl<'a> {
-    target: &'a str,
+    pub target: &'a str,
 }
 
 impl<'a> Step<'a> for Openssl<'a> {
     type Output = ();
 
+    fn should_run(_builder: &Builder, _path: &Path) -> bool {
+        false
+    }
+
     fn run(self, builder: &Builder) {
         let build = bulder.build;
         let target = self.target;
index 52ec273c3e8cd2239f51aec83aba2bba494ec256..442ca7aadbc0583476ef90b1eda7b60d191d5ad7 100644 (file)
@@ -15,7 +15,7 @@
 use Mode;
 use builder::{Step, Builder};
 use util::{exe, add_lib_path};
-use compile::{self, stamp, Rustc};
+use compile::{self, libtest_stamp, libstd_stamp, librustc_stamp, Rustc};
 use native;
 use channel::GitInfo;
 
@@ -63,7 +63,7 @@ fn run(self, builder: &Builder) {
         let target = self.target;
         let mode = self.mode;
 
-        let compiler = Compiler::new(stage, &build.build);
+        let compiler = builder.compiler(stage, &build.build);
 
         let stamp = match mode {
             Mode::Libstd => libstd_stamp(build, &compiler, target),
@@ -76,103 +76,39 @@ fn run(self, builder: &Builder) {
     }
 }
 
-// rules.build("tool-rustbook", "src/tools/rustbook")
-//      .dep(|s| s.name("maybe-clean-tools"))
-//      .dep(|s| s.name("librustc-tool"))
-//      .run(move |s| compile::tool(build, s.stage, s.target, "rustbook"));
-// rules.build("tool-error-index", "src/tools/error_index_generator")
-//      .dep(|s| s.name("maybe-clean-tools"))
-//      .dep(|s| s.name("librustc-tool"))
-//      .run(move |s| compile::tool(build, s.stage, s.target, "error_index_generator"));
-// rules.build("tool-unstable-book-gen", "src/tools/unstable-book-gen")
-//      .dep(|s| s.name("maybe-clean-tools"))
-//      .dep(|s| s.name("libstd-tool"))
-//      .run(move |s| compile::tool(build, s.stage, s.target, "unstable-book-gen"));
-// rules.build("tool-tidy", "src/tools/tidy")
-//      .dep(|s| s.name("maybe-clean-tools"))
-//      .dep(|s| s.name("libstd-tool"))
-//      .run(move |s| compile::tool(build, s.stage, s.target, "tidy"));
-// rules.build("tool-linkchecker", "src/tools/linkchecker")
-//      .dep(|s| s.name("maybe-clean-tools"))
-//      .dep(|s| s.name("libstd-tool"))
-//      .run(move |s| compile::tool(build, s.stage, s.target, "linkchecker"));
-// rules.build("tool-cargotest", "src/tools/cargotest")
-//      .dep(|s| s.name("maybe-clean-tools"))
-//      .dep(|s| s.name("libstd-tool"))
-//      .run(move |s| compile::tool(build, s.stage, s.target, "cargotest"));
-// rules.build("tool-compiletest", "src/tools/compiletest")
-//      .dep(|s| s.name("maybe-clean-tools"))
-//      .dep(|s| s.name("libtest-tool"))
-//      .run(move |s| compile::tool(build, s.stage, s.target, "compiletest"));
-// rules.build("tool-build-manifest", "src/tools/build-manifest")
-//      .dep(|s| s.name("maybe-clean-tools"))
-//      .dep(|s| s.name("libstd-tool"))
-//      .run(move |s| compile::tool(build, s.stage, s.target, "build-manifest"));
-// rules.build("tool-remote-test-server", "src/tools/remote-test-server")
-//      .dep(|s| s.name("maybe-clean-tools"))
-//      .dep(|s| s.name("libstd-tool"))
-//      .run(move |s| compile::tool(build, s.stage, s.target, "remote-test-server"));
-// rules.build("tool-remote-test-client", "src/tools/remote-test-client")
-//      .dep(|s| s.name("maybe-clean-tools"))
-//      .dep(|s| s.name("libstd-tool"))
-//      .run(move |s| compile::tool(build, s.stage, s.target, "remote-test-client"));
-// rules.build("tool-rust-installer", "src/tools/rust-installer")
-//      .dep(|s| s.name("maybe-clean-tools"))
-//      .dep(|s| s.name("libstd-tool"))
-//      .run(move |s| compile::tool(build, s.stage, s.target, "rust-installer"));
-// rules.build("tool-cargo", "src/tools/cargo")
-//      .host(true)
-//      .default(build.config.extended)
-//      .dep(|s| s.name("maybe-clean-tools"))
-//      .dep(|s| s.name("libstd-tool"))
-//      .dep(|s| s.stage(0).host(s.target).name("openssl"))
-//      .dep(move |s| {
-//          // Cargo depends on procedural macros, which requires a full host
-//          // compiler to be available, so we need to depend on that.
-//          s.name("librustc-link")
-//           .target(&build.build)
-//           .host(&build.build)
-//      })
-//      .run(move |s| compile::tool(build, s.stage, s.target, "cargo"));
-// rules.build("tool-rls", "src/tools/rls")
-//      .host(true)
-//      .default(build.config.extended)
-//      .dep(|s| s.name("librustc-tool"))
-//      .dep(|s| s.stage(0).host(s.target).name("openssl"))
-//      .dep(move |s| {
-//          // rls, like cargo, uses procedural macros
-//          s.name("librustc-link")
-//           .target(&build.build)
-//           .host(&build.build)
-//      })
-//      .run(move |s| compile::tool(build, s.stage, s.target, "rls"));
-//
-
 #[derive(Serialize)]
-pub struct Tool<'a> {
+pub struct ToolBuild<'a> {
     pub stage: u32,
     pub target: &'a str,
     pub tool: &'a str,
+    pub mode: Mode,
 }
 
-impl<'a> Step<'a> for Tool<'a> {
-    type Output = ();
+impl<'a> Step<'a> for ToolBuild<'a> {
+    type Output = PathBuf;
 
     /// Build a tool in `src/tools`
     ///
     /// This will build the specified tool with the specified `host` compiler in
     /// `stage` into the normal cargo output directory.
-    fn run(self, builder: &Builder) {
+    fn run(self, builder: &Builder) -> PathBuf {
         let build = builder.build;
         let stage = self.stage;
         let target = self.target;
         let tool = self.tool;
 
+        let compiler = builder.compiler(stage, &build.build);
+        builder.ensure(CleanTools { stage, target, mode: self.mode });
+        match self.mode {
+            Mode::Libstd => builder.ensure(compile::Std { compiler, target }),
+            Mode::Libtest => builder.ensure(compile::Test { compiler, target }),
+            Mode::Librustc => builder.ensure(compile::Rustc { compiler, target }),
+            Mode::Tool => panic!("unexpected Mode::Tool for tool build")
+        }
+
         let _folder = build.fold_output(|| format!("stage{}-{}", stage, tool));
         println!("Building stage{} tool {} ({})", stage, tool, target);
 
-        let compiler = Compiler::new(stage, &build.build);
-
         let mut cargo = build.cargo(&compiler, Mode::Tool, target, "build");
         let dir = build.src.join("src/tools").join(tool);
         cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
@@ -201,5 +137,238 @@ fn run(self, builder: &Builder) {
         }
 
         build.run(&mut cargo);
+        build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, compiler.host))
+    }
+}
+
+macro_rules! tool {
+    ($($name:ident, $path:expr, $tool_name:expr, $mode:expr;)+) => {
+        #[derive(Copy, Clone)]
+        pub enum Tool {
+            $(
+                $name,
+            )+
+        }
+
+        impl<'a> Builder<'a> {
+            pub fn tool_exe(&self, tool: Tool) -> PathBuf {
+                match tool {
+                    $(Tool::$name =>
+                        self.ensure($name {
+                            stage: 0,
+                            target: &self.build.build,
+                        }),
+                    )+
+                }
+            }
+        }
+
+        $(
+        #[derive(Serialize)]
+        pub struct $name<'a> {
+            pub stage: u32,
+            pub target: &'a str,
+        }
+
+        impl<'a> Step<'a> for $name<'a> {
+            type Output = PathBuf;
+            const NAME: &'static str = concat!(stringify!($name), " tool");
+
+            fn should_run(_builder: &Builder, path: &Path) -> bool {
+                path.ends_with($path)
+            }
+
+            fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, target: &str) {
+                builder.ensure($name {
+                    stage: builder.top_stage,
+                    target,
+                });
+            }
+
+            fn run(self, builder: &Builder) -> PathBuf {
+                builder.ensure(ToolBuild {
+                    stage: self.stage,
+                    target: self.target,
+                    tool: $tool_name,
+                    mode: $mode,
+                })
+            }
+        }
+        )+
+    }
+}
+
+tool!(
+    // rules.build("tool-rustbook", "src/tools/rustbook")
+    //      .dep(|s| s.name("maybe-clean-tools"))
+    //      .dep(|s| s.name("librustc-tool"))
+    //      .run(move |s| compile::tool(build, s.stage, s.target, "rustbook"));
+    Rustbook, "src/tools/rustbook", "rustbook", Mode::Librustc;
+    // rules.build("tool-error-index", "src/tools/error_index_generator")
+    //      .dep(|s| s.name("maybe-clean-tools"))
+    //      .dep(|s| s.name("librustc-tool"))
+    //      .run(move |s| compile::tool(build, s.stage, s.target, "error_index_generator"));
+    ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::Librustc;
+    // rules.build("tool-unstable-book-gen", "src/tools/unstable-book-gen")
+    //      .dep(|s| s.name("maybe-clean-tools"))
+    //      .dep(|s| s.name("libstd-tool"))
+    //      .run(move |s| compile::tool(build, s.stage, s.target, "unstable-book-gen"));
+    UnstableBook, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::Libstd;
+    // rules.build("tool-tidy", "src/tools/tidy")
+    //      .dep(|s| s.name("maybe-clean-tools"))
+    //      .dep(|s| s.name("libstd-tool"))
+    //      .run(move |s| compile::tool(build, s.stage, s.target, "tidy"));
+    Tidy, "src/tools/tidy", "tidy", Mode::Libstd;
+    // rules.build("tool-linkchecker", "src/tools/linkchecker")
+    //      .dep(|s| s.name("maybe-clean-tools"))
+    //      .dep(|s| s.name("libstd-tool"))
+    //      .run(move |s| compile::tool(build, s.stage, s.target, "linkchecker"));
+    Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::Libstd;
+    // rules.build("tool-cargotest", "src/tools/cargotest")
+    //      .dep(|s| s.name("maybe-clean-tools"))
+    //      .dep(|s| s.name("libstd-tool"))
+    //      .run(move |s| compile::tool(build, s.stage, s.target, "cargotest"));
+    CargoTest, "src/tools/cargotest", "cargotest", Mode::Libstd;
+    // rules.build("tool-compiletest", "src/tools/compiletest")
+    //      .dep(|s| s.name("maybe-clean-tools"))
+    //      .dep(|s| s.name("libtest-tool"))
+    //      .run(move |s| compile::tool(build, s.stage, s.target, "compiletest"));
+    Compiletest, "src/tools/compiletest", "compiletest", Mode::Libtest;
+    // rules.build("tool-build-manifest", "src/tools/build-manifest")
+    //      .dep(|s| s.name("maybe-clean-tools"))
+    //      .dep(|s| s.name("libstd-tool"))
+    //      .run(move |s| compile::tool(build, s.stage, s.target, "build-manifest"));
+    BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::Libstd;
+    // rules.build("tool-remote-test-server", "src/tools/remote-test-server")
+    //      .dep(|s| s.name("maybe-clean-tools"))
+    //      .dep(|s| s.name("libstd-tool"))
+    //      .run(move |s| compile::tool(build, s.stage, s.target, "remote-test-server"));
+    RemoteTestServer, "src/tools/remote-test-server", "remote-test-server", Mode::Libstd;
+    // rules.build("tool-remote-test-client", "src/tools/remote-test-client")
+    //      .dep(|s| s.name("maybe-clean-tools"))
+    //      .dep(|s| s.name("libstd-tool"))
+    //      .run(move |s| compile::tool(build, s.stage, s.target, "remote-test-client"));
+    RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::Libstd;
+    // rules.build("tool-rust-installer", "src/tools/rust-installer")
+    //      .dep(|s| s.name("maybe-clean-tools"))
+    //      .dep(|s| s.name("libstd-tool"))
+    //      .run(move |s| compile::tool(build, s.stage, s.target, "rust-installer"));
+    RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::Libstd;
+);
+
+// rules.build("tool-cargo", "src/tools/cargo")
+//      .host(true)
+//      .default(build.config.extended)
+//      .dep(|s| s.name("maybe-clean-tools"))
+//      .dep(|s| s.name("libstd-tool"))
+//      .dep(|s| s.stage(0).host(s.target).name("openssl"))
+//      .dep(move |s| {
+//          // Cargo depends on procedural macros, which requires a full host
+//          // compiler to be available, so we need to depend on that.
+//          s.name("librustc-link")
+//           .target(&build.build)
+//           .host(&build.build)
+//      })
+//      .run(move |s| compile::tool(build, s.stage, s.target, "cargo"));
+#[derive(Serialize)]
+pub struct Cargo<'a> {
+    pub stage: u32,
+    pub target: &'a str,
+}
+
+impl<'a> Step<'a> for Cargo<'a> {
+    type Output = PathBuf;
+    const NAME: &'static str = "cargo tool";
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/tools/cargo")
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, _host: &str, target: &str) {
+        if path.is_none() && !builder.build.config.extended {
+            return;
+        }
+        builder.ensure(Cargo {
+            stage: builder.top_stage,
+            target,
+        });
+    }
+
+    fn run(self, builder: &Builder) -> PathBuf {
+        builder.ensure(native::Openssl {
+            target: self.target,
+        });
+        // Cargo depends on procedural macros, which requires a full host
+        // compiler to be available, so we need to depend on that.
+        builder.ensure(Rustc {
+            compiler: builder.compiler(builder.top_stage, &builder.build.build),
+            target: &builder.build.build,
+        });
+        builder.ensure(ToolBuild {
+            stage: self.stage,
+            target: self.target,
+            tool: "cargo",
+            mode: Mode::Libstd,
+        })
+    }
+}
+
+// rules.build("tool-rls", "src/tools/rls")
+//      .host(true)
+//      .default(build.config.extended)
+//      .dep(|s| s.name("librustc-tool"))
+//      .dep(|s| s.stage(0).host(s.target).name("openssl"))
+//      .dep(move |s| {
+//          // rls, like cargo, uses procedural macros
+//          s.name("librustc-link")
+//           .target(&build.build)
+//           .host(&build.build)
+//      })
+//      .run(move |s| compile::tool(build, s.stage, s.target, "rls"));
+//
+#[derive(Serialize)]
+pub struct Rls<'a> {
+    pub stage: u32,
+    pub target: &'a str,
+}
+
+impl<'a> Step<'a> for Rls<'a> {
+    type Output = PathBuf;
+    const NAME: &'static str = "RLS tool";
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(_builder: &Builder, path: &Path) -> bool {
+        path.ends_with("src/tools/rls")
+    }
+
+    fn make_run(builder: &Builder, path: Option<&Path>, _host: &str, target: &str) {
+        if path.is_none() && !builder.build.config.extended {
+            return;
+        }
+        builder.ensure(Cargo {
+            stage: builder.top_stage,
+            target,
+        });
+    }
+
+    fn run(self, builder: &Builder) -> PathBuf {
+        builder.ensure(native::Openssl {
+            target: self.target,
+        });
+        // RLS depends on procedural macros, which requires a full host
+        // compiler to be available, so we need to depend on that.
+        builder.ensure(Rustc {
+            compiler: builder.compiler(builder.top_stage, &builder.build.build),
+            target: &builder.build.build,
+        });
+        builder.ensure(ToolBuild {
+            stage: self.stage,
+            target: self.target,
+            tool: "rls",
+            mode: Mode::Librustc,
+        })
     }
 }