]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/step.rs
Rollup merge of #39604 - est31:i128_tests, r=alexcrichton
[rust.git] / src / bootstrap / step.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Definition of steps of the build system.
12 //!
13 //! This is where some of the real meat of rustbuild is located, in how we
14 //! define targets and the dependencies amongst them. This file can sort of be
15 //! viewed as just defining targets in a makefile which shell out to predefined
16 //! functions elsewhere about how to execute the target.
17 //!
18 //! The primary function here you're likely interested in is the `build_rules`
19 //! function. This will create a `Rules` structure which basically just lists
20 //! everything that rustbuild can do. Each rule has a human-readable name, a
21 //! path associated with it, some dependencies, and then a closure of how to
22 //! actually perform the rule.
23 //!
24 //! All steps below are defined in self-contained units, so adding a new target
25 //! to the build system should just involve adding the meta information here
26 //! along with the actual implementation elsewhere. You can find more comments
27 //! about how to define rules themselves below.
28
29 use std::collections::{HashMap, HashSet};
30 use std::mem;
31
32 use check::{self, TestKind};
33 use compile;
34 use dist;
35 use doc;
36 use flags::Subcommand;
37 use install;
38 use native;
39 use {Compiler, Build, Mode};
40
41 pub fn run(build: &Build) {
42     let rules = build_rules(build);
43     let steps = rules.plan();
44     rules.run(&steps);
45 }
46
47 pub fn build_rules<'a>(build: &'a Build) -> Rules {
48     let mut rules = Rules::new(build);
49
50     // This is the first rule that we're going to define for rustbuild, which is
51     // used to compile LLVM itself. All rules are added through the `rules`
52     // structure created above and are configured through a builder-style
53     // interface.
54     //
55     // First up we see the `build` method. This represents a rule that's part of
56     // the top-level `build` subcommand. For example `./x.py build` is what this
57     // is associating with. Note that this is normally only relevant if you flag
58     // a rule as `default`, which we'll talk about later.
59     //
60     // Next up we'll see two arguments to this method:
61     //
62     // * `llvm` - this is the "human readable" name of this target. This name is
63     //            not accessed anywhere outside this file itself (e.g. not in
64     //            the CLI nor elsewhere in rustbuild). The purpose of this is to
65     //            easily define dependencies between rules. That is, other rules
66     //            will depend on this with the name "llvm".
67     // * `src/llvm` - this is the relevant path to the rule that we're working
68     //                with. This path is the engine behind how commands like
69     //                `./x.py build src/llvm` work. This should typically point
70     //                to the relevant component, but if there's not really a
71     //                path to be assigned here you can pass something like
72     //                `path/to/nowhere` to ignore it.
73     //
74     // After we create the rule with the `build` method we can then configure
75     // various aspects of it. For example this LLVM rule uses `.host(true)` to
76     // flag that it's a rule only for host targets. In other words, LLVM isn't
77     // compiled for targets configured through `--target` (e.g. those we're just
78     // building a standard library for).
79     //
80     // Next up the `dep` method will add a dependency to this rule. The closure
81     // is yielded the step that represents executing the `llvm` rule itself
82     // (containing information like stage, host, target, ...) and then it must
83     // return a target that the step depends on. Here LLVM is actually
84     // interesting where a cross-compiled LLVM depends on the host LLVM, but
85     // otherwise it has no dependencies.
86     //
87     // To handle this we do a bit of dynamic dispatch to see what the dependency
88     // is. If we're building a LLVM for the build triple, then we don't actually
89     // have any dependencies! To do that we return a dependency on the `Step::noop()`
90     // target which does nothing.
91     //
92     // If we're build a cross-compiled LLVM, however, we need to assemble the
93     // libraries from the previous compiler. This step has the same name as
94     // ours (llvm) but we want it for a different target, so we use the
95     // builder-style methods on `Step` to configure this target to the build
96     // triple.
97     //
98     // Finally, to finish off this rule, we define how to actually execute it.
99     // That logic is all defined in the `native` module so we just delegate to
100     // the relevant function there. The argument to the closure passed to `run`
101     // is a `Step` (defined below) which encapsulates information like the
102     // stage, target, host, etc.
103     rules.build("llvm", "src/llvm")
104          .host(true)
105          .dep(move |s| {
106              if s.target == build.config.build {
107                  Step::noop()
108              } else {
109                  s.target(&build.config.build)
110              }
111          })
112          .run(move |s| native::llvm(build, s.target));
113
114     // Ok! After that example rule  that's hopefully enough to explain what's
115     // going on here. You can check out the API docs below and also see a bunch
116     // more examples of rules directly below as well.
117
118     // the compiler with no target libraries ready to go
119     rules.build("rustc", "src/rustc")
120          .dep(|s| s.name("create-sysroot").target(s.host))
121          .dep(move |s| {
122              if s.stage == 0 {
123                  Step::noop()
124              } else {
125                  s.name("librustc")
126                   .host(&build.config.build)
127                   .stage(s.stage - 1)
128              }
129          })
130          .run(move |s| compile::assemble_rustc(build, s.stage, s.target));
131
132     // Helper for loading an entire DAG of crates, rooted at `name`
133     let krates = |name: &str| {
134         let mut ret = Vec::new();
135         let mut list = vec![name];
136         let mut visited = HashSet::new();
137         while let Some(krate) = list.pop() {
138             let default = krate == name;
139             let krate = &build.crates[krate];
140             let path = krate.path.strip_prefix(&build.src).unwrap();
141             ret.push((krate, path.to_str().unwrap(), default));
142             for dep in krate.deps.iter() {
143                 if visited.insert(dep) && dep != "build_helper" {
144                     list.push(dep);
145                 }
146             }
147         }
148         return ret
149     };
150
151     // ========================================================================
152     // Crate compilations
153     //
154     // Tools used during the build system but not shipped
155     rules.build("create-sysroot", "path/to/nowhere")
156          .run(move |s| compile::create_sysroot(build, &s.compiler()));
157
158     // These rules are "pseudo rules" that don't actually do any work
159     // themselves, but represent a complete sysroot with the relevant compiler
160     // linked into place.
161     //
162     // That is, depending on "libstd" means that when the rule is completed then
163     // the `stage` sysroot for the compiler `host` will be available with a
164     // standard library built for `target` linked in place. Not all rules need
165     // the compiler itself to be available, just the standard library, so
166     // there's a distinction between the two.
167     rules.build("libstd", "src/libstd")
168          .dep(|s| s.name("rustc").target(s.host))
169          .dep(|s| s.name("libstd-link"));
170     rules.build("libtest", "src/libtest")
171          .dep(|s| s.name("libstd"))
172          .dep(|s| s.name("libtest-link"))
173          .default(true);
174     rules.build("librustc", "src/librustc")
175          .dep(|s| s.name("libtest"))
176          .dep(|s| s.name("librustc-link"))
177          .host(true)
178          .default(true);
179
180     // Helper method to define the rules to link a crate into its place in the
181     // sysroot.
182     //
183     // The logic here is a little subtle as there's a few cases to consider.
184     // Not all combinations of (stage, host, target) actually require something
185     // to be compiled, but rather libraries could get propagated from a
186     // different location. For example:
187     //
188     // * Any crate with a `host` that's not the build triple will not actually
189     //   compile something. A different `host` means that the build triple will
190     //   actually compile the libraries, and then we'll copy them over from the
191     //   build triple to the `host` directory.
192     //
193     // * Some crates aren't even compiled by the build triple, but may be copied
194     //   from previous stages. For example if we're not doing a full bootstrap
195     //   then we may just depend on the stage1 versions of libraries to be
196     //   available to get linked forward.
197     //
198     // * Finally, there are some cases, however, which do indeed comiple crates
199     //   and link them into place afterwards.
200     //
201     // The rule definition below mirrors these three cases. The `dep` method
202     // calculates the correct dependency which either comes from stage1, a
203     // different compiler, or from actually building the crate itself (the `dep`
204     // rule). The `run` rule then mirrors these three cases and links the cases
205     // forward into the compiler sysroot specified from the correct location.
206     fn crate_rule<'a, 'b>(build: &'a Build,
207                           rules: &'b mut Rules<'a>,
208                           krate: &'a str,
209                           dep: &'a str,
210                           link: fn(&Build, &Compiler, &Compiler, &str))
211                           -> RuleBuilder<'a, 'b> {
212         let mut rule = rules.build(&krate, "path/to/nowhere");
213         rule.dep(move |s| {
214                 if build.force_use_stage1(&s.compiler(), s.target) {
215                     s.host(&build.config.build).stage(1)
216                 } else if s.host == build.config.build {
217                     s.name(dep)
218                 } else {
219                     s.host(&build.config.build)
220                 }
221             })
222             .run(move |s| {
223                 if build.force_use_stage1(&s.compiler(), s.target) {
224                     link(build,
225                          &s.stage(1).host(&build.config.build).compiler(),
226                          &s.compiler(),
227                          s.target)
228                 } else if s.host == build.config.build {
229                     link(build, &s.compiler(), &s.compiler(), s.target)
230                 } else {
231                     link(build,
232                          &s.host(&build.config.build).compiler(),
233                          &s.compiler(),
234                          s.target)
235                 }
236             });
237             return rule
238     }
239
240     // Similar to the `libstd`, `libtest`, and `librustc` rules above, except
241     // these rules only represent the libraries being available in the sysroot,
242     // not the compiler itself. This is done as not all rules need a compiler in
243     // the sysroot, but may just need the libraries.
244     //
245     // All of these rules use the helper definition above.
246     crate_rule(build,
247                &mut rules,
248                "libstd-link",
249                "build-crate-std_shim",
250                compile::std_link)
251         .dep(|s| s.name("startup-objects"))
252         .dep(|s| s.name("create-sysroot").target(s.host));
253     crate_rule(build,
254                &mut rules,
255                "libtest-link",
256                "build-crate-test_shim",
257                compile::test_link)
258         .dep(|s| s.name("libstd-link"));
259     crate_rule(build,
260                &mut rules,
261                "librustc-link",
262                "build-crate-rustc-main",
263                compile::rustc_link)
264         .dep(|s| s.name("libtest-link"));
265
266     for (krate, path, _default) in krates("std_shim") {
267         rules.build(&krate.build_step, path)
268              .dep(|s| s.name("startup-objects"))
269              .dep(move |s| s.name("rustc").host(&build.config.build).target(s.host))
270              .run(move |s| compile::std(build, s.target, &s.compiler()));
271     }
272     for (krate, path, _default) in krates("test_shim") {
273         rules.build(&krate.build_step, path)
274              .dep(|s| s.name("libstd-link"))
275              .run(move |s| compile::test(build, s.target, &s.compiler()));
276     }
277     for (krate, path, _default) in krates("rustc-main") {
278         rules.build(&krate.build_step, path)
279              .dep(|s| s.name("libtest-link"))
280              .dep(move |s| s.name("llvm").host(&build.config.build).stage(0))
281              .run(move |s| compile::rustc(build, s.target, &s.compiler()));
282     }
283
284     rules.build("startup-objects", "src/rtstartup")
285          .dep(|s| s.name("create-sysroot").target(s.host))
286          .run(move |s| compile::build_startup_objects(build, &s.compiler(), s.target));
287
288     // ========================================================================
289     // Test targets
290     //
291     // Various unit tests and tests suites we can run
292     {
293         let mut suite = |name, path, mode, dir| {
294             rules.test(name, path)
295                  .dep(|s| s.name("libtest"))
296                  .dep(|s| s.name("tool-compiletest").target(s.host).stage(0))
297                  .dep(|s| s.name("test-helpers"))
298                  .dep(|s| s.name("emulator-copy-libs"))
299                  .default(mode != "pretty") // pretty tests don't run everywhere
300                  .run(move |s| {
301                      check::compiletest(build, &s.compiler(), s.target, mode, dir)
302                  });
303         };
304
305         suite("check-rpass", "src/test/run-pass", "run-pass", "run-pass");
306         suite("check-cfail", "src/test/compile-fail", "compile-fail", "compile-fail");
307         suite("check-pfail", "src/test/parse-fail", "parse-fail", "parse-fail");
308         suite("check-rfail", "src/test/run-fail", "run-fail", "run-fail");
309         suite("check-rpass-valgrind", "src/test/run-pass-valgrind",
310               "run-pass-valgrind", "run-pass-valgrind");
311         suite("check-mir-opt", "src/test/mir-opt", "mir-opt", "mir-opt");
312         if build.config.codegen_tests {
313             suite("check-codegen", "src/test/codegen", "codegen", "codegen");
314         }
315         suite("check-codegen-units", "src/test/codegen-units", "codegen-units",
316               "codegen-units");
317         suite("check-incremental", "src/test/incremental", "incremental",
318               "incremental");
319     }
320
321     if build.config.build.contains("msvc") {
322         // nothing to do for debuginfo tests
323     } else {
324         rules.test("check-debuginfo-lldb", "src/test/debuginfo-lldb")
325              .dep(|s| s.name("libtest"))
326              .dep(|s| s.name("tool-compiletest").target(s.host).stage(0))
327              .dep(|s| s.name("test-helpers"))
328              .dep(|s| s.name("debugger-scripts"))
329              .run(move |s| check::compiletest(build, &s.compiler(), s.target,
330                                          "debuginfo-lldb", "debuginfo"));
331         rules.test("check-debuginfo-gdb", "src/test/debuginfo-gdb")
332              .dep(|s| s.name("libtest"))
333              .dep(|s| s.name("tool-compiletest").target(s.host).stage(0))
334              .dep(|s| s.name("test-helpers"))
335              .dep(|s| s.name("debugger-scripts"))
336              .dep(|s| s.name("emulator-copy-libs"))
337              .run(move |s| check::compiletest(build, &s.compiler(), s.target,
338                                          "debuginfo-gdb", "debuginfo"));
339         let mut rule = rules.test("check-debuginfo", "src/test/debuginfo");
340         rule.default(true);
341         if build.config.build.contains("apple") {
342             rule.dep(|s| s.name("check-debuginfo-lldb"));
343         } else {
344             rule.dep(|s| s.name("check-debuginfo-gdb"));
345         }
346     }
347
348     rules.test("debugger-scripts", "src/etc/lldb_batchmode.py")
349          .run(move |s| dist::debugger_scripts(build, &build.sysroot(&s.compiler()),
350                                          s.target));
351
352     {
353         let mut suite = |name, path, mode, dir| {
354             rules.test(name, path)
355                  .dep(|s| s.name("librustc"))
356                  .dep(|s| s.name("test-helpers"))
357                  .dep(|s| s.name("tool-compiletest").target(s.host).stage(0))
358                  .default(mode != "pretty")
359                  .host(true)
360                  .run(move |s| {
361                      check::compiletest(build, &s.compiler(), s.target, mode, dir)
362                  });
363         };
364
365         suite("check-ui", "src/test/ui", "ui", "ui");
366         suite("check-rpass-full", "src/test/run-pass-fulldeps",
367               "run-pass", "run-pass-fulldeps");
368         suite("check-rfail-full", "src/test/run-fail-fulldeps",
369               "run-fail", "run-fail-fulldeps");
370         suite("check-cfail-full", "src/test/compile-fail-fulldeps",
371               "compile-fail", "compile-fail-fulldeps");
372         suite("check-rmake", "src/test/run-make", "run-make", "run-make");
373         suite("check-rustdoc", "src/test/rustdoc", "rustdoc", "rustdoc");
374         suite("check-pretty", "src/test/pretty", "pretty", "pretty");
375         suite("check-pretty-rpass", "src/test/run-pass/pretty", "pretty",
376               "run-pass");
377         suite("check-pretty-rfail", "src/test/run-fail/pretty", "pretty",
378               "run-fail");
379         suite("check-pretty-valgrind", "src/test/run-pass-valgrind/pretty", "pretty",
380               "run-pass-valgrind");
381         suite("check-pretty-rpass-full", "src/test/run-pass-fulldeps/pretty",
382               "pretty", "run-pass-fulldeps");
383         suite("check-pretty-rfail-full", "src/test/run-fail-fulldeps/pretty",
384               "pretty", "run-fail-fulldeps");
385     }
386
387     for (krate, path, _default) in krates("std_shim") {
388         rules.test(&krate.test_step, path)
389              .dep(|s| s.name("libtest"))
390              .dep(|s| s.name("emulator-copy-libs"))
391              .run(move |s| check::krate(build, &s.compiler(), s.target,
392                                         Mode::Libstd, TestKind::Test,
393                                         Some(&krate.name)));
394     }
395     rules.test("check-std-all", "path/to/nowhere")
396          .dep(|s| s.name("libtest"))
397          .dep(|s| s.name("emulator-copy-libs"))
398          .default(true)
399          .run(move |s| check::krate(build, &s.compiler(), s.target,
400                                     Mode::Libstd, TestKind::Test, None));
401
402     // std benchmarks
403     for (krate, path, _default) in krates("std_shim") {
404         rules.bench(&krate.bench_step, path)
405              .dep(|s| s.name("libtest"))
406              .dep(|s| s.name("emulator-copy-libs"))
407              .run(move |s| check::krate(build, &s.compiler(), s.target,
408                                         Mode::Libstd, TestKind::Bench,
409                                         Some(&krate.name)));
410     }
411     rules.bench("bench-std-all", "path/to/nowhere")
412          .dep(|s| s.name("libtest"))
413          .dep(|s| s.name("emulator-copy-libs"))
414          .default(true)
415          .run(move |s| check::krate(build, &s.compiler(), s.target,
416                                     Mode::Libstd, TestKind::Bench, None));
417
418     for (krate, path, _default) in krates("test_shim") {
419         rules.test(&krate.test_step, path)
420              .dep(|s| s.name("libtest"))
421              .dep(|s| s.name("emulator-copy-libs"))
422              .run(move |s| check::krate(build, &s.compiler(), s.target,
423                                         Mode::Libtest, TestKind::Test,
424                                         Some(&krate.name)));
425     }
426     rules.test("check-test-all", "path/to/nowhere")
427          .dep(|s| s.name("libtest"))
428          .dep(|s| s.name("emulator-copy-libs"))
429          .default(true)
430          .run(move |s| check::krate(build, &s.compiler(), s.target,
431                                     Mode::Libtest, TestKind::Test, None));
432     for (krate, path, _default) in krates("rustc-main") {
433         rules.test(&krate.test_step, path)
434              .dep(|s| s.name("librustc"))
435              .dep(|s| s.name("emulator-copy-libs"))
436              .host(true)
437              .run(move |s| check::krate(build, &s.compiler(), s.target,
438                                         Mode::Librustc, TestKind::Test,
439                                         Some(&krate.name)));
440     }
441     rules.test("check-rustc-all", "path/to/nowhere")
442          .dep(|s| s.name("librustc"))
443          .dep(|s| s.name("emulator-copy-libs"))
444          .default(true)
445          .host(true)
446          .run(move |s| check::krate(build, &s.compiler(), s.target,
447                                     Mode::Librustc, TestKind::Test, None));
448
449     rules.test("check-linkchecker", "src/tools/linkchecker")
450          .dep(|s| s.name("tool-linkchecker").stage(0))
451          .dep(|s| s.name("default:doc"))
452          .default(true)
453          .host(true)
454          .run(move |s| check::linkcheck(build, s.target));
455     rules.test("check-cargotest", "src/tools/cargotest")
456          .dep(|s| s.name("tool-cargotest").stage(0))
457          .dep(|s| s.name("librustc"))
458          .host(true)
459          .run(move |s| check::cargotest(build, s.stage, s.target));
460     rules.test("check-tidy", "src/tools/tidy")
461          .dep(|s| s.name("tool-tidy").stage(0))
462          .default(true)
463          .host(true)
464          .only_build(true)
465          .run(move |s| check::tidy(build, s.target));
466     rules.test("check-error-index", "src/tools/error_index_generator")
467          .dep(|s| s.name("libstd"))
468          .dep(|s| s.name("tool-error-index").host(s.host).stage(0))
469          .default(true)
470          .host(true)
471          .run(move |s| check::error_index(build, &s.compiler()));
472     rules.test("check-docs", "src/doc")
473          .dep(|s| s.name("libtest"))
474          .default(true)
475          .host(true)
476          .run(move |s| check::docs(build, &s.compiler()));
477     rules.test("check-distcheck", "distcheck")
478          .dep(|s| s.name("dist-src"))
479          .run(move |_| check::distcheck(build));
480
481
482     rules.build("test-helpers", "src/rt/rust_test_helpers.c")
483          .run(move |s| native::test_helpers(build, s.target));
484
485     // Some test suites are run inside emulators, and most of our test binaries
486     // are linked dynamically which means we need to ship the standard library
487     // and such to the emulator ahead of time. This step represents this and is
488     // a dependency of all test suites.
489     //
490     // Most of the time this step is a noop (the `check::emulator_copy_libs`
491     // only does work if necessary). For some steps such as shipping data to
492     // QEMU we have to build our own tools so we've got conditional dependencies
493     // on those programs as well. Note that the QEMU client is built for the
494     // build target (us) and the server is built for the target.
495     rules.test("emulator-copy-libs", "path/to/nowhere")
496          .dep(|s| s.name("libtest"))
497          .dep(move |s| {
498              if build.qemu_rootfs(s.target).is_some() {
499                 s.name("tool-qemu-test-client").target(s.host).stage(0)
500              } else {
501                  Step::noop()
502              }
503          })
504          .dep(move |s| {
505              if build.qemu_rootfs(s.target).is_some() {
506                 s.name("tool-qemu-test-server")
507              } else {
508                  Step::noop()
509              }
510          })
511          .run(move |s| check::emulator_copy_libs(build, &s.compiler(), s.target));
512
513     rules.test("check-bootstrap", "src/bootstrap")
514          .default(true)
515          .host(true)
516          .only_build(true)
517          .run(move |_| check::bootstrap(build));
518
519     // ========================================================================
520     // Build tools
521     //
522     // Tools used during the build system but not shipped
523     rules.build("tool-rustbook", "src/tools/rustbook")
524          .dep(|s| s.name("librustc"))
525          .run(move |s| compile::tool(build, s.stage, s.target, "rustbook"));
526     rules.build("tool-error-index", "src/tools/error_index_generator")
527          .dep(|s| s.name("librustc"))
528          .run(move |s| compile::tool(build, s.stage, s.target, "error_index_generator"));
529     rules.build("tool-tidy", "src/tools/tidy")
530          .dep(|s| s.name("libstd"))
531          .run(move |s| compile::tool(build, s.stage, s.target, "tidy"));
532     rules.build("tool-linkchecker", "src/tools/linkchecker")
533          .dep(|s| s.name("libstd"))
534          .run(move |s| compile::tool(build, s.stage, s.target, "linkchecker"));
535     rules.build("tool-cargotest", "src/tools/cargotest")
536          .dep(|s| s.name("libstd"))
537          .run(move |s| compile::tool(build, s.stage, s.target, "cargotest"));
538     rules.build("tool-compiletest", "src/tools/compiletest")
539          .dep(|s| s.name("libtest"))
540          .run(move |s| compile::tool(build, s.stage, s.target, "compiletest"));
541     rules.build("tool-build-manifest", "src/tools/build-manifest")
542          .dep(|s| s.name("libstd"))
543          .run(move |s| compile::tool(build, s.stage, s.target, "build-manifest"));
544     rules.build("tool-qemu-test-server", "src/tools/qemu-test-server")
545          .dep(|s| s.name("libstd"))
546          .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-server"));
547     rules.build("tool-qemu-test-client", "src/tools/qemu-test-client")
548          .dep(|s| s.name("libstd"))
549          .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-client"));
550
551     // ========================================================================
552     // Documentation targets
553     rules.doc("doc-book", "src/doc/book")
554          .dep(move |s| {
555              s.name("tool-rustbook")
556               .host(&build.config.build)
557               .target(&build.config.build)
558               .stage(0)
559          })
560          .default(build.config.docs)
561          .run(move |s| doc::rustbook(build, s.target, "book"));
562     rules.doc("doc-nomicon", "src/doc/nomicon")
563          .dep(move |s| {
564              s.name("tool-rustbook")
565               .host(&build.config.build)
566               .target(&build.config.build)
567               .stage(0)
568          })
569          .default(build.config.docs)
570          .run(move |s| doc::rustbook(build, s.target, "nomicon"));
571     rules.doc("doc-standalone", "src/doc")
572          .dep(move |s| {
573              s.name("rustc")
574               .host(&build.config.build)
575               .target(&build.config.build)
576               .stage(0)
577          })
578          .default(build.config.docs)
579          .run(move |s| doc::standalone(build, s.target));
580     rules.doc("doc-error-index", "src/tools/error_index_generator")
581          .dep(move |s| s.name("tool-error-index").target(&build.config.build).stage(0))
582          .dep(move |s| s.name("librustc-link"))
583          .default(build.config.docs)
584          .host(true)
585          .run(move |s| doc::error_index(build, s.target));
586     for (krate, path, default) in krates("std_shim") {
587         rules.doc(&krate.doc_step, path)
588              .dep(|s| s.name("libstd-link"))
589              .default(default && build.config.docs)
590              .run(move |s| doc::std(build, s.stage, s.target));
591     }
592     for (krate, path, default) in krates("test_shim") {
593         rules.doc(&krate.doc_step, path)
594              .dep(|s| s.name("libtest-link"))
595              .default(default && build.config.compiler_docs)
596              .run(move |s| doc::test(build, s.stage, s.target));
597     }
598     for (krate, path, default) in krates("rustc-main") {
599         rules.doc(&krate.doc_step, path)
600              .dep(|s| s.name("librustc-link"))
601              .host(true)
602              .default(default && build.config.compiler_docs)
603              .run(move |s| doc::rustc(build, s.stage, s.target));
604     }
605
606     // ========================================================================
607     // Distribution targets
608     rules.dist("dist-rustc", "src/librustc")
609          .dep(move |s| s.name("rustc").host(&build.config.build))
610          .host(true)
611          .only_host_build(true)
612          .default(true)
613          .run(move |s| dist::rustc(build, s.stage, s.target));
614     rules.dist("dist-std", "src/libstd")
615          .dep(move |s| {
616              // We want to package up as many target libraries as possible
617              // for the `rust-std` package, so if this is a host target we
618              // depend on librustc and otherwise we just depend on libtest.
619              if build.config.host.iter().any(|t| t == s.target) {
620                  s.name("librustc-link")
621              } else {
622                  s.name("libtest-link")
623              }
624          })
625          .default(true)
626          .only_host_build(true)
627          .run(move |s| dist::std(build, &s.compiler(), s.target));
628     rules.dist("dist-mingw", "path/to/nowhere")
629          .default(true)
630          .only_host_build(true)
631          .run(move |s| {
632              if s.target.contains("pc-windows-gnu") {
633                  dist::mingw(build, s.target)
634              }
635          });
636     rules.dist("dist-src", "src")
637          .default(true)
638          .host(true)
639          .only_build(true)
640          .only_host_build(true)
641          .run(move |_| dist::rust_src(build));
642     rules.dist("dist-docs", "src/doc")
643          .default(true)
644          .only_host_build(true)
645          .dep(|s| s.name("default:doc"))
646          .run(move |s| dist::docs(build, s.stage, s.target));
647     rules.dist("dist-analysis", "analysis")
648          .dep(|s| s.name("dist-std"))
649          .default(true)
650          .only_host_build(true)
651          .run(move |s| dist::analysis(build, &s.compiler(), s.target));
652     rules.dist("install", "path/to/nowhere")
653          .dep(|s| s.name("default:dist"))
654          .run(move |s| install::install(build, s.stage, s.target));
655     rules.dist("dist-cargo", "cargo")
656          .host(true)
657          .only_host_build(true)
658          .run(move |s| dist::cargo(build, s.stage, s.target));
659     rules.dist("dist-extended", "extended")
660          .default(build.config.extended)
661          .host(true)
662          .only_host_build(true)
663          .dep(|d| d.name("dist-std"))
664          .dep(|d| d.name("dist-rustc"))
665          .dep(|d| d.name("dist-mingw"))
666          .dep(|d| d.name("dist-docs"))
667          .dep(|d| d.name("dist-cargo"))
668          .run(move |s| dist::extended(build, s.stage, s.target));
669
670     rules.dist("dist-sign", "hash-and-sign")
671          .host(true)
672          .only_build(true)
673          .only_host_build(true)
674          .dep(move |s| s.name("tool-build-manifest").target(&build.config.build).stage(0))
675          .run(move |_| dist::hash_and_sign(build));
676
677     rules.verify();
678     return rules;
679 }
680
681 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
682 struct Step<'a> {
683     /// Human readable name of the rule this step is executing. Possible names
684     /// are all defined above in `build_rules`.
685     name: &'a str,
686
687     /// The stage this step is executing in. This is typically 0, 1, or 2.
688     stage: u32,
689
690     /// This step will likely involve a compiler, and the target that compiler
691     /// itself is built for is called the host, this variable. Typically this is
692     /// the target of the build machine itself.
693     host: &'a str,
694
695     /// The target that this step represents generating. If you're building a
696     /// standard library for a new suite of targets, for example, this'll be set
697     /// to those targets.
698     target: &'a str,
699 }
700
701 impl<'a> Step<'a> {
702     fn noop() -> Step<'a> {
703         Step { name: "", stage: 0, host: "", target: "" }
704     }
705
706     /// Creates a new step which is the same as this, except has a new name.
707     fn name(&self, name: &'a str) -> Step<'a> {
708         Step { name: name, ..*self }
709     }
710
711     /// Creates a new step which is the same as this, except has a new stage.
712     fn stage(&self, stage: u32) -> Step<'a> {
713         Step { stage: stage, ..*self }
714     }
715
716     /// Creates a new step which is the same as this, except has a new host.
717     fn host(&self, host: &'a str) -> Step<'a> {
718         Step { host: host, ..*self }
719     }
720
721     /// Creates a new step which is the same as this, except has a new target.
722     fn target(&self, target: &'a str) -> Step<'a> {
723         Step { target: target, ..*self }
724     }
725
726     /// Returns the `Compiler` structure that this step corresponds to.
727     fn compiler(&self) -> Compiler<'a> {
728         Compiler::new(self.stage, self.host)
729     }
730 }
731
732 struct Rule<'a> {
733     /// The human readable name of this target, defined in `build_rules`.
734     name: &'a str,
735
736     /// The path associated with this target, used in the `./x.py` driver for
737     /// easy and ergonomic specification of what to do.
738     path: &'a str,
739
740     /// The "kind" of top-level command that this rule is associated with, only
741     /// relevant if this is a default rule.
742     kind: Kind,
743
744     /// List of dependencies this rule has. Each dependency is a function from a
745     /// step that's being executed to another step that should be executed.
746     deps: Vec<Box<Fn(&Step<'a>) -> Step<'a> + 'a>>,
747
748     /// How to actually execute this rule. Takes a step with contextual
749     /// information and then executes it.
750     run: Box<Fn(&Step<'a>) + 'a>,
751
752     /// Whether or not this is a "default" rule. That basically means that if
753     /// you run, for example, `./x.py test` whether it's included or not.
754     default: bool,
755
756     /// Whether or not this is a "host" rule, or in other words whether this is
757     /// only intended for compiler hosts and not for targets that are being
758     /// generated.
759     host: bool,
760
761     /// Whether this rule is only for steps where the host is the build triple,
762     /// not anything in hosts or targets.
763     only_host_build: bool,
764
765     /// Whether this rule is only for the build triple, not anything in hosts or
766     /// targets.
767     only_build: bool,
768 }
769
770 #[derive(PartialEq)]
771 enum Kind {
772     Build,
773     Test,
774     Bench,
775     Dist,
776     Doc,
777 }
778
779 impl<'a> Rule<'a> {
780     fn new(name: &'a str, path: &'a str, kind: Kind) -> Rule<'a> {
781         Rule {
782             name: name,
783             deps: Vec::new(),
784             run: Box::new(|_| ()),
785             path: path,
786             kind: kind,
787             default: false,
788             host: false,
789             only_host_build: false,
790             only_build: false,
791         }
792     }
793 }
794
795 /// Builder pattern returned from the various methods on `Rules` which will add
796 /// the rule to the internal list on `Drop`.
797 struct RuleBuilder<'a: 'b, 'b> {
798     rules: &'b mut Rules<'a>,
799     rule: Rule<'a>,
800 }
801
802 impl<'a, 'b> RuleBuilder<'a, 'b> {
803     fn dep<F>(&mut self, f: F) -> &mut Self
804         where F: Fn(&Step<'a>) -> Step<'a> + 'a,
805     {
806         self.rule.deps.push(Box::new(f));
807         self
808     }
809
810     fn run<F>(&mut self, f: F) -> &mut Self
811         where F: Fn(&Step<'a>) + 'a,
812     {
813         self.rule.run = Box::new(f);
814         self
815     }
816
817     fn default(&mut self, default: bool) -> &mut Self {
818         self.rule.default = default;
819         self
820     }
821
822     fn host(&mut self, host: bool) -> &mut Self {
823         self.rule.host = host;
824         self
825     }
826
827     fn only_build(&mut self, only_build: bool) -> &mut Self {
828         self.rule.only_build = only_build;
829         self
830     }
831
832     fn only_host_build(&mut self, only_host_build: bool) -> &mut Self {
833         self.rule.only_host_build = only_host_build;
834         self
835     }
836 }
837
838 impl<'a, 'b> Drop for RuleBuilder<'a, 'b> {
839     fn drop(&mut self) {
840         let rule = mem::replace(&mut self.rule, Rule::new("", "", Kind::Build));
841         let prev = self.rules.rules.insert(rule.name, rule);
842         if let Some(prev) = prev {
843             panic!("duplicate rule named: {}", prev.name);
844         }
845     }
846 }
847
848 pub struct Rules<'a> {
849     build: &'a Build,
850     sbuild: Step<'a>,
851     rules: HashMap<&'a str, Rule<'a>>,
852 }
853
854 impl<'a> Rules<'a> {
855     fn new(build: &'a Build) -> Rules<'a> {
856         Rules {
857             build: build,
858             sbuild: Step {
859                 stage: build.flags.stage.unwrap_or(2),
860                 target: &build.config.build,
861                 host: &build.config.build,
862                 name: "",
863             },
864             rules: HashMap::new(),
865         }
866     }
867
868     /// Creates a new rule of `Kind::Build` with the specified human readable
869     /// name and path associated with it.
870     ///
871     /// The builder returned should be configured further with information such
872     /// as how to actually run this rule.
873     fn build<'b>(&'b mut self, name: &'a str, path: &'a str)
874                  -> RuleBuilder<'a, 'b> {
875         self.rule(name, path, Kind::Build)
876     }
877
878     /// Same as `build`, but for `Kind::Test`.
879     fn test<'b>(&'b mut self, name: &'a str, path: &'a str)
880                 -> RuleBuilder<'a, 'b> {
881         self.rule(name, path, Kind::Test)
882     }
883
884     /// Same as `build`, but for `Kind::Bench`.
885     fn bench<'b>(&'b mut self, name: &'a str, path: &'a str)
886                 -> RuleBuilder<'a, 'b> {
887         self.rule(name, path, Kind::Bench)
888     }
889
890     /// Same as `build`, but for `Kind::Doc`.
891     fn doc<'b>(&'b mut self, name: &'a str, path: &'a str)
892                -> RuleBuilder<'a, 'b> {
893         self.rule(name, path, Kind::Doc)
894     }
895
896     /// Same as `build`, but for `Kind::Dist`.
897     fn dist<'b>(&'b mut self, name: &'a str, path: &'a str)
898                 -> RuleBuilder<'a, 'b> {
899         self.rule(name, path, Kind::Dist)
900     }
901
902     fn rule<'b>(&'b mut self,
903                 name: &'a str,
904                 path: &'a str,
905                 kind: Kind) -> RuleBuilder<'a, 'b> {
906         RuleBuilder {
907             rules: self,
908             rule: Rule::new(name, path, kind),
909         }
910     }
911
912     /// Verify the dependency graph defined by all our rules are correct, e.g.
913     /// everything points to a valid something else.
914     fn verify(&self) {
915         for rule in self.rules.values() {
916             for dep in rule.deps.iter() {
917                 let dep = dep(&self.sbuild.name(rule.name));
918                 if self.rules.contains_key(&dep.name) || dep.name.starts_with("default:") {
919                     continue
920                 }
921                 if dep == Step::noop() {
922                     continue
923                 }
924                 panic!("\
925
926 invalid rule dependency graph detected, was a rule added and maybe typo'd?
927
928     `{}` depends on `{}` which does not exist
929
930 ", rule.name, dep.name);
931             }
932         }
933     }
934
935     pub fn print_help(&self, command: &str) {
936         let kind = match command {
937             "build" => Kind::Build,
938             "doc" => Kind::Doc,
939             "test" => Kind::Test,
940             "bench" => Kind::Bench,
941             "dist" => Kind::Dist,
942             _ => return,
943         };
944         let rules = self.rules.values().filter(|r| r.kind == kind);
945         let rules = rules.filter(|r| !r.path.contains("nowhere"));
946         let mut rules = rules.collect::<Vec<_>>();
947         rules.sort_by_key(|r| r.path);
948
949         println!("Available paths:\n");
950         for rule in rules {
951             print!("    ./x.py {} {}", command, rule.path);
952
953             println!("");
954         }
955     }
956
957     /// Construct the top-level build steps that we're going to be executing,
958     /// given the subcommand that our build is performing.
959     fn plan(&self) -> Vec<Step<'a>> {
960         // Ok, the logic here is pretty subtle, and involves quite a few
961         // conditionals. The basic idea here is to:
962         //
963         // 1. First, filter all our rules to the relevant ones. This means that
964         //    the command specified corresponds to one of our `Kind` variants,
965         //    and we filter all rules based on that.
966         //
967         // 2. Next, we determine which rules we're actually executing. If a
968         //    number of path filters were specified on the command line we look
969         //    for those, otherwise we look for anything tagged `default`.
970         //
971         // 3. Finally, we generate some steps with host and target information.
972         //
973         // The last step is by far the most complicated and subtle. The basic
974         // thinking here is that we want to take the cartesian product of
975         // specified hosts and targets and build rules with that. The list of
976         // hosts and targets, if not specified, come from the how this build was
977         // configured. If the rule we're looking at is a host-only rule the we
978         // ignore the list of targets and instead consider the list of hosts
979         // also the list of targets.
980         //
981         // Once the host and target lists are generated we take the cartesian
982         // product of the two and then create a step based off them. Note that
983         // the stage each step is associated was specified with the `--step`
984         // flag on the command line.
985         let (kind, paths) = match self.build.flags.cmd {
986             Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
987             Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
988             Subcommand::Test { ref paths, test_args: _ } => (Kind::Test, &paths[..]),
989             Subcommand::Bench { ref paths, test_args: _ } => (Kind::Bench, &paths[..]),
990             Subcommand::Dist { ref paths, install } => {
991                 if install {
992                     return vec![self.sbuild.name("install")]
993                 } else {
994                     (Kind::Dist, &paths[..])
995                 }
996             }
997             Subcommand::Clean => panic!(),
998         };
999
1000         self.rules.values().filter(|rule| rule.kind == kind).filter(|rule| {
1001             (paths.len() == 0 && rule.default) || paths.iter().any(|path| {
1002                 path.ends_with(rule.path)
1003             })
1004         }).flat_map(|rule| {
1005             let hosts = if rule.only_host_build || rule.only_build {
1006                 &self.build.config.host[..1]
1007             } else if self.build.flags.host.len() > 0 {
1008                 &self.build.flags.host
1009             } else {
1010                 &self.build.config.host
1011             };
1012             let targets = if self.build.flags.target.len() > 0 {
1013                 &self.build.flags.target
1014             } else {
1015                 &self.build.config.target
1016             };
1017             // Determine the actual targets participating in this rule.
1018             // NOTE: We should keep the full projection from build triple to
1019             // the hosts for the dist steps, now that the hosts array above is
1020             // truncated to avoid duplication of work in that case. Therefore
1021             // the original non-shadowed hosts array is used below.
1022             let arr = if rule.host {
1023                 // If --target was specified but --host wasn't specified,
1024                 // don't run any host-only tests. Also, respect any `--host`
1025                 // overrides as done for `hosts`.
1026                 if self.build.flags.host.len() > 0 {
1027                     &self.build.flags.host[..]
1028                 } else if self.build.flags.target.len() > 0 {
1029                     &[]
1030                 } else if rule.only_build {
1031                     &self.build.config.host[..1]
1032                 } else {
1033                     &self.build.config.host[..]
1034                 }
1035             } else {
1036                 targets
1037             };
1038
1039             hosts.iter().flat_map(move |host| {
1040                 arr.iter().map(move |target| {
1041                     self.sbuild.name(rule.name).target(target).host(host)
1042                 })
1043             })
1044         }).collect()
1045     }
1046
1047     /// Execute all top-level targets indicated by `steps`.
1048     ///
1049     /// This will take the list returned by `plan` and then execute each step
1050     /// along with all required dependencies as it goes up the chain.
1051     fn run(&self, steps: &[Step<'a>]) {
1052         self.build.verbose("bootstrap top targets:");
1053         for step in steps.iter() {
1054             self.build.verbose(&format!("\t{:?}", step));
1055         }
1056
1057         // Using `steps` as the top-level targets, make a topological ordering
1058         // of what we need to do.
1059         let order = self.expand(steps);
1060
1061         // Print out what we're doing for debugging
1062         self.build.verbose("bootstrap build plan:");
1063         for step in order.iter() {
1064             self.build.verbose(&format!("\t{:?}", step));
1065         }
1066
1067         // And finally, iterate over everything and execute it.
1068         for step in order.iter() {
1069             if self.build.flags.keep_stage.map_or(false, |s| step.stage <= s) {
1070                 self.build.verbose(&format!("keeping step {:?}", step));
1071                 continue;
1072             }
1073             self.build.verbose(&format!("executing step {:?}", step));
1074             (self.rules[step.name].run)(step);
1075         }
1076     }
1077
1078     /// From the top level targets `steps` generate a topological ordering of
1079     /// all steps needed to run those steps.
1080     fn expand(&self, steps: &[Step<'a>]) -> Vec<Step<'a>> {
1081         let mut order = Vec::new();
1082         let mut added = HashSet::new();
1083         added.insert(Step::noop());
1084         for step in steps.iter().cloned() {
1085             self.fill(step, &mut order, &mut added);
1086         }
1087         return order
1088     }
1089
1090     /// Performs topological sort of dependencies rooted at the `step`
1091     /// specified, pushing all results onto the `order` vector provided.
1092     ///
1093     /// In other words, when this method returns, the `order` vector will
1094     /// contain a list of steps which if executed in order will eventually
1095     /// complete the `step` specified as well.
1096     ///
1097     /// The `added` set specified here is the set of steps that are already
1098     /// present in `order` (and hence don't need to be added again).
1099     fn fill(&self,
1100             step: Step<'a>,
1101             order: &mut Vec<Step<'a>>,
1102             added: &mut HashSet<Step<'a>>) {
1103         if !added.insert(step.clone()) {
1104             return
1105         }
1106         for dep in self.rules[step.name].deps.iter() {
1107             let dep = dep(&step);
1108             if dep.name.starts_with("default:") {
1109                 let kind = match &dep.name[8..] {
1110                     "doc" => Kind::Doc,
1111                     "dist" => Kind::Dist,
1112                     kind => panic!("unknown kind: `{}`", kind),
1113                 };
1114                 let host = self.build.config.host.iter().any(|h| h == dep.target);
1115                 let rules = self.rules.values().filter(|r| r.default);
1116                 for rule in rules.filter(|r| r.kind == kind && (!r.host || host)) {
1117                     self.fill(dep.name(rule.name), order, added);
1118                 }
1119             } else {
1120                 self.fill(dep, order, added);
1121             }
1122         }
1123         order.push(step);
1124     }
1125 }
1126
1127 #[cfg(test)]
1128 mod tests {
1129     use std::env;
1130
1131     use Build;
1132     use config::Config;
1133     use flags::Flags;
1134
1135     macro_rules! a {
1136         ($($a:expr),*) => (vec![$($a.to_string()),*])
1137     }
1138
1139     fn build(args: &[&str],
1140              extra_host: &[&str],
1141              extra_target: &[&str]) -> Build {
1142         let mut args = args.iter().map(|s| s.to_string()).collect::<Vec<_>>();
1143         args.push("--build".to_string());
1144         args.push("A".to_string());
1145         let flags = Flags::parse(&args);
1146
1147         let mut config = Config::default();
1148         config.docs = true;
1149         config.build = "A".to_string();
1150         config.host = vec![config.build.clone()];
1151         config.host.extend(extra_host.iter().map(|s| s.to_string()));
1152         config.target = config.host.clone();
1153         config.target.extend(extra_target.iter().map(|s| s.to_string()));
1154
1155         let mut build = Build::new(flags, config);
1156         let cwd = env::current_dir().unwrap();
1157         build.crates.insert("std_shim".to_string(), ::Crate {
1158             name: "std_shim".to_string(),
1159             deps: Vec::new(),
1160             path: cwd.join("src/std_shim"),
1161             doc_step: "doc-std_shim".to_string(),
1162             build_step: "build-crate-std_shim".to_string(),
1163             test_step: "test-std_shim".to_string(),
1164             bench_step: "bench-std_shim".to_string(),
1165         });
1166         build.crates.insert("test_shim".to_string(), ::Crate {
1167             name: "test_shim".to_string(),
1168             deps: Vec::new(),
1169             path: cwd.join("src/test_shim"),
1170             doc_step: "doc-test_shim".to_string(),
1171             build_step: "build-crate-test_shim".to_string(),
1172             test_step: "test-test_shim".to_string(),
1173             bench_step: "bench-test_shim".to_string(),
1174         });
1175         build.crates.insert("rustc-main".to_string(), ::Crate {
1176             name: "rustc-main".to_string(),
1177             deps: Vec::new(),
1178             path: cwd.join("src/rustc-main"),
1179             doc_step: "doc-rustc-main".to_string(),
1180             build_step: "build-crate-rustc-main".to_string(),
1181             test_step: "test-rustc-main".to_string(),
1182             bench_step: "bench-rustc-main".to_string(),
1183         });
1184         return build
1185     }
1186
1187     #[test]
1188     fn dist_baseline() {
1189         let build = build(&["dist"], &[], &[]);
1190         let rules = super::build_rules(&build);
1191         let plan = rules.plan();
1192         println!("rules: {:#?}", plan);
1193         assert!(plan.iter().all(|s| s.stage == 2));
1194         assert!(plan.iter().all(|s| s.host == "A" ));
1195         assert!(plan.iter().all(|s| s.target == "A" ));
1196
1197         let step = super::Step {
1198             name: "",
1199             stage: 2,
1200             host: &build.config.build,
1201             target: &build.config.build,
1202         };
1203
1204         assert!(plan.contains(&step.name("dist-docs")));
1205         assert!(plan.contains(&step.name("dist-mingw")));
1206         assert!(plan.contains(&step.name("dist-rustc")));
1207         assert!(plan.contains(&step.name("dist-std")));
1208         assert!(plan.contains(&step.name("dist-src")));
1209     }
1210
1211     #[test]
1212     fn dist_with_targets() {
1213         let build = build(&["dist"], &[], &["B"]);
1214         let rules = super::build_rules(&build);
1215         let plan = rules.plan();
1216         println!("rules: {:#?}", plan);
1217         assert!(plan.iter().all(|s| s.stage == 2));
1218         assert!(plan.iter().all(|s| s.host == "A" ));
1219
1220         let step = super::Step {
1221             name: "",
1222             stage: 2,
1223             host: &build.config.build,
1224             target: &build.config.build,
1225         };
1226
1227         assert!(plan.contains(&step.name("dist-docs")));
1228         assert!(plan.contains(&step.name("dist-mingw")));
1229         assert!(plan.contains(&step.name("dist-rustc")));
1230         assert!(plan.contains(&step.name("dist-std")));
1231         assert!(plan.contains(&step.name("dist-src")));
1232
1233         assert!(plan.contains(&step.target("B").name("dist-docs")));
1234         assert!(plan.contains(&step.target("B").name("dist-mingw")));
1235         assert!(!plan.contains(&step.target("B").name("dist-rustc")));
1236         assert!(plan.contains(&step.target("B").name("dist-std")));
1237         assert!(!plan.contains(&step.target("B").name("dist-src")));
1238     }
1239
1240     #[test]
1241     fn dist_with_hosts() {
1242         let build = build(&["dist"], &["B"], &[]);
1243         let rules = super::build_rules(&build);
1244         let plan = rules.plan();
1245         println!("rules: {:#?}", plan);
1246         assert!(plan.iter().all(|s| s.stage == 2));
1247
1248         let step = super::Step {
1249             name: "",
1250             stage: 2,
1251             host: &build.config.build,
1252             target: &build.config.build,
1253         };
1254
1255         assert!(!plan.iter().any(|s| s.host == "B"));
1256
1257         assert!(plan.contains(&step.name("dist-docs")));
1258         assert!(plan.contains(&step.name("dist-mingw")));
1259         assert!(plan.contains(&step.name("dist-rustc")));
1260         assert!(plan.contains(&step.name("dist-std")));
1261         assert!(plan.contains(&step.name("dist-src")));
1262
1263         assert!(plan.contains(&step.target("B").name("dist-docs")));
1264         assert!(plan.contains(&step.target("B").name("dist-mingw")));
1265         assert!(plan.contains(&step.target("B").name("dist-rustc")));
1266         assert!(plan.contains(&step.target("B").name("dist-std")));
1267         assert!(!plan.contains(&step.target("B").name("dist-src")));
1268     }
1269
1270     #[test]
1271     fn dist_with_targets_and_hosts() {
1272         let build = build(&["dist"], &["B"], &["C"]);
1273         let rules = super::build_rules(&build);
1274         let plan = rules.plan();
1275         println!("rules: {:#?}", plan);
1276         assert!(plan.iter().all(|s| s.stage == 2));
1277
1278         let step = super::Step {
1279             name: "",
1280             stage: 2,
1281             host: &build.config.build,
1282             target: &build.config.build,
1283         };
1284
1285         assert!(!plan.iter().any(|s| s.host == "B"));
1286         assert!(!plan.iter().any(|s| s.host == "C"));
1287
1288         assert!(plan.contains(&step.name("dist-docs")));
1289         assert!(plan.contains(&step.name("dist-mingw")));
1290         assert!(plan.contains(&step.name("dist-rustc")));
1291         assert!(plan.contains(&step.name("dist-std")));
1292         assert!(plan.contains(&step.name("dist-src")));
1293
1294         assert!(plan.contains(&step.target("B").name("dist-docs")));
1295         assert!(plan.contains(&step.target("B").name("dist-mingw")));
1296         assert!(plan.contains(&step.target("B").name("dist-rustc")));
1297         assert!(plan.contains(&step.target("B").name("dist-std")));
1298         assert!(!plan.contains(&step.target("B").name("dist-src")));
1299
1300         assert!(plan.contains(&step.target("C").name("dist-docs")));
1301         assert!(plan.contains(&step.target("C").name("dist-mingw")));
1302         assert!(!plan.contains(&step.target("C").name("dist-rustc")));
1303         assert!(plan.contains(&step.target("C").name("dist-std")));
1304         assert!(!plan.contains(&step.target("C").name("dist-src")));
1305     }
1306
1307     #[test]
1308     fn dist_target_with_target_flag() {
1309         let build = build(&["dist", "--target=C"], &["B"], &["C"]);
1310         let rules = super::build_rules(&build);
1311         let plan = rules.plan();
1312         println!("rules: {:#?}", plan);
1313         assert!(plan.iter().all(|s| s.stage == 2));
1314
1315         let step = super::Step {
1316             name: "",
1317             stage: 2,
1318             host: &build.config.build,
1319             target: &build.config.build,
1320         };
1321
1322         assert!(!plan.iter().any(|s| s.target == "A"));
1323         assert!(!plan.iter().any(|s| s.target == "B"));
1324         assert!(!plan.iter().any(|s| s.host == "B"));
1325         assert!(!plan.iter().any(|s| s.host == "C"));
1326
1327         assert!(plan.contains(&step.target("C").name("dist-docs")));
1328         assert!(plan.contains(&step.target("C").name("dist-mingw")));
1329         assert!(!plan.contains(&step.target("C").name("dist-rustc")));
1330         assert!(plan.contains(&step.target("C").name("dist-std")));
1331         assert!(!plan.contains(&step.target("C").name("dist-src")));
1332     }
1333
1334     #[test]
1335     fn dist_host_with_target_flag() {
1336         let build = build(&["dist", "--host=B", "--target=B"], &["B"], &["C"]);
1337         let rules = super::build_rules(&build);
1338         let plan = rules.plan();
1339         println!("rules: {:#?}", plan);
1340         assert!(plan.iter().all(|s| s.stage == 2));
1341
1342         let step = super::Step {
1343             name: "",
1344             stage: 2,
1345             host: &build.config.build,
1346             target: &build.config.build,
1347         };
1348
1349         assert!(!plan.iter().any(|s| s.target == "A"));
1350         assert!(!plan.iter().any(|s| s.target == "C"));
1351         assert!(!plan.iter().any(|s| s.host == "B"));
1352         assert!(!plan.iter().any(|s| s.host == "C"));
1353
1354         assert!(plan.contains(&step.target("B").name("dist-docs")));
1355         assert!(plan.contains(&step.target("B").name("dist-mingw")));
1356         assert!(plan.contains(&step.target("B").name("dist-rustc")));
1357         assert!(plan.contains(&step.target("B").name("dist-std")));
1358         assert!(plan.contains(&step.target("B").name("dist-src")));
1359
1360         let all = rules.expand(&plan);
1361         println!("all rules: {:#?}", all);
1362         assert!(!all.contains(&step.name("rustc")));
1363         assert!(!all.contains(&step.name("build-crate-std_shim").stage(1)));
1364
1365         // all stage0 compiles should be for the build target, A
1366         for step in all.iter().filter(|s| s.stage == 0) {
1367             if !step.name.contains("build-crate") {
1368                 continue
1369             }
1370             println!("step: {:?}", step);
1371             assert!(step.host != "B");
1372             assert!(step.target != "B");
1373             assert!(step.host != "C");
1374             assert!(step.target != "C");
1375         }
1376     }
1377
1378     #[test]
1379     fn build_default() {
1380         let build = build(&["build"], &["B"], &["C"]);
1381         let rules = super::build_rules(&build);
1382         let plan = rules.plan();
1383         println!("rules: {:#?}", plan);
1384         assert!(plan.iter().all(|s| s.stage == 2));
1385
1386         let step = super::Step {
1387             name: "",
1388             stage: 2,
1389             host: &build.config.build,
1390             target: &build.config.build,
1391         };
1392
1393         // rustc built for all for of (A, B) x (A, B)
1394         assert!(plan.contains(&step.name("librustc")));
1395         assert!(plan.contains(&step.target("B").name("librustc")));
1396         assert!(plan.contains(&step.host("B").target("A").name("librustc")));
1397         assert!(plan.contains(&step.host("B").target("B").name("librustc")));
1398
1399         // rustc never built for C
1400         assert!(!plan.iter().any(|s| {
1401             s.name.contains("rustc") && (s.host == "C" || s.target == "C")
1402         }));
1403
1404         // test built for everything
1405         assert!(plan.contains(&step.name("libtest")));
1406         assert!(plan.contains(&step.target("B").name("libtest")));
1407         assert!(plan.contains(&step.host("B").target("A").name("libtest")));
1408         assert!(plan.contains(&step.host("B").target("B").name("libtest")));
1409         assert!(plan.contains(&step.host("A").target("C").name("libtest")));
1410         assert!(plan.contains(&step.host("B").target("C").name("libtest")));
1411
1412         let all = rules.expand(&plan);
1413         println!("all rules: {:#?}", all);
1414         assert!(all.contains(&step.name("rustc")));
1415         assert!(all.contains(&step.name("libstd")));
1416     }
1417
1418     #[test]
1419     fn build_filtered() {
1420         let build = build(&["build", "--target=C"], &["B"], &["C"]);
1421         let rules = super::build_rules(&build);
1422         let plan = rules.plan();
1423         println!("rules: {:#?}", plan);
1424         assert!(plan.iter().all(|s| s.stage == 2));
1425
1426         assert!(!plan.iter().any(|s| s.name.contains("rustc")));
1427         assert!(plan.iter().all(|s| {
1428             !s.name.contains("test_shim") || s.target == "C"
1429         }));
1430     }
1431
1432     #[test]
1433     fn test_default() {
1434         let build = build(&["test"], &[], &[]);
1435         let rules = super::build_rules(&build);
1436         let plan = rules.plan();
1437         println!("rules: {:#?}", plan);
1438         assert!(plan.iter().all(|s| s.stage == 2));
1439         assert!(plan.iter().all(|s| s.host == "A"));
1440         assert!(plan.iter().all(|s| s.target == "A"));
1441
1442         assert!(plan.iter().any(|s| s.name.contains("-ui")));
1443         assert!(plan.iter().any(|s| s.name.contains("cfail")));
1444         assert!(plan.iter().any(|s| s.name.contains("cfail-full")));
1445         assert!(plan.iter().any(|s| s.name.contains("codegen-units")));
1446         assert!(plan.iter().any(|s| s.name.contains("debuginfo")));
1447         assert!(plan.iter().any(|s| s.name.contains("docs")));
1448         assert!(plan.iter().any(|s| s.name.contains("error-index")));
1449         assert!(plan.iter().any(|s| s.name.contains("incremental")));
1450         assert!(plan.iter().any(|s| s.name.contains("linkchecker")));
1451         assert!(plan.iter().any(|s| s.name.contains("mir-opt")));
1452         assert!(plan.iter().any(|s| s.name.contains("pfail")));
1453         assert!(plan.iter().any(|s| s.name.contains("rfail")));
1454         assert!(plan.iter().any(|s| s.name.contains("rfail-full")));
1455         assert!(plan.iter().any(|s| s.name.contains("rmake")));
1456         assert!(plan.iter().any(|s| s.name.contains("rpass")));
1457         assert!(plan.iter().any(|s| s.name.contains("rpass-full")));
1458         assert!(plan.iter().any(|s| s.name.contains("rustc-all")));
1459         assert!(plan.iter().any(|s| s.name.contains("rustdoc")));
1460         assert!(plan.iter().any(|s| s.name.contains("std-all")));
1461         assert!(plan.iter().any(|s| s.name.contains("test-all")));
1462         assert!(plan.iter().any(|s| s.name.contains("tidy")));
1463         assert!(plan.iter().any(|s| s.name.contains("valgrind")));
1464     }
1465
1466     #[test]
1467     fn test_with_a_target() {
1468         let build = build(&["test", "--target=C"], &[], &["C"]);
1469         let rules = super::build_rules(&build);
1470         let plan = rules.plan();
1471         println!("rules: {:#?}", plan);
1472         assert!(plan.iter().all(|s| s.stage == 2));
1473         assert!(plan.iter().all(|s| s.host == "A"));
1474         assert!(plan.iter().all(|s| s.target == "C"));
1475
1476         assert!(!plan.iter().any(|s| s.name.contains("-ui")));
1477         assert!(plan.iter().any(|s| s.name.contains("cfail")));
1478         assert!(!plan.iter().any(|s| s.name.contains("cfail-full")));
1479         assert!(plan.iter().any(|s| s.name.contains("codegen-units")));
1480         assert!(plan.iter().any(|s| s.name.contains("debuginfo")));
1481         assert!(!plan.iter().any(|s| s.name.contains("docs")));
1482         assert!(!plan.iter().any(|s| s.name.contains("error-index")));
1483         assert!(plan.iter().any(|s| s.name.contains("incremental")));
1484         assert!(!plan.iter().any(|s| s.name.contains("linkchecker")));
1485         assert!(plan.iter().any(|s| s.name.contains("mir-opt")));
1486         assert!(plan.iter().any(|s| s.name.contains("pfail")));
1487         assert!(plan.iter().any(|s| s.name.contains("rfail")));
1488         assert!(!plan.iter().any(|s| s.name.contains("rfail-full")));
1489         assert!(!plan.iter().any(|s| s.name.contains("rmake")));
1490         assert!(plan.iter().any(|s| s.name.contains("rpass")));
1491         assert!(!plan.iter().any(|s| s.name.contains("rpass-full")));
1492         assert!(!plan.iter().any(|s| s.name.contains("rustc-all")));
1493         assert!(!plan.iter().any(|s| s.name.contains("rustdoc")));
1494         assert!(plan.iter().any(|s| s.name.contains("std-all")));
1495         assert!(plan.iter().any(|s| s.name.contains("test-all")));
1496         assert!(!plan.iter().any(|s| s.name.contains("tidy")));
1497         assert!(plan.iter().any(|s| s.name.contains("valgrind")));
1498     }
1499 }