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.
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.
11 //! Definition of steps of the build system.
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.
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.
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.
29 use std::collections::{BTreeMap, HashSet, HashMap};
32 use check::{self, TestKind};
36 use flags::Subcommand;
39 use {Compiler, Build, Mode};
41 pub fn run(build: &Build) {
42 let rules = build_rules(build);
43 let steps = rules.plan();
47 pub fn build_rules<'a>(build: &'a Build) -> Rules {
48 let mut rules = Rules::new(build);
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
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.
60 // Next up we'll see two arguments to this method:
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.
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).
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.
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.
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
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")
106 if s.target == build.config.build {
109 s.target(&build.config.build)
112 .run(move |s| native::llvm(build, s.target));
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.
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))
126 .host(&build.config.build)
130 .run(move |s| compile::assemble_rustc(build, s.stage, s.target));
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" {
153 // ========================================================================
154 // Crate compilations
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()));
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.
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"))
176 rules.build("librustc", "src/librustc")
177 .dep(|s| s.name("libtest"))
178 .dep(|s| s.name("librustc-link"))
182 // Helper method to define the rules to link a crate into its place in the
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:
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.
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.
200 // * Finally, there are some cases, however, which do indeed comiple crates
201 // and link them into place afterwards.
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>,
212 link: fn(&Build, &Compiler, &Compiler, &str))
213 -> RuleBuilder<'a, 'b> {
214 let mut rule = rules.build(&krate, "path/to/nowhere");
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 {
221 s.host(&build.config.build)
225 if build.force_use_stage1(&s.compiler(), s.target) {
227 &s.stage(1).host(&build.config.build).compiler(),
230 } else if s.host == build.config.build {
231 link(build, &s.compiler(), &s.compiler(), s.target)
234 &s.host(&build.config.build).compiler(),
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.
247 // All of these rules use the helper definition above.
253 .dep(|s| s.name("startup-objects"))
254 .dep(|s| s.name("create-sysroot").target(s.host));
260 .dep(|s| s.name("libstd-link"));
264 "build-crate-rustc-main",
266 .dep(|s| s.name("libtest-link"));
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()));
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()));
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()));
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
290 rules.build("may-run-build-script", "path/to/nowhere")
292 s.name("libstd-link")
293 .host(&build.config.build)
294 .target(&build.config.build)
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));
300 // ========================================================================
303 // Various unit tests and tests suites we can run
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
313 check::compiletest(build, &s.compiler(), s.target, mode, dir)
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");
328 suite("check-codegen-units", "src/test/codegen-units", "codegen-units",
330 suite("check-incremental", "src/test/incremental", "incremental",
334 if build.config.build.contains("msvc") {
335 // nothing to do for debuginfo tests
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");
354 if build.config.build.contains("apple") {
355 rule.dep(|s| s.name("check-debuginfo-lldb"));
357 rule.dep(|s| s.name("check-debuginfo-gdb"));
361 rules.test("debugger-scripts", "src/etc/lldb_batchmode.py")
362 .run(move |s| dist::debugger_scripts(build, &build.sysroot(&s.compiler()),
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")
374 check::compiletest(build, &s.compiler(), s.target, mode, dir)
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",
390 suite("check-pretty-rfail", "src/test/run-fail/pretty", "pretty",
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");
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,
408 rules.test("check-std-all", "path/to/nowhere")
409 .dep(|s| s.name("libtest"))
410 .dep(|s| s.name("remote-copy-libs"))
412 .run(move |s| check::krate(build, &s.compiler(), s.target,
413 Mode::Libstd, TestKind::Test, None));
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,
424 rules.bench("bench-std-all", "path/to/nowhere")
425 .dep(|s| s.name("libtest"))
426 .dep(|s| s.name("remote-copy-libs"))
428 .run(move |s| check::krate(build, &s.compiler(), s.target,
429 Mode::Libstd, TestKind::Bench, None));
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,
439 rules.test("check-test-all", "path/to/nowhere")
440 .dep(|s| s.name("libtest"))
441 .dep(|s| s.name("remote-copy-libs"))
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"))
450 .run(move |s| check::krate(build, &s.compiler(), s.target,
451 Mode::Librustc, TestKind::Test,
454 rules.test("check-rustc-all", "path/to/nowhere")
455 .dep(|s| s.name("librustc"))
456 .dep(|s| s.name("remote-copy-libs"))
459 .run(move |s| check::krate(build, &s.compiler(), s.target,
460 Mode::Librustc, TestKind::Test, None));
462 rules.test("check-linkchecker", "src/tools/linkchecker")
463 .dep(|s| s.name("tool-linkchecker").stage(0))
464 .dep(|s| s.name("default:doc"))
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"))
472 .run(move |s| check::cargotest(build, s.stage, s.target));
473 rules.test("check-cargo", "cargo")
474 .dep(|s| s.name("tool-cargo"))
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))
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))
488 .run(move |s| check::error_index(build, &s.compiler()));
489 rules.test("check-docs", "src/doc")
490 .dep(|s| s.name("libtest"))
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));
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));
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.
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"))
516 if build.remote_tested(s.target) {
517 s.name("tool-remote-test-client").target(s.host).stage(0)
523 if build.remote_tested(s.target) {
524 s.name("tool-remote-test-server")
529 .run(move |s| check::remote_copy_libs(build, &s.compiler(), s.target));
531 rules.test("check-bootstrap", "src/bootstrap")
535 .run(move |_| check::bootstrap(build));
537 // ========================================================================
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")
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"))
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)
594 .run(move |s| compile::tool(build, s.stage, s.target, "cargo"));
595 rules.build("tool-rls", "src/tools/rls")
597 .default(build.config.extended)
598 .dep(|s| s.name("librustc-tool"))
599 .dep(|s| s.stage(0).host(s.target).name("openssl"))
601 // rls, like cargo, uses procedural macros
602 s.name("librustc-link")
603 .target(&build.config.build)
604 .host(&build.config.build)
606 .run(move |s| compile::tool(build, s.stage, s.target, "rls"));
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");
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));
627 // ========================================================================
628 // Documentation targets
629 rules.doc("doc-book", "src/doc/book")
631 s.name("tool-rustbook")
632 .host(&build.config.build)
633 .target(&build.config.build)
636 .default(build.config.docs)
637 .run(move |s| doc::book(build, s.target, "book"));
638 rules.doc("doc-nomicon", "src/doc/nomicon")
640 s.name("tool-rustbook")
641 .host(&build.config.build)
642 .target(&build.config.build)
645 .default(build.config.docs)
646 .run(move |s| doc::rustbook(build, s.target, "nomicon"));
647 rules.doc("doc-reference", "src/doc/reference")
649 s.name("tool-rustbook")
650 .host(&build.config.build)
651 .target(&build.config.build)
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")
658 s.name("tool-rustbook")
659 .host(&build.config.build)
660 .target(&build.config.build)
663 .default(build.config.docs)
664 .run(move |s| doc::rustbook(build, s.target, "unstable-book"));
665 rules.doc("doc-standalone", "src/doc")
668 .host(&build.config.build)
669 .target(&build.config.build)
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)
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));
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));
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"))
700 .default(default && build.config.docs)
701 .run(move |s| doc::rustc(build, s.stage, s.target));
704 // ========================================================================
705 // Distribution targets
706 rules.dist("dist-rustc", "src/librustc")
707 .dep(move |s| s.name("rustc").host(&build.config.build))
709 .only_host_build(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")
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")
721 s.name("libtest-link")
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")
730 .only_host_build(true)
731 .dep(move |s| tool_rust_installer(build, s))
733 if s.target.contains("pc-windows-gnu") {
734 dist::mingw(build, s.target)
737 rules.dist("dist-src", "src")
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")
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")
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::Installer::new(build).install(s.stage, s.target));
765 rules.dist("dist-cargo", "cargo")
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)
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));
785 rules.dist("dist-sign", "hash-and-sign")
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));
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)
804 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
806 /// Human readable name of the rule this step is executing. Possible names
807 /// are all defined above in `build_rules`.
810 /// The stage this step is executing in. This is typically 0, 1, or 2.
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.
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.
825 fn noop() -> Step<'a> {
826 Step { name: "", stage: 0, host: "", target: "" }
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 }
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 }
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 }
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 }
849 /// Returns the `Compiler` structure that this step corresponds to.
850 fn compiler(&self) -> Compiler<'a> {
851 Compiler::new(self.stage, self.host)
856 /// The human readable name of this target, defined in `build_rules`.
859 /// The path associated with this target, used in the `./x.py` driver for
860 /// easy and ergonomic specification of what to do.
863 /// The "kind" of top-level command that this rule is associated with, only
864 /// relevant if this is a default rule.
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>>,
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>,
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.
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
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,
888 /// Whether this rule is only for the build triple, not anything in hosts or
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.
908 fn new(name: &'a str, path: &'a str, kind: Kind) -> Rule<'a> {
912 run: Box::new(|_| ()),
917 only_host_build: false,
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>,
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,
935 self.rule.deps.push(Box::new(f));
939 fn after(&mut self, step: &'a str) -> &mut Self {
940 self.rule.after.push(step);
944 fn run<F>(&mut self, f: F) -> &mut Self
945 where F: Fn(&Step<'a>) + 'a,
947 self.rule.run = Box::new(f);
951 fn default(&mut self, default: bool) -> &mut Self {
952 self.rule.default = default;
956 fn host(&mut self, host: bool) -> &mut Self {
957 self.rule.host = host;
961 fn only_build(&mut self, only_build: bool) -> &mut Self {
962 self.rule.only_build = only_build;
966 fn only_host_build(&mut self, only_host_build: bool) -> &mut Self {
967 self.rule.only_host_build = only_host_build;
972 impl<'a, 'b> Drop for RuleBuilder<'a, 'b> {
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);
982 pub struct Rules<'a> {
985 rules: BTreeMap<&'a str, Rule<'a>>,
989 fn new(build: &'a Build) -> Rules<'a> {
993 stage: build.flags.stage.unwrap_or(2),
994 target: &build.config.build,
995 host: &build.config.build,
998 rules: BTreeMap::new(),
1002 /// Creates a new rule of `Kind::Build` with the specified human readable
1003 /// name and path associated with it.
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)
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)
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)
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)
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)
1036 fn rule<'b>(&'b mut self,
1039 kind: Kind) -> RuleBuilder<'a, 'b> {
1042 rule: Rule::new(name, path, kind),
1046 /// Verify the dependency graph defined by all our rules are correct, e.g.
1047 /// everything points to a valid something else.
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:") {
1055 if dep == Step::noop() {
1060 invalid rule dependency graph detected, was a rule added and maybe typo'd?
1062 `{}` depends on `{}` which does not exist
1064 ", rule.name, dep.name);
1069 pub fn get_help(&self, command: &str) -> Option<String> {
1070 let kind = match command {
1071 "build" => Kind::Build,
1073 "test" => Kind::Test,
1074 "bench" => Kind::Bench,
1075 "dist" => Kind::Dist,
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);
1083 let mut help_string = String::from("Available paths:\n");
1085 help_string.push_str(format!(" ./x.py {} {}\n", command, rule.path).as_str());
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:
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.
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.
1106 // 3. Finally, we generate some steps with host and target information.
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.
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 } => {
1127 return vec![self.sbuild.name("install")]
1129 (Kind::Dist, &paths[..])
1132 Subcommand::Clean => panic!(),
1135 let mut rules: Vec<_> = self.rules.values().filter_map(|rule| {
1136 if rule.kind != kind {
1140 if paths.len() == 0 && rule.default {
1143 paths.iter().position(|path| path.ends_with(rule.path))
1144 .map(|priority| (rule, priority))
1148 rules.sort_by_key(|&(_, priority)| priority);
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
1156 &self.build.config.host
1158 let targets = if self.build.flags.target.len() > 0 {
1159 &self.build.flags.target
1161 &self.build.config.target
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 {
1176 } else if rule.only_build {
1177 &self.build.config.host[..1]
1179 &self.build.config.host[..]
1185 hosts.iter().flat_map(move |host| {
1186 arr.iter().map(move |target| {
1187 self.sbuild.name(rule.name).target(target).host(host)
1193 /// Execute all top-level targets indicated by `steps`.
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));
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);
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));
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));
1219 self.build.verbose(&format!("executing step {:?}", step));
1220 (self.rules[step.name].run)(step);
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());
1236 self.build_graph(step.clone(), &mut nodes, &mut edges);
1239 // Now that we've built up the actual dependency graph, draw more
1240 // dependency edges to satisfy the `after` dependencies field for each
1242 self.satisfy_after_deps(&nodes, &mut edges);
1244 // And finally, perform a topological sort to return a list of steps to
1246 let mut order = Vec::new();
1247 let mut visited = HashSet::new();
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);
1256 /// Builds the dependency graph rooted at `step`.
1258 /// The `nodes` and `edges` maps are filled out according to the rule
1259 /// described by `step.name`.
1260 fn build_graph(&self,
1262 nodes: &mut HashMap<Step<'a>, usize>,
1263 edges: &mut HashMap<usize, HashSet<usize>>) -> usize {
1264 use std::collections::hash_map::Entry;
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(),
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..] {
1278 "dist" => Kind::Dist,
1279 kind => panic!("unknown kind: `{}`", kind),
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));
1287 deps.push(self.build_graph(dep, nodes, edges));
1291 edges.entry(idx).or_insert(HashSet::new()).extend(deps);
1295 /// Given a dependency graph with a finished list of `nodes`, fill out more
1296 /// dependency `edges`.
1298 /// This is the step which satisfies all `after` listed dependencies in
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
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);
1310 for (step, idx) in nodes {
1311 if *step == Step::noop() {
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());
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) {
1335 for dep in edges[&cur].iter() {
1336 self.topo_sort(*dep, nodes, edges, visited, order);
1338 order.push(nodes[&cur].clone());
1351 ($($a:expr),*) => (vec![$($a.to_string()),*])
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);
1362 let mut config = Config::default();
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()));
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(),
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(),
1382 build.crates.insert("test".to_string(), ::Crate {
1383 name: "test".to_string(),
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(),
1392 build.crates.insert("rustc-main".to_string(), ::Crate {
1393 name: "rustc-main".to_string(),
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(),
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" ));
1415 let step = super::Step {
1418 host: &build.config.build,
1419 target: &build.config.build,
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")));
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" ));
1438 let step = super::Step {
1441 host: &build.config.build,
1442 target: &build.config.build,
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")));
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")));
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));
1466 let step = super::Step {
1469 host: &build.config.build,
1470 target: &build.config.build,
1473 assert!(!plan.iter().any(|s| s.host == "B"));
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")));
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")));
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));
1496 let step = super::Step {
1499 host: &build.config.build,
1500 target: &build.config.build,
1503 assert!(!plan.iter().any(|s| s.host == "B"));
1504 assert!(!plan.iter().any(|s| s.host == "C"));
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")));
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")));
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")));
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));
1533 let step = super::Step {
1536 host: &build.config.build,
1537 target: &build.config.build,
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"));
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")));
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));
1560 let step = super::Step {
1563 host: &build.config.build,
1564 target: &build.config.build,
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"));
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")));
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)));
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") {
1588 println!("step: {:?}", step);
1589 assert!(step.host != "B");
1590 assert!(step.target != "B");
1591 assert!(step.host != "C");
1592 assert!(step.target != "C");
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));
1604 let step = super::Step {
1607 host: &build.config.build,
1608 target: &build.config.build,
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")));
1617 // rustc never built for C
1618 assert!(!plan.iter().any(|s| {
1619 s.name.contains("rustc") && (s.host == "C" || s.target == "C")
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")));
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")));
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));
1644 assert!(!plan.iter().any(|s| s.name.contains("rustc")));
1645 assert!(plan.iter().all(|s| {
1646 !s.name.contains("test") || s.target == "C"
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"));
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")));
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"));
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")));