1
Fork 0

Auto merge of #48105 - Mark-Simulacrum:exclude-paths, r=alexcrichton

Implement excluding a build-step via --exclude

First step to fixing https://github.com/rust-lang/rust/issues/47911. This doesn't change any CI configuration, but implements what I believe necessary to make that feasible in rustbuild.

In theory this should be sufficient to allow someone to open a PR against .travis.yml and appveyor.yml which splits the Windows 32-bit tests and maybe the OS X tests into multiple builders (depending on what our cost-concerns are) to reduce runtimes.

r? @alexcrichton
cc @kennytm
This commit is contained in:
bors 2018-02-15 10:32:33 +00:00
commit c83fa5d91c
10 changed files with 452 additions and 335 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: PathBuf,
}
struct StepDescription {
@ -105,6 +105,32 @@ 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 empty() -> PathSet {
PathSet { set: BTreeSet::new() }
}
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, builder: &Builder) -> PathBuf {
self.set.iter().next().unwrap_or(&builder.build.src).to_path_buf()
}
}
impl StepDescription {
@ -116,10 +142,18 @@ 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, path: Option<&Path>) {
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 {
build.build_triple()
@ -144,7 +178,7 @@ impl StepDescription {
for target in targets {
let run = RunConfig {
builder,
path,
path: pathset.path(builder),
host: *host,
target: *target,
};
@ -157,19 +191,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, 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, Some(path));
desc.maybe_run(builder, pathset);
}
}
@ -185,7 +228,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.
@ -206,25 +249,46 @@ 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(PathBuf::from(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(PathBuf::from(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
}
// allows being more explicit about why should_run in Step returns the value passed to it
pub fn never(self) -> ShouldRun<'a> {
pub fn never(mut self) -> ShouldRun<'a> {
self.paths.insert(PathSet::empty());
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))
}
}
@ -254,19 +318,23 @@ 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,
doc::Reference, doc::Rustdoc, doc::RustByExample, doc::CargoBook),
Kind::Dist => describe!(dist::Docs, dist::Mingw, dist::Rustc, dist::DebuggerScripts,
dist::Std, dist::Analysis, dist::Src, dist::PlainSourceTarball, dist::Cargo,
dist::Rls, dist::Rustfmt, dist::Extended, dist::HashSign,
dist::DontDistWithMiriEnabled),
dist::Rls, dist::Rustfmt, dist::Extended, dist::HashSign),
Kind::Install => describe!(install::Docs, install::Std, install::Cargo, install::Rls,
install::Rustfmt, install::Analysis, install::Src, install::Rustc),
}
@ -297,9 +365,11 @@ 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 {
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)
}
@ -323,6 +393,12 @@ impl<'a> Builder<'a> {
stack: RefCell::new(Vec::new()),
};
if kind == Kind::Dist {
assert!(!build.config.test_miri, "Do not distribute with miri enabled.\n\
The distributed libraries would include all MIR (increasing binary size).
The distributed MIR would include validation statements.");
}
StepDescription::run(&Builder::get_step_descriptions(builder.kind), &builder, paths);
}

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

