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 use std
::collections
::{HashMap, HashSet}
;
18 use flags
::Subcommand
;
21 use {Compiler, Build, Mode}
;
23 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
32 fn name(&self, name
: &'a
str) -> Step
<'a
> {
33 Step { name: name, ..*self }
36 fn stage(&self, stage
: u32) -> Step
<'a
> {
37 Step { stage: stage, ..*self }
40 fn host(&self, host
: &'a
str) -> Step
<'a
> {
41 Step { host: host, ..*self }
44 fn target(&self, target
: &'a
str) -> Step
<'a
> {
45 Step { target: target, ..*self }
48 fn compiler(&self) -> Compiler
<'a
> {
49 Compiler
::new(self.stage
, self.host
)
53 pub fn run(build
: &Build
) {
54 let rules
= build_rules(build
);
55 let steps
= rules
.plan();
59 pub fn build_rules(build
: &Build
) -> Rules
{
60 let mut rules
: Rules
= Rules
::new(build
);
61 // dummy rule to do nothing, useful when a dep maps to no deps
62 rules
.build("dummy", "path/to/nowhere");
63 fn dummy
<'a
>(s
: &Step
<'a
>, build
: &'a Build
) -> Step
<'a
> {
64 s
.name("dummy").stage(0)
65 .target(&build
.config
.build
)
66 .host(&build
.config
.build
)
69 // Helper for loading an entire DAG of crates, rooted at `name`
70 let krates
= |name
: &str| {
71 let mut ret
= Vec
::new();
72 let mut list
= vec
![name
];
73 let mut visited
= HashSet
::new();
74 while let Some(krate
) = list
.pop() {
75 let default = krate
== name
;
76 let krate
= &build
.crates
[krate
];
77 let path
= krate
.path
.strip_prefix(&build
.src
).unwrap();
78 ret
.push((krate
, path
.to_str().unwrap(), default));
79 for dep
in krate
.deps
.iter() {
80 if visited
.insert(dep
) && dep
!= "build_helper" {
88 rules
.build("rustc", "path/to/nowhere")
94 .host(&build
.config
.build
)
98 .run(move |s
| compile
::assemble_rustc(build
, s
.stage
, s
.target
));
99 rules
.build("llvm", "src/llvm")
101 .run(move |s
| native
::llvm(build
, s
.target
));
103 // ========================================================================
104 // Crate compilations
106 // Tools used during the build system but not shipped
107 rules
.build("libstd", "src/libstd")
108 .dep(|s
| s
.name("build-crate-std_shim"));
109 rules
.build("libtest", "src/libtest")
110 .dep(|s
| s
.name("build-crate-test_shim"));
111 rules
.build("librustc", "src/librustc")
112 .dep(|s
| s
.name("build-crate-rustc-main"));
113 for (krate
, path
, _default
) in krates("std_shim") {
114 rules
.build(&krate
.build_step
, path
)
115 .dep(move |s
| s
.name("rustc").host(&build
.config
.build
).target(s
.host
))
117 if s
.host
== build
.config
.build
{
120 s
.host(&build
.config
.build
)
124 if s
.host
== build
.config
.build
{
125 compile
::std(build
, s
.target
, &s
.compiler())
127 compile
::std_link(build
, s
.target
, s
.stage
, s
.host
)
131 for (krate
, path
, default) in krates("test_shim") {
132 rules
.build(&krate
.build_step
, path
)
133 .dep(|s
| s
.name("libstd"))
135 if s
.host
== build
.config
.build
{
138 s
.host(&build
.config
.build
)
143 if s
.host
== build
.config
.build
{
144 compile
::test(build
, s
.target
, &s
.compiler())
146 compile
::test_link(build
, s
.target
, s
.stage
, s
.host
)
150 for (krate
, path
, default) in krates("rustc-main") {
151 rules
.build(&krate
.build_step
, path
)
152 .dep(|s
| s
.name("libtest"))
153 .dep(move |s
| s
.name("llvm").host(&build
.config
.build
).stage(0))
155 if s
.host
== build
.config
.build
{
158 s
.host(&build
.config
.build
)
164 if s
.host
== build
.config
.build
{
165 compile
::rustc(build
, s
.target
, &s
.compiler())
167 compile
::rustc_link(build
, s
.target
, s
.stage
, s
.host
)
172 // ========================================================================
175 // Various unit tests and tests suites we can run
177 let mut suite
= |name
, path
, dir
, mode
| {
178 rules
.test(name
, path
)
179 .dep(|s
| s
.name("libtest"))
180 .dep(|s
| s
.name("tool-compiletest").target(s
.host
))
181 .dep(|s
| s
.name("test-helpers"))
183 if s
.target
.contains("android") {
184 s
.name("android-copy-libs")
191 check
::compiletest(build
, &s
.compiler(), s
.target
, dir
, mode
)
195 suite("check-rpass", "src/test/run-pass", "run-pass", "run-pass");
196 suite("check-cfail", "src/test/compile-fail", "compile-fail", "compile-fail");
197 suite("check-pfail", "src/test/parse-fail", "parse-fail", "parse-fail");
198 suite("check-rfail", "src/test/run-fail", "run-fail", "run-fail");
199 suite("check-rpass-valgrind", "src/test/run-pass-valgrind",
200 "run-pass-valgrind", "run-pass-valgrind");
201 suite("check-mir-opt", "src/test/mir-opt", "mir-opt", "mir-opt");
202 if build
.config
.codegen_tests
{
203 suite("check-codegen", "src/test/codegen", "codegen", "codegen");
205 suite("check-codegen-units", "src/test/codegen-units", "codegen-units",
207 suite("check-incremental", "src/test/incremental", "incremental",
209 suite("check-ui", "src/test/ui", "ui", "ui");
210 suite("check-pretty", "src/test/pretty", "pretty", "pretty");
211 suite("check-pretty-rpass", "src/test/run-pass/pretty", "pretty",
213 suite("check-pretty-rfail", "src/test/run-pass/pretty", "pretty",
215 suite("check-pretty-valgrind", "src/test/run-pass-valgrind", "pretty",
216 "run-pass-valgrind");
219 if build
.config
.build
.contains("msvc") {
220 // nothing to do for debuginfo tests
221 } else if build
.config
.build
.contains("apple") {
222 rules
.test("check-debuginfo", "src/test/debuginfo")
223 .dep(|s
| s
.name("libtest"))
224 .dep(|s
| s
.name("tool-compiletest").host(s
.host
))
225 .dep(|s
| s
.name("test-helpers"))
226 .dep(|s
| s
.name("debugger-scripts"))
227 .run(move |s
| check
::compiletest(build
, &s
.compiler(), s
.target
,
228 "debuginfo-lldb", "debuginfo"));
230 rules
.test("check-debuginfo", "src/test/debuginfo")
231 .dep(|s
| s
.name("libtest"))
232 .dep(|s
| s
.name("tool-compiletest").host(s
.host
))
233 .dep(|s
| s
.name("test-helpers"))
234 .dep(|s
| s
.name("debugger-scripts"))
235 .run(move |s
| check
::compiletest(build
, &s
.compiler(), s
.target
,
236 "debuginfo-gdb", "debuginfo"));
239 rules
.test("debugger-scripts", "src/etc/lldb_batchmode.py")
240 .run(move |s
| dist
::debugger_scripts(build
, &build
.sysroot(&s
.compiler()),
244 let mut suite
= |name
, path
, dir
, mode
| {
245 rules
.test(name
, path
)
246 .dep(|s
| s
.name("librustc"))
247 .dep(|s
| s
.name("tool-compiletest").target(s
.host
))
251 check
::compiletest(build
, &s
.compiler(), s
.target
, dir
, mode
)
255 suite("check-rpass-full", "src/test/run-pass-fulldeps",
256 "run-pass", "run-pass-fulldeps");
257 suite("check-cfail-full", "src/test/compile-fail-fulldeps",
258 "compile-fail", "compile-fail-fulldeps");
259 suite("check-rmake", "src/test/run-make", "run-make", "run-make");
260 suite("check-rustdoc", "src/test/rustdoc", "rustdoc", "rustdoc");
261 suite("check-pretty-rpass-full", "src/test/run-pass-fulldeps",
262 "pretty", "run-pass-fulldeps");
263 suite("check-pretty-rfail-full", "src/test/run-fail-fulldeps",
264 "pretty", "run-fail-fulldeps");
267 for (krate
, path
, _default
) in krates("std_shim") {
268 rules
.test(&krate
.test_step
, path
)
269 .dep(|s
| s
.name("libtest"))
270 .run(move |s
| check
::krate(build
, &s
.compiler(), s
.target
,
271 Mode
::Libstd
, Some(&krate
.name
)));
273 rules
.test("check-std-all", "path/to/nowhere")
274 .dep(|s
| s
.name("libtest"))
276 .run(move |s
| check
::krate(build
, &s
.compiler(), s
.target
, Mode
::Libstd
,
278 for (krate
, path
, _default
) in krates("test_shim") {
279 rules
.test(&krate
.test_step
, path
)
280 .dep(|s
| s
.name("libtest"))
281 .run(move |s
| check
::krate(build
, &s
.compiler(), s
.target
,
282 Mode
::Libtest
, Some(&krate
.name
)));
284 rules
.test("check-test-all", "path/to/nowhere")
285 .dep(|s
| s
.name("libtest"))
287 .run(move |s
| check
::krate(build
, &s
.compiler(), s
.target
, Mode
::Libtest
,
289 for (krate
, path
, _default
) in krates("rustc-main") {
290 rules
.test(&krate
.test_step
, path
)
291 .dep(|s
| s
.name("librustc"))
293 .run(move |s
| check
::krate(build
, &s
.compiler(), s
.target
,
294 Mode
::Librustc
, Some(&krate
.name
)));
296 rules
.test("check-rustc-all", "path/to/nowhere")
297 .dep(|s
| s
.name("librustc"))
300 .run(move |s
| check
::krate(build
, &s
.compiler(), s
.target
, Mode
::Librustc
,
303 rules
.test("check-linkchecker", "src/tools/linkchecker")
304 .dep(|s
| s
.name("tool-linkchecker"))
305 .dep(|s
| s
.name("default:doc"))
308 .run(move |s
| check
::linkcheck(build
, s
.stage
, s
.target
));
309 rules
.test("check-cargotest", "src/tools/cargotest")
310 .dep(|s
| s
.name("tool-cargotest"))
311 .dep(|s
| s
.name("librustc"))
313 .run(move |s
| check
::cargotest(build
, s
.stage
, s
.target
));
314 rules
.test("check-tidy", "src/tools/tidy")
315 .dep(|s
| s
.name("tool-tidy"))
318 .run(move |s
| check
::tidy(build
, s
.stage
, s
.target
));
319 rules
.test("check-error-index", "src/tools/error_index_generator")
320 .dep(|s
| s
.name("libstd"))
321 .dep(|s
| s
.name("tool-error-index").host(s
.host
))
324 .run(move |s
| check
::error_index(build
, &s
.compiler()));
325 rules
.test("check-docs", "src/doc")
326 .dep(|s
| s
.name("libtest"))
329 .run(move |s
| check
::docs(build
, &s
.compiler()));
331 rules
.build("test-helpers", "src/rt/rust_test_helpers.c")
332 .run(move |s
| native
::test_helpers(build
, s
.target
));
333 rules
.test("android-copy-libs", "path/to/nowhere")
334 .dep(|s
| s
.name("libtest"))
335 .run(move |s
| check
::android_copy_libs(build
, &s
.compiler(), s
.target
));
337 // ========================================================================
340 // Tools used during the build system but not shipped
341 rules
.build("tool-rustbook", "src/tools/rustbook")
342 .dep(|s
| s
.name("librustc"))
343 .run(move |s
| compile
::tool(build
, s
.stage
, s
.target
, "rustbook"));
344 rules
.build("tool-error-index", "src/tools/error_index_generator")
345 .dep(|s
| s
.name("librustc"))
346 .run(move |s
| compile
::tool(build
, s
.stage
, s
.target
, "error_index_generator"));
347 rules
.build("tool-tidy", "src/tools/tidy")
348 .dep(|s
| s
.name("libstd"))
349 .run(move |s
| compile
::tool(build
, s
.stage
, s
.target
, "tidy"));
350 rules
.build("tool-linkchecker", "src/tools/linkchecker")
351 .dep(|s
| s
.name("libstd"))
352 .run(move |s
| compile
::tool(build
, s
.stage
, s
.target
, "linkchecker"));
353 rules
.build("tool-cargotest", "src/tools/cargotest")
354 .dep(|s
| s
.name("libstd"))
355 .run(move |s
| compile
::tool(build
, s
.stage
, s
.target
, "cargotest"));
356 rules
.build("tool-compiletest", "src/tools/compiletest")
357 .dep(|s
| s
.name("libtest"))
358 .run(move |s
| compile
::tool(build
, s
.stage
, s
.target
, "compiletest"));
360 // ========================================================================
361 // Documentation targets
362 rules
.doc("doc-book", "src/doc/book")
363 .dep(move |s
| s
.name("tool-rustbook").target(&build
.config
.build
))
364 .default(build
.config
.docs
)
365 .run(move |s
| doc
::rustbook(build
, s
.stage
, s
.target
, "book"));
366 rules
.doc("doc-nomicon", "src/doc/nomicon")
367 .dep(move |s
| s
.name("tool-rustbook").target(&build
.config
.build
))
368 .default(build
.config
.docs
)
369 .run(move |s
| doc
::rustbook(build
, s
.stage
, s
.target
, "nomicon"));
370 rules
.doc("doc-standalone", "src/doc")
371 .dep(move |s
| s
.name("rustc").host(&build
.config
.build
).target(&build
.config
.build
))
372 .default(build
.config
.docs
)
373 .run(move |s
| doc
::standalone(build
, s
.stage
, s
.target
));
374 rules
.doc("doc-error-index", "src/tools/error_index_generator")
375 .dep(move |s
| s
.name("tool-error-index").target(&build
.config
.build
))
376 .dep(move |s
| s
.name("librustc"))
377 .default(build
.config
.docs
)
379 .run(move |s
| doc
::error_index(build
, s
.stage
, s
.target
));
380 for (krate
, path
, default) in krates("std_shim") {
381 rules
.doc(&krate
.doc_step
, path
)
382 .dep(|s
| s
.name("libstd"))
383 .default(default && build
.config
.docs
)
384 .run(move |s
| doc
::std(build
, s
.stage
, s
.target
));
386 for (krate
, path
, default) in krates("test_shim") {
387 rules
.doc(&krate
.doc_step
, path
)
388 .dep(|s
| s
.name("libtest"))
389 .default(default && build
.config
.docs
)
390 .run(move |s
| doc
::test(build
, s
.stage
, s
.target
));
392 for (krate
, path
, default) in krates("rustc-main") {
393 rules
.doc(&krate
.doc_step
, path
)
394 .dep(|s
| s
.name("librustc"))
396 .default(default && build
.config
.compiler_docs
)
397 .run(move |s
| doc
::rustc(build
, s
.stage
, s
.target
));
400 // ========================================================================
401 // Distribution targets
402 rules
.dist("dist-rustc", "src/librustc")
403 .dep(move |s
| s
.name("rustc").host(&build
.config
.build
))
406 .run(move |s
| dist
::rustc(build
, s
.stage
, s
.target
));
407 rules
.dist("dist-std", "src/libstd")
409 // We want to package up as many target libraries as possible
410 // for the `rust-std` package, so if this is a host target we
411 // depend on librustc and otherwise we just depend on libtest.
412 if build
.config
.host
.iter().any(|t
| t
== s
.target
) {
419 .run(move |s
| dist
::std(build
, &s
.compiler(), s
.target
));
420 rules
.dist("dist-mingw", "path/to/nowhere")
421 .run(move |s
| dist
::mingw(build
, s
.target
));
422 rules
.dist("dist-src", "src")
425 .run(move |_
| dist
::rust_src(build
));
426 rules
.dist("dist-docs", "src/doc")
428 .dep(|s
| s
.name("default:doc"))
429 .run(move |s
| dist
::docs(build
, s
.stage
, s
.target
));
430 rules
.dist("install", "src")
431 .dep(|s
| s
.name("default:dist"))
432 .run(move |s
| install
::install(build
, s
.stage
, s
.target
));
442 deps
: Vec
<Box
<Fn(&Step
<'a
>) -> Step
<'a
> + 'a
>>,
443 run
: Box
<Fn(&Step
<'a
>) + 'a
>,
457 fn new(name
: &'a
str, path
: &'a
str, kind
: Kind
) -> Rule
<'a
> {
461 run
: Box
::new(|_
| ()),
470 struct RuleBuilder
<'a
: 'b
, 'b
> {
471 rules
: &'b
mut Rules
<'a
>,
475 impl<'a
, 'b
> RuleBuilder
<'a
, 'b
> {
476 fn dep
<F
>(&mut self, f
: F
) -> &mut Self
477 where F
: Fn(&Step
<'a
>) -> Step
<'a
> + 'a
,
479 self.rule
.deps
.push(Box
::new(f
));
483 fn run
<F
>(&mut self, f
: F
) -> &mut Self
484 where F
: Fn(&Step
<'a
>) + 'a
,
486 self.rule
.run
= Box
::new(f
);
490 fn default(&mut self, default: bool
) -> &mut Self {
491 self.rule
.default = default;
495 fn host(&mut self, host
: bool
) -> &mut Self {
496 self.rule
.host
= host
;
501 impl<'a
, 'b
> Drop
for RuleBuilder
<'a
, 'b
> {
503 let rule
= mem
::replace(&mut self.rule
, Rule
::new("", "", Kind
::Build
));
504 let prev
= self.rules
.rules
.insert(rule
.name
, rule
);
505 if let Some(prev
) = prev
{
506 panic
!("duplicate rule named: {}", prev
.name
);
511 pub struct Rules
<'a
> {
514 rules
: HashMap
<&'a
str, Rule
<'a
>>,
518 fn new(build
: &'a Build
) -> Rules
<'a
> {
522 stage
: build
.flags
.stage
.unwrap_or(2),
523 target
: &build
.config
.build
,
524 host
: &build
.config
.build
,
527 rules
: HashMap
::new(),
531 fn build
<'b
>(&'b
mut self, name
: &'a
str, path
: &'a
str)
532 -> RuleBuilder
<'a
, 'b
> {
533 self.rule(name
, path
, Kind
::Build
)
536 fn test
<'b
>(&'b
mut self, name
: &'a
str, path
: &'a
str)
537 -> RuleBuilder
<'a
, 'b
> {
538 self.rule(name
, path
, Kind
::Test
)
541 fn doc
<'b
>(&'b
mut self, name
: &'a
str, path
: &'a
str)
542 -> RuleBuilder
<'a
, 'b
> {
543 self.rule(name
, path
, Kind
::Doc
)
546 fn dist
<'b
>(&'b
mut self, name
: &'a
str, path
: &'a
str)
547 -> RuleBuilder
<'a
, 'b
> {
548 self.rule(name
, path
, Kind
::Dist
)
551 fn rule
<'b
>(&'b
mut self,
554 kind
: Kind
) -> RuleBuilder
<'a
, 'b
> {
557 rule
: Rule
::new(name
, path
, kind
),
561 /// Verify the dependency graph defined by all our rules are correct, e.g.
562 /// everything points to a valid something else.
564 for rule
in self.rules
.values() {
565 for dep
in rule
.deps
.iter() {
566 let dep
= dep(&self.sbuild
.name(rule
.name
));
567 if self.rules
.contains_key(&dep
.name
) || dep
.name
.starts_with("default:") {
572 invalid rule dependency graph detected, was a rule added and maybe typo'd?
574 `{}` depends on `{}` which does not exist
576 ", rule
.name
, dep
.name
);
581 pub fn print_help(&self, command
: &str) {
582 let kind
= match command
{
583 "build" => Kind
::Build
,
585 "test" => Kind
::Test
,
586 "dist" => Kind
::Dist
,
589 let rules
= self.rules
.values().filter(|r
| r
.kind
== kind
);
590 let rules
= rules
.filter(|r
| !r
.path
.contains("nowhere"));
591 let mut rules
= rules
.collect
::<Vec
<_
>>();
592 rules
.sort_by_key(|r
| r
.path
);
594 println
!("Available paths:\n");
596 print
!(" ./x.py {} {}", command
, rule
.path
);
602 /// Construct the top-level build steps that we're going to be executing,
603 /// given the subcommand that our build is performing.
604 fn plan(&self) -> Vec
<Step
<'a
>> {
605 let (kind
, paths
) = match self.build
.flags
.cmd
{
606 Subcommand
::Build { ref paths }
=> (Kind
::Build
, &paths
[..]),
607 Subcommand
::Doc { ref paths }
=> (Kind
::Doc
, &paths
[..]),
608 Subcommand
::Test { ref paths, test_args: _ }
=> (Kind
::Test
, &paths
[..]),
609 Subcommand
::Dist { install }
=> {
611 return vec
![self.sbuild
.name("install")]
613 (Kind
::Dist
, &[][..])
616 Subcommand
::Clean
=> panic
!(),
619 self.rules
.values().filter(|rule
| rule
.kind
== kind
).filter(|rule
| {
620 (paths
.len() == 0 && rule
.default) || paths
.iter().any(|path
| {
621 path
.ends_with(rule
.path
)
624 let hosts
= if self.build
.flags
.host
.len() > 0 {
625 &self.build
.flags
.host
627 &self.build
.config
.host
629 let targets
= if self.build
.flags
.target
.len() > 0 {
630 &self.build
.flags
.target
632 &self.build
.config
.target
634 let arr
= if rule
.host {hosts}
else {targets}
;
636 hosts
.iter().flat_map(move |host
| {
637 arr
.iter().map(move |target
| {
638 self.sbuild
.name(rule
.name
).target(target
).host(host
)
644 /// Execute all top-level targets indicated by `steps`.
646 /// This will take the list returned by `plan` and then execute each step
647 /// along with all required dependencies as it goes up the chain.
648 fn run(&self, steps
: &[Step
<'a
>]) {
649 self.build
.verbose("bootstrap top targets:");
650 for step
in steps
.iter() {
651 self.build
.verbose(&format
!("\t{:?}", step
));
654 // Using `steps` as the top-level targets, make a topological ordering
655 // of what we need to do.
656 let mut order
= Vec
::new();
657 let mut added
= HashSet
::new();
658 for step
in steps
.iter().cloned() {
659 self.fill(step
, &mut order
, &mut added
);
662 // Print out what we're doing for debugging
663 self.build
.verbose("bootstrap build plan:");
664 for step
in order
.iter() {
665 self.build
.verbose(&format
!("\t{:?}", step
));
668 // And finally, iterate over everything and execute it.
669 for step
in order
.iter() {
670 self.build
.verbose(&format
!("executing step {:?}", step
));
671 (self.rules
[step
.name
].run
)(step
);
677 order
: &mut Vec
<Step
<'a
>>,
678 added
: &mut HashSet
<Step
<'a
>>) {
679 if !added
.insert(step
.clone()) {
682 for dep
in self.rules
[step
.name
].deps
.iter() {
683 let dep
= dep(&step
);
684 if dep
.name
.starts_with("default:") {
685 let kind
= match &dep
.name
[8..] {
687 "dist" => Kind
::Dist
,
688 kind
=> panic
!("unknown kind: `{}`", kind
),
690 let host
= self.build
.config
.host
.iter().any(|h
| h
== dep
.target
);
691 let rules
= self.rules
.values().filter(|r
| r
.default);
692 for rule
in rules
.filter(|r
| r
.kind
== kind
&& (!r
.host
|| host
)) {
693 self.fill(dep
.name(rule
.name
), order
, added
);
696 self.fill(dep
, order
, added
);