Skip to content

Commit a270b80

Browse files
committed
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.
1 parent 5665bdf commit a270b80

17 files changed

+1136
-985
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ ones from MSYS if you have it installed). You'll also need Visual Studio 2013 or
127127
newer with the C++ tools. Then all you need to do is to kick off rustbuild.
128128
129129
```
130-
python .\src\bootstrap\bootstrap.py
130+
python x.py build
131131
```
132132
133133
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.
137137
138138
```
139139
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat"
140-
python .\src\bootstrap\bootstrap.py
140+
python x.py build
141141
```
142142
143143
## Building Documentation

src/Cargo.lock

+7-13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/bootstrap/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ num_cpus = "0.2"
2727
toml = "0.1"
2828
getopts = "0.2"
2929
rustc-serialize = "0.3"
30-
gcc = { git = "https://github.com/alexcrichton/gcc-rs" }
30+
gcc = "0.3.36"
3131
libc = "0.2"
3232
md5 = "0.1"
3333

src/bootstrap/README.md

+59-11
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,72 @@ system.
1010
1111
## Using rustbuild
1212

13-
When configuring Rust via `./configure`, pass the following to enable building
14-
via this build system:
13+
The rustbuild build system has a primary entry point, a top level `x.py` script:
1514

1615
```
17-
./configure --enable-rustbuild
18-
make
16+
python ./x.py build
1917
```
2018

21-
Afterwards the `Makefile` which is generated will have a few commands like
22-
`make check`, `make tidy`, etc. For finer-grained control, the
23-
`bootstrap.py` entry point can be used:
19+
Note that if you're on Unix you should be able to execute the script directly:
2420

2521
```
26-
python src/bootstrap/bootstrap.py
22+
./x.py build
2723
```
2824

29-
This accepts a number of options like `--stage` and `--step` which can configure
30-
what's actually being done.
25+
The script accepts commands, flags, and filters to determine what to do:
26+
27+
* `build` - a general purpose command for compiling code. Alone `build` will
28+
bootstrap the entire compiler, and otherwise arguments passed indicate what to
29+
build. For example:
30+
31+
```
32+
# build the whole compiler
33+
./x.py build
34+
35+
# build the stage1 compier
36+
./x.py build --stage 1
37+
38+
# build stage0 libstd
39+
./x.py build --stage 0 src/libstd
40+
41+
# build a particular crate in stage0
42+
./x.py build --stage 0 src/libtest
43+
```
44+
45+
* `test` - a command for executing unit tests. Like the `build` command this
46+
will execute the entire test suite by default, and otherwise it can be used to
47+
select which test suite is run:
48+
49+
```
50+
# run all unit tests
51+
./x.py test
52+
53+
# execute the run-pass test suite
54+
./x.py test src/test/run-pass
55+
56+
# execute only some tests in the run-pass test suite
57+
./x.py test src/test/run-pass --filter my-filter
58+
59+
# execute tests in the standard library in stage0
60+
./x.py test --stage 0 src/libstd
61+
62+
# execute all doc tests
63+
./x.py test src/doc
64+
```
65+
66+
* `doc` - a command for building documentation. Like above can take arguments
67+
for what to document.
68+
69+
If you're more used to `./configure` and `make`, however, then you can also
70+
configure the build system to use rustbuild instead of the old makefiles:
71+
72+
```
73+
./configure --enable-rustbuild
74+
make
75+
```
76+
77+
Afterwards the `Makefile` which is generated will have a few commands like
78+
`make check`, `make tidy`, etc.
3179

3280
## Configuring rustbuild
3381

@@ -47,7 +95,7 @@ being invoked manually (via the python script).
4795
The rustbuild build system goes through a few phases to actually build the
4896
compiler. What actually happens when you invoke rustbuild is:
4997

50-
1. The entry point script, `src/bootstrap/bootstrap.py` is run. This script is
98+
1. The entry point script, `x.py` is run. This script is
5199
responsible for downloading the stage0 compiler/Cargo binaries, and it then
52100
compiles the build system itself (this folder). Finally, it then invokes the
53101
actual `bootstrap` binary build system.

