2 use crate::config::{Config, TargetSelection};
5 fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
6 configure_with_args(&[cmd.to_owned()], host, target)
9 fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config {
10 let mut config = Config::parse(cmd);
11 // don't save toolstates
12 config.save_toolstates = None;
13 config.dry_run = true;
15 // Ignore most submodules, since we don't need them for a dry run.
16 // But make sure to check out the `doc` and `rust-analyzer` submodules, since some steps need them
17 // just to know which commands to run.
18 let submodule_build = Build::new(Config {
19 // don't include LLVM, so CI doesn't require ninja/cmake to be installed
20 rust_codegen_backends: vec![],
21 ..Config::parse(&["check".to_owned()])
23 submodule_build.update_submodule(Path::new("src/doc/book"));
24 submodule_build.update_submodule(Path::new("src/tools/rust-analyzer"));
25 config.submodules = Some(false);
27 config.ninja_in_file = false;
28 // try to avoid spurious failures in dist where we create/delete each others file
29 // HACK: rather than pull in `tempdir`, use the one that cargo has conveniently created for us
30 let dir = Path::new(env!("OUT_DIR"))
31 .join("tmp-rustbuild-tests")
32 .join(&thread::current().name().unwrap_or("unknown").replace(":", "-"));
33 t!(fs::create_dir_all(&dir));
35 config.build = TargetSelection::from_user("A");
36 config.hosts = host.iter().map(|s| TargetSelection::from_user(s)).collect();
37 config.targets = target.iter().map(|s| TargetSelection::from_user(s)).collect();
41 fn first<A, B>(v: Vec<(A, B)>) -> Vec<A> {
42 v.into_iter().map(|(a, _)| a).collect::<Vec<_>>()
45 fn run_build(paths: &[PathBuf], config: Config) -> Cache {
46 let kind = config.cmd.kind();
47 let build = Build::new(config);
48 let builder = Builder::new(&build);
49 builder.run_step_descriptions(&Builder::get_step_descriptions(kind), paths);
53 fn check_cli<const N: usize>(paths: [&str; N]) {
55 &paths.map(PathBuf::from),
56 configure_with_args(&paths.map(String::from), &["A"], &["A"]),
62 // make sure multi suite paths are accepted
63 check_cli(["test", "src/test/ui/attr-start.rs", "src/test/ui/attr-shebang.rs"]);
69 // make sure that invalid paths are caught, even when combined with valid paths
70 check_cli(["test", "library/std", "x"]);
74 fn test_intersection() {
75 let set = PathSet::Set(
76 ["library/core", "library/alloc", "library/std"].into_iter().map(TaskPath::parse).collect(),
78 let mut command_paths =
79 vec![Path::new("library/core"), Path::new("library/alloc"), Path::new("library/stdarch")];
80 let subset = set.intersection_removing_matches(&mut command_paths, None);
83 PathSet::Set(["library/core", "library/alloc"].into_iter().map(TaskPath::parse).collect())
85 assert_eq!(command_paths, vec![Path::new("library/stdarch")]);
90 let mut config = configure("test", &["A"], &["A"]);
91 config.exclude = vec![TaskPath::parse("src/tools/tidy")];
92 let cache = run_build(&[], config);
94 // Ensure we have really excluded tidy
95 assert!(!cache.contains::<test::Tidy>());
97 // Ensure other tests are not affected.
98 assert!(cache.contains::<test::RustdocUi>());
102 fn test_exclude_kind() {
103 let path = PathBuf::from("src/tools/cargotest");
104 let exclude = TaskPath::parse("test::src/tools/cargotest");
105 assert_eq!(exclude, TaskPath { kind: Some(Kind::Test), path: path.clone() });
107 let mut config = configure("test", &["A"], &["A"]);
108 // Ensure our test is valid, and `test::Cargotest` would be run without the exclude.
109 assert!(run_build(&[path.clone()], config.clone()).contains::<test::Cargotest>());
110 // Ensure tests for cargotest are skipped.
111 config.exclude = vec![exclude.clone()];
112 assert!(!run_build(&[path.clone()], config).contains::<test::Cargotest>());
114 // Ensure builds for cargotest are not skipped.
115 let mut config = configure("build", &["A"], &["A"]);
116 config.exclude = vec![exclude];
117 assert!(run_build(&[path], config).contains::<tool::CargoTest>());
121 use super::{configure, first, run_build};
122 use crate::builder::*;
124 use pretty_assertions::assert_eq;
128 let mut cache = run_build(&[], configure("build", &["A"], &["A"]));
130 let a = TargetSelection::from_user("A");
132 first(cache.all::<compile::Std>()),
134 compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
135 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
138 assert!(!cache.all::<compile::Assemble>().is_empty());
139 // Make sure rustdoc is only built once.
141 first(cache.all::<tool::Rustdoc>()),
142 // Recall that rustdoc stages are off-by-one
143 // - this is the compiler it's _linked_ to, not built with.
144 &[tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }],
147 first(cache.all::<compile::Rustc>()),
148 &[compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },]
154 let config = Config { stage: 0, ..configure("build", &["A"], &["A"]) };
155 let mut cache = run_build(&[], config);
157 let a = TargetSelection::from_user("A");
159 first(cache.all::<compile::Std>()),
160 &[compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },]
162 assert!(!cache.all::<compile::Assemble>().is_empty());
164 first(cache.all::<tool::Rustdoc>()),
165 // This is the beta rustdoc.
166 // Add an assert here to make sure this is the only rustdoc built.
167 &[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } }],
169 assert!(cache.all::<compile::Rustc>().is_empty());
173 fn build_cross_compile() {
174 let config = Config { stage: 1, ..configure("build", &["A", "B"], &["A", "B"]) };
175 let mut cache = run_build(&[], config);
177 let a = TargetSelection::from_user("A");
178 let b = TargetSelection::from_user("B");
180 // Ideally, this build wouldn't actually have `target: a`
181 // rustdoc/rustcc/std here (the user only requested a host=B build, so
182 // there's not really a need for us to build for target A in this case
183 // (since we're producing stage 1 libraries/binaries). But currently
184 // rustbuild is just a bit buggy here; this should be fixed though.
186 first(cache.all::<compile::Std>()),
188 compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
189 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
190 compile::Std { compiler: Compiler { host: a, stage: 0 }, target: b },
191 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
195 first(cache.all::<compile::Assemble>()),
197 compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
198 compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
199 compile::Assemble { target_compiler: Compiler { host: b, stage: 1 } },
203 first(cache.all::<tool::Rustdoc>()),
205 tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } },
206 tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } },
210 first(cache.all::<compile::Rustc>()),
212 compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
213 compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: b },
220 let mut config = configure("doc", &["A"], &["A"]);
221 config.compiler_docs = true;
222 config.cmd = Subcommand::Doc { paths: Vec::new(), open: false };
223 let mut cache = run_build(&[], config);
224 let a = TargetSelection::from_user("A");
226 // error_index_generator uses stage 0 to share rustdoc artifacts with the
228 assert_eq!(first(cache.all::<doc::ErrorIndex>()), &[doc::ErrorIndex { target: a },]);
230 first(cache.all::<tool::ErrorIndex>()),
231 &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 0 } }]
233 // docs should be built with the beta compiler, not with the stage0 artifacts.
234 // recall that rustdoc is off-by-one: `stage` is the compiler rustdoc is _linked_ to,
235 // not the one it was built by.
237 first(cache.all::<tool::Rustdoc>()),
238 &[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } },]
244 use super::{first, run_build, Config};
245 use crate::builder::*;
246 use pretty_assertions::assert_eq;
248 fn configure(host: &[&str], target: &[&str]) -> Config {
249 Config { stage: 2, ..super::configure("dist", host, target) }
254 let mut cache = run_build(&[], configure(&["A"], &["A"]));
256 let a = TargetSelection::from_user("A");
258 assert_eq!(first(cache.all::<dist::Docs>()), &[dist::Docs { host: a },]);
259 assert_eq!(first(cache.all::<dist::Mingw>()), &[dist::Mingw { host: a },]);
261 first(cache.all::<dist::Rustc>()),
262 &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },]
265 first(cache.all::<dist::Std>()),
266 &[dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },]
268 assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
269 // Make sure rustdoc is only built once.
271 first(cache.all::<tool::Rustdoc>()),
272 &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },]
277 fn dist_with_targets() {
278 let mut cache = run_build(&[], configure(&["A"], &["A", "B"]));
280 let a = TargetSelection::from_user("A");
281 let b = TargetSelection::from_user("B");
284 first(cache.all::<dist::Docs>()),
285 &[dist::Docs { host: a }, dist::Docs { host: b },]
288 first(cache.all::<dist::Mingw>()),
289 &[dist::Mingw { host: a }, dist::Mingw { host: b },]
292 first(cache.all::<dist::Rustc>()),
293 &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },]
296 first(cache.all::<dist::Std>()),
298 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
299 dist::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
302 assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
306 fn dist_with_hosts() {
307 let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B"]));
309 let a = TargetSelection::from_user("A");
310 let b = TargetSelection::from_user("B");
313 first(cache.all::<dist::Docs>()),
314 &[dist::Docs { host: a }, dist::Docs { host: b },]
317 first(cache.all::<dist::Mingw>()),
318 &[dist::Mingw { host: a }, dist::Mingw { host: b },]
321 first(cache.all::<dist::Rustc>()),
323 dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
324 dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
328 first(cache.all::<dist::Std>()),
330 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
331 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
335 first(cache.all::<compile::Std>()),
337 compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
338 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
339 compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
340 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
341 compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
344 assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
348 fn dist_only_cross_host() {
349 let a = TargetSelection::from_user("A");
350 let b = TargetSelection::from_user("B");
351 let mut config = configure(&["A", "B"], &["A", "B"]);
353 config.extended = true;
354 config.hosts = vec![b];
355 let mut cache = run_build(&[], config);
358 first(cache.all::<dist::Rustc>()),
359 &[dist::Rustc { compiler: Compiler { host: b, stage: 2 } },]
362 first(cache.all::<compile::Rustc>()),
364 compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
365 compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
371 fn dist_with_targets_and_hosts() {
372 let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B", "C"]));
374 let a = TargetSelection::from_user("A");
375 let b = TargetSelection::from_user("B");
376 let c = TargetSelection::from_user("C");
379 first(cache.all::<dist::Docs>()),
380 &[dist::Docs { host: a }, dist::Docs { host: b }, dist::Docs { host: c },]
383 first(cache.all::<dist::Mingw>()),
384 &[dist::Mingw { host: a }, dist::Mingw { host: b }, dist::Mingw { host: c },]
387 first(cache.all::<dist::Rustc>()),
389 dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
390 dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
394 first(cache.all::<dist::Std>()),
396 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
397 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
398 dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
401 assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
405 fn dist_with_empty_host() {
406 let config = configure(&[], &["C"]);
407 let mut cache = run_build(&[], config);
409 let a = TargetSelection::from_user("A");
410 let c = TargetSelection::from_user("C");
412 assert_eq!(first(cache.all::<dist::Docs>()), &[dist::Docs { host: c },]);
413 assert_eq!(first(cache.all::<dist::Mingw>()), &[dist::Mingw { host: c },]);
415 first(cache.all::<dist::Std>()),
416 &[dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },]
421 fn dist_with_same_targets_and_hosts() {
422 let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B"]));
424 let a = TargetSelection::from_user("A");
425 let b = TargetSelection::from_user("B");
428 first(cache.all::<dist::Docs>()),
429 &[dist::Docs { host: a }, dist::Docs { host: b },]
432 first(cache.all::<dist::Mingw>()),
433 &[dist::Mingw { host: a }, dist::Mingw { host: b },]
436 first(cache.all::<dist::Rustc>()),
438 dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
439 dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
443 first(cache.all::<dist::Std>()),
445 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
446 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
449 assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
451 first(cache.all::<compile::Std>()),
453 compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
454 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
455 compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
456 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
457 compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
461 first(cache.all::<compile::Assemble>()),
463 compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
464 compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
465 compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } },
466 compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } },
473 let build = Build::new(configure(&["A", "B"], &["A", "B", "C"]));
474 let mut builder = Builder::new(&build);
475 builder.run_step_descriptions(
476 &Builder::get_step_descriptions(Kind::Build),
477 &["compiler/rustc".into(), "library/std".into()],
480 let a = TargetSelection::from_user("A");
481 let b = TargetSelection::from_user("B");
482 let c = TargetSelection::from_user("C");
485 first(builder.cache.all::<compile::Std>()),
487 compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
488 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
489 compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
490 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
491 compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
492 compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
495 assert!(!builder.cache.all::<compile::Assemble>().is_empty());
497 first(builder.cache.all::<compile::Rustc>()),
499 compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
500 compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a },
501 compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: a },
502 compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
503 compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: b },
509 fn build_with_empty_host() {
510 let config = configure(&[], &["C"]);
511 let build = Build::new(config);
512 let mut builder = Builder::new(&build);
513 builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
515 let a = TargetSelection::from_user("A");
516 let c = TargetSelection::from_user("C");
519 first(builder.cache.all::<compile::Std>()),
521 compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
522 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
523 compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
527 first(builder.cache.all::<compile::Assemble>()),
529 compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
530 compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
531 compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } },
535 first(builder.cache.all::<compile::Rustc>()),
537 compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
538 compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a },
544 fn test_with_no_doc_stage0() {
545 let mut config = configure(&["A"], &["A"]);
547 config.cmd = Subcommand::Test {
548 paths: vec!["library/std".into()],
553 doc_tests: DocTests::No,
557 rustfix_coverage: false,
562 let build = Build::new(config);
563 let mut builder = Builder::new(&build);
565 let host = TargetSelection::from_user("A");
567 builder.run_step_descriptions(
568 &[StepDescription::from::<test::Crate>(Kind::Test)],
569 &["library/std".into()],
572 // Ensure we don't build any compiler artifacts.
573 assert!(!builder.cache.contains::<compile::Rustc>());
575 first(builder.cache.all::<test::Crate>()),
577 compiler: Compiler { host, stage: 0 },
580 test_kind: test::TestKind::Test,
581 crates: vec![INTERNER.intern_str("std")],
588 let mut config = configure(&["A"], &["A"]);
589 config.compiler_docs = true;
590 config.cmd = Subcommand::Doc { paths: Vec::new(), open: false };
591 let build = Build::new(config);
592 let mut builder = Builder::new(&build);
593 builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]);
594 let a = TargetSelection::from_user("A");
596 // error_index_generator uses stage 1 to share rustdoc artifacts with the
599 first(builder.cache.all::<doc::ErrorIndex>()),
600 &[doc::ErrorIndex { target: a },]
603 first(builder.cache.all::<tool::ErrorIndex>()),
604 &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }]
606 // This is actually stage 1, but Rustdoc::run swaps out the compiler with
607 // stage minus 1 if --stage is not 0. Very confusing!
609 first(builder.cache.all::<tool::Rustdoc>()),
610 &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },]
616 // Behavior of `x.py test` doing various documentation tests.
617 let mut config = configure(&["A"], &["A"]);
618 config.cmd = Subcommand::Test {
624 doc_tests: DocTests::Yes,
628 rustfix_coverage: false,
632 // Make sure rustfmt binary not being found isn't an error.
633 config.channel = "beta".to_string();
634 let build = Build::new(config);
635 let mut builder = Builder::new(&build);
637 builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]);
638 let a = TargetSelection::from_user("A");
640 // error_index_generator uses stage 1 to share rustdoc artifacts with the
643 first(builder.cache.all::<doc::ErrorIndex>()),
644 &[doc::ErrorIndex { target: a },]
647 first(builder.cache.all::<tool::ErrorIndex>()),
648 &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }]
650 // Unfortunately rustdoc is built twice. Once from stage1 for compiletest
651 // (and other things), and once from stage0 for std crates. Ideally it
652 // would only be built once. If someone wants to fix this, it might be
653 // worth investigating if it would be possible to test std from stage1.
654 // Note that the stages here are +1 than what they actually are because
655 // Rustdoc::run swaps out the compiler with stage minus 1 if --stage is
658 // The stage 0 copy is the one downloaded for bootstrapping. It is
659 // (currently) needed to run "cargo test" on the linkchecker, and
660 // should be relatively "free".
662 first(builder.cache.all::<tool::Rustdoc>()),
664 tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } },
665 tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } },
666 tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },