]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/step.rs
rustbuild: allow running debuginfo-lldb tests on linux
[rust.git] / src / bootstrap / step.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Definition of steps of the build system.
12 //!
13 //! This is where some of the real meat of rustbuild is located, in how we
14 //! define targets and the dependencies amongst them. This file can sort of be
15 //! viewed as just defining targets in a makefile which shell out to predefined
16 //! functions elsewhere about how to execute the target.
17 //!
18 //! The primary function here you're likely interested in is the `build_rules`
19 //! function. This will create a `Rules` structure which basically just lists
20 //! everything that rustbuild can do. Each rule has a human-readable name, a
21 //! path associated with it, some dependencies, and then a closure of how to
22 //! actually perform the rule.
23 //!
24 //! All steps below are defined in self-contained units, so adding a new target
25 //! to the build system should just involve adding the meta information here
26 //! along with the actual implementation elsewhere. You can find more comments
27 //! about how to define rules themselves below.
28
29 use std::collections::{HashMap, HashSet};
30 use std::mem;
31
32 use check::{self, TestKind};
33 use compile;
34 use dist;
35 use doc;
36 use flags::Subcommand;
37 use install;
38 use native;
39 use {Compiler, Build, Mode};
40
41 pub fn run(build: &Build) {
42     let rules = build_rules(build);
43     let steps = rules.plan();
44     rules.run(&steps);
45 }
46
47 pub fn build_rules<'a>(build: &'a Build) -> Rules {
48     let mut rules = Rules::new(build);
49
50     // This is the first rule that we're going to define for rustbuild, which is
51     // used to compile LLVM itself. All rules are added through the `rules`
52     // structure created above and are configured through a builder-style
53     // interface.
54     //
55     // First up we see the `build` method. This represents a rule that's part of
56     // the top-level `build` subcommand. For example `./x.py build` is what this
57     // is associating with. Note that this is normally only relevant if you flag
58     // a rule as `default`, which we'll talk about later.
59     //
60     // Next up we'll see two arguments to this method:
61     //
62     // * `llvm` - this is the "human readable" name of this target. This name is
63     //            not accessed anywhere outside this file itself (e.g. not in
64     //            the CLI nor elsewhere in rustbuild). The purpose of this is to
65     //            easily define dependencies between rules. That is, other rules
66     //            will depend on this with the name "llvm".
67     // * `src/llvm` - this is the relevant path to the rule that we're working
68     //                with. This path is the engine behind how commands like
69     //                `./x.py build src/llvm` work. This should typically point
70     //                to the relevant component, but if there's not really a
71     //                path to be assigned here you can pass something like
72     //                `path/to/nowhere` to ignore it.
73     //
74     // After we create the rule with the `build` method we can then configure
75     // various aspects of it. For example this LLVM rule uses `.host(true)` to
76     // flag that it's a rule only for host targets. In other words, LLVM isn't
77     // compiled for targets configured through `--target` (e.g. those we're just
78     // building a standard library for).
79     //
80     // Next up the `dep` method will add a dependency to this rule. The closure
81     // is yielded the step that represents executing the `llvm` rule itself
82     // (containing information like stage, host, target, ...) and then it must
83     // return a target that the step depends on. Here LLVM is actually
84     // interesting where a cross-compiled LLVM depends on the host LLVM, but
85     // otherwise it has no dependencies.
86     //
87     // To handle this we do a bit of dynamic dispatch to see what the dependency
88     // is. If we're building a LLVM for the build triple, then we don't actually
89     // have any dependencies! To do that we return a dependency on the `Step::noop()`
90     // target which does nothing.
91     //
92     // If we're build a cross-compiled LLVM, however, we need to assemble the
93     // libraries from the previous compiler. This step has the same name as
94     // ours (llvm) but we want it for a different target, so we use the
95     // builder-style methods on `Step` to configure this target to the build
96     // triple.
97     //
98     // Finally, to finish off this rule, we define how to actually execute it.
99     // That logic is all defined in the `native` module so we just delegate to
100     // the relevant function there. The argument to the closure passed to `run`
101     // is a `Step` (defined below) which encapsulates information like the
102     // stage, target, host, etc.
103     rules.build("llvm", "src/llvm")
104          .host(true)
105          .dep(move |s| {
106              if s.target == build.config.build {
107                  Step::noop()
108              } else {
109                  s.target(&build.config.build)
110              }
111          })
112          .run(move |s| native::llvm(build, s.target));
113
114     // Ok! After that example rule  that's hopefully enough to explain what's
115     // going on here. You can check out the API docs below and also see a bunch
116     // more examples of rules directly below as well.
117
118     // the compiler with no target libraries ready to go
119     rules.build("rustc", "src/rustc")
120          .dep(|s| s.name("create-sysroot").target(s.host))
121          .dep(move |s| {
122              if s.stage == 0 {
123                  Step::noop()
124              } else {
125                  s.name("librustc")
126                   .host(&build.config.build)
127                   .stage(s.stage - 1)
128              }
129          })
130          .run(move |s| compile::assemble_rustc(build, s.stage, s.target));
131
132     // Helper for loading an entire DAG of crates, rooted at `name`
133     let krates = |name: &str| {
134         let mut ret = Vec::new();
135         let mut list = vec![name];
136         let mut visited = HashSet::new();
137         while let Some(krate) = list.pop() {
138             let default = krate == name;
139             let krate = &build.crates[krate];
140             let path = krate.path.strip_prefix(&build.src).unwrap();
141             ret.push((krate, path.to_str().unwrap(), default));
142             for dep in krate.deps.iter() {
143                 if visited.insert(dep) && dep != "build_helper" {
144                     list.push(dep);
145                 }
146             }
147         }
148         return ret
149     };
150
151     // ========================================================================
152     // Crate compilations
153     //
154     // Tools used during the build system but not shipped
155     rules.build("create-sysroot", "path/to/nowhere")
156          .run(move |s| compile::create_sysroot(build, &s.compiler()));
157
158     // These rules are "pseudo rules" that don't actually do any work
159     // themselves, but represent a complete sysroot with the relevant compiler
160     // linked into place.
161     //
162     // That is, depending on "libstd" means that when the rule is completed then
163     // the `stage` sysroot for the compiler `host` will be available with a
164     // standard library built for `target` linked in place. Not all rules need
165     // the compiler itself to be available, just the standard library, so
166     // there's a distinction between the two.
167     rules.build("libstd", "src/libstd")
168          .dep(|s| s.name("rustc").target(s.host))
169          .dep(|s| s.name("libstd-link"));
170     rules.build("libtest", "src/libtest")
171          .dep(|s| s.name("libstd"))
172          .dep(|s| s.name("libtest-link"))
173          .default(true);
174     rules.build("librustc", "src/librustc")
175          .dep(|s| s.name("libtest"))
176          .dep(|s| s.name("librustc-link"))
177          .host(true)
178          .default(true);
179
180     // Helper method to define the rules to link a crate into its place in the
181     // sysroot.
182     //
183     // The logic here is a little subtle as there's a few cases to consider.
184     // Not all combinations of (stage, host, target) actually require something
185     // to be compiled, but rather libraries could get propagated from a
186     // different location. For example:
187     //
188     // * Any crate with a `host` that's not the build triple will not actually
189     //   compile something. A different `host` means that the build triple will
190     //   actually compile the libraries, and then we'll copy them over from the
191     //   build triple to the `host` directory.
192     //
193     // * Some crates aren't even compiled by the build triple, but may be copied
194     //   from previous stages. For example if we're not doing a full bootstrap
195     //   then we may just depend on the stage1 versions of libraries to be
196     //   available to get linked forward.
197     //
198     // * Finally, there are some cases, however, which do indeed comiple crates
199     //   and link them into place afterwards.
200     //
201     // The rule definition below mirrors these three cases. The `dep` method
202     // calculates the correct dependency which either comes from stage1, a
203     // different compiler, or from actually building the crate itself (the `dep`
204     // rule). The `run` rule then mirrors these three cases and links the cases
205     // forward into the compiler sysroot specified from the correct location.
206     fn crate_rule<'a, 'b>(build: &'a Build,
207                           rules: &'b mut Rules<'a>,
208                           krate: &'a str,
209                           dep: &'a str,
210                           link: fn(&Build, &Compiler, &Compiler, &str))
211                           -> RuleBuilder<'a, 'b> {
212         let mut rule = rules.build(&krate, "path/to/nowhere");
213         rule.dep(move |s| {
214                 if build.force_use_stage1(&s.compiler(), s.target) {
215                     s.host(&build.config.build).stage(1)
216                 } else if s.host == build.config.build {
217                     s.name(dep)
218                 } else {
219                     s.host(&build.config.build)
220                 }
221             })
222             .run(move |s| {
223                 if build.force_use_stage1(&s.compiler(), s.target) {
224                     link(build,
225                          &s.stage(1).host(&build.config.build).compiler(),
226                          &s.compiler(),
227                          s.target)
228                 } else if s.host == build.config.build {
229                     link(build, &s.compiler(), &s.compiler(), s.target)
230                 } else {
231                     link(build,
232                          &s.host(&build.config.build).compiler(),
233                          &s.compiler(),
234                          s.target)
235                 }
236             });
237             return rule
238     }
239
240     // Similar to the `libstd`, `libtest`, and `librustc` rules above, except
241     // these rules only represent the libraries being available in the sysroot,
242     // not the compiler itself. This is done as not all rules need a compiler in
243     // the sysroot, but may just need the libraries.
244     //
245     // All of these rules use the helper definition above.
246     crate_rule(build,
247                &mut rules,
248                "libstd-link",
249                "build-crate-std_shim",
250                compile::std_link)
251         .dep(|s| s.name("startup-objects"))
252         .dep(|s| s.name("create-sysroot").target(s.host));
253     crate_rule(build,
254                &mut rules,
255                "libtest-link",
256                "build-crate-test_shim",
257                compile::test_link)
258         .dep(|s| s.name("libstd-link"));
259     crate_rule(build,
260                &mut rules,
261                "librustc-link",
262                "build-crate-rustc-main",
263                compile::rustc_link)
264         .dep(|s| s.name("libtest-link"));
265
266     for (krate, path, _default) in krates("std_shim") {
267         rules.build(&krate.build_step, path)
268              .dep(|s| s.name("startup-objects"))
269              .dep(move |s| s.name("rustc").host(&build.config.build).target(s.host))
270              .run(move |s| compile::std(build, s.target, &s.compiler()));
271     }
272     for (krate, path, _default) in krates("test_shim") {
273         rules.build(&krate.build_step, path)
274              .dep(|s| s.name("libstd-link"))
275              .run(move |s| compile::test(build, s.target, &s.compiler()));
276     }
277     for (krate, path, _default) in krates("rustc-main") {
278         rules.build(&krate.build_step, path)
279              .dep(|s| s.name("libtest-link"))
280              .dep(move |s| s.name("llvm").host(&build.config.build).stage(0))
281              .run(move |s| compile::rustc(build, s.target, &s.compiler()));
282     }
283
284     rules.build("startup-objects", "src/rtstartup")
285          .dep(|s| s.name("create-sysroot").target(s.host))
286          .run(move |s| compile::build_startup_objects(build, &s.compiler(), s.target));
287
288     // ========================================================================
289     // Test targets
290     //
291     // Various unit tests and tests suites we can run
292     {
293         let mut suite = |name, path, mode, dir| {
294             rules.test(name, path)
295                  .dep(|s| s.name("libtest"))
296                  .dep(|s| s.name("tool-compiletest").target(s.host))
297                  .dep(|s| s.name("test-helpers"))
298                  .dep(move |s| {
299                      if s.target.contains("android") {
300                          s.name("android-copy-libs")
301                      } else {
302                          Step::noop()
303                      }
304                  })
305                  .default(mode != "pretty") // pretty tests don't run everywhere
306                  .run(move |s| {
307                      check::compiletest(build, &s.compiler(), s.target, mode, dir)
308                  });
309         };
310
311         suite("check-rpass", "src/test/run-pass", "run-pass", "run-pass");
312         suite("check-cfail", "src/test/compile-fail", "compile-fail", "compile-fail");
313         suite("check-pfail", "src/test/parse-fail", "parse-fail", "parse-fail");
314         suite("check-rfail", "src/test/run-fail", "run-fail", "run-fail");
315         suite("check-rpass-valgrind", "src/test/run-pass-valgrind",
316               "run-pass-valgrind", "run-pass-valgrind");
317         suite("check-mir-opt", "src/test/mir-opt", "mir-opt", "mir-opt");
318         if build.config.codegen_tests {
319             suite("check-codegen", "src/test/codegen", "codegen", "codegen");
320         }
321         suite("check-codegen-units", "src/test/codegen-units", "codegen-units",
322               "codegen-units");
323         suite("check-incremental", "src/test/incremental", "incremental",
324               "incremental");
325         suite("check-ui", "src/test/ui", "ui", "ui");
326     }
327
328     if build.config.build.contains("msvc") {
329         // nothing to do for debuginfo tests
330     } else {
331         rules.test("check-debuginfo-lldb", "src/test/debuginfo-lldb")
332              .dep(|s| s.name("libtest"))
333              .dep(|s| s.name("tool-compiletest").target(s.host))
334              .dep(|s| s.name("test-helpers"))
335              .dep(|s| s.name("debugger-scripts"))
336              .run(move |s| check::compiletest(build, &s.compiler(), s.target,
337                                          "debuginfo-lldb", "debuginfo"));
338         rules.test("check-debuginfo-gdb", "src/test/debuginfo-gdb")
339              .dep(|s| s.name("libtest"))
340              .dep(|s| s.name("tool-compiletest").target(s.host))
341              .dep(|s| s.name("test-helpers"))
342              .dep(|s| s.name("debugger-scripts"))
343              .run(move |s| check::compiletest(build, &s.compiler(), s.target,
344                                          "debuginfo-gdb", "debuginfo"));
345         let mut rule = rules.test("check-debuginfo", "src/test/debuginfo");
346         rule.default(true);
347         if build.config.build.contains("apple") {
348             rule.dep(|s| s.name("check-debuginfo-lldb"));
349         } else {
350             rule.dep(|s| s.name("check-debuginfo-gdb"));
351         }
352     }
353
354     rules.test("debugger-scripts", "src/etc/lldb_batchmode.py")
355          .run(move |s| dist::debugger_scripts(build, &build.sysroot(&s.compiler()),
356                                          s.target));
357
358     {
359         let mut suite = |name, path, mode, dir| {
360             rules.test(name, path)
361                  .dep(|s| s.name("librustc"))
362                  .dep(|s| s.name("test-helpers"))
363                  .dep(|s| s.name("tool-compiletest").target(s.host))
364                  .default(mode != "pretty")
365                  .host(true)
366                  .run(move |s| {
367                      check::compiletest(build, &s.compiler(), s.target, mode, dir)
368                  });
369         };
370
371         suite("check-rpass-full", "src/test/run-pass-fulldeps",
372               "run-pass", "run-pass-fulldeps");
373         suite("check-cfail-full", "src/test/compile-fail-fulldeps",
374               "compile-fail", "compile-fail-fulldeps");
375         suite("check-rmake", "src/test/run-make", "run-make", "run-make");
376         suite("check-rustdoc", "src/test/rustdoc", "rustdoc", "rustdoc");
377         suite("check-pretty", "src/test/pretty", "pretty", "pretty");
378         suite("check-pretty-rpass", "src/test/run-pass/pretty", "pretty",
379               "run-pass");
380         suite("check-pretty-rfail", "src/test/run-fail/pretty", "pretty",
381               "run-fail");
382         suite("check-pretty-valgrind", "src/test/run-pass-valgrind/pretty", "pretty",
383               "run-pass-valgrind");
384         suite("check-pretty-rpass-full", "src/test/run-pass-fulldeps/pretty",
385               "pretty", "run-pass-fulldeps");
386         suite("check-pretty-rfail-full", "src/test/run-fail-fulldeps/pretty",
387               "pretty", "run-fail-fulldeps");
388     }
389
390     for (krate, path, _default) in krates("std_shim") {
391         rules.test(&krate.test_step, path)
392              .dep(|s| s.name("libtest"))
393              .run(move |s| check::krate(build, &s.compiler(), s.target,
394                                         Mode::Libstd, TestKind::Test,
395                                         Some(&krate.name)));
396     }
397     rules.test("check-std-all", "path/to/nowhere")
398          .dep(|s| s.name("libtest"))
399          .default(true)
400          .run(move |s| check::krate(build, &s.compiler(), s.target,
401                                     Mode::Libstd, TestKind::Test, None));
402
403     // std benchmarks
404     for (krate, path, _default) in krates("std_shim") {
405         rules.bench(&krate.bench_step, path)
406              .dep(|s| s.name("libtest"))
407              .run(move |s| check::krate(build, &s.compiler(), s.target,
408                                         Mode::Libstd, TestKind::Bench,
409                                         Some(&krate.name)));
410     }
411     rules.bench("bench-std-all", "path/to/nowhere")
412          .dep(|s| s.name("libtest"))
413          .default(true)
414          .run(move |s| check::krate(build, &s.compiler(), s.target,
415                                     Mode::Libstd, TestKind::Bench, None));
416
417     for (krate, path, _default) in krates("test_shim") {
418         rules.test(&krate.test_step, path)
419              .dep(|s| s.name("libtest"))
420              .run(move |s| check::krate(build, &s.compiler(), s.target,
421                                         Mode::Libtest, TestKind::Test,
422                                         Some(&krate.name)));
423     }
424     rules.test("check-test-all", "path/to/nowhere")
425          .dep(|s| s.name("libtest"))
426          .default(true)
427          .run(move |s| check::krate(build, &s.compiler(), s.target,
428                                     Mode::Libtest, TestKind::Test, None));
429     for (krate, path, _default) in krates("rustc-main") {
430         rules.test(&krate.test_step, path)
431              .dep(|s| s.name("librustc"))
432              .host(true)
433              .run(move |s| check::krate(build, &s.compiler(), s.target,
434                                         Mode::Librustc, TestKind::Test,
435                                         Some(&krate.name)));
436     }
437     rules.test("check-rustc-all", "path/to/nowhere")
438          .dep(|s| s.name("librustc"))
439          .default(true)
440          .host(true)
441          .run(move |s| check::krate(build, &s.compiler(), s.target,
442                                     Mode::Librustc, TestKind::Test, None));
443
444     rules.test("check-linkchecker", "src/tools/linkchecker")
445          .dep(|s| s.name("tool-linkchecker"))
446          .dep(|s| s.name("default:doc"))
447          .default(true)
448          .host(true)
449          .run(move |s| check::linkcheck(build, s.stage, s.target));
450     rules.test("check-cargotest", "src/tools/cargotest")
451          .dep(|s| s.name("tool-cargotest"))
452          .dep(|s| s.name("librustc"))
453          .host(true)
454          .run(move |s| check::cargotest(build, s.stage, s.target));
455     rules.test("check-tidy", "src/tools/tidy")
456          .dep(|s| s.name("tool-tidy").stage(0))
457          .default(true)
458          .host(true)
459          .run(move |s| check::tidy(build, 0, s.target));
460     rules.test("check-error-index", "src/tools/error_index_generator")
461          .dep(|s| s.name("libstd"))
462          .dep(|s| s.name("tool-error-index").host(s.host))
463          .default(true)
464          .host(true)
465          .run(move |s| check::error_index(build, &s.compiler()));
466     rules.test("check-docs", "src/doc")
467          .dep(|s| s.name("libtest"))
468          .default(true)
469          .host(true)
470          .run(move |s| check::docs(build, &s.compiler()));
471     rules.test("check-distcheck", "distcheck")
472          .dep(|s| s.name("dist-src"))
473          .run(move |_| check::distcheck(build));
474
475
476     rules.build("test-helpers", "src/rt/rust_test_helpers.c")
477          .run(move |s| native::test_helpers(build, s.target));
478     rules.test("android-copy-libs", "path/to/nowhere")
479          .dep(|s| s.name("libtest"))
480          .run(move |s| check::android_copy_libs(build, &s.compiler(), s.target));
481
482     // ========================================================================
483     // Build tools
484     //
485     // Tools used during the build system but not shipped
486     rules.build("tool-rustbook", "src/tools/rustbook")
487          .dep(|s| s.name("librustc"))
488          .run(move |s| compile::tool(build, s.stage, s.target, "rustbook"));
489     rules.build("tool-error-index", "src/tools/error_index_generator")
490          .dep(|s| s.name("librustc"))
491          .run(move |s| compile::tool(build, s.stage, s.target, "error_index_generator"));
492     rules.build("tool-tidy", "src/tools/tidy")
493          .dep(|s| s.name("libstd"))
494          .run(move |s| compile::tool(build, s.stage, s.target, "tidy"));
495     rules.build("tool-linkchecker", "src/tools/linkchecker")
496          .dep(|s| s.name("libstd"))
497          .run(move |s| compile::tool(build, s.stage, s.target, "linkchecker"));
498     rules.build("tool-cargotest", "src/tools/cargotest")
499          .dep(|s| s.name("libstd"))
500          .run(move |s| compile::tool(build, s.stage, s.target, "cargotest"));
501     rules.build("tool-compiletest", "src/tools/compiletest")
502          .dep(|s| s.name("libtest"))
503          .run(move |s| compile::tool(build, s.stage, s.target, "compiletest"));
504
505     // ========================================================================
506     // Documentation targets
507     rules.doc("doc-book", "src/doc/book")
508          .dep(move |s| s.name("tool-rustbook").target(&build.config.build))
509          .default(build.config.docs)
510          .run(move |s| doc::rustbook(build, s.stage, s.target, "book"));
511     rules.doc("doc-nomicon", "src/doc/nomicon")
512          .dep(move |s| s.name("tool-rustbook").target(&build.config.build))
513          .default(build.config.docs)
514          .run(move |s| doc::rustbook(build, s.stage, s.target, "nomicon"));
515     rules.doc("doc-standalone", "src/doc")
516          .dep(move |s| s.name("rustc").host(&build.config.build).target(&build.config.build))
517          .default(build.config.docs)
518          .run(move |s| doc::standalone(build, s.stage, s.target));
519     rules.doc("doc-error-index", "src/tools/error_index_generator")
520          .dep(move |s| s.name("tool-error-index").target(&build.config.build))
521          .dep(move |s| s.name("librustc-link"))
522          .default(build.config.docs)
523          .host(true)
524          .run(move |s| doc::error_index(build, s.stage, s.target));
525     for (krate, path, default) in krates("std_shim") {
526         rules.doc(&krate.doc_step, path)
527              .dep(|s| s.name("libstd-link"))
528              .default(default && build.config.docs)
529              .run(move |s| doc::std(build, s.stage, s.target));
530     }
531     for (krate, path, default) in krates("test_shim") {
532         rules.doc(&krate.doc_step, path)
533              .dep(|s| s.name("libtest-link"))
534              .default(default && build.config.compiler_docs)
535              .run(move |s| doc::test(build, s.stage, s.target));
536     }
537     for (krate, path, default) in krates("rustc-main") {
538         rules.doc(&krate.doc_step, path)
539              .dep(|s| s.name("librustc-link"))
540              .host(true)
541              .default(default && build.config.compiler_docs)
542              .run(move |s| doc::rustc(build, s.stage, s.target));
543     }
544
545     // ========================================================================
546     // Distribution targets
547     rules.dist("dist-rustc", "src/librustc")
548          .dep(move |s| s.name("rustc").host(&build.config.build))
549          .host(true)
550          .default(true)
551          .run(move |s| dist::rustc(build, s.stage, s.target));
552     rules.dist("dist-std", "src/libstd")
553          .dep(move |s| {
554              // We want to package up as many target libraries as possible
555              // for the `rust-std` package, so if this is a host target we
556              // depend on librustc and otherwise we just depend on libtest.
557              if build.config.host.iter().any(|t| t == s.target) {
558                  s.name("librustc-link")
559              } else {
560                  s.name("libtest-link")
561              }
562          })
563          .default(true)
564          .run(move |s| dist::std(build, &s.compiler(), s.target));
565     rules.dist("dist-mingw", "path/to/nowhere")
566          .default(true)
567          .run(move |s| {
568              if s.target.contains("pc-windows-gnu") {
569                  dist::mingw(build, s.target)
570              }
571          });
572     rules.dist("dist-src", "src")
573          .default(true)
574          .host(true)
575          .run(move |s| dist::rust_src(build, s.target));
576     rules.dist("dist-docs", "src/doc")
577          .default(true)
578          .dep(|s| s.name("default:doc"))
579          .run(move |s| dist::docs(build, s.stage, s.target));
580     rules.dist("dist-analysis", "analysis")
581          .dep(|s| s.name("dist-std"))
582          .default(true)
583          .run(move |s| dist::analysis(build, &s.compiler(), s.target));
584     rules.dist("install", "src")
585          .dep(|s| s.name("default:dist"))
586          .run(move |s| install::install(build, s.stage, s.target));
587
588     rules.verify();
589     return rules;
590 }
591
592 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
593 struct Step<'a> {
594     /// Human readable name of the rule this step is executing. Possible names
595     /// are all defined above in `build_rules`.
596     name: &'a str,
597
598     /// The stage this step is executing in. This is typically 0, 1, or 2.
599     stage: u32,
600
601     /// This step will likely involve a compiler, and the target that compiler
602     /// itself is built for is called the host, this variable. Typically this is
603     /// the target of the build machine itself.
604     host: &'a str,
605
606     /// The target that this step represents generating. If you're building a
607     /// standard library for a new suite of targets, for example, this'll be set
608     /// to those targets.
609     target: &'a str,
610 }
611
612 impl<'a> Step<'a> {
613     fn noop() -> Step<'a> {
614         Step { name: "", stage: 0, host: "", target: "" }
615     }
616
617     /// Creates a new step which is the same as this, except has a new name.
618     fn name(&self, name: &'a str) -> Step<'a> {
619         Step { name: name, ..*self }
620     }
621
622     /// Creates a new step which is the same as this, except has a new stage.
623     fn stage(&self, stage: u32) -> Step<'a> {
624         Step { stage: stage, ..*self }
625     }
626
627     /// Creates a new step which is the same as this, except has a new host.
628     fn host(&self, host: &'a str) -> Step<'a> {
629         Step { host: host, ..*self }
630     }
631
632     /// Creates a new step which is the same as this, except has a new target.
633     fn target(&self, target: &'a str) -> Step<'a> {
634         Step { target: target, ..*self }
635     }
636
637     /// Returns the `Compiler` structure that this step corresponds to.
638     fn compiler(&self) -> Compiler<'a> {
639         Compiler::new(self.stage, self.host)
640     }
641 }
642
643 struct Rule<'a> {
644     /// The human readable name of this target, defined in `build_rules`.
645     name: &'a str,
646
647     /// The path associated with this target, used in the `./x.py` driver for
648     /// easy and ergonomic specification of what to do.
649     path: &'a str,
650
651     /// The "kind" of top-level command that this rule is associated with, only
652     /// relevant if this is a default rule.
653     kind: Kind,
654
655     /// List of dependencies this rule has. Each dependency is a function from a
656     /// step that's being executed to another step that should be executed.
657     deps: Vec<Box<Fn(&Step<'a>) -> Step<'a> + 'a>>,
658
659     /// How to actually execute this rule. Takes a step with contextual
660     /// information and then executes it.
661     run: Box<Fn(&Step<'a>) + 'a>,
662
663     /// Whether or not this is a "default" rule. That basically means that if
664     /// you run, for example, `./x.py test` whether it's included or not.
665     default: bool,
666
667     /// Whether or not this is a "host" rule, or in other words whether this is
668     /// only intended for compiler hosts and not for targets that are being
669     /// generated.
670     host: bool,
671 }
672
673 #[derive(PartialEq)]
674 enum Kind {
675     Build,
676     Test,
677     Bench,
678     Dist,
679     Doc,
680 }
681
682 impl<'a> Rule<'a> {
683     fn new(name: &'a str, path: &'a str, kind: Kind) -> Rule<'a> {
684         Rule {
685             name: name,
686             deps: Vec::new(),
687             run: Box::new(|_| ()),
688             path: path,
689             kind: kind,
690             default: false,
691             host: false,
692         }
693     }
694 }
695
696 /// Builder pattern returned from the various methods on `Rules` which will add
697 /// the rule to the internal list on `Drop`.
698 struct RuleBuilder<'a: 'b, 'b> {
699     rules: &'b mut Rules<'a>,
700     rule: Rule<'a>,
701 }
702
703 impl<'a, 'b> RuleBuilder<'a, 'b> {
704     fn dep<F>(&mut self, f: F) -> &mut Self
705         where F: Fn(&Step<'a>) -> Step<'a> + 'a,
706     {
707         self.rule.deps.push(Box::new(f));
708         self
709     }
710
711     fn run<F>(&mut self, f: F) -> &mut Self
712         where F: Fn(&Step<'a>) + 'a,
713     {
714         self.rule.run = Box::new(f);
715         self
716     }
717
718     fn default(&mut self, default: bool) -> &mut Self {
719         self.rule.default = default;
720         self
721     }
722
723     fn host(&mut self, host: bool) -> &mut Self {
724         self.rule.host = host;
725         self
726     }
727 }
728
729 impl<'a, 'b> Drop for RuleBuilder<'a, 'b> {
730     fn drop(&mut self) {
731         let rule = mem::replace(&mut self.rule, Rule::new("", "", Kind::Build));
732         let prev = self.rules.rules.insert(rule.name, rule);
733         if let Some(prev) = prev {
734             panic!("duplicate rule named: {}", prev.name);
735         }
736     }
737 }
738
739 pub struct Rules<'a> {
740     build: &'a Build,
741     sbuild: Step<'a>,
742     rules: HashMap<&'a str, Rule<'a>>,
743 }
744
745 impl<'a> Rules<'a> {
746     fn new(build: &'a Build) -> Rules<'a> {
747         Rules {
748             build: build,
749             sbuild: Step {
750                 stage: build.flags.stage.unwrap_or(2),
751                 target: &build.config.build,
752                 host: &build.config.build,
753                 name: "",
754             },
755             rules: HashMap::new(),
756         }
757     }
758
759     /// Creates a new rule of `Kind::Build` with the specified human readable
760     /// name and path associated with it.
761     ///
762     /// The builder returned should be configured further with information such
763     /// as how to actually run this rule.
764     fn build<'b>(&'b mut self, name: &'a str, path: &'a str)
765                  -> RuleBuilder<'a, 'b> {
766         self.rule(name, path, Kind::Build)
767     }
768
769     /// Same as `build`, but for `Kind::Test`.
770     fn test<'b>(&'b mut self, name: &'a str, path: &'a str)
771                 -> RuleBuilder<'a, 'b> {
772         self.rule(name, path, Kind::Test)
773     }
774
775     /// Same as `build`, but for `Kind::Bench`.
776     fn bench<'b>(&'b mut self, name: &'a str, path: &'a str)
777                 -> RuleBuilder<'a, 'b> {
778         self.rule(name, path, Kind::Bench)
779     }
780
781     /// Same as `build`, but for `Kind::Doc`.
782     fn doc<'b>(&'b mut self, name: &'a str, path: &'a str)
783                -> RuleBuilder<'a, 'b> {
784         self.rule(name, path, Kind::Doc)
785     }
786
787     /// Same as `build`, but for `Kind::Dist`.
788     fn dist<'b>(&'b mut self, name: &'a str, path: &'a str)
789                 -> RuleBuilder<'a, 'b> {
790         self.rule(name, path, Kind::Dist)
791     }
792
793     fn rule<'b>(&'b mut self,
794                 name: &'a str,
795                 path: &'a str,
796                 kind: Kind) -> RuleBuilder<'a, 'b> {
797         RuleBuilder {
798             rules: self,
799             rule: Rule::new(name, path, kind),
800         }
801     }
802
803     /// Verify the dependency graph defined by all our rules are correct, e.g.
804     /// everything points to a valid something else.
805     fn verify(&self) {
806         for rule in self.rules.values() {
807             for dep in rule.deps.iter() {
808                 let dep = dep(&self.sbuild.name(rule.name));
809                 if self.rules.contains_key(&dep.name) || dep.name.starts_with("default:") {
810                     continue
811                 }
812                 if dep == Step::noop() {
813                     continue
814                 }
815                 panic!("\
816
817 invalid rule dependency graph detected, was a rule added and maybe typo'd?
818
819     `{}` depends on `{}` which does not exist
820
821 ", rule.name, dep.name);
822             }
823         }
824     }
825
826     pub fn print_help(&self, command: &str) {
827         let kind = match command {
828             "build" => Kind::Build,
829             "doc" => Kind::Doc,
830             "test" => Kind::Test,
831             "bench" => Kind::Bench,
832             "dist" => Kind::Dist,
833             _ => return,
834         };
835         let rules = self.rules.values().filter(|r| r.kind == kind);
836         let rules = rules.filter(|r| !r.path.contains("nowhere"));
837         let mut rules = rules.collect::<Vec<_>>();
838         rules.sort_by_key(|r| r.path);
839
840         println!("Available paths:\n");
841         for rule in rules {
842             print!("    ./x.py {} {}", command, rule.path);
843
844             println!("");
845         }
846     }
847
848     /// Construct the top-level build steps that we're going to be executing,
849     /// given the subcommand that our build is performing.
850     fn plan(&self) -> Vec<Step<'a>> {
851         // Ok, the logic here is pretty subtle, and involves quite a few
852         // conditionals. The basic idea here is to:
853         //
854         // 1. First, filter all our rules to the relevant ones. This means that
855         //    the command specified corresponds to one of our `Kind` variants,
856         //    and we filter all rules based on that.
857         //
858         // 2. Next, we determine which rules we're actually executing. If a
859         //    number of path filters were specified on the command line we look
860         //    for those, otherwise we look for anything tagged `default`.
861         //
862         // 3. Finally, we generate some steps with host and target information.
863         //
864         // The last step is by far the most complicated and subtle. The basic
865         // thinking here is that we want to take the cartesian product of
866         // specified hosts and targets and build rules with that. The list of
867         // hosts and targets, if not specified, come from the how this build was
868         // configured. If the rule we're looking at is a host-only rule the we
869         // ignore the list of targets and instead consider the list of hosts
870         // also the list of targets.
871         //
872         // Once the host and target lists are generated we take the cartesian
873         // product of the two and then create a step based off them. Note that
874         // the stage each step is associated was specified with the `--step`
875         // flag on the command line.
876         let (kind, paths) = match self.build.flags.cmd {
877             Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
878             Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
879             Subcommand::Test { ref paths, test_args: _ } => (Kind::Test, &paths[..]),
880             Subcommand::Bench { ref paths, test_args: _ } => (Kind::Bench, &paths[..]),
881             Subcommand::Dist { install } => {
882                 if install {
883                     return vec![self.sbuild.name("install")]
884                 } else {
885                     (Kind::Dist, &[][..])
886                 }
887             }
888             Subcommand::Clean => panic!(),
889         };
890
891         self.rules.values().filter(|rule| rule.kind == kind).filter(|rule| {
892             (paths.len() == 0 && rule.default) || paths.iter().any(|path| {
893                 path.ends_with(rule.path)
894             })
895         }).flat_map(|rule| {
896             let hosts = if self.build.flags.host.len() > 0 {
897                 &self.build.flags.host
898             } else {
899                 if kind == Kind::Dist {
900                     // For 'dist' steps we only distribute artifacts built from
901                     // the build platform, so only consider that in the hosts
902                     // array.
903                     // NOTE: This relies on the fact that the build triple is
904                     // always placed first, as done in `config.rs`.
905                     &self.build.config.host[..1]
906                 } else {
907                     &self.build.config.host
908                 }
909             };
910             let targets = if self.build.flags.target.len() > 0 {
911                 &self.build.flags.target
912             } else {
913                 &self.build.config.target
914             };
915             // Determine the actual targets participating in this rule.
916             // NOTE: We should keep the full projection from build triple to
917             // the hosts for the dist steps, now that the hosts array above is
918             // truncated to avoid duplication of work in that case. Therefore
919             // the original non-shadowed hosts array is used below.
920             let arr = if rule.host {
921                 // If --target was specified but --host wasn't specified,
922                 // don't run any host-only tests. Also, respect any `--host`
923                 // overrides as done for `hosts`.
924                 if self.build.flags.host.len() > 0 {
925                     &self.build.flags.host[..]
926                 } else if self.build.flags.target.len() > 0 {
927                     &[]
928                 } else {
929                     &self.build.config.host[..]
930                 }
931             } else {
932                 targets
933             };
934
935             hosts.iter().flat_map(move |host| {
936                 arr.iter().map(move |target| {
937                     self.sbuild.name(rule.name).target(target).host(host)
938                 })
939             })
940         }).collect()
941     }
942
943     /// Execute all top-level targets indicated by `steps`.
944     ///
945     /// This will take the list returned by `plan` and then execute each step
946     /// along with all required dependencies as it goes up the chain.
947     fn run(&self, steps: &[Step<'a>]) {
948         self.build.verbose("bootstrap top targets:");
949         for step in steps.iter() {
950             self.build.verbose(&format!("\t{:?}", step));
951         }
952
953         // Using `steps` as the top-level targets, make a topological ordering
954         // of what we need to do.
955         let mut order = Vec::new();
956         let mut added = HashSet::new();
957         added.insert(Step::noop());
958         for step in steps.iter().cloned() {
959             self.fill(step, &mut order, &mut added);
960         }
961
962         // Print out what we're doing for debugging
963         self.build.verbose("bootstrap build plan:");
964         for step in order.iter() {
965             self.build.verbose(&format!("\t{:?}", step));
966         }
967
968         // And finally, iterate over everything and execute it.
969         for step in order.iter() {
970             if self.build.flags.keep_stage.map_or(false, |s| step.stage <= s) {
971                 self.build.verbose(&format!("keeping step {:?}", step));
972                 continue;
973             }
974             self.build.verbose(&format!("executing step {:?}", step));
975             (self.rules[step.name].run)(step);
976         }
977     }
978
979     /// Performs topological sort of dependencies rooted at the `step`
980     /// specified, pushing all results onto the `order` vector provided.
981     ///
982     /// In other words, when this method returns, the `order` vector will
983     /// contain a list of steps which if executed in order will eventually
984     /// complete the `step` specified as well.
985     ///
986     /// The `added` set specified here is the set of steps that are already
987     /// present in `order` (and hence don't need to be added again).
988     fn fill(&self,
989             step: Step<'a>,
990             order: &mut Vec<Step<'a>>,
991             added: &mut HashSet<Step<'a>>) {
992         if !added.insert(step.clone()) {
993             return
994         }
995         for dep in self.rules[step.name].deps.iter() {
996             let dep = dep(&step);
997             if dep.name.starts_with("default:") {
998                 let kind = match &dep.name[8..] {
999                     "doc" => Kind::Doc,
1000                     "dist" => Kind::Dist,
1001                     kind => panic!("unknown kind: `{}`", kind),
1002                 };
1003                 let host = self.build.config.host.iter().any(|h| h == dep.target);
1004                 let rules = self.rules.values().filter(|r| r.default);
1005                 for rule in rules.filter(|r| r.kind == kind && (!r.host || host)) {
1006                     self.fill(dep.name(rule.name), order, added);
1007                 }
1008             } else {
1009                 self.fill(dep, order, added);
1010             }
1011         }
1012         order.push(step);
1013     }
1014 }