src/bootstrap/bootstrap.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -399,12 +399,10 @@ def main():
399399

400400
# Run the bootstrap
401401
args = [os.path.join(rb.build_dir, "bootstrap/debug/bootstrap")]
402-
args.append('--src')
403-
args.append(rb.rust_root)
404-
args.append('--build')
405-
args.append(rb.build)
406402
args.extend(sys.argv[1:])
407403
env = os.environ.copy()
404+
env["BUILD"] = rb.build
405+
env["SRC"] = rb.rust_root
408406
env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
409407
rb.run(args, env)
410408

src/bootstrap/check.rs

+25-66
Original file line numberDiff line numberDiff line change
@@ -13,44 +13,19 @@
1313
//! This file implements the various regression test suites that we execute on
1414
//! our CI.
1515
16-
use std::collections::{HashMap, HashSet};
16+
use std::collections::HashSet;
1717
use std::env;
1818
use std::fs;
1919
use std::path::{PathBuf, Path};
2020
use std::process::Command;
2121

2222
use build_helper::output;
23-
use rustc_serialize::json;
2423

2524
use {Build, Compiler, Mode};
2625
use util::{self, dylib_path, dylib_path_var};
2726

2827
const ADB_TEST_DIR: &'static str = "/data/tmp";
2928

30-
#[derive(RustcDecodable)]
31-
struct Output {
32-
packages: Vec<Package>,
33-
resolve: Resolve,
34-
}
35-
36-
#[derive(RustcDecodable)]
37-
struct Package {
38-
id: String,
39-
name: String,
40-
source: Option<String>,
41-
}
42-
43-
#[derive(RustcDecodable)]
44-
struct Resolve {
45-
nodes: Vec<ResolveNode>,
46-
}
47-
48-
#[derive(RustcDecodable)]
49-
struct ResolveNode {
50-
id: String,
51-
dependencies: Vec<String>,
52-
}
53-
5429
/// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
5530
///
5631
/// This tool in `src/tools` will verify the validity of all our links in the
@@ -181,7 +156,7 @@ pub fn compiletest(build: &Build,
181156
let llvm_version = output(Command::new(&llvm_config).arg("--version"));
182157
cmd.arg("--llvm-version").arg(llvm_version);
183158

184-
cmd.args(&build.flags.args);
159+
cmd.args(&build.flags.cmd.test_args());
185160

186161
if build.config.verbose || build.flags.verbose {
187162
cmd.arg("--verbose");
@@ -282,7 +257,7 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
282257
cmd.arg("--test");
283258
cmd.arg(markdown);
284259

285-
let mut test_args = build.flags.args.join(" ");
260+
let mut test_args = build.flags.cmd.test_args().join(" ");
286261
if build.config.quiet_tests {
287262
test_args.push_str(" --quiet");
288263
}
@@ -302,7 +277,8 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
302277
pub fn krate(build: &Build,
303278
compiler: &Compiler,
304279
target: &str,
305-
mode: Mode) {
280+
mode: Mode,
281+
krate: Option<&str>) {
306282
let (name, path, features, root) = match mode {
307283
Mode::Libstd => {
308284
("libstd", "src/rustc/std_shim", build.std_features(), "std_shim")
@@ -318,24 +294,6 @@ pub fn krate(build: &Build,
318294
println!("Testing {} stage{} ({} -> {})", name, compiler.stage,
319295
compiler.host, target);
320296

321-
// Run `cargo metadata` to figure out what crates we're testing.
322-
//
323-
// Down below we're going to call `cargo test`, but to test the right set
324-
// of packages we're going to have to know what `-p` arguments to pass it
325-
// to know what crates to test. Here we run `cargo metadata` to learn about
326-
// the dependency graph and what `-p` arguments there are.
327-
let mut cargo = Command::new(&build.cargo);
328-
cargo.arg("metadata")
329-
.arg("--manifest-path").arg(build.src.join(path).join("Cargo.toml"));
330-
let output = output(&mut cargo);
331-
let output: Output = json::decode(&output).unwrap();
332-
let id2pkg = output.packages.iter()
333-
.map(|pkg| (&pkg.id, pkg))
334-
.collect::<HashMap<_, _>>();
335-
let id2deps = output.resolve.nodes.iter()
336-
.map(|node| (&node.id, &node.dependencies))
337-
.collect::<HashMap<_, _>>();
338-
339297
// Build up the base `cargo test` command.
340298
//
341299
// Pass in some standard flags then iterate over the graph we've discovered
@@ -346,24 +304,25 @@ pub fn krate(build: &Build,
346304
.arg(build.src.join(path).join("Cargo.toml"))
347305
.arg("--features").arg(features);
348306

349-
let mut visited = HashSet::new();
350-
let root_pkg = output.packages.iter().find(|p| p.name == root).unwrap();
351-
let mut next = vec![&root_pkg.id];
352-
while let Some(id) = next.pop() {
353-
// Skip any packages with sources listed, as these come from crates.io
354-
// and we shouldn't be testing them.
355-
if id2pkg[id].source.is_some() {
356-
continue
357-
}
358-
// Right now jemalloc is our only target-specific crate in the sense
359-
// that it's not present on all platforms. Custom skip it here for now,
360-
// but if we add more this probably wants to get more generalized.
361-
if !id.contains("jemalloc") {
362-
cargo.arg("-p").arg(&id2pkg[id].name);
307+
match krate {
308+
Some(krate) => {
309+
cargo.arg("-p").arg(krate);
363310
}
364-
for dep in id2deps[id] {
365-
if visited.insert(dep) {
366-
next.push(dep);
311+
None => {
312+
let mut visited = HashSet::new();
313+
let mut next = vec![root];
314+
while let Some(name) = next.pop() {
315+
// Right now jemalloc is our only target-specific crate in the sense
316+
// that it's not present on all platforms. Custom skip it here for now,
317+
// but if we add more this probably wants to get more generalized.
318+
if !name.contains("jemalloc") {
319+
cargo.arg("-p").arg(name);
320+
}
321+
for dep in build.crates[name].deps.iter() {
322+
if visited.insert(dep) {
323+
next.push(dep);
324+
}
325+
}
367326
}
368327
}
369328
}
@@ -389,7 +348,7 @@ pub fn krate(build: &Build,
389348
build.run(cargo.arg("--no-run"));
390349
krate_emscripten(build, compiler, target, mode);
391350
} else {
392-
cargo.args(&build.flags.args);
351+
cargo.args(&build.flags.cmd.test_args());
393352
build.run(&mut cargo);
394353
}
395354
}
@@ -421,7 +380,7 @@ fn krate_android(build: &Build,
421380
target = target,
422381
test = test_file_name,
423382
log = log,
424-
args = build.flags.args.join(" "));
383+
args = build.flags.cmd.test_args().join(" "));
425384

426385
let output = output(Command::new("adb").arg("shell").arg(&program));
427386
println!("{}", output);

src/bootstrap/clean.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ pub fn clean(build: &Build) {
2525
rm_rf(build, &build.out.join("tmp"));
2626

2727
for host in build.config.host.iter() {
28-
29-
let out = build.out.join(host);
30-
31-
rm_rf(build, &out.join("doc"));
32-
33-
for stage in 0..4 {
34-
rm_rf(build, &out.join(format!("stage{}", stage)));
35-
rm_rf(build, &out.join(format!("stage{}-std", stage)));
36-
rm_rf(build, &out.join(format!("stage{}-rustc", stage)));
37-
rm_rf(build, &out.join(format!("stage{}-tools", stage)));
38-
rm_rf(build, &out.join(format!("stage{}-test", stage)));
28+
let entries = match build.out.join(host).read_dir() {
29+
Ok(iter) => iter,
30+
Err(_) => continue,
31+
};
32+
33+
for entry in entries {
34+
let entry = t!(entry);
35+
if entry.file_name().to_str() == Some("llvm") {
36+
continue
37+
}
38+
t!(fs::remove_dir_all(&entry.path()));
3939
}
4040
}
4141
}

0 commit comments

Comments
 (0)