Add ./x.py check src/{libstd,libtest,rustc}.

This currently only supports a limited subset of the full compilation,
but is likely 90% of what people will want and is possible without
building a full compiler (i.e., running LLVM). In theory, this means
that contributors who don't want to build LLVM now have an easy way to
compile locally, though running tests won't work.
This commit is contained in:
Mark Simulacrum 2018-01-15 10:44:00 -07:00
parent 734ee0fb43
commit 6aeb1cfb64
7 changed files with 211 additions and 27 deletions

View file

@ -125,11 +125,6 @@ fn main() {
cmd.arg(format!("-Clinker={}", target_linker)); cmd.arg(format!("-Clinker={}", target_linker));
} }
// Pass down incremental directory, if any.
if let Ok(dir) = env::var("RUSTC_INCREMENTAL") {
cmd.arg(format!("-Zincremental={}", dir));
}
let crate_name = args.windows(2) let crate_name = args.windows(2)
.find(|a| &*a[0] == "--crate-name") .find(|a| &*a[0] == "--crate-name")
.unwrap(); .unwrap();

View file

@ -602,6 +602,7 @@ class RustBuild(object):
env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
(os.pathsep + env["LIBRARY_PATH"]) \ (os.pathsep + env["LIBRARY_PATH"]) \
if "LIBRARY_PATH" in env else "" if "LIBRARY_PATH" in env else ""
env["RUSTFLAGS"] = "-Cdebuginfo=2"
env["PATH"] = os.path.join(self.bin_root(), "bin") + \ env["PATH"] = os.path.join(self.bin_root(), "bin") + \
os.pathsep + env["PATH"] os.pathsep + env["PATH"]
if not os.path.isfile(self.cargo()): if not os.path.isfile(self.cargo()):

View file

