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