@ -56,6 +56,7 @@ pub struct Config {
pub sanitizers: bool,
pub profiler: bool,
pub ignore_git: bool,
pub exclude: Vec<PathBuf>,
pub run_host_only: bool,
@ -311,6 +312,7 @@ impl Config {
let flags = Flags::parse(&args);
let file = flags.config.clone();
let mut config = Config::default();
config.exclude = flags.exclude;
config.llvm_enabled = true;
config.llvm_optimize = true;
config.llvm_version_check = true;

View file

@ -1233,31 +1233,6 @@ impl Step for Rustfmt {
}
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct DontDistWithMiriEnabled;
impl Step for DontDistWithMiriEnabled {
type Output = PathBuf;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
let build_miri = run.builder.build.config.test_miri;
run.default_condition(build_miri)
}
fn make_run(run: RunConfig) {
run.builder.ensure(DontDistWithMiriEnabled);
}
fn run(self, _: &Builder) -> PathBuf {
panic!("Do not distribute with miri enabled.\n\
The distributed libraries would include all MIR (increasing binary size).
The distributed MIR would include validation statements.");
}
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Extended {
stage: u32,

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

@ -42,6 +42,7 @@ pub struct Flags {
pub jobs: Option<u32>,
pub cmd: Subcommand,
pub incremental: bool,
pub exclude: Vec<PathBuf>,
}
pub enum Subcommand {
@ -109,6 +110,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
opts.optmulti("", "host", "host targets to build", "HOST");
opts.optmulti("", "target", "target targets to build", "TARGET");
opts.optmulti("", "exclude", "build paths to exclude", "PATH");
opts.optopt("", "on-fail", "command to run on failure", "CMD");
opts.optopt("", "stage", "stage to build", "N");
opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
@ -273,7 +275,12 @@ Arguments:
};
// Get any optional paths which occur after the subcommand
let cwd = t!(env::current_dir());
let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::<Vec<_>>();
let src = matches.opt_str("src").map(PathBuf::from)
.or_else(|| env::var_os("SRC").map(PathBuf::from))
.unwrap_or(cwd.clone());
let paths = matches.free[1..].iter().map(|p| {
cwd.join(p).strip_prefix(&src).expect("paths passed to be inside checkout").into()
}).collect::<Vec<PathBuf>>();
let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| {
if fs::metadata("config.toml").is_ok() {
@ -358,11 +365,6 @@ Arguments:
stage = Some(1);
}
let cwd = t!(env::current_dir());
let src = matches.opt_str("src").map(PathBuf::from)
.or_else(|| env::var_os("SRC").map(PathBuf::from))
.unwrap_or(cwd);
Flags {
verbose: matches.opt_count("verbose"),
stage,
@ -374,10 +376,14 @@ Arguments:
target: split(matches.opt_strs("target"))
.into_iter().map(|x| INTERNER.intern_string(x)).collect::<Vec<_>>(),
config: cfg_file,
src,
jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()),
cmd,
incremental: matches.opt_present("incremental"),
exclude: split(matches.opt_strs("exclude"))
.into_iter().map(|p| {
cwd.join(p).strip_prefix(&src).expect("paths to be inside checkout").into()
}).collect::<Vec<_>>(),
src,
}
}
}

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,25 +960,21 @@ 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));
if krate.is_local(self) {
ret.push(krate);
for dep in &krate.deps {
if visited.insert(dep) && dep != "build_helper" {
list.push(*dep);
}
}
}
}
ret
}
}

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 {
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"
},
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" },
});
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" },
];
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct DefaultCompiletest {
compiler: Compiler,
target: Interned<String>,
mode: &'static str,
suite: &'static str,
}
impl Step for DefaultCompiletest {
type Output = ();
const DEFAULT: bool = true;
fn should_run(mut run: ShouldRun) -> ShouldRun {
for test in DEFAULT_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| {
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);
})
mode: "debuginfo-XXX",
suite: "debuginfo"
});
if let Some(test) = test {
run.builder.ensure(DefaultCompiletest {
compiler,
target: run.target,
mode: test.mode,
suite: test.suite,
host_test!(UiFullDeps {
path: "src/test/ui-fulldeps",
mode: "ui",
suite: "ui-fulldeps"
});
} else {
for test in DEFAULT_COMPILETESTS {
run.builder.ensure(DefaultCompiletest {
compiler,
target: run.target,
mode: test.mode,
suite: test.suite
host_test!(RunPassFullDeps {
path: "src/test/run-pass-fulldeps",
mode: "run-pass",
suite: "run-pass-fulldeps"
});
}
}
}
fn run(self, builder: &Builder) {
builder.ensure(Compiletest {
compiler: self.compiler,
target: self.target,
mode: self.mode,
suite: self.suite,
})
}
}
host_test!(RunFailFullDeps {
path: "src/test/run-fail-fulldeps",
mode: "run-fail",
suite: "run-fail-fulldeps"
});
// 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 {
host_test!(CompileFailFullDeps {
path: "src/test/compile-fail-fulldeps",
mode: "compile-fail",
suite: "compile-fail-fulldeps",
},
Test {
suite: "compile-fail-fulldeps"
});
host_test!(IncrementalFullDeps {
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);
})
suite: "incremental-fulldeps"
});
if let Some(test) = test {
run.builder.ensure(HostCompiletest {
compiler,
target: run.target,
mode: test.mode,
suite: test.suite,
host_test!(Rustdoc {
path: "src/test/rustdoc",
mode: "rustdoc",
suite: "rustdoc"
});
} 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,
})
}
}
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
});
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,7 +1148,8 @@ impl Step for CrateLibrustc {
let builder = run.builder;
let compiler = builder.compiler(builder.top_stage, run.host);
let make = |name: Option<Interned<String>>| {
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 {
@ -1128,21 +1162,11 @@ impl Step for CrateLibrustc {
compiler,
target: run.target,
test_kind,
krate: name,
krate: 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));
}
}
} else {
make(None);
}
}
fn run(self, builder: &Builder) {
builder.ensure(Crate {
@ -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);
}
}
}
}
}
// 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,
});