mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
rustbuild: Rewrite user-facing interface
This commit is a rewrite of the user-facing interface to the rustbuild build
system. The intention here is to make it much easier to compile/test the project
without having to remember weird rule names and such. An overall view of the new
interface is:
# build everything
./x.py build
# document everyting
./x.py doc
# test everything
./x.py test
# test libstd
./x.py test src/libstd
# build libcore stage0
./x.py build src/libcore --stage 0
# run stage1 run-pass tests
./x.py test src/test/run-pass --stage 1
The `src/bootstrap/bootstrap.py` script is now aliased as a top-level `x.py`
script. This `x` was chosen to be both short and easily tab-completable (no
collisions in that namespace!). The build system now accepts a "subcommand" of
what to do next, the main ones being build/doc/test.
Each subcommand then receives an optional list of arguments. These arguments are
paths in the source repo of what to work with. That is, if you want to test a
directory, you just pass that directory as an argument.
The purpose of this rewrite is to do away with all of the arcane renames like
"rpass" is the "run-pass" suite, "cfail" is the "compile-fail" suite, etc. By
simply working with directories and files it's much more intuitive of how to run
a test (just pass it as an argument).
The rustbuild step/dependency management was also rewritten along the way to
make this easy to work with and define, but that's largely just a refactoring of
what was there before.
The *intention* is that this support is extended for arbitrary files (e.g.
`src/test/run-pass/my-test-case.rs`), but that isn't quite implemented just yet.
Instead directories work for now but we can follow up with stricter path
filtering logic to plumb through all the arguments.
This commit is contained in:
@@ -127,7 +127,7 @@ ones from MSYS if you have it installed). You'll also need Visual Studio 2013 or
|
||||
newer with the C++ tools. Then all you need to do is to kick off rustbuild.
|
||||
|
||||
```
|
||||
python .\src\bootstrap\bootstrap.py
|
||||
python x.py build
|
||||
```
|
||||
|
||||
Currently rustbuild only works with some known versions of Visual Studio. If you
|
||||
@@ -137,7 +137,7 @@ by manually calling the appropriate vcvars file before running the bootstrap.
|
||||
|
||||
```
|
||||
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat"
|
||||
python .\src\bootstrap\bootstrap.py
|
||||
python x.py build
|
||||
```
|
||||
|
||||
## Building Documentation
|
||||
|
||||
Generated
+7
-13
@@ -40,9 +40,9 @@ name = "bootstrap"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"build_helper 0.1.0",
|
||||
"cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gcc 0.3.38 (git+https://github.com/alexcrichton/gcc-rs)",
|
||||
"gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -63,7 +63,7 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -131,11 +131,6 @@ dependencies = [
|
||||
name = "fmt_macros"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.38"
|
||||
source = "git+https://github.com/alexcrichton/gcc-rs#be620ac6d3ddb498cd0c700d5312c6a4c3c19597"
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.38"
|
||||
@@ -189,7 +184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
name = "linkchecker"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"url 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -725,7 +720,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.2.2"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -743,10 +738,9 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978"
|
||||
"checksum cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0e5bcf27e097a184c1df4437654ed98df3d7a516e8508a6ba45d8b092bbdf283"
|
||||
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
|
||||
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
|
||||
"checksum gcc 0.3.38 (git+https://github.com/alexcrichton/gcc-rs)" = "<none>"
|
||||
"checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"
|
||||
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
|
||||
"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
|
||||
@@ -760,6 +754,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796"
|
||||
"checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f"
|
||||
"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172"
|
||||
"checksum url 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ba5a45db1d2e0effb7a1c00cc73ffc63a973da8c7d1fcd5b46f24285ade6c54"
|
||||
"checksum url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "48ccf7bd87a81b769cf84ad556e034541fb90e1cd6d4bc375c822ed9500cd9d7"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
||||
@@ -27,7 +27,7 @@ num_cpus = "0.2"
|
||||
toml = "0.1"
|
||||
getopts = "0.2"
|
||||
rustc-serialize = "0.3"
|
||||
gcc = { git = "https://github.com/alexcrichton/gcc-rs" }
|
||||
gcc = "0.3.36"
|
||||
libc = "0.2"
|
||||
md5 = "0.1"
|
||||
|
||||
|
||||
+60
-12
@@ -10,8 +10,64 @@ system.
|
||||
|
||||
## Using rustbuild
|
||||
|
||||
When configuring Rust via `./configure`, pass the following to enable building
|
||||
via this build system:
|
||||
The rustbuild build system has a primary entry point, a top level `x.py` script:
|
||||
|
||||
```
|
||||
python ./x.py build
|
||||
```
|
||||
|
||||
Note that if you're on Unix you should be able to execute the script directly:
|
||||
|
||||
```
|
||||
./x.py build
|
||||
```
|
||||
|
||||
The script accepts commands, flags, and filters to determine what to do:
|
||||
|
||||
* `build` - a general purpose command for compiling code. Alone `build` will
|
||||
bootstrap the entire compiler, and otherwise arguments passed indicate what to
|
||||
build. For example:
|
||||
|
||||
```
|
||||
# build the whole compiler
|
||||
./x.py build
|
||||
|
||||
# build the stage1 compier
|
||||
./x.py build --stage 1
|
||||
|
||||
# build stage0 libstd
|
||||
./x.py build --stage 0 src/libstd
|
||||
|
||||
# build a particular crate in stage0
|
||||
./x.py build --stage 0 src/libtest
|
||||
```
|
||||
|
||||
* `test` - a command for executing unit tests. Like the `build` command this
|
||||
will execute the entire test suite by default, and otherwise it can be used to
|
||||
select which test suite is run:
|
||||
|
||||
```
|
||||
# run all unit tests
|
||||
./x.py test
|
||||
|
||||
# execute the run-pass test suite
|
||||
./x.py test src/test/run-pass
|
||||
|
||||
# execute only some tests in the run-pass test suite
|
||||
./x.py test src/test/run-pass --filter my-filter
|
||||
|
||||
# execute tests in the standard library in stage0
|
||||
./x.py test --stage 0 src/libstd
|
||||
|
||||
# execute all doc tests
|
||||
./x.py test src/doc
|
||||
```
|
||||
|
||||
* `doc` - a command for building documentation. Like above can take arguments
|
||||
for what to document.
|
||||
|
||||
If you're more used to `./configure` and `make`, however, then you can also
|
||||
configure the build system to use rustbuild instead of the old makefiles:
|
||||
|
||||
```
|
||||
./configure --enable-rustbuild
|
||||
@@ -19,15 +75,7 @@ make
|
||||
```
|
||||
|
||||
Afterwards the `Makefile` which is generated will have a few commands like
|
||||
`make check`, `make tidy`, etc. For finer-grained control, the
|
||||
`bootstrap.py` entry point can be used:
|
||||
|
||||
```
|
||||
python src/bootstrap/bootstrap.py
|
||||
```
|
||||
|
||||
This accepts a number of options like `--stage` and `--step` which can configure
|
||||
what's actually being done.
|
||||
`make check`, `make tidy`, etc.
|
||||
|
||||
## Configuring rustbuild
|
||||
|
||||
@@ -47,7 +95,7 @@ being invoked manually (via the python script).
|
||||
The rustbuild build system goes through a few phases to actually build the
|
||||
compiler. What actually happens when you invoke rustbuild is:
|
||||
|
||||
1. The entry point script, `src/bootstrap/bootstrap.py` is run. This script is
|
||||
1. The entry point script, `x.py` is run. This script is
|
||||
responsible for downloading the stage0 compiler/Cargo binaries, and it then
|
||||
compiles the build system itself (this folder). Finally, it then invokes the
|
||||
actual `bootstrap` binary build system.
|
||||
|
||||
@@ -399,12 +399,10 @@ def main():
|
||||
|
||||
# Run the bootstrap
|
||||
args = [os.path.join(rb.build_dir, "bootstrap/debug/bootstrap")]
|
||||
args.append('--src')
|
||||
args.append(rb.rust_root)
|
||||
args.append('--build')
|
||||
args.append(rb.build)
|
||||
args.extend(sys.argv[1:])
|
||||
env = os.environ.copy()
|
||||
env["BUILD"] = rb.build
|
||||
env["SRC"] = rb.rust_root
|
||||
env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
|
||||
rb.run(args, env)
|
||||
|
||||
|
||||
+25
-66
@@ -13,44 +13,19 @@
|
||||
//! This file implements the various regression test suites that we execute on
|
||||
//! our CI.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::process::Command;
|
||||
|
||||
use build_helper::output;
|
||||
use rustc_serialize::json;
|
||||
|
||||
use {Build, Compiler, Mode};
|
||||
use util::{self, dylib_path, dylib_path_var};
|
||||
|
||||
const ADB_TEST_DIR: &'static str = "/data/tmp";
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct Output {
|
||||
packages: Vec<Package>,
|
||||
resolve: Resolve,
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct Package {
|
||||
id: String,
|
||||
name: String,
|
||||
source: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct Resolve {
|
||||
nodes: Vec<ResolveNode>,
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct ResolveNode {
|
||||
id: String,
|
||||
dependencies: Vec<String>,
|
||||
}
|
||||
|
||||
/// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
|
||||
///
|
||||
/// This tool in `src/tools` will verify the validity of all our links in the
|
||||
@@ -181,7 +156,7 @@ pub fn compiletest(build: &Build,
|
||||
let llvm_version = output(Command::new(&llvm_config).arg("--version"));
|
||||
cmd.arg("--llvm-version").arg(llvm_version);
|
||||
|
||||
cmd.args(&build.flags.args);
|
||||
cmd.args(&build.flags.cmd.test_args());
|
||||
|
||||
if build.config.verbose || build.flags.verbose {
|
||||
cmd.arg("--verbose");
|
||||
@@ -282,7 +257,7 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
|
||||
cmd.arg("--test");
|
||||
cmd.arg(markdown);
|
||||
|
||||
let mut test_args = build.flags.args.join(" ");
|
||||
let mut test_args = build.flags.cmd.test_args().join(" ");
|
||||
if build.config.quiet_tests {
|
||||
test_args.push_str(" --quiet");
|
||||
}
|
||||
@@ -302,7 +277,8 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
|
||||
pub fn krate(build: &Build,
|
||||
compiler: &Compiler,
|
||||
target: &str,
|
||||
mode: Mode) {
|
||||
mode: Mode,
|
||||
krate: Option<&str>) {
|
||||
let (name, path, features, root) = match mode {
|
||||
Mode::Libstd => {
|
||||
("libstd", "src/rustc/std_shim", build.std_features(), "std_shim")
|
||||
@@ -318,24 +294,6 @@ pub fn krate(build: &Build,
|
||||
println!("Testing {} stage{} ({} -> {})", name, compiler.stage,
|
||||
compiler.host, target);
|
||||
|
||||
// Run `cargo metadata` to figure out what crates we're testing.
|
||||
//
|
||||
// Down below we're going to call `cargo test`, but to test the right set
|
||||
// of packages we're going to have to know what `-p` arguments to pass it
|
||||
// to know what crates to test. Here we run `cargo metadata` to learn about
|
||||
// the dependency graph and what `-p` arguments there are.
|
||||
let mut cargo = Command::new(&build.cargo);
|
||||
cargo.arg("metadata")
|
||||
.arg("--manifest-path").arg(build.src.join(path).join("Cargo.toml"));
|
||||
let output = output(&mut cargo);
|
||||
let output: Output = json::decode(&output).unwrap();
|
||||
let id2pkg = output.packages.iter()
|
||||
.map(|pkg| (&pkg.id, pkg))
|
||||
.collect::<HashMap<_, _>>();
|
||||
let id2deps = output.resolve.nodes.iter()
|
||||
.map(|node| (&node.id, &node.dependencies))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
// Build up the base `cargo test` command.
|
||||
//
|
||||
// Pass in some standard flags then iterate over the graph we've discovered
|
||||
@@ -346,24 +304,25 @@ pub fn krate(build: &Build,
|
||||
.arg(build.src.join(path).join("Cargo.toml"))
|
||||
.arg("--features").arg(features);
|
||||
|
||||
let mut visited = HashSet::new();
|
||||
let root_pkg = output.packages.iter().find(|p| p.name == root).unwrap();
|
||||
let mut next = vec![&root_pkg.id];
|
||||
while let Some(id) = next.pop() {
|
||||
// Skip any packages with sources listed, as these come from crates.io
|
||||
// and we shouldn't be testing them.
|
||||
if id2pkg[id].source.is_some() {
|
||||
continue
|
||||
match krate {
|
||||
Some(krate) => {
|
||||
cargo.arg("-p").arg(krate);
|
||||
}
|
||||
// Right now jemalloc is our only 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.
|
||||
if !id.contains("jemalloc") {
|
||||
cargo.arg("-p").arg(&id2pkg[id].name);
|
||||
}
|
||||
for dep in id2deps[id] {
|
||||
if visited.insert(dep) {
|
||||
next.push(dep);
|
||||
None => {
|
||||
let mut visited = HashSet::new();
|
||||
let mut next = vec![root];
|
||||
while let Some(name) = next.pop() {
|
||||
// Right now jemalloc is our only 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.
|
||||
if !name.contains("jemalloc") {
|
||||
cargo.arg("-p").arg(name);
|
||||
}
|
||||
for dep in build.crates[name].deps.iter() {
|
||||
if visited.insert(dep) {
|
||||
next.push(dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -389,7 +348,7 @@ pub fn krate(build: &Build,
|
||||
build.run(cargo.arg("--no-run"));
|
||||
krate_emscripten(build, compiler, target, mode);
|
||||
} else {
|
||||
cargo.args(&build.flags.args);
|
||||
cargo.args(&build.flags.cmd.test_args());
|
||||
build.run(&mut cargo);
|
||||
}
|
||||
}
|
||||
@@ -421,7 +380,7 @@ fn krate_android(build: &Build,
|
||||
target = target,
|
||||
test = test_file_name,
|
||||
log = log,
|
||||
args = build.flags.args.join(" "));
|
||||
args = build.flags.cmd.test_args().join(" "));
|
||||
|
||||
let output = output(Command::new("adb").arg("shell").arg(&program));
|
||||
println!("{}", output);
|
||||
|
||||
+10
-10
@@ -25,17 +25,17 @@ pub fn clean(build: &Build) {
|
||||
rm_rf(build, &build.out.join("tmp"));
|
||||
|
||||
for host in build.config.host.iter() {
|
||||
let entries = match build.out.join(host).read_dir() {
|
||||
Ok(iter) => iter,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let out = build.out.join(host);
|
||||
|
||||
rm_rf(build, &out.join("doc"));
|
||||
|
||||
for stage in 0..4 {
|
||||
rm_rf(build, &out.join(format!("stage{}", stage)));
|
||||
rm_rf(build, &out.join(format!("stage{}-std", stage)));
|
||||
rm_rf(build, &out.join(format!("stage{}-rustc", stage)));
|
||||
rm_rf(build, &out.join(format!("stage{}-tools", stage)));
|
||||
rm_rf(build, &out.join(format!("stage{}-test", stage)));
|
||||
for entry in entries {
|
||||
let entry = t!(entry);
|
||||
if entry.file_name().to_str() == Some("llvm") {
|
||||
continue
|
||||
}
|
||||
t!(fs::remove_dir_all(&entry.path()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-11
@@ -64,8 +64,8 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
}
|
||||
|
||||
build.run(&mut cargo);
|
||||
update_mtime(&libstd_stamp(build, compiler, target));
|
||||
std_link(build, target, compiler, compiler.host);
|
||||
update_mtime(&libstd_stamp(build, &compiler, target));
|
||||
std_link(build, target, compiler.stage, compiler.host);
|
||||
}
|
||||
|
||||
/// Link all libstd rlibs/dylibs into the sysroot location.
|
||||
@@ -74,11 +74,12 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
/// by `compiler` into `host`'s sysroot.
|
||||
pub fn std_link(build: &Build,
|
||||
target: &str,
|
||||
compiler: &Compiler,
|
||||
stage: u32,
|
||||
host: &str) {
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let target_compiler = Compiler::new(compiler.stage, host);
|
||||
let libdir = build.sysroot_libdir(&target_compiler, target);
|
||||
let out_dir = build.cargo_out(compiler, Mode::Libstd, target);
|
||||
let out_dir = build.cargo_out(&compiler, Mode::Libstd, target);
|
||||
|
||||
// If we're linking one compiler host's output into another, then we weren't
|
||||
// called from the `std` method above. In that case we clean out what's
|
||||
@@ -146,7 +147,7 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
.arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
|
||||
build.run(&mut cargo);
|
||||
update_mtime(&libtest_stamp(build, compiler, target));
|
||||
test_link(build, target, compiler, compiler.host);
|
||||
test_link(build, target, compiler.stage, compiler.host);
|
||||
}
|
||||
|
||||
/// Link all libtest rlibs/dylibs into the sysroot location.
|
||||
@@ -155,11 +156,12 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
/// by `compiler` into `host`'s sysroot.
|
||||
pub fn test_link(build: &Build,
|
||||
target: &str,
|
||||
compiler: &Compiler,
|
||||
stage: u32,
|
||||
host: &str) {
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let target_compiler = Compiler::new(compiler.stage, host);
|
||||
let libdir = build.sysroot_libdir(&target_compiler, target);
|
||||
let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
|
||||
let out_dir = build.cargo_out(&compiler, Mode::Libtest, target);
|
||||
add_to_sysroot(&out_dir, &libdir);
|
||||
}
|
||||
|
||||
@@ -218,7 +220,7 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
}
|
||||
build.run(&mut cargo);
|
||||
|
||||
rustc_link(build, target, compiler, compiler.host);
|
||||
rustc_link(build, target, compiler.stage, compiler.host);
|
||||
}
|
||||
|
||||
/// Link all librustc rlibs/dylibs into the sysroot location.
|
||||
@@ -227,11 +229,12 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
/// by `compiler` into `host`'s sysroot.
|
||||
pub fn rustc_link(build: &Build,
|
||||
target: &str,
|
||||
compiler: &Compiler,
|
||||
stage: u32,
|
||||
host: &str) {
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let target_compiler = Compiler::new(compiler.stage, host);
|
||||
let libdir = build.sysroot_libdir(&target_compiler, target);
|
||||
let out_dir = build.cargo_out(compiler, Mode::Librustc, target);
|
||||
let out_dir = build.cargo_out(&compiler, Mode::Librustc, target);
|
||||
add_to_sysroot(&out_dir, &libdir);
|
||||
}
|
||||
|
||||
@@ -259,7 +262,10 @@ fn compiler_file(compiler: &Path, file: &str) -> PathBuf {
|
||||
/// must have been previously produced by the `stage - 1` build.config.build
|
||||
/// compiler.
|
||||
pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
|
||||
assert!(stage > 0, "the stage0 compiler isn't assembled, it's downloaded");
|
||||
// nothing to do in stage0
|
||||
if stage == 0 {
|
||||
return
|
||||
}
|
||||
// The compiler that we're assembling
|
||||
let target_compiler = Compiler::new(stage, host);
|
||||
|
||||
|
||||
+22
-17
@@ -19,7 +19,6 @@
|
||||
|
||||
use std::fs::{self, File};
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use {Build, Compiler, Mode};
|
||||
@@ -30,8 +29,9 @@
|
||||
///
|
||||
/// This will not actually generate any documentation if the documentation has
|
||||
/// already been generated.
|
||||
pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str, out: &Path) {
|
||||
t!(fs::create_dir_all(out));
|
||||
pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str) {
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
|
||||
let out = out.join(name);
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
@@ -57,9 +57,10 @@ pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str, out: &Path)
|
||||
/// `STAMP` alongw ith providing the various header/footer HTML we've cutomized.
|
||||
///
|
||||
/// In the end, this is just a glorified wrapper around rustdoc!
|
||||
pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
pub fn standalone(build: &Build, stage: u32, target: &str) {
|
||||
println!("Documenting stage{} standalone ({})", stage, target);
|
||||
t!(fs::create_dir_all(out));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
|
||||
@@ -109,7 +110,7 @@ pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
.arg("--html-in-header").arg(&favicon)
|
||||
.arg("--markdown-playground-url")
|
||||
.arg("https://play.rust-lang.org/")
|
||||
.arg("-o").arg(out)
|
||||
.arg("-o").arg(&out)
|
||||
.arg(&path);
|
||||
|
||||
if filename == "reference.md" {
|
||||
@@ -131,9 +132,10 @@ pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
///
|
||||
/// This will generate all documentation for the standard library and its
|
||||
/// dependencies. This is largely just a wrapper around `cargo doc`.
|
||||
pub fn std(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
pub fn std(build: &Build, stage: u32, target: &str) {
|
||||
println!("Documenting stage{} std ({})", stage, target);
|
||||
t!(fs::create_dir_all(out));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let out_dir = build.stage_out(&compiler, Mode::Libstd)
|
||||
.join(target).join("doc");
|
||||
@@ -146,16 +148,17 @@ pub fn std(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
.arg(build.src.join("src/rustc/std_shim/Cargo.toml"))
|
||||
.arg("--features").arg(build.std_features());
|
||||
build.run(&mut cargo);
|
||||
cp_r(&out_dir, out)
|
||||
cp_r(&out_dir, &out)
|
||||
}
|
||||
|
||||
/// Compile all libtest documentation.
|
||||
///
|
||||
/// This will generate all documentation for libtest and its dependencies. This
|
||||
/// is largely just a wrapper around `cargo doc`.
|
||||
pub fn test(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
pub fn test(build: &Build, stage: u32, target: &str) {
|
||||
println!("Documenting stage{} test ({})", stage, target);
|
||||
t!(fs::create_dir_all(out));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let out_dir = build.stage_out(&compiler, Mode::Libtest)
|
||||
.join(target).join("doc");
|
||||
@@ -167,16 +170,17 @@ pub fn test(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
cargo.arg("--manifest-path")
|
||||
.arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
|
||||
build.run(&mut cargo);
|
||||
cp_r(&out_dir, out)
|
||||
cp_r(&out_dir, &out)
|
||||
}
|
||||
|
||||
/// Generate all compiler documentation.
|
||||
///
|
||||
/// This will generate all documentation for the compiler libraries and their
|
||||
/// dependencies. This is largely just a wrapper around `cargo doc`.
|
||||
pub fn rustc(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
pub fn rustc(build: &Build, stage: u32, target: &str) {
|
||||
println!("Documenting stage{} compiler ({})", stage, target);
|
||||
t!(fs::create_dir_all(out));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let out_dir = build.stage_out(&compiler, Mode::Librustc)
|
||||
.join(target).join("doc");
|
||||
@@ -189,14 +193,15 @@ pub fn rustc(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
.arg(build.src.join("src/rustc/Cargo.toml"))
|
||||
.arg("--features").arg(build.rustc_features());
|
||||
build.run(&mut cargo);
|
||||
cp_r(&out_dir, out)
|
||||
cp_r(&out_dir, &out)
|
||||
}
|
||||
|
||||
/// Generates the HTML rendered error-index by running the
|
||||
/// `error_index_generator` tool.
|
||||
pub fn error_index(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
pub fn error_index(build: &Build, stage: u32, target: &str) {
|
||||
println!("Documenting stage{} error index ({})", stage, target);
|
||||
t!(fs::create_dir_all(out));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let mut index = build.tool_cmd(&compiler, "error_index_generator");
|
||||
index.arg("html");
|
||||
|
||||
+202
-37
@@ -13,30 +13,46 @@
|
||||
//! This module implements the command-line parsing of the build system which
|
||||
//! has various flags to configure how it's run.
|
||||
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use std::slice;
|
||||
|
||||
use getopts::Options;
|
||||
use getopts::{Matches, Options};
|
||||
|
||||
use Build;
|
||||
use config::Config;
|
||||
use metadata;
|
||||
use step;
|
||||
|
||||
/// Deserialized version of all flags for this compile.
|
||||
pub struct Flags {
|
||||
pub verbose: bool,
|
||||
pub stage: Option<u32>,
|
||||
pub build: String,
|
||||
pub host: Filter,
|
||||
pub target: Filter,
|
||||
pub step: Vec<String>,
|
||||
pub host: Vec<String>,
|
||||
pub target: Vec<String>,
|
||||
pub config: Option<PathBuf>,
|
||||
pub src: Option<PathBuf>,
|
||||
pub jobs: Option<u32>,
|
||||
pub args: Vec<String>,
|
||||
pub clean: bool,
|
||||
pub cmd: Subcommand,
|
||||
}
|
||||
|
||||
pub struct Filter {
|
||||
values: Vec<String>,
|
||||
pub enum Subcommand {
|
||||
Build {
|
||||
paths: Vec<PathBuf>,
|
||||
},
|
||||
Doc {
|
||||
paths: Vec<PathBuf>,
|
||||
},
|
||||
Test {
|
||||
paths: Vec<PathBuf>,
|
||||
test_args: Vec<String>,
|
||||
},
|
||||
Clean,
|
||||
Dist {
|
||||
install: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl Flags {
|
||||
@@ -44,29 +60,177 @@ pub fn parse(args: &[String]) -> Flags {
|
||||
let mut opts = Options::new();
|
||||
opts.optflag("v", "verbose", "use verbose output");
|
||||
opts.optopt("", "config", "TOML configuration file for build", "FILE");
|
||||
opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
|
||||
opts.optmulti("", "host", "host targets to build", "HOST");
|
||||
opts.reqopt("", "build", "build target of the stage0 compiler", "BUILD");
|
||||
opts.optmulti("", "target", "targets to build", "TARGET");
|
||||
opts.optmulti("s", "step", "build step to execute", "STEP");
|
||||
opts.optmulti("", "target", "target targets to build", "TARGET");
|
||||
opts.optopt("", "stage", "stage to build", "N");
|
||||
opts.optopt("", "src", "path to repo root", "DIR");
|
||||
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
|
||||
opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
|
||||
opts.optflag("", "clean", "clean output directory");
|
||||
opts.optflag("h", "help", "print this help message");
|
||||
|
||||
let usage = |n| -> ! {
|
||||
let brief = format!("Usage: rust.py [options]");
|
||||
print!("{}", opts.usage(&brief));
|
||||
let usage = |n, opts: &Options| -> ! {
|
||||
let command = args.get(0).map(|s| &**s);
|
||||
let brief = format!("Usage: x.py {} [options] [<args>...]",
|
||||
command.unwrap_or("<command>"));
|
||||
|
||||
println!("{}", opts.usage(&brief));
|
||||
match command {
|
||||
Some("build") => {
|
||||
println!("\
|
||||
Arguments:
|
||||
This subcommand accepts a number of positional arguments of directories to
|
||||
the crates and/or artifacts to compile. For example:
|
||||
|
||||
./x.py build src/libcore
|
||||
./x.py build src/libproc_macro
|
||||
./x.py build src/libstd --stage 1
|
||||
|
||||
If no arguments are passed then the complete artifacts for that stage are
|
||||
also compiled.
|
||||
|
||||
./x.py build
|
||||
./x.py build --stage 1
|
||||
|
||||
For a quick build with a usable compile, you can pass:
|
||||
|
||||
./x.py build --stage 1 src/libtest
|
||||
");
|
||||
}
|
||||
|
||||
Some("test") => {
|
||||
println!("\
|
||||
Arguments:
|
||||
This subcommand accepts a number of positional arguments of directories to
|
||||
tests that should be compiled and run. For example:
|
||||
|
||||
./x.py test src/test/run-pass
|
||||
./x.py test src/test/run-pass/assert-*
|
||||
./x.py test src/libstd --test-args hash_map
|
||||
./x.py test src/libstd --stage 0
|
||||
|
||||
If no arguments are passed then the complete artifacts for that stage are
|
||||
compiled and tested.
|
||||
|
||||
./x.py test
|
||||
./x.py test --stage 1
|
||||
");
|
||||
}
|
||||
|
||||
Some("doc") => {
|
||||
println!("\
|
||||
Arguments:
|
||||
This subcommand accepts a number of positional arguments of directories of
|
||||
documentation to build. For example:
|
||||
|
||||
./x.py doc src/doc/book
|
||||
./x.py doc src/doc/nomicon
|
||||
./x.py doc src/libstd
|
||||
|
||||
If no arguments are passed then everything is documented:
|
||||
|
||||
./x.py doc
|
||||
./x.py doc --stage 1
|
||||
");
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let Some(command) = command {
|
||||
if command == "build" ||
|
||||
command == "dist" ||
|
||||
command == "doc" ||
|
||||
command == "test" ||
|
||||
command == "clean" {
|
||||
println!("Available invocations:");
|
||||
if args.iter().any(|a| a == "-v") {
|
||||
let flags = Flags::parse(&["build".to_string()]);
|
||||
let mut config = Config::default();
|
||||
config.build = flags.build.clone();
|
||||
let mut build = Build::new(flags, config);
|
||||
metadata::build(&mut build);
|
||||
step::build_rules(&build).print_help(command);
|
||||
} else {
|
||||
println!(" ... elided, run `./x.py {} -h -v` to see",
|
||||
command);
|
||||
}
|
||||
|
||||
println!("");
|
||||
}
|
||||
}
|
||||
|
||||
println!("\
|
||||
Subcommands:
|
||||
build Compile either the compiler or libraries
|
||||
test Build and run some test suites
|
||||
doc Build documentation
|
||||
clean Clean out build directories
|
||||
dist Build and/or install distribution artifacts
|
||||
|
||||
To learn more about a subcommand, run `./x.py <command> -h`
|
||||
");
|
||||
|
||||
process::exit(n);
|
||||
};
|
||||
|
||||
let m = opts.parse(args).unwrap_or_else(|e| {
|
||||
println!("failed to parse options: {}", e);
|
||||
usage(1);
|
||||
});
|
||||
if m.opt_present("h") {
|
||||
usage(0);
|
||||
if args.len() == 0 {
|
||||
println!("a command must be passed");
|
||||
usage(1, &opts);
|
||||
}
|
||||
let parse = |opts: &Options| {
|
||||
let m = opts.parse(&args[1..]).unwrap_or_else(|e| {
|
||||
println!("failed to parse options: {}", e);
|
||||
usage(1, opts);
|
||||
});
|
||||
if m.opt_present("h") {
|
||||
usage(0, opts);
|
||||
}
|
||||
return m
|
||||
};
|
||||
|
||||
let cwd = t!(env::current_dir());
|
||||
let remaining_as_path = |m: &Matches| {
|
||||
m.free.iter().map(|p| cwd.join(p)).collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
let m: Matches;
|
||||
let cmd = match &args[0][..] {
|
||||
"build" => {
|
||||
m = parse(&opts);
|
||||
Subcommand::Build { paths: remaining_as_path(&m) }
|
||||
}
|
||||
"doc" => {
|
||||
m = parse(&opts);
|
||||
Subcommand::Doc { paths: remaining_as_path(&m) }
|
||||
}
|
||||
"test" => {
|
||||
opts.optmulti("", "test-args", "extra arguments", "ARGS");
|
||||
m = parse(&opts);
|
||||
Subcommand::Test {
|
||||
paths: remaining_as_path(&m),
|
||||
test_args: m.opt_strs("test-args"),
|
||||
}
|
||||
}
|
||||
"clean" => {
|
||||
m = parse(&opts);
|
||||
if m.free.len() > 0 {
|
||||
println!("clean takes no arguments");
|
||||
usage(1, &opts);
|
||||
}
|
||||
Subcommand::Clean
|
||||
}
|
||||
"dist" => {
|
||||
opts.optflag("", "install", "run installer as well");
|
||||
m = parse(&opts);
|
||||
Subcommand::Dist {
|
||||
install: m.opt_present("install"),
|
||||
}
|
||||
}
|
||||
cmd => {
|
||||
println!("unknown command: {}", cmd);
|
||||
usage(1, &opts);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| {
|
||||
if fs::metadata("config.toml").is_ok() {
|
||||
@@ -78,26 +242,27 @@ pub fn parse(args: &[String]) -> Flags {
|
||||
|
||||
Flags {
|
||||
verbose: m.opt_present("v"),
|
||||
clean: m.opt_present("clean"),
|
||||
stage: m.opt_str("stage").map(|j| j.parse().unwrap()),
|
||||
build: m.opt_str("build").unwrap(),
|
||||
host: Filter { values: m.opt_strs("host") },
|
||||
target: Filter { values: m.opt_strs("target") },
|
||||
step: m.opt_strs("step"),
|
||||
build: m.opt_str("build").unwrap_or_else(|| {
|
||||
env::var("BUILD").unwrap()
|
||||
}),
|
||||
host: m.opt_strs("host"),
|
||||
target: m.opt_strs("target"),
|
||||
config: cfg_file,
|
||||
src: m.opt_str("src").map(PathBuf::from),
|
||||
jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()),
|
||||
args: m.free.clone(),
|
||||
cmd: cmd,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Filter {
|
||||
pub fn contains(&self, name: &str) -> bool {
|
||||
self.values.len() == 0 || self.values.iter().any(|s| s == name)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> slice::Iter<String> {
|
||||
self.values.iter()
|
||||
impl Subcommand {
|
||||
pub fn test_args(&self) -> Vec<&str> {
|
||||
match *self {
|
||||
Subcommand::Test { ref test_args, .. } => {
|
||||
test_args.iter().flat_map(|s| s.split_whitespace()).collect()
|
||||
}
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-245
@@ -57,6 +57,7 @@ macro_rules! t {
|
||||
mod check;
|
||||
mod clean;
|
||||
mod compile;
|
||||
mod metadata;
|
||||
mod config;
|
||||
mod dist;
|
||||
mod doc;
|
||||
@@ -76,7 +77,7 @@ pub unsafe fn setup() {}
|
||||
}
|
||||
|
||||
pub use config::Config;
|
||||
pub use flags::Flags;
|
||||
pub use flags::{Flags, Subcommand};
|
||||
|
||||
/// A structure representing a Rust compiler.
|
||||
///
|
||||
@@ -130,6 +131,17 @@ pub struct Build {
|
||||
// Runtime state filled in later on
|
||||
cc: HashMap<String, (gcc::Tool, Option<PathBuf>)>,
|
||||
cxx: HashMap<String, gcc::Tool>,
|
||||
crates: HashMap<String, Crate>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Crate {
|
||||
name: String,
|
||||
deps: Vec<String>,
|
||||
path: PathBuf,
|
||||
doc_step: String,
|
||||
build_step: String,
|
||||
test_step: String,
|
||||
}
|
||||
|
||||
/// The various "modes" of invoking Cargo.
|
||||
@@ -162,7 +174,9 @@ impl Build {
|
||||
/// By default all build output will be placed in the current directory.
|
||||
pub fn new(flags: Flags, config: Config) -> Build {
|
||||
let cwd = t!(env::current_dir());
|
||||
let src = flags.src.clone().unwrap_or(cwd.clone());
|
||||
let src = flags.src.clone().or_else(|| {
|
||||
env::var_os("SRC").map(|x| x.into())
|
||||
}).unwrap_or(cwd.clone());
|
||||
let out = cwd.join("build");
|
||||
|
||||
let stage0_root = out.join(&config.build).join("stage0/bin");
|
||||
@@ -196,6 +210,7 @@ pub fn new(flags: Flags, config: Config) -> Build {
|
||||
package_vers: String::new(),
|
||||
cc: HashMap::new(),
|
||||
cxx: HashMap::new(),
|
||||
crates: HashMap::new(),
|
||||
gdb_version: None,
|
||||
lldb_version: None,
|
||||
lldb_python_dir: None,
|
||||
@@ -204,13 +219,11 @@ pub fn new(flags: Flags, config: Config) -> Build {
|
||||
|
||||
/// Executes the entire build, as configured by the flags and configuration.
|
||||
pub fn build(&mut self) {
|
||||
use step::Source::*;
|
||||
|
||||
unsafe {
|
||||
job::setup();
|
||||
}
|
||||
|
||||
if self.flags.clean {
|
||||
if let Subcommand::Clean = self.flags.cmd {
|
||||
return clean::clean(self);
|
||||
}
|
||||
|
||||
@@ -232,247 +245,10 @@ pub fn build(&mut self) {
|
||||
}
|
||||
self.verbose("updating submodules");
|
||||
self.update_submodules();
|
||||
self.verbose("learning about cargo");
|
||||
metadata::build(self);
|
||||
|
||||
// The main loop of the build system.
|
||||
//
|
||||
// The `step::all` function returns a topographically sorted list of all
|
||||
// steps that need to be executed as part of this build. Each step has a
|
||||
// corresponding entry in `step.rs` and indicates some unit of work that
|
||||
// needs to be done as part of the build.
|
||||
//
|
||||
// Almost all of these are simple one-liners that shell out to the
|
||||
// corresponding functionality in the extra modules, where more
|
||||
// documentation can be found.
|
||||
let steps = step::all(self);
|
||||
|
||||
self.verbose("bootstrap build plan:");
|
||||
for step in &steps {
|
||||
self.verbose(&format!("{:?}", step));
|
||||
}
|
||||
|
||||
for target in steps {
|
||||
let doc_out = self.out.join(&target.target).join("doc");
|
||||
match target.src {
|
||||
Llvm { _dummy } => {
|
||||
native::llvm(self, target.target);
|
||||
}
|
||||
TestHelpers { _dummy } => {
|
||||
native::test_helpers(self, target.target);
|
||||
}
|
||||
Libstd { compiler } => {
|
||||
compile::std(self, target.target, &compiler);
|
||||
}
|
||||
Libtest { compiler } => {
|
||||
compile::test(self, target.target, &compiler);
|
||||
}
|
||||
Librustc { compiler } => {
|
||||
compile::rustc(self, target.target, &compiler);
|
||||
}
|
||||
LibstdLink { compiler, host } => {
|
||||
compile::std_link(self, target.target, &compiler, host);
|
||||
}
|
||||
LibtestLink { compiler, host } => {
|
||||
compile::test_link(self, target.target, &compiler, host);
|
||||
}
|
||||
LibrustcLink { compiler, host } => {
|
||||
compile::rustc_link(self, target.target, &compiler, host);
|
||||
}
|
||||
Rustc { stage: 0 } => {
|
||||
// nothing to do...
|
||||
}
|
||||
Rustc { stage } => {
|
||||
compile::assemble_rustc(self, stage, target.target);
|
||||
}
|
||||
ToolLinkchecker { stage } => {
|
||||
compile::tool(self, stage, target.target, "linkchecker");
|
||||
}
|
||||
ToolRustbook { stage } => {
|
||||
compile::tool(self, stage, target.target, "rustbook");
|
||||
}
|
||||
ToolErrorIndex { stage } => {
|
||||
compile::tool(self, stage, target.target,
|
||||
"error_index_generator");
|
||||
}
|
||||
ToolCargoTest { stage } => {
|
||||
compile::tool(self, stage, target.target, "cargotest");
|
||||
}
|
||||
ToolTidy { stage } => {
|
||||
compile::tool(self, stage, target.target, "tidy");
|
||||
}
|
||||
ToolCompiletest { stage } => {
|
||||
compile::tool(self, stage, target.target, "compiletest");
|
||||
}
|
||||
DocBook { stage } => {
|
||||
doc::rustbook(self, stage, target.target, "book", &doc_out);
|
||||
}
|
||||
DocNomicon { stage } => {
|
||||
doc::rustbook(self, stage, target.target, "nomicon",
|
||||
&doc_out);
|
||||
}
|
||||
DocStandalone { stage } => {
|
||||
doc::standalone(self, stage, target.target, &doc_out);
|
||||
}
|
||||
DocStd { stage } => {
|
||||
doc::std(self, stage, target.target, &doc_out);
|
||||
}
|
||||
DocTest { stage } => {
|
||||
doc::test(self, stage, target.target, &doc_out);
|
||||
}
|
||||
DocRustc { stage } => {
|
||||
doc::rustc(self, stage, target.target, &doc_out);
|
||||
}
|
||||
DocErrorIndex { stage } => {
|
||||
doc::error_index(self, stage, target.target, &doc_out);
|
||||
}
|
||||
|
||||
CheckLinkcheck { stage } => {
|
||||
check::linkcheck(self, stage, target.target);
|
||||
}
|
||||
CheckCargoTest { stage } => {
|
||||
check::cargotest(self, stage, target.target);
|
||||
}
|
||||
CheckTidy { stage } => {
|
||||
check::tidy(self, stage, target.target);
|
||||
}
|
||||
CheckRPass { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"run-pass", "run-pass");
|
||||
}
|
||||
CheckRPassFull { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"run-pass", "run-pass-fulldeps");
|
||||
}
|
||||
CheckCFail { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"compile-fail", "compile-fail");
|
||||
}
|
||||
CheckCFailFull { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"compile-fail", "compile-fail-fulldeps")
|
||||
}
|
||||
CheckPFail { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"parse-fail", "parse-fail");
|
||||
}
|
||||
CheckRFail { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"run-fail", "run-fail");
|
||||
}
|
||||
CheckRFailFull { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"run-fail", "run-fail-fulldeps");
|
||||
}
|
||||
CheckPretty { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"pretty", "pretty");
|
||||
}
|
||||
CheckPrettyRPass { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"pretty", "run-pass");
|
||||
}
|
||||
CheckPrettyRPassFull { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"pretty", "run-pass-fulldeps");
|
||||
}
|
||||
CheckPrettyRFail { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"pretty", "run-fail");
|
||||
}
|
||||
CheckPrettyRFailFull { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"pretty", "run-fail-fulldeps");
|
||||
}
|
||||
CheckPrettyRPassValgrind { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"pretty", "run-pass-valgrind");
|
||||
}
|
||||
CheckMirOpt { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"mir-opt", "mir-opt");
|
||||
}
|
||||
CheckCodegen { compiler } => {
|
||||
if self.config.codegen_tests {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"codegen", "codegen");
|
||||
}
|
||||
}
|
||||
CheckCodegenUnits { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"codegen-units", "codegen-units");
|
||||
}
|
||||
CheckIncremental { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"incremental", "incremental");
|
||||
}
|
||||
CheckUi { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"ui", "ui");
|
||||
}
|
||||
CheckDebuginfo { compiler } => {
|
||||
if target.target.contains("msvc") {
|
||||
// nothing to do
|
||||
} else if target.target.contains("apple") {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"debuginfo-lldb", "debuginfo");
|
||||
} else {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"debuginfo-gdb", "debuginfo");
|
||||
}
|
||||
}
|
||||
CheckRustdoc { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"rustdoc", "rustdoc");
|
||||
}
|
||||
CheckRPassValgrind { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"run-pass-valgrind", "run-pass-valgrind");
|
||||
}
|
||||
CheckDocs { compiler } => {
|
||||
check::docs(self, &compiler);
|
||||
}
|
||||
CheckErrorIndex { compiler } => {
|
||||
check::error_index(self, &compiler);
|
||||
}
|
||||
CheckRMake { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"run-make", "run-make")
|
||||
}
|
||||
CheckCrateStd { compiler } => {
|
||||
check::krate(self, &compiler, target.target, Mode::Libstd)
|
||||
}
|
||||
CheckCrateTest { compiler } => {
|
||||
check::krate(self, &compiler, target.target, Mode::Libtest)
|
||||
}
|
||||
CheckCrateRustc { compiler } => {
|
||||
check::krate(self, &compiler, target.target, Mode::Librustc)
|
||||
}
|
||||
|
||||
DistDocs { stage } => dist::docs(self, stage, target.target),
|
||||
DistMingw { _dummy } => dist::mingw(self, target.target),
|
||||
DistRustc { stage } => dist::rustc(self, stage, target.target),
|
||||
DistStd { compiler } => dist::std(self, &compiler, target.target),
|
||||
DistSrc { _dummy } => dist::rust_src(self),
|
||||
|
||||
Install { stage } => install::install(self, stage, target.target),
|
||||
|
||||
DebuggerScripts { stage } => {
|
||||
let compiler = Compiler::new(stage, target.target);
|
||||
dist::debugger_scripts(self,
|
||||
&self.sysroot(&compiler),
|
||||
target.target);
|
||||
}
|
||||
|
||||
AndroidCopyLibs { compiler } => {
|
||||
check::android_copy_libs(self, &compiler, target.target);
|
||||
}
|
||||
|
||||
// pseudo-steps
|
||||
Dist { .. } |
|
||||
Doc { .. } |
|
||||
CheckTarget { .. } |
|
||||
Check { .. } => {}
|
||||
}
|
||||
}
|
||||
step::run(self);
|
||||
}
|
||||
|
||||
/// Updates all git submodules that we have.
|
||||
@@ -812,6 +588,11 @@ fn llvm_out(&self, target: &str) -> PathBuf {
|
||||
self.out.join(target).join("llvm")
|
||||
}
|
||||
|
||||
/// Output directory for all documentation for a target
|
||||
fn doc_out(&self, target: &str) -> PathBuf {
|
||||
self.out.join(target).join("doc")
|
||||
}
|
||||
|
||||
/// Returns true if no custom `llvm-config` is set for the specified target.
|
||||
///
|
||||
/// If no custom `llvm-config` was specified then Rust's llvm will be used.
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::process::Command;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use build_helper::output;
|
||||
use rustc_serialize::json;
|
||||
|
||||
use {Build, Crate};
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct Output {
|
||||
packages: Vec<Package>,
|
||||
resolve: Resolve,
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct Package {
|
||||
id: String,
|
||||
name: String,
|
||||
source: Option<String>,
|
||||
manifest_path: String,
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct Resolve {
|
||||
nodes: Vec<ResolveNode>,
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct ResolveNode {
|
||||
id: String,
|
||||
dependencies: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn build(build: &mut Build) {
|
||||
build_krate(build, "src/rustc/std_shim");
|
||||
build_krate(build, "src/rustc/test_shim");
|
||||
build_krate(build, "src/rustc");
|
||||
}
|
||||
|
||||
fn build_krate(build: &mut Build, krate: &str) {
|
||||
// Run `cargo metadata` to figure out what crates we're testing.
|
||||
//
|
||||
// Down below we're going to call `cargo test`, but to test the right set
|
||||
// of packages we're going to have to know what `-p` arguments to pass it
|
||||
// to know what crates to test. Here we run `cargo metadata` to learn about
|
||||
// the dependency graph and what `-p` arguments there are.
|
||||
let mut cargo = Command::new(&build.cargo);
|
||||
cargo.arg("metadata")
|
||||
.arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml"));
|
||||
let output = output(&mut cargo);
|
||||
let output: Output = json::decode(&output).unwrap();
|
||||
let mut id2name = HashMap::new();
|
||||
for package in output.packages {
|
||||
if package.source.is_none() {
|
||||
id2name.insert(package.id, package.name.clone());
|
||||
let mut path = PathBuf::from(package.manifest_path);
|
||||
path.pop();
|
||||
build.crates.insert(package.name.clone(), Crate {
|
||||
build_step: format!("build-crate-{}", package.name),
|
||||
doc_step: format!("doc-crate-{}", package.name),
|
||||
test_step: format!("test-crate-{}", package.name),
|
||||
name: package.name,
|
||||
deps: Vec::new(),
|
||||
path: path,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for node in output.resolve.nodes {
|
||||
let name = match id2name.get(&node.id) {
|
||||
Some(name) => name,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let krate = build.crates.get_mut(name).unwrap();
|
||||
for dep in node.dependencies.iter() {
|
||||
let dep = match id2name.get(dep) {
|
||||
Some(dep) => dep,
|
||||
None => continue,
|
||||
};
|
||||
krate.deps.push(dep.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,47 +17,46 @@ else
|
||||
BOOTSTRAP_ARGS :=
|
||||
endif
|
||||
|
||||
BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py $(BOOTSTRAP_ARGS)
|
||||
BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py
|
||||
|
||||
all:
|
||||
$(Q)$(BOOTSTRAP)
|
||||
$(Q)$(BOOTSTRAP) build $(BOOTSTRAP_ARGS)
|
||||
$(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS)
|
||||
|
||||
# Don’t use $(Q) here, always show how to invoke the bootstrap script directly
|
||||
help:
|
||||
$(BOOTSTRAP) --help
|
||||
|
||||
clean:
|
||||
$(Q)$(BOOTSTRAP) --clean
|
||||
$(Q)$(BOOTSTRAP) clean $(BOOTSTRAP_ARGS)
|
||||
|
||||
rustc-stage1:
|
||||
$(Q)$(BOOTSTRAP) --step libtest --stage 1
|
||||
$(Q)$(BOOTSTRAP) build --stage 1 src/libtest $(BOOTSTRAP_ARGS)
|
||||
rustc-stage2:
|
||||
$(Q)$(BOOTSTRAP) --step libtest --stage 2
|
||||
$(Q)$(BOOTSTRAP) build --stage 2 src/libtest $(BOOTSTRAP_ARGS)
|
||||
|
||||
docs: doc
|
||||
doc:
|
||||
$(Q)$(BOOTSTRAP) --step doc
|
||||
style:
|
||||
$(Q)$(BOOTSTRAP) --step doc-style
|
||||
$(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS)
|
||||
nomicon:
|
||||
$(Q)$(BOOTSTRAP) --step doc-nomicon
|
||||
$(Q)$(BOOTSTRAP) doc src/doc/nomicon $(BOOTSTRAP_ARGS)
|
||||
book:
|
||||
$(Q)$(BOOTSTRAP) --step doc-book
|
||||
$(Q)$(BOOTSTRAP) doc src/doc/book $(BOOTSTRAP_ARGS)
|
||||
standalone-docs:
|
||||
$(Q)$(BOOTSTRAP) --step doc-standalone
|
||||
$(Q)$(BOOTSTRAP) doc src/doc $(BOOTSTRAP_ARGS)
|
||||
check:
|
||||
$(Q)$(BOOTSTRAP) --step check
|
||||
$(Q)$(BOOTSTRAP) test $(BOOTSTRAP_ARGS)
|
||||
check-cargotest:
|
||||
$(Q)$(BOOTSTRAP) --step check-cargotest
|
||||
$(Q)$(BOOTSTRAP) test src/tools/cargotest $(BOOTSTRAP_ARGS)
|
||||
dist:
|
||||
$(Q)$(BOOTSTRAP) --step dist
|
||||
$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
|
||||
install:
|
||||
ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
|
||||
$(Q)echo "'sudo make install' is not supported currently."
|
||||
else
|
||||
$(Q)$(BOOTSTRAP) --step install
|
||||
$(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS)
|
||||
endif
|
||||
tidy:
|
||||
$(Q)$(BOOTSTRAP) --step check-tidy --stage 0
|
||||
$(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS)
|
||||
|
||||
.PHONY: dist
|
||||
|
||||
+657
-574
@@ -8,600 +8,683 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Major workhorse of rustbuild, definition and dependencies between stages of
|
||||
//! the copmile.
|
||||
//!
|
||||
//! The primary purpose of this module is to define the various `Step`s of
|
||||
//! execution of the build. Each `Step` has a corresponding `Source` indicating
|
||||
//! what it's actually doing along with a number of dependencies which must be
|
||||
//! executed first.
|
||||
//!
|
||||
//! This module will take the CLI as input and calculate the steps required for
|
||||
//! the build requested, ensuring that all intermediate pieces are in place.
|
||||
//! Essentially this module is a `make`-replacement, but not as good.
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::mem;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use check;
|
||||
use compile;
|
||||
use dist;
|
||||
use doc;
|
||||
use flags::Subcommand;
|
||||
use install;
|
||||
use native;
|
||||
use {Compiler, Build, Mode};
|
||||
|
||||
use {Build, Compiler};
|
||||
|
||||
#[derive(Hash, Eq, PartialEq, Clone, Debug)]
|
||||
pub struct Step<'a> {
|
||||
pub src: Source<'a>,
|
||||
pub target: &'a str,
|
||||
}
|
||||
|
||||
/// Macro used to iterate over all targets that are recognized by the build
|
||||
/// system.
|
||||
///
|
||||
/// Whenever a new step is added it will involve adding an entry here, updating
|
||||
/// the dependencies section below, and then adding an implementation of the
|
||||
/// step in `build/mod.rs`.
|
||||
///
|
||||
/// This macro takes another macro as an argument and then calls that macro with
|
||||
/// all steps that the build system knows about.
|
||||
macro_rules! targets {
|
||||
($m:ident) => {
|
||||
$m! {
|
||||
// Step representing building the stageN compiler. This is just the
|
||||
// compiler executable itself, not any of the support libraries
|
||||
(rustc, Rustc { stage: u32 }),
|
||||
|
||||
// Steps for the two main cargo builds. These are parameterized over
|
||||
// the compiler which is producing the artifact.
|
||||
(libstd, Libstd { compiler: Compiler<'a> }),
|
||||
(libtest, Libtest { compiler: Compiler<'a> }),
|
||||
(librustc, Librustc { compiler: Compiler<'a> }),
|
||||
|
||||
// Links the target produced by the compiler provided into the
|
||||
// host's directory also provided.
|
||||
(libstd_link, LibstdLink {
|
||||
compiler: Compiler<'a>,
|
||||
host: &'a str
|
||||
}),
|
||||
(libtest_link, LibtestLink {
|
||||
compiler: Compiler<'a>,
|
||||
host: &'a str
|
||||
}),
|
||||
(librustc_link, LibrustcLink {
|
||||
compiler: Compiler<'a>,
|
||||
host: &'a str
|
||||
}),
|
||||
|
||||
// Various tools that we can build as part of the build.
|
||||
(tool_linkchecker, ToolLinkchecker { stage: u32 }),
|
||||
(tool_rustbook, ToolRustbook { stage: u32 }),
|
||||
(tool_error_index, ToolErrorIndex { stage: u32 }),
|
||||
(tool_cargotest, ToolCargoTest { stage: u32 }),
|
||||
(tool_tidy, ToolTidy { stage: u32 }),
|
||||
(tool_compiletest, ToolCompiletest { stage: u32 }),
|
||||
|
||||
// Steps for long-running native builds. Ideally these wouldn't
|
||||
// actually exist and would be part of build scripts, but for now
|
||||
// these are here.
|
||||
//
|
||||
// There aren't really any parameters to this, but empty structs
|
||||
// with braces are unstable so we just pick something that works.
|
||||
(llvm, Llvm { _dummy: () }),
|
||||
(test_helpers, TestHelpers { _dummy: () }),
|
||||
(debugger_scripts, DebuggerScripts { stage: u32 }),
|
||||
|
||||
// Steps for various pieces of documentation that we can generate,
|
||||
// the 'doc' step is just a pseudo target to depend on a bunch of
|
||||
// others.
|
||||
(doc, Doc { stage: u32 }),
|
||||
(doc_book, DocBook { stage: u32 }),
|
||||
(doc_nomicon, DocNomicon { stage: u32 }),
|
||||
(doc_standalone, DocStandalone { stage: u32 }),
|
||||
(doc_std, DocStd { stage: u32 }),
|
||||
(doc_test, DocTest { stage: u32 }),
|
||||
(doc_rustc, DocRustc { stage: u32 }),
|
||||
(doc_error_index, DocErrorIndex { stage: u32 }),
|
||||
|
||||
// Steps for running tests. The 'check' target is just a pseudo
|
||||
// target to depend on a bunch of others.
|
||||
(check, Check { stage: u32, compiler: Compiler<'a> }),
|
||||
(check_target, CheckTarget { stage: u32, compiler: Compiler<'a> }),
|
||||
(check_linkcheck, CheckLinkcheck { stage: u32 }),
|
||||
(check_cargotest, CheckCargoTest { stage: u32 }),
|
||||
(check_tidy, CheckTidy { stage: u32 }),
|
||||
(check_rpass, CheckRPass { compiler: Compiler<'a> }),
|
||||
(check_rpass_full, CheckRPassFull { compiler: Compiler<'a> }),
|
||||
(check_rpass_valgrind, CheckRPassValgrind { compiler: Compiler<'a> }),
|
||||
(check_rfail, CheckRFail { compiler: Compiler<'a> }),
|
||||
(check_rfail_full, CheckRFailFull { compiler: Compiler<'a> }),
|
||||
(check_cfail, CheckCFail { compiler: Compiler<'a> }),
|
||||
(check_cfail_full, CheckCFailFull { compiler: Compiler<'a> }),
|
||||
(check_pfail, CheckPFail { compiler: Compiler<'a> }),
|
||||
(check_pretty, CheckPretty { compiler: Compiler<'a> }),
|
||||
(check_pretty_rpass, CheckPrettyRPass { compiler: Compiler<'a> }),
|
||||
(check_pretty_rpass_full, CheckPrettyRPassFull { compiler: Compiler<'a> }),
|
||||
(check_pretty_rfail, CheckPrettyRFail { compiler: Compiler<'a> }),
|
||||
(check_pretty_rfail_full, CheckPrettyRFailFull { compiler: Compiler<'a> }),
|
||||
(check_pretty_rpass_valgrind, CheckPrettyRPassValgrind { compiler: Compiler<'a> }),
|
||||
(check_codegen, CheckCodegen { compiler: Compiler<'a> }),
|
||||
(check_codegen_units, CheckCodegenUnits { compiler: Compiler<'a> }),
|
||||
(check_incremental, CheckIncremental { compiler: Compiler<'a> }),
|
||||
(check_ui, CheckUi { compiler: Compiler<'a> }),
|
||||
(check_mir_opt, CheckMirOpt { compiler: Compiler<'a> }),
|
||||
(check_debuginfo, CheckDebuginfo { compiler: Compiler<'a> }),
|
||||
(check_rustdoc, CheckRustdoc { compiler: Compiler<'a> }),
|
||||
(check_docs, CheckDocs { compiler: Compiler<'a> }),
|
||||
(check_error_index, CheckErrorIndex { compiler: Compiler<'a> }),
|
||||
(check_rmake, CheckRMake { compiler: Compiler<'a> }),
|
||||
(check_crate_std, CheckCrateStd { compiler: Compiler<'a> }),
|
||||
(check_crate_test, CheckCrateTest { compiler: Compiler<'a> }),
|
||||
(check_crate_rustc, CheckCrateRustc { compiler: Compiler<'a> }),
|
||||
|
||||
// Distribution targets, creating tarballs
|
||||
(dist, Dist { stage: u32 }),
|
||||
(dist_docs, DistDocs { stage: u32 }),
|
||||
(dist_mingw, DistMingw { _dummy: () }),
|
||||
(dist_rustc, DistRustc { stage: u32 }),
|
||||
(dist_std, DistStd { compiler: Compiler<'a> }),
|
||||
(dist_src, DistSrc { _dummy: () }),
|
||||
|
||||
// install target
|
||||
(install, Install { stage: u32 }),
|
||||
|
||||
// Misc targets
|
||||
(android_copy_libs, AndroidCopyLibs { compiler: Compiler<'a> }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Define the `Source` enum by iterating over all the steps and peeling out just
|
||||
// the types that we want to define.
|
||||
|
||||
macro_rules! item { ($a:item) => ($a) }
|
||||
|
||||
macro_rules! define_source {
|
||||
($(($short:ident, $name:ident { $($args:tt)* }),)*) => {
|
||||
item! {
|
||||
#[derive(Hash, Eq, PartialEq, Clone, Debug)]
|
||||
pub enum Source<'a> {
|
||||
$($name { $($args)* }),*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
targets!(define_source);
|
||||
|
||||
/// Calculate a list of all steps described by `build`.
|
||||
///
|
||||
/// This will inspect the flags passed in on the command line and use that to
|
||||
/// build up a list of steps to execute. These steps will then be transformed
|
||||
/// into a topologically sorted list which when executed left-to-right will
|
||||
/// correctly sequence the entire build.
|
||||
pub fn all(build: &Build) -> Vec<Step> {
|
||||
build.verbose("inferred build steps:");
|
||||
|
||||
let mut ret = Vec::new();
|
||||
let mut all = HashSet::new();
|
||||
for target in top_level(build) {
|
||||
fill(build, &target, &mut ret, &mut all);
|
||||
}
|
||||
return ret;
|
||||
|
||||
fn fill<'a>(build: &'a Build,
|
||||
target: &Step<'a>,
|
||||
ret: &mut Vec<Step<'a>>,
|
||||
set: &mut HashSet<Step<'a>>) {
|
||||
if set.insert(target.clone()) {
|
||||
for dep in target.deps(build) {
|
||||
build.verbose(&format!("{:?}\n -> {:?}", target, dep));
|
||||
fill(build, &dep, ret, set);
|
||||
}
|
||||
ret.push(target.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines what top-level targets are requested as part of this build,
|
||||
/// returning them as a list.
|
||||
fn top_level(build: &Build) -> Vec<Step> {
|
||||
let mut targets = Vec::new();
|
||||
let stage = build.flags.stage.unwrap_or(2);
|
||||
|
||||
let host = Step {
|
||||
src: Source::Llvm { _dummy: () },
|
||||
target: build.flags.host.iter().next()
|
||||
.unwrap_or(&build.config.build),
|
||||
};
|
||||
let target = Step {
|
||||
src: Source::Llvm { _dummy: () },
|
||||
target: build.flags.target.iter().next().map(|x| &x[..])
|
||||
.unwrap_or(host.target)
|
||||
};
|
||||
|
||||
// First, try to find steps on the command line.
|
||||
add_steps(build, stage, &host, &target, &mut targets);
|
||||
|
||||
// If none are specified, then build everything.
|
||||
if targets.len() == 0 {
|
||||
let t = Step {
|
||||
src: Source::Llvm { _dummy: () },
|
||||
target: &build.config.build,
|
||||
};
|
||||
if build.config.docs {
|
||||
targets.push(t.doc(stage));
|
||||
}
|
||||
for host in build.config.host.iter() {
|
||||
if !build.flags.host.contains(host) {
|
||||
continue
|
||||
}
|
||||
let host = t.target(host);
|
||||
if host.target == build.config.build {
|
||||
targets.push(host.librustc(host.compiler(stage)));
|
||||
} else {
|
||||
targets.push(host.librustc_link(t.compiler(stage), host.target));
|
||||
}
|
||||
for target in build.config.target.iter() {
|
||||
if !build.flags.target.contains(target) {
|
||||
continue
|
||||
}
|
||||
|
||||
if host.target == build.config.build {
|
||||
targets.push(host.target(target)
|
||||
.libtest(host.compiler(stage)));
|
||||
} else {
|
||||
targets.push(host.target(target)
|
||||
.libtest_link(t.compiler(stage), host.target));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
targets
|
||||
}
|
||||
|
||||
fn add_steps<'a>(build: &'a Build,
|
||||
stage: u32,
|
||||
host: &Step<'a>,
|
||||
target: &Step<'a>,
|
||||
targets: &mut Vec<Step<'a>>) {
|
||||
struct Context<'a> {
|
||||
stage: u32,
|
||||
compiler: Compiler<'a>,
|
||||
_dummy: (),
|
||||
host: &'a str,
|
||||
}
|
||||
for step in build.flags.step.iter() {
|
||||
|
||||
// The macro below insists on hygienic access to all local variables, so
|
||||
// we shove them all in a struct and subvert hygiene by accessing struct
|
||||
// fields instead,
|
||||
let cx = Context {
|
||||
stage: stage,
|
||||
compiler: host.target(&build.config.build).compiler(stage),
|
||||
_dummy: (),
|
||||
host: host.target,
|
||||
};
|
||||
macro_rules! add_step {
|
||||
($(($short:ident, $name:ident { $($arg:ident: $t:ty),* }),)*) => ({$(
|
||||
let name = stringify!($short).replace("_", "-");
|
||||
if &step[..] == &name[..] {
|
||||
targets.push(target.$short($(cx.$arg),*));
|
||||
continue
|
||||
}
|
||||
drop(name);
|
||||
)*})
|
||||
}
|
||||
|
||||
targets!(add_step);
|
||||
|
||||
panic!("unknown step: {}", step);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! constructors {
|
||||
($(($short:ident, $name:ident { $($arg:ident: $t:ty),* }),)*) => {$(
|
||||
fn $short(&self, $($arg: $t),*) -> Step<'a> {
|
||||
Step {
|
||||
src: Source::$name { $($arg: $arg),* },
|
||||
target: self.target,
|
||||
}
|
||||
}
|
||||
)*}
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
||||
struct Step<'a> {
|
||||
name: &'a str,
|
||||
stage: u32,
|
||||
host: &'a str,
|
||||
target: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> Step<'a> {
|
||||
fn compiler(&self, stage: u32) -> Compiler<'a> {
|
||||
Compiler::new(stage, self.target)
|
||||
fn name(&self, name: &'a str) -> Step<'a> {
|
||||
Step { name: name, ..*self }
|
||||
}
|
||||
|
||||
fn stage(&self, stage: u32) -> Step<'a> {
|
||||
Step { stage: stage, ..*self }
|
||||
}
|
||||
|
||||
fn host(&self, host: &'a str) -> Step<'a> {
|
||||
Step { host: host, ..*self }
|
||||
}
|
||||
|
||||
fn target(&self, target: &'a str) -> Step<'a> {
|
||||
Step { target: target, src: self.src.clone() }
|
||||
Step { target: target, ..*self }
|
||||
}
|
||||
|
||||
// Define ergonomic constructors for each step defined above so they can be
|
||||
// easily constructed.
|
||||
targets!(constructors);
|
||||
fn compiler(&self) -> Compiler<'a> {
|
||||
Compiler::new(self.stage, self.host)
|
||||
}
|
||||
}
|
||||
|
||||
/// Mapping of all dependencies for rustbuild.
|
||||
///
|
||||
/// This function receives a step, the build that we're building for, and
|
||||
/// then returns a list of all the dependencies of that step.
|
||||
pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
|
||||
match self.src {
|
||||
Source::Rustc { stage: 0 } => {
|
||||
Vec::new()
|
||||
}
|
||||
Source::Rustc { stage } => {
|
||||
let compiler = Compiler::new(stage - 1, &build.config.build);
|
||||
vec![self.librustc(compiler)]
|
||||
}
|
||||
Source::Librustc { compiler } => {
|
||||
vec![self.libtest(compiler), self.llvm(())]
|
||||
}
|
||||
Source::Libtest { compiler } => {
|
||||
vec![self.libstd(compiler)]
|
||||
}
|
||||
Source::Libstd { compiler } => {
|
||||
vec![self.rustc(compiler.stage).target(compiler.host)]
|
||||
}
|
||||
Source::LibrustcLink { compiler, host } => {
|
||||
vec![self.librustc(compiler),
|
||||
self.libtest_link(compiler, host)]
|
||||
}
|
||||
Source::LibtestLink { compiler, host } => {
|
||||
vec![self.libtest(compiler), self.libstd_link(compiler, host)]
|
||||
}
|
||||
Source::LibstdLink { compiler, host } => {
|
||||
vec![self.libstd(compiler),
|
||||
self.target(host).rustc(compiler.stage)]
|
||||
}
|
||||
Source::Llvm { _dummy } => Vec::new(),
|
||||
Source::TestHelpers { _dummy } => Vec::new(),
|
||||
Source::DebuggerScripts { stage: _ } => Vec::new(),
|
||||
pub fn run(build: &Build) {
|
||||
let rules = build_rules(build);
|
||||
let steps = rules.plan();
|
||||
rules.run(&steps);
|
||||
}
|
||||
|
||||
// Note that all doc targets depend on artifacts from the build
|
||||
// architecture, not the target (which is where we're generating
|
||||
// docs into).
|
||||
Source::DocStd { stage } => {
|
||||
let compiler = self.target(&build.config.build).compiler(stage);
|
||||
vec![self.libstd(compiler)]
|
||||
}
|
||||
Source::DocTest { stage } => {
|
||||
let compiler = self.target(&build.config.build).compiler(stage);
|
||||
vec![self.libtest(compiler)]
|
||||
}
|
||||
Source::DocBook { stage } |
|
||||
Source::DocNomicon { stage } => {
|
||||
vec![self.target(&build.config.build).tool_rustbook(stage)]
|
||||
}
|
||||
Source::DocErrorIndex { stage } => {
|
||||
vec![self.target(&build.config.build).tool_error_index(stage)]
|
||||
}
|
||||
Source::DocStandalone { stage } => {
|
||||
vec![self.target(&build.config.build).rustc(stage)]
|
||||
}
|
||||
Source::DocRustc { stage } => {
|
||||
vec![self.doc_test(stage)]
|
||||
}
|
||||
Source::Doc { stage } => {
|
||||
let mut deps = vec![
|
||||
self.doc_book(stage), self.doc_nomicon(stage),
|
||||
self.doc_standalone(stage), self.doc_std(stage),
|
||||
self.doc_error_index(stage),
|
||||
];
|
||||
pub fn build_rules(build: &Build) -> Rules {
|
||||
let mut rules: Rules = Rules::new(build);
|
||||
// dummy rule to do nothing, useful when a dep maps to no deps
|
||||
rules.build("dummy", "path/to/nowhere");
|
||||
fn dummy<'a>(s: &Step<'a>, build: &'a Build) -> Step<'a> {
|
||||
s.name("dummy").stage(0)
|
||||
.target(&build.config.build)
|
||||
.host(&build.config.build)
|
||||
}
|
||||
|
||||
if build.config.compiler_docs {
|
||||
deps.push(self.doc_rustc(stage));
|
||||
}
|
||||
|
||||
deps
|
||||
}
|
||||
Source::Check { stage, compiler } => {
|
||||
// Check is just a pseudo step which means check all targets,
|
||||
// so just depend on checking all targets.
|
||||
build.config.target.iter().map(|t| {
|
||||
self.target(t).check_target(stage, compiler)
|
||||
}).collect()
|
||||
}
|
||||
Source::CheckTarget { stage, compiler } => {
|
||||
// CheckTarget here means run all possible test suites for this
|
||||
// target. Most of the time, however, we can't actually run
|
||||
// anything if we're not the build triple as we could be cross
|
||||
// compiling.
|
||||
//
|
||||
// As a result, the base set of targets here is quite stripped
|
||||
// down from the standard set of targets. These suites have
|
||||
// their own internal logic to run in cross-compiled situations
|
||||
// if they'll run at all. For example compiletest knows that
|
||||
// when testing Android targets we ship artifacts to the
|
||||
// emulator.
|
||||
//
|
||||
// When in doubt the rule of thumb for adding to this list is
|
||||
// "should this test suite run on the android bot?"
|
||||
let mut base = vec![
|
||||
self.check_rpass(compiler),
|
||||
self.check_rfail(compiler),
|
||||
self.check_crate_std(compiler),
|
||||
self.check_crate_test(compiler),
|
||||
self.check_debuginfo(compiler),
|
||||
];
|
||||
|
||||
// If we're testing the build triple, then we know we can
|
||||
// actually run binaries and such, so we run all possible tests
|
||||
// that we know about.
|
||||
if self.target == build.config.build {
|
||||
base.extend(vec![
|
||||
// docs-related
|
||||
self.check_docs(compiler),
|
||||
self.check_error_index(compiler),
|
||||
self.check_rustdoc(compiler),
|
||||
|
||||
// UI-related
|
||||
self.check_cfail(compiler),
|
||||
self.check_pfail(compiler),
|
||||
self.check_ui(compiler),
|
||||
|
||||
// codegen-related
|
||||
self.check_incremental(compiler),
|
||||
self.check_codegen(compiler),
|
||||
self.check_codegen_units(compiler),
|
||||
|
||||
// misc compiletest-test suites
|
||||
self.check_rpass_full(compiler),
|
||||
self.check_rfail_full(compiler),
|
||||
self.check_cfail_full(compiler),
|
||||
self.check_pretty_rpass_full(compiler),
|
||||
self.check_pretty_rfail_full(compiler),
|
||||
self.check_rpass_valgrind(compiler),
|
||||
self.check_rmake(compiler),
|
||||
self.check_mir_opt(compiler),
|
||||
|
||||
// crates
|
||||
self.check_crate_rustc(compiler),
|
||||
|
||||
// pretty
|
||||
self.check_pretty(compiler),
|
||||
self.check_pretty_rpass(compiler),
|
||||
self.check_pretty_rfail(compiler),
|
||||
self.check_pretty_rpass_valgrind(compiler),
|
||||
|
||||
// misc
|
||||
self.check_linkcheck(stage),
|
||||
self.check_tidy(stage),
|
||||
|
||||
// can we make the distributables?
|
||||
self.dist(stage),
|
||||
]);
|
||||
}
|
||||
base
|
||||
}
|
||||
Source::CheckLinkcheck { stage } => {
|
||||
vec![self.tool_linkchecker(stage), self.doc(stage)]
|
||||
}
|
||||
Source::CheckCargoTest { stage } => {
|
||||
vec![self.tool_cargotest(stage),
|
||||
self.librustc(self.compiler(stage))]
|
||||
}
|
||||
Source::CheckTidy { stage } => {
|
||||
vec![self.tool_tidy(stage)]
|
||||
}
|
||||
Source::CheckMirOpt { compiler} |
|
||||
Source::CheckPrettyRPass { compiler } |
|
||||
Source::CheckPrettyRFail { compiler } |
|
||||
Source::CheckRFail { compiler } |
|
||||
Source::CheckPFail { compiler } |
|
||||
Source::CheckCodegen { compiler } |
|
||||
Source::CheckCodegenUnits { compiler } |
|
||||
Source::CheckIncremental { compiler } |
|
||||
Source::CheckUi { compiler } |
|
||||
Source::CheckPretty { compiler } |
|
||||
Source::CheckCFail { compiler } |
|
||||
Source::CheckRPassValgrind { compiler } |
|
||||
Source::CheckRPass { compiler } => {
|
||||
let mut base = vec![
|
||||
self.libtest(compiler),
|
||||
self.target(compiler.host).tool_compiletest(compiler.stage),
|
||||
self.test_helpers(()),
|
||||
];
|
||||
if self.target.contains("android") {
|
||||
base.push(self.android_copy_libs(compiler));
|
||||
}
|
||||
base
|
||||
}
|
||||
Source::CheckDebuginfo { compiler } => {
|
||||
vec![
|
||||
self.libtest(compiler),
|
||||
self.target(compiler.host).tool_compiletest(compiler.stage),
|
||||
self.test_helpers(()),
|
||||
self.debugger_scripts(compiler.stage),
|
||||
]
|
||||
}
|
||||
Source::CheckRustdoc { compiler } |
|
||||
Source::CheckRPassFull { compiler } |
|
||||
Source::CheckRFailFull { compiler } |
|
||||
Source::CheckCFailFull { compiler } |
|
||||
Source::CheckPrettyRPassFull { compiler } |
|
||||
Source::CheckPrettyRFailFull { compiler } |
|
||||
Source::CheckPrettyRPassValgrind { compiler } |
|
||||
Source::CheckRMake { compiler } => {
|
||||
vec![self.librustc(compiler),
|
||||
self.target(compiler.host).tool_compiletest(compiler.stage)]
|
||||
}
|
||||
Source::CheckDocs { compiler } => {
|
||||
vec![self.libtest(compiler)]
|
||||
}
|
||||
Source::CheckErrorIndex { compiler } => {
|
||||
vec![self.libstd(compiler),
|
||||
self.target(compiler.host).tool_error_index(compiler.stage)]
|
||||
}
|
||||
Source::CheckCrateStd { compiler } => {
|
||||
vec![self.libtest(compiler)]
|
||||
}
|
||||
Source::CheckCrateTest { compiler } => {
|
||||
vec![self.libtest(compiler)]
|
||||
}
|
||||
Source::CheckCrateRustc { compiler } => {
|
||||
vec![self.libtest(compiler)]
|
||||
}
|
||||
|
||||
Source::ToolLinkchecker { stage } |
|
||||
Source::ToolTidy { stage } => {
|
||||
vec![self.libstd(self.compiler(stage))]
|
||||
}
|
||||
Source::ToolErrorIndex { stage } |
|
||||
Source::ToolRustbook { stage } => {
|
||||
vec![self.librustc(self.compiler(stage))]
|
||||
}
|
||||
Source::ToolCargoTest { stage } => {
|
||||
vec![self.libstd(self.compiler(stage))]
|
||||
}
|
||||
Source::ToolCompiletest { stage } => {
|
||||
vec![self.libtest(self.compiler(stage))]
|
||||
}
|
||||
|
||||
Source::DistDocs { stage } => vec![self.doc(stage)],
|
||||
Source::DistMingw { _dummy: _ } => Vec::new(),
|
||||
Source::DistRustc { stage } => {
|
||||
vec![self.rustc(stage)]
|
||||
}
|
||||
Source::DistStd { compiler } => {
|
||||
// We want to package up as many target libraries as possible
|
||||
// for the `rust-std` package, so if this is a host target we
|
||||
// depend on librustc and otherwise we just depend on libtest.
|
||||
if build.config.host.iter().any(|t| t == self.target) {
|
||||
vec![self.librustc(compiler)]
|
||||
} else {
|
||||
vec![self.libtest(compiler)]
|
||||
// Helper for loading an entire DAG of crates, rooted at `name`
|
||||
let krates = |name: &str| {
|
||||
let mut ret = Vec::new();
|
||||
let mut list = vec![name];
|
||||
let mut visited = HashSet::new();
|
||||
while let Some(krate) = list.pop() {
|
||||
let default = krate == name;
|
||||
let krate = &build.crates[krate];
|
||||
let path = krate.path.strip_prefix(&build.src).unwrap();
|
||||
ret.push((krate, path.to_str().unwrap(), default));
|
||||
for dep in krate.deps.iter() {
|
||||
if visited.insert(dep) && dep != "build_helper" {
|
||||
list.push(dep);
|
||||
}
|
||||
}
|
||||
Source::DistSrc { _dummy: _ } => Vec::new(),
|
||||
}
|
||||
return ret
|
||||
};
|
||||
|
||||
Source::Dist { stage } => {
|
||||
let mut base = Vec::new();
|
||||
rules.build("rustc", "path/to/nowhere")
|
||||
.dep(move |s| {
|
||||
if s.stage == 0 {
|
||||
dummy(s, build)
|
||||
} else {
|
||||
s.name("librustc")
|
||||
.host(&build.config.build)
|
||||
.stage(s.stage - 1)
|
||||
}
|
||||
})
|
||||
.run(move |s| compile::assemble_rustc(build, s.stage, s.target));
|
||||
rules.build("llvm", "src/llvm")
|
||||
.host(true)
|
||||
.run(move |s| native::llvm(build, s.target));
|
||||
|
||||
for host in build.config.host.iter() {
|
||||
let host = self.target(host);
|
||||
base.push(host.dist_src(()));
|
||||
base.push(host.dist_rustc(stage));
|
||||
if host.target.contains("windows-gnu") {
|
||||
base.push(host.dist_mingw(()));
|
||||
}
|
||||
// ========================================================================
|
||||
// Crate compilations
|
||||
//
|
||||
// Tools used during the build system but not shipped
|
||||
rules.build("libstd", "src/libstd")
|
||||
.dep(|s| s.name("build-crate-std_shim"));
|
||||
rules.build("libtest", "src/libtest")
|
||||
.dep(|s| s.name("build-crate-test_shim"));
|
||||
rules.build("librustc", "src/librustc")
|
||||
.dep(|s| s.name("build-crate-rustc-main"));
|
||||
for (krate, path, _default) in krates("std_shim") {
|
||||
rules.build(&krate.build_step, path)
|
||||
.dep(|s| s.name("rustc").target(s.host))
|
||||
.dep(move |s| {
|
||||
if s.host == build.config.build {
|
||||
dummy(s, build)
|
||||
} else {
|
||||
s.host(&build.config.build)
|
||||
}
|
||||
})
|
||||
.run(move |s| {
|
||||
if s.host == build.config.build {
|
||||
compile::std(build, s.target, &s.compiler())
|
||||
} else {
|
||||
compile::std_link(build, s.target, s.stage, s.host)
|
||||
}
|
||||
});
|
||||
}
|
||||
for (krate, path, default) in krates("test_shim") {
|
||||
rules.build(&krate.build_step, path)
|
||||
.dep(|s| s.name("libstd"))
|
||||
.dep(move |s| {
|
||||
if s.host == build.config.build {
|
||||
dummy(s, build)
|
||||
} else {
|
||||
s.host(&build.config.build)
|
||||
}
|
||||
})
|
||||
.default(default)
|
||||
.run(move |s| {
|
||||
if s.host == build.config.build {
|
||||
compile::test(build, s.target, &s.compiler())
|
||||
} else {
|
||||
compile::test_link(build, s.target, s.stage, s.host)
|
||||
}
|
||||
});
|
||||
}
|
||||
for (krate, path, default) in krates("rustc-main") {
|
||||
rules.build(&krate.build_step, path)
|
||||
.dep(|s| s.name("libtest"))
|
||||
.dep(move |s| s.name("llvm").host(&build.config.build).stage(0))
|
||||
.dep(move |s| {
|
||||
if s.host == build.config.build {
|
||||
dummy(s, build)
|
||||
} else {
|
||||
s.host(&build.config.build)
|
||||
}
|
||||
})
|
||||
.host(true)
|
||||
.default(default)
|
||||
.run(move |s| {
|
||||
if s.host == build.config.build {
|
||||
compile::rustc(build, s.target, &s.compiler())
|
||||
} else {
|
||||
compile::rustc_link(build, s.target, s.stage, s.host)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let compiler = self.compiler(stage);
|
||||
for target in build.config.target.iter() {
|
||||
let target = self.target(target);
|
||||
if build.config.docs {
|
||||
base.push(target.dist_docs(stage));
|
||||
}
|
||||
base.push(target.dist_std(compiler));
|
||||
}
|
||||
}
|
||||
base
|
||||
}
|
||||
// ========================================================================
|
||||
// Test targets
|
||||
//
|
||||
// Various unit tests and tests suites we can run
|
||||
{
|
||||
let mut suite = |name, path, dir, mode| {
|
||||
rules.test(name, path)
|
||||
.dep(|s| s.name("libtest"))
|
||||
.dep(|s| s.name("tool-compiletest").target(s.host))
|
||||
.dep(|s| s.name("test-helpers"))
|
||||
.dep(move |s| {
|
||||
if s.target.contains("android") {
|
||||
s.name("android-copy-libs")
|
||||
} else {
|
||||
dummy(s, build)
|
||||
}
|
||||
})
|
||||
.default(true)
|
||||
.run(move |s| {
|
||||
check::compiletest(build, &s.compiler(), s.target, dir, mode)
|
||||
});
|
||||
};
|
||||
|
||||
Source::Install { stage } => {
|
||||
vec![self.dist(stage)]
|
||||
}
|
||||
suite("check-rpass", "src/test/run-pass", "run-pass", "run-pass");
|
||||
suite("check-cfail", "src/test/compile-fail", "compile-fail", "compile-fail");
|
||||
suite("check-pfail", "src/test/parse-fail", "parse-fail", "parse-fail");
|
||||
suite("check-rfail", "src/test/run-fail", "run-fail", "run-fail");
|
||||
suite("check-rpass-valgrind", "src/test/run-pass-valgrind",
|
||||
"run-pass-valgrind", "run-pass-valgrind");
|
||||
suite("check-mir-opt", "src/test/mir-opt", "mir-opt", "mir-opt");
|
||||
if build.config.codegen_tests {
|
||||
suite("check-codegen", "src/test/codegen", "codegen", "codegen");
|
||||
}
|
||||
suite("check-codegen-units", "src/test/codegen-units", "codegen-units",
|
||||
"codegen-units");
|
||||
suite("check-incremental", "src/test/incremental", "incremental",
|
||||
"incremental");
|
||||
suite("check-ui", "src/test/ui", "ui", "ui");
|
||||
suite("check-pretty", "src/test/pretty", "pretty", "pretty");
|
||||
suite("check-pretty-rpass", "src/test/run-pass/pretty", "pretty",
|
||||
"run-pass");
|
||||
suite("check-pretty-rfail", "src/test/run-pass/pretty", "pretty",
|
||||
"run-fail");
|
||||
suite("check-pretty-valgrind", "src/test/run-pass-valgrind", "pretty",
|
||||
"run-pass-valgrind");
|
||||
}
|
||||
|
||||
Source::AndroidCopyLibs { compiler } => {
|
||||
vec![self.libtest(compiler)]
|
||||
}
|
||||
if build.config.build.contains("msvc") {
|
||||
// nothing to do for debuginfo tests
|
||||
} else if build.config.build.contains("apple") {
|
||||
rules.test("check-debuginfo", "src/test/debuginfo")
|
||||
.dep(|s| s.name("libtest"))
|
||||
.dep(|s| s.name("tool-compiletest").host(s.host))
|
||||
.dep(|s| s.name("test-helpers"))
|
||||
.dep(|s| s.name("debugger-scripts"))
|
||||
.run(move |s| check::compiletest(build, &s.compiler(), s.target,
|
||||
"debuginfo-lldb", "debuginfo"));
|
||||
} else {
|
||||
rules.test("check-debuginfo", "src/test/debuginfo")
|
||||
.dep(|s| s.name("libtest"))
|
||||
.dep(|s| s.name("tool-compiletest").host(s.host))
|
||||
.dep(|s| s.name("test-helpers"))
|
||||
.dep(|s| s.name("debugger-scripts"))
|
||||
.run(move |s| check::compiletest(build, &s.compiler(), s.target,
|
||||
"debuginfo-gdb", "debuginfo"));
|
||||
}
|
||||
|
||||
rules.test("debugger-scripts", "src/etc/lldb_batchmode.py")
|
||||
.run(move |s| dist::debugger_scripts(build, &build.sysroot(&s.compiler()),
|
||||
s.target));
|
||||
|
||||
{
|
||||
let mut suite = |name, path, dir, mode| {
|
||||
rules.test(name, path)
|
||||
.dep(|s| s.name("librustc"))
|
||||
.dep(|s| s.name("tool-compiletest").target(s.host))
|
||||
.default(true)
|
||||
.host(true)
|
||||
.run(move |s| {
|
||||
check::compiletest(build, &s.compiler(), s.target, dir, mode)
|
||||
});
|
||||
};
|
||||
|
||||
suite("check-rpass-full", "src/test/run-pass-fulldeps",
|
||||
"run-pass", "run-pass-fulldeps");
|
||||
suite("check-cfail-full", "src/test/compile-fail-fulldeps",
|
||||
"compile-fail", "compile-fail-fulldeps");
|
||||
suite("check-rmake", "src/test/run-make", "run-make", "run-make");
|
||||
suite("check-rustdoc", "src/test/rustdoc", "rustdoc", "rustdoc");
|
||||
suite("check-pretty-rpass-full", "src/test/run-pass-fulldeps",
|
||||
"pretty", "run-pass-fulldeps");
|
||||
suite("check-pretty-rfail-full", "src/test/run-fail-fulldeps",
|
||||
"pretty", "run-fail-fulldeps");
|
||||
}
|
||||
|
||||
for (krate, path, _default) in krates("std_shim") {
|
||||
rules.test(&krate.test_step, path)
|
||||
.dep(|s| s.name("libtest"))
|
||||
.run(move |s| check::krate(build, &s.compiler(), s.target,
|
||||
Mode::Libstd, Some(&krate.name)));
|
||||
}
|
||||
rules.test("check-std-all", "path/to/nowhere")
|
||||
.dep(|s| s.name("libtest"))
|
||||
.default(true)
|
||||
.run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libstd,
|
||||
None));
|
||||
for (krate, path, _default) in krates("test_shim") {
|
||||
rules.test(&krate.test_step, path)
|
||||
.dep(|s| s.name("libtest"))
|
||||
.run(move |s| check::krate(build, &s.compiler(), s.target,
|
||||
Mode::Libtest, Some(&krate.name)));
|
||||
}
|
||||
rules.test("check-test-all", "path/to/nowhere")
|
||||
.dep(|s| s.name("libtest"))
|
||||
.default(true)
|
||||
.run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libtest,
|
||||
None));
|
||||
for (krate, path, _default) in krates("rustc-main") {
|
||||
rules.test(&krate.test_step, path)
|
||||
.dep(|s| s.name("libtest"))
|
||||
.host(true)
|
||||
.run(move |s| check::krate(build, &s.compiler(), s.target,
|
||||
Mode::Librustc, Some(&krate.name)));
|
||||
}
|
||||
rules.test("check-rustc-all", "path/to/nowhere")
|
||||
.dep(|s| s.name("libtest"))
|
||||
.default(true)
|
||||
.host(true)
|
||||
.run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Librustc,
|
||||
None));
|
||||
|
||||
rules.test("check-linkchecker", "src/tools/linkchecker")
|
||||
.dep(|s| s.name("tool-linkchecker"))
|
||||
.dep(|s| s.name("default:doc"))
|
||||
.default(true)
|
||||
.run(move |s| check::linkcheck(build, s.stage, s.target));
|
||||
rules.test("check-cargotest", "src/tools/cargotest")
|
||||
.dep(|s| s.name("tool-cargotest"))
|
||||
.dep(|s| s.name("librustc"))
|
||||
.run(move |s| check::cargotest(build, s.stage, s.target));
|
||||
rules.test("check-tidy", "src/tools/tidy")
|
||||
.dep(|s| s.name("tool-tidy"))
|
||||
.default(true)
|
||||
.run(move |s| check::tidy(build, s.stage, s.target));
|
||||
rules.test("check-error-index", "src/tools/error_index_generator")
|
||||
.dep(|s| s.name("libstd"))
|
||||
.dep(|s| s.name("tool-error-index").host(s.host))
|
||||
.default(true)
|
||||
.run(move |s| check::error_index(build, &s.compiler()));
|
||||
rules.test("check-docs", "src/doc")
|
||||
.dep(|s| s.name("libtest"))
|
||||
.default(true)
|
||||
.run(move |s| check::docs(build, &s.compiler()));
|
||||
|
||||
rules.build("test-helpers", "src/rt/rust_test_helpers.c")
|
||||
.run(move |s| native::test_helpers(build, s.target));
|
||||
rules.test("android-copy-libs", "path/to/nowhere")
|
||||
.dep(|s| s.name("libtest"))
|
||||
.run(move |s| check::android_copy_libs(build, &s.compiler(), s.target));
|
||||
|
||||
// ========================================================================
|
||||
// Build tools
|
||||
//
|
||||
// Tools used during the build system but not shipped
|
||||
rules.build("tool-rustbook", "src/tools/rustbook")
|
||||
.dep(|s| s.name("librustc"))
|
||||
.run(move |s| compile::tool(build, s.stage, s.target, "rustbook"));
|
||||
rules.build("tool-error-index", "src/tools/error_index_generator")
|
||||
.dep(|s| s.name("librustc"))
|
||||
.run(move |s| compile::tool(build, s.stage, s.target, "error_index_generator"));
|
||||
rules.build("tool-tidy", "src/tools/tidy")
|
||||
.dep(|s| s.name("libstd"))
|
||||
.run(move |s| compile::tool(build, s.stage, s.target, "tidy"));
|
||||
rules.build("tool-linkchecker", "src/tools/linkchecker")
|
||||
.dep(|s| s.name("libstd"))
|
||||
.run(move |s| compile::tool(build, s.stage, s.target, "linkchecker"));
|
||||
rules.build("tool-cargotest", "src/tools/cargotest")
|
||||
.dep(|s| s.name("libstd"))
|
||||
.run(move |s| compile::tool(build, s.stage, s.target, "cargotest"));
|
||||
rules.build("tool-compiletest", "src/tools/compiletest")
|
||||
.dep(|s| s.name("libtest"))
|
||||
.run(move |s| compile::tool(build, s.stage, s.target, "compiletest"));
|
||||
|
||||
// ========================================================================
|
||||
// Documentation targets
|
||||
rules.doc("doc-book", "src/doc/book")
|
||||
.dep(move |s| s.name("tool-rustbook").target(&build.config.build))
|
||||
.default(build.config.docs)
|
||||
.run(move |s| doc::rustbook(build, s.stage, s.target, "book"));
|
||||
rules.doc("doc-nomicon", "src/doc/nomicon")
|
||||
.dep(move |s| s.name("tool-rustbook").target(&build.config.build))
|
||||
.default(build.config.docs)
|
||||
.run(move |s| doc::rustbook(build, s.stage, s.target, "nomicon"));
|
||||
rules.doc("doc-standalone", "src/doc")
|
||||
.dep(move |s| s.name("rustc").target(&build.config.build))
|
||||
.default(build.config.docs)
|
||||
.run(move |s| doc::standalone(build, s.stage, s.target));
|
||||
rules.doc("doc-error-index", "src/tools/error_index_generator")
|
||||
.dep(move |s| s.name("tool-error-index").target(&build.config.build))
|
||||
.default(build.config.docs)
|
||||
.run(move |s| doc::error_index(build, s.stage, s.target));
|
||||
for (krate, path, default) in krates("std_shim") {
|
||||
rules.doc(&krate.doc_step, path)
|
||||
.dep(|s| s.name("libstd"))
|
||||
.default(default && build.config.docs)
|
||||
.run(move |s| doc::std(build, s.stage, s.target));
|
||||
}
|
||||
for (krate, path, default) in krates("test_shim") {
|
||||
rules.doc(&krate.doc_step, path)
|
||||
.dep(|s| s.name("libtest"))
|
||||
.default(default && build.config.docs)
|
||||
.run(move |s| doc::test(build, s.stage, s.target));
|
||||
}
|
||||
for (krate, path, default) in krates("rustc-main") {
|
||||
rules.doc(&krate.doc_step, path)
|
||||
.dep(|s| s.name("librustc"))
|
||||
.host(true)
|
||||
.default(default && build.config.compiler_docs)
|
||||
.run(move |s| doc::rustc(build, s.stage, s.target));
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Distribution targets
|
||||
rules.dist("dist-rustc", "src/librustc")
|
||||
.dep(|s| s.name("rustc"))
|
||||
.host(true)
|
||||
.default(true)
|
||||
.run(move |s| dist::rustc(build, s.stage, s.target));
|
||||
rules.dist("dist-std", "src/libstd")
|
||||
.dep(move |s| {
|
||||
// We want to package up as many target libraries as possible
|
||||
// for the `rust-std` package, so if this is a host target we
|
||||
// depend on librustc and otherwise we just depend on libtest.
|
||||
if build.config.host.iter().any(|t| t == s.target) {
|
||||
s.name("librustc")
|
||||
} else {
|
||||
s.name("libtest")
|
||||
}
|
||||
})
|
||||
.default(true)
|
||||
.run(move |s| dist::std(build, &s.compiler(), s.target));
|
||||
rules.dist("dist-mingw", "path/to/nowhere")
|
||||
.run(move |s| dist::mingw(build, s.target));
|
||||
rules.dist("dist-src", "src")
|
||||
.default(true)
|
||||
.host(true)
|
||||
.run(move |_| dist::rust_src(build));
|
||||
rules.dist("dist-docs", "src/doc")
|
||||
.dep(|s| s.name("default:doc"))
|
||||
.run(move |s| dist::docs(build, s.stage, s.target));
|
||||
rules.dist("install", "src")
|
||||
.dep(|s| s.name("default:dist"))
|
||||
.run(move |s| install::install(build, s.stage, s.target));
|
||||
|
||||
rules.verify();
|
||||
return rules
|
||||
}
|
||||
|
||||
struct Rule<'a> {
|
||||
name: &'a str,
|
||||
path: &'a str,
|
||||
kind: Kind,
|
||||
deps: Vec<Box<Fn(&Step<'a>) -> Step<'a> + 'a>>,
|
||||
run: Box<Fn(&Step<'a>) + 'a>,
|
||||
default: bool,
|
||||
host: bool,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum Kind {
|
||||
Build,
|
||||
Test,
|
||||
Dist,
|
||||
Doc,
|
||||
}
|
||||
|
||||
impl<'a> Rule<'a> {
|
||||
fn new(name: &'a str, path: &'a str, kind: Kind) -> Rule<'a> {
|
||||
Rule {
|
||||
name: name,
|
||||
deps: Vec::new(),
|
||||
run: Box::new(|_| ()),
|
||||
path: path,
|
||||
kind: kind,
|
||||
default: false,
|
||||
host: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RuleBuilder<'a: 'b, 'b> {
|
||||
rules: &'b mut Rules<'a>,
|
||||
rule: Rule<'a>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> RuleBuilder<'a, 'b> {
|
||||
fn dep<F>(&mut self, f: F) -> &mut Self
|
||||
where F: Fn(&Step<'a>) -> Step<'a> + 'a,
|
||||
{
|
||||
self.rule.deps.push(Box::new(f));
|
||||
self
|
||||
}
|
||||
|
||||
fn run<F>(&mut self, f: F) -> &mut Self
|
||||
where F: Fn(&Step<'a>) + 'a,
|
||||
{
|
||||
self.rule.run = Box::new(f);
|
||||
self
|
||||
}
|
||||
|
||||
fn default(&mut self, default: bool) -> &mut Self {
|
||||
self.rule.default = default;
|
||||
self
|
||||
}
|
||||
|
||||
fn host(&mut self, host: bool) -> &mut Self {
|
||||
self.rule.host = host;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Drop for RuleBuilder<'a, 'b> {
|
||||
fn drop(&mut self) {
|
||||
let rule = mem::replace(&mut self.rule, Rule::new("", "", Kind::Build));
|
||||
let prev = self.rules.rules.insert(rule.name, rule);
|
||||
if let Some(prev) = prev {
|
||||
panic!("duplicate rule named: {}", prev.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Rules<'a> {
|
||||
build: &'a Build,
|
||||
sbuild: Step<'a>,
|
||||
rules: HashMap<&'a str, Rule<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Rules<'a> {
|
||||
fn new(build: &'a Build) -> Rules<'a> {
|
||||
Rules {
|
||||
build: build,
|
||||
sbuild: Step {
|
||||
stage: build.flags.stage.unwrap_or(2),
|
||||
target: &build.config.build,
|
||||
host: &build.config.build,
|
||||
name: "",
|
||||
},
|
||||
rules: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn build<'b>(&'b mut self, name: &'a str, path: &'a str)
|
||||
-> RuleBuilder<'a, 'b> {
|
||||
self.rule(name, path, Kind::Build)
|
||||
}
|
||||
|
||||
fn test<'b>(&'b mut self, name: &'a str, path: &'a str)
|
||||
-> RuleBuilder<'a, 'b> {
|
||||
self.rule(name, path, Kind::Test)
|
||||
}
|
||||
|
||||
fn doc<'b>(&'b mut self, name: &'a str, path: &'a str)
|
||||
-> RuleBuilder<'a, 'b> {
|
||||
self.rule(name, path, Kind::Doc)
|
||||
}
|
||||
|
||||
fn dist<'b>(&'b mut self, name: &'a str, path: &'a str)
|
||||
-> RuleBuilder<'a, 'b> {
|
||||
self.rule(name, path, Kind::Dist)
|
||||
}
|
||||
|
||||
fn rule<'b>(&'b mut self,
|
||||
name: &'a str,
|
||||
path: &'a str,
|
||||
kind: Kind) -> RuleBuilder<'a, 'b> {
|
||||
RuleBuilder {
|
||||
rules: self,
|
||||
rule: Rule::new(name, path, kind),
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify the dependency graph defined by all our rules are correct, e.g.
|
||||
/// everything points to a valid something else.
|
||||
fn verify(&self) {
|
||||
for rule in self.rules.values() {
|
||||
for dep in rule.deps.iter() {
|
||||
let dep = dep(&self.sbuild.name(rule.name));
|
||||
if self.rules.contains_key(&dep.name) || dep.name.starts_with("default:") {
|
||||
continue }
|
||||
panic!("\
|
||||
|
||||
invalid rule dependency graph detected, was a rule added and maybe typo'd?
|
||||
|
||||
`{}` depends on `{}` which does not exist
|
||||
|
||||
", rule.name, dep.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_help(&self, command: &str) {
|
||||
let kind = match command {
|
||||
"build" => Kind::Build,
|
||||
"doc" => Kind::Doc,
|
||||
"test" => Kind::Test,
|
||||
"dist" => Kind::Dist,
|
||||
_ => return,
|
||||
};
|
||||
let rules = self.rules.values().filter(|r| r.kind == kind);
|
||||
let rules = rules.filter(|r| !r.path.contains("nowhere"));
|
||||
let mut rules = rules.collect::<Vec<_>>();
|
||||
rules.sort_by_key(|r| r.path);
|
||||
|
||||
println!("Available paths:\n");
|
||||
for rule in rules {
|
||||
print!(" ./x.py {} {}", command, rule.path);
|
||||
|
||||
println!("");
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct the top-level build steps that we're going to be executing,
|
||||
/// given the subcommand that our build is performing.
|
||||
fn plan(&self) -> Vec<Step<'a>> {
|
||||
let (kind, paths) = match self.build.flags.cmd {
|
||||
Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
|
||||
Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
|
||||
Subcommand::Test { ref paths, test_args: _ } => (Kind::Test, &paths[..]),
|
||||
Subcommand::Dist { install } => {
|
||||
if install {
|
||||
return vec![self.sbuild.name("install")]
|
||||
} else {
|
||||
(Kind::Dist, &[][..])
|
||||
}
|
||||
}
|
||||
Subcommand::Clean => panic!(),
|
||||
};
|
||||
|
||||
self.rules.values().filter(|rule| rule.kind == kind).filter(|rule| {
|
||||
(paths.len() == 0 && rule.default) || paths.iter().any(|path| {
|
||||
path.ends_with(rule.path)
|
||||
})
|
||||
}).flat_map(|rule| {
|
||||
let hosts = if self.build.flags.host.len() > 0 {
|
||||
&self.build.flags.host
|
||||
} else {
|
||||
&self.build.config.host
|
||||
};
|
||||
let targets = if self.build.flags.target.len() > 0 {
|
||||
&self.build.flags.target
|
||||
} else {
|
||||
&self.build.config.target
|
||||
};
|
||||
let arr = if rule.host {hosts} else {targets};
|
||||
|
||||
hosts.iter().flat_map(move |host| {
|
||||
arr.iter().map(move |target| {
|
||||
self.sbuild.name(rule.name).target(target).host(host)
|
||||
})
|
||||
})
|
||||
}).collect()
|
||||
}
|
||||
|
||||
/// Execute all top-level targets indicated by `steps`.
|
||||
///
|
||||
/// This will take the list returned by `plan` and then execute each step
|
||||
/// along with all required dependencies as it goes up the chain.
|
||||
fn run(&self, steps: &[Step<'a>]) {
|
||||
self.build.verbose("bootstrap top targets:");
|
||||
for step in steps.iter() {
|
||||
self.build.verbose(&format!("\t{:?}", step));
|
||||
}
|
||||
|
||||
// Using `steps` as the top-level targets, make a topological ordering
|
||||
// of what we need to do.
|
||||
let mut order = Vec::new();
|
||||
let mut added = HashSet::new();
|
||||
for step in steps.iter().cloned() {
|
||||
self.fill(step, &mut order, &mut added);
|
||||
}
|
||||
|
||||
// Print out what we're doing for debugging
|
||||
self.build.verbose("bootstrap build plan:");
|
||||
for step in order.iter() {
|
||||
self.build.verbose(&format!("\t{:?}", step));
|
||||
}
|
||||
|
||||
// And finally, iterate over everything and execute it.
|
||||
for step in order.iter() {
|
||||
(self.rules[step.name].run)(step);
|
||||
}
|
||||
}
|
||||
|
||||
fn fill(&self,
|
||||
step: Step<'a>,
|
||||
order: &mut Vec<Step<'a>>,
|
||||
added: &mut HashSet<Step<'a>>) {
|
||||
if !added.insert(step.clone()) {
|
||||
return
|
||||
}
|
||||
for dep in self.rules[step.name].deps.iter() {
|
||||
let dep = dep(&step);
|
||||
if dep.name.starts_with("default:") {
|
||||
let kind = match &dep.name[8..] {
|
||||
"doc" => Kind::Doc,
|
||||
"dist" => Kind::Dist,
|
||||
kind => panic!("unknown kind: `{}`", kind),
|
||||
};
|
||||
let rules = self.rules.values().filter(|r| r.default);
|
||||
for rule in rules.filter(|r| r.kind == kind) {
|
||||
self.fill(dep.name(rule.name), order, added);
|
||||
}
|
||||
} else {
|
||||
self.fill(dep, order, added);
|
||||
}
|
||||
}
|
||||
order.push(step);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +57,7 @@ pub fn cp_r(src: &Path, dst: &Path) {
|
||||
let name = path.file_name().unwrap();
|
||||
let dst = dst.join(name);
|
||||
if t!(f.file_type()).is_dir() {
|
||||
let _ = fs::remove_dir_all(&dst);
|
||||
t!(fs::create_dir(&dst));
|
||||
t!(fs::create_dir_all(&dst));
|
||||
cp_r(&path, &dst);
|
||||
} else {
|
||||
let _ = fs::remove_file(&dst);
|
||||
|
||||
@@ -11,4 +11,4 @@ crate-type = ["dylib"]
|
||||
[dependencies]
|
||||
log = { path = "../liblog" }
|
||||
serialize = { path = "../libserialize" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright 2016 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.
|
||||
|
||||
import sys
|
||||
import os
|
||||
dir = os.path.dirname(__file__)
|
||||
sys.path.append(os.path.abspath(os.path.join(dir, "src", "bootstrap")))
|
||||
|
||||
import bootstrap
|
||||
|
||||
bootstrap.main()
|
||||
Reference in New Issue
Block a user