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