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