@ -26,6 +26,7 @@ use util::{exe, libdir, add_lib_path};
use {Build, Mode}; use {Build, Mode};
use cache::{INTERNER, Interned, Cache}; use cache::{INTERNER, Interned, Cache};
use check; use check;
use test;
use flags::Subcommand; use flags::Subcommand;
use doc; use doc;
use tool; use tool;
@ -230,6 +231,7 @@ impl<'a> ShouldRun<'a> {
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Kind { pub enum Kind {
Build, Build,
Check,
Test, Test,
Bench, Bench,
Dist, Dist,
@ -251,13 +253,13 @@ impl<'a> Builder<'a> {
tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient, tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient,
tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy, tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy,
native::Llvm, tool::Rustfmt, tool::Miri), native::Llvm, tool::Rustfmt, tool::Miri),
Kind::Test => describe!(check::Tidy, check::Bootstrap, check::DefaultCompiletest, Kind::Check => describe!(check::Std, check::Test, check::Rustc),
check::HostCompiletest, check::Crate, check::CrateLibrustc, check::Rustdoc, Kind::Test => describe!(test::Tidy, test::Bootstrap, test::DefaultCompiletest,
check::Linkcheck, check::Cargotest, check::Cargo, check::Rls, check::Docs, test::HostCompiletest, test::Crate, test::CrateLibrustc, test::Rustdoc,
check::ErrorIndex, check::Distcheck, check::Rustfmt, check::Miri, check::Clippy, test::Linkcheck, test::Cargotest, test::Cargo, test::Rls, test::Docs,
check::RustdocJS), test::ErrorIndex, test::Distcheck, test::Rustfmt, test::Miri, test::Clippy,
test::RustdocJS),
Kind::Bench => describe!(check::Crate, check::CrateLibrustc), Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon, doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon,
doc::Reference, doc::Rustdoc, doc::RustByExample, doc::CargoBook), doc::Reference, doc::Rustdoc, doc::RustByExample, doc::CargoBook),
@ -304,6 +306,7 @@ impl<'a> Builder<'a> {
pub fn run(build: &Build) { pub fn run(build: &Build) {
let (kind, paths) = match build.config.cmd { let (kind, paths) = match build.config.cmd {
Subcommand::Build { ref paths } => (Kind::Build, &paths[..]), Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
Subcommand::Check { ref paths } => (Kind::Check, &paths[..]),
Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]), Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]), Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]),
Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]), Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
@ -493,13 +496,14 @@ impl<'a> Builder<'a> {
cargo.env("RUSTC_CODEGEN_UNITS", n.to_string()); cargo.env("RUSTC_CODEGEN_UNITS", n.to_string());
} }
if let Some(host_linker) = self.build.linker(compiler.host) { if let Some(host_linker) = self.build.linker(compiler.host) {
cargo.env("RUSTC_HOST_LINKER", host_linker); cargo.env("RUSTC_HOST_LINKER", host_linker);
} }
if let Some(target_linker) = self.build.linker(target) { if let Some(target_linker) = self.build.linker(target) {
cargo.env("RUSTC_TARGET_LINKER", target_linker); cargo.env("RUSTC_TARGET_LINKER", target_linker);
} }
if cmd != "build" { if cmd != "build" && cmd != "check" {
cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.build.build))); cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.build.build)));
} }
@ -566,8 +570,7 @@ impl<'a> Builder<'a> {
// not guaranteeing correctness across builds if the compiler // not guaranteeing correctness across builds if the compiler
// is changing under your feet.` // is changing under your feet.`
if self.config.incremental && compiler.stage == 0 { if self.config.incremental && compiler.stage == 0 {
let incr_dir = self.incremental_dir(compiler); cargo.env("CARGO_INCREMENTAL", "1");
cargo.env("RUSTC_INCREMENTAL", incr_dir);
} }
if let Some(ref on_fail) = self.config.on_fail { if let Some(ref on_fail) = self.config.on_fail {

163
src/bootstrap/check.rs Normal file
View file

@ -0,0 +1,163 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation of compiling the compiler and standard library, in "check" mode.
use compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, add_to_sysroot};
use builder::{RunConfig, Builder, ShouldRun, Step};
use {Build, Compiler, Mode};
use cache::Interned;
use std::path::PathBuf;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Std {
pub target: Interned<String>,
}
impl Step for Std {
type Output = ();
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/libstd").krate("std")
}
fn make_run(run: RunConfig) {
run.builder.ensure(Std {
target: run.target,
});
}
fn run(self, builder: &Builder) {
let build = builder.build;
let target = self.target;
let compiler = builder.compiler(0, build.build);
let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
println!("Checking std artifacts ({} -> {})", &compiler.host, target);
let out_dir = build.stage_out(compiler, Mode::Libstd);
build.clear_if_dirty(&out_dir, &builder.rustc(compiler));
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "check");
std_cargo(build, &compiler, target, &mut cargo);
run_cargo(build,
&mut cargo,
&libstd_stamp(build, compiler, target),
true);
let libdir = builder.sysroot_libdir(compiler, target);
add_to_sysroot(&libdir, &libstd_stamp(build, compiler, target));
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustc {
pub target: Interned<String>,
}
impl Step for Rustc {
type Output = ();
const ONLY_HOSTS: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/librustc").krate("rustc-main")
}
fn make_run(run: RunConfig) {
run.builder.ensure(Rustc {
target: run.target,
});
}
/// Build the compiler.
///
/// This will build the compiler for a particular stage of the build using
/// the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
fn run(self, builder: &Builder) {
let build = builder.build;
let compiler = builder.compiler(0, build.build);
let target = self.target;
let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
println!("Checking compiler artifacts ({} -> {})", &compiler.host, target);
let stage_out = builder.stage_out(compiler, Mode::Librustc);
build.clear_if_dirty(&stage_out, &libstd_stamp(build, compiler, target));
build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check");
rustc_cargo(build, target, &mut cargo);
run_cargo(build,
&mut cargo,
&librustc_stamp(build, compiler, target),
true);
let libdir = builder.sysroot_libdir(compiler, target);
add_to_sysroot(&libdir, &librustc_stamp(build, compiler, target));
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Test {
pub target: Interned<String>,
}
impl Step for Test {
type Output = ();
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/libtest").krate("test")
}
fn make_run(run: RunConfig) {
run.builder.ensure(Test {
target: run.target,
});
}
fn run(self, builder: &Builder) {
let build = builder.build;
let target = self.target;
let compiler = builder.compiler(0, build.build);
let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
println!("Checking test artifacts ({} -> {})", &compiler.host, target);
let out_dir = build.stage_out(compiler, Mode::Libtest);
build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "check");
test_cargo(build, &compiler, target, &mut cargo);
run_cargo(build,
&mut cargo,
&libtest_stamp(build, compiler, target),
true);
let libdir = builder.sysroot_libdir(compiler, target);
add_to_sysroot(&libdir, &libtest_stamp(build, compiler, target));
}
}
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
pub fn libstd_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
build.cargo_out(compiler, Mode::Libstd, target).join(".libstd-check.stamp")
}
/// Cargo's output path for libtest in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn libtest_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
build.cargo_out(compiler, Mode::Libtest, target).join(".libtest-check.stamp")
}
/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
build.cargo_out(compiler, Mode::Librustc, target).join(".librustc-check.stamp")
}

View file

