Skip to content

Commit 4ec5ce5

Browse files
committed
Auto merge of #33282 - alexcrichton:rustbuild-crate-tests, r=brson
rustbuild: Add support for crate tests + doctests This commit adds support to rustbuild to run crate unit tests (those defined by `#[test]`) as well as documentation tests. All tests are powered by `cargo test` under the hood. Each step requires the `libtest` library is built for that corresponding stage. Ideally the `test` crate would be a dev-dependency, but for now it's just easier to ensure that we sequence everything in the right order. Currently no filtering is implemented, so there's not actually a method of testing *only* libstd or *only* libcore, but rather entire swaths of crates are tested all at once. A few points of note here are: * The `coretest` and `collectionstest` crates are just listed as `[[test]]` entires for `cargo test` to naturally pick up. This mean that `cargo test -p core` actually runs all the tests for libcore. * Libraries that aren't tested all mention `test = false` in their `Cargo.toml` * Crates aren't currently allowed to have dev-dependencies due to rust-lang/cargo#860, but we can likely alleviate this restriction once workspaces are implemented. cc #31590
2 parents e88defe + bb9062a commit 4ec5ce5

File tree

28 files changed

+182
-26
lines changed

28 files changed

+182
-26
lines changed

src/bootstrap/build/check.rs

+77-2
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@
1313
//! This file implements the various regression test suites that we execute on
1414
//! our CI.
1515
16-
use std::fs;
16+
use std::env;
17+
use std::fs::{self, File};
18+
use std::io::prelude::*;
1719
use std::path::{PathBuf, Path};
1820
use std::process::Command;
1921

2022
use build_helper::output;
23+
use bootstrap::{dylib_path, dylib_path_var};
2124

22-
use build::{Build, Compiler};
25+
use build::{Build, Compiler, Mode};
2326

2427
/// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
2528
///
@@ -222,3 +225,75 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
222225
cmd.arg("--test-args").arg(build.flags.args.join(" "));
223226
build.run(&mut cmd);
224227
}
228+
229+
/// Run all unit tests plus documentation tests for an entire crate DAG defined
230+
/// by a `Cargo.toml`
231+
///
232+
/// This is what runs tests for crates like the standard library, compiler, etc.
233+
/// It essentially is the driver for running `cargo test`.
234+
///
235+
/// Currently this runs all tests for a DAG by passing a bunch of `-p foo`
236+
/// arguments, and those arguments are discovered from `Cargo.lock`.
237+
pub fn krate(build: &Build,
238+
compiler: &Compiler,
239+
target: &str,
240+
mode: Mode) {
241+
let (name, path, features) = match mode {
242+
Mode::Libstd => ("libstd", "src/rustc/std_shim", build.std_features()),
243+
Mode::Libtest => ("libtest", "src/rustc/test_shim", String::new()),
244+
Mode::Librustc => ("librustc", "src/rustc", build.rustc_features()),
245+
_ => panic!("can only test libraries"),
246+
};
247+
println!("Testing {} stage{} ({} -> {})", name, compiler.stage,
248+
compiler.host, target);
249+
250+
// Build up the base `cargo test` command.
251+
let mut cargo = build.cargo(compiler, mode, target, "test");
252+
cargo.arg("--manifest-path")
253+
.arg(build.src.join(path).join("Cargo.toml"))
254+
.arg("--features").arg(features);
255+
256+
// Generate a list of `-p` arguments to pass to the `cargo test` invocation
257+
// by crawling the corresponding Cargo.lock file.
258+
let lockfile = build.src.join(path).join("Cargo.lock");
259+
let mut contents = String::new();
260+
t!(t!(File::open(&lockfile)).read_to_string(&mut contents));
261+
let mut lines = contents.lines();
262+
while let Some(line) = lines.next() {
263+
let prefix = "name = \"";
264+
if !line.starts_with(prefix) {
265+
continue
266+
}
267+
lines.next(); // skip `version = ...`
268+
269+
// skip crates.io or otherwise non-path crates
270+
if let Some(line) = lines.next() {
271+
if line.starts_with("source") {
272+
continue
273+
}
274+
}
275+
276+
let crate_name = &line[prefix.len()..line.len() - 1];
277+
278+
// Right now jemalloc is our only target-specific crate in the sense
279+
// that it's not present on all platforms. Custom skip it here for now,
280+
// but if we add more this probably wants to get more generalized.
281+
if crate_name.contains("jemalloc") {
282+
continue
283+
}
284+
285+
cargo.arg("-p").arg(crate_name);
286+
}
287+
288+
// The tests are going to run with the *target* libraries, so we need to
289+
// ensure that those libraries show up in the LD_LIBRARY_PATH equivalent.
290+
//
291+
// Note that to run the compiler we need to run with the *host* libraries,
292+
// but our wrapper scripts arrange for that to be the case anyway.
293+
let mut dylib_path = dylib_path();
294+
dylib_path.insert(0, build.sysroot_libdir(compiler, target));
295+
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
296+
cargo.args(&build.flags.args);
297+
298+
build.run(&mut cargo);
299+
}

