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