@ -108,7 +108,8 @@ impl Step for Std {
std_cargo(build, &compiler, target, &mut cargo); std_cargo(build, &compiler, target, &mut cargo);
run_cargo(build, run_cargo(build,
&mut cargo, &mut cargo,
&libstd_stamp(build, compiler, target)); &libstd_stamp(build, compiler, target),
false);
builder.ensure(StdLink { builder.ensure(StdLink {
compiler: builder.compiler(compiler.stage, build.build), compiler: builder.compiler(compiler.stage, build.build),
@ -360,7 +361,8 @@ impl Step for Test {
test_cargo(build, &compiler, target, &mut cargo); test_cargo(build, &compiler, target, &mut cargo);
run_cargo(build, run_cargo(build,
&mut cargo, &mut cargo,
&libtest_stamp(build, compiler, target)); &libtest_stamp(build, compiler, target),
false);
builder.ensure(TestLink { builder.ensure(TestLink {
compiler: builder.compiler(compiler.stage, build.build), compiler: builder.compiler(compiler.stage, build.build),
@ -488,7 +490,8 @@ impl Step for Rustc {
rustc_cargo(build, target, &mut cargo); rustc_cargo(build, target, &mut cargo);
run_cargo(build, run_cargo(build,
&mut cargo, &mut cargo,
&librustc_stamp(build, compiler, target)); &librustc_stamp(build, compiler, target),
false);
builder.ensure(RustcLink { builder.ensure(RustcLink {
compiler: builder.compiler(compiler.stage, build.build), compiler: builder.compiler(compiler.stage, build.build),
@ -755,7 +758,7 @@ impl Step for Assemble {
/// ///
/// For a particular stage this will link the file listed in `stamp` into the /// For a particular stage this will link the file listed in `stamp` into the
/// `sysroot_dst` provided. /// `sysroot_dst` provided.
fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) { pub fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) {
t!(fs::create_dir_all(&sysroot_dst)); t!(fs::create_dir_all(&sysroot_dst));
for path in read_stamp_file(stamp) { for path in read_stamp_file(stamp) {
copy(&path, &sysroot_dst.join(path.file_name().unwrap())); copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
@ -785,7 +788,7 @@ fn stderr_isatty() -> bool {
} }
} }
fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path) { pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: bool) {
// Instruct Cargo to give us json messages on stdout, critically leaving // Instruct Cargo to give us json messages on stdout, critically leaving
// stderr as piped so we can get those pretty colors. // stderr as piped so we can get those pretty colors.
cargo.arg("--message-format").arg("json") cargo.arg("--message-format").arg("json")
@ -836,7 +839,8 @@ fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path) {
// Skip files like executables // Skip files like executables
if !filename.ends_with(".rlib") && if !filename.ends_with(".rlib") &&
!filename.ends_with(".lib") && !filename.ends_with(".lib") &&
!is_dylib(&filename) { !is_dylib(&filename) &&
!(is_check && filename.ends_with(".rmeta")) {
continue continue
} }

View file

@ -48,6 +48,9 @@ pub enum Subcommand {
Build { Build {
paths: Vec<PathBuf>, paths: Vec<PathBuf>,
}, },
Check {
paths: Vec<PathBuf>,
},
Doc { Doc {
paths: Vec<PathBuf>, paths: Vec<PathBuf>,
}, },
@ -88,6 +91,7 @@ Usage: x.py <subcommand> [options] [<paths>...]
Subcommands: Subcommands:
build Compile either the compiler or libraries build Compile either the compiler or libraries
check Compile either the compiler or libraries, using cargo check
test Build and run some test suites test Build and run some test suites
bench Build and run some benchmarks bench Build and run some benchmarks
doc Build documentation doc Build documentation
@ -128,6 +132,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
// there on out. // there on out.
let subcommand = args.iter().find(|&s| let subcommand = args.iter().find(|&s|
(s == "build") (s == "build")
|| (s == "check")
|| (s == "test") || (s == "test")
|| (s == "bench") || (s == "bench")
|| (s == "doc") || (s == "doc")
@ -217,6 +222,21 @@ Arguments:
arguments would), and then use the compiler built in stage 0 to build arguments would), and then use the compiler built in stage 0 to build
src/libtest and its dependencies. src/libtest and its dependencies.
Once this is done, build/$ARCH/stage1 contains a usable compiler."); Once this is done, build/$ARCH/stage1 contains a usable compiler.");
}
"check" => {
subcommand_help.push_str("\n
Arguments:
This subcommand accepts a number of paths to directories to the crates
and/or artifacts to compile. For example:
./x.py check src/libcore
./x.py check src/libcore src/libproc_macro
If no arguments are passed then the complete artifacts are compiled: std, test, and rustc. Note
also that since we use `cargo check`, by default this will automatically enable incremental
compilation, so there's no need to pass it separately, though it won't hurt. We also completely
ignore the stage passed, as there's no way to compile in non-stage 0 without actually building
the compiler.");
} }
"test" => { "test" => {
subcommand_help.push_str("\n subcommand_help.push_str("\n
@ -286,6 +306,9 @@ Arguments:
"build" => { "build" => {
Subcommand::Build { paths: paths } Subcommand::Build { paths: paths }
} }
"check" => {
Subcommand::Check { paths: paths }
}
"test" => { "test" => {
Subcommand::Test { Subcommand::Test {
paths, paths,

View file

@ -150,6 +150,7 @@ use util::{exe, libdir, OutputFolder, CiEnv};
mod cc_detect; mod cc_detect;
mod channel; mod channel;
mod check; mod check;
mod test;
mod clean; mod clean;
mod compile; mod compile;
mod metadata; mod metadata;
@ -449,12 +450,6 @@ impl Build {
out out
} }
/// Get the directory for incremental by-products when using the
/// given compiler.
fn incremental_dir(&self, compiler: Compiler) -> PathBuf {
self.out.join(&*compiler.host).join(format!("stage{}-incremental", compiler.stage))
}
/// Returns the root directory for all output generated in a particular /// Returns the root directory for all output generated in a particular
/// stage when running with a particular host compiler. /// stage when running with a particular host compiler.
/// ///