src/bootstrap/build/mod.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,15 @@ impl Build {
380380
check::compiletest(self, &compiler, target.target,
381381
"run-make", "run-make")
382382
}
383+
CheckCrateStd { compiler } => {
384+
check::krate(self, &compiler, target.target, Mode::Libstd)
385+
}
386+
CheckCrateTest { compiler } => {
387+
check::krate(self, &compiler, target.target, Mode::Libtest)
388+
}
389+
CheckCrateRustc { compiler } => {
390+
check::krate(self, &compiler, target.target, Mode::Librustc)
391+
}
383392

384393
DistDocs { stage } => dist::docs(self, stage, target.target),
385394
DistMingw { _dummy } => dist::mingw(self, target.target),
@@ -485,6 +494,7 @@ impl Build {
485494
self.config.rust_debug_assertions.to_string())
486495
.env("RUSTC_SNAPSHOT", &self.rustc)
487496
.env("RUSTC_SYSROOT", self.sysroot(compiler))
497+
.env("RUSTC_LIBDIR", self.rustc_libdir(compiler))
488498
.env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir())
489499
.env("RUSTC_RPATH", self.config.rust_rpath.to_string())
490500
.env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
@@ -520,7 +530,6 @@ impl Build {
520530
if self.config.rust_optimize {
521531
cargo.arg("--release");
522532
}
523-
self.add_rustc_lib_path(compiler, &mut cargo);
524533
return cargo
525534
}
526535

src/bootstrap/build/step.rs

