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};
31 use std::path::PathBuf;
34 use check::{self, TestKind};
38 use flags::Subcommand;
41 use {Compiler, Build, Mode};
43 pub fn run(build: &Build) {
44 let rules = build_rules(build);
45 let steps = rules.plan();
49 pub fn build_rules<'a>(build: &'a Build) -> Rules {
50 let mut rules = Rules::new(build);
52 // This is the first rule that we're going to define for rustbuild, which is
53 // used to compile LLVM itself. All rules are added through the `rules`
54 // structure created above and are configured through a builder-style
57 // First up we see the `build` method. This represents a rule that's part of
58 // the top-level `build` subcommand. For example `./x.py build` is what this
59 // is associating with. Note that this is normally only relevant if you flag
60 // a rule as `default`, which we'll talk about later.
62 // Next up we'll see two arguments to this method:
64 // * `llvm` - this is the "human readable" name of this target. This name is
65 // not accessed anywhere outside this file itself (e.g. not in
66 // the CLI nor elsewhere in rustbuild). The purpose of this is to
67 // easily define dependencies between rules. That is, other rules
68 // will depend on this with the name "llvm".
69 // * `src/llvm` - this is the relevant path to the rule that we're working
70 // with. This path is the engine behind how commands like
71 // `./x.py build src/llvm` work. This should typically point
72 // to the relevant component, but if there's not really a
73 // path to be assigned here you can pass something like
74 // `path/to/nowhere` to ignore it.
76 // After we create the rule with the `build` method we can then configure
77 // various aspects of it. For example this LLVM rule uses `.host(true)` to
78 // flag that it's a rule only for host targets. In other words, LLVM isn't
79 // compiled for targets configured through `--target` (e.g. those we're just
80 // building a standard library for).
82 // Next up the `dep` method will add a dependency to this rule. The closure
83 // is yielded the step that represents executing the `llvm` rule itself
84 // (containing information like stage, host, target, ...) and then it must
85 // return a target that the step depends on. Here LLVM is actually
86 // interesting where a cross-compiled LLVM depends on the host LLVM, but
87 // otherwise it has no dependencies.
89 // To handle this we do a bit of dynamic dispatch to see what the dependency
90 // is. If we're building a LLVM for the build triple, then we don't actually
91 // have any dependencies! To do that we return a dependency on the `Step::noop()`
92 // target which does nothing.
94 // If we're build a cross-compiled LLVM, however, we need to assemble the
95 // libraries from the previous compiler. This step has the same name as
96 // ours (llvm) but we want it for a different target, so we use the
97 // builder-style methods on `Step` to configure this target to the build
100 // Finally, to finish off this rule, we define how to actually execute it.
101 // That logic is all defined in the `native` module so we just delegate to
102 // the relevant function there. The argument to the closure passed to `run`
103 // is a `Step` (defined below) which encapsulates information like the
104 // stage, target, host, etc.
105 rules.build("llvm", "src/llvm")
108 if s.target == build.build {
111 s.target(&build.build)
114 .run(move |s| native::llvm(build, s.target));
116 // Ok! After that example rule that's hopefully enough to explain what's
117 // going on here. You can check out the API docs below and also see a bunch
118 // more examples of rules directly below as well.
120 // the compiler with no target libraries ready to go
121 rules.build("rustc", "src/rustc")
122 .dep(|s| s.name("create-sysroot").target(s.host))
132 .run(move |s| compile::assemble_rustc(build, s.stage, s.target));
134 // Helper for loading an entire DAG of crates, rooted at `name`
135 let krates = |name: &str| {
136 let mut ret = Vec::new();
137 let mut list = vec![name];
138 let mut visited = HashSet::new();
139 while let Some(krate) = list.pop() {
140 let default = krate == name;
141 let krate = &build.crates[krate];
142 let path = krate.path.strip_prefix(&build.src)
143 // This handles out of tree paths
144 .unwrap_or(&krate.path);
145 ret.push((krate, path.to_str().unwrap(), default));
146 for dep in krate.deps.iter() {
147 if visited.insert(dep) && dep != "build_helper" {
155 // ========================================================================
156 // Crate compilations
158 // Tools used during the build system but not shipped
159 rules.build("create-sysroot", "path/to/nowhere")
160 .run(move |s| compile::create_sysroot(build, &s.compiler()));
162 // These rules are "pseudo rules" that don't actually do any work
163 // themselves, but represent a complete sysroot with the relevant compiler
164 // linked into place.
166 // That is, depending on "libstd" means that when the rule is completed then
167 // the `stage` sysroot for the compiler `host` will be available with a
168 // standard library built for `target` linked in place. Not all rules need
169 // the compiler itself to be available, just the standard library, so
170 // there's a distinction between the two.
171 rules.build("libstd", "src/libstd")
172 .dep(|s| s.name("rustc").target(s.host))
173 .dep(|s| s.name("libstd-link"));
174 rules.build("libtest", "src/libtest")
175 .dep(|s| s.name("libstd"))
176 .dep(|s| s.name("libtest-link"))
178 rules.build("librustc", "src/librustc")
179 .dep(|s| s.name("libtest"))
180 .dep(|s| s.name("librustc-link"))
184 // Helper method to define the rules to link a crate into its place in the
187 // The logic here is a little subtle as there's a few cases to consider.
188 // Not all combinations of (stage, host, target) actually require something
189 // to be compiled, but rather libraries could get propagated from a
190 // different location. For example:
192 // * Any crate with a `host` that's not the build triple will not actually
193 // compile something. A different `host` means that the build triple will
194 // actually compile the libraries, and then we'll copy them over from the
195 // build triple to the `host` directory.
197 // * Some crates aren't even compiled by the build triple, but may be copied
198 // from previous stages. For example if we're not doing a full bootstrap
199 // then we may just depend on the stage1 versions of libraries to be
200 // available to get linked forward.
202 // * Finally, there are some cases, however, which do indeed comiple crates
203 // and link them into place afterwards.
205 // The rule definition below mirrors these three cases. The `dep` method
206 // calculates the correct dependency which either comes from stage1, a
207 // different compiler, or from actually building the crate itself (the `dep`
208 // rule). The `run` rule then mirrors these three cases and links the cases
209 // forward into the compiler sysroot specified from the correct location.
210 fn crate_rule<'a, 'b>(build: &'a Build,
211 rules: &'b mut Rules<'a>,
214 link: fn(&Build, &Compiler, &Compiler, &str))
215 -> RuleBuilder<'a, 'b> {
216 let mut rule = rules.build(&krate, "path/to/nowhere");
218 if build.force_use_stage1(&s.compiler(), s.target) {
219 s.host(&build.build).stage(1)
220 } else if s.host == build.build {
227 if build.force_use_stage1(&s.compiler(), s.target) {
229 &s.stage(1).host(&build.build).compiler(),
232 } else if s.host == build.build {
233 link(build, &s.compiler(), &s.compiler(), s.target)
236 &s.host(&build.build).compiler(),
244 // Similar to the `libstd`, `libtest`, and `librustc` rules above, except
245 // these rules only represent the libraries being available in the sysroot,
246 // not the compiler itself. This is done as not all rules need a compiler in
247 // the sysroot, but may just need the libraries.
249 // All of these rules use the helper definition above.
255 .dep(|s| s.name("startup-objects"))
256 .dep(|s| s.name("create-sysroot").target(s.host));
262 .dep(|s| s.name("libstd-link"));
266 "build-crate-rustc-main",
268 .dep(|s| s.name("libtest-link"));
270 for (krate, path, _default) in krates("std") {
271 rules.build(&krate.build_step, path)
272 .dep(|s| s.name("startup-objects"))
273 .dep(move |s| s.name("rustc").host(&build.build).target(s.host))
274 .run(move |s| compile::std(build, s.target, &s.compiler()));
276 for (krate, path, _default) in krates("test") {
277 rules.build(&krate.build_step, path)
278 .dep(|s| s.name("libstd-link"))
279 .run(move |s| compile::test(build, s.target, &s.compiler()));
281 for (krate, path, _default) in krates("rustc-main") {
282 rules.build(&krate.build_step, path)
283 .dep(|s| s.name("libtest-link"))
284 .dep(move |s| s.name("llvm").host(&build.build).stage(0))
285 .dep(|s| s.name("may-run-build-script"))
286 .run(move |s| compile::rustc(build, s.target, &s.compiler()));
289 // Crates which have build scripts need to rely on this rule to ensure that
290 // the necessary prerequisites for a build script are linked and located in
292 rules.build("may-run-build-script", "path/to/nowhere")
294 s.name("libstd-link")
296 .target(&build.build)
298 rules.build("startup-objects", "src/rtstartup")
299 .dep(|s| s.name("create-sysroot").target(s.host))
300 .run(move |s| compile::build_startup_objects(build, &s.compiler(), s.target));
302 // ========================================================================
305 // Various unit tests and tests suites we can run
307 let mut suite = |name, path, mode, dir| {
308 rules.test(name, path)
309 .dep(|s| s.name("libtest"))
310 .dep(|s| s.name("tool-compiletest").target(s.host).stage(0))
311 .dep(|s| s.name("test-helpers"))
312 .dep(|s| s.name("remote-copy-libs"))
313 .default(mode != "pretty") // pretty tests don't run everywhere
315 check::compiletest(build, &s.compiler(), s.target, mode, dir)
319 suite("check-ui", "src/test/ui", "ui", "ui");
320 suite("check-rpass", "src/test/run-pass", "run-pass", "run-pass");
321 suite("check-cfail", "src/test/compile-fail", "compile-fail", "compile-fail");
322 suite("check-pfail", "src/test/parse-fail", "parse-fail", "parse-fail");
323 suite("check-rfail", "src/test/run-fail", "run-fail", "run-fail");
324 suite("check-rpass-valgrind", "src/test/run-pass-valgrind",
325 "run-pass-valgrind", "run-pass-valgrind");
326 suite("check-mir-opt", "src/test/mir-opt", "mir-opt", "mir-opt");
327 if build.config.codegen_tests {
328 suite("check-codegen", "src/test/codegen", "codegen", "codegen");
330 suite("check-codegen-units", "src/test/codegen-units", "codegen-units",
332 suite("check-incremental", "src/test/incremental", "incremental",
336 if build.build.contains("msvc") {
337 // nothing to do for debuginfo tests
339 rules.test("check-debuginfo-lldb", "src/test/debuginfo-lldb")
340 .dep(|s| s.name("libtest"))
341 .dep(|s| s.name("tool-compiletest").target(s.host).stage(0))
342 .dep(|s| s.name("test-helpers"))
343 .dep(|s| s.name("debugger-scripts"))
344 .run(move |s| check::compiletest(build, &s.compiler(), s.target,
345 "debuginfo-lldb", "debuginfo"));
346 rules.test("check-debuginfo-gdb", "src/test/debuginfo-gdb")
347 .dep(|s| s.name("libtest"))
348 .dep(|s| s.name("tool-compiletest").target(s.host).stage(0))
349 .dep(|s| s.name("test-helpers"))
350 .dep(|s| s.name("debugger-scripts"))
351 .dep(|s| s.name("remote-copy-libs"))
352 .run(move |s| check::compiletest(build, &s.compiler(), s.target,
353 "debuginfo-gdb", "debuginfo"));
354 let mut rule = rules.test("check-debuginfo", "src/test/debuginfo");
356 if build.build.contains("apple") {
357 rule.dep(|s| s.name("check-debuginfo-lldb"));
359 rule.dep(|s| s.name("check-debuginfo-gdb"));
363 rules.test("debugger-scripts", "src/etc/lldb_batchmode.py")
364 .run(move |s| dist::debugger_scripts(build, &build.sysroot(&s.compiler()),
368 let mut suite = |name, path, mode, dir| {
369 rules.test(name, path)
370 .dep(|s| s.name("librustc"))
371 .dep(|s| s.name("test-helpers"))
372 .dep(|s| s.name("tool-compiletest").target(s.host).stage(0))
373 .default(mode != "pretty")
376 check::compiletest(build, &s.compiler(), s.target, mode, dir)
380 suite("check-ui-full", "src/test/ui-fulldeps", "ui", "ui-fulldeps");
381 suite("check-rpass-full", "src/test/run-pass-fulldeps",
382 "run-pass", "run-pass-fulldeps");
383 suite("check-rfail-full", "src/test/run-fail-fulldeps",
384 "run-fail", "run-fail-fulldeps");
385 suite("check-cfail-full", "src/test/compile-fail-fulldeps",
386 "compile-fail", "compile-fail-fulldeps");
387 suite("check-rmake", "src/test/run-make", "run-make", "run-make");
388 suite("check-rustdoc", "src/test/rustdoc", "rustdoc", "rustdoc");
389 suite("check-pretty", "src/test/pretty", "pretty", "pretty");
390 suite("check-pretty-rpass", "src/test/run-pass/pretty", "pretty",
392 suite("check-pretty-rfail", "src/test/run-fail/pretty", "pretty",
394 suite("check-pretty-valgrind", "src/test/run-pass-valgrind/pretty", "pretty",
395 "run-pass-valgrind");
396 suite("check-pretty-rpass-full", "src/test/run-pass-fulldeps/pretty",
397 "pretty", "run-pass-fulldeps");
398 suite("check-pretty-rfail-full", "src/test/run-fail-fulldeps/pretty",
399 "pretty", "run-fail-fulldeps");
402 for (krate, path, _default) in krates("std") {
403 rules.test(&krate.test_step, path)
404 .dep(|s| s.name("libtest"))
405 .dep(|s| s.name("remote-copy-libs"))
406 .run(move |s| check::krate(build, &s.compiler(), s.target,
407 Mode::Libstd, TestKind::Test,
410 rules.test("check-std-all", "path/to/nowhere")
411 .dep(|s| s.name("libtest"))
412 .dep(|s| s.name("remote-copy-libs"))
414 .run(move |s| check::krate(build, &s.compiler(), s.target,
415 Mode::Libstd, TestKind::Test, None));
418 for (krate, path, _default) in krates("std") {
419 rules.bench(&krate.bench_step, path)
420 .dep(|s| s.name("libtest"))
421 .dep(|s| s.name("remote-copy-libs"))
422 .run(move |s| check::krate(build, &s.compiler(), s.target,
423 Mode::Libstd, TestKind::Bench,
426 rules.bench("bench-std-all", "path/to/nowhere")
427 .dep(|s| s.name("libtest"))
428 .dep(|s| s.name("remote-copy-libs"))
430 .run(move |s| check::krate(build, &s.compiler(), s.target,
431 Mode::Libstd, TestKind::Bench, None));
433 for (krate, path, _default) in krates("test") {
434 rules.test(&krate.test_step, path)
435 .dep(|s| s.name("libtest"))
436 .dep(|s| s.name("remote-copy-libs"))
437 .run(move |s| check::krate(build, &s.compiler(), s.target,
438 Mode::Libtest, TestKind::Test,
441 rules.test("check-test-all", "path/to/nowhere")
442 .dep(|s| s.name("libtest"))
443 .dep(|s| s.name("remote-copy-libs"))
445 .run(move |s| check::krate(build, &s.compiler(), s.target,
446 Mode::Libtest, TestKind::Test, None));
447 for (krate, path, _default) in krates("rustc-main") {
448 rules.test(&krate.test_step, path)
449 .dep(|s| s.name("librustc"))
450 .dep(|s| s.name("remote-copy-libs"))
452 .run(move |s| check::krate(build, &s.compiler(), s.target,
453 Mode::Librustc, TestKind::Test,
456 rules.test("check-rustc-all", "path/to/nowhere")
457 .dep(|s| s.name("librustc"))
458 .dep(|s| s.name("remote-copy-libs"))
461 .run(move |s| check::krate(build, &s.compiler(), s.target,
462 Mode::Librustc, TestKind::Test, None));
464 rules.test("check-linkchecker", "src/tools/linkchecker")
465 .dep(|s| s.name("tool-linkchecker").stage(0))
466 .dep(|s| s.name("default:doc"))
467 .default(build.config.docs)
469 .run(move |s| check::linkcheck(build, s.target));
470 rules.test("check-cargotest", "src/tools/cargotest")
471 .dep(|s| s.name("tool-cargotest").stage(0))
472 .dep(|s| s.name("librustc"))
474 .run(move |s| check::cargotest(build, s.stage, s.target));
475 rules.test("check-cargo", "cargo")
476 .dep(|s| s.name("tool-cargo"))
478 .run(move |s| check::cargo(build, s.stage, s.target));
479 rules.test("check-tidy", "src/tools/tidy")
480 .dep(|s| s.name("tool-tidy").stage(0))
484 .run(move |s| check::tidy(build, s.target));
485 rules.test("check-error-index", "src/tools/error_index_generator")
486 .dep(|s| s.name("libstd"))
487 .dep(|s| s.name("tool-error-index").host(s.host).stage(0))
490 .run(move |s| check::error_index(build, &s.compiler()));
491 rules.test("check-docs", "src/doc")
492 .dep(|s| s.name("libtest"))
495 .run(move |s| check::docs(build, &s.compiler()));
496 rules.test("check-distcheck", "distcheck")
497 .dep(|s| s.name("dist-plain-source-tarball"))
498 .dep(|s| s.name("dist-src"))
499 .run(move |_| check::distcheck(build));
501 rules.build("test-helpers", "src/rt/rust_test_helpers.c")
502 .run(move |s| native::test_helpers(build, s.target));
503 rules.build("openssl", "path/to/nowhere")
504 .run(move |s| native::openssl(build, s.target));
506 // Some test suites are run inside emulators or on remote devices, and most
507 // of our test binaries are linked dynamically which means we need to ship
508 // the standard library and such to the emulator ahead of time. This step
509 // represents this and is a dependency of all test suites.
511 // Most of the time this step is a noop (the `check::emulator_copy_libs`
512 // only does work if necessary). For some steps such as shipping data to
513 // QEMU we have to build our own tools so we've got conditional dependencies
514 // on those programs as well. Note that the remote test client is built for
515 // the build target (us) and the server is built for the target.
516 rules.test("remote-copy-libs", "path/to/nowhere")
517 .dep(|s| s.name("libtest"))
519 if build.remote_tested(s.target) {
520 s.name("tool-remote-test-client").target(s.host).stage(0)
526 if build.remote_tested(s.target) {
527 s.name("tool-remote-test-server")
532 .run(move |s| check::remote_copy_libs(build, &s.compiler(), s.target));
534 rules.test("check-bootstrap", "src/bootstrap")
538 .run(move |_| check::bootstrap(build));
540 // ========================================================================
543 // Tools used during the build system but not shipped
544 rules.build("tool-rustbook", "src/tools/rustbook")
545 .dep(|s| s.name("maybe-clean-tools"))
546 .dep(|s| s.name("librustc-tool"))
547 .run(move |s| compile::tool(build, s.stage, s.target, "rustbook"));
548 rules.build("tool-error-index", "src/tools/error_index_generator")
549 .dep(|s| s.name("maybe-clean-tools"))
550 .dep(|s| s.name("librustc-tool"))
551 .run(move |s| compile::tool(build, s.stage, s.target, "error_index_generator"));
552 rules.build("tool-unstable-book-gen", "src/tools/unstable-book-gen")
553 .dep(|s| s.name("maybe-clean-tools"))
554 .dep(|s| s.name("libstd-tool"))
555 .run(move |s| compile::tool(build, s.stage, s.target, "unstable-book-gen"));
556 rules.build("tool-tidy", "src/tools/tidy")
557 .dep(|s| s.name("maybe-clean-tools"))
558 .dep(|s| s.name("libstd-tool"))
559 .run(move |s| compile::tool(build, s.stage, s.target, "tidy"));
560 rules.build("tool-linkchecker", "src/tools/linkchecker")
561 .dep(|s| s.name("maybe-clean-tools"))
562 .dep(|s| s.name("libstd-tool"))
563 .run(move |s| compile::tool(build, s.stage, s.target, "linkchecker"));
564 rules.build("tool-cargotest", "src/tools/cargotest")
565 .dep(|s| s.name("maybe-clean-tools"))
566 .dep(|s| s.name("libstd-tool"))
567 .run(move |s| compile::tool(build, s.stage, s.target, "cargotest"));
568 rules.build("tool-compiletest", "src/tools/compiletest")
569 .dep(|s| s.name("maybe-clean-tools"))
570 .dep(|s| s.name("libtest-tool"))
571 .run(move |s| compile::tool(build, s.stage, s.target, "compiletest"));
572 rules.build("tool-build-manifest", "src/tools/build-manifest")
573 .dep(|s| s.name("maybe-clean-tools"))
574 .dep(|s| s.name("libstd-tool"))
575 .run(move |s| compile::tool(build, s.stage, s.target, "build-manifest"));
576 rules.build("tool-remote-test-server", "src/tools/remote-test-server")
577 .dep(|s| s.name("maybe-clean-tools"))
578 .dep(|s| s.name("libstd-tool"))
579 .run(move |s| compile::tool(build, s.stage, s.target, "remote-test-server"));
580 rules.build("tool-remote-test-client", "src/tools/remote-test-client")
581 .dep(|s| s.name("maybe-clean-tools"))
582 .dep(|s| s.name("libstd-tool"))
583 .run(move |s| compile::tool(build, s.stage, s.target, "remote-test-client"));
584 rules.build("tool-rust-installer", "src/tools/rust-installer")
585 .dep(|s| s.name("maybe-clean-tools"))
586 .dep(|s| s.name("libstd-tool"))
587 .run(move |s| compile::tool(build, s.stage, s.target, "rust-installer"));
588 rules.build("tool-cargo", "src/tools/cargo")
590 .default(build.config.extended)
591 .dep(|s| s.name("maybe-clean-tools"))
592 .dep(|s| s.name("libstd-tool"))
593 .dep(|s| s.stage(0).host(s.target).name("openssl"))
595 // Cargo depends on procedural macros, which requires a full host
596 // compiler to be available, so we need to depend on that.
597 s.name("librustc-link")
598 .target(&build.build)
601 .run(move |s| compile::tool(build, s.stage, s.target, "cargo"));
602 rules.build("tool-rls", "src/tools/rls")
604 .default(build.config.extended)
605 .dep(|s| s.name("librustc-tool"))
606 .dep(|s| s.stage(0).host(s.target).name("openssl"))
608 // rls, like cargo, uses procedural macros
609 s.name("librustc-link")
610 .target(&build.build)
613 .run(move |s| compile::tool(build, s.stage, s.target, "rls"));
615 // "pseudo rule" which represents completely cleaning out the tools dir in
616 // one stage. This needs to happen whenever a dependency changes (e.g.
617 // libstd, libtest, librustc) and all of the tool compilations above will
618 // be sequenced after this rule.
619 rules.build("maybe-clean-tools", "path/to/nowhere")
620 .after("librustc-tool")
621 .after("libtest-tool")
622 .after("libstd-tool");
624 rules.build("librustc-tool", "path/to/nowhere")
625 .dep(|s| s.name("librustc"))
626 .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Librustc));
627 rules.build("libtest-tool", "path/to/nowhere")
628 .dep(|s| s.name("libtest"))
629 .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Libtest));
630 rules.build("libstd-tool", "path/to/nowhere")
631 .dep(|s| s.name("libstd"))
632 .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Libstd));
634 // ========================================================================
635 // Documentation targets
636 rules.doc("doc-book", "src/doc/book")
638 s.name("tool-rustbook")
640 .target(&build.build)
643 .default(build.config.docs)
644 .run(move |s| doc::book(build, s.target, "book"));
645 rules.doc("doc-nomicon", "src/doc/nomicon")
647 s.name("tool-rustbook")
649 .target(&build.build)
652 .default(build.config.docs)
653 .run(move |s| doc::rustbook(build, s.target, "nomicon"));
654 rules.doc("doc-reference", "src/doc/reference")
656 s.name("tool-rustbook")
658 .target(&build.build)
661 .default(build.config.docs)
662 .run(move |s| doc::rustbook(build, s.target, "reference"));
663 rules.doc("doc-unstable-book", "src/doc/unstable-book")
665 s.name("tool-rustbook")
667 .target(&build.build)
670 .dep(move |s| s.name("doc-unstable-book-gen"))
671 .default(build.config.docs)
672 .run(move |s| doc::rustbook_src(build,
675 &build.md_doc_out(s.target)));
676 rules.doc("doc-standalone", "src/doc")
680 .target(&build.build)
683 .default(build.config.docs)
684 .run(move |s| doc::standalone(build, s.target));
685 rules.doc("doc-error-index", "src/tools/error_index_generator")
686 .dep(move |s| s.name("tool-error-index").target(&build.build).stage(0))
687 .dep(move |s| s.name("librustc-link"))
688 .default(build.config.docs)
690 .run(move |s| doc::error_index(build, s.target));
691 rules.doc("doc-unstable-book-gen", "src/tools/unstable-book-gen")
693 s.name("tool-unstable-book-gen")
695 .target(&build.build)
698 .dep(move |s| s.name("libstd-link"))
699 .default(build.config.docs)
701 .run(move |s| doc::unstable_book_gen(build, s.target));
702 for (krate, path, default) in krates("std") {
703 rules.doc(&krate.doc_step, path)
704 .dep(|s| s.name("libstd-link"))
705 .default(default && build.config.docs)
706 .run(move |s| doc::std(build, s.stage, s.target));
708 for (krate, path, default) in krates("test") {
709 rules.doc(&krate.doc_step, path)
710 .dep(|s| s.name("libtest-link"))
711 // Needed so rustdoc generates relative links to std.
712 .dep(|s| s.name("doc-crate-std"))
713 .default(default && build.config.compiler_docs)
714 .run(move |s| doc::test(build, s.stage, s.target));
716 for (krate, path, default) in krates("rustc-main") {
717 rules.doc(&krate.doc_step, path)
718 .dep(|s| s.name("librustc-link"))
719 // Needed so rustdoc generates relative links to std.
720 .dep(|s| s.name("doc-crate-std"))
722 .default(default && build.config.docs)
723 .run(move |s| doc::rustc(build, s.stage, s.target));
726 // ========================================================================
727 // Distribution targets
728 rules.dist("dist-rustc", "src/librustc")
729 .dep(move |s| s.name("rustc").host(&build.build))
731 .only_host_build(true)
733 .dep(move |s| tool_rust_installer(build, s))
734 .run(move |s| dist::rustc(build, s.stage, s.target));
735 rules.dist("dist-std", "src/libstd")
737 // We want to package up as many target libraries as possible
738 // for the `rust-std` package, so if this is a host target we
739 // depend on librustc and otherwise we just depend on libtest.
740 if build.config.host.iter().any(|t| t == s.target) {
741 s.name("librustc-link")
743 s.name("libtest-link")
747 .only_host_build(true)
748 .dep(move |s| tool_rust_installer(build, s))
749 .run(move |s| dist::std(build, &s.compiler(), s.target));
750 rules.dist("dist-mingw", "path/to/nowhere")
752 .only_host_build(true)
753 .dep(move |s| tool_rust_installer(build, s))
755 if s.target.contains("pc-windows-gnu") {
756 dist::mingw(build, s.target)
759 rules.dist("dist-plain-source-tarball", "src")
760 .default(build.config.rust_dist_src)
763 .only_host_build(true)
764 .dep(move |s| tool_rust_installer(build, s))
765 .run(move |_| dist::plain_source_tarball(build));
766 rules.dist("dist-src", "src")
770 .only_host_build(true)
771 .dep(move |s| tool_rust_installer(build, s))
772 .run(move |_| dist::rust_src(build));
773 rules.dist("dist-docs", "src/doc")
775 .only_host_build(true)
776 .dep(|s| s.name("default:doc"))
777 .dep(move |s| tool_rust_installer(build, s))
778 .run(move |s| dist::docs(build, s.stage, s.target));
779 rules.dist("dist-analysis", "analysis")
780 .default(build.config.extended)
781 .dep(|s| s.name("dist-std"))
782 .only_host_build(true)
783 .dep(move |s| tool_rust_installer(build, s))
784 .run(move |s| dist::analysis(build, &s.compiler(), s.target));
785 rules.dist("dist-rls", "rls")
787 .only_host_build(true)
788 .dep(|s| s.name("tool-rls"))
789 .dep(move |s| tool_rust_installer(build, s))
790 .run(move |s| dist::rls(build, s.stage, s.target));
791 rules.dist("dist-cargo", "cargo")
793 .only_host_build(true)
794 .dep(|s| s.name("tool-cargo"))
795 .dep(move |s| tool_rust_installer(build, s))
796 .run(move |s| dist::cargo(build, s.stage, s.target));
797 rules.dist("dist-extended", "extended")
798 .default(build.config.extended)
800 .only_host_build(true)
801 .dep(|d| d.name("dist-std"))
802 .dep(|d| d.name("dist-rustc"))
803 .dep(|d| d.name("dist-mingw"))
804 .dep(|d| d.name("dist-docs"))
805 .dep(|d| d.name("dist-cargo"))
806 .dep(|d| d.name("dist-rls"))
807 .dep(|d| d.name("dist-analysis"))
808 .dep(move |s| tool_rust_installer(build, s))
809 .run(move |s| dist::extended(build, s.stage, s.target));
811 rules.dist("dist-sign", "hash-and-sign")
814 .only_host_build(true)
815 .dep(move |s| s.name("tool-build-manifest").target(&build.build).stage(0))
816 .run(move |_| dist::hash_and_sign(build));
818 rules.install("install-docs", "src/doc")
819 .default(build.config.docs)
820 .only_host_build(true)
821 .dep(|s| s.name("dist-docs"))
822 .run(move |s| install::Installer::new(build).install_docs(s.stage, s.target));
823 rules.install("install-std", "src/libstd")
825 .only_host_build(true)
826 .dep(|s| s.name("dist-std"))
827 .run(move |s| install::Installer::new(build).install_std(s.stage));
828 rules.install("install-cargo", "cargo")
829 .default(build.config.extended)
831 .only_host_build(true)
832 .dep(|s| s.name("dist-cargo"))
833 .run(move |s| install::Installer::new(build).install_cargo(s.stage, s.target));
834 rules.install("install-rls", "rls")
835 .default(build.config.extended)
837 .only_host_build(true)
838 .dep(|s| s.name("dist-rls"))
839 .run(move |s| install::Installer::new(build).install_rls(s.stage, s.target));
840 rules.install("install-analysis", "analysis")
841 .default(build.config.extended)
842 .only_host_build(true)
843 .dep(|s| s.name("dist-analysis"))
844 .run(move |s| install::Installer::new(build).install_analysis(s.stage, s.target));
845 rules.install("install-src", "src")
846 .default(build.config.extended)
849 .only_host_build(true)
850 .dep(|s| s.name("dist-src"))
851 .run(move |s| install::Installer::new(build).install_src(s.stage));
852 rules.install("install-rustc", "src/librustc")
855 .only_host_build(true)
856 .dep(|s| s.name("dist-rustc"))
857 .run(move |s| install::Installer::new(build).install_rustc(s.stage, s.target));
862 /// Helper to depend on a stage0 build-only rust-installer tool.
863 fn tool_rust_installer<'a>(build: &'a Build, step: &Step<'a>) -> Step<'a> {
864 step.name("tool-rust-installer")
866 .target(&build.build)
871 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
873 /// Human readable name of the rule this step is executing. Possible names
874 /// are all defined above in `build_rules`.
877 /// The stage this step is executing in. This is typically 0, 1, or 2.
880 /// This step will likely involve a compiler, and the target that compiler
881 /// itself is built for is called the host, this variable. Typically this is
882 /// the target of the build machine itself.
885 /// The target that this step represents generating. If you're building a
886 /// standard library for a new suite of targets, for example, this'll be set
887 /// to those targets.
892 fn noop() -> Step<'a> {
893 Step { name: "", stage: 0, host: "", target: "" }
896 /// Creates a new step which is the same as this, except has a new name.
897 fn name(&self, name: &'a str) -> Step<'a> {
898 Step { name: name, ..*self }
901 /// Creates a new step which is the same as this, except has a new stage.
902 fn stage(&self, stage: u32) -> Step<'a> {
903 Step { stage: stage, ..*self }
906 /// Creates a new step which is the same as this, except has a new host.
907 fn host(&self, host: &'a str) -> Step<'a> {
908 Step { host: host, ..*self }
911 /// Creates a new step which is the same as this, except has a new target.
912 fn target(&self, target: &'a str) -> Step<'a> {
913 Step { target: target, ..*self }
916 /// Returns the `Compiler` structure that this step corresponds to.
917 fn compiler(&self) -> Compiler<'a> {
918 Compiler::new(self.stage, self.host)
923 /// The human readable name of this target, defined in `build_rules`.
926 /// The path associated with this target, used in the `./x.py` driver for
927 /// easy and ergonomic specification of what to do.
930 /// The "kind" of top-level command that this rule is associated with, only
931 /// relevant if this is a default rule.
934 /// List of dependencies this rule has. Each dependency is a function from a
935 /// step that's being executed to another step that should be executed.
936 deps: Vec<Box<Fn(&Step<'a>) -> Step<'a> + 'a>>,
938 /// How to actually execute this rule. Takes a step with contextual
939 /// information and then executes it.
940 run: Box<Fn(&Step<'a>) + 'a>,
942 /// Whether or not this is a "default" rule. That basically means that if
943 /// you run, for example, `./x.py test` whether it's included or not.
946 /// Whether or not this is a "host" rule, or in other words whether this is
947 /// only intended for compiler hosts and not for targets that are being
951 /// Whether this rule is only for steps where the host is the build triple,
952 /// not anything in hosts or targets.
953 only_host_build: bool,
955 /// Whether this rule is only for the build triple, not anything in hosts or
959 /// A list of "order only" dependencies. This rules does not actually
960 /// depend on these rules, but if they show up in the dependency graph then
961 /// this rule must be executed after all these rules.
976 fn new(name: &'a str, path: &'a str, kind: Kind) -> Rule<'a> {
980 run: Box::new(|_| ()),
985 only_host_build: false,
992 /// Builder pattern returned from the various methods on `Rules` which will add
993 /// the rule to the internal list on `Drop`.
994 struct RuleBuilder<'a: 'b, 'b> {
995 rules: &'b mut Rules<'a>,
999 impl<'a, 'b> RuleBuilder<'a, 'b> {
1000 fn dep<F>(&mut self, f: F) -> &mut Self
1001 where F: Fn(&Step<'a>) -> Step<'a> + 'a,
1003 self.rule.deps.push(Box::new(f));
1007 fn after(&mut self, step: &'a str) -> &mut Self {
1008 self.rule.after.push(step);
1012 fn run<F>(&mut self, f: F) -> &mut Self
1013 where F: Fn(&Step<'a>) + 'a,
1015 self.rule.run = Box::new(f);
1019 fn default(&mut self, default: bool) -> &mut Self {
1020 self.rule.default = default;
1024 fn host(&mut self, host: bool) -> &mut Self {
1025 self.rule.host = host;
1029 fn only_build(&mut self, only_build: bool) -> &mut Self {
1030 self.rule.only_build = only_build;
1034 fn only_host_build(&mut self, only_host_build: bool) -> &mut Self {
1035 self.rule.only_host_build = only_host_build;
1040 impl<'a, 'b> Drop for RuleBuilder<'a, 'b> {
1041 fn drop(&mut self) {
1042 let rule = mem::replace(&mut self.rule, Rule::new("", "", Kind::Build));
1043 let prev = self.rules.rules.insert(rule.name, rule);
1044 if let Some(prev) = prev {
1045 panic!("duplicate rule named: {}", prev.name);
1050 pub struct Rules<'a> {
1053 rules: BTreeMap<&'a str, Rule<'a>>,
1056 impl<'a> Rules<'a> {
1057 fn new(build: &'a Build) -> Rules<'a> {
1061 stage: build.flags.stage.unwrap_or(2),
1062 target: &build.build,
1066 rules: BTreeMap::new(),
1070 /// Creates a new rule of `Kind::Build` with the specified human readable
1071 /// name and path associated with it.
1073 /// The builder returned should be configured further with information such
1074 /// as how to actually run this rule.
1075 fn build<'b>(&'b mut self, name: &'a str, path: &'a str)
1076 -> RuleBuilder<'a, 'b> {
1077 self.rule(name, path, Kind::Build)
1080 /// Same as `build`, but for `Kind::Test`.
1081 fn test<'b>(&'b mut self, name: &'a str, path: &'a str)
1082 -> RuleBuilder<'a, 'b> {
1083 self.rule(name, path, Kind::Test)
1086 /// Same as `build`, but for `Kind::Bench`.
1087 fn bench<'b>(&'b mut self, name: &'a str, path: &'a str)
1088 -> RuleBuilder<'a, 'b> {
1089 self.rule(name, path, Kind::Bench)
1092 /// Same as `build`, but for `Kind::Doc`.
1093 fn doc<'b>(&'b mut self, name: &'a str, path: &'a str)
1094 -> RuleBuilder<'a, 'b> {
1095 self.rule(name, path, Kind::Doc)
1098 /// Same as `build`, but for `Kind::Dist`.
1099 fn dist<'b>(&'b mut self, name: &'a str, path: &'a str)
1100 -> RuleBuilder<'a, 'b> {
1101 self.rule(name, path, Kind::Dist)
1104 /// Same as `build`, but for `Kind::Install`.
1105 fn install<'b>(&'b mut self, name: &'a str, path: &'a str)
1106 -> RuleBuilder<'a, 'b> {
1107 self.rule(name, path, Kind::Install)
1110 fn rule<'b>(&'b mut self,
1113 kind: Kind) -> RuleBuilder<'a, 'b> {
1116 rule: Rule::new(name, path, kind),
1120 /// Verify the dependency graph defined by all our rules are correct, e.g.
1121 /// everything points to a valid something else.
1123 for rule in self.rules.values() {
1124 for dep in rule.deps.iter() {
1125 let dep = dep(&self.sbuild.name(rule.name));
1126 if self.rules.contains_key(&dep.name) || dep.name.starts_with("default:") {
1129 if dep == Step::noop() {
1134 invalid rule dependency graph detected, was a rule added and maybe typo'd?
1136 `{}` depends on `{}` which does not exist
1138 ", rule.name, dep.name);
1143 pub fn get_help(&self, command: &str) -> Option<String> {
1144 let kind = match command {
1145 "build" => Kind::Build,
1147 "test" => Kind::Test,
1148 "bench" => Kind::Bench,
1149 "dist" => Kind::Dist,
1150 "install" => Kind::Install,
1153 let rules = self.rules.values().filter(|r| r.kind == kind);
1154 let rules = rules.filter(|r| !r.path.contains("nowhere"));
1155 let mut rules = rules.collect::<Vec<_>>();
1156 rules.sort_by_key(|r| r.path);
1158 let mut help_string = String::from("Available paths:\n");
1160 help_string.push_str(format!(" ./x.py {} {}\n", command, rule.path).as_str());
1165 /// Construct the top-level build steps that we're going to be executing,
1166 /// given the subcommand that our build is performing.
1167 fn plan(&self) -> Vec<Step<'a>> {
1168 // Ok, the logic here is pretty subtle, and involves quite a few
1169 // conditionals. The basic idea here is to:
1171 // 1. First, filter all our rules to the relevant ones. This means that
1172 // the command specified corresponds to one of our `Kind` variants,
1173 // and we filter all rules based on that.
1175 // 2. Next, we determine which rules we're actually executing. If a
1176 // number of path filters were specified on the command line we look
1177 // for those, otherwise we look for anything tagged `default`.
1178 // Here we also compute the priority of each rule based on how early
1179 // in the command line the matching path filter showed up.
1181 // 3. Finally, we generate some steps with host and target information.
1183 // The last step is by far the most complicated and subtle. The basic
1184 // thinking here is that we want to take the cartesian product of
1185 // specified hosts and targets and build rules with that. The list of
1186 // hosts and targets, if not specified, come from the how this build was
1187 // configured. If the rule we're looking at is a host-only rule the we
1188 // ignore the list of targets and instead consider the list of hosts
1189 // also the list of targets.
1191 // Once the host and target lists are generated we take the cartesian
1192 // product of the two and then create a step based off them. Note that
1193 // the stage each step is associated was specified with the `--step`
1194 // flag on the command line.
1195 let (kind, paths) = match self.build.flags.cmd {
1196 Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
1197 Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
1198 Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]),
1199 Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
1200 Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
1201 Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
1202 Subcommand::Clean => panic!(),
1205 let mut rules: Vec<_> = self.rules.values().filter_map(|rule| {
1206 if rule.kind != kind {
1210 if paths.len() == 0 && rule.default {
1214 .position(|path| path.ends_with(rule.path))
1215 .map(|priority| (rule, priority))
1219 if rules.is_empty() &&
1220 !paths.get(0).unwrap_or(&PathBuf::new())
1221 .ends_with("nonexistent/path/to/trigger/cargo/metadata") {
1222 println!("\nNothing to run...\n");
1226 rules.sort_by_key(|&(_, priority)| priority);
1228 rules.into_iter().flat_map(|(rule, _)| {
1229 let hosts = if rule.only_host_build || rule.only_build {
1230 self.build.build_slice()
1234 // Determine the actual targets participating in this rule.
1235 // NOTE: We should keep the full projection from build triple to
1236 // the hosts for the dist steps, now that the hosts array above is
1237 // truncated to avoid duplication of work in that case. Therefore
1238 // the original non-shadowed hosts array is used below.
1239 let arr = if rule.host {
1240 // If --target was specified but --host wasn't specified,
1241 // don't run any host-only tests.
1242 if self.build.flags.host.len() > 0 {
1244 } else if self.build.flags.target.len() > 0 {
1246 } else if rule.only_build {
1247 self.build.build_slice()
1255 hosts.iter().flat_map(move |host| {
1256 arr.iter().map(move |target| {
1257 self.sbuild.name(rule.name).target(target).host(host)
1263 /// Execute all top-level targets indicated by `steps`.
1265 /// This will take the list returned by `plan` and then execute each step
1266 /// along with all required dependencies as it goes up the chain.
1267 fn run(&self, steps: &[Step<'a>]) {
1268 self.build.verbose("bootstrap top targets:");
1269 for step in steps.iter() {
1270 self.build.verbose(&format!("\t{:?}", step));
1273 // Using `steps` as the top-level targets, make a topological ordering
1274 // of what we need to do.
1275 let order = self.expand(steps);
1277 // Print out what we're doing for debugging
1278 self.build.verbose("bootstrap build plan:");
1279 for step in order.iter() {
1280 self.build.verbose(&format!("\t{:?}", step));
1283 // And finally, iterate over everything and execute it.
1284 for step in order.iter() {
1285 if self.build.flags.keep_stage.map_or(false, |s| step.stage <= s) {
1286 self.build.verbose(&format!("keeping step {:?}", step));
1289 self.build.verbose(&format!("executing step {:?}", step));
1290 (self.rules[step.name].run)(step);
1293 // Check for postponed failures from `test --no-fail-fast`.
1294 let failures = self.build.delayed_failures.get();
1296 println!("\n{} command(s) did not execute successfully.\n", failures);
1301 /// From the top level targets `steps` generate a topological ordering of
1302 /// all steps needed to run those steps.
1303 fn expand(&self, steps: &[Step<'a>]) -> Vec<Step<'a>> {
1304 // First up build a graph of steps and their dependencies. The `nodes`
1305 // map is a map from step to a unique number. The `edges` map is a
1306 // map from these unique numbers to a list of other numbers,
1307 // representing dependencies.
1308 let mut nodes = HashMap::new();
1309 nodes.insert(Step::noop(), 0);
1310 let mut edges = HashMap::new();
1311 edges.insert(0, HashSet::new());
1313 self.build_graph(step.clone(), &mut nodes, &mut edges);
1316 // Now that we've built up the actual dependency graph, draw more
1317 // dependency edges to satisfy the `after` dependencies field for each
1319 self.satisfy_after_deps(&nodes, &mut edges);
1321 // And finally, perform a topological sort to return a list of steps to
1323 let mut order = Vec::new();
1324 let mut visited = HashSet::new();
1326 let idx_to_node = nodes.iter().map(|p| (*p.1, p.0)).collect::<HashMap<_, _>>();
1327 for idx in 0..nodes.len() {
1328 self.topo_sort(idx, &idx_to_node, &edges, &mut visited, &mut order);
1333 /// Builds the dependency graph rooted at `step`.
1335 /// The `nodes` and `edges` maps are filled out according to the rule
1336 /// described by `step.name`.
1337 fn build_graph(&self,
1339 nodes: &mut HashMap<Step<'a>, usize>,
1340 edges: &mut HashMap<usize, HashSet<usize>>) -> usize {
1341 use std::collections::hash_map::Entry;
1343 let idx = nodes.len();
1344 match nodes.entry(step.clone()) {
1345 Entry::Vacant(e) => { e.insert(idx); }
1346 Entry::Occupied(e) => return *e.get(),
1349 let mut deps = Vec::new();
1350 for dep in self.rules[step.name].deps.iter() {
1351 let dep = dep(&step);
1352 if dep.name.starts_with("default:") {
1353 let kind = match &dep.name[8..] {
1355 "dist" => Kind::Dist,
1356 kind => panic!("unknown kind: `{}`", kind),
1358 let host = self.build.config.host.iter().any(|h| h == dep.target);
1359 let rules = self.rules.values().filter(|r| r.default);
1360 for rule in rules.filter(|r| r.kind == kind && (!r.host || host)) {
1361 deps.push(self.build_graph(dep.name(rule.name), nodes, edges));
1364 deps.push(self.build_graph(dep, nodes, edges));
1368 edges.entry(idx).or_insert(HashSet::new()).extend(deps);
1372 /// Given a dependency graph with a finished list of `nodes`, fill out more
1373 /// dependency `edges`.
1375 /// This is the step which satisfies all `after` listed dependencies in
1377 fn satisfy_after_deps(&self,
1378 nodes: &HashMap<Step<'a>, usize>,
1379 edges: &mut HashMap<usize, HashSet<usize>>) {
1380 // Reverse map from the name of a step to the node indices that it
1382 let mut name_to_idx = HashMap::new();
1383 for (step, &idx) in nodes {
1384 name_to_idx.entry(step.name).or_insert(Vec::new()).push(idx);
1387 for (step, idx) in nodes {
1388 if *step == Step::noop() {
1391 for after in self.rules[step.name].after.iter() {
1392 // This is the critical piece of an `after` dependency. If the
1393 // dependency isn't actually in our graph then no edge is drawn,
1394 // only if it's already present do we draw the edges.
1395 if let Some(idxs) = name_to_idx.get(after) {
1396 edges.get_mut(idx).unwrap()
1397 .extend(idxs.iter().cloned());
1405 nodes: &HashMap<usize, &Step<'a>>,
1406 edges: &HashMap<usize, HashSet<usize>>,
1407 visited: &mut HashSet<usize>,
1408 order: &mut Vec<Step<'a>>) {
1409 if !visited.insert(cur) {
1412 for dep in edges[&cur].iter() {
1413 self.topo_sort(*dep, nodes, edges, visited, order);
1415 order.push(nodes[&cur].clone());
1427 fn build(args: &[&str],
1428 extra_host: &[&str],
1429 extra_target: &[&str]) -> Build {
1430 build_(args, extra_host, extra_target, true)
1433 fn build_(args: &[&str],
1434 extra_host: &[&str],
1435 extra_target: &[&str],
1436 docs: bool) -> Build {
1437 let mut args = args.iter().map(|s| s.to_string()).collect::<Vec<_>>();
1438 args.push("--build".to_string());
1439 args.push("A".to_string());
1440 let flags = Flags::parse(&args);
1442 let mut config = Config::default();
1444 config.build = "A".to_string();
1445 config.host = vec![config.build.clone()];
1446 config.host.extend(extra_host.iter().map(|s| s.to_string()));
1447 config.target = config.host.clone();
1448 config.target.extend(extra_target.iter().map(|s| s.to_string()));
1450 let mut build = Build::new(flags, config);
1451 let cwd = env::current_dir().unwrap();
1452 build.crates.insert("std".to_string(), ::Crate {
1453 name: "std".to_string(),
1455 path: cwd.join("src/std"),
1456 doc_step: "doc-crate-std".to_string(),
1457 build_step: "build-crate-std".to_string(),
1458 test_step: "test-crate-std".to_string(),
1459 bench_step: "bench-crate-std".to_string(),
1460 version: String::new(),
1462 build.crates.insert("test".to_string(), ::Crate {
1463 name: "test".to_string(),
1465 path: cwd.join("src/test"),
1466 doc_step: "doc-crate-test".to_string(),
1467 build_step: "build-crate-test".to_string(),
1468 test_step: "test-crate-test".to_string(),
1469 bench_step: "bench-crate-test".to_string(),
1470 version: String::new(),
1472 build.crates.insert("rustc-main".to_string(), ::Crate {
1473 name: "rustc-main".to_string(),
1475 version: String::new(),
1476 path: cwd.join("src/rustc-main"),
1477 doc_step: "doc-crate-rustc-main".to_string(),
1478 build_step: "build-crate-rustc-main".to_string(),
1479 test_step: "test-crate-rustc-main".to_string(),
1480 bench_step: "bench-crate-rustc-main".to_string(),
1486 fn dist_baseline() {
1487 let build = build(&["dist"], &[], &[]);
1488 let rules = super::build_rules(&build);
1489 let plan = rules.plan();
1490 println!("rules: {:#?}", plan);
1491 assert!(plan.iter().all(|s| s.stage == 2));
1492 assert!(plan.iter().all(|s| s.host == "A" ));
1493 assert!(plan.iter().all(|s| s.target == "A" ));
1495 let step = super::Step {
1499 target: &build.build,
1502 assert!(plan.contains(&step.name("dist-docs")));
1503 assert!(plan.contains(&step.name("dist-mingw")));
1504 assert!(plan.contains(&step.name("dist-rustc")));
1505 assert!(plan.contains(&step.name("dist-std")));
1506 assert!(plan.contains(&step.name("dist-src")));
1510 fn dist_with_targets() {
1511 let build = build(&["dist"], &[], &["B"]);
1512 let rules = super::build_rules(&build);
1513 let plan = rules.plan();
1514 println!("rules: {:#?}", plan);
1515 assert!(plan.iter().all(|s| s.stage == 2));
1516 assert!(plan.iter().all(|s| s.host == "A" ));
1518 let step = super::Step {
1522 target: &build.build,
1525 assert!(plan.contains(&step.name("dist-docs")));
1526 assert!(plan.contains(&step.name("dist-mingw")));
1527 assert!(plan.contains(&step.name("dist-rustc")));
1528 assert!(plan.contains(&step.name("dist-std")));
1529 assert!(plan.contains(&step.name("dist-src")));
1531 assert!(plan.contains(&step.target("B").name("dist-docs")));
1532 assert!(plan.contains(&step.target("B").name("dist-mingw")));
1533 assert!(!plan.contains(&step.target("B").name("dist-rustc")));
1534 assert!(plan.contains(&step.target("B").name("dist-std")));
1535 assert!(!plan.contains(&step.target("B").name("dist-src")));
1539 fn dist_with_hosts() {
1540 let build = build(&["dist"], &["B"], &[]);
1541 let rules = super::build_rules(&build);
1542 let plan = rules.plan();
1543 println!("rules: {:#?}", plan);
1544 assert!(plan.iter().all(|s| s.stage == 2));
1546 let step = super::Step {
1550 target: &build.build,
1553 assert!(!plan.iter().any(|s| s.host == "B"));
1555 assert!(plan.contains(&step.name("dist-docs")));
1556 assert!(plan.contains(&step.name("dist-mingw")));
1557 assert!(plan.contains(&step.name("dist-rustc")));
1558 assert!(plan.contains(&step.name("dist-std")));
1559 assert!(plan.contains(&step.name("dist-src")));
1561 assert!(plan.contains(&step.target("B").name("dist-docs")));
1562 assert!(plan.contains(&step.target("B").name("dist-mingw")));
1563 assert!(plan.contains(&step.target("B").name("dist-rustc")));
1564 assert!(plan.contains(&step.target("B").name("dist-std")));
1565 assert!(!plan.contains(&step.target("B").name("dist-src")));
1569 fn dist_with_targets_and_hosts() {
1570 let build = build(&["dist"], &["B"], &["C"]);
1571 let rules = super::build_rules(&build);
1572 let plan = rules.plan();
1573 println!("rules: {:#?}", plan);
1574 assert!(plan.iter().all(|s| s.stage == 2));
1576 let step = super::Step {
1580 target: &build.build,
1583 assert!(!plan.iter().any(|s| s.host == "B"));
1584 assert!(!plan.iter().any(|s| s.host == "C"));
1586 assert!(plan.contains(&step.name("dist-docs")));
1587 assert!(plan.contains(&step.name("dist-mingw")));
1588 assert!(plan.contains(&step.name("dist-rustc")));
1589 assert!(plan.contains(&step.name("dist-std")));
1590 assert!(plan.contains(&step.name("dist-src")));
1592 assert!(plan.contains(&step.target("B").name("dist-docs")));
1593 assert!(plan.contains(&step.target("B").name("dist-mingw")));
1594 assert!(plan.contains(&step.target("B").name("dist-rustc")));
1595 assert!(plan.contains(&step.target("B").name("dist-std")));
1596 assert!(!plan.contains(&step.target("B").name("dist-src")));
1598 assert!(plan.contains(&step.target("C").name("dist-docs")));
1599 assert!(plan.contains(&step.target("C").name("dist-mingw")));
1600 assert!(!plan.contains(&step.target("C").name("dist-rustc")));
1601 assert!(plan.contains(&step.target("C").name("dist-std")));
1602 assert!(!plan.contains(&step.target("C").name("dist-src")));
1606 fn dist_target_with_target_flag() {
1607 let build = build(&["dist", "--target=C"], &["B"], &["C"]);
1608 let rules = super::build_rules(&build);
1609 let plan = rules.plan();
1610 println!("rules: {:#?}", plan);
1611 assert!(plan.iter().all(|s| s.stage == 2));
1613 let step = super::Step {
1617 target: &build.build,
1620 assert!(!plan.iter().any(|s| s.target == "A"));
1621 assert!(!plan.iter().any(|s| s.target == "B"));
1622 assert!(!plan.iter().any(|s| s.host == "B"));
1623 assert!(!plan.iter().any(|s| s.host == "C"));
1625 assert!(plan.contains(&step.target("C").name("dist-docs")));
1626 assert!(plan.contains(&step.target("C").name("dist-mingw")));
1627 assert!(!plan.contains(&step.target("C").name("dist-rustc")));
1628 assert!(plan.contains(&step.target("C").name("dist-std")));
1629 assert!(!plan.contains(&step.target("C").name("dist-src")));
1633 fn dist_host_with_target_flag() {
1634 let build = build(&["dist", "--host=B", "--target=B"], &["B"], &["C"]);
1635 let rules = super::build_rules(&build);
1636 let plan = rules.plan();
1637 println!("rules: {:#?}", plan);
1638 assert!(plan.iter().all(|s| s.stage == 2));
1640 let step = super::Step {
1644 target: &build.build,
1647 assert!(!plan.iter().any(|s| s.target == "A"));
1648 assert!(!plan.iter().any(|s| s.target == "C"));
1649 assert!(!plan.iter().any(|s| s.host == "B"));
1650 assert!(!plan.iter().any(|s| s.host == "C"));
1652 assert!(plan.contains(&step.target("B").name("dist-docs")));
1653 assert!(plan.contains(&step.target("B").name("dist-mingw")));
1654 assert!(plan.contains(&step.target("B").name("dist-rustc")));
1655 assert!(plan.contains(&step.target("B").name("dist-std")));
1656 assert!(plan.contains(&step.target("B").name("dist-src")));
1658 let all = rules.expand(&plan);
1659 println!("all rules: {:#?}", all);
1660 assert!(!all.contains(&step.name("rustc")));
1661 assert!(!all.contains(&step.name("build-crate-test").stage(1)));
1663 // all stage0 compiles should be for the build target, A
1664 for step in all.iter().filter(|s| s.stage == 0) {
1665 if !step.name.contains("build-crate") {
1668 println!("step: {:?}", step);
1669 assert!(step.host != "B");
1670 assert!(step.target != "B");
1671 assert!(step.host != "C");
1672 assert!(step.target != "C");
1677 fn build_default() {
1678 let build = build(&["build"], &["B"], &["C"]);
1679 let rules = super::build_rules(&build);
1680 let plan = rules.plan();
1681 println!("rules: {:#?}", plan);
1682 assert!(plan.iter().all(|s| s.stage == 2));
1684 let step = super::Step {
1688 target: &build.build,
1691 // rustc built for all for of (A, B) x (A, B)
1692 assert!(plan.contains(&step.name("librustc")));
1693 assert!(plan.contains(&step.target("B").name("librustc")));
1694 assert!(plan.contains(&step.host("B").target("A").name("librustc")));
1695 assert!(plan.contains(&step.host("B").target("B").name("librustc")));
1697 // rustc never built for C
1698 assert!(!plan.iter().any(|s| {
1699 s.name.contains("rustc") && (s.host == "C" || s.target == "C")
1702 // test built for everything
1703 assert!(plan.contains(&step.name("libtest")));
1704 assert!(plan.contains(&step.target("B").name("libtest")));
1705 assert!(plan.contains(&step.host("B").target("A").name("libtest")));
1706 assert!(plan.contains(&step.host("B").target("B").name("libtest")));
1707 assert!(plan.contains(&step.host("A").target("C").name("libtest")));
1708 assert!(plan.contains(&step.host("B").target("C").name("libtest")));
1710 let all = rules.expand(&plan);
1711 println!("all rules: {:#?}", all);
1712 assert!(all.contains(&step.name("rustc")));
1713 assert!(all.contains(&step.name("libstd")));
1717 fn build_filtered() {
1718 let build = build(&["build", "--target=C"], &["B"], &["C"]);
1719 let rules = super::build_rules(&build);
1720 let plan = rules.plan();
1721 println!("rules: {:#?}", plan);
1722 assert!(plan.iter().all(|s| s.stage == 2));
1724 assert!(!plan.iter().any(|s| s.name.contains("rustc")));
1725 assert!(plan.iter().all(|s| {
1726 !s.name.contains("test") || s.target == "C"
1732 let build = build(&["test"], &[], &[]);
1733 let rules = super::build_rules(&build);
1734 let plan = rules.plan();
1735 println!("rules: {:#?}", plan);
1736 assert!(plan.iter().all(|s| s.stage == 2));
1737 assert!(plan.iter().all(|s| s.host == "A"));
1738 assert!(plan.iter().all(|s| s.target == "A"));
1740 assert!(plan.iter().any(|s| s.name.contains("-ui")));
1741 assert!(plan.iter().any(|s| s.name.contains("cfail")));
1742 assert!(plan.iter().any(|s| s.name.contains("cfail-full")));
1743 assert!(plan.iter().any(|s| s.name.contains("codegen-units")));
1744 assert!(plan.iter().any(|s| s.name.contains("debuginfo")));
1745 assert!(plan.iter().any(|s| s.name.contains("docs")));
1746 assert!(plan.iter().any(|s| s.name.contains("error-index")));
1747 assert!(plan.iter().any(|s| s.name.contains("incremental")));
1748 assert!(plan.iter().any(|s| s.name.contains("linkchecker")));
1749 assert!(plan.iter().any(|s| s.name.contains("mir-opt")));
1750 assert!(plan.iter().any(|s| s.name.contains("pfail")));
1751 assert!(plan.iter().any(|s| s.name.contains("rfail")));
1752 assert!(plan.iter().any(|s| s.name.contains("rfail-full")));
1753 assert!(plan.iter().any(|s| s.name.contains("rmake")));
1754 assert!(plan.iter().any(|s| s.name.contains("rpass")));
1755 assert!(plan.iter().any(|s| s.name.contains("rpass-full")));
1756 assert!(plan.iter().any(|s| s.name.contains("rustc-all")));
1757 assert!(plan.iter().any(|s| s.name.contains("rustdoc")));
1758 assert!(plan.iter().any(|s| s.name.contains("std-all")));
1759 assert!(plan.iter().any(|s| s.name.contains("test-all")));
1760 assert!(plan.iter().any(|s| s.name.contains("tidy")));
1761 assert!(plan.iter().any(|s| s.name.contains("valgrind")));
1765 fn test_with_a_target() {
1766 let build = build(&["test", "--target=C"], &[], &["C"]);
1767 let rules = super::build_rules(&build);
1768 let plan = rules.plan();
1769 println!("rules: {:#?}", plan);
1770 assert!(plan.iter().all(|s| s.stage == 2));
1771 assert!(plan.iter().all(|s| s.host == "A"));
1772 assert!(plan.iter().all(|s| s.target == "C"));
1774 assert!(plan.iter().any(|s| s.name.contains("-ui")));
1775 assert!(!plan.iter().any(|s| s.name.contains("ui-full")));
1776 assert!(plan.iter().any(|s| s.name.contains("cfail")));
1777 assert!(!plan.iter().any(|s| s.name.contains("cfail-full")));
1778 assert!(plan.iter().any(|s| s.name.contains("codegen-units")));
1779 assert!(plan.iter().any(|s| s.name.contains("debuginfo")));
1780 assert!(!plan.iter().any(|s| s.name.contains("docs")));
1781 assert!(!plan.iter().any(|s| s.name.contains("error-index")));
1782 assert!(plan.iter().any(|s| s.name.contains("incremental")));
1783 assert!(!plan.iter().any(|s| s.name.contains("linkchecker")));
1784 assert!(plan.iter().any(|s| s.name.contains("mir-opt")));
1785 assert!(plan.iter().any(|s| s.name.contains("pfail")));
1786 assert!(plan.iter().any(|s| s.name.contains("rfail")));
1787 assert!(!plan.iter().any(|s| s.name.contains("rfail-full")));
1788 assert!(!plan.iter().any(|s| s.name.contains("rmake")));
1789 assert!(plan.iter().any(|s| s.name.contains("rpass")));
1790 assert!(!plan.iter().any(|s| s.name.contains("rpass-full")));
1791 assert!(!plan.iter().any(|s| s.name.contains("rustc-all")));
1792 assert!(!plan.iter().any(|s| s.name.contains("rustdoc")));
1793 assert!(plan.iter().any(|s| s.name.contains("std-all")));
1794 assert!(plan.iter().any(|s| s.name.contains("test-all")));
1795 assert!(!plan.iter().any(|s| s.name.contains("tidy")));
1796 assert!(plan.iter().any(|s| s.name.contains("valgrind")));
1800 fn test_disable_docs() {
1801 let build = build_(&["test"], &[], &[], false);
1802 let rules = super::build_rules(&build);
1803 let plan = rules.plan();
1804 println!("rules: {:#?}", plan);
1805 assert!(!plan.iter().any(|s| {
1806 s.name.contains("doc-") || s.name.contains("default:doc")
1808 // none of the dependencies should be a doc rule either
1809 assert!(!plan.iter().any(|s| {
1810 rules.rules[s.name].deps.iter().any(|dep| {
1811 let dep = dep(&rules.sbuild.name(s.name));
1812 dep.name.contains("doc-") || dep.name.contains("default:doc")