Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustbuild: Allow quick testing of libstd and libcore at stage0 #50466

Merged
merged 9 commits into from
May 6, 2018
43 changes: 40 additions & 3 deletions src/bootstrap/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use compile;
use install;
use dist;
use util::{exe, libdir, add_lib_path};
use {Build, Mode};
use {Build, Mode, DocTestsOption};
use cache::{INTERNER, Interned, Cache};
use check;
use test;
Expand Down Expand Up @@ -591,6 +591,8 @@ impl<'a> Builder<'a> {
format!("{} {}", env::var("RUSTFLAGS").unwrap_or_default(), extra_args));
}

let want_rustdoc = self.doc_tests != DocTestsOption::No;

// Customize the compiler we're running. Specify the compiler to cargo
// as our shim and then pass it some various options used to configure
// how the actual compiler itself is called.
Expand All @@ -607,7 +609,7 @@ impl<'a> Builder<'a> {
.env("RUSTC_LIBDIR", self.rustc_libdir(compiler))
.env("RUSTC_RPATH", self.config.rust_rpath.to_string())
.env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
.env("RUSTDOC_REAL", if cmd == "doc" || cmd == "test" {
.env("RUSTDOC_REAL", if cmd == "doc" || (cmd == "test" && want_rustdoc) {
self.rustdoc(compiler.host)
} else {
PathBuf::from("/path/to/nowhere/rustdoc/not/required")
Expand All @@ -624,7 +626,7 @@ impl<'a> Builder<'a> {
if let Some(ref error_format) = self.config.rustc_error_format {
cargo.env("RUSTC_ERROR_FORMAT", error_format);
}
if cmd != "build" && cmd != "check" {
if cmd != "build" && cmd != "check" && want_rustdoc {
cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.config.build)));
}

Expand Down Expand Up @@ -1403,4 +1405,39 @@ mod __test {
},
]);
}

#[test]
fn test_with_no_doc_stage0() {
let mut config = configure(&[], &[]);
config.stage = Some(0);
config.cmd = Subcommand::Test {
paths: vec!["src/libstd".into()],
test_args: vec![],
rustc_args: vec![],
fail_fast: true,
doc_tests: DocTestsOption::No,
};

let build = Build::new(config);
let mut builder = Builder::new(&build);

let host = INTERNER.intern_str("A");

builder.run_step_descriptions(
&[StepDescription::from::<test::Crate>()],
&["src/libstd".into()],
);

// Ensure we don't build any compiler artifacts.
assert!(builder.cache.all::<compile::Rustc>().is_empty());
assert_eq!(first(builder.cache.all::<test::Crate>()), &[
test::Crate {
compiler: Compiler { host, stage: 0 },
target: host,
mode: Mode::Libstd,
test_kind: test::TestKind::Test,
krate: INTERNER.intern_str("std"),
},
]);
}
}
19 changes: 13 additions & 6 deletions src/bootstrap/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use std::process;

use getopts::Options;

use Build;
use {Build, DocTestsOption};
use config::Config;
use metadata;
use builder::Builder;
Expand Down Expand Up @@ -62,7 +62,7 @@ pub enum Subcommand {
test_args: Vec<String>,
rustc_args: Vec<String>,
fail_fast: bool,
doc_tests: bool,
doc_tests: DocTestsOption,
},
Bench {
paths: Vec<PathBuf>,
Expand Down Expand Up @@ -171,7 +171,8 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
"extra options to pass the compiler when running tests",
"ARGS",
);
opts.optflag("", "doc", "run doc tests");
opts.optflag("", "no-doc", "do not run doc tests");
opts.optflag("", "doc", "only run doc tests");
},
"bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
"clean" => { opts.optflag("", "all", "clean all build artifacts"); },
Expand Down Expand Up @@ -324,7 +325,13 @@ Arguments:
test_args: matches.opt_strs("test-args"),
rustc_args: matches.opt_strs("rustc-args"),
fail_fast: !matches.opt_present("no-fail-fast"),
doc_tests: matches.opt_present("doc"),
doc_tests: if matches.opt_present("doc") {
DocTestsOption::Only
} else if matches.opt_present("no-doc") {
DocTestsOption::No
} else {
DocTestsOption::Yes
}
}
}
"bench" => {
Expand Down Expand Up @@ -411,10 +418,10 @@ impl Subcommand {
}
}

pub fn doc_tests(&self) -> bool {
pub fn doc_tests(&self) -> DocTestsOption {
match *self {
Subcommand::Test { doc_tests, .. } => doc_tests,
_ => false,
_ => DocTestsOption::Yes,
}
}
}
Expand Down
14 changes: 12 additions & 2 deletions src/bootstrap/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,16 @@ pub struct Compiler {
host: Interned<String>,
}

#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum DocTestsOption {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename this to DocTests? I think it might have uses outside just being passed on the command line...

// Default, run normal tests and doc tests.
Yes,
// Do not run any doc tests.
No,
// Only run doc tests.
Only,
}

