Auto merge of #43051 - Mark-Simulacrum:rollup, r=Mark-Simulacrum

Rollup of 8 pull requests

- Successful merges: #42227, #42836, #42975, #42994, #43041, #43042, #43043, #43045
- Failed merges:
This commit is contained in:
bors 2017-07-04 15:58:24 +00:00
commit 2fbba5bdba
28 changed files with 558 additions and 430 deletions

1
.gitignore vendored
View File

@ -51,6 +51,7 @@
.hg/
.hgignore
.idea
*.iml
__pycache__/
*.py[cod]
*$py.class

View File

@ -40,8 +40,9 @@ Read ["Installation"] from [The Book].
> ***Note:*** Install locations can be adjusted by copying the config file
> from `./src/bootstrap/config.toml.example` to `./config.toml`, and
> adjusting the `prefix` option under `[install]`. Various other options are
> also supported, and are documented in the config file.
> adjusting the `prefix` option under `[install]`. Various other options, such
> as enabling debug information, are also supported, and are documented in
> the config file.
When complete, `sudo ./x.py install` will place several programs into
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the

View File

@ -75,16 +75,11 @@ fn main() {
Err(_) => 0,
};
// Build scripts always use the snapshot compiler which is guaranteed to be
// able to produce an executable, whereas intermediate compilers may not
// have the standard library built yet and may not be able to produce an
// executable. Otherwise we just use the standard compiler we're
// bootstrapping with.
//
// Also note that cargo will detect the version of the compiler to trigger
// a rebuild when the compiler changes. If this happens, we want to make
// sure to use the actual compiler instead of the snapshot compiler becase
// that's the one that's actually changing.
// Use a different compiler for build scripts, since there may not yet be a
// libstd for the real compiler to use. However, if Cargo is attempting to
// determine the version of the compiler, the real compiler needs to be
// used. Currently, these two states are differentiated based on whether
// --target and -vV is/isn't passed.
let (rustc, libdir) = if target.is_none() && version.is_none() {
("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR")
} else {

View File

@ -42,10 +42,13 @@ use config::Target;
pub fn find(build: &mut Build) {
// For all targets we're going to need a C compiler for building some shims
// and such as well as for being a linker for Rust code.
for target in build.config.target.iter() {
//
// This includes targets that aren't necessarily passed on the commandline
// (FIXME: Perhaps it shouldn't?)
for target in &build.config.target {
let mut cfg = gcc::Config::new();
cfg.cargo_metadata(false).opt_level(0).debug(false)
.target(target).host(&build.config.build);
.target(target).host(&build.build);
let config = build.config.target_config.get(target);
if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
@ -64,10 +67,13 @@ pub fn find(build: &mut Build) {
}
// For all host triples we need to find a C++ compiler as well
for host in build.config.host.iter() {
//
// This includes hosts that aren't necessarily passed on the commandline
// (FIXME: Perhaps it shouldn't?)
for host in &build.config.host {
let mut cfg = gcc::Config::new();
cfg.cargo_metadata(false).opt_level(0).debug(false).cpp(true)
.target(host).host(&build.config.build);
.target(host).host(&build.build);
let config = build.config.target_config.get(host);
if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
cfg.compiler(cxx);

View File

@ -23,12 +23,12 @@ use build_helper::output;
use Build;
// The version number
pub const CFG_RELEASE_NUM: &'static str = "1.20.0";
pub const CFG_RELEASE_NUM: &str = "1.20.0";
// An optional number to put after the label, e.g. '.2' -> '-beta.2'
// Be sure to make this starts with a dot to conform to semver pre-release
// versions (section 9)
pub const CFG_PRERELEASE_VERSION: &'static str = ".1";
pub const CFG_PRERELEASE_VERSION: &str = ".1";
pub struct GitInfo {
inner: Option<Info>,
@ -99,6 +99,10 @@ impl GitInfo {
version.push_str(&inner.commit_date);
version.push_str(")");
}
return version
version
}
pub fn is_git(&self) -> bool {
self.inner.is_some()
}
}

View File

@ -13,23 +13,22 @@
//! This file implements the various regression test suites that we execute on
//! our CI.
extern crate build_helper;
use std::collections::HashSet;
use std::env;
use std::iter;
use std::fmt;
use std::fs::{self, File};
use std::path::{PathBuf, Path};
use std::process::Command;
use std::io::Read;
use build_helper::output;
use build_helper::{self, output};
use {Build, Compiler, Mode};
use dist;
use util::{self, dylib_path, dylib_path_var, exe};
const ADB_TEST_DIR: &'static str = "/data/tmp/work";
const ADB_TEST_DIR: &str = "/data/tmp/work";
/// The two modes of the test runner; tests or benchmarks.
#[derive(Copy, Clone)]
@ -60,7 +59,7 @@ impl fmt::Display for TestKind {
}
fn try_run(build: &Build, cmd: &mut Command) {
if build.flags.cmd.no_fail_fast() {
if !build.fail_fast {
if !build.try_run(cmd) {
let failures = build.delayed_failures.get();
build.delayed_failures.set(failures + 1);
@ -71,7 +70,7 @@ fn try_run(build: &Build, cmd: &mut Command) {
}
fn try_run_quiet(build: &Build, cmd: &mut Command) {
if build.flags.cmd.no_fail_fast() {
if !build.fail_fast {
if !build.try_run_quiet(cmd) {
let failures = build.delayed_failures.get();
build.delayed_failures.set(failures + 1);
@ -99,7 +98,7 @@ pub fn linkcheck(build: &Build, host: &str) {
/// This tool in `src/tools` will check out a few Rust projects and run `cargo
/// test` to ensure that we don't regress the test suites there.
pub fn cargotest(build: &Build, stage: u32, host: &str) {
let ref compiler = Compiler::new(stage, host);
let compiler = Compiler::new(stage, host);
// Note that this is a short, cryptic, and not scoped directory name. This
// is currently to minimize the length of path on Windows where we otherwise
@ -109,11 +108,11 @@ pub fn cargotest(build: &Build, stage: u32, host: &str) {
let _time = util::timeit();
let mut cmd = Command::new(build.tool(&Compiler::new(0, host), "cargotest"));
build.prepare_tool_cmd(compiler, &mut cmd);
try_run(build, cmd.arg(&build.cargo)
build.prepare_tool_cmd(&compiler, &mut cmd);
try_run(build, cmd.arg(&build.initial_cargo)
.arg(&out_dir)
.env("RUSTC", build.compiler_path(compiler))
.env("RUSTDOC", build.rustdoc(compiler)));
.env("RUSTC", build.compiler_path(&compiler))
.env("RUSTDOC", build.rustdoc(&compiler)));
}
/// Runs `cargo test` for `cargo` packaged with Rust.
@ -124,13 +123,12 @@ pub fn cargo(build: &Build, stage: u32, host: &str) {
// and not RUSTC because the Cargo test suite has tests that will
// fail if rustc is not spelled `rustc`.
let path = build.sysroot(compiler).join("bin");
let old_path = ::std::env::var("PATH").expect("");
let sep = if cfg!(windows) { ";" } else {":" };
let ref newpath = format!("{}{}{}", path.display(), sep, old_path);
let old_path = env::var_os("PATH").unwrap_or_default();
let newpath = env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("");
let mut cargo = build.cargo(compiler, Mode::Tool, host, "test");
cargo.arg("--manifest-path").arg(build.src.join("src/tools/cargo/Cargo.toml"));
if build.flags.cmd.no_fail_fast() {
if !build.fail_fast {
cargo.arg("--no-fail-fast");
}
@ -198,9 +196,9 @@ pub fn compiletest(build: &Build,
cmd.arg("--mode").arg(mode);
cmd.arg("--target").arg(target);
cmd.arg("--host").arg(compiler.host);
cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build));
cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.build));
if let Some(nodejs) = build.config.nodejs.as_ref() {
if let Some(ref nodejs) = build.config.nodejs {
cmd.arg("--nodejs").arg(nodejs);
}
@ -224,7 +222,7 @@ pub fn compiletest(build: &Build,
cmd.arg("--docck-python").arg(build.python());
if build.config.build.ends_with("apple-darwin") {
if build.build.ends_with("apple-darwin") {
// Force /usr/bin/python on macOS for LLDB tests because we're loading the
// LLDB plugin's compiled module which only works with the system python
// (namely not Homebrew-installed python)
@ -251,7 +249,7 @@ pub fn compiletest(build: &Build,
cmd.args(&build.flags.cmd.test_args());
if build.config.verbose() || build.flags.verbose() {
if build.is_verbose() {
cmd.arg("--verbose");
}
@ -279,7 +277,7 @@ pub fn compiletest(build: &Build,
if build.remote_tested(target) {
cmd.arg("--remote-test-client")
.arg(build.tool(&Compiler::new(0, &build.config.build),
.arg(build.tool(&Compiler::new(0, &build.build),
"remote-test-client"));
}
@ -368,7 +366,7 @@ pub fn error_index(build: &Build, compiler: &Compiler) {
"error_index_generator")
.arg("markdown")
.arg(&output)
.env("CFG_BUILD", &build.config.build));
.env("CFG_BUILD", &build.build));
markdown_test(build, compiler, &output);
}
@ -450,7 +448,7 @@ pub fn krate(build: &Build,
cargo.arg("--manifest-path")
.arg(build.src.join(path).join("Cargo.toml"))
.arg("--features").arg(features);
if test_kind.subcommand() == "test" && build.flags.cmd.no_fail_fast() {
if test_kind.subcommand() == "test" && !build.fail_fast {
cargo.arg("--no-fail-fast");
}
@ -520,16 +518,14 @@ fn krate_emscripten(build: &Build,
compiler: &Compiler,
target: &str,
mode: Mode) {
let mut tests = Vec::new();
let out_dir = build.cargo_out(compiler, mode, target);
find_tests(&out_dir.join("deps"), target, &mut tests);
let tests = find_tests(&out_dir.join("deps"), target);
let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured");
for test in tests {
let test_file_name = test.to_string_lossy().into_owned();
println!("running {}", test_file_name);
let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured");
println!("running {}", test.display());
let mut cmd = Command::new(nodejs);
cmd.arg(&test_file_name);
cmd.arg(&test);
if build.config.quiet_tests {
cmd.arg("--quiet");
}
@ -541,11 +537,10 @@ fn krate_remote(build: &Build,
compiler: &Compiler,
target: &str,
mode: Mode) {
let mut tests = Vec::new();
let out_dir = build.cargo_out(compiler, mode, target);
find_tests(&out_dir.join("deps"), target, &mut tests);
let tests = find_tests(&out_dir.join("deps"), target);
let tool = build.tool(&Compiler::new(0, &build.config.build),
let tool = build.tool(&Compiler::new(0, &build.build),
"remote-test-client");
for test in tests {
let mut cmd = Command::new(&tool);
@ -559,9 +554,8 @@ fn krate_remote(build: &Build,
}
}
fn find_tests(dir: &Path,
target: &str,
dst: &mut Vec<PathBuf>) {
fn find_tests(dir: &Path, target: &str) -> Vec<PathBuf> {
let mut dst = Vec::new();
for e in t!(dir.read_dir()).map(|e| t!(e)) {
let file_type = t!(e.file_type());
if !file_type.is_file() {
@ -576,6 +570,7 @@ fn find_tests(dir: &Path,
dst.push(e.path());
}
}
dst
}
pub fn remote_copy_libs(build: &Build, compiler: &Compiler, target: &str) {
@ -590,7 +585,7 @@ pub fn remote_copy_libs(build: &Build, compiler: &Compiler, target: &str) {
.join(exe("remote-test-server", target));
// Spawn the emulator and wait for it to come online
let tool = build.tool(&Compiler::new(0, &build.config.build),
let tool = build.tool(&Compiler::new(0, &build.build),
"remote-test-client");
let mut cmd = Command::new(&tool);
cmd.arg("spawn-emulator")
@ -616,7 +611,7 @@ pub fn remote_copy_libs(build: &Build, compiler: &Compiler, target: &str) {
/// Run "distcheck", a 'make check' from a tarball
pub fn distcheck(build: &Build) {
if build.config.build != "x86_64-unknown-linux-gnu" {
if build.build != "x86_64-unknown-linux-gnu" {
return
}
if !build.config.host.iter().any(|s| s == "x86_64-unknown-linux-gnu") {
@ -641,7 +636,7 @@ pub fn distcheck(build: &Build) {
.args(&build.config.configure_args)
.arg("--enable-vendor")
.current_dir(&dir));
build.run(Command::new(build_helper::make(&build.config.build))
build.run(Command::new(build_helper::make(&build.build))
.arg("check")
.current_dir(&dir));
@ -659,7 +654,7 @@ pub fn distcheck(build: &Build) {
build.run(&mut cmd);
let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml");
build.run(Command::new(&build.cargo)
build.run(Command::new(&build.initial_cargo)
.arg("generate-lockfile")
.arg("--manifest-path")
.arg(&toml)
@ -668,13 +663,13 @@ pub fn distcheck(build: &Build) {
/// Test the build system itself
pub fn bootstrap(build: &Build) {
let mut cmd = Command::new(&build.cargo);
let mut cmd = Command::new(&build.initial_cargo);
cmd.arg("test")
.current_dir(build.src.join("src/bootstrap"))
.env("CARGO_TARGET_DIR", build.out.join("bootstrap"))
.env("RUSTC_BOOTSTRAP", "1")
.env("RUSTC", &build.rustc);
if build.flags.cmd.no_fail_fast() {
.env("RUSTC", &build.initial_rustc);
if !build.fail_fast {
cmd.arg("--no-fail-fast");
}
cmd.arg("--").args(&build.flags.cmd.test_args());

View File

@ -50,7 +50,7 @@ pub fn std(build: &Build, target: &str, compiler: &Compiler) {
let mut cargo = build.cargo(compiler, Mode::Libstd, target, "build");
let mut features = build.std_features();
if let Ok(target) = env::var("MACOSX_STD_DEPLOYMENT_TARGET") {
if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
}
@ -158,7 +158,7 @@ pub fn build_startup_objects(build: &Build, for_compiler: &Compiler, target: &st
return
}
let compiler = Compiler::new(0, &build.config.build);
let compiler = Compiler::new(0, &build.build);
let compiler_path = build.compiler_path(&compiler);
let src_dir = &build.src.join("src/rtstartup");
let dst_dir = &build.native_dir(target).join("rtstartup");
@ -199,7 +199,7 @@ pub fn test(build: &Build, target: &str, compiler: &Compiler) {
let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build");
if let Ok(target) = env::var("MACOSX_STD_DEPLOYMENT_TARGET") {
if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
}
cargo.arg("--manifest-path")
@ -247,7 +247,7 @@ pub fn rustc(build: &Build, target: &str, compiler: &Compiler) {
cargo.env("CFG_RELEASE", build.rust_release())
.env("CFG_RELEASE_CHANNEL", &build.config.channel)
.env("CFG_VERSION", build.rust_version())
.env("CFG_PREFIX", build.config.prefix.clone().unwrap_or(PathBuf::new()));
.env("CFG_PREFIX", build.config.prefix.clone().unwrap_or_default());
if compiler.stage == 0 {
cargo.env("CFG_LIBDIR_RELATIVE", "lib");
@ -351,7 +351,7 @@ pub fn create_sysroot(build: &Build, compiler: &Compiler) {
/// Prepare a new compiler from the artifacts in `stage`
///
/// This will assemble a compiler in `build/$host/stage$stage`. The compiler
/// must have been previously produced by the `stage - 1` build.config.build
/// must have been previously produced by the `stage - 1` build.build
/// compiler.
pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
// nothing to do in stage0
@ -365,7 +365,7 @@ pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
let target_compiler = Compiler::new(stage, host);
// The compiler that compiled the compiler we're assembling
let build_compiler = Compiler::new(stage - 1, &build.config.build);
let build_compiler = Compiler::new(stage - 1, &build.build);
// Link in all dylibs to the libdir
let sysroot = build.sysroot(&target_compiler);
@ -385,7 +385,7 @@ pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
let rustc = out_dir.join(exe("rustc", host));
let bindir = sysroot.join("bin");
t!(fs::create_dir_all(&bindir));
let compiler = build.compiler_path(&Compiler::new(stage, host));
let compiler = build.compiler_path(&target_compiler);
let _ = fs::remove_file(&compiler);
copy(&rustc, &compiler);
@ -407,6 +407,8 @@ fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) {
t!(fs::create_dir_all(&sysroot_dst));
let mut contents = Vec::new();
t!(t!(File::open(stamp)).read_to_end(&mut contents));
// This is the method we use for extracting paths from the stamp file passed to us. See
// run_cargo for more information (in this file).
for part in contents.split(|b| *b == 0) {
if part.is_empty() {
continue
@ -421,7 +423,7 @@ fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) {
/// This will build the specified tool with the specified `host` compiler in
/// `stage` into the normal cargo output directory.
pub fn maybe_clean_tools(build: &Build, stage: u32, target: &str, mode: Mode) {
let compiler = Compiler::new(stage, &build.config.build);
let compiler = Compiler::new(stage, &build.build);
let stamp = match mode {
Mode::Libstd => libstd_stamp(build, &compiler, target),
@ -441,7 +443,7 @@ pub fn tool(build: &Build, stage: u32, target: &str, tool: &str) {
let _folder = build.fold_output(|| format!("stage{}-{}", stage, tool));
println!("Building stage{} tool {} ({})", stage, tool, target);
let compiler = Compiler::new(stage, &build.config.build);
let compiler = Compiler::new(stage, &build.build);
let mut cargo = build.cargo(&compiler, Mode::Tool, target, "build");
let dir = build.src.join("src/tools").join(tool);
@ -557,23 +559,24 @@ fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path) {
// If this was an output file in the "host dir" we don't actually
// worry about it, it's not relevant for us.
if filename.starts_with(&host_root_dir) {
continue
continue;
}
// If this was output in the `deps` dir then this is a precise file
// name (hash included) so we start tracking it.
} else if filename.starts_with(&target_deps_dir) {
if filename.starts_with(&target_deps_dir) {
deps.push(filename.to_path_buf());
continue;
}
// Otherwise this was a "top level artifact" which right now doesn't
// have a hash in the name, but there's a version of this file in
// the `deps` folder which *does* have a hash in the name. That's
// the one we'll want to we'll probe for it later.
} else {
toplevel.push((filename.file_stem().unwrap()
.to_str().unwrap().to_string(),
filename.extension().unwrap().to_owned()
.to_str().unwrap().to_string()));
}
toplevel.push((filename.file_stem().unwrap()
.to_str().unwrap().to_string(),
filename.extension().unwrap().to_owned()
.to_str().unwrap().to_string()));
}
}

View File

@ -81,8 +81,6 @@ pub struct Config {
pub build: String,
pub host: Vec<String>,
pub target: Vec<String>,
pub rustc: Option<PathBuf>,
pub cargo: Option<PathBuf>,
pub local_rebuild: bool,
// dist misc
@ -114,11 +112,18 @@ pub struct Config {
pub python: Option<PathBuf>,
pub configure_args: Vec<String>,
pub openssl_static: bool,
// These are either the stage0 downloaded binaries or the locally installed ones.
pub initial_cargo: PathBuf,
pub initial_rustc: PathBuf,
}
/// Per-target configuration stored in the global configuration structure.
#[derive(Default)]
pub struct Target {
/// Some(path to llvm-config) if using an external LLVM.
pub llvm_config: Option<PathBuf>,
pub jemalloc: Option<PathBuf>,
pub cc: Option<PathBuf>,
@ -307,8 +312,6 @@ impl Config {
config.target.push(target.clone());
}
}
config.rustc = build.rustc.map(PathBuf::from);
config.cargo = build.cargo.map(PathBuf::from);
config.nodejs = build.nodejs.map(PathBuf::from);
config.gdb = build.gdb.map(PathBuf::from);
config.python = build.python.map(PathBuf::from);
@ -410,13 +413,25 @@ impl Config {
set(&mut config.rust_dist_src, t.src_tarball);
}
let cwd = t!(env::current_dir());
let out = cwd.join("build");
let stage0_root = out.join(&config.build).join("stage0/bin");
config.initial_rustc = match build.rustc {
Some(s) => PathBuf::from(s),
None => stage0_root.join(exe("rustc", &config.build)),
};
config.initial_cargo = match build.cargo {
Some(s) => PathBuf::from(s),
None => stage0_root.join(exe("cargo", &config.build)),
};
// compat with `./configure` while we're still using that
if fs::metadata("config.mk").is_ok() {
config.update_with_config_mk();
}
return config
config
}
/// "Temporary" routine to parse `config.mk` into this configuration.
@ -609,8 +624,8 @@ impl Config {
}
"CFG_LOCAL_RUST_ROOT" if value.len() > 0 => {
let path = parse_configure_path(value);
self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"]));
self.cargo = Some(push_exe_path(path, &["bin", "cargo"]));
self.initial_rustc = push_exe_path(path.clone(), &["bin", "rustc"]);
self.initial_cargo = push_exe_path(path, &["bin", "cargo"]);
}
"CFG_PYTHON" if value.len() > 0 => {
let path = parse_configure_path(value);

View File

@ -50,7 +50,7 @@ pub fn tmpdir(build: &Build) -> PathBuf {
}
fn rust_installer(build: &Build) -> Command {
build.tool_cmd(&Compiler::new(0, &build.config.build), "rust-installer")
build.tool_cmd(&Compiler::new(0, &build.build), "rust-installer")
}
/// Builds the `rust-docs` installer component.
@ -89,7 +89,7 @@ pub fn docs(build: &Build, stage: u32, host: &str) {
// As part of this step, *also* copy the docs directory to a directory which
// buildbot typically uploads.
if host == build.config.build {
if host == build.build {
let dst = distdir(build).join("doc").join(build.rust_package_vers());
t!(fs::create_dir_all(&dst));
cp_r(&src, &dst);
@ -97,7 +97,7 @@ pub fn docs(build: &Build, stage: u32, host: &str) {
}
fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
let mut found = Vec::new();
let mut found = Vec::with_capacity(files.len());
for file in files {
let file_path =
@ -119,17 +119,9 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build:
//Ask gcc where it keeps its stuff
let mut cmd = Command::new(build.cc(target_triple));
cmd.arg("-print-search-dirs");
build.run_quiet(&mut cmd);
let gcc_out =
String::from_utf8(
cmd
.output()
.expect("failed to execute gcc")
.stdout).expect("gcc.exe output was not utf8");
let gcc_out = output(&mut cmd);
let mut bin_path: Vec<_> =
env::split_paths(&env::var_os("PATH").unwrap_or_default())
.collect();
let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect();
let mut lib_path = Vec::new();
for line in gcc_out.lines() {
@ -140,7 +132,7 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build:
line[(idx + 1)..]
.trim_left_matches(trim_chars)
.split(';')
.map(|s| PathBuf::from(s));
.map(PathBuf::from);
if key == "programs" {
bin_path.extend(value);
@ -149,7 +141,7 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build:
}
}
let target_tools = vec!["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe", "libwinpthread-1.dll"];
let target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe", "libwinpthread-1.dll"];
let mut rustc_dlls = vec!["libstdc++-6.dll", "libwinpthread-1.dll"];
if target_triple.starts_with("i686-") {
rustc_dlls.push("libgcc_s_dw2-1.dll");
@ -157,7 +149,7 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build:
rustc_dlls.push("libgcc_s_seh-1.dll");
}
let target_libs = vec![ //MinGW libs
let target_libs = [ //MinGW libs
"libgcc.a",
"libgcc_eh.a",
"libgcc_s.a",
@ -203,7 +195,7 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build:
let target_libs = find_files(&target_libs, &lib_path);
fn copy_to_folder(src: &Path, dest_folder: &Path) {
let file_name = src.file_name().unwrap().to_os_string();
let file_name = src.file_name().unwrap();
let dest = dest_folder.join(file_name);
copy(src, &dest);
}
@ -234,8 +226,6 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build:
///
/// This contains all the bits and pieces to run the MinGW Windows targets
/// without any extra installed software (e.g. we bundle gcc, libraries, etc).
/// Currently just shells out to a python script, but that should be rewritten
/// in Rust.
pub fn mingw(build: &Build, host: &str) {
println!("Dist mingw ({})", host);
let name = pkgname(build, "rust-mingw");
@ -366,9 +356,9 @@ pub fn rustc(build: &Build, stage: u32, host: &str) {
pub fn debugger_scripts(build: &Build,
sysroot: &Path,
host: &str) {
let dst = sysroot.join("lib/rustlib/etc");
t!(fs::create_dir_all(&dst));
let cp_debugger_script = |file: &str| {
let dst = sysroot.join("lib/rustlib/etc");
t!(fs::create_dir_all(&dst));
install(&build.src.join("src/etc/").join(file), &dst, 0o644);
};
if host.contains("windows-msvc") {
@ -404,7 +394,7 @@ pub fn std(build: &Build, compiler: &Compiler, target: &str) {
// The only true set of target libraries came from the build triple, so
// let's reduce redundant work by only producing archives from that host.
if compiler.host != build.config.build {
if compiler.host != build.build {
println!("\tskipping, not a build host");
return
}
@ -450,7 +440,7 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) {
assert!(build.config.extended);
println!("Dist analysis");
if compiler.host != build.config.build {
if compiler.host != build.build {
println!("\tskipping, not a build host");
return;
}
@ -498,12 +488,11 @@ fn copy_src_dirs(build: &Build, src_dirs: &[&str], exclude_dirs: &[&str], dst_di
if spath.ends_with("~") || spath.ends_with(".pyc") {
return false
}
if spath.contains("llvm/test") || spath.contains("llvm\\test") {
if spath.ends_with(".ll") ||
spath.ends_with(".td") ||
spath.ends_with(".s") {
return false
}
if (spath.contains("llvm/test") || spath.contains("llvm\\test")) &&
(spath.ends_with(".ll") ||
spath.ends_with(".td") ||
spath.ends_with(".s")) {
return false
}
let full_path = Path::new(dir).join(path);
@ -595,7 +584,7 @@ pub fn rust_src(build: &Build) {
t!(fs::remove_dir_all(&image));
}
const CARGO_VENDOR_VERSION: &'static str = "0.1.4";
const CARGO_VENDOR_VERSION: &str = "0.1.4";
/// Creates the plain source tarball
pub fn plain_source_tarball(build: &Build) {
@ -634,26 +623,26 @@ pub fn plain_source_tarball(build: &Build) {
write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes());
// If we're building from git sources, we need to vendor a complete distribution.
if build.src_is_git {
if build.rust_info.is_git() {
// Get cargo-vendor installed, if it isn't already.
let mut has_cargo_vendor = false;
let mut cmd = Command::new(&build.cargo);
let mut cmd = Command::new(&build.initial_cargo);
for line in output(cmd.arg("install").arg("--list")).lines() {
has_cargo_vendor |= line.starts_with("cargo-vendor ");
}
if !has_cargo_vendor {
let mut cmd = Command::new(&build.cargo);
let mut cmd = Command::new(&build.initial_cargo);
cmd.arg("install")
.arg("--force")
.arg("--debug")
.arg("--vers").arg(CARGO_VENDOR_VERSION)
.arg("cargo-vendor")
.env("RUSTC", &build.rustc);
.env("RUSTC", &build.initial_rustc);
build.run(&mut cmd);
}
// Vendor all Cargo dependencies
let mut cmd = Command::new(&build.cargo);
let mut cmd = Command::new(&build.initial_cargo);
cmd.arg("vendor")
.current_dir(&plain_dst_src.join("src"));
build.run(&mut cmd);
@ -716,7 +705,7 @@ fn write_file(path: &Path, data: &[u8]) {
pub fn cargo(build: &Build, stage: u32, target: &str) {
println!("Dist cargo stage{} ({})", stage, target);
let compiler = Compiler::new(stage, &build.config.build);
let compiler = Compiler::new(stage, &build.build);
let src = build.src.join("src/tools/cargo");
let etc = src.join("src/etc");
@ -777,7 +766,7 @@ pub fn cargo(build: &Build, stage: u32, target: &str) {
pub fn rls(build: &Build, stage: u32, target: &str) {
assert!(build.config.extended);
println!("Dist RLS stage{} ({})", stage, target);
let compiler = Compiler::new(stage, &build.config.build);
let compiler = Compiler::new(stage, &build.build);
let src = build.src.join("src/tools/rls");
let release_num = build.release_num("rls");
@ -1209,7 +1198,7 @@ fn add_env(build: &Build, cmd: &mut Command, target: &str) {
}
pub fn hash_and_sign(build: &Build) {
let compiler = Compiler::new(0, &build.config.build);
let compiler = Compiler::new(0, &build.build);
let mut cmd = build.tool_cmd(&compiler, "build-manifest");
let sign = build.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")

View File

@ -45,7 +45,7 @@ pub fn rustbook_src(build: &Build, target: &str, name: &str, src: &Path) {
t!(fs::create_dir_all(&out));
let out = out.join(name);
let compiler = Compiler::new(0, &build.config.build);
let compiler = Compiler::new(0, &build.build);
let src = src.join(name);
let index = out.join("index.html");
let rustbook = build.tool(&compiler, "rustbook");
@ -95,7 +95,7 @@ pub fn book(build: &Build, target: &str, name: &str) {
fn invoke_rustdoc(build: &Build, target: &str, markdown: &str) {
let out = build.doc_out(target);
let compiler = Compiler::new(0, &build.config.build);
let compiler = Compiler::new(0, &build.build);
let path = build.src.join("src/doc").join(markdown);
@ -150,7 +150,7 @@ pub fn standalone(build: &Build, target: &str) {
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = Compiler::new(0, &build.config.build);
let compiler = Compiler::new(0, &build.build);
let favicon = build.src.join("src/doc/favicon.inc");
let footer = build.src.join("src/doc/footer.inc");
@ -217,7 +217,7 @@ pub fn std(build: &Build, stage: u32, target: &str) {
println!("Documenting stage{} std ({})", stage, target);
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = Compiler::new(stage, &build.config.build);
let compiler = Compiler::new(stage, &build.build);
let compiler = if build.force_use_stage1(&compiler, target) {
Compiler::new(1, compiler.host)
} else {
@ -276,7 +276,7 @@ pub fn test(build: &Build, stage: u32, target: &str) {
println!("Documenting stage{} test ({})", stage, target);
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = Compiler::new(stage, &build.config.build);
let compiler = Compiler::new(stage, &build.build);
let compiler = if build.force_use_stage1(&compiler, target) {
Compiler::new(1, compiler.host)
} else {
@ -306,7 +306,7 @@ pub fn rustc(build: &Build, stage: u32, target: &str) {
println!("Documenting stage{} compiler ({})", stage, target);
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = Compiler::new(stage, &build.config.build);
let compiler = Compiler::new(stage, &build.build);
let compiler = if build.force_use_stage1(&compiler, target) {
Compiler::new(1, compiler.host)
} else {
@ -351,13 +351,13 @@ pub fn error_index(build: &Build, target: &str) {
println!("Documenting error index ({})", target);
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = Compiler::new(0, &build.config.build);
let compiler = Compiler::new(0, &build.build);
let mut index = build.tool_cmd(&compiler, "error_index_generator");
index.arg("html");
index.arg(out.join("error-index.html"));
// FIXME: shouldn't have to pass this env var
index.env("CFG_BUILD", &build.config.build);
index.env("CFG_BUILD", &build.build);
build.run(&mut index);
}
@ -367,7 +367,7 @@ pub fn unstable_book_gen(build: &Build, target: &str) {
let out = build.md_doc_out(target).join("unstable-book");
t!(fs::create_dir_all(&out));
t!(fs::remove_dir_all(&out));
let compiler = Compiler::new(0, &build.config.build);
let compiler = Compiler::new(0, &build.build);
let mut cmd = build.tool_cmd(&compiler, "unstable-book-gen");
cmd.arg(build.src.join("src"));
cmd.arg(out);

View File

@ -35,22 +35,12 @@ pub struct Flags {
pub host: Vec<String>,
pub target: Vec<String>,
pub config: Option<PathBuf>,
pub src: Option<PathBuf>,
pub src: PathBuf,
pub jobs: Option<u32>,
pub cmd: Subcommand,
pub incremental: bool,
}
impl Flags {
pub fn verbose(&self) -> bool {
self.verbose > 0
}
pub fn very_verbose(&self) -> bool {
self.verbose > 1
}
}
pub enum Subcommand {
Build {
paths: Vec<PathBuf>,
@ -61,7 +51,7 @@ pub enum Subcommand {
Test {
paths: Vec<PathBuf>,
test_args: Vec<String>,
no_fail_fast: bool,
fail_fast: bool,
},
Bench {
paths: Vec<PathBuf>,
@ -122,16 +112,15 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
// the subcommand. Therefore we must manually identify the subcommand first, so that we can
// complete the definition of the options. Then we can use the getopt::Matches object from
// there on out.
let mut possible_subcommands = args.iter().collect::<Vec<_>>();
possible_subcommands.retain(|&s|
(s == "build")
|| (s == "test")
|| (s == "bench")
|| (s == "doc")
|| (s == "clean")
|| (s == "dist")
|| (s == "install"));
let subcommand = match possible_subcommands.first() {
let subcommand = args.iter().find(|&s|
(s == "build")
|| (s == "test")
|| (s == "bench")
|| (s == "doc")
|| (s == "clean")
|| (s == "dist")
|| (s == "install"));
let subcommand = match subcommand {
Some(s) => s,
None => {
// No subcommand -- show the general usage and subcommand help
@ -164,7 +153,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
let mut pass_sanity_check = true;
match matches.free.get(0) {
Some(check_subcommand) => {
if &check_subcommand != subcommand {
if check_subcommand != subcommand {
pass_sanity_check = false;
}
},
@ -279,7 +268,7 @@ Arguments:
Subcommand::Test {
paths: paths,
test_args: matches.opt_strs("test-args"),
no_fail_fast: matches.opt_present("no-fail-fast"),
fail_fast: !matches.opt_present("no-fail-fast"),
}
}
"bench" => {
@ -316,12 +305,15 @@ Arguments:
let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap());
if matches.opt_present("incremental") {
if stage.is_none() {
stage = Some(1);
}
if matches.opt_present("incremental") && stage.is_none() {
stage = Some(1);
}
let cwd = t!(env::current_dir());
let src = matches.opt_str("src").map(PathBuf::from)
.or_else(|| env::var_os("SRC").map(PathBuf::from))
.unwrap_or(cwd);
Flags {
verbose: matches.opt_count("verbose"),
stage: stage,
@ -333,7 +325,7 @@ Arguments:
host: split(matches.opt_strs("host")),
target: split(matches.opt_strs("target")),
config: cfg_file,
src: matches.opt_str("src").map(PathBuf::from),
src: src,
jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()),
cmd: cmd,
incremental: matches.opt_present("incremental"),
@ -352,9 +344,9 @@ impl Subcommand {
}
}
pub fn no_fail_fast(&self) -> bool {
pub fn fail_fast(&self) -> bool {
match *self {
Subcommand::Test { no_fail_fast, .. } => no_fail_fast,
Subcommand::Test { fail_fast, .. } => fail_fast,
_ => false,
}
}

View File

@ -146,5 +146,5 @@ fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
_ => {}
}
}
return ret
ret
}

View File

@ -161,25 +161,35 @@ pub struct Build {
flags: Flags,
// Derived properties from the above two configurations
cargo: PathBuf,
rustc: PathBuf,
src: PathBuf,
out: PathBuf,
rust_info: channel::GitInfo,
cargo_info: channel::GitInfo,
rls_info: channel::GitInfo,
local_rebuild: bool,
fail_fast: bool,
verbosity: usize,
// Targets for which to build.
build: String,
hosts: Vec<String>,
targets: Vec<String>,
// Stage 0 (downloaded) compiler and cargo or their local rust equivalents.
initial_rustc: PathBuf,
initial_cargo: PathBuf,
// Probed tools at runtime
lldb_version: Option<String>,
lldb_python_dir: Option<String>,
// Runtime state filled in later on
// target -> (cc, ar)
cc: HashMap<String, (gcc::Tool, Option<PathBuf>)>,
// host -> (cc, ar)
cxx: HashMap<String, gcc::Tool>,
crates: HashMap<String, Crate>,
is_sudo: bool,
src_is_git: bool,
ci_env: CiEnv,
delayed_failures: Cell<usize>,
}
@ -202,20 +212,16 @@ struct Crate {
/// build system, with each mod generating output in a different directory.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Mode {
/// This cargo is going to build the standard library, placing output in the
/// "stageN-std" directory.
/// Build the standard library, placing output in the "stageN-std" directory.
Libstd,
/// This cargo is going to build libtest, placing output in the
/// "stageN-test" directory.
/// Build libtest, placing output in the "stageN-test" directory.
Libtest,
/// This cargo is going to build librustc and compiler libraries, placing
/// output in the "stageN-rustc" directory.
/// Build librustc and compiler libraries, placing output in the "stageN-rustc" directory.
Librustc,
/// This cargo is going to build some tool, placing output in the
/// "stageN-tools" directory.
/// Build some tool, placing output in the "stageN-tools" directory.
Tool,
}
@ -226,22 +232,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().or_else(|| {
env::var_os("SRC").map(|x| x.into())
}).unwrap_or(cwd.clone());
let src = flags.src.clone();
let out = cwd.join("build");
let stage0_root = out.join(&config.build).join("stage0/bin");
let rustc = match config.rustc {
Some(ref s) => PathBuf::from(s),
None => stage0_root.join(exe("rustc", &config.build)),
};
let cargo = match config.cargo {
Some(ref s) => PathBuf::from(s),
None => stage0_root.join(exe("cargo", &config.build)),
};
let local_rebuild = config.local_rebuild;
let is_sudo = match env::var_os("SUDO_USER") {
Some(sudo_user) => {
match env::var_os("USER") {
@ -254,32 +247,64 @@ impl Build {
let rust_info = channel::GitInfo::new(&src);
let cargo_info = channel::GitInfo::new(&src.join("src/tools/cargo"));
let rls_info = channel::GitInfo::new(&src.join("src/tools/rls"));
let src_is_git = src.join(".git").exists();
let hosts = if !flags.host.is_empty() {
for host in flags.host.iter() {
if !config.host.contains(host) {
panic!("specified host `{}` is not in configuration", host);
}
}
flags.host.clone()
} else {
config.host.clone()
};
let targets = if !flags.target.is_empty() {
for target in flags.target.iter() {
if !config.target.contains(target) {
panic!("specified target `{}` is not in configuration", target);
}
}
flags.target.clone()
} else {
config.target.clone()
};
Build {
initial_rustc: config.initial_rustc.clone(),
initial_cargo: config.initial_cargo.clone(),
local_rebuild: config.local_rebuild,
fail_fast: flags.cmd.fail_fast(),
verbosity: cmp::max(flags.verbose, config.verbose),
build: config.host[0].clone(),
hosts: hosts,
targets: targets,
flags: flags,
config: config,
cargo: cargo,
rustc: rustc,
src: src,
out: out,
rust_info: rust_info,
cargo_info: cargo_info,
rls_info: rls_info,
local_rebuild: local_rebuild,
cc: HashMap::new(),
cxx: HashMap::new(),
crates: HashMap::new(),
lldb_version: None,
lldb_python_dir: None,
is_sudo: is_sudo,
src_is_git: src_is_git,
ci_env: CiEnv::current(),
delayed_failures: Cell::new(0),
}
}
fn build_slice(&self) -> &[String] {
unsafe {
std::slice::from_raw_parts(&self.build, 1)
}
}
/// Executes the entire build, as configured by the flags and configuration.
pub fn build(&mut self) {
unsafe {
@ -296,7 +321,7 @@ impl Build {
sanity::check(self);
// If local-rust is the same major.minor as the current version, then force a local-rebuild
let local_version_verbose = output(
Command::new(&self.rustc).arg("--version").arg("--verbose"));
Command::new(&self.initial_rustc).arg("--version").arg("--verbose"));
let local_release = local_version_verbose
.lines().filter(|x| x.starts_with("release:"))
.next().unwrap().trim_left_matches("release:").trim();
@ -338,7 +363,7 @@ impl Build {
mode: Mode,
target: &str,
cmd: &str) -> Command {
let mut cargo = Command::new(&self.cargo);
let mut cargo = Command::new(&self.initial_cargo);
let out_dir = self.stage_out(compiler, mode);
cargo.env("CARGO_TARGET_DIR", out_dir)
.arg(cmd)
@ -422,7 +447,7 @@ impl Build {
// library up and running, so we can use the normal compiler to compile
// build scripts in that situation.
if mode == Mode::Libstd {
cargo.env("RUSTC_SNAPSHOT", &self.rustc)
cargo.env("RUSTC_SNAPSHOT", &self.initial_rustc)
.env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
} else {
cargo.env("RUSTC_SNAPSHOT", self.compiler_path(compiler))
@ -441,8 +466,7 @@ impl Build {
cargo.env("RUSTC_ON_FAIL", on_fail);
}
let verbose = cmp::max(self.config.verbose, self.flags.verbose);
cargo.env("RUSTC_VERBOSE", format!("{}", verbose));
cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity));
// Specify some various options for build scripts used throughout
// the build.
@ -480,7 +504,7 @@ impl Build {
// FIXME: should update code to not require this env var
cargo.env("CFG_COMPILER_HOST_TRIPLE", target);
if self.config.verbose() || self.flags.verbose() {
if self.is_verbose() {
cargo.arg("-v");
}
// FIXME: cargo bench does not accept `--release`
@ -496,13 +520,13 @@ impl Build {
self.ci_env.force_coloring_in_ci(&mut cargo);
return cargo
cargo
}
/// Get a path to the compiler specified.
fn compiler_path(&self, compiler: &Compiler) -> PathBuf {
if compiler.is_snapshot(self) {
self.rustc.clone()
self.initial_rustc.clone()
} else {
self.sysroot(compiler).join("bin").join(exe("rustc", compiler.host))
}
@ -519,7 +543,7 @@ impl Build {
let mut rustdoc = self.compiler_path(compiler);
rustdoc.pop();
rustdoc.push(exe("rustdoc", compiler.host));
return rustdoc
rustdoc
}
/// Get a `Command` which is ready to run `tool` in `stage` built for
@ -527,7 +551,7 @@ impl Build {
fn tool_cmd(&self, compiler: &Compiler, tool: &str) -> Command {
let mut cmd = Command::new(self.tool(&compiler, tool));
self.prepare_tool_cmd(compiler, &mut cmd);
return cmd
cmd
}
/// Prepares the `cmd` provided to be able to run the `compiler` provided.
@ -578,7 +602,7 @@ impl Build {
if self.config.profiler {
features.push_str(" profiler");
}
return features
features
}
/// Get the space-separated set of activated features for the compiler.
@ -587,7 +611,7 @@ impl Build {
if self.config.use_jemalloc {
features.push_str(" jemalloc");
}
return features
features
}
/// Component directory that Cargo will produce output into (e.g.
@ -760,7 +784,7 @@ impl Build {
/// Returns the libdir of the snapshot compiler.
fn rustc_snapshot_libdir(&self) -> PathBuf {
self.rustc.parent().unwrap().parent().unwrap()
self.initial_rustc.parent().unwrap().parent().unwrap()
.join(libdir(&self.config.build))
}
@ -792,9 +816,17 @@ impl Build {
try_run_suppressed(cmd)
}
pub fn is_verbose(&self) -> bool {
self.verbosity > 0
}
pub fn is_very_verbose(&self) -> bool {
self.verbosity > 1
}
/// Prints a message if this build is configured in verbose mode.
fn verbose(&self, msg: &str) {
if self.flags.verbose() || self.config.verbose() {
if self.is_verbose() {
println!("{}", msg);
}
}
@ -802,7 +834,7 @@ impl Build {
/// Returns the number of parallel jobs that have been configured for this
/// build.
fn jobs(&self) -> u32 {
self.flags.jobs.unwrap_or(num_cpus::get() as u32)
self.flags.jobs.unwrap_or_else(|| num_cpus::get() as u32)
}
/// Returns the path to the C compiler for the target specified.
@ -834,7 +866,7 @@ impl Build {
if target == "i686-pc-windows-gnu" {
base.push("-fno-omit-frame-pointer".into());
}
return base
base
}
/// Returns the path to the `ar` archive utility for the target specified.
@ -866,7 +898,7 @@ impl Build {
!target.contains("emscripten") {
base.push(format!("-Clinker={}", self.cc(target).display()));
}
return base
base
}
/// Returns the "musl root" for this `target`, if defined
@ -1047,7 +1079,7 @@ impl<'a> Compiler<'a> {
/// Returns whether this is a snapshot compiler for `build`'s configuration
fn is_snapshot(&self, build: &Build) -> bool {
self.stage == 0 && self.host == build.config.build
self.stage == 0 && self.host == build.build
}
/// Returns if this compiler should be treated as a final stage one in the

View File

@ -56,7 +56,7 @@ fn build_krate(build: &mut Build, krate: &str) {
// 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);
let mut cargo = Command::new(&build.initial_cargo);
cargo.arg("metadata")
.arg("--format-version").arg("1")
.arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml"));

View File

@ -94,7 +94,7 @@ pub fn llvm(build: &Build, target: &str) {
let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"};
cfg.target(target)
.host(&build.config.build)
.host(&build.build)
.out_dir(&out_dir)
.profile(profile)
.define("LLVM_ENABLE_ASSERTIONS", assertions)
@ -129,11 +129,11 @@ pub fn llvm(build: &Build, target: &str) {
}
// http://llvm.org/docs/HowToCrossCompileLLVM.html
if target != build.config.build {
if target != build.build {
// FIXME: if the llvm root for the build triple is overridden then we
// should use llvm-tblgen from there, also should verify that it
// actually exists most of the time in normal installs of LLVM.
let host = build.llvm_out(&build.config.build).join("bin/llvm-tblgen");
let host = build.llvm_out(&build.build).join("bin/llvm-tblgen");
cfg.define("CMAKE_CROSSCOMPILING", "True")
.define("LLVM_TABLEGEN", &host);
}
@ -243,7 +243,7 @@ pub fn test_helpers(build: &Build, target: &str) {
cfg.cargo_metadata(false)
.out_dir(&dst)
.target(target)
.host(&build.config.build)
.host(&build.build)
.opt_level(0)
.debug(false)
.file(build.src.join("src/rt/rust_test_helpers.c"))

View File

@ -18,9 +18,9 @@
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!
use std::collections::HashSet;
use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::ffi::{OsString, OsStr};
use std::fs;
use std::process::Command;
use std::path::PathBuf;
@ -29,45 +29,59 @@ use build_helper::output;
use Build;
struct Finder {
cache: HashMap<OsString, Option<PathBuf>>,
path: OsString,
}
impl Finder {
fn new() -> Self {
Self {
cache: HashMap::new(),
path: env::var_os("PATH").unwrap_or_default()
}
}
fn maybe_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> Option<PathBuf> {
let cmd: OsString = cmd.as_ref().into();
let path = self.path.clone();
self.cache.entry(cmd.clone()).or_insert_with(|| {
for path in env::split_paths(&path) {
let target = path.join(&cmd);
let mut cmd_alt = cmd.clone();
cmd_alt.push(".exe");
if target.is_file() || // some/path/git
target.with_extension("exe").exists() || // some/path/git.exe
target.join(&cmd_alt).exists() { // some/path/git/git.exe
return Some(target);
}
}
None
}).clone()
}
fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
self.maybe_have(&cmd).unwrap_or_else(|| {
panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
})
}
}
pub fn check(build: &mut Build) {
let mut checked = HashSet::new();
let path = env::var_os("PATH").unwrap_or(OsString::new());
let path = env::var_os("PATH").unwrap_or_default();
// On Windows, quotes are invalid characters for filename paths, and if
// one is present as part of the PATH then that can lead to the system
// being unable to identify the files properly. See
// https://github.com/rust-lang/rust/issues/34959 for more details.
if cfg!(windows) {
if path.to_string_lossy().contains("\"") {
panic!("PATH contains invalid character '\"'");
}
if cfg!(windows) && path.to_string_lossy().contains("\"") {
panic!("PATH contains invalid character '\"'");
}
let have_cmd = |cmd: &OsStr| {
for path in env::split_paths(&path) {
let target = path.join(cmd);
let mut cmd_alt = cmd.to_os_string();
cmd_alt.push(".exe");
if target.is_file() ||
target.with_extension("exe").exists() ||
target.join(cmd_alt).exists() {
return Some(target);
}
}
return None;
};
let mut need_cmd = |cmd: &OsStr| {
if !checked.insert(cmd.to_owned()) {
return
}
if have_cmd(cmd).is_none() {
panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
}
};
let mut cmd_finder = Finder::new();
// If we've got a git directory we're gona need git to update
// submodules and learn about various other aspects.
if build.src_is_git {
need_cmd("git".as_ref());
if build.rust_info.is_git() {
cmd_finder.must_have("git");
}
// We need cmake, but only if we're actually building LLVM or sanitizers.
@ -75,57 +89,32 @@ pub fn check(build: &mut Build) {
.filter_map(|host| build.config.target_config.get(host))
.any(|config| config.llvm_config.is_none());
if building_llvm || build.config.sanitizers {
need_cmd("cmake".as_ref());
cmd_finder.must_have("cmake");
}
// Ninja is currently only used for LLVM itself.
if building_llvm && build.config.ninja {
// Some Linux distros rename `ninja` to `ninja-build`.
// CMake can work with either binary name.
if have_cmd("ninja-build".as_ref()).is_none() {
need_cmd("ninja".as_ref());
}
// Some Linux distros rename `ninja` to `ninja-build`.
// CMake can work with either binary name.
if building_llvm && build.config.ninja && cmd_finder.maybe_have("ninja-build").is_none() {
cmd_finder.must_have("ninja");
}
if build.config.python.is_none() {
// set by bootstrap.py
if let Some(v) = env::var_os("BOOTSTRAP_PYTHON") {
build.config.python = Some(PathBuf::from(v));
}
}
if build.config.python.is_none() {
build.config.python = have_cmd("python2.7".as_ref());
}
if build.config.python.is_none() {
build.config.python = have_cmd("python2".as_ref());
}
if build.config.python.is_none() {
need_cmd("python".as_ref());
build.config.python = Some("python".into());
}
need_cmd(build.config.python.as_ref().unwrap().as_ref());
build.config.python = build.config.python.take().map(|p| cmd_finder.must_have(p))
.or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
.or_else(|| cmd_finder.maybe_have("python2.7"))
.or_else(|| cmd_finder.maybe_have("python2"))
.or_else(|| Some(cmd_finder.must_have("python")));
build.config.nodejs = build.config.nodejs.take().map(|p| cmd_finder.must_have(p))
.or_else(|| cmd_finder.maybe_have("node"))
.or_else(|| cmd_finder.maybe_have("nodejs"));
if let Some(ref s) = build.config.nodejs {
need_cmd(s.as_ref());
} else {
// Look for the nodejs command, needed for emscripten testing
if let Some(node) = have_cmd("node".as_ref()) {
build.config.nodejs = Some(node);
} else if let Some(node) = have_cmd("nodejs".as_ref()) {
build.config.nodejs = Some(node);
}
}
if let Some(ref gdb) = build.config.gdb {
need_cmd(gdb.as_ref());
} else {
build.config.gdb = have_cmd("gdb".as_ref());
}
build.config.gdb = build.config.gdb.take().map(|p| cmd_finder.must_have(p))
.or_else(|| cmd_finder.maybe_have("gdb"));
// We're gonna build some custom C code here and there, host triples
// also build some C++ shims for LLVM so we need a C++ compiler.
for target in build.config.target.iter() {
for target in &build.config.target {
// On emscripten we don't actually need the C compiler to just
// build the target artifacts, only for testing. For the sake
// of easier bot configuration, just skip detection.
@ -133,33 +122,32 @@ pub fn check(build: &mut Build) {
continue;
}
need_cmd(build.cc(target).as_ref());
cmd_finder.must_have(build.cc(target));
if let Some(ar) = build.ar(target) {
need_cmd(ar.as_ref());
cmd_finder.must_have(ar);
}
}
for host in build.config.host.iter() {
need_cmd(build.cxx(host).unwrap().as_ref());
}
// The msvc hosts don't use jemalloc, turn it off globally to
// avoid packaging the dummy liballoc_jemalloc on that platform.
for host in build.config.host.iter() {
cmd_finder.must_have(build.cxx(host).unwrap());
// The msvc hosts don't use jemalloc, turn it off globally to
// avoid packaging the dummy liballoc_jemalloc on that platform.
if host.contains("msvc") {
build.config.use_jemalloc = false;
}
}
// Externally configured LLVM requires FileCheck to exist
let filecheck = build.llvm_filecheck(&build.config.build);
let filecheck = build.llvm_filecheck(&build.build);
if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
panic!("FileCheck executable {:?} does not exist", filecheck);
}
for target in build.config.target.iter() {
for target in &build.config.target {
// Can't compile for iOS unless we're on macOS
if target.contains("apple-ios") &&
!build.config.build.contains("apple-darwin") {
!build.build.contains("apple-darwin") {
panic!("the iOS target is only supported on macOS");
}
@ -206,18 +194,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
}
}
for host in build.flags.host.iter() {
if !build.config.host.contains(host) {
panic!("specified host `{}` is not in the ./configure list", host);
}
}
for target in build.flags.target.iter() {
if !build.config.target.contains(target) {
panic!("specified target `{}` is not in the ./configure list",
target);
}
}
let run = |cmd: &mut Command| {
cmd.output().map(|output| {
String::from_utf8_lossy(&output.stdout)
@ -231,6 +207,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
}
if let Some(ref s) = build.config.ccache {
need_cmd(s.as_ref());
cmd_finder.must_have(s);
}
}

View File

@ -104,10 +104,10 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
rules.build("llvm", "src/llvm")
.host(true)
.dep(move |s| {
if s.target == build.config.build {
if s.target == build.build {
Step::noop()
} else {
s.target(&build.config.build)
s.target(&build.build)
}
})
.run(move |s| native::llvm(build, s.target));
@ -124,7 +124,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
Step::noop()
} else {
s.name("librustc")
.host(&build.config.build)
.host(&build.build)
.stage(s.stage - 1)
}
})
@ -148,7 +148,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
}
}
}
return ret
ret
};
// ========================================================================
@ -215,29 +215,29 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
let mut rule = rules.build(&krate, "path/to/nowhere");
rule.dep(move |s| {
if build.force_use_stage1(&s.compiler(), s.target) {
s.host(&build.config.build).stage(1)
} else if s.host == build.config.build {
s.host(&build.build).stage(1)
} else if s.host == build.build {
s.name(dep)
} else {
s.host(&build.config.build)
s.host(&build.build)
}
})
.run(move |s| {
if build.force_use_stage1(&s.compiler(), s.target) {
link(build,
&s.stage(1).host(&build.config.build).compiler(),
&s.stage(1).host(&build.build).compiler(),
&s.compiler(),
s.target)
} else if s.host == build.config.build {
} else if s.host == build.build {
link(build, &s.compiler(), &s.compiler(), s.target)
} else {
link(build,
&s.host(&build.config.build).compiler(),
&s.host(&build.build).compiler(),
&s.compiler(),
s.target)
}
});
return rule
rule
}
// Similar to the `libstd`, `libtest`, and `librustc` rules above, except
@ -269,7 +269,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
for (krate, path, _default) in krates("std") {
rules.build(&krate.build_step, path)
.dep(|s| s.name("startup-objects"))
.dep(move |s| s.name("rustc").host(&build.config.build).target(s.host))
.dep(move |s| s.name("rustc").host(&build.build).target(s.host))
.run(move |s| compile::std(build, s.target, &s.compiler()));
}
for (krate, path, _default) in krates("test") {
@ -280,7 +280,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
for (krate, path, _default) in krates("rustc-main") {
rules.build(&krate.build_step, path)
.dep(|s| s.name("libtest-link"))
.dep(move |s| s.name("llvm").host(&build.config.build).stage(0))
.dep(move |s| s.name("llvm").host(&build.build).stage(0))
.dep(|s| s.name("may-run-build-script"))
.run(move |s| compile::rustc(build, s.target, &s.compiler()));
}
@ -291,8 +291,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
rules.build("may-run-build-script", "path/to/nowhere")
.dep(move |s| {
s.name("libstd-link")
.host(&build.config.build)
.target(&build.config.build)
.host(&build.build)
.target(&build.build)
});
rules.build("startup-objects", "src/rtstartup")
.dep(|s| s.name("create-sysroot").target(s.host))
@ -332,7 +332,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
"incremental");
}
if build.config.build.contains("msvc") {
if build.build.contains("msvc") {
// nothing to do for debuginfo tests
} else {
rules.test("check-debuginfo-lldb", "src/test/debuginfo-lldb")
@ -352,7 +352,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
"debuginfo-gdb", "debuginfo"));
let mut rule = rules.test("check-debuginfo", "src/test/debuginfo");
rule.default(true);
if build.config.build.contains("apple") {
if build.build.contains("apple") {
rule.dep(|s| s.name("check-debuginfo-lldb"));
} else {
rule.dep(|s| s.name("check-debuginfo-gdb"));
@ -594,8 +594,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
// Cargo depends on procedural macros, which requires a full host
// compiler to be available, so we need to depend on that.
s.name("librustc-link")
.target(&build.config.build)
.host(&build.config.build)
.target(&build.build)
.host(&build.build)
})
.run(move |s| compile::tool(build, s.stage, s.target, "cargo"));
rules.build("tool-rls", "src/tools/rls")
@ -606,8 +606,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
.dep(move |s| {
// rls, like cargo, uses procedural macros
s.name("librustc-link")
.target(&build.config.build)
.host(&build.config.build)
.target(&build.build)
.host(&build.build)
})
.run(move |s| compile::tool(build, s.stage, s.target, "rls"));
@ -635,8 +635,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
rules.doc("doc-book", "src/doc/book")
.dep(move |s| {
s.name("tool-rustbook")
.host(&build.config.build)
.target(&build.config.build)
.host(&build.build)
.target(&build.build)
.stage(0)
})
.default(build.config.docs)
@ -644,8 +644,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
rules.doc("doc-nomicon", "src/doc/nomicon")
.dep(move |s| {
s.name("tool-rustbook")
.host(&build.config.build)
.target(&build.config.build)
.host(&build.build)
.target(&build.build)
.stage(0)
})
.default(build.config.docs)
@ -653,8 +653,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
rules.doc("doc-reference", "src/doc/reference")
.dep(move |s| {
s.name("tool-rustbook")
.host(&build.config.build)
.target(&build.config.build)
.host(&build.build)
.target(&build.build)
.stage(0)
})
.default(build.config.docs)
@ -662,8 +662,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
rules.doc("doc-unstable-book", "src/doc/unstable-book")
.dep(move |s| {
s.name("tool-rustbook")
.host(&build.config.build)
.target(&build.config.build)
.host(&build.build)
.target(&build.build)
.stage(0)
})
.dep(move |s| s.name("doc-unstable-book-gen"))
@ -675,14 +675,14 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
rules.doc("doc-standalone", "src/doc")
.dep(move |s| {
s.name("rustc")
.host(&build.config.build)
.target(&build.config.build)
.host(&build.build)
.target(&build.build)
.stage(0)
})
.default(build.config.docs)
.run(move |s| doc::standalone(build, s.target));
rules.doc("doc-error-index", "src/tools/error_index_generator")
.dep(move |s| s.name("tool-error-index").target(&build.config.build).stage(0))
.dep(move |s| s.name("tool-error-index").target(&build.build).stage(0))
.dep(move |s| s.name("librustc-link"))
.default(build.config.docs)
.host(true)
@ -690,8 +690,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
rules.doc("doc-unstable-book-gen", "src/tools/unstable-book-gen")
.dep(move |s| {
s.name("tool-unstable-book-gen")
.host(&build.config.build)
.target(&build.config.build)
.host(&build.build)
.target(&build.build)
.stage(0)
})
.dep(move |s| s.name("libstd-link"))
@ -725,7 +725,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
// ========================================================================
// Distribution targets
rules.dist("dist-rustc", "src/librustc")
.dep(move |s| s.name("rustc").host(&build.config.build))
.dep(move |s| s.name("rustc").host(&build.build))
.host(true)
.only_host_build(true)
.default(true)
@ -811,7 +811,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
.host(true)
.only_build(true)
.only_host_build(true)
.dep(move |s| s.name("tool-build-manifest").target(&build.config.build).stage(0))
.dep(move |s| s.name("tool-build-manifest").target(&build.build).stage(0))
.run(move |_| dist::hash_and_sign(build));
rules.install("install-docs", "src/doc")
@ -861,8 +861,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
/// Helper to depend on a stage0 build-only rust-installer tool.
fn tool_rust_installer<'a>(build: &'a Build, step: &Step<'a>) -> Step<'a> {
step.name("tool-rust-installer")
.host(&build.config.build)
.target(&build.config.build)
.host(&build.build)
.target(&build.build)
.stage(0)
}
}
@ -1058,8 +1058,8 @@ impl<'a> Rules<'a> {
build: build,
sbuild: Step {
stage: build.flags.stage.unwrap_or(2),
target: &build.config.build,
host: &build.config.build,
target: &build.build,
host: &build.build,
name: "",
},
rules: BTreeMap::new(),
@ -1218,16 +1218,9 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
rules.into_iter().flat_map(|(rule, _)| {
let hosts = if rule.only_host_build || rule.only_build {
&self.build.config.host[..1]
} else if self.build.flags.host.len() > 0 {
&self.build.flags.host
self.build.build_slice()
} else {
&self.build.config.host
};
let targets = if self.build.flags.target.len() > 0 {
&self.build.flags.target
} else {
&self.build.config.target
&self.build.hosts
};
// Determine the actual targets participating in this rule.
// NOTE: We should keep the full projection from build triple to
@ -1236,19 +1229,18 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
// the original non-shadowed hosts array is used below.
let arr = if rule.host {
// If --target was specified but --host wasn't specified,
// don't run any host-only tests. Also, respect any `--host`
// overrides as done for `hosts`.
// don't run any host-only tests.
if self.build.flags.host.len() > 0 {
&self.build.flags.host[..]
&self.build.hosts
} else if self.build.flags.target.len() > 0 {
&[]
} else if rule.only_build {
&self.build.config.host[..1]
self.build.build_slice()
} else {
&self.build.config.host[..]
&self.build.hosts
}
} else {
targets
&self.build.targets
};
hosts.iter().flat_map(move |host| {
@ -1326,7 +1318,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
for idx in 0..nodes.len() {
self.topo_sort(idx, &idx_to_node, &edges, &mut visited, &mut order);
}
return order
order
}
/// Builds the dependency graph rooted at `step`.
@ -1365,7 +1357,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
}
edges.entry(idx).or_insert(HashSet::new()).extend(deps);
return idx
idx
}
/// Given a dependency graph with a finished list of `nodes`, fill out more
@ -1494,8 +1486,8 @@ mod tests {
let step = super::Step {
name: "",
stage: 2,
host: &build.config.build,
target: &build.config.build,
host: &build.build,
target: &build.build,
};
assert!(plan.contains(&step.name("dist-docs")));
@ -1517,8 +1509,8 @@ mod tests {
let step = super::Step {
name: "",
stage: 2,
host: &build.config.build,
target: &build.config.build,
host: &build.build,
target: &build.build,
};
assert!(plan.contains(&step.name("dist-docs")));
@ -1545,8 +1537,8 @@ mod tests {
let step = super::Step {
name: "",
stage: 2,
host: &build.config.build,
target: &build.config.build,
host: &build.build,
target: &build.build,
};
assert!(!plan.iter().any(|s| s.host == "B"));
@ -1575,8 +1567,8 @@ mod tests {
let step = super::Step {
name: "",
stage: 2,
host: &build.config.build,
target: &build.config.build,
host: &build.build,
target: &build.build,
};
assert!(!plan.iter().any(|s| s.host == "B"));
@ -1612,8 +1604,8 @@ mod tests {
let step = super::Step {
name: "",
stage: 2,
host: &build.config.build,
target: &build.config.build,
host: &build.build,
target: &build.build,
};
assert!(!plan.iter().any(|s| s.target == "A"));
@ -1639,8 +1631,8 @@ mod tests {
let step = super::Step {
name: "",
stage: 2,
host: &build.config.build,
target: &build.config.build,
host: &build.build,
target: &build.build,
};
assert!(!plan.iter().any(|s| s.target == "A"));
@ -1683,8 +1675,8 @@ mod tests {
let step = super::Step {
name: "",
stage: 2,
host: &build.config.build,
target: &build.config.build,
host: &build.build,
target: &build.build,
};
// rustc built for all for of (A, B) x (A, B)

View File

@ -14,7 +14,6 @@
//! not a lot of interesting happenings here unfortunately.
use std::env;
use std::ffi::OsString;
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
@ -32,16 +31,9 @@ pub fn staticlib(name: &str, target: &str) -> String {
}
}
/// Copies a file from `src` to `dst`, attempting to use hard links and then
/// falling back to an actually filesystem copy if necessary.
/// Copies a file from `src` to `dst`
pub fn copy(src: &Path, dst: &Path) {
// A call to `hard_link` will fail if `dst` exists, so remove it if it
// already exists so we can try to help `hard_link` succeed.
let _ = fs::remove_file(&dst);
// Attempt to "easy copy" by creating a hard link (symlinks don't work on
// windows), but if that fails just fall back to a slow `copy` operation.
// let res = fs::hard_link(src, dst);
let res = fs::copy(src, dst);
if let Err(e) = res {
panic!("failed to copy `{}` to `{}`: {}", src.display(),
@ -149,8 +141,7 @@ pub fn dylib_path_var() -> &'static str {
/// Parses the `dylib_path_var()` environment variable, returning a list of
/// paths that are members of this lookup path.
pub fn dylib_path() -> Vec<PathBuf> {
env::split_paths(&env::var_os(dylib_path_var()).unwrap_or(OsString::new()))
.collect()
env::split_paths(&env::var_os(dylib_path_var()).unwrap_or_default()).collect()
}
/// `push` all components to `buf`. On windows, append `.exe` to the last component.
@ -422,4 +413,4 @@ impl CiEnv {
cmd.env("TERM", "xterm").args(&["--color", "always"]);
}
}
}
}

View File

@ -2008,10 +2008,10 @@ impl From<Box<str>> for String {
}
}
#[stable(feature = "box_from_str", since = "1.18.0")]
impl Into<Box<str>> for String {
fn into(self) -> Box<str> {
self.into_boxed_str()
#[stable(feature = "box_from_str", since = "1.20.0")]
impl From<String> for Box<str> {
fn from(s: String) -> Box<str> {
s.into_boxed_str()
}
}

View File

@ -274,6 +274,11 @@ fn test_dedup_by() {
vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
let mut vec = vec![("foo", 1), ("foo", 2), ("bar", 3), ("bar", 4), ("bar", 5)];
vec.dedup_by(|a, b| a.0 == b.0 && { b.1 += a.1; true });
assert_eq!(vec, [("foo", 3), ("bar", 12)]);
}
#[test]

View File

@ -823,7 +823,8 @@ impl<T> Vec<T> {
}
}
/// Removes consecutive elements in the vector that resolve to the same key.
/// Removes all but the first of consecutive elements in the vector that resolve to the same
/// key.
///
/// If the vector is sorted, this removes all duplicates.
///
@ -842,11 +843,13 @@ impl<T> Vec<T> {
self.dedup_by(|a, b| key(a) == key(b))
}
/// Removes consecutive elements in the vector according to a predicate.
/// Removes all but the first of consecutive elements in the vector satisfying a given equality
/// relation.
///
/// The `same_bucket` function is passed references to two elements from the vector, and
/// returns `true` if the elements compare equal, or `false` if they do not. Only the first
/// of adjacent equal items is kept.
/// returns `true` if the elements compare equal, or `false` if they do not. The elements are
/// passed in opposite order from their order in the vector, so if `same_bucket(a, b)` returns
/// `true`, `a` is removed.
///
/// If the vector is sorted, this removes all duplicates.
///

View File

@ -343,7 +343,7 @@ impl Ordering {
/// ```
#[derive(PartialEq, Eq, Debug)]
#[stable(feature = "reverse_cmp_key", since = "1.19.0")]
pub struct Reverse<T>(pub T);
pub struct Reverse<T>(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T);
#[stable(feature = "reverse_cmp_key", since = "1.19.0")]
impl<T: PartialOrd> PartialOrd for Reverse<T> {

View File

@ -49,9 +49,37 @@ impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> {
}
}
/// A struct to help with `fmt::Debug` implementations.
/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
///
/// Constructed by the `Formatter::debug_struct` method.
/// This is useful when you wish to output a formatted struct as a part of your
/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
///
/// This can be constructed by the
/// [`Formatter::debug_struct`](struct.Formatter.html#method.debug_struct)
/// method.
///
/// # Example
///
/// ```
/// use std::fmt;
///
/// struct Foo {
/// bar: i32,
/// baz: String,
/// }
///
/// impl fmt::Debug for Foo {
/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
/// fmt.debug_struct("Foo")
/// .field("bar", &self.bar)
/// .field("baz", &self.baz)
/// .finish()
/// }
/// }
///
/// // prints "Foo { bar: 10, baz: "Hello World" }"
/// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() });
/// ```
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
@ -116,9 +144,34 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
}
}
/// A struct to help with `fmt::Debug` implementations.
/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
///
/// Constructed by the `Formatter::debug_tuple` method.
/// This is useful when you wish to output a formatted tuple as a part of your
/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
///
/// This can be constructed by the
/// [`Formatter::debug_tuple`](struct.Formatter.html#method.debug_tuple)
/// method.
///
/// # Example
///
/// ```
/// use std::fmt;
///
/// struct Foo(i32, String);
///
/// impl fmt::Debug for Foo {
/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
/// fmt.debug_tuple("Foo")
/// .field(&self.0)
/// .field(&self.1)
/// .finish()
/// }
/// }
///
/// // prints "Foo(10, "Hello World")"
/// println!("{:?}", Foo(10, "Hello World".to_string()));
/// ```
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
@ -228,9 +281,31 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
}
}
/// A struct to help with `fmt::Debug` implementations.
/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
///
/// Constructed by the `Formatter::debug_set` method.
/// This is useful when you wish to output a formatted set of items as a part
/// of your [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
///
/// This can be constructed by the
/// [`Formatter::debug_set`](struct.Formatter.html#method.debug_set)
/// method.
///
/// # Example
///
/// ```
/// use std::fmt;
///
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
/// fmt.debug_set().entries(self.0.iter()).finish()
/// }
/// }
///
/// // prints "{10, 11}"
/// println!("{:?}", Foo(vec![10, 11]));
/// ```
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
@ -277,9 +352,31 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> {
}
}
/// A struct to help with `fmt::Debug` implementations.
/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
///
/// Constructed by the `Formatter::debug_list` method.
/// This is useful when you wish to output a formatted list of items as a part
/// of your [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
///
/// This can be constructed by the
/// [`Formatter::debug_list`](struct.Formatter.html#method.debug_list)
/// method.
///
/// # Example
///
/// ```
/// use std::fmt;
///
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
/// fmt.debug_list().entries(self.0.iter()).finish()
/// }
/// }
///
/// // prints "[10, 11]"
/// println!("{:?}", Foo(vec![10, 11]));
/// ```
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
@ -326,9 +423,31 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> {
}
}
/// A struct to help with `fmt::Debug` implementations.
/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
///
/// Constructed by the `Formatter::debug_map` method.
/// This is useful when you wish to output a formatted map as a part of your
/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
///
/// This can be constructed by the
/// [`Formatter::debug_map`](struct.Formatter.html#method.debug_map)
/// method.
///
/// # Example
///
/// ```
/// use std::fmt;
///
/// struct Foo(Vec<(String, i32)>);
///
/// impl fmt::Debug for Foo {
/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
/// fmt.debug_map().entries(self.0.iter().map(|&(ref k, ref v)| (k, v))).finish()
/// }
/// }
///
/// // prints "{"A": 10, "B": 11}"
/// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)]));
/// ```
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]

View File

@ -585,11 +585,11 @@ impl From<Box<CStr>> for CString {
}
}
#[stable(feature = "box_from_c_string", since = "1.18.0")]
impl Into<Box<CStr>> for CString {
#[stable(feature = "box_from_c_string", since = "1.20.0")]
impl From<CString> for Box<CStr> {
#[inline]
fn into(self) -> Box<CStr> {
self.into_boxed_c_str()
fn from(s: CString) -> Box<CStr> {
s.into_boxed_c_str()
}
}

View File

@ -540,10 +540,10 @@ impl From<Box<OsStr>> for OsString {
}
}
#[stable(feature = "box_from_os_string", since = "1.18.0")]
impl Into<Box<OsStr>> for OsString {
fn into(self) -> Box<OsStr> {
self.into_boxed_os_str()
#[stable(feature = "box_from_os_string", since = "1.20.0")]
impl From<OsString> for Box<OsStr> {
fn from(s: OsString) -> Box<OsStr> {
s.into_boxed_os_str()
}
}

View File

@ -1348,10 +1348,10 @@ impl From<Box<Path>> for PathBuf {
}
}
#[stable(feature = "box_from_path_buf", since = "1.18.0")]
impl Into<Box<Path>> for PathBuf {
fn into(self) -> Box<Path> {
self.into_boxed_path()
#[stable(feature = "box_from_path_buf", since = "1.20.0")]
impl From<PathBuf> for Box<Path> {
fn from(p: PathBuf) -> Box<Path> {
p.into_boxed_path()
}
}

View File

@ -420,12 +420,19 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
}
pub fn readlink(p: &Path) -> io::Result<PathBuf> {
canonicalize(p)
let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_SYMLINK | syscall::O_RDONLY))?;
let mut buf: [u8; 4096] = [0; 4096];
let count = cvt(syscall::read(fd, &mut buf))?;
cvt(syscall::close(fd))?;
Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }))
}
pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
::sys_common::util::dumb_print(format_args!("Symlink\n"));
unimplemented!();
pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
let fd = cvt(syscall::open(dst.to_str().unwrap(),
syscall::O_SYMLINK | syscall::O_CREAT | syscall::O_WRONLY | 0o777))?;
cvt(syscall::write(fd, src.to_str().unwrap().as_bytes()))?;
cvt(syscall::close(fd))?;
Ok(())
}
pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {

View File

@ -33,6 +33,7 @@ pub const MAP_WRITE_COMBINE: usize = 2;
pub const MODE_TYPE: u16 = 0xF000;
pub const MODE_DIR: u16 = 0x4000;
pub const MODE_FILE: u16 = 0x8000;
pub const MODE_SYMLINK: u16 = 0xA000;
pub const MODE_PERM: u16 = 0x0FFF;
pub const MODE_SETUID: u16 = 0o4000;
@ -53,6 +54,7 @@ pub const O_TRUNC: usize = 0x0400_0000;
pub const O_EXCL: usize = 0x0800_0000;
pub const O_DIRECTORY: usize = 0x1000_0000;
pub const O_STAT: usize = 0x2000_0000;
pub const O_SYMLINK: usize = 0x4000_0000;
pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR;
pub const SEEK_SET: usize = 0;