Change Step to be invoked with a path when in default mode.

Previously, a Step would be able to tell on its own when it was invoked
"by-default" (that is, `./x.py test` was called instead of `./x.py test
some/path`). This commit replaces that functionality, invoking each Step
with each of the paths it has specified as "should be invoked by."

For example, if a step calls `path("src/tools/cargo")` and
`path("src/doc/cargo")` then it's make_run will be called twice, with
"src/tools/cargo" and "src/doc/cargo." This makes it so that default
handling logic is in builder, instead of spread across various Steps.

However, this meant that some Step specifications needed to be updated,
since for example `rustdoc` can be built by `./x.py build
src/librustdoc` or `./x.py build src/tools/rustdoc`. A `PathSet`
abstraction is added that handles this: now, each Step can not only list
`path(...)` but also `paths(&[a, b, ...])` which will make it so that we
don't invoke it with each of the individual paths, instead invoking it
with the first path in the list (though this shouldn't be depended on).

Future work likely consists of implementing a better/easier way for a
given Step to work with "any" crate in-tree, especially those that want
to run tests, build, or check crates in the std, test, or rustc crate
trees. Currently this is rather painful to do as most of the logic is
duplicated across should_run and make_run. It seems likely this can be
abstracted away into builder somehow.
This commit is contained in:
Mark Simulacrum 2018-02-11 09:51:58 -07:00
parent 55c36e3744
commit f104b12059
7 changed files with 423 additions and 320 deletions

View file

@ -95,7 +95,7 @@ pub struct RunConfig<'a> {
pub builder: &'a Builder<'a>,
pub host: Interned<String>,
pub target: Interned<String>,
pub path: Option<&'a Path>,
pub path: &'a Path,
}
struct StepDescription {
@ -105,6 +105,28 @@ struct StepDescription {
only_build: bool,
should_run: fn(ShouldRun) -> ShouldRun,
make_run: fn(RunConfig),
name: &'static str,
}
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
struct PathSet {
set: BTreeSet<PathBuf>,
}
impl PathSet {
fn one<P: Into<PathBuf>>(path: P) -> PathSet {
let mut set = BTreeSet::new();
set.insert(path.into());
PathSet { set }
}
fn has(&self, needle: &Path) -> bool {
self.set.iter().any(|p| p.ends_with(needle))
}
fn path(&self) -> &Path {
self.set.iter().next().unwrap()
}
}
impl StepDescription {
@ -116,30 +138,17 @@ impl StepDescription {
only_build: S::ONLY_BUILD,
should_run: S::should_run,
make_run: S::make_run,
name: unsafe { ::std::intrinsics::type_name::<S>() },
}
}
fn maybe_run(&self, builder: &Builder, should_run: &ShouldRun, path: Option<&Path>) {
if let Some(path) = path {
if builder.config.exclude.iter().any(|e| e == path) {
eprintln!("Skipping {:?} because this path is excluded", path);
return;
} else if !builder.config.exclude.is_empty() {
eprintln!("{:?} not skipped -- not in {:?}", path, builder.config.exclude);
}
} else {
if !should_run.paths.is_empty() {
if should_run.paths.iter().all(|p| builder.config.exclude.contains(&p)) {
eprintln!("Skipping because all of its paths ({:?}) are excluded",
should_run.paths);
return;
} else if should_run.paths.len() > 1 {
for path in &should_run.paths {
self.maybe_run(builder, should_run, Some(path));
}
return;
}
}
fn maybe_run(&self, builder: &Builder, pathset: &PathSet) {
if builder.config.exclude.iter().any(|e| pathset.has(e)) {
eprintln!("Skipping {:?} because it is excluded", pathset);
return;
} else if !builder.config.exclude.is_empty() {
eprintln!("{:?} not skipped for {:?} -- not in {:?}", pathset,
self.name, builder.config.exclude);
}
let build = builder.build;
let hosts = if self.only_build_targets || self.only_build {
@ -165,7 +174,7 @@ impl StepDescription {
for target in targets {
let run = RunConfig {
builder,
path,
path: pathset.path(),
host: *host,
target: *target,
};
@ -178,19 +187,28 @@ impl StepDescription {
let should_runs = v.iter().map(|desc| {
(desc.should_run)(ShouldRun::new(builder))
}).collect::<Vec<_>>();
// sanity checks on rules
for (desc, should_run) in v.iter().zip(&should_runs) {
assert!(!should_run.paths.is_empty(),
"{:?} should have at least one pathset", desc.name);
}
if paths.is_empty() {
for (desc, should_run) in v.iter().zip(should_runs) {
if desc.default && should_run.is_really_default {
desc.maybe_run(builder, &should_run, None);
for pathset in &should_run.paths {
desc.maybe_run(builder, pathset);
}
}
}
} else {
for path in paths {
let mut attempted_run = false;
for (desc, should_run) in v.iter().zip(&should_runs) {
if should_run.run(path) {
if let Some(pathset) = should_run.pathset_for_path(path) {
attempted_run = true;
desc.maybe_run(builder, &should_run, Some(path));
desc.maybe_run(builder, pathset);
}
}
@ -206,7 +224,7 @@ impl StepDescription {
pub struct ShouldRun<'a> {
pub builder: &'a Builder<'a>,
// use a BTreeSet to maintain sort order
paths: BTreeSet<PathBuf>,
paths: BTreeSet<PathSet>,
// If this is a default rule, this is an additional constraint placed on
// it's run. Generally something like compiler docs being enabled.
@ -227,15 +245,35 @@ impl<'a> ShouldRun<'a> {
self
}
// Unlike `krate` this will create just one pathset. As such, it probably shouldn't actually
// ever be used, but as we transition to having all rules properly handle passing krate(...) by
// actually doing something different for every crate passed.
pub fn all_krates(mut self, name: &str) -> Self {
let mut set = BTreeSet::new();
for krate in self.builder.in_tree_crates(name) {
set.insert(PathBuf::from(&krate.path));
}
self.paths.insert(PathSet { set });
self
}
pub fn krate(mut self, name: &str) -> Self {
for (_, krate_path) in self.builder.crates(name) {
self.paths.insert(t!(env::current_dir()).join(krate_path));
for krate in self.builder.in_tree_crates(name) {
self.paths.insert(PathSet::one(&krate.path));
}
self
}
pub fn path(mut self, path: &str) -> Self {
self.paths.insert(t!(env::current_dir()).join(path));
// single, non-aliased path
pub fn path(self, path: &str) -> Self {
self.paths(&[path])
}
// multiple aliases for the same job
pub fn paths(mut self, paths: &[&str]) -> Self {
self.paths.insert(PathSet {
set: paths.iter().map(PathBuf::from).collect(),
});
self
}
@ -244,8 +282,8 @@ impl<'a> ShouldRun<'a> {
self
}
fn run(&self, path: &Path) -> bool {
self.paths.iter().any(|p| path.ends_with(p))
fn pathset_for_path(&self, path: &Path) -> Option<&PathSet> {
self.paths.iter().find(|pathset| pathset.has(path))
}
}
@ -275,11 +313,16 @@ impl<'a> Builder<'a> {
tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy,
native::Llvm, tool::Rustfmt, tool::Miri),
Kind::Check => describe!(check::Std, check::Test, check::Rustc),
Kind::Test => describe!(test::Tidy, test::Bootstrap, test::DefaultCompiletest,
test::HostCompiletest, test::Crate, test::CrateLibrustc, test::Rustdoc,
test::Linkcheck, test::Cargotest, test::Cargo, test::Rls, test::Docs,
test::ErrorIndex, test::Distcheck, test::Rustfmt, test::Miri, test::Clippy,
test::RustdocJS, test::RustdocTheme),
Kind::Test => describe!(test::Tidy, test::Bootstrap, test::Ui, test::RunPass,
test::CompileFail, test::ParseFail, test::RunFail, test::RunPassValgrind,
test::MirOpt, test::Codegen, test::CodegenUnits, test::Incremental, test::Debuginfo,
test::UiFullDeps, test::RunPassFullDeps, test::RunFailFullDeps,
test::CompileFailFullDeps, test::IncrementalFullDeps, test::Rustdoc, test::Pretty,
test::RunPassPretty, test::RunFailPretty, test::RunPassValgrindPretty,
test::RunPassFullDepsPretty, test::RunFailFullDepsPretty, test::RunMake,
test::Crate, test::CrateLibrustc, test::Rustdoc, test::Linkcheck, test::Cargotest,
test::Cargo, test::Rls, test::Docs, test::ErrorIndex, test::Distcheck,
test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme),
Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon,
@ -317,8 +360,10 @@ impl<'a> Builder<'a> {
should_run = (desc.should_run)(should_run);
}
let mut help = String::from("Available paths:\n");
for path in should_run.paths {
help.push_str(format!(" ./x.py {} {}\n", subcommand, path.display()).as_str());
for pathset in should_run.paths {
for path in pathset.set {
help.push_str(format!(" ./x.py {} {}\n", subcommand, path.display()).as_str());
}
}
Some(help)
}

View file

@ -26,7 +26,7 @@ impl Step for Std {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/libstd").krate("std")
run.all_krates("std")
}
fn make_run(run: RunConfig) {
@ -67,7 +67,7 @@ impl Step for Rustc {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/librustc").krate("rustc-main")
run.all_krates("rustc-main")
}
fn make_run(run: RunConfig) {
@ -114,7 +114,7 @@ impl Step for Test {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/libtest").krate("test")
run.all_krates("test")
}
fn make_run(run: RunConfig) {

View file

@ -48,7 +48,7 @@ impl Step for Std {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/libstd").krate("std")
run.all_krates("std")
}
fn make_run(run: RunConfig) {
@ -320,7 +320,7 @@ impl Step for Test {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/libtest").krate("test")
run.all_krates("test")
}
fn make_run(run: RunConfig) {
@ -436,7 +436,7 @@ impl Step for Rustc {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/librustc").krate("rustc-main")
run.all_krates("rustc-main")
}
fn make_run(run: RunConfig) {
@ -593,7 +593,7 @@ impl Step for CodegenBackend {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/librustc_trans")
run.all_krates("rustc_trans")
}
fn make_run(run: RunConfig) {
@ -828,7 +828,7 @@ impl Step for Assemble {
type Output = Compiler;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/rustc")
run.all_krates("rustc-main")
}
/// Prepare a new compiler from the artifacts in `stage`

View file

@ -429,7 +429,7 @@ impl Step for Std {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.krate("std").default_condition(builder.build.config.docs)
run.all_krates("std").default_condition(builder.build.config.docs)
}
fn make_run(run: RunConfig) {

View file

@ -113,9 +113,8 @@
//! More documentation can be found in each respective module below, and you can
//! also check out the `src/bootstrap/README.md` file for more information.
#![deny(warnings)]
#![allow(stable_features)]
#![feature(associated_consts)]
//#![deny(warnings)]
#![feature(core_intrinsics)]
#[macro_use]
extern crate build_helper;
@ -267,6 +266,18 @@ struct Crate {
bench_step: String,
}
impl Crate {
fn is_local(&self, build: &Build) -> bool {
self.path.starts_with(&build.config.src) &&
!self.path.to_string_lossy().ends_with("_shim")
}
fn local_path(&self, build: &Build) -> PathBuf {
assert!(self.is_local(build));
self.path.strip_prefix(&build.config.src).unwrap().into()
}
}
/// The various "modes" of invoking Cargo.
///
/// These entries currently correspond to the various output directories of the
@ -949,22 +960,18 @@ impl Build {
}
}
/// Get a list of crates from a root crate.
///
/// Returns Vec<(crate, path to crate, is_root_crate)>
fn crates(&self, root: &str) -> Vec<(Interned<String>, &Path)> {
let interned = INTERNER.intern_string(root.to_owned());
fn in_tree_crates(&self, root: &str) -> Vec<&Crate> {
let mut ret = Vec::new();
let mut list = vec![interned];
let mut list = vec![INTERNER.intern_str(root)];
let mut visited = HashSet::new();
while let Some(krate) = list.pop() {
let krate = &self.crates[&krate];
// If we can't strip prefix, then out-of-tree path
let path = krate.path.strip_prefix(&self.src).unwrap_or(&krate.path);
ret.push((krate.name, path));
for dep in &krate.deps {
if visited.insert(dep) && dep != "build_helper" {
list.push(*dep);
if krate.is_local(self) {
ret.push(krate);
for dep in &krate.deps {
if visited.insert(dep) && dep != "build_helper" {
list.push(*dep);
}
}
}
}

View file

@ -51,9 +51,7 @@ impl Step for Llvm {
}
fn make_run(run: RunConfig) {
let emscripten = run.path.map(|p| {
p.ends_with("llvm-emscripten")
}).unwrap_or(false);
let emscripten = run.path.ends_with("llvm-emscripten");
run.builder.ensure(Llvm {
target: run.target,
emscripten,

View file

@ -13,7 +13,6 @@
//! This file implements the various regression test suites that we execute on
//! our CI.
use std::collections::HashSet;
use std::env;
use std::ffi::OsString;
use std::iter;
@ -26,6 +25,7 @@ use std::io::Read;
use build_helper::{self, output};
use builder::{Kind, RunConfig, ShouldRun, Builder, Compiler, Step};
use Crate as CargoCrate;
use cache::{INTERNER, Interned};
use compile;
use dist;
@ -550,180 +550,213 @@ fn testdir(build: &Build, host: Interned<String>) -> PathBuf {
build.out.join(host).join("test")
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
struct Test {
path: &'static str,
mode: &'static str,
suite: &'static str,
macro_rules! default_test {
($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => {
test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: false });
}
}
static DEFAULT_COMPILETESTS: &[Test] = &[
Test { path: "src/test/ui", mode: "ui", suite: "ui" },
Test { path: "src/test/run-pass", mode: "run-pass", suite: "run-pass" },
Test { path: "src/test/compile-fail", mode: "compile-fail", suite: "compile-fail" },
Test { path: "src/test/parse-fail", mode: "parse-fail", suite: "parse-fail" },
Test { path: "src/test/run-fail", mode: "run-fail", suite: "run-fail" },
Test {
path: "src/test/run-pass-valgrind",
mode: "run-pass-valgrind",
suite: "run-pass-valgrind"
},
Test { path: "src/test/mir-opt", mode: "mir-opt", suite: "mir-opt" },
Test { path: "src/test/codegen", mode: "codegen", suite: "codegen" },
Test { path: "src/test/codegen-units", mode: "codegen-units", suite: "codegen-units" },
Test { path: "src/test/incremental", mode: "incremental", suite: "incremental" },
macro_rules! host_test {
($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => {
test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: true });
}
}
macro_rules! test {
($name:ident {
path: $path:expr,
mode: $mode:expr,
suite: $suite:expr,
default: $default:expr,
host: $host:expr
}) => {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct $name {
pub compiler: Compiler,
pub target: Interned<String>,
}
impl Step for $name {
type Output = ();
const DEFAULT: bool = $default;
const ONLY_HOSTS: bool = $host;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path($path)
}
fn make_run(run: RunConfig) {
let compiler = run.builder.compiler(run.builder.top_stage, run.host);
run.builder.ensure($name {
compiler,
target: run.target,
});
}
fn run(self, builder: &Builder) {
builder.ensure(Compiletest {
compiler: self.compiler,
target: self.target,
mode: $mode,
suite: $suite,
})
}
}
}
}
default_test!(Ui {
path: "src/test/ui",
mode: "ui",
suite: "ui"
});
default_test!(RunPass {
path: "src/test/run-pass",
mode: "run-pass",
suite: "run-pass"
});
default_test!(CompileFail {
path: "src/test/compile-fail",
mode: "compile-fail",
suite: "compile-fail"
});
default_test!(ParseFail {
path: "src/test/parse-fail",
mode: "parse-fail",
suite: "parse-fail"
});
default_test!(RunFail {
path: "src/test/run-fail",
mode: "run-fail",
suite: "run-fail"
});
default_test!(RunPassValgrind {
path: "src/test/run-pass-valgrind",
mode: "run-pass-valgrind",
suite: "run-pass-valgrind"
});
default_test!(MirOpt {
path: "src/test/mir-opt",
mode: "mir-opt",
suite: "mir-opt"
});
default_test!(Codegen {
path: "src/test/codegen",
mode: "codegen",
suite: "codegen"
});
default_test!(CodegenUnits {
path: "src/test/codegen-units",
mode: "codegen-units",
suite: "codegen-units"
});
default_test!(Incremental {
path: "src/test/incremental",
mode: "incremental",
suite: "incremental"
});
default_test!(Debuginfo {
path: "src/test/debuginfo",
// What this runs varies depending on the native platform being apple
Test { path: "src/test/debuginfo", mode: "debuginfo-XXX", suite: "debuginfo" },
];
mode: "debuginfo-XXX",
suite: "debuginfo"
});
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct DefaultCompiletest {
compiler: Compiler,
target: Interned<String>,
mode: &'static str,
suite: &'static str,
}
host_test!(UiFullDeps {
path: "src/test/ui-fulldeps",
mode: "ui",
suite: "ui-fulldeps"
});
impl Step for DefaultCompiletest {
type Output = ();
const DEFAULT: bool = true;
host_test!(RunPassFullDeps {
path: "src/test/run-pass-fulldeps",
mode: "run-pass",
suite: "run-pass-fulldeps"
});
fn should_run(mut run: ShouldRun) -> ShouldRun {
for test in DEFAULT_COMPILETESTS {
run = run.path(test.path);
}
run
}
host_test!(RunFailFullDeps {
path: "src/test/run-fail-fulldeps",
mode: "run-fail",
suite: "run-fail-fulldeps"
});
fn make_run(run: RunConfig) {
let compiler = run.builder.compiler(run.builder.top_stage, run.host);
host_test!(CompileFailFullDeps {
path: "src/test/compile-fail-fulldeps",
mode: "compile-fail",
suite: "compile-fail-fulldeps"
});
let test = run.path.map(|path| {
DEFAULT_COMPILETESTS.iter().find(|&&test| {
path.ends_with(test.path)
}).unwrap_or_else(|| {
panic!("make_run in compile test to receive test path, received {:?}", path);
})
});
host_test!(IncrementalFullDeps {
path: "src/test/incremental-fulldeps",
mode: "incremental",
suite: "incremental-fulldeps"
});
if let Some(test) = test {
run.builder.ensure(DefaultCompiletest {
compiler,
target: run.target,
mode: test.mode,
suite: test.suite,
});
} else {
for test in DEFAULT_COMPILETESTS {
run.builder.ensure(DefaultCompiletest {
compiler,
target: run.target,
mode: test.mode,
suite: test.suite
});
}
}
}
host_test!(Rustdoc {
path: "src/test/rustdoc",
mode: "rustdoc",
suite: "rustdoc"
});
fn run(self, builder: &Builder) {
builder.ensure(Compiletest {
compiler: self.compiler,
target: self.target,
mode: self.mode,
suite: self.suite,
})
}
}
test!(Pretty {
path: "src/test/pretty",
mode: "pretty",
suite: "pretty",
default: false,
host: true
});
test!(RunPassPretty {
path: "src/test/run-pass/pretty",
mode: "pretty",
suite: "run-pass",
default: false,
host: true
});
test!(RunFailPretty {
path: "src/test/run-fail/pretty",
mode: "pretty",
suite: "run-fail",
default: false,
host: true
});
test!(RunPassValgrindPretty {
path: "src/test/run-pass-valgrind/pretty",
mode: "pretty",
suite: "run-pass-valgrind",
default: false,
host: true
});
test!(RunPassFullDepsPretty {
path: "src/test/run-pass-fulldeps/pretty",
mode: "pretty",
suite: "run-pass-fulldeps",
default: false,
host: true
});
test!(RunFailFullDepsPretty {
path: "src/test/run-fail-fulldeps/pretty",
mode: "pretty",
suite: "run-fail-fulldeps",
default: false,
host: true
});
// Also default, but host-only.
static HOST_COMPILETESTS: &[Test] = &[
Test { path: "src/test/ui-fulldeps", mode: "ui", suite: "ui-fulldeps" },
Test { path: "src/test/run-pass-fulldeps", mode: "run-pass", suite: "run-pass-fulldeps" },
Test { path: "src/test/run-fail-fulldeps", mode: "run-fail", suite: "run-fail-fulldeps" },
Test {
path: "src/test/compile-fail-fulldeps",
mode: "compile-fail",
suite: "compile-fail-fulldeps",
},
Test {
path: "src/test/incremental-fulldeps",
mode: "incremental",
suite: "incremental-fulldeps",
},
Test { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" },
Test { path: "src/test/pretty", mode: "pretty", suite: "pretty" },
Test { path: "src/test/run-pass/pretty", mode: "pretty", suite: "run-pass" },
Test { path: "src/test/run-fail/pretty", mode: "pretty", suite: "run-fail" },
Test { path: "src/test/run-pass-valgrind/pretty", mode: "pretty", suite: "run-pass-valgrind" },
Test { path: "src/test/run-pass-fulldeps/pretty", mode: "pretty", suite: "run-pass-fulldeps" },
Test { path: "src/test/run-fail-fulldeps/pretty", mode: "pretty", suite: "run-fail-fulldeps" },
Test { path: "src/test/run-make", mode: "run-make", suite: "run-make" },
];
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct HostCompiletest {
compiler: Compiler,
target: Interned<String>,
mode: &'static str,
suite: &'static str,
}
impl Step for HostCompiletest {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(mut run: ShouldRun) -> ShouldRun {
for test in HOST_COMPILETESTS {
run = run.path(test.path);
}
run
}
fn make_run(run: RunConfig) {
let compiler = run.builder.compiler(run.builder.top_stage, run.host);
let test = run.path.map(|path| {
HOST_COMPILETESTS.iter().find(|&&test| {
path.ends_with(test.path)
}).unwrap_or_else(|| {
panic!("make_run in compile test to receive test path, received {:?}", path);
})
});
if let Some(test) = test {
run.builder.ensure(HostCompiletest {
compiler,
target: run.target,
mode: test.mode,
suite: test.suite,
});
} else {
for test in HOST_COMPILETESTS {
if test.mode == "pretty" {
continue;
}
run.builder.ensure(HostCompiletest {
compiler,
target: run.target,
mode: test.mode,
suite: test.suite
});
}
}
}
fn run(self, builder: &Builder) {
builder.ensure(Compiletest {
compiler: self.compiler,
target: self.target,
mode: self.mode,
suite: self.suite,
})
}
}
host_test!(RunMake {
path: "src/test/run-make",
mode: "run-make",
suite: "run-make"
});
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
struct Compiletest {
@ -902,7 +935,7 @@ impl Step for Compiletest {
}
}
if suite == "run-make" && !build.config.llvm_enabled {
println!("Ignoring run-make test suite as they generally don't work without LLVM");
println!("Ignoring run-make test suite as they generally dont work without LLVM");
return;
}
@ -1099,7 +1132,7 @@ pub struct CrateLibrustc {
compiler: Compiler,
target: Interned<String>,
test_kind: TestKind,
krate: Option<Interned<String>>,
krate: Interned<String>,
}
impl Step for CrateLibrustc {
@ -1115,35 +1148,26 @@ impl Step for CrateLibrustc {
let builder = run.builder;
let compiler = builder.compiler(builder.top_stage, run.host);
let make = |name: Option<Interned<String>>| {
let test_kind = if builder.kind == Kind::Test {
TestKind::Test
} else if builder.kind == Kind::Bench {
TestKind::Bench
} else {
panic!("unexpected builder.kind in crate: {:?}", builder.kind);
};
for krate in builder.in_tree_crates("rustc-main") {
if run.path.ends_with(&krate.path) {
let test_kind = if builder.kind == Kind::Test {
TestKind::Test
} else if builder.kind == Kind::Bench {
TestKind::Bench
} else {
panic!("unexpected builder.kind in crate: {:?}", builder.kind);
};
builder.ensure(CrateLibrustc {
compiler,
target: run.target,
test_kind,
krate: name,
});
};
if let Some(path) = run.path {
for (name, krate_path) in builder.crates("rustc-main") {
if path.ends_with(krate_path) {
make(Some(name));
}
builder.ensure(CrateLibrustc {
compiler,
target: run.target,
test_kind,
krate: krate.name,
});
}
} else {
make(None);
}
}
fn run(self, builder: &Builder) {
builder.ensure(Crate {
compiler: self.compiler,
@ -1156,27 +1180,95 @@ impl Step for CrateLibrustc {
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Crate {
pub struct CrateNotDefault {
compiler: Compiler,
target: Interned<String>,
mode: Mode,
test_kind: TestKind,
krate: Option<Interned<String>>,
krate: &'static str,
}
impl Step for Crate {
impl Step for CrateNotDefault {
type Output = ();
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.krate("std").krate("test")
run.path("src/liballoc_jemalloc")
.path("src/librustc_asan")
.path("src/librustc_lsan")
.path("src/librustc_msan")
.path("src/librustc_tsan")
}
fn make_run(run: RunConfig) {
let builder = run.builder;
let compiler = builder.compiler(builder.top_stage, run.host);
let make = |mode: Mode, name: Option<Interned<String>>| {
let test_kind = if builder.kind == Kind::Test {
TestKind::Test
} else if builder.kind == Kind::Bench {
TestKind::Bench
} else {
panic!("unexpected builder.kind in crate: {:?}", builder.kind);
};
builder.ensure(CrateNotDefault {
compiler,
target: run.target,
test_kind,
krate: match run.path {
_ if run.path.ends_with("src/liballoc_jemalloc") => "alloc_jemalloc",
_ if run.path.ends_with("src/librustc_asan") => "rustc_asan",
_ if run.path.ends_with("src/librustc_lsan") => "rustc_lsan",
_ if run.path.ends_with("src/librustc_msan") => "rustc_msan",
_ if run.path.ends_with("src/librustc_tsan") => "rustc_tsan",
_ => panic!("unexpected path {:?}", run.path),
},
});
}
fn run(self, builder: &Builder) {
builder.ensure(Crate {
compiler: self.compiler,
target: self.target,
mode: Mode::Libstd,
test_kind: self.test_kind,
krate: INTERNER.intern_str(self.krate),
});
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Crate {
compiler: Compiler,
target: Interned<String>,
mode: Mode,
test_kind: TestKind,
krate: Interned<String>,
}
impl Step for Crate {
type Output = ();
const DEFAULT: bool = true;
fn should_run(mut run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run = run.krate("test");
for krate in run.builder.in_tree_crates("std") {
if krate.is_local(&run.builder) &&
!krate.name.contains("jemalloc") &&
!(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) &&
krate.name != "dlmalloc" {
run = run.path(krate.local_path(&builder).to_str().unwrap());
}
}
run
}
fn make_run(run: RunConfig) {
let builder = run.builder;
let compiler = builder.compiler(builder.top_stage, run.host);
let make = |mode: Mode, krate: &CargoCrate| {
let test_kind = if builder.kind == Kind::Test {
TestKind::Test
} else if builder.kind == Kind::Bench {
@ -1190,29 +1282,24 @@ impl Step for Crate {
target: run.target,
mode,
test_kind,
krate: name,
krate: krate.name,
});
};
if let Some(path) = run.path {
for (name, krate_path) in builder.crates("std") {
if path.ends_with(krate_path) {
make(Mode::Libstd, Some(name));
}
for krate in builder.in_tree_crates("std") {
if run.path.ends_with(&krate.local_path(&builder)) {
make(Mode::Libstd, krate);
}
for (name, krate_path) in builder.crates("test") {
if path.ends_with(krate_path) {
make(Mode::Libtest, Some(name));
}
}
for krate in builder.in_tree_crates("test") {
if run.path.ends_with(&krate.local_path(&builder)) {
make(Mode::Libtest, krate);
}
} else {
make(Mode::Libstd, None);
make(Mode::Libtest, None);
}
}
/// Run all unit tests plus documentation tests for an entire crate DAG defined
/// by a `Cargo.toml`
/// Run all unit tests plus documentation tests for a given crate defined
/// by a `Cargo.toml` (single manifest)
///
/// This is what runs tests for crates like the standard library, compiler, etc.
/// It essentially is the driver for running `cargo test`.
@ -1241,27 +1328,23 @@ impl Step for Crate {
};
let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand());
let (name, root) = match mode {
match mode {
Mode::Libstd => {
compile::std_cargo(build, &compiler, target, &mut cargo);
("libstd", "std")
}
Mode::Libtest => {
compile::test_cargo(build, &compiler, target, &mut cargo);
("libtest", "test")
}
Mode::Librustc => {
builder.ensure(compile::Rustc { compiler, target });
compile::rustc_cargo(build, &mut cargo);
("librustc", "rustc-main")
}
_ => panic!("can only test libraries"),
};
let root = INTERNER.intern_string(String::from(root));
let _folder = build.fold_output(|| {
format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, name)
format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate)
});
println!("{} {} stage{} ({} -> {})", test_kind, name, compiler.stage,
println!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage,
&compiler.host, target);
// Build up the base `cargo test` command.
@ -1273,37 +1356,7 @@ impl Step for Crate {
cargo.arg("--no-fail-fast");
}
match krate {
Some(krate) => {
cargo.arg("-p").arg(krate);
}
None => {
let mut visited = HashSet::new();
let mut next = vec![root];
while let Some(name) = next.pop() {
// Right now jemalloc and the sanitizer crates are
// target-specific crate in the sense that it's not present
// on all platforms. Custom skip it here for now, but if we
// add more this probably wants to get more generalized.
//
// Also skip `build_helper` as it's not compiled normally
// for target during the bootstrap and it's just meant to be
// a helper crate, not tested. If it leaks through then it
// ends up messing with various mtime calculations and such.
if !name.contains("jemalloc") &&
*name != *"build_helper" &&
!(name.starts_with("rustc_") && name.ends_with("san")) &&
name != "dlmalloc" {
cargo.arg("-p").arg(&format!("{}:0.0.0", name));
}
for dep in build.crates[&name].deps.iter() {
if visited.insert(dep) {
next.push(*dep);
}
}
}
}
}
cargo.arg("-p").arg(krate);
// The tests are going to run with the *target* libraries, so we need to
// ensure that those libraries show up in the LD_LIBRARY_PATH equivalent.
@ -1355,18 +1408,18 @@ impl Step for Crate {
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustdoc {
pub struct CrateRustdoc {
host: Interned<String>,
test_kind: TestKind,
}
impl Step for Rustdoc {
impl Step for CrateRustdoc {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/librustdoc").path("src/tools/rustdoc")
run.paths(&["src/librustdoc", "src/tools/rustdoc"])
}
fn make_run(run: RunConfig) {
@ -1380,7 +1433,7 @@ impl Step for Rustdoc {
panic!("unexpected builder.kind in crate: {:?}", builder.kind);
};
builder.ensure(Rustdoc {
builder.ensure(CrateRustdoc {
host: run.host,
test_kind,
});