/// Global configuration for the build system.
///
/// This structure transitively contains all configuration for the build system.
Expand All @@ -233,7 +243,7 @@ pub struct Build {
rustfmt_info: channel::GitInfo,
local_rebuild: bool,
fail_fast: bool,
doc_tests: bool,
doc_tests: DocTestsOption,
verbosity: usize,

// Targets for which to build.
Expand Down Expand Up @@ -294,7 +304,7 @@ impl Crate {
///
/// These entries currently correspond to the various output directories of the
/// build system, with each mod generating output in a different directory.
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Mode {
/// Build the standard library, placing output in the "stageN-std" directory.
Libstd,
Expand Down
26 changes: 16 additions & 10 deletions src/bootstrap/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ use dist;
use native;
use tool::{self, Tool};
use util::{self, dylib_path, dylib_path_var};
use Mode;
use {Mode, DocTestsOption};
use toolstate::ToolState;

const ADB_TEST_DIR: &str = "/data/tmp/work";

/// The two modes of the test runner; tests or benchmarks.
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)]
pub enum TestKind {
/// Run `cargo test`
Test,
Expand Down Expand Up @@ -1407,13 +1407,13 @@ impl Step for CrateNotDefault {
}


#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Crate {
compiler: Compiler,
target: Interned<String>,
mode: Mode,
test_kind: TestKind,
krate: Interned<String>,
pub compiler: Compiler,
pub target: Interned<String>,
pub mode: Mode,
pub test_kind: TestKind,
pub krate: Interned<String>,
}

impl Step for Crate {
Expand Down Expand Up @@ -1519,8 +1519,14 @@ impl Step for Crate {
if test_kind.subcommand() == "test" && !builder.fail_fast {
cargo.arg("--no-fail-fast");
}
if builder.doc_tests {
cargo.arg("--doc");
match builder.doc_tests {
DocTestsOption::Only => {
cargo.arg("--doc");
}
DocTestsOption::No => {
cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
}
DocTestsOption::Yes => {}
}

cargo.arg("-p").arg(krate);
Expand Down
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@

// Since libcore defines many fundamental lang items, all tests live in a
// separate crate, libcoretest, to avoid bizarre issues.
#![cfg(not(test))]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels odd; presumably independent of whether we are running tests we would expect core to exist and define everything -- or am I misreading what this does?

Copy link
Member Author

@kennytm kennytm May 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Mark-Simulacrum

The problem is when we are testing the library, we will build an executable and link to libtest. Now, this executable defines some lang items, and at the same time libtest imports the non-testing libcore which also defines some lang items. This will cause the E0152 "duplicate lang item found" error. I'm not sure why this is not discovered before, maybe no one tried to ./x.py test src/libcore? 🙃

Reduced test case:

#![cfg(not(test))] // <-- comment out to cause E0152 when `cargo test`.

#![feature(no_core, lang_items)]
#![no_core]

/// ```
///                               
/// ```
#[lang = "sized"]
pub trait Sized {}

In cargo test, the doc tests are still discovered and executed even with this cfg. I assume this is the same for rustbuild, though if it turns out to be wrong we could change the cfg to any(dox, not(test)). Edit: Yes they are executed.

I've updated this comment to explain the attribute.


#![stable(feature = "core", since = "1.6.0")]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
Expand Down
82 changes: 0 additions & 82 deletions src/libcore/slice/memchr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,85 +135,3 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
// find the byte before the point the body loop stopped
text[..offset].iter().rposition(|elt| *elt == x)
}

// test fallback implementations on all platforms
#[test]
fn matches_one() {
assert_eq!(Some(0), memchr(b'a', b"a"));
}

#[test]
fn matches_begin() {
assert_eq!(Some(0), memchr(b'a', b"aaaa"));
}

#[test]
fn matches_end() {
assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
}

#[test]
fn matches_nul() {
assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
}

#[test]
fn matches_past_nul() {
assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
}

#[test]
fn no_match_empty() {
assert_eq!(None, memchr(b'a', b""));
}

#[test]
fn no_match() {
assert_eq!(None, memchr(b'a', b"xyz"));
}

#[test]
fn matches_one_reversed() {
assert_eq!(Some(0), memrchr(b'a', b"a"));
}

#[test]
fn matches_begin_reversed() {
assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
}

#[test]
fn matches_end_reversed() {
assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
}

#[test]
fn matches_nul_reversed() {
assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
}

#[test]
fn matches_past_nul_reversed() {
assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
}

#[test]
fn no_match_empty_reversed() {
assert_eq!(None, memrchr(b'a', b""));
}

#[test]
fn no_match_reversed() {
assert_eq!(None, memrchr(b'a', b"xyz"));
}

#[test]
fn each_alignment_reversed() {
let mut data = [1u8; 64];
let needle = 2;
let pos = 40;
data[pos] = needle;
for start in 0..16 {
assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
}
}
2 changes: 2 additions & 0 deletions src/libcore/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#![feature(reverse_bits)]
#![feature(inclusive_range_methods)]
#![feature(iterator_find_map)]
#![feature(slice_internals)]

extern crate core;
extern crate test;
Expand Down Expand Up @@ -74,4 +75,5 @@ mod result;
mod slice;
mod str;
mod str_lossy;
mod time;
mod tuple;
1 change: 1 addition & 0 deletions src/libcore/tests/num/uint_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ mod tests {
}

#[test]
#[cfg(not(stage0))]
fn test_reverse_bits() {
assert_eq!(A.reverse_bits().reverse_bits(), A);
assert_eq!(B.reverse_bits().reverse_bits(), B);
Expand Down
Loading