+15
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ macro_rules! targets {
120120
(check_docs, CheckDocs { compiler: Compiler<'a> }),
121121
(check_error_index, CheckErrorIndex { compiler: Compiler<'a> }),
122122
(check_rmake, CheckRMake { compiler: Compiler<'a> }),
123+
(check_crate_std, CheckCrateStd { compiler: Compiler<'a> }),
124+
(check_crate_test, CheckCrateTest { compiler: Compiler<'a> }),
125+
(check_crate_rustc, CheckCrateRustc { compiler: Compiler<'a> }),
123126

124127
// Distribution targets, creating tarballs
125128
(dist, Dist { stage: u32 }),
@@ -376,6 +379,9 @@ impl<'a> Step<'a> {
376379
self.check_cfail(compiler),
377380
self.check_rfail(compiler),
378381
self.check_pfail(compiler),
382+
self.check_crate_std(compiler),
383+
self.check_crate_test(compiler),
384+
self.check_crate_rustc(compiler),
379385
self.check_codegen(compiler),
380386
self.check_codegen_units(compiler),
381387
self.check_debuginfo(compiler),
@@ -437,6 +443,15 @@ impl<'a> Step<'a> {
437443
Source::CheckErrorIndex { compiler } => {
438444
vec![self.libstd(compiler), self.tool_error_index(compiler.stage)]
439445
}
446+
Source::CheckCrateStd { compiler } => {
447+
vec![self.libtest(compiler)]
448+
}
449+
Source::CheckCrateTest { compiler } => {
450+
vec![self.libtest(compiler)]
451+
}
452+
Source::CheckCrateRustc { compiler } => {
453+
vec![self.libtest(compiler)]
454+
}
440455

441456
Source::ToolLinkchecker { stage } |
442457
Source::ToolTidy { stage } => {

src/bootstrap/rustc.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extern crate bootstrap;
2929

3030
use std::env;
3131
use std::ffi::OsString;
32+
use std::path::PathBuf;
3233
use std::process::Command;
3334

3435
fn main() {
@@ -43,16 +44,22 @@ fn main() {
4344
// have the standard library built yet and may not be able to produce an
4445
// executable. Otherwise we just use the standard compiler we're
4546
// bootstrapping with.
46-
let rustc = if target.is_none() {
47-
env::var_os("RUSTC_SNAPSHOT").unwrap()
47+
let (rustc, libdir) = if target.is_none() {
48+
("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR")
4849
} else {
49-
env::var_os("RUSTC_REAL").unwrap()
50+
("RUSTC_REAL", "RUSTC_LIBDIR")
5051
};
5152
let stage = env::var("RUSTC_STAGE").unwrap();
5253

54+
let rustc = env::var_os(rustc).unwrap();
55+
let libdir = env::var_os(libdir).unwrap();
56+
let mut dylib_path = bootstrap::dylib_path();
57+
dylib_path.insert(0, PathBuf::from(libdir));
58+
5359
let mut cmd = Command::new(rustc);
5460
cmd.args(&args)
55-
.arg("--cfg").arg(format!("stage{}", stage));
61+
.arg("--cfg").arg(format!("stage{}", stage))
62+
.env(bootstrap::dylib_path_var(), env::join_paths(&dylib_path).unwrap());
5663

5764
if let Some(target) = target {
5865
// The stage0 compiler has a special sysroot distinct from what we

src/bootstrap/rustdoc.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,25 @@
1212
//!
1313
//! See comments in `src/bootstrap/rustc.rs` for more information.
1414
15+
extern crate bootstrap;
16+
1517
use std::env;
1618
use std::process::Command;
19+
use std::path::PathBuf;
1720

1821
fn main() {
1922
let args = env::args_os().skip(1).collect::<Vec<_>>();
2023
let rustdoc = env::var_os("RUSTDOC_REAL").unwrap();
24+
let libdir = env::var_os("RUSTC_LIBDIR").unwrap();
25+
26+
let mut dylib_path = bootstrap::dylib_path();
27+
dylib_path.insert(0, PathBuf::from(libdir));
2128

2229
let mut cmd = Command::new(rustdoc);
2330
cmd.args(&args)
2431
.arg("--cfg").arg(format!("stage{}", env::var("RUSTC_STAGE").unwrap()))
25-
.arg("--cfg").arg("dox");
32+
.arg("--cfg").arg("dox")
33+
.env(bootstrap::dylib_path_var(), env::join_paths(&dylib_path).unwrap());
2634
std::process::exit(match cmd.status() {
2735
Ok(s) => s.code().unwrap_or(1),
2836
Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),

src/liballoc/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ version = "0.0.0"
66
[lib]
77
name = "alloc"
88
path = "lib.rs"
9-
test = false
109

1110
[dependencies]
1211
core = { path = "../libcore" }

src/liballoc_jemalloc/build.rs

+16
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![deny(warnings)]
12+
1113
extern crate build_helper;
1214
extern crate gcc;
1315

@@ -18,6 +20,7 @@ use build_helper::run;
1820

1921
fn main() {
2022
println!("cargo:rustc-cfg=cargobuild");
23+
println!("cargo:rerun-if-changed=build.rs");
2124

2225
let target = env::var("TARGET").unwrap();
2326
let host = env::var("HOST").unwrap();
@@ -40,6 +43,19 @@ fn main() {
4043
let cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
4144
.collect::<Vec<_>>().join(" ");
4245

46+
let mut stack = src_dir.join("../jemalloc")
47+
.read_dir().unwrap()
48+
.map(|e| e.unwrap())
49+
.collect::<Vec<_>>();
50+
while let Some(entry) = stack.pop() {
51+
let path = entry.path();
52+
if entry.file_type().unwrap().is_dir() {
53+
stack.extend(path.read_dir().unwrap().map(|e| e.unwrap()));
54+
} else {
55+
println!("cargo:rerun-if-changed={}", path.display());
56+
}
57+
}
58+
4359
let mut cmd = Command::new("sh");
4460
cmd.arg(src_dir.join("../jemalloc/configure").to_str().unwrap()
4561
.replace("C:\\", "/c/")

src/libcollections/Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ version = "0.0.0"
66
[lib]
77
name = "collections"
88
path = "lib.rs"
9-
test = false
109

1110
[dependencies]
1211
alloc = { path = "../liballoc" }
1312
core = { path = "../libcore" }
1413
rustc_unicode = { path = "../librustc_unicode" }
14+
15+
[[test]]
16+
name = "collectionstest"
17+
path = "../libcollectionstest/lib.rs"

src/libcore/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,7 @@ build = "build.rs"
88
name = "core"
99
path = "lib.rs"
1010
test = false
11+
12+
[[test]]
13+
name = "coretest"
14+
path = "../libcoretest/lib.rs"

src/libcore/build.rs

+3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![deny(warnings)]
12+
1113
fn main() {
1214
// Remove this whenever snapshots and rustbuild nightlies are synced.
1315
println!("cargo:rustc-cfg=cargobuild");
16+
println!("cargo:rerun-if-changed=build.rs")
1417
}

src/libflate/lib.rs

+1-11
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,7 @@
2727
#![feature(libc)]
2828
#![feature(staged_api)]
2929
#![feature(unique)]
30-
#![cfg_attr(test, feature(rustc_private, rand))]
31-
32-
#[cfg(test)]
33-
#[macro_use]
34-
extern crate log;
30+
#![cfg_attr(test, feature(rand))]
3531

3632
extern crate libc;
3733

@@ -175,14 +171,8 @@ mod tests {
175171
for _ in 0..2000 {
176172
input.extend_from_slice(r.choose(&words).unwrap());
177173
}
178-
debug!("de/inflate of {} bytes of random word-sequences",
179-
input.len());
180174
let cmp = deflate_bytes(&input);
181175
let out = inflate_bytes(&cmp).unwrap();
182-
debug!("{} bytes deflated to {} ({:.1}% size)",
183-
input.len(),
184-
cmp.len(),
185-
100.0 * ((cmp.len() as f64) / (input.len() as f64)));
186176
assert_eq!(&*input, &*out);
187177
}
188178
}

src/libpanic_abort/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ version = "0.0.0"
55

66
[lib]
77
path = "lib.rs"
8+
test = false
89

910
[dependencies]
1011
core = { path = "../libcore" }

src/libpanic_unwind/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ version = "0.0.0"
55

66
[lib]
77
path = "lib.rs"
8+
test = false
89

910
[dependencies]
1011
alloc = { path = "../liballoc" }

src/librand/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ version = "0.0.0"
66
[lib]
77
name = "rand"
88
path = "lib.rs"
9-
test = false
109

1110
[dependencies]
1211
core = { path = "../libcore" }

src/librustc_bitflags/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ version = "0.0.0"
77
name = "rustc_bitflags"
88
path = "lib.rs"
99
test = false
10+
doctest = false

src/librustc_borrowck/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ version = "0.0.0"
77
name = "rustc_borrowck"
88
path = "lib.rs"
99
crate-type = ["dylib"]
10+
test = false
1011

1112
[dependencies]
1213
log = { path = "../liblog" }

src/librustc_lint/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ version = "0.0.0"
77
name = "rustc_lint"
88
path = "lib.rs"
99
crate-type = ["dylib"]
10+
test = false
1011

1112
[dependencies]
1213
log = { path = "../liblog" }

src/librustc_resolve/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ version = "0.0.0"
77
name = "rustc_resolve"
88
path = "lib.rs"
99
crate-type = ["dylib"]
10+
test = false
1011

1112
[dependencies]
1213
log = { path = "../liblog" }

src/librustc_trans/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ version = "0.0.0"
77
name = "rustc_trans"
88
path = "lib.rs"
99
crate-type = ["dylib"]
10+
test = false
1011

1112
[dependencies]
1213
arena = { path = "../libarena" }

src/librustc_typeck/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ version = "0.0.0"
77
name = "rustc_typeck"
88
path = "lib.rs"
99
crate-type = ["dylib"]
10+
test = false
1011

1112
[dependencies]
1213
log = { path = "../liblog" }

0 commit comments

Comments
 (0)