commit
5e94d5498d
1465 changed files with 19236 additions and 12568 deletions
876
src/Cargo.lock
generated
876
src/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -42,3 +42,7 @@ serde_json = "1.0.2"
|
|||
toml = "0.4"
|
||||
lazy_static = "0.2"
|
||||
time = "0.1"
|
||||
petgraph = "0.4.12"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.5"
|
||||
|
|
|
|||
|
|
@ -31,9 +31,11 @@ extern crate bootstrap;
|
|||
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::str::FromStr;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, ExitStatus};
|
||||
use std::process::Command;
|
||||
use std::str::FromStr;
|
||||
use std::time::Instant;
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args_os().skip(1).collect::<Vec<_>>();
|
||||
|
|
@ -90,7 +92,7 @@ fn main() {
|
|||
};
|
||||
let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
|
||||
let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
|
||||
let mut on_fail = env::var_os("RUSTC_ON_FAIL").map(|of| Command::new(of));
|
||||
let on_fail = env::var_os("RUSTC_ON_FAIL").map(|of| Command::new(of));
|
||||
|
||||
let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
|
||||
let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
|
||||
|
|
@ -103,6 +105,7 @@ fn main() {
|
|||
.arg(format!("stage{}", stage))
|
||||
.env(bootstrap::util::dylib_path_var(),
|
||||
env::join_paths(&dylib_path).unwrap());
|
||||
let mut maybe_crate = None;
|
||||
|
||||
if let Some(target) = target {
|
||||
// The stage0 compiler has a special sysroot distinct from what we
|
||||
|
|
@ -134,6 +137,7 @@ fn main() {
|
|||
.find(|a| &*a[0] == "--crate-name")
|
||||
.unwrap();
|
||||
let crate_name = &*crate_name[1];
|
||||
maybe_crate = Some(crate_name);
|
||||
|
||||
// If we're compiling specifically the `panic_abort` crate then we pass
|
||||
// the `-C panic=abort` option. Note that we do not do this for any
|
||||
|
|
@ -281,31 +285,52 @@ fn main() {
|
|||
eprintln!("libdir: {:?}", libdir);
|
||||
}
|
||||
|
||||
// Actually run the compiler!
|
||||
std::process::exit(if let Some(ref mut on_fail) = on_fail {
|
||||
match cmd.status() {
|
||||
Ok(s) if s.success() => 0,
|
||||
_ => {
|
||||
println!("\nDid not run successfully:\n{:?}\n-------------", cmd);
|
||||
exec_cmd(on_fail).expect("could not run the backup command");
|
||||
1
|
||||
if let Some(mut on_fail) = on_fail {
|
||||
let e = match cmd.status() {
|
||||
Ok(s) if s.success() => std::process::exit(0),
|
||||
e => e,
|
||||
};
|
||||
println!("\nDid not run successfully: {:?}\n{:?}\n-------------", e, cmd);
|
||||
exec_cmd(&mut on_fail).expect("could not run the backup command");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some() {
|
||||
if let Some(krate) = maybe_crate {
|
||||
let start = Instant::now();
|
||||
let status = cmd
|
||||
.status()
|
||||
.expect(&format!("\n\n failed to run {:?}", cmd));
|
||||
let dur = start.elapsed();
|
||||
|
||||
let is_test = args.iter().any(|a| a == "--test");
|
||||
eprintln!("[RUSTC-TIMING] {} test:{} {}.{:03}",
|
||||
krate.to_string_lossy(),
|
||||
is_test,
|
||||
dur.as_secs(),
|
||||
dur.subsec_nanos() / 1_000_000);
|
||||
|
||||
match status.code() {
|
||||
Some(i) => std::process::exit(i),
|
||||
None => {
|
||||
eprintln!("rustc exited with {}", status);
|
||||
std::process::exit(0xfe);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::process::exit(match exec_cmd(&mut cmd) {
|
||||
Ok(s) => s.code().unwrap_or(0xfe),
|
||||
Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
let code = exec_cmd(&mut cmd).expect(&format!("\n\n failed to run {:?}", cmd));
|
||||
std::process::exit(code);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn exec_cmd(cmd: &mut Command) -> ::std::io::Result<ExitStatus> {
|
||||
fn exec_cmd(cmd: &mut Command) -> io::Result<i32> {
|
||||
use std::os::unix::process::CommandExt;
|
||||
Err(cmd.exec())
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn exec_cmd(cmd: &mut Command) -> ::std::io::Result<ExitStatus> {
|
||||
cmd.status()
|
||||
fn exec_cmd(cmd: &mut Command) -> io::Result<i32> {
|
||||
cmd.status().map(|status| status.code().unwrap())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ class RustBuild(object):
|
|||
self.build_dir = os.path.join(os.getcwd(), "build")
|
||||
self.clean = False
|
||||
self.config_toml = ''
|
||||
self.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
|
||||
self.rust_root = ''
|
||||
self.use_locked_deps = ''
|
||||
self.use_vendored_sources = ''
|
||||
self.verbose = False
|
||||
|
|
@ -647,7 +647,7 @@ class RustBuild(object):
|
|||
if (not os.path.exists(os.path.join(self.rust_root, ".git"))) or \
|
||||
self.get_toml('submodules') == "false":
|
||||
return
|
||||
slow_submodules = self.get_toml('fast-submodule') == "false"
|
||||
slow_submodules = self.get_toml('fast-submodules') == "false"
|
||||
start_time = time()
|
||||
if slow_submodules:
|
||||
print('Unconditionally updating all submodules')
|
||||
|
|
@ -710,6 +710,7 @@ def bootstrap(help_triggered):
|
|||
parser = argparse.ArgumentParser(description='Build rust')
|
||||
parser.add_argument('--config')
|
||||
parser.add_argument('--build')
|
||||
parser.add_argument('--src')
|
||||
parser.add_argument('--clean', action='store_true')
|
||||
parser.add_argument('-v', '--verbose', action='count', default=0)
|
||||
|
||||
|
|
@ -718,6 +719,7 @@ def bootstrap(help_triggered):
|
|||
|
||||
# Configure initial bootstrap
|
||||
build = RustBuild()
|
||||
build.rust_root = args.src or os.path.abspath(os.path.join(__file__, '../../..'))
|
||||
build.verbose = args.verbose
|
||||
build.clean = args.clean
|
||||
|
||||
|
|
@ -788,6 +790,7 @@ def bootstrap(help_triggered):
|
|||
env["SRC"] = build.rust_root
|
||||
env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
|
||||
env["BOOTSTRAP_PYTHON"] = sys.executable
|
||||
env["BUILD_DIR"] = build.build_dir
|
||||
run(args, env=env, verbose=build.verbose)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use std::any::Any;
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::BTreeSet;
|
||||
use std::env;
|
||||
use std::fmt::Debug;
|
||||
|
|
@ -18,6 +18,8 @@ use std::hash::Hash;
|
|||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::time::{Instant, Duration};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use compile;
|
||||
use install;
|
||||
|
|
@ -34,12 +36,20 @@ use native;
|
|||
|
||||
pub use Compiler;
|
||||
|
||||
use petgraph::Graph;
|
||||
use petgraph::graph::NodeIndex;
|
||||
|
||||
pub struct Builder<'a> {
|
||||
pub build: &'a Build,
|
||||
pub top_stage: u32,
|
||||
pub kind: Kind,
|
||||
cache: Cache,
|
||||
stack: RefCell<Vec<Box<Any>>>,
|
||||
time_spent_on_dependencies: Cell<Duration>,
|
||||
pub paths: Vec<PathBuf>,
|
||||
graph_nodes: RefCell<HashMap<String, NodeIndex>>,
|
||||
graph: RefCell<Graph<String, bool>>,
|
||||
parent: Cell<Option<NodeIndex>>,
|
||||
}
|
||||
|
||||
impl<'a> Deref for Builder<'a> {
|
||||
|
|
@ -308,19 +318,24 @@ impl<'a> Builder<'a> {
|
|||
test::UiFullDeps, test::RunPassFullDeps, test::RunFailFullDeps,
|
||||
test::CompileFailFullDeps, test::IncrementalFullDeps, test::Rustdoc, test::Pretty,
|
||||
test::RunPassPretty, test::RunFailPretty, test::RunPassValgrindPretty,
|
||||
test::RunPassFullDepsPretty, test::RunFailFullDepsPretty, test::RunMake,
|
||||
test::RunPassFullDepsPretty, test::RunFailFullDepsPretty,
|
||||
test::Crate, test::CrateLibrustc, test::CrateRustdoc, test::Linkcheck,
|
||||
test::Cargotest, test::Cargo, test::Rls, test::ErrorIndex, test::Distcheck,
|
||||
test::RunMakeFullDeps,
|
||||
test::Nomicon, test::Reference, test::RustdocBook, test::RustByExample,
|
||||
test::TheBook, test::UnstableBook,
|
||||
test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme),
|
||||
test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme,
|
||||
// Run run-make last, since these won't pass without make on Windows
|
||||
test::RunMake),
|
||||
Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
|
||||
Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
|
||||
doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon,
|
||||
doc::Reference, doc::Rustdoc, doc::RustByExample, doc::CargoBook),
|
||||
Kind::Dist => describe!(dist::Docs, dist::Mingw, dist::Rustc, dist::DebuggerScripts,
|
||||
dist::Std, dist::Analysis, dist::Src, dist::PlainSourceTarball, dist::Cargo,
|
||||
dist::Rls, dist::Rustfmt, dist::Extended, dist::HashSign),
|
||||
doc::Standalone, doc::Std, doc::Test, doc::WhitelistedRustc, doc::Rustc,
|
||||
doc::ErrorIndex, doc::Nomicon, doc::Reference, doc::Rustdoc, doc::RustByExample,
|
||||
doc::CargoBook),
|
||||
Kind::Dist => describe!(dist::Docs, dist::RustcDocs, dist::Mingw, dist::Rustc,
|
||||
dist::DebuggerScripts, dist::Std, dist::Analysis, dist::Src,
|
||||
dist::PlainSourceTarball, dist::Cargo, dist::Rls, dist::Rustfmt, dist::Extended,
|
||||
dist::HashSign),
|
||||
Kind::Install => describe!(install::Docs, install::Std, install::Cargo, install::Rls,
|
||||
install::Rustfmt, install::Analysis, install::Src, install::Rustc),
|
||||
}
|
||||
|
|
@ -343,6 +358,11 @@ impl<'a> Builder<'a> {
|
|||
kind,
|
||||
cache: Cache::new(),
|
||||
stack: RefCell::new(Vec::new()),
|
||||
time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
|
||||
paths: vec![],
|
||||
graph_nodes: RefCell::new(HashMap::new()),
|
||||
graph: RefCell::new(Graph::new()),
|
||||
parent: Cell::new(None),
|
||||
};
|
||||
|
||||
let builder = &builder;
|
||||
|
|
@ -359,7 +379,7 @@ impl<'a> Builder<'a> {
|
|||
Some(help)
|
||||
}
|
||||
|
||||
pub fn run(build: &Build) {
|
||||
pub fn new(build: &Build) -> Builder {
|
||||
let (kind, paths) = match build.config.cmd {
|
||||
Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
|
||||
Subcommand::Check { ref paths } => (Kind::Check, &paths[..]),
|
||||
|
|
@ -371,32 +391,40 @@ impl<'a> Builder<'a> {
|
|||
Subcommand::Clean { .. } => panic!(),
|
||||
};
|
||||
|
||||
if let Some(path) = paths.get(0) {
|
||||
if path == Path::new("nonexistent/path/to/trigger/cargo/metadata") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let builder = Builder {
|
||||
build,
|
||||
top_stage: build.config.stage.unwrap_or(2),
|
||||
kind,
|
||||
cache: Cache::new(),
|
||||
stack: RefCell::new(Vec::new()),
|
||||
time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
|
||||
paths: paths.to_owned(),
|
||||
graph_nodes: RefCell::new(HashMap::new()),
|
||||
graph: RefCell::new(Graph::new()),
|
||||
parent: Cell::new(None),
|
||||
};
|
||||
|
||||
if kind == Kind::Dist {
|
||||
assert!(!build.config.test_miri, "Do not distribute with miri enabled.\n\
|
||||
assert!(!builder.config.test_miri, "Do not distribute with miri enabled.\n\
|
||||
The distributed libraries would include all MIR (increasing binary size).
|
||||
The distributed MIR would include validation statements.");
|
||||
}
|
||||
|
||||
StepDescription::run(&Builder::get_step_descriptions(builder.kind), &builder, paths);
|
||||
builder
|
||||
}
|
||||
|
||||
pub fn execute_cli(&self) -> Graph<String, bool> {
|
||||
self.run_step_descriptions(&Builder::get_step_descriptions(self.kind), &self.paths);
|
||||
self.graph.borrow().clone()
|
||||
}
|
||||
|
||||
pub fn default_doc(&self, paths: Option<&[PathBuf]>) {
|
||||
let paths = paths.unwrap_or(&[]);
|
||||
StepDescription::run(&Builder::get_step_descriptions(Kind::Doc), self, paths);
|
||||
self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths);
|
||||
}
|
||||
|
||||
fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) {
|
||||
StepDescription::run(v, self, paths);
|
||||
}
|
||||
|
||||
/// Obtain a compiler at a given stage and for a given host. Explicitly does
|
||||
|
|
@ -546,7 +574,9 @@ impl<'a> Builder<'a> {
|
|||
let mut extra_args = env::var(&format!("RUSTFLAGS_STAGE_{}", stage)).unwrap_or_default();
|
||||
if stage != 0 {
|
||||
let s = env::var("RUSTFLAGS_STAGE_NOT_0").unwrap_or_default();
|
||||
extra_args.push_str(" ");
|
||||
if !extra_args.is_empty() {
|
||||
extra_args.push_str(" ");
|
||||
}
|
||||
extra_args.push_str(&s);
|
||||
}
|
||||
|
||||
|
|
@ -662,6 +692,10 @@ impl<'a> Builder<'a> {
|
|||
cargo.env("RUSTC_ON_FAIL", on_fail);
|
||||
}
|
||||
|
||||
if self.config.print_step_timings {
|
||||
cargo.env("RUSTC_PRINT_STEP_TIMINGS", "1");
|
||||
}
|
||||
|
||||
cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity));
|
||||
|
||||
// Throughout the build Cargo can execute a number of build scripts
|
||||
|
|
@ -813,12 +847,56 @@ impl<'a> Builder<'a> {
|
|||
if let Some(out) = self.cache.get(&step) {
|
||||
self.build.verbose(&format!("{}c {:?}", " ".repeat(stack.len()), step));
|
||||
|
||||
{
|
||||
let mut graph = self.graph.borrow_mut();
|
||||
let parent = self.parent.get();
|
||||
let us = *self.graph_nodes.borrow_mut()
|
||||
.entry(format!("{:?}", step))
|
||||
.or_insert_with(|| graph.add_node(format!("{:?}", step)));
|
||||
if let Some(parent) = parent {
|
||||
graph.add_edge(parent, us, false);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
self.build.verbose(&format!("{}> {:?}", " ".repeat(stack.len()), step));
|
||||
stack.push(Box::new(step.clone()));
|
||||
}
|
||||
let out = step.clone().run(self);
|
||||
|
||||
let prev_parent = self.parent.get();
|
||||
|
||||
{
|
||||
let mut graph = self.graph.borrow_mut();
|
||||
let parent = self.parent.get();
|
||||
let us = *self.graph_nodes.borrow_mut()
|
||||
.entry(format!("{:?}", step))
|
||||
.or_insert_with(|| graph.add_node(format!("{:?}", step)));
|
||||
self.parent.set(Some(us));
|
||||
if let Some(parent) = parent {
|
||||
graph.add_edge(parent, us, true);
|
||||
}
|
||||
}
|
||||
|
||||
let (out, dur) = {
|
||||
let start = Instant::now();
|
||||
let zero = Duration::new(0, 0);
|
||||
let parent = self.time_spent_on_dependencies.replace(zero);
|
||||
let out = step.clone().run(self);
|
||||
let dur = start.elapsed();
|
||||
let deps = self.time_spent_on_dependencies.replace(parent + dur);
|
||||
(out, dur - deps)
|
||||
};
|
||||
|
||||
self.parent.set(prev_parent);
|
||||
|
||||
if self.build.config.print_step_timings && dur > Duration::from_millis(100) {
|
||||
println!("[TIMING] {:?} -- {}.{:03}",
|
||||
step,
|
||||
dur.as_secs(),
|
||||
dur.subsec_nanos() / 1_000_000);
|
||||
}
|
||||
|
||||
{
|
||||
let mut stack = self.stack.borrow_mut();
|
||||
let cur_step = stack.pop().expect("step stack empty");
|
||||
|
|
@ -829,3 +907,483 @@ impl<'a> Builder<'a> {
|
|||
out
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod __test {
|
||||
use config::Config;
|
||||
use std::thread;
|
||||
use super::*;
|
||||
|
||||
fn configure(host: &[&str], target: &[&str]) -> Config {
|
||||
let mut config = Config::default_opts();
|
||||
// don't save toolstates
|
||||
config.save_toolstates = None;
|
||||
config.run_host_only = true;
|
||||
config.dry_run = true;
|
||||
// try to avoid spurious failures in dist where we create/delete each others file
|
||||
let dir = config.out.join("tmp-rustbuild-tests")
|
||||
.join(&thread::current().name().unwrap_or("unknown").replace(":", "-"));
|
||||
t!(fs::create_dir_all(&dir));
|
||||
config.out = dir;
|
||||
config.build = INTERNER.intern_str("A");
|
||||
config.hosts = vec![config.build].clone().into_iter()
|
||||
.chain(host.iter().map(|s| INTERNER.intern_str(s))).collect::<Vec<_>>();
|
||||
config.targets = config.hosts.clone().into_iter()
|
||||
.chain(target.iter().map(|s| INTERNER.intern_str(s))).collect::<Vec<_>>();
|
||||
config
|
||||
}
|
||||
|
||||
fn first<A, B>(v: Vec<(A, B)>) -> Vec<A> {
|
||||
v.into_iter().map(|(a, _)| a).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_baseline() {
|
||||
let build = Build::new(configure(&[], &[]));
|
||||
let mut builder = Builder::new(&build);
|
||||
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
|
||||
|
||||
let a = INTERNER.intern_str("A");
|
||||
|
||||
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
|
||||
dist::Docs { stage: 2, host: a },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
|
||||
dist::Mingw { host: a },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
|
||||
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
|
||||
dist::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_with_targets() {
|
||||
let build = Build::new(configure(&[], &["B"]));
|
||||
let mut builder = Builder::new(&build);
|
||||
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
|
||||
|
||||
let a = INTERNER.intern_str("A");
|
||||
let b = INTERNER.intern_str("B");
|
||||
|
||||
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
|
||||
dist::Docs { stage: 2, host: a },
|
||||
dist::Docs { stage: 2, host: b },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
|
||||
dist::Mingw { host: a },
|
||||
dist::Mingw { host: b },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
|
||||
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
|
||||
dist::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
dist::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: b,
|
||||
},
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_with_hosts() {
|
||||
let build = Build::new(configure(&["B"], &[]));
|
||||
let mut builder = Builder::new(&build);
|
||||
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
|
||||
|
||||
let a = INTERNER.intern_str("A");
|
||||
let b = INTERNER.intern_str("B");
|
||||
|
||||
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
|
||||
dist::Docs { stage: 2, host: a },
|
||||
dist::Docs { stage: 2, host: b },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
|
||||
dist::Mingw { host: a },
|
||||
dist::Mingw { host: b },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
|
||||
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
|
||||
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
|
||||
dist::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
dist::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: b,
|
||||
},
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_with_targets_and_hosts() {
|
||||
let build = Build::new(configure(&["B"], &["C"]));
|
||||
let mut builder = Builder::new(&build);
|
||||
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
|
||||
|
||||
let a = INTERNER.intern_str("A");
|
||||
let b = INTERNER.intern_str("B");
|
||||
let c = INTERNER.intern_str("C");
|
||||
|
||||
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
|
||||
dist::Docs { stage: 2, host: a },
|
||||
dist::Docs { stage: 2, host: b },
|
||||
dist::Docs { stage: 2, host: c },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
|
||||
dist::Mingw { host: a },
|
||||
dist::Mingw { host: b },
|
||||
dist::Mingw { host: c },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
|
||||
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
|
||||
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
|
||||
dist::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
dist::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: b,
|
||||
},
|
||||
dist::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: c,
|
||||
},
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_with_target_flag() {
|
||||
let mut config = configure(&["B"], &["C"]);
|
||||
config.run_host_only = false; // as-if --target=C was passed
|
||||
let build = Build::new(config);
|
||||
let mut builder = Builder::new(&build);
|
||||
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
|
||||
|
||||
let a = INTERNER.intern_str("A");
|
||||
let b = INTERNER.intern_str("B");
|
||||
let c = INTERNER.intern_str("C");
|
||||
|
||||
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
|
||||
dist::Docs { stage: 2, host: a },
|
||||
dist::Docs { stage: 2, host: b },
|
||||
dist::Docs { stage: 2, host: c },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
|
||||
dist::Mingw { host: a },
|
||||
dist::Mingw { host: b },
|
||||
dist::Mingw { host: c },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
|
||||
dist::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
dist::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: b,
|
||||
},
|
||||
dist::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: c,
|
||||
},
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Src>()), &[]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_with_same_targets_and_hosts() {
|
||||
let build = Build::new(configure(&["B"], &["B"]));
|
||||
let mut builder = Builder::new(&build);
|
||||
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
|
||||
|
||||
let a = INTERNER.intern_str("A");
|
||||
let b = INTERNER.intern_str("B");
|
||||
|
||||
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
|
||||
dist::Docs { stage: 2, host: a },
|
||||
dist::Docs { stage: 2, host: b },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
|
||||
dist::Mingw { host: a },
|
||||
dist::Mingw { host: b },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
|
||||
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
|
||||
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
|
||||
dist::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
dist::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: b,
|
||||
},
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
|
||||
assert_eq!(first(builder.cache.all::<compile::Std>()), &[
|
||||
compile::Std {
|
||||
compiler: Compiler { host: a, stage: 0 },
|
||||
target: a,
|
||||
},
|
||||
compile::Std {
|
||||
compiler: Compiler { host: a, stage: 1 },
|
||||
target: a,
|
||||
},
|
||||
compile::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
compile::Std {
|
||||
compiler: Compiler { host: a, stage: 1 },
|
||||
target: b,
|
||||
},
|
||||
compile::Std {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: b,
|
||||
},
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<compile::Test>()), &[
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 0 },
|
||||
target: a,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 1 },
|
||||
target: a,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 1 },
|
||||
target: b,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: b,
|
||||
},
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<compile::Assemble>()), &[
|
||||
compile::Assemble {
|
||||
target_compiler: Compiler { host: a, stage: 0 },
|
||||
},
|
||||
compile::Assemble {
|
||||
target_compiler: Compiler { host: a, stage: 1 },
|
||||
},
|
||||
compile::Assemble {
|
||||
target_compiler: Compiler { host: a, stage: 2 },
|
||||
},
|
||||
compile::Assemble {
|
||||
target_compiler: Compiler { host: b, stage: 2 },
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_default() {
|
||||
let build = Build::new(configure(&["B"], &["C"]));
|
||||
let mut builder = Builder::new(&build);
|
||||
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
|
||||
|
||||
let a = INTERNER.intern_str("A");
|
||||
let b = INTERNER.intern_str("B");
|
||||
let c = INTERNER.intern_str("C");
|
||||
|
||||
assert!(!builder.cache.all::<compile::Std>().is_empty());
|
||||
assert!(!builder.cache.all::<compile::Assemble>().is_empty());
|
||||
assert_eq!(first(builder.cache.all::<compile::Rustc>()), &[
|
||||
compile::Rustc {
|
||||
compiler: Compiler { host: a, stage: 0 },
|
||||
target: a,
|
||||
},
|
||||
compile::Rustc {
|
||||
compiler: Compiler { host: a, stage: 1 },
|
||||
target: a,
|
||||
},
|
||||
compile::Rustc {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
compile::Rustc {
|
||||
compiler: Compiler { host: b, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
compile::Rustc {
|
||||
compiler: Compiler { host: a, stage: 0 },
|
||||
target: b,
|
||||
},
|
||||
compile::Rustc {
|
||||
compiler: Compiler { host: a, stage: 1 },
|
||||
target: b,
|
||||
},
|
||||
compile::Rustc {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: b,
|
||||
},
|
||||
compile::Rustc {
|
||||
compiler: Compiler { host: b, stage: 2 },
|
||||
target: b,
|
||||
},
|
||||
]);
|
||||
|
||||
assert_eq!(first(builder.cache.all::<compile::Test>()), &[
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 0 },
|
||||
target: a,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 1 },
|
||||
target: a,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: b, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 0 },
|
||||
target: b,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 1 },
|
||||
target: b,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: b,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: b, stage: 2 },
|
||||
target: b,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: c,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: b, stage: 2 },
|
||||
target: c,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_with_target_flag() {
|
||||
let mut config = configure(&["B"], &["C"]);
|
||||
config.run_host_only = false;
|
||||
let build = Build::new(config);
|
||||
let mut builder = Builder::new(&build);
|
||||
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
|
||||
|
||||
let a = INTERNER.intern_str("A");
|
||||
let b = INTERNER.intern_str("B");
|
||||
let c = INTERNER.intern_str("C");
|
||||
|
||||
assert!(!builder.cache.all::<compile::Std>().is_empty());
|
||||
assert_eq!(first(builder.cache.all::<compile::Assemble>()), &[
|
||||
compile::Assemble {
|
||||
target_compiler: Compiler { host: a, stage: 0 },
|
||||
},
|
||||
compile::Assemble {
|
||||
target_compiler: Compiler { host: a, stage: 1 },
|
||||
},
|
||||
compile::Assemble {
|
||||
target_compiler: Compiler { host: b, stage: 1 },
|
||||
},
|
||||
compile::Assemble {
|
||||
target_compiler: Compiler { host: a, stage: 2 },
|
||||
},
|
||||
compile::Assemble {
|
||||
target_compiler: Compiler { host: b, stage: 2 },
|
||||
},
|
||||
]);
|
||||
assert_eq!(first(builder.cache.all::<compile::Rustc>()), &[
|
||||
compile::Rustc {
|
||||
compiler: Compiler { host: a, stage: 0 },
|
||||
target: a,
|
||||
},
|
||||
compile::Rustc {
|
||||
compiler: Compiler { host: a, stage: 1 },
|
||||
target: a,
|
||||
},
|
||||
compile::Rustc {
|
||||
compiler: Compiler { host: a, stage: 0 },
|
||||
target: b,
|
||||
},
|
||||
compile::Rustc {
|
||||
compiler: Compiler { host: a, stage: 1 },
|
||||
target: b,
|
||||
},
|
||||
]);
|
||||
|
||||
assert_eq!(first(builder.cache.all::<compile::Test>()), &[
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 0 },
|
||||
target: a,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 1 },
|
||||
target: a,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: b, stage: 2 },
|
||||
target: a,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 0 },
|
||||
target: b,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 1 },
|
||||
target: b,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: b,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: b, stage: 2 },
|
||||
target: b,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: a, stage: 2 },
|
||||
target: c,
|
||||
},
|
||||
compile::Test {
|
||||
compiler: Compiler { host: b, stage: 2 },
|
||||
target: c,
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use std::mem;
|
|||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Mutex;
|
||||
use std::cmp::{PartialOrd, Ord, Ordering};
|
||||
|
||||
use builder::Step;
|
||||
|
||||
|
|
@ -154,6 +155,19 @@ impl AsRef<OsStr> for Interned<String> {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Interned<String>> for Interned<String> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
let l = INTERNER.strs.lock().unwrap();
|
||||
l.get(*self).partial_cmp(l.get(*other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Interned<String> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let l = INTERNER.strs.lock().unwrap();
|
||||
l.get(*self).cmp(l.get(*other))
|
||||
}
|
||||
}
|
||||
|
||||
struct TyIntern<T> {
|
||||
items: Vec<T>,
|
||||
|
|
@ -264,4 +278,16 @@ impl Cache {
|
|||
.expect("invalid type mapped");
|
||||
stepcache.get(step).cloned()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn all<S: Ord + Copy + Step>(&mut self) -> Vec<(S, S::Output)> {
|
||||
let cache = self.0.get_mut();
|
||||
let type_id = TypeId::of::<S>();
|
||||
let mut v = cache.remove(&type_id)
|
||||
.map(|b| b.downcast::<HashMap<S, S::Output>>().expect("correct type"))
|
||||
.map(|m| m.into_iter().collect::<Vec<_>>())
|
||||
.unwrap_or_default();
|
||||
v.sort_by_key(|&(a, _)| a);
|
||||
v
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ use Build;
|
|||
use config::Config;
|
||||
|
||||
// The version number
|
||||
pub const CFG_RELEASE_NUM: &str = "1.26.0";
|
||||
pub const CFG_RELEASE_NUM: &str = "1.27.0";
|
||||
|
||||
pub struct GitInfo {
|
||||
inner: Option<Info>,
|
||||
|
|
|
|||
|
|
@ -40,19 +40,20 @@ impl Step for Std {
|
|||
let target = self.target;
|
||||
let compiler = builder.compiler(0, build.build);
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
|
||||
println!("Checking std artifacts ({} -> {})", &compiler.host, target);
|
||||
|
||||
let out_dir = build.stage_out(compiler, Mode::Libstd);
|
||||
build.clear_if_dirty(&out_dir, &builder.rustc(compiler));
|
||||
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "check");
|
||||
std_cargo(builder, &compiler, target, &mut cargo);
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
|
||||
println!("Checking std artifacts ({} -> {})", &compiler.host, target);
|
||||
run_cargo(build,
|
||||
&mut cargo,
|
||||
&libstd_stamp(build, compiler, target),
|
||||
true);
|
||||
|
||||
let libdir = builder.sysroot_libdir(compiler, target);
|
||||
add_to_sysroot(&libdir, &libstd_stamp(build, compiler, target));
|
||||
add_to_sysroot(&build, &libdir, &libstd_stamp(build, compiler, target));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,21 +87,22 @@ impl Step for Rustc {
|
|||
let compiler = builder.compiler(0, build.build);
|
||||
let target = self.target;
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
|
||||
println!("Checking compiler artifacts ({} -> {})", &compiler.host, target);
|
||||
|
||||
let stage_out = builder.stage_out(compiler, Mode::Librustc);
|
||||
build.clear_if_dirty(&stage_out, &libstd_stamp(build, compiler, target));
|
||||
build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target));
|
||||
|
||||
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check");
|
||||
rustc_cargo(build, &mut cargo);
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
|
||||
println!("Checking compiler artifacts ({} -> {})", &compiler.host, target);
|
||||
run_cargo(build,
|
||||
&mut cargo,
|
||||
&librustc_stamp(build, compiler, target),
|
||||
true);
|
||||
|
||||
let libdir = builder.sysroot_libdir(compiler, target);
|
||||
add_to_sysroot(&libdir, &librustc_stamp(build, compiler, target));
|
||||
add_to_sysroot(&build, &libdir, &librustc_stamp(build, compiler, target));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -128,18 +130,20 @@ impl Step for Test {
|
|||
let target = self.target;
|
||||
let compiler = builder.compiler(0, build.build);
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
|
||||
println!("Checking test artifacts ({} -> {})", &compiler.host, target);
|
||||
let out_dir = build.stage_out(compiler, Mode::Libtest);
|
||||
build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
|
||||
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "check");
|
||||
test_cargo(build, &compiler, target, &mut cargo);
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
|
||||
println!("Checking test artifacts ({} -> {})", &compiler.host, target);
|
||||
run_cargo(build,
|
||||
&mut cargo,
|
||||
&libtest_stamp(build, compiler, target),
|
||||
true);
|
||||
|
||||
let libdir = builder.sysroot_libdir(compiler, target);
|
||||
add_to_sysroot(&libdir, &libtest_stamp(build, compiler, target));
|
||||
add_to_sysroot(&build, &libdir, &libtest_stamp(build, compiler, target));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
//! compiler. This module is also responsible for assembling the sysroot as it
|
||||
//! goes along from the output of the previous stage.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::BufReader;
|
||||
|
|
@ -29,7 +30,7 @@ use build_helper::{output, mtime, up_to_date};
|
|||
use filetime::FileTime;
|
||||
use serde_json;
|
||||
|
||||
use util::{exe, libdir, is_dylib, copy, read_stamp_file, CiEnv};
|
||||
use util::{exe, libdir, is_dylib, CiEnv};
|
||||
use {Build, Compiler, Mode};
|
||||
use native;
|
||||
use tool;
|
||||
|
|
@ -37,7 +38,7 @@ use tool;
|
|||
use cache::{INTERNER, Interned};
|
||||
use builder::{Step, RunConfig, ShouldRun, Builder};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Std {
|
||||
pub target: Interned<String>,
|
||||
pub compiler: Compiler,
|
||||
|
|
@ -76,7 +77,7 @@ impl Step for Std {
|
|||
compiler: from,
|
||||
target,
|
||||
});
|
||||
println!("Uplifting stage1 std ({} -> {})", from.host, target);
|
||||
builder.info(&format!("Uplifting stage1 std ({} -> {})", from.host, target));
|
||||
|
||||
// Even if we're not building std this stage, the new sysroot must
|
||||
// still contain the musl startup objects.
|
||||
|
|
@ -93,19 +94,19 @@ impl Step for Std {
|
|||
return;
|
||||
}
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
|
||||
println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
|
||||
&compiler.host, target);
|
||||
|
||||
if target.contains("musl") {
|
||||
let libdir = builder.sysroot_libdir(compiler, target);
|
||||
copy_musl_third_party_objects(build, target, &libdir);
|
||||
}
|
||||
|
||||
let out_dir = build.stage_out(compiler, Mode::Libstd);
|
||||
let out_dir = build.cargo_out(compiler, Mode::Libstd, target);
|
||||
build.clear_if_dirty(&out_dir, &builder.rustc(compiler));
|
||||
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "build");
|
||||
std_cargo(builder, &compiler, target, &mut cargo);
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
|
||||
build.info(&format!("Building stage{} std artifacts ({} -> {})", compiler.stage,
|
||||
&compiler.host, target));
|
||||
run_cargo(build,
|
||||
&mut cargo,
|
||||
&libstd_stamp(build, compiler, target),
|
||||
|
|
@ -129,7 +130,7 @@ fn copy_musl_third_party_objects(build: &Build,
|
|||
target: Interned<String>,
|
||||
into: &Path) {
|
||||
for &obj in &["crt1.o", "crti.o", "crtn.o"] {
|
||||
copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
|
||||
build.copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -139,48 +140,58 @@ pub fn std_cargo(build: &Builder,
|
|||
compiler: &Compiler,
|
||||
target: Interned<String>,
|
||||
cargo: &mut Command) {
|
||||
let mut features = build.std_features();
|
||||
|
||||
if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
|
||||
cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
|
||||
}
|
||||
|
||||
// When doing a local rebuild we tell cargo that we're stage1 rather than
|
||||
// stage0. This works fine if the local rust and being-built rust have the
|
||||
// same view of what the default allocator is, but fails otherwise. Since
|
||||
// we don't have a way to express an allocator preference yet, work
|
||||
// around the issue in the case of a local rebuild with jemalloc disabled.
|
||||
if compiler.stage == 0 && build.local_rebuild && !build.config.use_jemalloc {
|
||||
features.push_str(" force_alloc_system");
|
||||
}
|
||||
if build.no_std(target) == Some(true) {
|
||||
// for no-std targets we only compile a few no_std crates
|
||||
cargo.arg("--features").arg("c mem")
|
||||
.args(&["-p", "alloc"])
|
||||
.args(&["-p", "compiler_builtins"])
|
||||
.args(&["-p", "std_unicode"])
|
||||
.arg("--manifest-path")
|
||||
.arg(build.src.join("src/rustc/compiler_builtins_shim/Cargo.toml"));
|
||||
} else {
|
||||
let mut features = build.std_features();
|
||||
|
||||
if compiler.stage != 0 && build.config.sanitizers {
|
||||
// This variable is used by the sanitizer runtime crates, e.g.
|
||||
// rustc_lsan, to build the sanitizer runtime from C code
|
||||
// When this variable is missing, those crates won't compile the C code,
|
||||
// so we don't set this variable during stage0 where llvm-config is
|
||||
// missing
|
||||
// We also only build the runtimes when --enable-sanitizers (or its
|
||||
// config.toml equivalent) is used
|
||||
let llvm_config = build.ensure(native::Llvm {
|
||||
target: build.config.build,
|
||||
emscripten: false,
|
||||
});
|
||||
cargo.env("LLVM_CONFIG", llvm_config);
|
||||
}
|
||||
|
||||
cargo.arg("--features").arg(features)
|
||||
.arg("--manifest-path")
|
||||
.arg(build.src.join("src/libstd/Cargo.toml"));
|
||||
|
||||
if let Some(target) = build.config.target_config.get(&target) {
|
||||
if let Some(ref jemalloc) = target.jemalloc {
|
||||
cargo.env("JEMALLOC_OVERRIDE", jemalloc);
|
||||
// When doing a local rebuild we tell cargo that we're stage1 rather than
|
||||
// stage0. This works fine if the local rust and being-built rust have the
|
||||
// same view of what the default allocator is, but fails otherwise. Since
|
||||
// we don't have a way to express an allocator preference yet, work
|
||||
// around the issue in the case of a local rebuild with jemalloc disabled.
|
||||
if compiler.stage == 0 && build.local_rebuild && !build.config.use_jemalloc {
|
||||
features.push_str(" force_alloc_system");
|
||||
}
|
||||
}
|
||||
if target.contains("musl") {
|
||||
if let Some(p) = build.musl_root(target) {
|
||||
cargo.env("MUSL_ROOT", p);
|
||||
|
||||
if compiler.stage != 0 && build.config.sanitizers {
|
||||
// This variable is used by the sanitizer runtime crates, e.g.
|
||||
// rustc_lsan, to build the sanitizer runtime from C code
|
||||
// When this variable is missing, those crates won't compile the C code,
|
||||
// so we don't set this variable during stage0 where llvm-config is
|
||||
// missing
|
||||
// We also only build the runtimes when --enable-sanitizers (or its
|
||||
// config.toml equivalent) is used
|
||||
let llvm_config = build.ensure(native::Llvm {
|
||||
target: build.config.build,
|
||||
emscripten: false,
|
||||
});
|
||||
cargo.env("LLVM_CONFIG", llvm_config);
|
||||
}
|
||||
|
||||
cargo.arg("--features").arg(features)
|
||||
.arg("--manifest-path")
|
||||
.arg(build.src.join("src/libstd/Cargo.toml"));
|
||||
|
||||
if let Some(target) = build.config.target_config.get(&target) {
|
||||
if let Some(ref jemalloc) = target.jemalloc {
|
||||
cargo.env("JEMALLOC_OVERRIDE", jemalloc);
|
||||
}
|
||||
}
|
||||
if target.contains("musl") {
|
||||
if let Some(p) = build.musl_root(target) {
|
||||
cargo.env("MUSL_ROOT", p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -212,20 +223,20 @@ impl Step for StdLink {
|
|||
let compiler = self.compiler;
|
||||
let target_compiler = self.target_compiler;
|
||||
let target = self.target;
|
||||
println!("Copying stage{} std from stage{} ({} -> {} / {})",
|
||||
build.info(&format!("Copying stage{} std from stage{} ({} -> {} / {})",
|
||||
target_compiler.stage,
|
||||
compiler.stage,
|
||||
&compiler.host,
|
||||
target_compiler.host,
|
||||
target);
|
||||
target));
|
||||
let libdir = builder.sysroot_libdir(target_compiler, target);
|
||||
add_to_sysroot(&libdir, &libstd_stamp(build, compiler, target));
|
||||
add_to_sysroot(&build, &libdir, &libstd_stamp(build, compiler, target));
|
||||
|
||||
if build.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" {
|
||||
// The sanitizers are only built in stage1 or above, so the dylibs will
|
||||
// be missing in stage0 and causes panic. See the `std()` function above
|
||||
// for reason why the sanitizers are not built in stage0.
|
||||
copy_apple_sanitizer_dylibs(&build.native_dir(target), "osx", &libdir);
|
||||
copy_apple_sanitizer_dylibs(&build, &build.native_dir(target), "osx", &libdir);
|
||||
}
|
||||
|
||||
builder.ensure(tool::CleanTools {
|
||||
|
|
@ -236,7 +247,7 @@ impl Step for StdLink {
|
|||
}
|
||||
}
|
||||
|
||||
fn copy_apple_sanitizer_dylibs(native_dir: &Path, platform: &str, into: &Path) {
|
||||
fn copy_apple_sanitizer_dylibs(build: &Build, native_dir: &Path, platform: &str, into: &Path) {
|
||||
for &sanitizer in &["asan", "tsan"] {
|
||||
let filename = format!("libclang_rt.{}_{}_dynamic.dylib", sanitizer, platform);
|
||||
let mut src_path = native_dir.join(sanitizer);
|
||||
|
|
@ -244,7 +255,7 @@ fn copy_apple_sanitizer_dylibs(native_dir: &Path, platform: &str, into: &Path) {
|
|||
src_path.push("lib");
|
||||
src_path.push("darwin");
|
||||
src_path.push(&filename);
|
||||
copy(&src_path, &into.join(filename));
|
||||
build.copy(&src_path, &into.join(filename));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -300,7 +311,7 @@ impl Step for StartupObjects {
|
|||
.arg(src_file));
|
||||
}
|
||||
|
||||
copy(dst_file, &sysroot_dir.join(file.to_string() + ".o"));
|
||||
build.copy(dst_file, &sysroot_dir.join(file.to_string() + ".o"));
|
||||
}
|
||||
|
||||
for obj in ["crt2.o", "dllcrt2.o"].iter() {
|
||||
|
|
@ -308,15 +319,15 @@ impl Step for StartupObjects {
|
|||
build.cc(target),
|
||||
target,
|
||||
obj);
|
||||
copy(&src, &sysroot_dir.join(obj));
|
||||
build.copy(&src, &sysroot_dir.join(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Test {
|
||||
pub compiler: Compiler,
|
||||
pub target: Interned<String>,
|
||||
pub compiler: Compiler,
|
||||
}
|
||||
|
||||
impl Step for Test {
|
||||
|
|
@ -351,7 +362,7 @@ impl Step for Test {
|
|||
compiler: builder.compiler(1, build.build),
|
||||
target,
|
||||
});
|
||||
println!("Uplifting stage1 test ({} -> {})", &build.build, target);
|
||||
build.info(&format!("Uplifting stage1 test ({} -> {})", &build.build, target));
|
||||
builder.ensure(TestLink {
|
||||
compiler: builder.compiler(1, build.build),
|
||||
target_compiler: compiler,
|
||||
|
|
@ -360,13 +371,14 @@ impl Step for Test {
|
|||
return;
|
||||
}
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
|
||||
println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
|
||||
&compiler.host, target);
|
||||
let out_dir = build.stage_out(compiler, Mode::Libtest);
|
||||
let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
|
||||
build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
|
||||
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "build");
|
||||
test_cargo(build, &compiler, target, &mut cargo);
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
|
||||
build.info(&format!("Building stage{} test artifacts ({} -> {})", compiler.stage,
|
||||
&compiler.host, target));
|
||||
run_cargo(build,
|
||||
&mut cargo,
|
||||
&libtest_stamp(build, compiler, target),
|
||||
|
|
@ -412,13 +424,13 @@ impl Step for TestLink {
|
|||
let compiler = self.compiler;
|
||||
let target_compiler = self.target_compiler;
|
||||
let target = self.target;
|
||||
println!("Copying stage{} test from stage{} ({} -> {} / {})",
|
||||
build.info(&format!("Copying stage{} test from stage{} ({} -> {} / {})",
|
||||
target_compiler.stage,
|
||||
compiler.stage,
|
||||
&compiler.host,
|
||||
target_compiler.host,
|
||||
target);
|
||||
add_to_sysroot(&builder.sysroot_libdir(target_compiler, target),
|
||||
target));
|
||||
add_to_sysroot(&build, &builder.sysroot_libdir(target_compiler, target),
|
||||
&libtest_stamp(build, compiler, target));
|
||||
builder.ensure(tool::CleanTools {
|
||||
compiler: target_compiler,
|
||||
|
|
@ -428,10 +440,10 @@ impl Step for TestLink {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Rustc {
|
||||
pub compiler: Compiler,
|
||||
pub target: Interned<String>,
|
||||
pub compiler: Compiler,
|
||||
}
|
||||
|
||||
impl Step for Rustc {
|
||||
|
|
@ -467,7 +479,7 @@ impl Step for Rustc {
|
|||
compiler: builder.compiler(1, build.build),
|
||||
target,
|
||||
});
|
||||
println!("Uplifting stage1 rustc ({} -> {})", &build.build, target);
|
||||
build.info(&format!("Uplifting stage1 rustc ({} -> {})", &build.build, target));
|
||||
builder.ensure(RustcLink {
|
||||
compiler: builder.compiler(1, build.build),
|
||||
target_compiler: compiler,
|
||||
|
|
@ -481,17 +493,16 @@ impl Step for Rustc {
|
|||
compiler: builder.compiler(self.compiler.stage, build.build),
|
||||
target: build.build,
|
||||
});
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
|
||||
println!("Building stage{} compiler artifacts ({} -> {})",
|
||||
compiler.stage, &compiler.host, target);
|
||||
|
||||
let stage_out = builder.stage_out(compiler, Mode::Librustc);
|
||||
build.clear_if_dirty(&stage_out, &libstd_stamp(build, compiler, target));
|
||||
build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target));
|
||||
let cargo_out = builder.cargo_out(compiler, Mode::Librustc, target);
|
||||
build.clear_if_dirty(&cargo_out, &libstd_stamp(build, compiler, target));
|
||||
build.clear_if_dirty(&cargo_out, &libtest_stamp(build, compiler, target));
|
||||
|
||||
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
|
||||
rustc_cargo(build, &mut cargo);
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
|
||||
build.info(&format!("Building stage{} compiler artifacts ({} -> {})",
|
||||
compiler.stage, &compiler.host, target));
|
||||
run_cargo(build,
|
||||
&mut cargo,
|
||||
&librustc_stamp(build, compiler, target),
|
||||
|
|
@ -568,13 +579,13 @@ impl Step for RustcLink {
|
|||
let compiler = self.compiler;
|
||||
let target_compiler = self.target_compiler;
|
||||
let target = self.target;
|
||||
println!("Copying stage{} rustc from stage{} ({} -> {} / {})",
|
||||
build.info(&format!("Copying stage{} rustc from stage{} ({} -> {} / {})",
|
||||
target_compiler.stage,
|
||||
compiler.stage,
|
||||
&compiler.host,
|
||||
target_compiler.host,
|
||||
target);
|
||||
add_to_sysroot(&builder.sysroot_libdir(target_compiler, target),
|
||||
target));
|
||||
add_to_sysroot(&build, &builder.sysroot_libdir(target_compiler, target),
|
||||
&librustc_stamp(build, compiler, target));
|
||||
builder.ensure(tool::CleanTools {
|
||||
compiler: target_compiler,
|
||||
|
|
@ -634,8 +645,6 @@ impl Step for CodegenBackend {
|
|||
.arg(build.src.join("src/librustc_trans/Cargo.toml"));
|
||||
rustc_cargo_env(build, &mut cargo);
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
|
||||
|
||||
match &*self.backend {
|
||||
"llvm" | "emscripten" => {
|
||||
// Build LLVM for our target. This will implicitly build the
|
||||
|
|
@ -649,8 +658,8 @@ impl Step for CodegenBackend {
|
|||
features.push_str(" emscripten");
|
||||
}
|
||||
|
||||
println!("Building stage{} codegen artifacts ({} -> {}, {})",
|
||||
compiler.stage, &compiler.host, target, self.backend);
|
||||
build.info(&format!("Building stage{} codegen artifacts ({} -> {}, {})",
|
||||
compiler.stage, &compiler.host, target, self.backend));
|
||||
|
||||
// Pass down configuration from the LLVM build into the build of
|
||||
// librustc_llvm and librustc_trans.
|
||||
|
|
@ -685,10 +694,15 @@ impl Step for CodegenBackend {
|
|||
|
||||
let tmp_stamp = build.cargo_out(compiler, Mode::Librustc, target)
|
||||
.join(".tmp.stamp");
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
|
||||
let files = run_cargo(build,
|
||||
cargo.arg("--features").arg(features),
|
||||
&tmp_stamp,
|
||||
false);
|
||||
if builder.config.dry_run {
|
||||
return;
|
||||
}
|
||||
let mut files = files.into_iter()
|
||||
.filter(|f| {
|
||||
let filename = f.file_name().unwrap().to_str().unwrap();
|
||||
|
|
@ -732,6 +746,10 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder,
|
|||
let dst = builder.sysroot_codegen_backends(target_compiler);
|
||||
t!(fs::create_dir_all(&dst));
|
||||
|
||||
if builder.config.dry_run {
|
||||
return;
|
||||
}
|
||||
|
||||
for backend in builder.config.rust_codegen_backends.iter() {
|
||||
let stamp = codegen_backend_stamp(build, compiler, target, *backend);
|
||||
let mut dylib = String::new();
|
||||
|
|
@ -747,7 +765,7 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder,
|
|||
backend,
|
||||
&filename[dot..])
|
||||
};
|
||||
copy(&file, &dst.join(target_filename));
|
||||
build.copy(&file, &dst.join(target_filename));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -763,7 +781,7 @@ fn copy_lld_to_sysroot(builder: &Builder,
|
|||
t!(fs::create_dir_all(&dst));
|
||||
|
||||
let exe = exe("lld", &target);
|
||||
copy(&lld_install_root.join("bin").join(&exe), &dst.join(&exe));
|
||||
builder.copy(&lld_install_root.join("bin").join(&exe), &dst.join(&exe));
|
||||
}
|
||||
|
||||
/// Cargo's output path for the standard library in a given stage, compiled
|
||||
|
|
@ -835,7 +853,7 @@ impl Step for Sysroot {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Copy, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Assemble {
|
||||
/// The compiler which we will produce in this step. Assemble itself will
|
||||
/// take care of ensuring that the necessary prerequisites to do so exist,
|
||||
|
|
@ -915,7 +933,7 @@ impl Step for Assemble {
|
|||
}
|
||||
}
|
||||
|
||||
let lld_install = if build.config.lld_enabled && target_compiler.stage > 0 {
|
||||
let lld_install = if build.config.lld_enabled {
|
||||
Some(builder.ensure(native::Lld {
|
||||
target: target_compiler.host,
|
||||
}))
|
||||
|
|
@ -925,17 +943,17 @@ impl Step for Assemble {
|
|||
|
||||
let stage = target_compiler.stage;
|
||||
let host = target_compiler.host;
|
||||
println!("Assembling stage{} compiler ({})", stage, host);
|
||||
build.info(&format!("Assembling stage{} compiler ({})", stage, host));
|
||||
|
||||
// Link in all dylibs to the libdir
|
||||
let sysroot = builder.sysroot(target_compiler);
|
||||
let sysroot_libdir = sysroot.join(libdir(&*host));
|
||||
t!(fs::create_dir_all(&sysroot_libdir));
|
||||
let src_libdir = builder.sysroot_libdir(build_compiler, host);
|
||||
for f in t!(fs::read_dir(&src_libdir)).map(|f| t!(f)) {
|
||||
for f in builder.read_dir(&src_libdir) {
|
||||
let filename = f.file_name().into_string().unwrap();
|
||||
if is_dylib(&filename) {
|
||||
copy(&f.path(), &sysroot_libdir.join(&filename));
|
||||
builder.copy(&f.path(), &sysroot_libdir.join(&filename));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -953,7 +971,7 @@ impl Step for Assemble {
|
|||
t!(fs::create_dir_all(&bindir));
|
||||
let compiler = builder.rustc(target_compiler);
|
||||
let _ = fs::remove_file(&compiler);
|
||||
copy(&rustc, &compiler);
|
||||
builder.copy(&rustc, &compiler);
|
||||
|
||||
target_compiler
|
||||
}
|
||||
|
|
@ -963,10 +981,10 @@ impl Step for Assemble {
|
|||
///
|
||||
/// For a particular stage this will link the file listed in `stamp` into the
|
||||
/// `sysroot_dst` provided.
|
||||
pub fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) {
|
||||
pub fn add_to_sysroot(build: &Build, sysroot_dst: &Path, stamp: &Path) {
|
||||
t!(fs::create_dir_all(&sysroot_dst));
|
||||
for path in read_stamp_file(stamp) {
|
||||
copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
|
||||
for path in build.read_stamp_file(stamp) {
|
||||
build.copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -996,24 +1014,10 @@ fn stderr_isatty() -> bool {
|
|||
pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: bool)
|
||||
-> Vec<PathBuf>
|
||||
{
|
||||
// Instruct Cargo to give us json messages on stdout, critically leaving
|
||||
// stderr as piped so we can get those pretty colors.
|
||||
cargo.arg("--message-format").arg("json")
|
||||
.stdout(Stdio::piped());
|
||||
|
||||
if stderr_isatty() && build.ci_env == CiEnv::None {
|
||||
// since we pass message-format=json to cargo, we need to tell the rustc
|
||||
// wrapper to give us colored output if necessary. This is because we
|
||||
// only want Cargo's JSON output, not rustcs.
|
||||
cargo.env("RUSTC_COLOR", "1");
|
||||
if build.config.dry_run {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
build.verbose(&format!("running: {:?}", cargo));
|
||||
let mut child = match cargo.spawn() {
|
||||
Ok(child) => child,
|
||||
Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cargo, e),
|
||||
};
|
||||
|
||||
// `target_root_dir` looks like $dir/$target/release
|
||||
let target_root_dir = stamp.parent().unwrap();
|
||||
// `target_deps_dir` looks like $dir/$target/release/deps
|
||||
|
|
@ -1028,46 +1032,33 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo
|
|||
// files we need to probe for later.
|
||||
let mut deps = Vec::new();
|
||||
let mut toplevel = Vec::new();
|
||||
let stdout = BufReader::new(child.stdout.take().unwrap());
|
||||
for line in stdout.lines() {
|
||||
let line = t!(line);
|
||||
let json: serde_json::Value = if line.starts_with("{") {
|
||||
t!(serde_json::from_str(&line))
|
||||
} else {
|
||||
// If this was informational, just print it out and continue
|
||||
println!("{}", line);
|
||||
continue
|
||||
let ok = stream_cargo(build, cargo, &mut |msg| {
|
||||
let filenames = match msg {
|
||||
CargoMessage::CompilerArtifact { filenames, .. } => filenames,
|
||||
_ => return,
|
||||
};
|
||||
if json["reason"].as_str() != Some("compiler-artifact") {
|
||||
if build.config.rustc_error_format.as_ref().map_or(false, |e| e == "json") {
|
||||
// most likely not a cargo message, so let's send it out as well
|
||||
println!("{}", line);
|
||||
}
|
||||
continue
|
||||
}
|
||||
for filename in json["filenames"].as_array().unwrap() {
|
||||
let filename = filename.as_str().unwrap();
|
||||
for filename in filenames {
|
||||
// Skip files like executables
|
||||
if !filename.ends_with(".rlib") &&
|
||||
!filename.ends_with(".lib") &&
|
||||
!is_dylib(&filename) &&
|
||||
!(is_check && filename.ends_with(".rmeta")) {
|
||||
continue
|
||||
return;
|
||||
}
|
||||
|
||||
let filename = Path::new(filename);
|
||||
let filename = Path::new(&*filename);
|
||||
|
||||
// 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;
|
||||
return;
|
||||
}
|
||||
|
||||
// If this was output in the `deps` dir then this is a precise file
|
||||
// name (hash included) so we start tracking it.
|
||||
if filename.starts_with(&target_deps_dir) {
|
||||
deps.push(filename.to_path_buf());
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise this was a "top level artifact" which right now doesn't
|
||||
|
|
@ -1088,15 +1079,10 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo
|
|||
|
||||
toplevel.push((file_stem, extension, expected_len));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure Cargo actually succeeded after we read all of its stdout.
|
||||
let status = t!(child.wait());
|
||||
if !status.success() {
|
||||
panic!("command did not execute successfully: {:?}\n\
|
||||
expected success, got: {}",
|
||||
cargo,
|
||||
status);
|
||||
if !ok {
|
||||
panic!("cargo must succeed");
|
||||
}
|
||||
|
||||
// Ok now we need to actually find all the files listed in `toplevel`. We've
|
||||
|
|
@ -1155,7 +1141,7 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo
|
|||
let max = max.unwrap();
|
||||
let max_path = max_path.unwrap();
|
||||
if stamp_contents == new_contents && max <= stamp_mtime {
|
||||
build.verbose(&format!("not updating {:?}; contents equal and {} <= {}",
|
||||
build.verbose(&format!("not updating {:?}; contents equal and {:?} <= {:?}",
|
||||
stamp, max, stamp_mtime));
|
||||
return deps
|
||||
}
|
||||
|
|
@ -1167,3 +1153,66 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo
|
|||
t!(t!(File::create(stamp)).write_all(&new_contents));
|
||||
deps
|
||||
}
|
||||
|
||||
pub fn stream_cargo(
|
||||
build: &Build,
|
||||
cargo: &mut Command,
|
||||
cb: &mut FnMut(CargoMessage),
|
||||
) -> bool {
|
||||
if build.config.dry_run {
|
||||
return true;
|
||||
}
|
||||
// Instruct Cargo to give us json messages on stdout, critically leaving
|
||||
// stderr as piped so we can get those pretty colors.
|
||||
cargo.arg("--message-format").arg("json")
|
||||
.stdout(Stdio::piped());
|
||||
|
||||
if stderr_isatty() && build.ci_env == CiEnv::None {
|
||||
// since we pass message-format=json to cargo, we need to tell the rustc
|
||||
// wrapper to give us colored output if necessary. This is because we
|
||||
// only want Cargo's JSON output, not rustcs.
|
||||
cargo.env("RUSTC_COLOR", "1");
|
||||
}
|
||||
|
||||
build.verbose(&format!("running: {:?}", cargo));
|
||||
let mut child = match cargo.spawn() {
|
||||
Ok(child) => child,
|
||||
Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cargo, e),
|
||||
};
|
||||
|
||||
// Spawn Cargo slurping up its JSON output. We'll start building up the
|
||||
// `deps` array of all files it generated along with a `toplevel` array of
|
||||
// files we need to probe for later.
|
||||
let stdout = BufReader::new(child.stdout.take().unwrap());
|
||||
for line in stdout.lines() {
|
||||
let line = t!(line);
|
||||
match serde_json::from_str::<CargoMessage>(&line) {
|
||||
Ok(msg) => cb(msg),
|
||||
// If this was informational, just print it out and continue
|
||||
Err(_) => println!("{}", line)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure Cargo actually succeeded after we read all of its stdout.
|
||||
let status = t!(child.wait());
|
||||
if !status.success() {
|
||||
eprintln!("command did not execute successfully: {:?}\n\
|
||||
expected success, got: {}",
|
||||
cargo,
|
||||
status);
|
||||
}
|
||||
status.success()
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "reason", rename_all = "kebab-case")]
|
||||
pub enum CargoMessage<'a> {
|
||||
CompilerArtifact {
|
||||
package_id: Cow<'a, str>,
|
||||
features: Vec<Cow<'a, str>>,
|
||||
filenames: Vec<Cow<'a, str>>,
|
||||
},
|
||||
BuildScriptExecuted {
|
||||
package_id: Cow<'a, str>,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::fs::{self, File};
|
||||
use std::io::prelude::*;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process;
|
||||
|
|
@ -45,6 +45,7 @@ pub struct Config {
|
|||
pub ninja: bool,
|
||||
pub verbose: usize,
|
||||
pub submodules: bool,
|
||||
pub fast_submodules: bool,
|
||||
pub compiler_docs: bool,
|
||||
pub docs: bool,
|
||||
pub locked_deps: bool,
|
||||
|
|
@ -68,6 +69,7 @@ pub struct Config {
|
|||
pub jobs: Option<u32>,
|
||||
pub cmd: Subcommand,
|
||||
pub incremental: bool,
|
||||
pub dry_run: bool,
|
||||
|
||||
// llvm codegen options
|
||||
pub llvm_enabled: bool,
|
||||
|
|
@ -121,6 +123,7 @@ pub struct Config {
|
|||
pub quiet_tests: bool,
|
||||
pub test_miri: bool,
|
||||
pub save_toolstates: Option<PathBuf>,
|
||||
pub print_step_timings: bool,
|
||||
|
||||
// Fallback musl-root for all targets
|
||||
pub musl_root: Option<PathBuf>,
|
||||
|
|
@ -141,6 +144,7 @@ pub struct Config {
|
|||
// These are either the stage0 downloaded binaries or the locally installed ones.
|
||||
pub initial_cargo: PathBuf,
|
||||
pub initial_rustc: PathBuf,
|
||||
pub out: PathBuf,
|
||||
}
|
||||
|
||||
/// Per-target configuration stored in the global configuration structure.
|
||||
|
|
@ -157,6 +161,7 @@ pub struct Target {
|
|||
pub crt_static: Option<bool>,
|
||||
pub musl_root: Option<PathBuf>,
|
||||
pub qemu_rootfs: Option<PathBuf>,
|
||||
pub no_std: bool,
|
||||
}
|
||||
|
||||
/// Structure of the `config.toml` file that configuration is read from.
|
||||
|
|
@ -190,6 +195,7 @@ struct Build {
|
|||
compiler_docs: Option<bool>,
|
||||
docs: Option<bool>,
|
||||
submodules: Option<bool>,
|
||||
fast_submodules: Option<bool>,
|
||||
gdb: Option<String>,
|
||||
locked_deps: Option<bool>,
|
||||
vendor: Option<bool>,
|
||||
|
|
@ -204,6 +210,7 @@ struct Build {
|
|||
openssl_static: Option<bool>,
|
||||
configure_args: Option<Vec<String>>,
|
||||
local_rebuild: Option<bool>,
|
||||
print_step_timings: Option<bool>,
|
||||
}
|
||||
|
||||
/// TOML representation of various global install decisions.
|
||||
|
|
@ -313,11 +320,8 @@ struct TomlTarget {
|
|||
}
|
||||
|
||||
impl Config {
|
||||
pub fn parse(args: &[String]) -> Config {
|
||||
let flags = Flags::parse(&args);
|
||||
let file = flags.config.clone();
|
||||
pub fn default_opts() -> Config {
|
||||
let mut config = Config::default();
|
||||
config.exclude = flags.exclude;
|
||||
config.llvm_enabled = true;
|
||||
config.llvm_optimize = true;
|
||||
config.llvm_version_check = true;
|
||||
|
|
@ -326,6 +330,7 @@ impl Config {
|
|||
config.rust_optimize = true;
|
||||
config.rust_optimize_tests = true;
|
||||
config.submodules = true;
|
||||
config.fast_submodules = true;
|
||||
config.docs = true;
|
||||
config.rust_rpath = true;
|
||||
config.channel = "dev".to_string();
|
||||
|
|
@ -336,15 +341,38 @@ impl Config {
|
|||
config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
|
||||
config.rust_codegen_backends_dir = "codegen-backends".to_owned();
|
||||
|
||||
// set by bootstrap.py
|
||||
config.src = env::var_os("SRC").map(PathBuf::from).expect("'SRC' to be set");
|
||||
config.build = INTERNER.intern_str(&env::var("BUILD").expect("'BUILD' to be set"));
|
||||
config.out = env::var_os("BUILD_DIR").map(PathBuf::from).expect("'BUILD_DIR' set");
|
||||
|
||||
let stage0_root = config.out.join(&config.build).join("stage0/bin");
|
||||
config.initial_rustc = stage0_root.join(exe("rustc", &config.build));
|
||||
config.initial_cargo = stage0_root.join(exe("cargo", &config.build));
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
pub fn parse(args: &[String]) -> Config {
|
||||
let flags = Flags::parse(&args);
|
||||
let file = flags.config.clone();
|
||||
let mut config = Config::default_opts();
|
||||
config.exclude = flags.exclude;
|
||||
config.rustc_error_format = flags.rustc_error_format;
|
||||
config.on_fail = flags.on_fail;
|
||||
config.stage = flags.stage;
|
||||
config.src = flags.src;
|
||||
config.jobs = flags.jobs;
|
||||
config.cmd = flags.cmd;
|
||||
config.incremental = flags.incremental;
|
||||
config.dry_run = flags.dry_run;
|
||||
config.keep_stage = flags.keep_stage;
|
||||
|
||||
if config.dry_run {
|
||||
let dir = config.out.join("tmp-dry-run");
|
||||
t!(fs::create_dir_all(&dir));
|
||||
config.out = dir;
|
||||
}
|
||||
|
||||
// If --target was specified but --host wasn't specified, don't run any host-only tests.
|
||||
config.run_host_only = !(flags.host.is_empty() && !flags.target.is_empty());
|
||||
|
||||
|
|
@ -363,12 +391,7 @@ impl Config {
|
|||
}).unwrap_or_else(|| TomlConfig::default());
|
||||
|
||||
let build = toml.build.clone().unwrap_or(Build::default());
|
||||
set(&mut config.build, build.build.clone().map(|x| INTERNER.intern_string(x)));
|
||||
set(&mut config.build, flags.build);
|
||||
if config.build.is_empty() {
|
||||
// set by bootstrap.py
|
||||
config.build = INTERNER.intern_str(&env::var("BUILD").unwrap());
|
||||
}
|
||||
// set by bootstrap.py
|
||||
config.hosts.push(config.build.clone());
|
||||
for host in build.host.iter() {
|
||||
let host = INTERNER.intern_str(host);
|
||||
|
|
@ -402,6 +425,7 @@ impl Config {
|
|||
set(&mut config.compiler_docs, build.compiler_docs);
|
||||
set(&mut config.docs, build.docs);
|
||||
set(&mut config.submodules, build.submodules);
|
||||
set(&mut config.fast_submodules, build.fast_submodules);
|
||||
set(&mut config.locked_deps, build.locked_deps);
|
||||
set(&mut config.vendor, build.vendor);
|
||||
set(&mut config.full_bootstrap, build.full_bootstrap);
|
||||
|
|
@ -413,6 +437,7 @@ impl Config {
|
|||
set(&mut config.openssl_static, build.openssl_static);
|
||||
set(&mut config.configure_args, build.configure_args);
|
||||
set(&mut config.local_rebuild, build.local_rebuild);
|
||||
set(&mut config.print_step_timings, build.print_step_timings);
|
||||
config.verbose = cmp::max(config.verbose, flags.verbose);
|
||||
|
||||
if let Some(ref install) = toml.install {
|
||||
|
|
@ -507,13 +532,13 @@ impl Config {
|
|||
let mut target = Target::default();
|
||||
|
||||
if let Some(ref s) = cfg.llvm_config {
|
||||
target.llvm_config = Some(env::current_dir().unwrap().join(s));
|
||||
target.llvm_config = Some(config.src.join(s));
|
||||
}
|
||||
if let Some(ref s) = cfg.jemalloc {
|
||||
target.jemalloc = Some(env::current_dir().unwrap().join(s));
|
||||
target.jemalloc = Some(config.src.join(s));
|
||||
}
|
||||
if let Some(ref s) = cfg.android_ndk {
|
||||
target.ndk = Some(env::current_dir().unwrap().join(s));
|
||||
target.ndk = Some(config.src.join(s));
|
||||
}
|
||||
target.cc = cfg.cc.clone().map(PathBuf::from);
|
||||
target.cxx = cfg.cxx.clone().map(PathBuf::from);
|
||||
|
|
@ -534,22 +559,12 @@ 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)),
|
||||
};
|
||||
|
||||
// Now that we've reached the end of our configuration, infer the
|
||||
// default values for all options that we haven't otherwise stored yet.
|
||||
|
||||
set(&mut config.initial_rustc, build.rustc.map(PathBuf::from));
|
||||
set(&mut config.initial_rustc, build.cargo.map(PathBuf::from));
|
||||
|
||||
let default = false;
|
||||
config.llvm_assertions = llvm_assertions.unwrap_or(default);
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ o("debug", "rust.debug", "debug mode; disables optimization unless `--enable-opt
|
|||
o("docs", "build.docs", "build standard library documentation")
|
||||
o("compiler-docs", "build.compiler-docs", "build compiler documentation")
|
||||
o("optimize-tests", "rust.optimize-tests", "build tests with optimizations")
|
||||
o("experimental-parallel-queries", "rust.experimental-parallel-queries", "build rustc with experimental parallelization")
|
||||
o("test-miri", "rust.test-miri", "run miri's test suite")
|
||||
o("debuginfo-tests", "rust.debuginfo-tests", "build tests with debugger metadata")
|
||||
o("quiet-tests", "rust.quiet-tests", "enable quieter output when running tests")
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ use build_helper::output;
|
|||
|
||||
use {Build, Compiler, Mode};
|
||||
use channel;
|
||||
use util::{cp_r, libdir, is_dylib, cp_filtered, copy, replace_in_file, exe};
|
||||
use util::{libdir, is_dylib, exe};
|
||||
use builder::{Builder, RunConfig, ShouldRun, Step};
|
||||
use compile;
|
||||
use native;
|
||||
|
|
@ -61,7 +61,7 @@ fn rust_installer(builder: &Builder) -> Command {
|
|||
builder.tool_cmd(Tool::RustInstaller)
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Docs {
|
||||
pub stage: u32,
|
||||
pub host: Interned<String>,
|
||||
|
|
@ -89,9 +89,9 @@ impl Step for Docs {
|
|||
|
||||
let name = pkgname(build, "rust-docs");
|
||||
|
||||
println!("Dist docs ({})", host);
|
||||
build.info(&format!("Dist docs ({})", host));
|
||||
if !build.config.docs {
|
||||
println!("\tskipping - docs disabled");
|
||||
build.info(&format!("\tskipping - docs disabled"));
|
||||
return distdir(build).join(format!("{}-{}.tar.gz", name, host));
|
||||
}
|
||||
|
||||
|
|
@ -102,8 +102,8 @@ impl Step for Docs {
|
|||
|
||||
let dst = image.join("share/doc/rust/html");
|
||||
t!(fs::create_dir_all(&dst));
|
||||
let src = build.out.join(host).join("doc");
|
||||
cp_r(&src, &dst);
|
||||
let src = build.doc_out(host);
|
||||
build.cp_r(&src, &dst);
|
||||
|
||||
let mut cmd = rust_installer(builder);
|
||||
cmd.arg("generate")
|
||||
|
|
@ -118,16 +118,71 @@ impl Step for Docs {
|
|||
.arg("--legacy-manifest-dirs=rustlib,cargo")
|
||||
.arg("--bulk-dirs=share/doc/rust/html");
|
||||
build.run(&mut cmd);
|
||||
t!(fs::remove_dir_all(&image));
|
||||
build.remove_dir(&image);
|
||||
|
||||
// As part of this step, *also* copy the docs directory to a directory which
|
||||
// buildbot typically uploads.
|
||||
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);
|
||||
distdir(build).join(format!("{}-{}.tar.gz", name, host))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct RustcDocs {
|
||||
pub stage: u32,
|
||||
pub host: Interned<String>,
|
||||
}
|
||||
|
||||
impl Step for RustcDocs {
|
||||
type Output = PathBuf;
|
||||
const DEFAULT: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun) -> ShouldRun {
|
||||
run.path("src/librustc")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig) {
|
||||
run.builder.ensure(RustcDocs {
|
||||
stage: run.builder.top_stage,
|
||||
host: run.target,
|
||||
});
|
||||
}
|
||||
|
||||
/// Builds the `rustc-docs` installer component.
|
||||
fn run(self, builder: &Builder) -> PathBuf {
|
||||
let build = builder.build;
|
||||
let host = self.host;
|
||||
|
||||
let name = pkgname(build, "rustc-docs");
|
||||
|
||||
build.info(&format!("Dist compiler docs ({})", host));
|
||||
if !build.config.compiler_docs {
|
||||
build.info(&format!("\tskipping - compiler docs disabled"));
|
||||
return distdir(build).join(format!("{}-{}.tar.gz", name, host));
|
||||
}
|
||||
|
||||
builder.default_doc(None);
|
||||
|
||||
let image = tmpdir(build).join(format!("{}-{}-image", name, host));
|
||||
let _ = fs::remove_dir_all(&image);
|
||||
|
||||
let dst = image.join("share/doc/rust/html");
|
||||
t!(fs::create_dir_all(&dst));
|
||||
let src = build.compiler_doc_out(host);
|
||||
build.cp_r(&src, &dst);
|
||||
|
||||
let mut cmd = rust_installer(builder);
|
||||
cmd.arg("generate")
|
||||
.arg("--product-name=Rustc-Documentation")
|
||||
.arg("--rel-manifest-dir=rustlib")
|
||||
.arg("--success-message=Rustc-documentation-is-installed.")
|
||||
.arg("--image-dir").arg(&image)
|
||||
.arg("--work-dir").arg(&tmpdir(build))
|
||||
.arg("--output-dir").arg(&distdir(build))
|
||||
.arg(format!("--package-name={}-{}", name, host))
|
||||
.arg("--component-name=rustc-docs")
|
||||
.arg("--legacy-manifest-dirs=rustlib,cargo")
|
||||
.arg("--bulk-dirs=share/doc/rust/html");
|
||||
build.run(&mut cmd);
|
||||
build.remove_dir(&image);
|
||||
|
||||
distdir(build).join(format!("{}-{}.tar.gz", name, host))
|
||||
}
|
||||
}
|
||||
|
|
@ -237,37 +292,31 @@ fn make_win_dist(
|
|||
let rustc_dlls = find_files(&rustc_dlls, &bin_path);
|
||||
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();
|
||||
let dest = dest_folder.join(file_name);
|
||||
copy(src, &dest);
|
||||
}
|
||||
|
||||
//Copy runtime dlls next to rustc.exe
|
||||
// Copy runtime dlls next to rustc.exe
|
||||
let dist_bin_dir = rust_root.join("bin/");
|
||||
fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed");
|
||||
for src in rustc_dlls {
|
||||
copy_to_folder(&src, &dist_bin_dir);
|
||||
build.copy_to_folder(&src, &dist_bin_dir);
|
||||
}
|
||||
|
||||
//Copy platform tools to platform-specific bin directory
|
||||
let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin");
|
||||
fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
|
||||
for src in target_tools {
|
||||
copy_to_folder(&src, &target_bin_dir);
|
||||
build.copy_to_folder(&src, &target_bin_dir);
|
||||
}
|
||||
|
||||
//Copy platform libs to platform-specific lib directory
|
||||
let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib");
|
||||
fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
|
||||
for src in target_libs {
|
||||
copy_to_folder(&src, &target_lib_dir);
|
||||
build.copy_to_folder(&src, &target_lib_dir);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Mingw {
|
||||
host: Interned<String>,
|
||||
pub host: Interned<String>,
|
||||
}
|
||||
|
||||
impl Step for Mingw {
|
||||
|
|
@ -294,7 +343,7 @@ impl Step for Mingw {
|
|||
return None;
|
||||
}
|
||||
|
||||
println!("Dist mingw ({})", host);
|
||||
build.info(&format!("Dist mingw ({})", host));
|
||||
let name = pkgname(build, "rust-mingw");
|
||||
let image = tmpdir(build).join(format!("{}-{}-image", name, host));
|
||||
let _ = fs::remove_dir_all(&image);
|
||||
|
|
@ -323,7 +372,7 @@ impl Step for Mingw {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Rustc {
|
||||
pub compiler: Compiler,
|
||||
}
|
||||
|
|
@ -349,7 +398,7 @@ impl Step for Rustc {
|
|||
let compiler = self.compiler;
|
||||
let host = self.compiler.host;
|
||||
|
||||
println!("Dist rustc stage{} ({})", compiler.stage, compiler.host);
|
||||
build.info(&format!("Dist rustc stage{} ({})", compiler.stage, compiler.host));
|
||||
let name = pkgname(build, "rustc");
|
||||
let image = tmpdir(build).join(format!("{}-{}-image", name, host));
|
||||
let _ = fs::remove_dir_all(&image);
|
||||
|
|
@ -362,7 +411,7 @@ impl Step for Rustc {
|
|||
// Prepare the overlay which is part of the tarball but won't actually be
|
||||
// installed
|
||||
let cp = |file: &str| {
|
||||
install(&build.src.join(file), &overlay, 0o644);
|
||||
build.install(&build.src.join(file), &overlay, 0o644);
|
||||
};
|
||||
cp("COPYRIGHT");
|
||||
cp("LICENSE-APACHE");
|
||||
|
|
@ -370,9 +419,9 @@ impl Step for Rustc {
|
|||
cp("README.md");
|
||||
// tiny morsel of metadata is used by rust-packaging
|
||||
let version = build.rust_version();
|
||||
t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
|
||||
build.create(&overlay.join("version"), &version);
|
||||
if let Some(sha) = build.rust_sha() {
|
||||
t!(t!(File::create(overlay.join("git-commit-hash"))).write_all(sha.as_bytes()));
|
||||
build.create(&overlay.join("git-commit-hash"), &sha);
|
||||
}
|
||||
|
||||
// On MinGW we've got a few runtime DLL dependencies that we need to
|
||||
|
|
@ -390,7 +439,7 @@ impl Step for Rustc {
|
|||
|
||||
let dst = image.join("share/doc");
|
||||
t!(fs::create_dir_all(&dst));
|
||||
cp_r(&build.src.join("src/etc/third-party"), &dst);
|
||||
build.cp_r(&build.src.join("src/etc/third-party"), &dst);
|
||||
}
|
||||
|
||||
// Finally, wrap everything up in a nice tarball!
|
||||
|
|
@ -407,8 +456,8 @@ impl Step for Rustc {
|
|||
.arg("--component-name=rustc")
|
||||
.arg("--legacy-manifest-dirs=rustlib,cargo");
|
||||
build.run(&mut cmd);
|
||||
t!(fs::remove_dir_all(&image));
|
||||
t!(fs::remove_dir_all(&overlay));
|
||||
build.remove_dir(&image);
|
||||
build.remove_dir(&overlay);
|
||||
|
||||
return distdir(build).join(format!("{}-{}.tar.gz", name, host));
|
||||
|
||||
|
|
@ -420,17 +469,17 @@ impl Step for Rustc {
|
|||
|
||||
// Copy rustc/rustdoc binaries
|
||||
t!(fs::create_dir_all(image.join("bin")));
|
||||
cp_r(&src.join("bin"), &image.join("bin"));
|
||||
build.cp_r(&src.join("bin"), &image.join("bin"));
|
||||
|
||||
install(&builder.rustdoc(compiler.host), &image.join("bin"), 0o755);
|
||||
build.install(&builder.rustdoc(compiler.host), &image.join("bin"), 0o755);
|
||||
|
||||
// Copy runtime DLLs needed by the compiler
|
||||
if libdir != "bin" {
|
||||
for entry in t!(src.join(libdir).read_dir()).map(|e| t!(e)) {
|
||||
for entry in build.read_dir(&src.join(libdir)) {
|
||||
let name = entry.file_name();
|
||||
if let Some(s) = name.to_str() {
|
||||
if is_dylib(s) {
|
||||
install(&entry.path(), &image.join(libdir), 0o644);
|
||||
build.install(&entry.path(), &image.join(libdir), 0o644);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -441,7 +490,7 @@ impl Step for Rustc {
|
|||
let backends_rel = backends_src.strip_prefix(&src).unwrap();
|
||||
let backends_dst = image.join(&backends_rel);
|
||||
t!(fs::create_dir_all(&backends_dst));
|
||||
cp_r(&backends_src, &backends_dst);
|
||||
build.cp_r(&backends_src, &backends_dst);
|
||||
|
||||
// Copy over lld if it's there
|
||||
if builder.config.lld_enabled {
|
||||
|
|
@ -456,7 +505,7 @@ impl Step for Rustc {
|
|||
.join("bin")
|
||||
.join(&exe);
|
||||
t!(fs::create_dir_all(&dst.parent().unwrap()));
|
||||
copy(&src, &dst);
|
||||
build.copy(&src, &dst);
|
||||
}
|
||||
|
||||
// Man pages
|
||||
|
|
@ -466,13 +515,12 @@ impl Step for Rustc {
|
|||
let month_year = t!(time::strftime("%B %Y", &time::now()));
|
||||
// don't use our `bootstrap::util::{copy, cp_r}`, because those try
|
||||
// to hardlink, and we don't want to edit the source templates
|
||||
for entry_result in t!(fs::read_dir(man_src)) {
|
||||
let file_entry = t!(entry_result);
|
||||
for file_entry in build.read_dir(&man_src) {
|
||||
let page_src = file_entry.path();
|
||||
let page_dst = man_dst.join(file_entry.file_name());
|
||||
t!(fs::copy(&page_src, &page_dst));
|
||||
// template in month/year and version number
|
||||
replace_in_file(&page_dst,
|
||||
build.replace_in_file(&page_dst,
|
||||
&[("<INSERT DATE HERE>", &month_year),
|
||||
("<INSERT VERSION HERE>", channel::CFG_RELEASE_NUM)]);
|
||||
}
|
||||
|
|
@ -485,7 +533,7 @@ impl Step for Rustc {
|
|||
|
||||
// Misc license info
|
||||
let cp = |file: &str| {
|
||||
install(&build.src.join(file), &image.join("share/doc/rust"), 0o644);
|
||||
build.install(&build.src.join(file), &image.join("share/doc/rust"), 0o644);
|
||||
};
|
||||
cp("COPYRIGHT");
|
||||
cp("LICENSE-APACHE");
|
||||
|
|
@ -523,11 +571,11 @@ impl Step for DebuggerScripts {
|
|||
let dst = sysroot.join("lib/rustlib/etc");
|
||||
t!(fs::create_dir_all(&dst));
|
||||
let cp_debugger_script = |file: &str| {
|
||||
install(&build.src.join("src/etc/").join(file), &dst, 0o644);
|
||||
build.install(&build.src.join("src/etc/").join(file), &dst, 0o644);
|
||||
};
|
||||
if host.contains("windows-msvc") {
|
||||
// windbg debugger scripts
|
||||
install(&build.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"),
|
||||
build.install(&build.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"),
|
||||
0o755);
|
||||
|
||||
cp_debugger_script("natvis/intrinsic.natvis");
|
||||
|
|
@ -537,14 +585,14 @@ impl Step for DebuggerScripts {
|
|||
cp_debugger_script("debugger_pretty_printers_common.py");
|
||||
|
||||
// gdb debugger scripts
|
||||
install(&build.src.join("src/etc/rust-gdb"), &sysroot.join("bin"),
|
||||
build.install(&build.src.join("src/etc/rust-gdb"), &sysroot.join("bin"),
|
||||
0o755);
|
||||
|
||||
cp_debugger_script("gdb_load_rust_pretty_printers.py");
|
||||
cp_debugger_script("gdb_rust_pretty_printing.py");
|
||||
|
||||
// lldb debugger scripts
|
||||
install(&build.src.join("src/etc/rust-lldb"), &sysroot.join("bin"),
|
||||
build.install(&build.src.join("src/etc/rust-lldb"), &sysroot.join("bin"),
|
||||
0o755);
|
||||
|
||||
cp_debugger_script("lldb_rust_formatters.py");
|
||||
|
|
@ -552,7 +600,7 @@ impl Step for DebuggerScripts {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Std {
|
||||
pub compiler: Compiler,
|
||||
pub target: Interned<String>,
|
||||
|
|
@ -579,12 +627,12 @@ impl Step for Std {
|
|||
let target = self.target;
|
||||
|
||||
let name = pkgname(build, "rust-std");
|
||||
println!("Dist std stage{} ({} -> {})", compiler.stage, &compiler.host, target);
|
||||
build.info(&format!("Dist std stage{} ({} -> {})", compiler.stage, &compiler.host, target));
|
||||
|
||||
// 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.build {
|
||||
println!("\tskipping, not a build host");
|
||||
build.info(&format!("\tskipping, not a build host"));
|
||||
return distdir(build).join(format!("{}-{}.tar.gz", name, target));
|
||||
}
|
||||
|
||||
|
|
@ -594,7 +642,12 @@ impl Step for Std {
|
|||
if build.hosts.iter().any(|t| t == target) {
|
||||
builder.ensure(compile::Rustc { compiler, target });
|
||||
} else {
|
||||
builder.ensure(compile::Test { compiler, target });
|
||||
if build.no_std(target) == Some(true) {
|
||||
// the `test` doesn't compile for no-std targets
|
||||
builder.ensure(compile::Std { compiler, target });
|
||||
} else {
|
||||
builder.ensure(compile::Test { compiler, target });
|
||||
}
|
||||
}
|
||||
|
||||
let image = tmpdir(build).join(format!("{}-{}-image", name, target));
|
||||
|
|
@ -604,7 +657,7 @@ impl Step for Std {
|
|||
t!(fs::create_dir_all(&dst));
|
||||
let mut src = builder.sysroot_libdir(compiler, target).to_path_buf();
|
||||
src.pop(); // Remove the trailing /lib folder from the sysroot_libdir
|
||||
cp_filtered(&src, &dst, &|path| {
|
||||
build.cp_filtered(&src, &dst, &|path| {
|
||||
let name = path.file_name().and_then(|s| s.to_str());
|
||||
name != Some(build.config.rust_codegen_backends_dir.as_str()) &&
|
||||
name != Some("bin")
|
||||
|
|
@ -623,7 +676,7 @@ impl Step for Std {
|
|||
.arg(format!("--component-name=rust-std-{}", target))
|
||||
.arg("--legacy-manifest-dirs=rustlib,cargo");
|
||||
build.run(&mut cmd);
|
||||
t!(fs::remove_dir_all(&image));
|
||||
build.remove_dir(&image);
|
||||
distdir(build).join(format!("{}-{}.tar.gz", name, target))
|
||||
}
|
||||
}
|
||||
|
|
@ -656,11 +709,11 @@ impl Step for Analysis {
|
|||
let compiler = self.compiler;
|
||||
let target = self.target;
|
||||
assert!(build.config.extended);
|
||||
println!("Dist analysis");
|
||||
build.info(&format!("Dist analysis"));
|
||||
let name = pkgname(build, "rust-analysis");
|
||||
|
||||
if &compiler.host != build.build {
|
||||
println!("\tskipping, not a build host");
|
||||
build.info(&format!("\tskipping, not a build host"));
|
||||
return distdir(build).join(format!("{}-{}.tar.gz", name, target));
|
||||
}
|
||||
|
||||
|
|
@ -682,8 +735,8 @@ impl Step for Analysis {
|
|||
let image_src = src.join("save-analysis");
|
||||
let dst = image.join("lib/rustlib").join(target).join("analysis");
|
||||
t!(fs::create_dir_all(&dst));
|
||||
println!("image_src: {:?}, dst: {:?}", image_src, dst);
|
||||
cp_r(&image_src, &dst);
|
||||
build.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst));
|
||||
build.cp_r(&image_src, &dst);
|
||||
|
||||
let mut cmd = rust_installer(builder);
|
||||
cmd.arg("generate")
|
||||
|
|
@ -697,7 +750,7 @@ impl Step for Analysis {
|
|||
.arg(format!("--component-name=rust-analysis-{}", target))
|
||||
.arg("--legacy-manifest-dirs=rustlib,cargo");
|
||||
build.run(&mut cmd);
|
||||
t!(fs::remove_dir_all(&image));
|
||||
build.remove_dir(&image);
|
||||
distdir(build).join(format!("{}-{}.tar.gz", name, target))
|
||||
}
|
||||
}
|
||||
|
|
@ -741,11 +794,11 @@ fn copy_src_dirs(build: &Build, src_dirs: &[&str], exclude_dirs: &[&str], dst_di
|
|||
for item in src_dirs {
|
||||
let dst = &dst_dir.join(item);
|
||||
t!(fs::create_dir_all(dst));
|
||||
cp_filtered(&build.src.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
|
||||
build.cp_filtered(&build.src.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Src;
|
||||
|
||||
impl Step for Src {
|
||||
|
|
@ -765,7 +818,7 @@ impl Step for Src {
|
|||
/// Creates the `rust-src` installer component
|
||||
fn run(self, builder: &Builder) -> PathBuf {
|
||||
let build = builder.build;
|
||||
println!("Dist src");
|
||||
build.info(&format!("Dist src"));
|
||||
|
||||
let name = pkgname(build, "rust-src");
|
||||
let image = tmpdir(build).join(format!("{}-image", name));
|
||||
|
|
@ -815,7 +868,7 @@ impl Step for Src {
|
|||
|
||||
copy_src_dirs(build, &std_src_dirs[..], &std_src_dirs_exclude[..], &dst_src);
|
||||
for file in src_files.iter() {
|
||||
copy(&build.src.join(file), &dst_src.join(file));
|
||||
build.copy(&build.src.join(file), &dst_src.join(file));
|
||||
}
|
||||
|
||||
// Create source tarball in rust-installer format
|
||||
|
|
@ -832,14 +885,14 @@ impl Step for Src {
|
|||
.arg("--legacy-manifest-dirs=rustlib,cargo");
|
||||
build.run(&mut cmd);
|
||||
|
||||
t!(fs::remove_dir_all(&image));
|
||||
build.remove_dir(&image);
|
||||
distdir(build).join(&format!("{}.tar.gz", name))
|
||||
}
|
||||
}
|
||||
|
||||
const CARGO_VENDOR_VERSION: &str = "0.1.4";
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct PlainSourceTarball;
|
||||
|
||||
impl Step for PlainSourceTarball {
|
||||
|
|
@ -860,7 +913,7 @@ impl Step for PlainSourceTarball {
|
|||
/// Creates the plain source tarball
|
||||
fn run(self, builder: &Builder) -> PathBuf {
|
||||
let build = builder.build;
|
||||
println!("Create plain source tarball");
|
||||
build.info(&format!("Create plain source tarball"));
|
||||
|
||||
// Make sure that the root folder of tarball has the correct name
|
||||
let plain_name = format!("{}-src", pkgname(build, "rustc"));
|
||||
|
|
@ -888,13 +941,13 @@ impl Step for PlainSourceTarball {
|
|||
|
||||
// Copy the files normally
|
||||
for item in &src_files {
|
||||
copy(&build.src.join(item), &plain_dst_src.join(item));
|
||||
build.copy(&build.src.join(item), &plain_dst_src.join(item));
|
||||
}
|
||||
|
||||
// Create the version file
|
||||
write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes());
|
||||
build.create(&plain_dst_src.join("version"), &build.rust_version());
|
||||
if let Some(sha) = build.rust_sha() {
|
||||
write_file(&plain_dst_src.join("git-commit-hash"), sha.as_bytes());
|
||||
build.create(&plain_dst_src.join("git-commit-hash"), &sha);
|
||||
}
|
||||
|
||||
// If we're building from git sources, we need to vendor a complete distribution.
|
||||
|
|
@ -935,9 +988,9 @@ impl Step for PlainSourceTarball {
|
|||
tarball.set_extension(""); // strip .gz
|
||||
tarball.set_extension(""); // strip .tar
|
||||
if let Some(dir) = tarball.parent() {
|
||||
t!(fs::create_dir_all(dir));
|
||||
build.create_dir(&dir);
|
||||
}
|
||||
println!("running installer");
|
||||
build.info(&format!("running installer"));
|
||||
let mut cmd = rust_installer(builder);
|
||||
cmd.arg("tarball")
|
||||
.arg("--input").arg(&plain_name)
|
||||
|
|
@ -949,26 +1002,6 @@ impl Step for PlainSourceTarball {
|
|||
}
|
||||
}
|
||||
|
||||
fn install(src: &Path, dstdir: &Path, perms: u32) {
|
||||
let dst = dstdir.join(src.file_name().unwrap());
|
||||
t!(fs::create_dir_all(dstdir));
|
||||
drop(fs::remove_file(&dst));
|
||||
{
|
||||
let mut s = t!(fs::File::open(&src));
|
||||
let mut d = t!(fs::File::create(&dst));
|
||||
io::copy(&mut s, &mut d).expect("failed to copy");
|
||||
}
|
||||
chmod(&dst, perms);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn chmod(path: &Path, perms: u32) {
|
||||
use std::os::unix::fs::*;
|
||||
t!(fs::set_permissions(path, fs::Permissions::from_mode(perms)));
|
||||
}
|
||||
#[cfg(windows)]
|
||||
fn chmod(_path: &Path, _perms: u32) {}
|
||||
|
||||
// We have to run a few shell scripts, which choke quite a bit on both `\`
|
||||
// characters and on `C:\` paths, so normalize both of them away.
|
||||
pub fn sanitize_sh(path: &Path) -> String {
|
||||
|
|
@ -988,12 +1021,7 @@ pub fn sanitize_sh(path: &Path) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn write_file(path: &Path, data: &[u8]) {
|
||||
let mut vf = t!(fs::File::create(path));
|
||||
t!(vf.write_all(data));
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Cargo {
|
||||
pub stage: u32,
|
||||
pub target: Interned<String>,
|
||||
|
|
@ -1019,7 +1047,7 @@ impl Step for Cargo {
|
|||
let stage = self.stage;
|
||||
let target = self.target;
|
||||
|
||||
println!("Dist cargo stage{} ({})", stage, target);
|
||||
build.info(&format!("Dist cargo stage{} ({})", stage, target));
|
||||
let src = build.src.join("src/tools/cargo");
|
||||
let etc = src.join("src/etc");
|
||||
let release_num = build.release_num("cargo");
|
||||
|
|
@ -1029,38 +1057,38 @@ impl Step for Cargo {
|
|||
let tmp = tmpdir(build);
|
||||
let image = tmp.join("cargo-image");
|
||||
drop(fs::remove_dir_all(&image));
|
||||
t!(fs::create_dir_all(&image));
|
||||
build.create_dir(&image);
|
||||
|
||||
// Prepare the image directory
|
||||
t!(fs::create_dir_all(image.join("share/zsh/site-functions")));
|
||||
t!(fs::create_dir_all(image.join("etc/bash_completion.d")));
|
||||
build.create_dir(&image.join("share/zsh/site-functions"));
|
||||
build.create_dir(&image.join("etc/bash_completion.d"));
|
||||
let cargo = builder.ensure(tool::Cargo {
|
||||
compiler: builder.compiler(stage, build.build),
|
||||
target
|
||||
});
|
||||
install(&cargo, &image.join("bin"), 0o755);
|
||||
build.install(&cargo, &image.join("bin"), 0o755);
|
||||
for man in t!(etc.join("man").read_dir()) {
|
||||
let man = t!(man);
|
||||
install(&man.path(), &image.join("share/man/man1"), 0o644);
|
||||
build.install(&man.path(), &image.join("share/man/man1"), 0o644);
|
||||
}
|
||||
install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
|
||||
copy(&etc.join("cargo.bashcomp.sh"),
|
||||
build.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
|
||||
build.copy(&etc.join("cargo.bashcomp.sh"),
|
||||
&image.join("etc/bash_completion.d/cargo"));
|
||||
let doc = image.join("share/doc/cargo");
|
||||
install(&src.join("README.md"), &doc, 0o644);
|
||||
install(&src.join("LICENSE-MIT"), &doc, 0o644);
|
||||
install(&src.join("LICENSE-APACHE"), &doc, 0o644);
|
||||
install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
|
||||
build.install(&src.join("README.md"), &doc, 0o644);
|
||||
build.install(&src.join("LICENSE-MIT"), &doc, 0o644);
|
||||
build.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
|
||||
build.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
|
||||
|
||||
// Prepare the overlay
|
||||
let overlay = tmp.join("cargo-overlay");
|
||||
drop(fs::remove_dir_all(&overlay));
|
||||
t!(fs::create_dir_all(&overlay));
|
||||
install(&src.join("README.md"), &overlay, 0o644);
|
||||
install(&src.join("LICENSE-MIT"), &overlay, 0o644);
|
||||
install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
|
||||
install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
|
||||
t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
|
||||
build.create_dir(&overlay);
|
||||
build.install(&src.join("README.md"), &overlay, 0o644);
|
||||
build.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
|
||||
build.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
|
||||
build.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
|
||||
build.create(&overlay.join("version"), &version);
|
||||
|
||||
// Generate the installer tarball
|
||||
let mut cmd = rust_installer(builder);
|
||||
|
|
@ -1080,7 +1108,7 @@ impl Step for Cargo {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Rls {
|
||||
pub stage: u32,
|
||||
pub target: Interned<String>,
|
||||
|
|
@ -1107,7 +1135,7 @@ impl Step for Rls {
|
|||
let target = self.target;
|
||||
assert!(build.config.extended);
|
||||
|
||||
println!("Dist RLS stage{} ({})", stage, target);
|
||||
build.info(&format!("Dist RLS stage{} ({})", stage, target));
|
||||
let src = build.src.join("src/tools/rls");
|
||||
let release_num = build.release_num("rls");
|
||||
let name = pkgname(build, "rls");
|
||||
|
|
@ -1126,20 +1154,20 @@ impl Step for Rls {
|
|||
target, extra_features: Vec::new()
|
||||
}).or_else(|| { println!("Unable to build RLS, skipping dist"); None })?;
|
||||
|
||||
install(&rls, &image.join("bin"), 0o755);
|
||||
build.install(&rls, &image.join("bin"), 0o755);
|
||||
let doc = image.join("share/doc/rls");
|
||||
install(&src.join("README.md"), &doc, 0o644);
|
||||
install(&src.join("LICENSE-MIT"), &doc, 0o644);
|
||||
install(&src.join("LICENSE-APACHE"), &doc, 0o644);
|
||||
build.install(&src.join("README.md"), &doc, 0o644);
|
||||
build.install(&src.join("LICENSE-MIT"), &doc, 0o644);
|
||||
build.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
|
||||
|
||||
// Prepare the overlay
|
||||
let overlay = tmp.join("rls-overlay");
|
||||
drop(fs::remove_dir_all(&overlay));
|
||||
t!(fs::create_dir_all(&overlay));
|
||||
install(&src.join("README.md"), &overlay, 0o644);
|
||||
install(&src.join("LICENSE-MIT"), &overlay, 0o644);
|
||||
install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
|
||||
t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
|
||||
build.install(&src.join("README.md"), &overlay, 0o644);
|
||||
build.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
|
||||
build.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
|
||||
build.create(&overlay.join("version"), &version);
|
||||
|
||||
// Generate the installer tarball
|
||||
let mut cmd = rust_installer(builder);
|
||||
|
|
@ -1161,7 +1189,7 @@ impl Step for Rls {
|
|||
}
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Rustfmt {
|
||||
pub stage: u32,
|
||||
pub target: Interned<String>,
|
||||
|
|
@ -1186,9 +1214,8 @@ impl Step for Rustfmt {
|
|||
let build = builder.build;
|
||||
let stage = self.stage;
|
||||
let target = self.target;
|
||||
assert!(build.config.extended);
|
||||
|
||||
println!("Dist Rustfmt stage{} ({})", stage, target);
|
||||
build.info(&format!("Dist Rustfmt stage{} ({})", stage, target));
|
||||
let src = build.src.join("src/tools/rustfmt");
|
||||
let release_num = build.release_num("rustfmt");
|
||||
let name = pkgname(build, "rustfmt");
|
||||
|
|
@ -1197,7 +1224,7 @@ impl Step for Rustfmt {
|
|||
let tmp = tmpdir(build);
|
||||
let image = tmp.join("rustfmt-image");
|
||||
drop(fs::remove_dir_all(&image));
|
||||
t!(fs::create_dir_all(&image));
|
||||
build.create_dir(&image);
|
||||
|
||||
// Prepare the image directory
|
||||
let rustfmt = builder.ensure(tool::Rustfmt {
|
||||
|
|
@ -1209,21 +1236,21 @@ impl Step for Rustfmt {
|
|||
target, extra_features: Vec::new()
|
||||
}).or_else(|| { println!("Unable to build Cargofmt, skipping dist"); None })?;
|
||||
|
||||
install(&rustfmt, &image.join("bin"), 0o755);
|
||||
install(&cargofmt, &image.join("bin"), 0o755);
|
||||
build.install(&rustfmt, &image.join("bin"), 0o755);
|
||||
build.install(&cargofmt, &image.join("bin"), 0o755);
|
||||
let doc = image.join("share/doc/rustfmt");
|
||||
install(&src.join("README.md"), &doc, 0o644);
|
||||
install(&src.join("LICENSE-MIT"), &doc, 0o644);
|
||||
install(&src.join("LICENSE-APACHE"), &doc, 0o644);
|
||||
build.install(&src.join("README.md"), &doc, 0o644);
|
||||
build.install(&src.join("LICENSE-MIT"), &doc, 0o644);
|
||||
build.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
|
||||
|
||||
// Prepare the overlay
|
||||
let overlay = tmp.join("rustfmt-overlay");
|
||||
drop(fs::remove_dir_all(&overlay));
|
||||
t!(fs::create_dir_all(&overlay));
|
||||
install(&src.join("README.md"), &overlay, 0o644);
|
||||
install(&src.join("LICENSE-MIT"), &overlay, 0o644);
|
||||
install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
|
||||
t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
|
||||
build.create_dir(&overlay);
|
||||
build.install(&src.join("README.md"), &overlay, 0o644);
|
||||
build.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
|
||||
build.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
|
||||
build.create(&overlay.join("version"), &version);
|
||||
|
||||
// Generate the installer tarball
|
||||
let mut cmd = rust_installer(builder);
|
||||
|
|
@ -1244,7 +1271,7 @@ impl Step for Rustfmt {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Extended {
|
||||
stage: u32,
|
||||
host: Interned<String>,
|
||||
|
|
@ -1275,7 +1302,7 @@ impl Step for Extended {
|
|||
let stage = self.stage;
|
||||
let target = self.target;
|
||||
|
||||
println!("Dist extended stage{} ({})", stage, target);
|
||||
build.info(&format!("Dist extended stage{} ({})", stage, target));
|
||||
|
||||
let rustc_installer = builder.ensure(Rustc {
|
||||
compiler: builder.compiler(stage, target),
|
||||
|
|
@ -1301,15 +1328,15 @@ impl Step for Extended {
|
|||
let work = tmp.join("work");
|
||||
|
||||
let _ = fs::remove_dir_all(&overlay);
|
||||
install(&build.src.join("COPYRIGHT"), &overlay, 0o644);
|
||||
install(&build.src.join("LICENSE-APACHE"), &overlay, 0o644);
|
||||
install(&build.src.join("LICENSE-MIT"), &overlay, 0o644);
|
||||
build.install(&build.src.join("COPYRIGHT"), &overlay, 0o644);
|
||||
build.install(&build.src.join("LICENSE-APACHE"), &overlay, 0o644);
|
||||
build.install(&build.src.join("LICENSE-MIT"), &overlay, 0o644);
|
||||
let version = build.rust_version();
|
||||
t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
|
||||
build.create(&overlay.join("version"), &version);
|
||||
if let Some(sha) = build.rust_sha() {
|
||||
t!(t!(File::create(overlay.join("git-commit-hash"))).write_all(sha.as_bytes()));
|
||||
build.create(&overlay.join("git-commit-hash"), &sha);
|
||||
}
|
||||
install(&etc.join("README.md"), &overlay, 0o644);
|
||||
build.install(&etc.join("README.md"), &overlay, 0o644);
|
||||
|
||||
// When rust-std package split from rustc, we needed to ensure that during
|
||||
// upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
|
||||
|
|
@ -1348,11 +1375,11 @@ impl Step for Extended {
|
|||
build.run(&mut cmd);
|
||||
|
||||
let mut license = String::new();
|
||||
t!(t!(File::open(build.src.join("COPYRIGHT"))).read_to_string(&mut license));
|
||||
license += &build.read(&build.src.join("COPYRIGHT"));
|
||||
license += &build.read(&build.src.join("LICENSE-APACHE"));
|
||||
license += &build.read(&build.src.join("LICENSE-MIT"));
|
||||
license.push_str("\n");
|
||||
t!(t!(File::open(build.src.join("LICENSE-APACHE"))).read_to_string(&mut license));
|
||||
license.push_str("\n");
|
||||
t!(t!(File::open(build.src.join("LICENSE-MIT"))).read_to_string(&mut license));
|
||||
|
||||
let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
|
||||
let mut rtf = rtf.to_string();
|
||||
|
|
@ -1409,10 +1436,10 @@ impl Step for Extended {
|
|||
};
|
||||
|
||||
let prepare = |name: &str| {
|
||||
t!(fs::create_dir_all(pkg.join(name)));
|
||||
cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target)),
|
||||
build.create_dir(&pkg.join(name));
|
||||
build.cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target)),
|
||||
&pkg.join(name));
|
||||
install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
|
||||
build.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
|
||||
pkgbuild(name);
|
||||
};
|
||||
prepare("rustc");
|
||||
|
|
@ -1426,12 +1453,12 @@ impl Step for Extended {
|
|||
}
|
||||
|
||||
// create an 'uninstall' package
|
||||
install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
|
||||
build.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
|
||||
pkgbuild("uninstall");
|
||||
|
||||
t!(fs::create_dir_all(pkg.join("res")));
|
||||
t!(t!(File::create(pkg.join("res/LICENSE.txt"))).write_all(license.as_bytes()));
|
||||
install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
|
||||
build.create_dir(&pkg.join("res"));
|
||||
build.create(&pkg.join("res/LICENSE.txt"), &license);
|
||||
build.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
|
||||
let mut cmd = Command::new("productbuild");
|
||||
cmd.arg("--distribution").arg(xform(&etc.join("pkg/Distribution.xml")))
|
||||
.arg("--resources").arg(pkg.join("res"))
|
||||
|
|
@ -1447,7 +1474,7 @@ impl Step for Extended {
|
|||
let _ = fs::remove_dir_all(&exe);
|
||||
|
||||
let prepare = |name: &str| {
|
||||
t!(fs::create_dir_all(exe.join(name)));
|
||||
build.create_dir(&exe.join(name));
|
||||
let dir = if name == "rust-std" || name == "rust-analysis" {
|
||||
format!("{}-{}", name, target)
|
||||
} else if name == "rls" {
|
||||
|
|
@ -1455,10 +1482,10 @@ impl Step for Extended {
|
|||
} else {
|
||||
name.to_string()
|
||||
};
|
||||
cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target))
|
||||
build.cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target))
|
||||
.join(dir),
|
||||
&exe.join(name));
|
||||
t!(fs::remove_file(exe.join(name).join("manifest.in")));
|
||||
build.remove(&exe.join(name).join("manifest.in"));
|
||||
};
|
||||
prepare("rustc");
|
||||
prepare("cargo");
|
||||
|
|
@ -1472,11 +1499,11 @@ impl Step for Extended {
|
|||
prepare("rust-mingw");
|
||||
}
|
||||
|
||||
install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644);
|
||||
install(&etc.join("exe/modpath.iss"), &exe, 0o644);
|
||||
install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
|
||||
install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
|
||||
t!(t!(File::create(exe.join("LICENSE.txt"))).write_all(license.as_bytes()));
|
||||
build.install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644);
|
||||
build.install(&etc.join("exe/modpath.iss"), &exe, 0o644);
|
||||
build.install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
|
||||
build.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
|
||||
build.create(&exe.join("LICENSE.txt"), &license);
|
||||
|
||||
// Generate exe installer
|
||||
let mut cmd = Command::new("iscc");
|
||||
|
|
@ -1487,7 +1514,7 @@ impl Step for Extended {
|
|||
}
|
||||
add_env(build, &mut cmd, target);
|
||||
build.run(&mut cmd);
|
||||
install(&exe.join(format!("{}-{}.exe", pkgname(build, "rust"), target)),
|
||||
build.install(&exe.join(format!("{}-{}.exe", pkgname(build, "rust"), target)),
|
||||
&distdir(build),
|
||||
0o755);
|
||||
|
||||
|
|
@ -1611,9 +1638,9 @@ impl Step for Extended {
|
|||
candle("GccGroup.wxs".as_ref());
|
||||
}
|
||||
|
||||
t!(t!(File::create(exe.join("LICENSE.rtf"))).write_all(rtf.as_bytes()));
|
||||
install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
|
||||
install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
|
||||
build.create(&exe.join("LICENSE.rtf"), &rtf);
|
||||
build.install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
|
||||
build.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
|
||||
|
||||
let filename = format!("{}-{}.msi", pkgname(build, "rust"), target);
|
||||
let mut cmd = Command::new(&light);
|
||||
|
|
@ -1643,7 +1670,9 @@ impl Step for Extended {
|
|||
|
||||
build.run(&mut cmd);
|
||||
|
||||
t!(fs::rename(exe.join(&filename), distdir(build).join(&filename)));
|
||||
if !build.config.dry_run {
|
||||
t!(fs::rename(exe.join(&filename), distdir(build).join(&filename)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1677,7 +1706,7 @@ fn add_env(build: &Build, cmd: &mut Command, target: Interned<String>) {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct HashSign;
|
||||
|
||||
impl Step for HashSign {
|
||||
|
|
@ -1695,6 +1724,9 @@ impl Step for HashSign {
|
|||
fn run(self, builder: &Builder) {
|
||||
let build = builder.build;
|
||||
let mut cmd = builder.tool_cmd(Tool::BuildManifest);
|
||||
if build.config.dry_run {
|
||||
return;
|
||||
}
|
||||
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")
|
||||
});
|
||||
|
|
@ -1718,7 +1750,7 @@ impl Step for HashSign {
|
|||
cmd.arg(build.package_vers(&build.release_num("rustfmt")));
|
||||
cmd.arg(addr);
|
||||
|
||||
t!(fs::create_dir_all(distdir(build)));
|
||||
build.create_dir(&distdir(build));
|
||||
|
||||
let mut child = t!(cmd.stdin(Stdio::piped()).spawn());
|
||||
t!(child.stdin.take().unwrap().write_all(pass.as_bytes()));
|
||||
|
|
|
|||
|
|
@ -17,19 +17,21 @@
|
|||
//! Everything here is basically just a shim around calling either `rustbook` or
|
||||
//! `rustdoc`.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::fs::{self, File};
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::path::{PathBuf, Path};
|
||||
|
||||
use Mode;
|
||||
use {Build, Mode};
|
||||
use build_helper::up_to_date;
|
||||
|
||||
use util::{cp_r, symlink_dir};
|
||||
use util::symlink_dir;
|
||||
use builder::{Builder, Compiler, RunConfig, ShouldRun, Step};
|
||||
use tool::Tool;
|
||||
use compile;
|
||||
use cache::{INTERNER, Interned};
|
||||
use config::Config;
|
||||
|
||||
macro_rules! book {
|
||||
($($name:ident, $path:expr, $book_name:expr;)+) => {
|
||||
|
|
@ -167,7 +169,7 @@ impl Step for CargoBook {
|
|||
|
||||
let out = out.join(name);
|
||||
|
||||
println!("Cargo Book ({}) - {}", target, name);
|
||||
build.info(&format!("Cargo Book ({}) - {}", target, name));
|
||||
|
||||
let _ = fs::remove_dir_all(&out);
|
||||
|
||||
|
|
@ -209,12 +211,13 @@ impl Step for RustbookSrc {
|
|||
let src = src.join(name);
|
||||
let index = out.join("index.html");
|
||||
let rustbook = builder.tool_exe(Tool::Rustbook);
|
||||
let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
|
||||
if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
|
||||
return
|
||||
}
|
||||
println!("Rustbook ({}) - {}", target, name);
|
||||
build.info(&format!("Rustbook ({}) - {}", target, name));
|
||||
let _ = fs::remove_dir_all(&out);
|
||||
build.run(builder.tool_cmd(Tool::Rustbook)
|
||||
build.run(rustbook_cmd
|
||||
.arg("build")
|
||||
.arg(&src)
|
||||
.arg("-d")
|
||||
|
|
@ -280,11 +283,11 @@ impl Step for TheBook {
|
|||
|
||||
// build the index page
|
||||
let index = format!("{}/index.md", name);
|
||||
println!("Documenting book index ({})", target);
|
||||
build.info(&format!("Documenting book index ({})", target));
|
||||
invoke_rustdoc(builder, compiler, target, &index);
|
||||
|
||||
// build the redirect pages
|
||||
println!("Documenting book redirect pages ({})", target);
|
||||
build.info(&format!("Documenting book redirect pages ({})", target));
|
||||
for file in t!(fs::read_dir(build.src.join("src/doc/book/redirects"))) {
|
||||
let file = t!(file);
|
||||
let path = file.path();
|
||||
|
|
@ -357,7 +360,7 @@ impl Step for Standalone {
|
|||
let build = builder.build;
|
||||
let target = self.target;
|
||||
let compiler = self.compiler;
|
||||
println!("Documenting standalone ({})", target);
|
||||
build.info(&format!("Documenting standalone ({})", target));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
|
||||
|
|
@ -369,7 +372,7 @@ impl Step for Standalone {
|
|||
let version_input = build.src.join("src/doc/version_info.html.template");
|
||||
let version_info = out.join("version_info.html");
|
||||
|
||||
if !up_to_date(&version_input, &version_info) {
|
||||
if !build.config.dry_run && !up_to_date(&version_input, &version_info) {
|
||||
let mut info = String::new();
|
||||
t!(t!(File::open(&version_input)).read_to_string(&mut info));
|
||||
let info = info.replace("VERSION", &build.rust_release())
|
||||
|
|
@ -393,7 +396,7 @@ impl Step for Standalone {
|
|||
up_to_date(&favicon, &html) &&
|
||||
up_to_date(&full_toc, &html) &&
|
||||
up_to_date(&version_info, &html) &&
|
||||
up_to_date(&rustdoc, &html) {
|
||||
(build.config.dry_run || up_to_date(&rustdoc, &html)) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -448,7 +451,7 @@ impl Step for Std {
|
|||
let build = builder.build;
|
||||
let stage = self.stage;
|
||||
let target = self.target;
|
||||
println!("Documenting stage{} std ({})", stage, target);
|
||||
build.info(&format!("Documenting stage{} std ({})", stage, target));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
let compiler = builder.compiler(stage, build.build);
|
||||
|
|
@ -478,28 +481,24 @@ impl Step for Std {
|
|||
// will also directly handle merging.
|
||||
let my_out = build.crate_doc_out(target);
|
||||
build.clear_if_dirty(&my_out, &rustdoc);
|
||||
t!(symlink_dir_force(&my_out, &out_dir));
|
||||
t!(symlink_dir_force(&build.config, &my_out, &out_dir));
|
||||
|
||||
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "doc");
|
||||
compile::std_cargo(builder, &compiler, target, &mut cargo);
|
||||
|
||||
// We don't want to build docs for internal std dependencies unless
|
||||
// in compiler-docs mode. When not in that mode, we whitelist the crates
|
||||
// for which docs must be built.
|
||||
if !build.config.compiler_docs {
|
||||
cargo.arg("--no-deps");
|
||||
for krate in &["alloc", "core", "std", "std_unicode"] {
|
||||
cargo.arg("-p").arg(krate);
|
||||
// Create all crate output directories first to make sure rustdoc uses
|
||||
// relative links.
|
||||
// FIXME: Cargo should probably do this itself.
|
||||
t!(fs::create_dir_all(out_dir.join(krate)));
|
||||
}
|
||||
// Keep a whitelist so we do not build internal stdlib crates, these will be
|
||||
// build by the rustc step later if enabled.
|
||||
cargo.arg("--no-deps");
|
||||
for krate in &["alloc", "core", "std", "std_unicode"] {
|
||||
cargo.arg("-p").arg(krate);
|
||||
// Create all crate output directories first to make sure rustdoc uses
|
||||
// relative links.
|
||||
// FIXME: Cargo should probably do this itself.
|
||||
t!(fs::create_dir_all(out_dir.join(krate)));
|
||||
}
|
||||
|
||||
|
||||
build.run(&mut cargo);
|
||||
cp_r(&my_out, &out);
|
||||
build.cp_r(&my_out, &out);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -533,7 +532,7 @@ impl Step for Test {
|
|||
let build = builder.build;
|
||||
let stage = self.stage;
|
||||
let target = self.target;
|
||||
println!("Documenting stage{} test ({})", stage, target);
|
||||
build.info(&format!("Documenting stage{} test ({})", stage, target));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
let compiler = builder.compiler(stage, build.build);
|
||||
|
|
@ -554,12 +553,87 @@ impl Step for Test {
|
|||
// See docs in std above for why we symlink
|
||||
let my_out = build.crate_doc_out(target);
|
||||
build.clear_if_dirty(&my_out, &rustdoc);
|
||||
t!(symlink_dir_force(&my_out, &out_dir));
|
||||
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
|
||||
|
||||
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "doc");
|
||||
compile::test_cargo(build, &compiler, target, &mut cargo);
|
||||
build.run(&mut cargo);
|
||||
cp_r(&my_out, &out);
|
||||
build.cp_r(&my_out, &out);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct WhitelistedRustc {
|
||||
stage: u32,
|
||||
target: Interned<String>,
|
||||
}
|
||||
|
||||
impl Step for WhitelistedRustc {
|
||||
type Output = ();
|
||||
const DEFAULT: bool = true;
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun) -> ShouldRun {
|
||||
let builder = run.builder;
|
||||
run.krate("rustc-main").default_condition(builder.build.config.docs)
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig) {
|
||||
run.builder.ensure(WhitelistedRustc {
|
||||
stage: run.builder.top_stage,
|
||||
target: run.target,
|
||||
});
|
||||
}
|
||||
|
||||
/// Generate whitelisted compiler crate documentation.
|
||||
///
|
||||
/// This will generate all documentation for crates that are whitelisted
|
||||
/// to be included in the standard documentation. This documentation is
|
||||
/// included in the standard Rust documentation, so we should always
|
||||
/// document it and symlink to merge with the rest of the std and test
|
||||
/// documentation. We don't build other compiler documentation
|
||||
/// here as we want to be able to keep it separate from the standard
|
||||
/// documentation. This is largely just a wrapper around `cargo doc`.
|
||||
fn run(self, builder: &Builder) {
|
||||
let build = builder.build;
|
||||
let stage = self.stage;
|
||||
let target = self.target;
|
||||
build.info(&format!("Documenting stage{} whitelisted compiler ({})", stage, target));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
let compiler = builder.compiler(stage, build.build);
|
||||
let rustdoc = builder.rustdoc(compiler.host);
|
||||
let compiler = if build.force_use_stage1(compiler, target) {
|
||||
builder.compiler(1, compiler.host)
|
||||
} else {
|
||||
compiler
|
||||
};
|
||||
|
||||
// Build libstd docs so that we generate relative links
|
||||
builder.ensure(Std { stage, target });
|
||||
|
||||
builder.ensure(compile::Rustc { compiler, target });
|
||||
let out_dir = build.stage_out(compiler, Mode::Librustc)
|
||||
.join(target).join("doc");
|
||||
|
||||
// See docs in std above for why we symlink
|
||||
let my_out = build.crate_doc_out(target);
|
||||
build.clear_if_dirty(&my_out, &rustdoc);
|
||||
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
|
||||
|
||||
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
|
||||
compile::rustc_cargo(build, &mut cargo);
|
||||
|
||||
// We don't want to build docs for internal compiler dependencies in this
|
||||
// step (there is another step for that). Therefore, we whitelist the crates
|
||||
// for which docs must be built.
|
||||
cargo.arg("--no-deps");
|
||||
for krate in &["proc_macro"] {
|
||||
cargo.arg("-p").arg(krate);
|
||||
}
|
||||
|
||||
build.run(&mut cargo);
|
||||
build.cp_r(&my_out, &out);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -586,16 +660,18 @@ impl Step for Rustc {
|
|||
});
|
||||
}
|
||||
|
||||
/// Generate all compiler documentation.
|
||||
/// Generate compiler documentation.
|
||||
///
|
||||
/// This will generate all documentation for the compiler libraries and their
|
||||
/// dependencies. This is largely just a wrapper around `cargo doc`.
|
||||
/// This will generate all documentation for compiler and dependencies.
|
||||
/// Compiler documentation is distributed separately, so we make sure
|
||||
/// we do not merge it with the other documentation from std, test and
|
||||
/// proc_macros. This is largely just a wrapper around `cargo doc`.
|
||||
fn run(self, builder: &Builder) {
|
||||
let build = builder.build;
|
||||
let stage = self.stage;
|
||||
let target = self.target;
|
||||
println!("Documenting stage{} compiler ({})", stage, target);
|
||||
let out = build.doc_out(target);
|
||||
build.info(&format!("Documenting stage{} compiler ({})", stage, target));
|
||||
let out = build.compiler_doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
let compiler = builder.compiler(stage, build.build);
|
||||
let rustdoc = builder.rustdoc(compiler.host);
|
||||
|
|
@ -605,36 +681,57 @@ impl Step for Rustc {
|
|||
compiler
|
||||
};
|
||||
|
||||
if !build.config.compiler_docs {
|
||||
build.info(&format!("\tskipping - compiler docs disabled"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Build libstd docs so that we generate relative links
|
||||
builder.ensure(Std { stage, target });
|
||||
|
||||
builder.ensure(compile::Rustc { compiler, target });
|
||||
let out_dir = build.stage_out(compiler, Mode::Librustc)
|
||||
.join(target).join("doc");
|
||||
|
||||
// See docs in std above for why we symlink
|
||||
let my_out = build.crate_doc_out(target);
|
||||
build.clear_if_dirty(&my_out, &rustdoc);
|
||||
t!(symlink_dir_force(&my_out, &out_dir));
|
||||
// We do not symlink to the same shared folder that already contains std library
|
||||
// documentation from previous steps as we do not want to include that.
|
||||
build.clear_if_dirty(&out, &rustdoc);
|
||||
t!(symlink_dir_force(&builder.config, &out, &out_dir));
|
||||
|
||||
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
|
||||
cargo.env("RUSTDOCFLAGS", "--document-private-items");
|
||||
compile::rustc_cargo(build, &mut cargo);
|
||||
|
||||
if build.config.compiler_docs {
|
||||
// src/rustc/Cargo.toml contains a bin crate called rustc which
|
||||
// would otherwise overwrite the docs for the real rustc lib crate.
|
||||
cargo.arg("-p").arg("rustc_driver");
|
||||
} else {
|
||||
// Like with libstd above if compiler docs aren't enabled then we're not
|
||||
// documenting internal dependencies, so we have a whitelist.
|
||||
cargo.arg("--no-deps");
|
||||
for krate in &["proc_macro"] {
|
||||
cargo.arg("-p").arg(krate);
|
||||
}
|
||||
// Only include compiler crates, no dependencies of those, such as `libc`.
|
||||
cargo.arg("--no-deps");
|
||||
|
||||
// Find dependencies for top level crates.
|
||||
let mut compiler_crates = HashSet::new();
|
||||
for root_crate in &["rustc", "rustc_driver"] {
|
||||
let interned_root_crate = INTERNER.intern_str(root_crate);
|
||||
find_compiler_crates(&build, &interned_root_crate, &mut compiler_crates);
|
||||
}
|
||||
|
||||
for krate in &compiler_crates {
|
||||
cargo.arg("-p").arg(krate);
|
||||
}
|
||||
|
||||
build.run(&mut cargo);
|
||||
cp_r(&my_out, &out);
|
||||
}
|
||||
}
|
||||
|
||||
fn find_compiler_crates(
|
||||
build: &Build,
|
||||
name: &Interned<String>,
|
||||
crates: &mut HashSet<Interned<String>>
|
||||
) {
|
||||
// Add current crate.
|
||||
crates.insert(*name);
|
||||
|
||||
// Look for dependencies.
|
||||
for dep in build.crates.get(name).unwrap().deps.iter() {
|
||||
if build.crates.get(dep).unwrap().is_local(build) {
|
||||
find_compiler_crates(build, dep, crates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -665,7 +762,7 @@ impl Step for ErrorIndex {
|
|||
let build = builder.build;
|
||||
let target = self.target;
|
||||
|
||||
println!("Documenting error index ({})", target);
|
||||
build.info(&format!("Documenting error index ({})", target));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
let mut index = builder.tool_cmd(Tool::ErrorIndex);
|
||||
|
|
@ -710,10 +807,10 @@ impl Step for UnstableBookGen {
|
|||
target,
|
||||
});
|
||||
|
||||
println!("Generating unstable book md files ({})", target);
|
||||
build.info(&format!("Generating unstable book md files ({})", target));
|
||||
let out = build.md_doc_out(target).join("unstable-book");
|
||||
t!(fs::create_dir_all(&out));
|
||||
t!(fs::remove_dir_all(&out));
|
||||
build.create_dir(&out);
|
||||
build.remove_dir(&out);
|
||||
let mut cmd = builder.tool_cmd(Tool::UnstableBookGen);
|
||||
cmd.arg(build.src.join("src"));
|
||||
cmd.arg(out);
|
||||
|
|
@ -722,7 +819,10 @@ impl Step for UnstableBookGen {
|
|||
}
|
||||
}
|
||||
|
||||
fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> {
|
||||
fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()> {
|
||||
if config.dry_run {
|
||||
return Ok(());
|
||||
}
|
||||
if let Ok(m) = fs::symlink_metadata(dst) {
|
||||
if m.file_type().is_dir() {
|
||||
try!(fs::remove_dir_all(dst));
|
||||
|
|
@ -735,5 +835,5 @@ fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
symlink_dir(src, dst)
|
||||
symlink_dir(config, src, dst)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
//! 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;
|
||||
|
|
@ -33,17 +32,16 @@ pub struct Flags {
|
|||
pub on_fail: Option<String>,
|
||||
pub stage: Option<u32>,
|
||||
pub keep_stage: Option<u32>,
|
||||
pub build: Option<Interned<String>>,
|
||||
|
||||
pub host: Vec<Interned<String>>,
|
||||
pub target: Vec<Interned<String>>,
|
||||
pub config: Option<PathBuf>,
|
||||
pub src: PathBuf,
|
||||
pub jobs: Option<u32>,
|
||||
pub cmd: Subcommand,
|
||||
pub incremental: bool,
|
||||
pub exclude: Vec<PathBuf>,
|
||||
pub rustc_error_format: Option<String>,
|
||||
pub dry_run: bool,
|
||||
}
|
||||
|
||||
pub enum Subcommand {
|
||||
|
|
@ -114,6 +112,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
|
|||
opts.optmulti("", "target", "target targets to build", "TARGET");
|
||||
opts.optmulti("", "exclude", "build paths to exclude", "PATH");
|
||||
opts.optopt("", "on-fail", "command to run on failure", "CMD");
|
||||
opts.optflag("", "dry-run", "dry run; don't build anything");
|
||||
opts.optopt("", "stage", "stage to build", "N");
|
||||
opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
|
||||
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
|
||||
|
|
@ -278,10 +277,6 @@ Arguments:
|
|||
_ => { }
|
||||
};
|
||||
// Get any optional paths which occur after the subcommand
|
||||
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.clone());
|
||||
let paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
|
||||
|
||||
let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| {
|
||||
|
|
@ -371,10 +366,10 @@ Arguments:
|
|||
Flags {
|
||||
verbose: matches.opt_count("verbose"),
|
||||
stage,
|
||||
dry_run: matches.opt_present("dry-run"),
|
||||
on_fail: matches.opt_str("on-fail"),
|
||||
rustc_error_format: matches.opt_str("error-format"),
|
||||
keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()),
|
||||
build: matches.opt_str("build").map(|s| INTERNER.intern_string(s)),
|
||||
host: split(matches.opt_strs("host"))
|
||||
.into_iter().map(|x| INTERNER.intern_string(x)).collect::<Vec<_>>(),
|
||||
target: split(matches.opt_strs("target"))
|
||||
|
|
@ -385,7 +380,6 @@ Arguments:
|
|||
incremental: matches.opt_present("incremental"),
|
||||
exclude: split(matches.opt_strs("exclude"))
|
||||
.into_iter().map(|p| p.into()).collect::<Vec<_>>(),
|
||||
src,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ fn install_sh(
|
|||
host: Option<Interned<String>>
|
||||
) {
|
||||
let build = builder.build;
|
||||
println!("Install {} stage{} ({:?})", package, stage, host);
|
||||
build.info(&format!("Install {} stage{} ({:?})", package, stage, host));
|
||||
|
||||
let prefix_default = PathBuf::from("/usr/local");
|
||||
let sysconfdir_default = PathBuf::from("/etc");
|
||||
|
|
@ -212,7 +212,7 @@ install!((self, builder, _config),
|
|||
Self::should_install(builder) {
|
||||
install_rls(builder, self.stage, self.target);
|
||||
} else {
|
||||
println!("skipping Install RLS stage{} ({})", self.stage, self.target);
|
||||
builder.info(&format!("skipping Install RLS stage{} ({})", self.stage, self.target));
|
||||
}
|
||||
};
|
||||
Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, {
|
||||
|
|
@ -220,7 +220,8 @@ install!((self, builder, _config),
|
|||
Self::should_install(builder) {
|
||||
install_rustfmt(builder, self.stage, self.target);
|
||||
} else {
|
||||
println!("skipping Install Rustfmt stage{} ({})", self.stage, self.target);
|
||||
builder.info(
|
||||
&format!("skipping Install Rustfmt stage{} ({})", self.stage, self.target));
|
||||
}
|
||||
};
|
||||
Analysis, "analysis", Self::should_build(_config), only_hosts: false, {
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@
|
|||
//! also check out the `src/bootstrap/README.md` file for more information.
|
||||
|
||||
#![deny(warnings)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(conservative_impl_trait, fs_read_write, core_intrinsics)]
|
||||
#![feature(slice_concat_ext)]
|
||||
|
||||
#[macro_use]
|
||||
|
|
@ -131,6 +131,11 @@ extern crate getopts;
|
|||
extern crate num_cpus;
|
||||
extern crate toml;
|
||||
extern crate time;
|
||||
extern crate petgraph;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate pretty_assertions;
|
||||
|
||||
#[cfg(unix)]
|
||||
extern crate libc;
|
||||
|
|
@ -138,13 +143,15 @@ extern crate libc;
|
|||
use std::cell::{RefCell, Cell};
|
||||
use std::collections::{HashSet, HashMap};
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Read;
|
||||
use std::fs::{self, OpenOptions, File};
|
||||
use std::io::{self, Seek, SeekFrom, Write, Read};
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::process::{self, Command};
|
||||
use std::slice;
|
||||
use std::str;
|
||||
|
||||
use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime};
|
||||
use filetime::FileTime;
|
||||
|
||||
use util::{exe, libdir, OutputFolder, CiEnv};
|
||||
|
||||
|
|
@ -198,7 +205,7 @@ use toolstate::ToolState;
|
|||
/// Each compiler has a `stage` that it is associated with and a `host` that
|
||||
/// corresponds to the platform the compiler runs on. This structure is used as
|
||||
/// a parameter to many methods below.
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
|
||||
#[derive(Eq, PartialOrd, Ord, PartialEq, Clone, Copy, Hash, Debug)]
|
||||
pub struct Compiler {
|
||||
stage: u32,
|
||||
host: Interned<String>,
|
||||
|
|
@ -254,6 +261,10 @@ pub struct Build {
|
|||
ci_env: CiEnv,
|
||||
delayed_failures: RefCell<Vec<String>>,
|
||||
prerelease_version: Cell<Option<u32>>,
|
||||
tool_artifacts: RefCell<HashMap<
|
||||
Interned<String>,
|
||||
HashMap<String, (&'static str, PathBuf, Vec<String>)>
|
||||
>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -305,9 +316,8 @@ impl Build {
|
|||
///
|
||||
/// By default all build output will be placed in the current directory.
|
||||
pub fn new(config: Config) -> Build {
|
||||
let cwd = t!(env::current_dir());
|
||||
let src = config.src.clone();
|
||||
let out = cwd.join("build");
|
||||
let out = config.out.clone();
|
||||
|
||||
let is_sudo = match env::var_os("SUDO_USER") {
|
||||
Some(sudo_user) => {
|
||||
|
|
@ -323,7 +333,7 @@ impl Build {
|
|||
let rls_info = channel::GitInfo::new(&config, &src.join("src/tools/rls"));
|
||||
let rustfmt_info = channel::GitInfo::new(&config, &src.join("src/tools/rustfmt"));
|
||||
|
||||
Build {
|
||||
let mut build = Build {
|
||||
initial_rustc: config.initial_rustc.clone(),
|
||||
initial_cargo: config.initial_cargo.clone(),
|
||||
local_rebuild: config.local_rebuild,
|
||||
|
|
@ -353,7 +363,31 @@ impl Build {
|
|||
ci_env: CiEnv::current(),
|
||||
delayed_failures: RefCell::new(Vec::new()),
|
||||
prerelease_version: Cell::new(None),
|
||||
tool_artifacts: Default::default(),
|
||||
};
|
||||
|
||||
build.verbose("finding compilers");
|
||||
cc_detect::find(&mut build);
|
||||
build.verbose("running sanity check");
|
||||
sanity::check(&mut build);
|
||||
|
||||
// If local-rust is the same major.minor as the current version, then force a
|
||||
// local-rebuild
|
||||
let local_version_verbose = output(
|
||||
Command::new(&build.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();
|
||||
let my_version = channel::CFG_RELEASE_NUM;
|
||||
if local_release.split('.').take(2).eq(my_version.split('.').take(2)) {
|
||||
build.verbose(&format!("auto-detected local-rebuild {}", local_release));
|
||||
build.local_rebuild = true;
|
||||
}
|
||||
|
||||
build.verbose("learning about cargo");
|
||||
metadata::build(&mut build);
|
||||
|
||||
build
|
||||
}
|
||||
|
||||
pub fn build_triple(&self) -> &[Interned<String>] {
|
||||
|
|
@ -372,25 +406,28 @@ impl Build {
|
|||
return clean::clean(self, all);
|
||||
}
|
||||
|
||||
self.verbose("finding compilers");
|
||||
cc_detect::find(self);
|
||||
self.verbose("running sanity check");
|
||||
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.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();
|
||||
let my_version = channel::CFG_RELEASE_NUM;
|
||||
if local_release.split('.').take(2).eq(my_version.split('.').take(2)) {
|
||||
self.verbose(&format!("auto-detected local-rebuild {}", local_release));
|
||||
self.local_rebuild = true;
|
||||
{
|
||||
let builder = builder::Builder::new(&self);
|
||||
if let Some(path) = builder.paths.get(0) {
|
||||
if path == Path::new("nonexistent/path/to/trigger/cargo/metadata") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.verbose("learning about cargo");
|
||||
metadata::build(self);
|
||||
|
||||
builder::Builder::run(&self);
|
||||
if !self.config.dry_run {
|
||||
{
|
||||
self.config.dry_run = true;
|
||||
let builder = builder::Builder::new(&self);
|
||||
builder.execute_cli();
|
||||
}
|
||||
self.config.dry_run = false;
|
||||
let builder = builder::Builder::new(&self);
|
||||
builder.execute_cli();
|
||||
} else {
|
||||
let builder = builder::Builder::new(&self);
|
||||
let _ = builder.execute_cli();
|
||||
}
|
||||
|
||||
// Check for postponed failures from `test --no-fail-fast`.
|
||||
let failures = self.delayed_failures.borrow();
|
||||
|
|
@ -511,6 +548,11 @@ impl Build {
|
|||
self.out.join(&*target).join("doc")
|
||||
}
|
||||
|
||||
/// Output directory for all documentation for a target
|
||||
fn compiler_doc_out(&self, target: Interned<String>) -> PathBuf {
|
||||
self.out.join(&*target).join("compiler-doc")
|
||||
}
|
||||
|
||||
/// Output directory for some generated md crate documentation for a target (temporary)
|
||||
fn md_doc_out(&self, target: Interned<String>) -> Interned<PathBuf> {
|
||||
INTERNER.intern_path(self.out.join(&*target).join("md-doc"))
|
||||
|
|
@ -576,12 +618,14 @@ impl Build {
|
|||
|
||||
/// Runs a command, printing out nice contextual information if it fails.
|
||||
fn run(&self, cmd: &mut Command) {
|
||||
if self.config.dry_run { return; }
|
||||
self.verbose(&format!("running: {:?}", cmd));
|
||||
run_silent(cmd)
|
||||
}
|
||||
|
||||
/// Runs a command, printing out nice contextual information if it fails.
|
||||
fn run_quiet(&self, cmd: &mut Command) {
|
||||
if self.config.dry_run { return; }
|
||||
self.verbose(&format!("running: {:?}", cmd));
|
||||
run_suppressed(cmd)
|
||||
}
|
||||
|
|
@ -590,6 +634,7 @@ impl Build {
|
|||
/// Exits if the command failed to execute at all, otherwise returns its
|
||||
/// `status.success()`.
|
||||
fn try_run(&self, cmd: &mut Command) -> bool {
|
||||
if self.config.dry_run { return true; }
|
||||
self.verbose(&format!("running: {:?}", cmd));
|
||||
try_run_silent(cmd)
|
||||
}
|
||||
|
|
@ -598,6 +643,7 @@ impl Build {
|
|||
/// Exits if the command failed to execute at all, otherwise returns its
|
||||
/// `status.success()`.
|
||||
fn try_run_quiet(&self, cmd: &mut Command) -> bool {
|
||||
if self.config.dry_run { return true; }
|
||||
self.verbose(&format!("running: {:?}", cmd));
|
||||
try_run_suppressed(cmd)
|
||||
}
|
||||
|
|
@ -613,6 +659,11 @@ impl Build {
|
|||
}
|
||||
}
|
||||
|
||||
fn info(&self, msg: &str) {
|
||||
if self.config.dry_run { return; }
|
||||
println!("{}", msg);
|
||||
}
|
||||
|
||||
/// Returns the number of parallel jobs that have been configured for this
|
||||
/// build.
|
||||
fn jobs(&self) -> u32 {
|
||||
|
|
@ -699,6 +750,12 @@ impl Build {
|
|||
.map(|p| &**p)
|
||||
}
|
||||
|
||||
/// Returns true if this is a no-std `target`, if defined
|
||||
fn no_std(&self, target: Interned<String>) -> Option<bool> {
|
||||
self.config.target_config.get(&target)
|
||||
.map(|t| t.no_std)
|
||||
}
|
||||
|
||||
/// Returns whether the target will be tested using the `remote-test-client`
|
||||
/// and `remote-test-server` binaries.
|
||||
fn remote_tested(&self, target: Interned<String>) -> bool {
|
||||
|
|
@ -920,7 +977,7 @@ impl Build {
|
|||
pub fn fold_output<D, F>(&self, name: F) -> Option<OutputFolder>
|
||||
where D: Into<String>, F: FnOnce() -> D
|
||||
{
|
||||
if self.ci_env == CiEnv::Travis {
|
||||
if !self.config.dry_run && self.ci_env == CiEnv::Travis {
|
||||
Some(OutputFolder::new(name().into()))
|
||||
} else {
|
||||
None
|
||||
|
|
@ -968,8 +1025,173 @@ impl Build {
|
|||
}
|
||||
ret
|
||||
}
|
||||
|
||||
fn read_stamp_file(&self, stamp: &Path) -> Vec<PathBuf> {
|
||||
if self.config.dry_run {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let mut paths = Vec::new();
|
||||
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 compile.rs).
|
||||
for part in contents.split(|b| *b == 0) {
|
||||
if part.is_empty() {
|
||||
continue
|
||||
}
|
||||
let path = PathBuf::from(t!(str::from_utf8(part)));
|
||||
paths.push(path);
|
||||
}
|
||||
paths
|
||||
}
|
||||
|
||||
/// Copies a file from `src` to `dst`
|
||||
pub fn copy(&self, src: &Path, dst: &Path) {
|
||||
if self.config.dry_run { return; }
|
||||
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.
|
||||
if let Ok(()) = fs::hard_link(src, dst) {
|
||||
return
|
||||
}
|
||||
if let Err(e) = fs::copy(src, dst) {
|
||||
panic!("failed to copy `{}` to `{}`: {}", src.display(),
|
||||
dst.display(), e)
|
||||
}
|
||||
let metadata = t!(src.metadata());
|
||||
t!(fs::set_permissions(dst, metadata.permissions()));
|
||||
let atime = FileTime::from_last_access_time(&metadata);
|
||||
let mtime = FileTime::from_last_modification_time(&metadata);
|
||||
t!(filetime::set_file_times(dst, atime, mtime));
|
||||
}
|
||||
|
||||
/// Search-and-replaces within a file. (Not maximally efficiently: allocates a
|
||||
/// new string for each replacement.)
|
||||
pub fn replace_in_file(&self, path: &Path, replacements: &[(&str, &str)]) {
|
||||
if self.config.dry_run { return; }
|
||||
let mut contents = String::new();
|
||||
let mut file = t!(OpenOptions::new().read(true).write(true).open(path));
|
||||
t!(file.read_to_string(&mut contents));
|
||||
for &(target, replacement) in replacements {
|
||||
contents = contents.replace(target, replacement);
|
||||
}
|
||||
t!(file.seek(SeekFrom::Start(0)));
|
||||
t!(file.set_len(0));
|
||||
t!(file.write_all(contents.as_bytes()));
|
||||
}
|
||||
|
||||
/// Copies the `src` directory recursively to `dst`. Both are assumed to exist
|
||||
/// when this function is called.
|
||||
pub fn cp_r(&self, src: &Path, dst: &Path) {
|
||||
if self.config.dry_run { return; }
|
||||
for f in t!(fs::read_dir(src)) {
|
||||
let f = t!(f);
|
||||
let path = f.path();
|
||||
let name = path.file_name().unwrap();
|
||||
let dst = dst.join(name);
|
||||
if t!(f.file_type()).is_dir() {
|
||||
t!(fs::create_dir_all(&dst));
|
||||
self.cp_r(&path, &dst);
|
||||
} else {
|
||||
let _ = fs::remove_file(&dst);
|
||||
self.copy(&path, &dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Copies the `src` directory recursively to `dst`. Both are assumed to exist
|
||||
/// when this function is called. Unwanted files or directories can be skipped
|
||||
/// by returning `false` from the filter function.
|
||||
pub fn cp_filtered(&self, src: &Path, dst: &Path, filter: &Fn(&Path) -> bool) {
|
||||
// Immediately recurse with an empty relative path
|
||||
self.recurse_(src, dst, Path::new(""), filter)
|
||||
}
|
||||
|
||||
// Inner function does the actual work
|
||||
fn recurse_(&self, src: &Path, dst: &Path, relative: &Path, filter: &Fn(&Path) -> bool) {
|
||||
for f in self.read_dir(src) {
|
||||
let path = f.path();
|
||||
let name = path.file_name().unwrap();
|
||||
let dst = dst.join(name);
|
||||
let relative = relative.join(name);
|
||||
// Only copy file or directory if the filter function returns true
|
||||
if filter(&relative) {
|
||||
if t!(f.file_type()).is_dir() {
|
||||
let _ = fs::remove_dir_all(&dst);
|
||||
self.create_dir(&dst);
|
||||
self.recurse_(&path, &dst, &relative, filter);
|
||||
} else {
|
||||
let _ = fs::remove_file(&dst);
|
||||
self.copy(&path, &dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_to_folder(&self, src: &Path, dest_folder: &Path) {
|
||||
let file_name = src.file_name().unwrap();
|
||||
let dest = dest_folder.join(file_name);
|
||||
self.copy(src, &dest);
|
||||
}
|
||||
|
||||
fn install(&self, src: &Path, dstdir: &Path, perms: u32) {
|
||||
if self.config.dry_run { return; }
|
||||
let dst = dstdir.join(src.file_name().unwrap());
|
||||
t!(fs::create_dir_all(dstdir));
|
||||
drop(fs::remove_file(&dst));
|
||||
{
|
||||
let mut s = t!(fs::File::open(&src));
|
||||
let mut d = t!(fs::File::create(&dst));
|
||||
io::copy(&mut s, &mut d).expect("failed to copy");
|
||||
}
|
||||
chmod(&dst, perms);
|
||||
}
|
||||
|
||||
fn create(&self, path: &Path, s: &str) {
|
||||
if self.config.dry_run { return; }
|
||||
t!(fs::write(path, s));
|
||||
}
|
||||
|
||||
fn read(&self, path: &Path) -> String {
|
||||
if self.config.dry_run { return String::new(); }
|
||||
t!(fs::read_string(path))
|
||||
}
|
||||
|
||||
fn create_dir(&self, dir: &Path) {
|
||||
if self.config.dry_run { return; }
|
||||
t!(fs::create_dir_all(dir))
|
||||
}
|
||||
|
||||
fn remove_dir(&self, dir: &Path) {
|
||||
if self.config.dry_run { return; }
|
||||
t!(fs::remove_dir_all(dir))
|
||||
}
|
||||
|
||||
fn read_dir(&self, dir: &Path) -> impl Iterator<Item=fs::DirEntry> {
|
||||
let iter = match fs::read_dir(dir) {
|
||||
Ok(v) => v,
|
||||
Err(_) if self.config.dry_run => return vec![].into_iter(),
|
||||
Err(err) => panic!("could not read dir {:?}: {:?}", dir, err),
|
||||
};
|
||||
iter.map(|e| t!(e)).collect::<Vec<_>>().into_iter()
|
||||
}
|
||||
|
||||
fn remove(&self, f: &Path) {
|
||||
if self.config.dry_run { return; }
|
||||
fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {:?}", f));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn chmod(path: &Path, perms: u32) {
|
||||
use std::os::unix::fs::*;
|
||||
t!(fs::set_permissions(path, fs::Permissions::from_mode(perms)));
|
||||
}
|
||||
#[cfg(windows)]
|
||||
fn chmod(_path: &Path, _perms: u32) {}
|
||||
|
||||
|
||||
impl<'a> Compiler {
|
||||
pub fn with_stage(mut self, stage: u32) -> Compiler {
|
||||
self.stage = stage;
|
||||
|
|
|
|||
|
|
@ -85,5 +85,12 @@ check-stage2-T-arm-linux-androideabi-H-x86_64-unknown-linux-gnu:
|
|||
check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu:
|
||||
$(Q)$(BOOTSTRAP) test --target x86_64-unknown-linux-musl
|
||||
|
||||
TESTS_IN_2 := src/test/run-pass src/test/compile-fail src/test/run-pass-fulldeps
|
||||
|
||||
appveyor-subset-1:
|
||||
$(Q)$(BOOTSTRAP) test $(TESTS_IN_2:%=--exclude %)
|
||||
appveyor-subset-2:
|
||||
$(Q)$(BOOTSTRAP) test $(TESTS_IN_2)
|
||||
|
||||
|
||||
.PHONY: dist
|
||||
|
|
|
|||
|
|
@ -106,8 +106,8 @@ impl Step for Llvm {
|
|||
|
||||
let _folder = build.fold_output(|| "llvm");
|
||||
let descriptor = if emscripten { "Emscripten " } else { "" };
|
||||
println!("Building {}LLVM for {}", descriptor, target);
|
||||
let _time = util::timeit();
|
||||
build.info(&format!("Building {}LLVM for {}", descriptor, target));
|
||||
let _time = util::timeit(&build);
|
||||
t!(fs::create_dir_all(&out_dir));
|
||||
|
||||
// http://llvm.org/docs/CMake.html
|
||||
|
|
@ -217,6 +217,11 @@ impl Step for Llvm {
|
|||
// libraries here, e.g. we just want a few components and a few
|
||||
// tools. Figure out how to filter them down and only build the right
|
||||
// tools and libs on all platforms.
|
||||
|
||||
if builder.config.dry_run {
|
||||
return build_llvm_config;
|
||||
}
|
||||
|
||||
cfg.build();
|
||||
|
||||
t!(t!(File::create(&done_stamp)).write_all(rebuild_trigger_contents.as_bytes()));
|
||||
|
|
@ -230,6 +235,10 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) {
|
|||
return
|
||||
}
|
||||
|
||||
if build.config.dry_run {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut cmd = Command::new(llvm_config);
|
||||
let version = output(cmd.arg("--version"));
|
||||
let mut parts = version.split('.').take(2)
|
||||
|
|
@ -336,6 +345,9 @@ impl Step for Lld {
|
|||
|
||||
/// Compile LLVM for `target`.
|
||||
fn run(self, builder: &Builder) -> PathBuf {
|
||||
if builder.config.dry_run {
|
||||
return PathBuf::from("lld-out-dir-test-gen");
|
||||
}
|
||||
let target = self.target;
|
||||
let build = builder.build;
|
||||
|
||||
|
|
@ -351,8 +363,8 @@ impl Step for Lld {
|
|||
}
|
||||
|
||||
let _folder = build.fold_output(|| "lld");
|
||||
println!("Building LLD for {}", target);
|
||||
let _time = util::timeit();
|
||||
build.info(&format!("Building LLD for {}", target));
|
||||
let _time = util::timeit(&build);
|
||||
t!(fs::create_dir_all(&out_dir));
|
||||
|
||||
let mut cfg = cmake::Config::new(build.src.join("src/tools/lld"));
|
||||
|
|
@ -389,6 +401,9 @@ impl Step for TestHelpers {
|
|||
/// Compiles the `rust_test_helpers.c` library which we used in various
|
||||
/// `run-pass` test suites for ABI testing.
|
||||
fn run(self, builder: &Builder) {
|
||||
if builder.config.dry_run {
|
||||
return;
|
||||
}
|
||||
let build = builder.build;
|
||||
let target = self.target;
|
||||
let dst = build.test_helpers_out(target);
|
||||
|
|
@ -398,7 +413,7 @@ impl Step for TestHelpers {
|
|||
}
|
||||
|
||||
let _folder = build.fold_output(|| "build_test_helpers");
|
||||
println!("Building test helpers");
|
||||
build.info(&format!("Building test helpers"));
|
||||
t!(fs::create_dir_all(&dst));
|
||||
let mut cfg = cc::Build::new();
|
||||
|
||||
|
|
@ -441,6 +456,9 @@ impl Step for Openssl {
|
|||
}
|
||||
|
||||
fn run(self, builder: &Builder) {
|
||||
if builder.config.dry_run {
|
||||
return;
|
||||
}
|
||||
let build = builder.build;
|
||||
let target = self.target;
|
||||
let out = match build.openssl_dir(target) {
|
||||
|
|
@ -591,11 +609,11 @@ impl Step for Openssl {
|
|||
configure.arg("no-asm");
|
||||
}
|
||||
configure.current_dir(&obj);
|
||||
println!("Configuring openssl for {}", target);
|
||||
build.info(&format!("Configuring openssl for {}", target));
|
||||
build.run_quiet(&mut configure);
|
||||
println!("Building openssl for {}", target);
|
||||
build.info(&format!("Building openssl for {}", target));
|
||||
build.run_quiet(Command::new("make").arg("-j1").current_dir(&obj));
|
||||
println!("Installing openssl for {}", target);
|
||||
build.info(&format!("Installing openssl for {}", target));
|
||||
build.run_quiet(Command::new("make").arg("install").arg("-j1").current_dir(&obj));
|
||||
|
||||
let mut f = t!(File::create(&stamp));
|
||||
|
|
|
|||
|
|
@ -169,6 +169,19 @@ pub fn check(build: &mut Build) {
|
|||
panic!("the iOS target is only supported on macOS");
|
||||
}
|
||||
|
||||
if target.contains("-none-") {
|
||||
if build.no_std(*target).is_none() {
|
||||
let target = build.config.target_config.entry(target.clone())
|
||||
.or_insert(Default::default());
|
||||
|
||||
target.no_std = true;
|
||||
}
|
||||
|
||||
if build.no_std(*target) == Some(false) {
|
||||
panic!("All the *-none-* targets are no-std targets")
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure musl-root is valid
|
||||
if target.contains("musl") {
|
||||
// If this is a native target (host is also musl) and no musl-root is given,
|
||||
|
|
|
|||
|
|
@ -109,11 +109,11 @@ impl Step for Linkcheck {
|
|||
let build = builder.build;
|
||||
let host = self.host;
|
||||
|
||||
println!("Linkcheck ({})", host);
|
||||
build.info(&format!("Linkcheck ({})", host));
|
||||
|
||||
builder.default_doc(None);
|
||||
|
||||
let _time = util::timeit();
|
||||
let _time = util::timeit(&build);
|
||||
try_run(build, builder.tool_cmd(Tool::Linkchecker)
|
||||
.arg(build.out.join(host).join("doc")));
|
||||
}
|
||||
|
|
@ -164,7 +164,7 @@ impl Step for Cargotest {
|
|||
let out_dir = build.out.join("ct");
|
||||
t!(fs::create_dir_all(&out_dir));
|
||||
|
||||
let _time = util::timeit();
|
||||
let _time = util::timeit(&build);
|
||||
let mut cmd = builder.tool_cmd(Tool::CargoTest);
|
||||
try_run(build, cmd.arg(&build.initial_cargo)
|
||||
.arg(&out_dir)
|
||||
|
|
@ -509,7 +509,7 @@ impl Step for RustdocJS {
|
|||
});
|
||||
builder.run(&mut command);
|
||||
} else {
|
||||
println!("No nodejs found, skipping \"src/test/rustdoc-js\" tests");
|
||||
builder.info(&format!("No nodejs found, skipping \"src/test/rustdoc-js\" tests"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -530,8 +530,6 @@ impl Step for Tidy {
|
|||
fn run(self, builder: &Builder) {
|
||||
let build = builder.build;
|
||||
|
||||
let _folder = build.fold_output(|| "tidy");
|
||||
println!("tidy check");
|
||||
let mut cmd = builder.tool_cmd(Tool::Tidy);
|
||||
cmd.arg(build.src.join("src"));
|
||||
cmd.arg(&build.initial_cargo);
|
||||
|
|
@ -541,6 +539,9 @@ impl Step for Tidy {
|
|||
if build.config.quiet_tests {
|
||||
cmd.arg("--quiet");
|
||||
}
|
||||
|
||||
let _folder = build.fold_output(|| "tidy");
|
||||
builder.info(&format!("tidy check"));
|
||||
try_run(build, &mut cmd);
|
||||
}
|
||||
|
||||
|
|
@ -759,12 +760,18 @@ test!(RunFailFullDepsPretty {
|
|||
host: true
|
||||
});
|
||||
|
||||
host_test!(RunMake {
|
||||
default_test!(RunMake {
|
||||
path: "src/test/run-make",
|
||||
mode: "run-make",
|
||||
suite: "run-make"
|
||||
});
|
||||
|
||||
host_test!(RunMakeFullDeps {
|
||||
path: "src/test/run-make-fulldeps",
|
||||
mode: "run-make",
|
||||
suite: "run-make-fulldeps"
|
||||
});
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
struct Compiletest {
|
||||
compiler: Compiler,
|
||||
|
|
@ -827,8 +834,7 @@ impl Step for Compiletest {
|
|||
// FIXME: Does pretty need librustc compiled? Note that there are
|
||||
// fulldeps test suites with mode = pretty as well.
|
||||
mode == "pretty" ||
|
||||
mode == "rustdoc" ||
|
||||
mode == "run-make" {
|
||||
mode == "rustdoc" {
|
||||
builder.ensure(compile::Rustc { compiler, target });
|
||||
}
|
||||
|
||||
|
|
@ -836,9 +842,6 @@ impl Step for Compiletest {
|
|||
builder.ensure(native::TestHelpers { target });
|
||||
builder.ensure(RemoteCopyLibs { compiler, target });
|
||||
|
||||
let _folder = build.fold_output(|| format!("test_{}", suite));
|
||||
println!("Check compiletest suite={} mode={} ({} -> {})",
|
||||
suite, mode, &compiler.host, target);
|
||||
let mut cmd = builder.tool_cmd(Tool::Compiletest);
|
||||
|
||||
// compiletest currently has... a lot of arguments, so let's just pass all
|
||||
|
|
@ -849,7 +852,7 @@ impl Step for Compiletest {
|
|||
cmd.arg("--rustc-path").arg(builder.rustc(compiler));
|
||||
|
||||
// Avoid depending on rustdoc when we don't need it.
|
||||
if mode == "rustdoc" || mode == "run-make" {
|
||||
if mode == "rustdoc" || (mode == "run-make" && suite.ends_with("fulldeps")) {
|
||||
cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host));
|
||||
}
|
||||
|
||||
|
|
@ -923,15 +926,17 @@ impl Step for Compiletest {
|
|||
target: build.config.build,
|
||||
emscripten: false,
|
||||
});
|
||||
let llvm_version = output(Command::new(&llvm_config).arg("--version"));
|
||||
cmd.arg("--llvm-version").arg(llvm_version);
|
||||
if !build.config.dry_run {
|
||||
let llvm_version = output(Command::new(&llvm_config).arg("--version"));
|
||||
cmd.arg("--llvm-version").arg(llvm_version);
|
||||
}
|
||||
if !build.is_rust_llvm(target) {
|
||||
cmd.arg("--system-llvm");
|
||||
}
|
||||
|
||||
// Only pass correct values for these flags for the `run-make` suite as it
|
||||
// requires that a C++ compiler was configured which isn't always the case.
|
||||
if suite == "run-make" {
|
||||
if !build.config.dry_run && suite == "run-make-fulldeps" {
|
||||
let llvm_components = output(Command::new(&llvm_config).arg("--components"));
|
||||
let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
|
||||
cmd.arg("--cc").arg(build.cc(target))
|
||||
|
|
@ -944,12 +949,13 @@ impl Step for Compiletest {
|
|||
}
|
||||
}
|
||||
}
|
||||
if suite == "run-make" && !build.config.llvm_enabled {
|
||||
println!("Ignoring run-make test suite as they generally don't work without LLVM");
|
||||
if suite == "run-make-fulldeps" && !build.config.llvm_enabled {
|
||||
builder.info(
|
||||
&format!("Ignoring run-make test suite as they generally don't work without LLVM"));
|
||||
return;
|
||||
}
|
||||
|
||||
if suite != "run-make" {
|
||||
if suite != "run-make-fulldeps" {
|
||||
cmd.arg("--cc").arg("")
|
||||
.arg("--cxx").arg("")
|
||||
.arg("--cflags").arg("")
|
||||
|
|
@ -998,7 +1004,10 @@ impl Step for Compiletest {
|
|||
|
||||
build.ci_env.force_coloring_in_ci(&mut cmd);
|
||||
|
||||
let _time = util::timeit();
|
||||
let _folder = build.fold_output(|| format!("test_{}", suite));
|
||||
builder.info(&format!("Check compiletest suite={} mode={} ({} -> {})",
|
||||
suite, mode, &compiler.host, target));
|
||||
let _time = util::timeit(&build);
|
||||
try_run(build, &mut cmd);
|
||||
}
|
||||
}
|
||||
|
|
@ -1033,9 +1042,10 @@ impl Step for DocTest {
|
|||
// Do a breadth-first traversal of the `src/doc` directory and just run
|
||||
// tests for all files that end in `*.md`
|
||||
let mut stack = vec![build.src.join(self.path)];
|
||||
let _time = util::timeit();
|
||||
let _time = util::timeit(&build);
|
||||
let _folder = build.fold_output(|| format!("test_{}", self.name));
|
||||
|
||||
let mut files = Vec::new();
|
||||
while let Some(p) = stack.pop() {
|
||||
if p.is_dir() {
|
||||
stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
|
||||
|
|
@ -1052,7 +1062,13 @@ impl Step for DocTest {
|
|||
continue;
|
||||
}
|
||||
|
||||
let test_result = markdown_test(builder, compiler, &p);
|
||||
files.push(p);
|
||||
}
|
||||
|
||||
files.sort();
|
||||
|
||||
for file in files {
|
||||
let test_result = markdown_test(builder, compiler, &file);
|
||||
if self.is_ext_doc {
|
||||
let toolstate = if test_result {
|
||||
ToolState::TestPass
|
||||
|
|
@ -1142,34 +1158,39 @@ impl Step for ErrorIndex {
|
|||
|
||||
builder.ensure(compile::Std { compiler, target: compiler.host });
|
||||
|
||||
let _folder = build.fold_output(|| "test_error_index");
|
||||
println!("Testing error-index stage{}", compiler.stage);
|
||||
|
||||
let dir = testdir(build, compiler.host);
|
||||
t!(fs::create_dir_all(&dir));
|
||||
let output = dir.join("error-index.md");
|
||||
|
||||
let _time = util::timeit();
|
||||
build.run(builder.tool_cmd(Tool::ErrorIndex)
|
||||
.arg("markdown")
|
||||
.arg(&output)
|
||||
.env("CFG_BUILD", &build.build)
|
||||
.env("RUSTC_ERROR_METADATA_DST", build.extended_error_dir()));
|
||||
let mut tool = builder.tool_cmd(Tool::ErrorIndex);
|
||||
tool.arg("markdown")
|
||||
.arg(&output)
|
||||
.env("CFG_BUILD", &build.build)
|
||||
.env("RUSTC_ERROR_METADATA_DST", build.extended_error_dir());
|
||||
|
||||
|
||||
let _folder = build.fold_output(|| "test_error_index");
|
||||
build.info(&format!("Testing error-index stage{}", compiler.stage));
|
||||
let _time = util::timeit(&build);
|
||||
build.run(&mut tool);
|
||||
markdown_test(builder, compiler, &output);
|
||||
}
|
||||
}
|
||||
|
||||
fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool {
|
||||
let build = builder.build;
|
||||
let mut file = t!(File::open(markdown));
|
||||
let mut contents = String::new();
|
||||
t!(file.read_to_string(&mut contents));
|
||||
if !contents.contains("```") {
|
||||
return true;
|
||||
match File::open(markdown) {
|
||||
Ok(mut file) => {
|
||||
let mut contents = String::new();
|
||||
t!(file.read_to_string(&mut contents));
|
||||
if !contents.contains("```") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Err(_) => {},
|
||||
}
|
||||
|
||||
println!("doc tests for: {}", markdown.display());
|
||||
build.info(&format!("doc tests for: {}", markdown.display()));
|
||||
let mut cmd = builder.rustdoc_cmd(compiler.host);
|
||||
build.add_rust_test_threads(&mut cmd);
|
||||
cmd.arg("--test");
|
||||
|
|
@ -1400,11 +1421,6 @@ impl Step for Crate {
|
|||
}
|
||||
_ => panic!("can only test libraries"),
|
||||
};
|
||||
let _folder = build.fold_output(|| {
|
||||
format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate)
|
||||
});
|
||||
println!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage,
|
||||
&compiler.host, target);
|
||||
|
||||
// Build up the base `cargo test` command.
|
||||
//
|
||||
|
|
@ -1436,8 +1452,6 @@ impl Step for Crate {
|
|||
cargo.arg("--quiet");
|
||||
}
|
||||
|
||||
let _time = util::timeit();
|
||||
|
||||
if target.contains("emscripten") {
|
||||
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
|
||||
build.config.nodejs.as_ref().expect("nodejs not configured"));
|
||||
|
|
@ -1446,8 +1460,8 @@ impl Step for Crate {
|
|||
// The javascript shim implements the syscall interface so that test
|
||||
// output can be correctly reported.
|
||||
if !build.config.wasm_syscall {
|
||||
println!("Libstd was built without `wasm_syscall` feature enabled: \
|
||||
test output may not be visible.");
|
||||
build.info(&format!("Libstd was built without `wasm_syscall` feature enabled: \
|
||||
test output may not be visible."));
|
||||
}
|
||||
|
||||
// On the wasm32-unknown-unknown target we're using LTO which is
|
||||
|
|
@ -1465,6 +1479,13 @@ impl Step for Crate {
|
|||
format!("{} run",
|
||||
builder.tool_exe(Tool::RemoteTestClient).display()));
|
||||
}
|
||||
|
||||
let _folder = build.fold_output(|| {
|
||||
format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate)
|
||||
});
|
||||
build.info(&format!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage,
|
||||
&compiler.host, target));
|
||||
let _time = util::timeit(&build);
|
||||
try_run(build, &mut cargo);
|
||||
}
|
||||
}
|
||||
|
|
@ -1513,12 +1534,6 @@ impl Step for CrateRustdoc {
|
|||
target,
|
||||
test_kind.subcommand(),
|
||||
"src/tools/rustdoc");
|
||||
let _folder = build.fold_output(|| {
|
||||
format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage)
|
||||
});
|
||||
println!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage,
|
||||
&compiler.host, target);
|
||||
|
||||
if test_kind.subcommand() == "test" && !build.fail_fast {
|
||||
cargo.arg("--no-fail-fast");
|
||||
}
|
||||
|
|
@ -1532,7 +1547,12 @@ impl Step for CrateRustdoc {
|
|||
cargo.arg("--quiet");
|
||||
}
|
||||
|
||||
let _time = util::timeit();
|
||||
let _folder = build.fold_output(|| {
|
||||
format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage)
|
||||
});
|
||||
build.info(&format!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage,
|
||||
&compiler.host, target));
|
||||
let _time = util::timeit(&build);
|
||||
|
||||
try_run(build, &mut cargo);
|
||||
}
|
||||
|
|
@ -1579,7 +1599,7 @@ impl Step for RemoteCopyLibs {
|
|||
|
||||
builder.ensure(compile::Test { compiler, target });
|
||||
|
||||
println!("REMOTE copy libs to emulator ({})", target);
|
||||
build.info(&format!("REMOTE copy libs to emulator ({})", target));
|
||||
t!(fs::create_dir_all(build.out.join("tmp")));
|
||||
|
||||
let server = builder.ensure(tool::RemoteTestServer { compiler, target });
|
||||
|
|
@ -1627,7 +1647,7 @@ impl Step for Distcheck {
|
|||
fn run(self, builder: &Builder) {
|
||||
let build = builder.build;
|
||||
|
||||
println!("Distcheck");
|
||||
build.info(&format!("Distcheck"));
|
||||
let dir = build.out.join("tmp").join("distcheck");
|
||||
let _ = fs::remove_dir_all(&dir);
|
||||
t!(fs::create_dir_all(&dir));
|
||||
|
|
@ -1651,7 +1671,7 @@ impl Step for Distcheck {
|
|||
.current_dir(&dir));
|
||||
|
||||
// Now make sure that rust-src has all of libstd's dependencies
|
||||
println!("Distcheck rust-src");
|
||||
build.info(&format!("Distcheck rust-src"));
|
||||
let dir = build.out.join("tmp").join("distcheck-src");
|
||||
let _ = fs::remove_dir_all(&dir);
|
||||
t!(fs::create_dir_all(&dir));
|
||||
|
|
@ -1686,9 +1706,16 @@ impl Step for Bootstrap {
|
|||
let mut cmd = Command::new(&build.initial_cargo);
|
||||
cmd.arg("test")
|
||||
.current_dir(build.src.join("src/bootstrap"))
|
||||
.env("RUSTFLAGS", "-Cdebuginfo=2")
|
||||
.env("CARGO_TARGET_DIR", build.out.join("bootstrap"))
|
||||
.env("RUSTC_BOOTSTRAP", "1")
|
||||
.env("RUSTC", &build.initial_rustc);
|
||||
if let Some(flags) = option_env!("RUSTFLAGS") {
|
||||
// Use the same rustc flags for testing as for "normal" compilation,
|
||||
// so that Cargo doesn’t recompile the entire dependency graph every time:
|
||||
// https://github.com/rust-lang/rust/issues/49215
|
||||
cmd.env("RUSTFLAGS", flags);
|
||||
}
|
||||
if !build.fail_fast {
|
||||
cmd.arg("--no-fail-fast");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use std::slice::SliceConcatExt;
|
|||
use Mode;
|
||||
use Compiler;
|
||||
use builder::{Step, RunConfig, ShouldRun, Builder};
|
||||
use util::{copy, exe, add_lib_path};
|
||||
use util::{exe, add_lib_path};
|
||||
use compile::{self, libtest_stamp, libstd_stamp, librustc_stamp};
|
||||
use native;
|
||||
use channel::GitInfo;
|
||||
|
|
@ -112,12 +112,85 @@ impl Step for ToolBuild {
|
|||
Mode::Tool => panic!("unexpected Mode::Tool for tool build")
|
||||
}
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
|
||||
println!("Building stage{} tool {} ({})", compiler.stage, tool, target);
|
||||
|
||||
let mut cargo = prepare_tool_cargo(builder, compiler, target, "build", path);
|
||||
cargo.arg("--features").arg(self.extra_features.join(" "));
|
||||
let is_expected = build.try_run(&mut cargo);
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
|
||||
build.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
|
||||
let mut duplicates = Vec::new();
|
||||
let is_expected = compile::stream_cargo(build, &mut cargo, &mut |msg| {
|
||||
// Only care about big things like the RLS/Cargo for now
|
||||
if tool != "rls" && tool != "cargo" {
|
||||
return
|
||||
}
|
||||
let (id, features, filenames) = match msg {
|
||||
compile::CargoMessage::CompilerArtifact {
|
||||
package_id,
|
||||
features,
|
||||
filenames
|
||||
} => {
|
||||
(package_id, features, filenames)
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
let features = features.iter().map(|s| s.to_string()).collect::<Vec<_>>();
|
||||
|
||||
for path in filenames {
|
||||
let val = (tool, PathBuf::from(&*path), features.clone());
|
||||
// we're only interested in deduplicating rlibs for now
|
||||
if val.1.extension().and_then(|s| s.to_str()) != Some("rlib") {
|
||||
continue
|
||||
}
|
||||
|
||||
// Don't worry about libs that turn out to be host dependencies
|
||||
// or build scripts, we only care about target dependencies that
|
||||
// are in `deps`.
|
||||
if let Some(maybe_target) = val.1
|
||||
.parent() // chop off file name
|
||||
.and_then(|p| p.parent()) // chop off `deps`
|
||||
.and_then(|p| p.parent()) // chop off `release`
|
||||
.and_then(|p| p.file_name())
|
||||
.and_then(|p| p.to_str())
|
||||
{
|
||||
if maybe_target != &*target {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
let mut artifacts = build.tool_artifacts.borrow_mut();
|
||||
let prev_artifacts = artifacts
|
||||
.entry(target)
|
||||
.or_insert_with(Default::default);
|
||||
if let Some(prev) = prev_artifacts.get(&*id) {
|
||||
if prev.1 != val.1 {
|
||||
duplicates.push((
|
||||
id.to_string(),
|
||||
val,
|
||||
prev.clone(),
|
||||
));
|
||||
}
|
||||
return
|
||||
}
|
||||
prev_artifacts.insert(id.to_string(), val);
|
||||
}
|
||||
});
|
||||
|
||||
if is_expected && duplicates.len() != 0 {
|
||||
println!("duplicate artfacts found when compiling a tool, this \
|
||||
typically means that something was recompiled because \
|
||||
a transitive dependency has different features activated \
|
||||
than in a previous build:\n");
|
||||
for (id, cur, prev) in duplicates {
|
||||
println!(" {}", id);
|
||||
println!(" `{}` enabled features {:?} at {:?}",
|
||||
cur.0, cur.2, cur.1);
|
||||
println!(" `{}` enabled features {:?} at {:?}",
|
||||
prev.0, prev.2, prev.1);
|
||||
}
|
||||
println!("");
|
||||
panic!("tools should not compile multiple copies of the same crate");
|
||||
}
|
||||
|
||||
build.save_toolstate(tool, if is_expected {
|
||||
ToolState::TestFail
|
||||
} else {
|
||||
|
|
@ -134,7 +207,7 @@ impl Step for ToolBuild {
|
|||
let cargo_out = build.cargo_out(compiler, Mode::Tool, target)
|
||||
.join(exe(tool, &compiler.host));
|
||||
let bin = build.tools_dir(compiler).join(exe(tool, &compiler.host));
|
||||
copy(&cargo_out, &bin);
|
||||
build.copy(&cargo_out, &bin);
|
||||
Some(bin)
|
||||
}
|
||||
}
|
||||
|
|
@ -338,9 +411,10 @@ impl Step for Rustdoc {
|
|||
};
|
||||
|
||||
builder.ensure(compile::Rustc { compiler: build_compiler, target });
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage));
|
||||
println!("Building rustdoc for stage{} ({})", target_compiler.stage, target_compiler.host);
|
||||
builder.ensure(compile::Rustc {
|
||||
compiler: build_compiler,
|
||||
target: builder.build.build,
|
||||
});
|
||||
|
||||
let mut cargo = prepare_tool_cargo(builder,
|
||||
build_compiler,
|
||||
|
|
@ -352,7 +426,11 @@ impl Step for Rustdoc {
|
|||
cargo.env("RUSTC_DEBUGINFO", builder.config.rust_debuginfo.to_string())
|
||||
.env("RUSTC_DEBUGINFO_LINES", builder.config.rust_debuginfo_lines.to_string());
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage));
|
||||
build.info(&format!("Building rustdoc for stage{} ({})",
|
||||
target_compiler.stage, target_compiler.host));
|
||||
build.run(&mut cargo);
|
||||
|
||||
// Cargo adds a number of paths to the dylib search path on windows, which results in
|
||||
// the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
|
||||
// rustdoc a different name.
|
||||
|
|
@ -366,7 +444,7 @@ impl Step for Rustdoc {
|
|||
t!(fs::create_dir_all(&bindir));
|
||||
let bin_rustdoc = bindir.join(exe("rustdoc", &*target_compiler.host));
|
||||
let _ = fs::remove_file(&bin_rustdoc);
|
||||
copy(&tool_rustdoc, &bin_rustdoc);
|
||||
build.copy(&tool_rustdoc, &bin_rustdoc);
|
||||
bin_rustdoc
|
||||
} else {
|
||||
tool_rustdoc
|
||||
|
|
|
|||
|
|
@ -15,13 +15,14 @@
|
|||
|
||||
use std::env;
|
||||
use std::str;
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
use std::io::{self, Read, Write, Seek, SeekFrom};
|
||||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::time::{SystemTime, Instant};
|
||||
|
||||
use filetime::{self, FileTime};
|
||||
use config::Config;
|
||||
use Build;
|
||||
|
||||
/// Returns the `name` as the filename of a static library for `target`.
|
||||
pub fn staticlib(name: &str, target: &str) -> String {
|
||||
|
|
@ -32,102 +33,6 @@ pub fn staticlib(name: &str, target: &str) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
/// Copies a file from `src` to `dst`
|
||||
pub fn copy(src: &Path, dst: &Path) {
|
||||
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.
|
||||
if let Ok(()) = fs::hard_link(src, dst) {
|
||||
return
|
||||
}
|
||||
if let Err(e) = fs::copy(src, dst) {
|
||||
panic!("failed to copy `{}` to `{}`: {}", src.display(),
|
||||
dst.display(), e)
|
||||
}
|
||||
let metadata = t!(src.metadata());
|
||||
t!(fs::set_permissions(dst, metadata.permissions()));
|
||||
let atime = FileTime::from_last_access_time(&metadata);
|
||||
let mtime = FileTime::from_last_modification_time(&metadata);
|
||||
t!(filetime::set_file_times(dst, atime, mtime));
|
||||
}
|
||||
|
||||
/// Search-and-replaces within a file. (Not maximally efficiently: allocates a
|
||||
/// new string for each replacement.)
|
||||
pub fn replace_in_file(path: &Path, replacements: &[(&str, &str)]) {
|
||||
let mut contents = String::new();
|
||||
let mut file = t!(OpenOptions::new().read(true).write(true).open(path));
|
||||
t!(file.read_to_string(&mut contents));
|
||||
for &(target, replacement) in replacements {
|
||||
contents = contents.replace(target, replacement);
|
||||
}
|
||||
t!(file.seek(SeekFrom::Start(0)));
|
||||
t!(file.set_len(0));
|
||||
t!(file.write_all(contents.as_bytes()));
|
||||
}
|
||||
|
||||
pub fn read_stamp_file(stamp: &Path) -> Vec<PathBuf> {
|
||||
let mut paths = Vec::new();
|
||||
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 compile.rs).
|
||||
for part in contents.split(|b| *b == 0) {
|
||||
if part.is_empty() {
|
||||
continue
|
||||
}
|
||||
let path = PathBuf::from(t!(str::from_utf8(part)));
|
||||
paths.push(path);
|
||||
}
|
||||
paths
|
||||
}
|
||||
|
||||
/// Copies the `src` directory recursively to `dst`. Both are assumed to exist
|
||||
/// when this function is called.
|
||||
pub fn cp_r(src: &Path, dst: &Path) {
|
||||
for f in t!(fs::read_dir(src)) {
|
||||
let f = t!(f);
|
||||
let path = f.path();
|
||||
let name = path.file_name().unwrap();
|
||||
let dst = dst.join(name);
|
||||
if t!(f.file_type()).is_dir() {
|
||||
t!(fs::create_dir_all(&dst));
|
||||
cp_r(&path, &dst);
|
||||
} else {
|
||||
let _ = fs::remove_file(&dst);
|
||||
copy(&path, &dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Copies the `src` directory recursively to `dst`. Both are assumed to exist
|
||||
/// when this function is called. Unwanted files or directories can be skipped
|
||||
/// by returning `false` from the filter function.
|
||||
pub fn cp_filtered(src: &Path, dst: &Path, filter: &Fn(&Path) -> bool) {
|
||||
// Inner function does the actual work
|
||||
fn recurse(src: &Path, dst: &Path, relative: &Path, filter: &Fn(&Path) -> bool) {
|
||||
for f in t!(fs::read_dir(src)) {
|
||||
let f = t!(f);
|
||||
let path = f.path();
|
||||
let name = path.file_name().unwrap();
|
||||
let dst = dst.join(name);
|
||||
let relative = relative.join(name);
|
||||
// Only copy file or directory if the filter function returns true
|
||||
if filter(&relative) {
|
||||
if t!(f.file_type()).is_dir() {
|
||||
let _ = fs::remove_dir_all(&dst);
|
||||
t!(fs::create_dir(&dst));
|
||||
recurse(&path, &dst, &relative, filter);
|
||||
} else {
|
||||
let _ = fs::remove_file(&dst);
|
||||
copy(&path, &dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Immediately recurse with an empty relative path
|
||||
recurse(src, dst, Path::new(""), filter)
|
||||
}
|
||||
|
||||
/// Given an executable called `name`, return the filename for the
|
||||
/// executable for a particular target.
|
||||
pub fn exe(name: &str, target: &str) -> String {
|
||||
|
|
@ -196,25 +101,28 @@ pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf {
|
|||
buf
|
||||
}
|
||||
|
||||
pub struct TimeIt(Instant);
|
||||
pub struct TimeIt(bool, Instant);
|
||||
|
||||
/// Returns an RAII structure that prints out how long it took to drop.
|
||||
pub fn timeit() -> TimeIt {
|
||||
TimeIt(Instant::now())
|
||||
pub fn timeit(build: &Build) -> TimeIt {
|
||||
TimeIt(build.config.dry_run, Instant::now())
|
||||
}
|
||||
|
||||
impl Drop for TimeIt {
|
||||
fn drop(&mut self) {
|
||||
let time = self.0.elapsed();
|
||||
println!("\tfinished in {}.{:03}",
|
||||
time.as_secs(),
|
||||
time.subsec_nanos() / 1_000_000);
|
||||
let time = self.1.elapsed();
|
||||
if !self.0 {
|
||||
println!("\tfinished in {}.{:03}",
|
||||
time.as_secs(),
|
||||
time.subsec_nanos() / 1_000_000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Symlinks two directories, using junctions on Windows and normal symlinks on
|
||||
/// Unix.
|
||||
pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> {
|
||||
pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
|
||||
if config.dry_run { return Ok(()); }
|
||||
let _ = fs::remove_dir(dest);
|
||||
return symlink_dir_inner(src, dest);
|
||||
|
||||
|
|
@ -288,6 +196,7 @@ pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> {
|
|||
nOutBufferSize: DWORD,
|
||||
lpBytesReturned: LPDWORD,
|
||||
lpOverlapped: LPOVERLAPPED) -> BOOL;
|
||||
fn CloseHandle(hObject: HANDLE) -> BOOL;
|
||||
}
|
||||
|
||||
fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
|
||||
|
|
@ -341,11 +250,13 @@ pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> {
|
|||
&mut ret,
|
||||
ptr::null_mut());
|
||||
|
||||
if res == 0 {
|
||||
let out = if res == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
CloseHandle(h);
|
||||
out
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,3 @@ authors = ["The Rust Project Developers"]
|
|||
[lib]
|
||||
name = "build_helper"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
filetime = "0.1"
|
||||
|
|
|
|||
|
|
@ -10,14 +10,11 @@
|
|||
|
||||
#![deny(warnings)]
|
||||
|
||||
extern crate filetime;
|
||||
|
||||
use std::fs::File;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Stdio};
|
||||
use std::{fs, env};
|
||||
|
||||
use filetime::FileTime;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
/// A helper macro to `unwrap` a result except also print out details like:
|
||||
///
|
||||
|
|
@ -137,10 +134,8 @@ pub fn rerun_if_changed_anything_in_dir(dir: &Path) {
|
|||
}
|
||||
|
||||
/// Returns the last-modified time for `path`, or zero if it doesn't exist.
|
||||
pub fn mtime(path: &Path) -> FileTime {
|
||||
fs::metadata(path).map(|f| {
|
||||
FileTime::from_last_modification_time(&f)
|
||||
}).unwrap_or(FileTime::zero())
|
||||
pub fn mtime(path: &Path) -> SystemTime {
|
||||
fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH)
|
||||
}
|
||||
|
||||
/// Returns whether `dst` is up to date given that the file or files in `src`
|
||||
|
|
@ -157,9 +152,9 @@ pub fn up_to_date(src: &Path, dst: &Path) -> bool {
|
|||
Err(e) => panic!("source {:?} failed to get metadata: {}", src, e),
|
||||
};
|
||||
if meta.is_dir() {
|
||||
dir_up_to_date(src, &threshold)
|
||||
dir_up_to_date(src, threshold)
|
||||
} else {
|
||||
FileTime::from_last_modification_time(&meta) <= threshold
|
||||
meta.modified().unwrap_or(UNIX_EPOCH) <= threshold
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -226,13 +221,13 @@ pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result<NativeLibBoiler
|
|||
search_path)
|
||||
}
|
||||
|
||||
fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool {
|
||||
fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool {
|
||||
t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| {
|
||||
let meta = t!(e.metadata());
|
||||
if meta.is_dir() {
|
||||
dir_up_to_date(&e.path(), threshold)
|
||||
} else {
|
||||
FileTime::from_last_modification_time(&meta) < *threshold
|
||||
meta.modified().unwrap_or(UNIX_EPOCH) < threshold
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,5 +32,5 @@ ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-gcc \
|
|||
|
||||
ENV HOSTS=aarch64-unknown-linux-gnu
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ ENV RUST_CONFIGURE_ARGS \
|
|||
--armv7-linux-androideabi-ndk=/android/ndk/arm-14 \
|
||||
--i686-linux-android-ndk=/android/ndk/x86-14 \
|
||||
--aarch64-linux-android-ndk=/android/ndk/arm64-21 \
|
||||
--x86_64-linux-android-ndk=/android/ndk/x86_64-21
|
||||
--x86_64-linux-android-ndk=/android/ndk/x86_64-21 \
|
||||
--disable-docs
|
||||
|
||||
ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
|
||||
|
||||
|
|
|
|||
|
|
@ -32,5 +32,5 @@ ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \
|
|||
|
||||
ENV HOSTS=arm-unknown-linux-gnueabi
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -32,5 +32,5 @@ ENV CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \
|
|||
|
||||
ENV HOSTS=arm-unknown-linux-gnueabihf
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -32,5 +32,5 @@ ENV CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \
|
|||
|
||||
ENV HOSTS=armv7-unknown-linux-gnueabihf
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ RUN sh /scripts/sccache.sh
|
|||
ENV RUST_CONFIGURE_ARGS \
|
||||
--musl-root-i586=/musl-i586 \
|
||||
--musl-root-i686=/musl-i686 \
|
||||
--enable-extended
|
||||
--enable-extended \
|
||||
--disable-docs
|
||||
|
||||
# Newer binutils broke things on some vms/distros (i.e., linking against
|
||||
# unknown relocs disabled by the following flag), so we need to go out of our
|
||||
|
|
|
|||
|
|
@ -29,5 +29,5 @@ ENV \
|
|||
|
||||
ENV HOSTS=i686-unknown-freebsd
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -17,6 +17,23 @@ GCC=4.8.5
|
|||
|
||||
curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf -
|
||||
cd gcc-$GCC
|
||||
|
||||
# FIXME(#49246): Remove the `sed` below.
|
||||
#
|
||||
# On 2018 March 21st, two Travis builders' cache for Docker are suddenly invalidated. Normally this
|
||||
# is fine, because we just need to rebuild the Docker image. However, it reveals a network issue:
|
||||
# downloading from `ftp://gcc.gnu.org/` from Travis (using passive mode) often leads to "Connection
|
||||
# timed out" error, and even when the download completed, the file is usually corrupted. This causes
|
||||
# nothing to be landed that day.
|
||||
#
|
||||
# We observed that the `gcc-4.8.5.tar.bz2` above can be downloaded successfully, so as a stability
|
||||
# improvement we try to download from the HTTPS mirror instead. Turns out this uncovered the third
|
||||
# bug: the host `gcc.gnu.org` and `cygwin.com` share the same IP, and the TLS certificate of the
|
||||
# latter host is presented to `wget`! Therefore, we choose to download from the insecure HTTP server
|
||||
# instead here.
|
||||
#
|
||||
sed -i'' 's|ftp://gcc\.gnu\.org/|http://gcc.gnu.org/|g' ./contrib/download_prerequisites
|
||||
|
||||
./contrib/download_prerequisites
|
||||
mkdir ../gcc-build
|
||||
cd ../gcc-build
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
set -ex
|
||||
source shared.sh
|
||||
|
||||
curl https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf -
|
||||
curl -L https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf -
|
||||
|
||||
cd git-2.10.0
|
||||
make configure
|
||||
|
|
|
|||
|
|
@ -22,5 +22,5 @@ RUN sh /scripts/sccache.sh
|
|||
|
||||
ENV HOSTS=mips-unknown-linux-gnu
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -21,5 +21,5 @@ RUN sh /scripts/sccache.sh
|
|||
|
||||
ENV HOSTS=mips64-unknown-linux-gnuabi64
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -22,5 +22,5 @@ RUN sh /scripts/sccache.sh
|
|||
|
||||
ENV HOSTS=mips64el-unknown-linux-gnuabi64
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -21,5 +21,5 @@ RUN sh /scripts/sccache.sh
|
|||
|
||||
ENV HOSTS=mipsel-unknown-linux-gnu
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ ENV \
|
|||
|
||||
ENV HOSTS=powerpc-unknown-linux-gnu
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
||||
# FIXME(#36150) this will fail the bootstrap. Probably means something bad is
|
||||
|
|
|
|||
|
|
@ -35,5 +35,5 @@ ENV \
|
|||
|
||||
ENV HOSTS=powerpc64-unknown-linux-gnu
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -32,5 +32,5 @@ ENV \
|
|||
|
||||
ENV HOSTS=powerpc64le-unknown-linux-gnu
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -34,5 +34,5 @@ ENV \
|
|||
|
||||
ENV HOSTS=s390x-unknown-linux-gnu
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
bzip2 \
|
||||
patch \
|
||||
libssl-dev \
|
||||
pkg-config
|
||||
pkg-config \
|
||||
gcc-arm-none-eabi \
|
||||
libnewlib-arm-none-eabi
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
|
|
@ -66,6 +68,14 @@ RUN env \
|
|||
bash musl.sh mipsel && \
|
||||
rm -rf /build/*
|
||||
|
||||
# FIXME(mozilla/sccache#235) this shouldn't be necessary but is currently
|
||||
# necessary to disambiguate the mips compiler with the mipsel compiler. We want
|
||||
# to give these two wrapper scripts (currently identical ones) different hashes
|
||||
# to ensure that sccache understands that they're different compilers.
|
||||
RUN \
|
||||
echo "# a" >> /usr/local/mips-linux-musl/bin/mips-openwrt-linux-musl-wrapper.sh && \
|
||||
echo "# b" >> /usr/local/mipsel-linux-musl/bin/mipsel-openwrt-linux-musl-wrapper.sh
|
||||
|
||||
ENV TARGETS=asmjs-unknown-emscripten
|
||||
ENV TARGETS=$TARGETS,wasm32-unknown-emscripten
|
||||
ENV TARGETS=$TARGETS,x86_64-rumprun-netbsd
|
||||
|
|
@ -78,6 +88,10 @@ ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf
|
|||
ENV TARGETS=$TARGETS,aarch64-unknown-linux-musl
|
||||
ENV TARGETS=$TARGETS,sparc64-unknown-linux-gnu
|
||||
ENV TARGETS=$TARGETS,x86_64-unknown-redox
|
||||
ENV TARGETS=$TARGETS,thumbv6m-none-eabi
|
||||
ENV TARGETS=$TARGETS,thumbv7m-none-eabi
|
||||
ENV TARGETS=$TARGETS,thumbv7em-none-eabi
|
||||
ENV TARGETS=$TARGETS,thumbv7em-none-eabihf
|
||||
|
||||
# FIXME: remove armv5te vars after https://github.com/alexcrichton/cc-rs/issues/271
|
||||
# get fixed and cc update
|
||||
|
|
@ -95,7 +109,8 @@ ENV RUST_CONFIGURE_ARGS \
|
|||
--musl-root-aarch64=/musl-aarch64 \
|
||||
--musl-root-mips=/musl-mips \
|
||||
--musl-root-mipsel=/musl-mipsel \
|
||||
--enable-emscripten
|
||||
--enable-emscripten \
|
||||
--disable-docs
|
||||
|
||||
ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
|
||||
|
||||
|
|
|
|||
|
|
@ -55,5 +55,5 @@ ENV TARGETS=$TARGETS,x86_64-sun-solaris
|
|||
ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32
|
||||
ENV TARGETS=$TARGETS,x86_64-unknown-cloudabi
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
|
||||
|
|
|
|||
|
|
@ -29,5 +29,5 @@ ENV \
|
|||
|
||||
ENV HOSTS=x86_64-unknown-freebsd
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -84,7 +84,8 @@ ENV HOSTS=x86_64-unknown-linux-gnu
|
|||
ENV RUST_CONFIGURE_ARGS \
|
||||
--enable-full-tools \
|
||||
--enable-sanitizers \
|
||||
--enable-profiler
|
||||
--enable-profiler \
|
||||
--enable-compiler-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
||||
# This is the only builder which will create source tarballs
|
||||
|
|
|
|||
|
|
@ -17,6 +17,23 @@ GCC=4.8.5
|
|||
|
||||
curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf -
|
||||
cd gcc-$GCC
|
||||
|
||||
# FIXME(#49246): Remove the `sed` below.
|
||||
#
|
||||
# On 2018 March 21st, two Travis builders' cache for Docker are suddenly invalidated. Normally this
|
||||
# is fine, because we just need to rebuild the Docker image. However, it reveals a network issue:
|
||||
# downloading from `ftp://gcc.gnu.org/` from Travis (using passive mode) often leads to "Connection
|
||||
# timed out" error, and even when the download completed, the file is usually corrupted. This causes
|
||||
# nothing to be landed that day.
|
||||
#
|
||||
# We observed that the `gcc-4.8.5.tar.bz2` above can be downloaded successfully, so as a stability
|
||||
# improvement we try to download from the HTTPS mirror instead. Turns out this uncovered the third
|
||||
# bug: the host `gcc.gnu.org` and `cygwin.com` share the same IP, and the TLS certificate of the
|
||||
# latter host is presented to `wget`! Therefore, we choose to download from the insecure HTTP server
|
||||
# instead here.
|
||||
#
|
||||
sed -i'' 's|ftp://gcc\.gnu\.org/|http://gcc.gnu.org/|g' ./contrib/download_prerequisites
|
||||
|
||||
./contrib/download_prerequisites
|
||||
mkdir ../gcc-build
|
||||
cd ../gcc-build
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
set -ex
|
||||
source shared.sh
|
||||
|
||||
curl https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf -
|
||||
curl -L https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf -
|
||||
|
||||
cd git-2.10.0
|
||||
make configure
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ RUN sh /scripts/sccache.sh
|
|||
|
||||
ENV RUST_CONFIGURE_ARGS \
|
||||
--musl-root-x86_64=/musl-x86_64 \
|
||||
--enable-extended
|
||||
--enable-extended \
|
||||
--disable-docs
|
||||
|
||||
# Newer binutils broke things on some vms/distros (i.e., linking against
|
||||
# unknown relocs disabled by the following flag), so we need to go out of our
|
||||
|
|
|
|||
|
|
@ -33,5 +33,5 @@ ENV \
|
|||
|
||||
ENV HOSTS=x86_64-unknown-netbsd
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
|
|||
|
|
@ -27,6 +27,21 @@ travis_fold start build_docker
|
|||
travis_time_start
|
||||
|
||||
if [ -f "$docker_dir/$image/Dockerfile" ]; then
|
||||
if [ "$CI" != "" ]; then
|
||||
cksum=$(find $docker_dir/$image $docker_dir/scripts -type f | \
|
||||
sort | \
|
||||
xargs cat | \
|
||||
sha512sum | \
|
||||
awk '{print $1}')
|
||||
s3url="s3://$SCCACHE_BUCKET/docker/$cksum"
|
||||
url="https://s3-us-west-1.amazonaws.com/$SCCACHE_BUCKET/docker/$cksum"
|
||||
echo "Attempting to download $s3url"
|
||||
set +e
|
||||
loaded_images=$(curl $url | docker load | sed 's/.* sha/sha/')
|
||||
set -e
|
||||
echo "Downloaded containers:\n$loaded_images"
|
||||
fi
|
||||
|
||||
dockerfile="$docker_dir/$image/Dockerfile"
|
||||
if [ -x /usr/bin/cygpath ]; then
|
||||
context="`cygpath -w $docker_dir`"
|
||||
|
|
@ -40,6 +55,23 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
|
|||
-t rust-ci \
|
||||
-f "$dockerfile" \
|
||||
"$context"
|
||||
|
||||
if [ "$s3url" != "" ]; then
|
||||
digest=$(docker inspect rust-ci --format '{{.Id}}')
|
||||
echo "Built container $digest"
|
||||
if ! grep -q "$digest" <(echo "$loaded_images"); then
|
||||
echo "Uploading finished image to $s3url"
|
||||
set +e
|
||||
docker history -q rust-ci | \
|
||||
grep -v missing | \
|
||||
xargs docker save | \
|
||||
gzip | \
|
||||
aws s3 cp - $s3url
|
||||
set -e
|
||||
else
|
||||
echo "Looks like docker image is the same as before, not uploading"
|
||||
fi
|
||||
fi
|
||||
elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then
|
||||
if [ -n "$TRAVIS_OS_NAME" ]; then
|
||||
echo Cannot run disabled images on travis!
|
||||
|
|
@ -72,8 +104,6 @@ if [ "$SCCACHE_BUCKET" != "" ]; then
|
|||
args="$args --env SCCACHE_REGION"
|
||||
args="$args --env AWS_ACCESS_KEY_ID"
|
||||
args="$args --env AWS_SECRET_ACCESS_KEY"
|
||||
args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log"
|
||||
args="$args --volume $objdir/tmp:/tmp/sccache"
|
||||
else
|
||||
mkdir -p $HOME/.cache/sccache
|
||||
args="$args --env SCCACHE_DIR=/sccache --volume $HOME/.cache/sccache:/sccache"
|
||||
|
|
|
|||
|
|
@ -13,6 +13,6 @@
|
|||
set -ex
|
||||
|
||||
curl -fo /usr/local/bin/sccache \
|
||||
https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-05-12-sccache-x86_64-unknown-linux-musl
|
||||
https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-02-sccache-x86_64-unknown-linux-musl
|
||||
|
||||
chmod +x /usr/local/bin/sccache
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ ENV RUST_CONFIGURE_ARGS \
|
|||
--set rust.lld
|
||||
|
||||
ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \
|
||||
src/test/run-make \
|
||||
src/test/ui \
|
||||
src/test/run-pass \
|
||||
src/test/compile-fail \
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
ENV PARALLEL_CHECK 1
|
||||
ENV RUST_CONFIGURE_ARGS \
|
||||
--build=x86_64-unknown-linux-gnu \
|
||||
--enable-debug \
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
FROM ubuntu:16.04
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
g++ \
|
||||
make \
|
||||
file \
|
||||
curl \
|
||||
ca-certificates \
|
||||
python2.7 \
|
||||
git \
|
||||
cmake \
|
||||
sudo \
|
||||
gdb \
|
||||
xz-utils
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
|
||||
ENV RUSTFLAGS -Zincremental=/tmp/rust-incr-cache
|
||||
ENV RUST_CHECK_TARGET check
|
||||
ENV CARGO_INCREMENTAL 0
|
||||
|
|
@ -17,6 +17,7 @@ ci_dir=$(cd $(dirname $0) && pwd)
|
|||
. "$ci_dir/shared.sh"
|
||||
|
||||
travis_fold start init_repo
|
||||
travis_time_start
|
||||
|
||||
REPO_DIR="$1"
|
||||
CACHE_DIR="$2"
|
||||
|
|
@ -42,54 +43,39 @@ if grep -q RUST_RELEASE_CHANNEL=beta src/ci/run.sh; then
|
|||
git fetch origin --unshallow beta master
|
||||
fi
|
||||
|
||||
travis_fold start update_cache
|
||||
travis_time_start
|
||||
function fetch_submodule {
|
||||
local module=$1
|
||||
local cached="download-${module//\//-}.tar.gz"
|
||||
retry sh -c "rm -f $cached && \
|
||||
curl -sSL -o $cached $2"
|
||||
mkdir $module
|
||||
touch "$module/.git"
|
||||
tar -C $module --strip-components=1 -xf $cached
|
||||
rm $cached
|
||||
}
|
||||
|
||||
# Update the cache (a pristine copy of the rust source master)
|
||||
retry sh -c "rm -rf $cache_src_dir && mkdir -p $cache_src_dir && \
|
||||
git clone --depth 1 https://github.com/rust-lang/rust.git $cache_src_dir"
|
||||
if [ -d $cache_src_dir/src/llvm ]; then
|
||||
(cd $cache_src_dir && git rm src/llvm)
|
||||
fi
|
||||
if [ -d $cache_src_dir/src/llvm-emscripten ]; then
|
||||
(cd $cache_src_dir && git rm src/llvm-emscripten)
|
||||
fi
|
||||
retry sh -c "cd $cache_src_dir && \
|
||||
git submodule deinit -f . && git submodule sync && git submodule update --init"
|
||||
|
||||
travis_fold end update_cache
|
||||
travis_time_finish
|
||||
|
||||
travis_fold start update_submodules
|
||||
travis_time_start
|
||||
|
||||
# Update the submodules of the repo we're in, using the pristine repo as
|
||||
# a cache for any object files
|
||||
# No, `git submodule foreach` won't work:
|
||||
# http://stackoverflow.com/questions/12641469/list-submodules-in-a-git-repository
|
||||
included="src/llvm src/llvm-emscripten src/doc/book src/doc/rust-by-example"
|
||||
modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)"
|
||||
for module in $modules; do
|
||||
if [ "$module" = src/llvm ] || [ "$module" = src/llvm-emscripten ]; then
|
||||
modules=($modules)
|
||||
use_git=""
|
||||
urls="$(git config --file .gitmodules --get-regexp '\.url$' | cut -d' ' -f2)"
|
||||
urls=($urls)
|
||||
for i in ${!modules[@]}; do
|
||||
module=${modules[$i]}
|
||||
if [[ " $included " = *" $module "* ]]; then
|
||||
commit="$(git ls-tree HEAD $module | awk '{print $3}')"
|
||||
git rm $module
|
||||
retry sh -c "rm -f $commit.tar.gz && \
|
||||
curl -sSL -O https://github.com/rust-lang/llvm/archive/$commit.tar.gz"
|
||||
tar -C src/ -xf "$commit.tar.gz"
|
||||
rm "$commit.tar.gz"
|
||||
mv "src/llvm-$commit" $module
|
||||
url=${urls[$i]}
|
||||
url=${url/\.git/}
|
||||
fetch_submodule $module "$url/archive/$commit.tar.gz" &
|
||||
continue
|
||||
else
|
||||
use_git="$use_git $module"
|
||||
fi
|
||||
if [ ! -e "$cache_src_dir/$module/.git" ]; then
|
||||
echo "WARNING: $module not found in pristine repo"
|
||||
retry sh -c "git submodule deinit -f $module && \
|
||||
git submodule update --init --recursive $module"
|
||||
continue
|
||||
fi
|
||||
retry sh -c "git submodule deinit -f $module && \
|
||||
git submodule update --init --recursive --reference $cache_src_dir/$module $module"
|
||||
done
|
||||
|
||||
travis_fold end update_submodules
|
||||
travis_time_finish
|
||||
|
||||
retry sh -c "git submodule deinit -f $use_git && \
|
||||
git submodule sync && \
|
||||
git submodule update -j 16 --init --recursive $use_git"
|
||||
wait
|
||||
travis_fold end init_repo
|
||||
travis_time_finish
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ source "$ci_dir/shared.sh"
|
|||
|
||||
if [ "$TRAVIS" == "true" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests"
|
||||
else
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings"
|
||||
fi
|
||||
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache"
|
||||
|
|
@ -72,6 +74,13 @@ fi
|
|||
# sccache server at the start of the build, but no need to worry if this fails.
|
||||
SCCACHE_IDLE_TIMEOUT=10800 sccache --start-server || true
|
||||
|
||||
if [ "$PARALLEL_CHECK" != "" ]; then
|
||||
$SRC/configure --enable-experimental-parallel-queries
|
||||
python2.7 ../x.py check
|
||||
rm -f config.toml
|
||||
rm -rf build
|
||||
fi
|
||||
|
||||
travis_fold start configure
|
||||
travis_time_start
|
||||
$SRC/configure $RUST_CONFIGURE_ARGS
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 98921e9de849acdaeaed08cfad6758bb89769b7d
|
||||
Subproject commit b889e1e30c5e9953834aa9fa6c982bb28df46ac9
|
||||
|
|
@ -6,55 +6,72 @@ nav {
|
|||
}
|
||||
</style>
|
||||
|
||||
This page is an overview of the documentation included with your Rust install.
|
||||
Other unofficial documentation may exist elsewhere; for example, the [Rust
|
||||
Learning] project collects documentation from the community, and [Docs.rs]
|
||||
builds documentation for individual Rust packages.
|
||||
Welcome to an overview of the documentation provided by the Rust project.
|
||||
All of these projects are managed by the Docs Team; there are other
|
||||
unofficial documentation resources as well!
|
||||
|
||||
# API Documentation
|
||||
Many of these resources take the form of "books"; we collectively call these
|
||||
"The Rust Bookshelf." Some are large, some are small.
|
||||
|
||||
Rust provides a standard library with a number of features; [we host its
|
||||
documentation here][api].
|
||||
## Learn Rust
|
||||
|
||||
# Extended Error Documentation
|
||||
If you'd like to learn Rust, this is the spot for you! All of these resources
|
||||
assume that you have programmed before, but not in any specific language:
|
||||
|
||||
### The Rust Programming Language
|
||||
|
||||
Affectionately nicknamed "the book," [The Rust Programming
|
||||
Language](book/index.html) will give you an overview of the language from
|
||||
first principles. You'll build a few projects along the way, and by the end,
|
||||
you'll have a solid grasp of the language.
|
||||
|
||||
### Rust By Example
|
||||
|
||||
If reading multiple hundreds of pages about a language isn't your style, then
|
||||
[Rust By Example](rust-by-example/index.html) has you covered. While the book talks about code with
|
||||
a lot of words, RBE shows off a bunch of code, and keeps the talking to a
|
||||
minimum. It also includes exercises!
|
||||
|
||||
## Use Rust
|
||||
|
||||
Once you've gotten familliar with the language, these resources can help you
|
||||
when you're actually using it day-to-day.
|
||||
|
||||
### The Standard Library
|
||||
|
||||
Rust's standard library has [extensive API documentation](std/index.html),
|
||||
with explanations of how to use various things, as well as example code for
|
||||
accomplishing various tasks.
|
||||
|
||||
### The Cargo Book
|
||||
|
||||
[The Cargo Book](cargo/index.html) is a guide to Cargo, Rust's build tool and dependency manager.
|
||||
|
||||
### The Rustdoc Book
|
||||
|
||||
[The Rustdoc Book](rustdoc/index.html) describes our documentation tool, `rustdoc`.
|
||||
|
||||
### Extended Error Listing
|
||||
|
||||
Many of Rust's errors come with error codes, and you can request extended
|
||||
diagnostics from the compiler on those errors. We also [have the text of those
|
||||
extended errors on the web][err], if you prefer to read them that way.
|
||||
diagnostics from the compiler on those errors. You can also [read them
|
||||
here](error-index.html), if you prefer to read them that way.
|
||||
|
||||
# The Rust Bookshelf
|
||||
## Master Rust
|
||||
|
||||
Rust provides a number of book-length sets of documentation, collectively
|
||||
nicknamed 'The Rust Bookshelf.'
|
||||
Once you're quite familiar with the language, you may find these advanced
|
||||
resources useful.
|
||||
|
||||
* [The Rust Programming Language][book] teaches you how to program in Rust.
|
||||
* [Rust By Example][rbe] teaches you how to program in Rust using editable examples.
|
||||
* [The Cargo Book][cargo-book] is a guide to Cargo, Rust's build tool and dependency manager.
|
||||
* [The Unstable Book][unstable-book] has documentation for unstable features.
|
||||
* [The Rustonomicon][nomicon] is your guidebook to the dark arts of unsafe Rust.
|
||||
* [The Reference][ref] is not a formal spec, but is more detailed and comprehensive than the book.
|
||||
* [The Rustdoc Book][rustdoc-book] describes our documentation tool, `rustdoc`.
|
||||
### The Reference
|
||||
|
||||
Initially, documentation lands in the Unstable Book, and then, as part of the
|
||||
stabilization process, is moved into the Book, Nomicon, or Reference.
|
||||
[The Reference](reference/index.html) is not a formal spec, but is more detailed and
|
||||
comprehensive than the book.
|
||||
|
||||
Another few words about the reference: it is guaranteed to be accurate, but not
|
||||
complete. We have a policy that features must have documentation to be stabilized,
|
||||
but we did not always have this policy, and so there are some stable things that
|
||||
are not yet in the reference. We're working on back-filling things that landed
|
||||
before this policy was put into place. That work is being tracked
|
||||
[here][refchecklist].
|
||||
### The Rustonomicon
|
||||
|
||||
[Rust Learning]: https://github.com/ctjhoa/rust-learning
|
||||
[Docs.rs]: https://docs.rs/
|
||||
[api]: std/index.html
|
||||
[ref]: reference/index.html
|
||||
[refchecklist]: https://github.com/rust-lang-nursery/reference/issues/9
|
||||
[err]: error-index.html
|
||||
[book]: book/index.html
|
||||
[rbe]: rust-by-example/index.html
|
||||
[nomicon]: nomicon/index.html
|
||||
[unstable-book]: unstable-book/index.html
|
||||
[rustdoc-book]: rustdoc/index.html
|
||||
[cargo-book]: cargo/index.html
|
||||
[The Rustonomicon](nomicon/index.html) is your guidebook to the dark arts of unsafe
|
||||
Rust. It's also sometimes called "the 'nomicon."
|
||||
|
||||
### The Unstable Book
|
||||
|
||||
[The Unstable Book](unstable-book/index.html) has documentation for unstable features.
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit ad5ddd62c098d5b424151beda574ae7df2154df1
|
||||
Subproject commit 6a8f0a27e9a58c55c89d07bc43a176fdae5e051c
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 254df654a9b75abf6ca08806535dbe1fad41be3f
|
||||
Subproject commit 76296346e97c3702974d3398fdb94af9e10111a2
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit ebb28c95b2ea68b96eddb9e71aff4d32eacc74f0
|
||||
Subproject commit d5ec87eabe5733cc2348c7dada89fc67c086f391
|
||||
|
|
@ -5,3 +5,4 @@
|
|||
- [The `#[doc]` attribute](the-doc-attribute.md)
|
||||
- [Documentation tests](documentation-tests.md)
|
||||
- [Passes](passes.md)
|
||||
- [Unstable features](unstable-features.md)
|
||||
|
|
|
|||
375
src/doc/rustdoc/src/unstable-features.md
Normal file
375
src/doc/rustdoc/src/unstable-features.md
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
# Unstable features
|
||||
|
||||
Rustdoc is under active developement, and like the Rust compiler, some features are only available
|
||||
on the nightly releases. Some of these are new and need some more testing before they're able to get
|
||||
released to the world at large, and some of them are tied to features in the Rust compiler that are
|
||||
themselves unstable. Several features here require a matching `#![feature(...)]` attribute to
|
||||
enable, and thus are more fully documented in the [Unstable Book]. Those sections will link over
|
||||
there as necessary.
|
||||
|
||||
[Unstable Book]: ../unstable-book/index.html
|
||||
|
||||
## Nightly-gated functionality
|
||||
|
||||
These features just require a nightly build to operate. Unlike the other features on this page,
|
||||
these don't need to be "turned on" with a command-line flag or a `#![feature(...)]` attribute in
|
||||
your crate. This can give them some subtle fallback modes when used on a stable release, so be
|
||||
careful!
|
||||
|
||||
### Error numbers for `compile-fail` doctests
|
||||
|
||||
As detailed in [the chapter on documentation tests][doctest-attributes], you can add a
|
||||
`compile_fail` attribute to a doctest to state that the test should fail to compile. However, on
|
||||
nightly, you can optionally add an error number to state that a doctest should emit a specific error
|
||||
number:
|
||||
|
||||
[doctest-attributes]: documentation-tests.html#attributes
|
||||
|
||||
``````markdown
|
||||
```compile_fail,E0044
|
||||
extern { fn some_func<T>(x: T); }
|
||||
```
|
||||
``````
|
||||
|
||||
This is used by the error index to ensure that the samples that correspond to a given error number
|
||||
properly emit that error code. However, these error codes aren't guaranteed to be the only thing
|
||||
that a piece of code emits from version to version, so this is unlikely to be stabilized in the
|
||||
future.
|
||||
|
||||
Attempting to use these error numbers on stable will result in the code sample being interpreted as
|
||||
plain text.
|
||||
|
||||
### Linking to items by type
|
||||
|
||||
As designed in [RFC 1946], Rustdoc can parse paths to items when you use them as links. To resolve
|
||||
these type names, it uses the items currently in-scope, either by declaration or by `use` statement.
|
||||
For modules, the "active scope" depends on whether the documentation is written outside the module
|
||||
(as `///` comments on the `mod` statement) or inside the module (at `//!` comments inside the file
|
||||
or block). For all other items, it uses the enclosing module's scope.
|
||||
|
||||
[RFC 1946]: https://github.com/rust-lang/rfcs/pull/1946
|
||||
|
||||
For example, in the following code:
|
||||
|
||||
```rust
|
||||
/// Does the thing.
|
||||
pub fn do_the_thing(_: SomeType) {
|
||||
println!("Let's do the thing!");
|
||||
}
|
||||
|
||||
/// Token you use to [`do_the_thing`].
|
||||
pub struct SomeType;
|
||||
```
|
||||
|
||||
The link to ``[`do_the_thing`]`` in `SomeType`'s docs will properly link to the page for `fn
|
||||
do_the_thing`. Note that here, rustdoc will insert the link target for you, but manually writing the
|
||||
target out also works:
|
||||
|
||||
```rust
|
||||
pub mod some_module {
|
||||
/// Token you use to do the thing.
|
||||
pub struct SomeStruct;
|
||||
}
|
||||
|
||||
/// Does the thing. Requires one [`SomeStruct`] for the thing to work.
|
||||
///
|
||||
/// [`SomeStruct`]: some_module::SomeStruct
|
||||
pub fn do_the_thing(_: some_module::SomeStruct) {
|
||||
println!("Let's do the thing!");
|
||||
}
|
||||
```
|
||||
|
||||
For more details, check out [the RFC][RFC 1946], and see [the tracking issue][43466] for more
|
||||
information about what parts of the feature are available.
|
||||
|
||||
[43466]: https://github.com/rust-lang/rust/issues/43466
|
||||
|
||||
## Extensions to the `#[doc]` attribute
|
||||
|
||||
These features operate by extending the `#[doc]` attribute, and thus can be caught by the compiler
|
||||
and enabled with a `#![feature(...)]` attribute in your crate.
|
||||
|
||||
### Documenting platform-/feature-specific information
|
||||
|
||||
Because of the way Rustdoc documents a crate, the documentation it creates is specific to the target
|
||||
rustc compiles for. Anything that's specific to any other target is dropped via `#[cfg]` attribute
|
||||
processing early in the compilation process. However, Rustdoc has a trick up its sleeve to handle
|
||||
platform-specific code if it *does* receive it.
|
||||
|
||||
Because Rustdoc doesn't need to fully compile a crate to binary, it replaces function bodies with
|
||||
`loop {}` to prevent having to process more than necessary. This means that any code within a
|
||||
function that requires platform-specific pieces is ignored. Combined with a special attribute,
|
||||
`#[doc(cfg(...))]`, you can tell Rustdoc exactly which platform something is supposed to run on,
|
||||
ensuring that doctests are only run on the appropriate platforms.
|
||||
|
||||
The `#[doc(cfg(...))]` attribute has another effect: When Rustdoc renders documentation for that
|
||||
item, it will be accompanied by a banner explaining that the item is only available on certain
|
||||
platforms.
|
||||
|
||||
As mentioned earlier, getting the items to Rustdoc requires some extra preparation. The standard
|
||||
library adds a `--cfg dox` flag to every Rustdoc command, but the same thing can be accomplished by
|
||||
adding a feature to your Cargo.toml and adding `--feature dox` (or whatever you choose to name the
|
||||
feature) to your `cargo doc` calls.
|
||||
|
||||
Either way, once you create an environment for the documentation, you can start to augment your
|
||||
`#[cfg]` attributes to allow both the target platform *and* the documentation configuration to leave
|
||||
the item in. For example, `#[cfg(any(windows, feature = "dox"))]` will preserve the item either on
|
||||
Windows or during the documentation process. Then, adding a new attribute `#[doc(cfg(windows))]`
|
||||
will tell Rustdoc that the item is supposed to be used on Windows. For example:
|
||||
|
||||
```rust
|
||||
#![feature(doc_cfg)]
|
||||
|
||||
/// Token struct that can only be used on Windows.
|
||||
#[cfg(any(windows, feature = "dox"))]
|
||||
#[doc(cfg(windows))]
|
||||
pub struct WindowsToken;
|
||||
|
||||
/// Token struct that can only be used on Unix.
|
||||
#[cfg(any(unix, feature = "dox"))]
|
||||
#[doc(cfg(unix))]
|
||||
pub struct UnixToken;
|
||||
```
|
||||
|
||||
In this sample, the tokens will only appear on their respective platforms, but they will both appear
|
||||
in documentation.
|
||||
|
||||
`#[doc(cfg(...))]` was introduced to be used by the standard library and currently requires the
|
||||
`#![feature(doc_cfg)]` feature gate. For more information, see [its chapter in the Unstable
|
||||
Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg].
|
||||
|
||||
[unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html
|
||||
[issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781
|
||||
|
||||
### Adding your trait to the "Important Traits" dialog
|
||||
|
||||
Rustdoc keeps a list of a few traits that are believed to be "fundamental" to a given type when
|
||||
implemented on it. These traits are intended to be the primary interface for their types, and are
|
||||
often the only thing available to be documented on their types. For this reason, Rustdoc will track
|
||||
when a given type implements one of these traits and call special attention to it when a function
|
||||
returns one of these types. This is the "Important Traits" dialog, visible as a circle-i button next
|
||||
to the function, which, when clicked, shows the dialog.
|
||||
|
||||
In the standard library, the traits that qualify for inclusion are `Iterator`, `io::Read`, and
|
||||
`io::Write`. However, rather than being implemented as a hard-coded list, these traits have a
|
||||
special marker attribute on them: `#[doc(spotlight)]`. This means that you could apply this
|
||||
attribute to your own trait to include it in the "Important Traits" dialog in documentation.
|
||||
|
||||
The `#[doc(spotlight)]` attribute currently requires the `#![feature(doc_spotlight)]` feature gate.
|
||||
For more information, see [its chapter in the Unstable Book][unstable-spotlight] and [its tracking
|
||||
issue][issue-spotlight].
|
||||
|
||||
[unstable-spotlight]: ../unstable-book/language-features/doc-spotlight.html
|
||||
[issue-spotlight]: https://github.com/rust-lang/rust/issues/45040
|
||||
|
||||
### Exclude certain dependencies from documentation
|
||||
|
||||
The standard library uses several dependencies which, in turn, use several types and traits from the
|
||||
standard library. In addition, there are several compiler-internal crates that are not considered to
|
||||
be part of the official standard library, and thus would be a distraction to include in
|
||||
documentation. It's not enough to exclude their crate documentation, since information about trait
|
||||
implementations appears on the pages for both the type and the trait, which can be in different
|
||||
crates!
|
||||
|
||||
To prevent internal types from being included in documentation, the standard library adds an
|
||||
attribute to their `extern crate` declarations: `#[doc(masked)]`. This causes Rustdoc to "mask out"
|
||||
types from these crates when building lists of trait implementations.
|
||||
|
||||
The `#[doc(masked)]` attribute is intended to be used internally, and requires the
|
||||
`#![feature(doc_masked)]` feature gate. For more information, see [its chapter in the Unstable
|
||||
Book][unstable-masked] and [its tracking issue][issue-masked].
|
||||
|
||||
[unstable-masked]: ../unstable-book/language-features/doc-masked.html
|
||||
[issue-masked]: https://github.com/rust-lang/rust/issues/44027
|
||||
|
||||
### Include external files as API documentation
|
||||
|
||||
As designed in [RFC 1990], Rustdoc can read an external file to use as a type's documentation. This
|
||||
is useful if certain documentation is so long that it would break the flow of reading the source.
|
||||
Instead of writing it all inline, writing `#[doc(include = "sometype.md")]` (where `sometype.md` is
|
||||
a file adjacent to the `lib.rs` for the crate) will ask Rustdoc to instead read that file and use it
|
||||
as if it were written inline.
|
||||
|
||||
[RFC 1990]: https://github.com/rust-lang/rfcs/pull/1990
|
||||
|
||||
`#[doc(include = "...")]` currently requires the `#![feature(external_doc)]` feature gate. For more
|
||||
information, see [its chapter in the Unstable Book][unstable-include] and [its tracking
|
||||
issue][issue-include].
|
||||
|
||||
[unstable-include]: ../unstable-book/language-features/external-doc.html
|
||||
[issue-include]: https://github.com/rust-lang/rust/issues/44732
|
||||
|
||||
## Unstable command-line arguments
|
||||
|
||||
These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are
|
||||
themselves marked as unstable. To use any of these options, pass `-Z unstable-options` as well as
|
||||
the flag in question to Rustdoc on the command-line. To do this from Cargo, you can either use the
|
||||
`RUSTDOCFLAGS` environment variable or the `cargo rustdoc` command.
|
||||
|
||||
### `--markdown-before-content`: include rendered Markdown before the content
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
```bash
|
||||
$ rustdoc src/lib.rs -Z unstable-options --markdown-before-content extra.md
|
||||
$ rustdoc README.md -Z unstable-options --markdown-before-content extra.md
|
||||
```
|
||||
|
||||
Just like `--html-before-content`, this allows you to insert extra content inside the `<body>` tag
|
||||
but before the other content `rustdoc` would normally produce in the rendered documentation.
|
||||
However, instead of directly inserting the file verbatim, `rustdoc` will pass the files through a
|
||||
Markdown renderer before inserting the result into the file.
|
||||
|
||||
### `--markdown-after-content`: include rendered Markdown after the content
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
```bash
|
||||
$ rustdoc src/lib.rs -Z unstable-options --markdown-after-content extra.md
|
||||
$ rustdoc README.md -Z unstable-options --markdown-after-content extra.md
|
||||
```
|
||||
|
||||
Just like `--html-after-content`, this allows you to insert extra content before the `</body>` tag
|
||||
but after the other content `rustdoc` would normally produce in the rendered documentation.
|
||||
However, instead of directly inserting the file verbatim, `rustdoc` will pass the files through a
|
||||
Markdown renderer before inserting the result into the file.
|
||||
|
||||
### `--playground-url`: control the location of the playground
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
```bash
|
||||
$ rustdoc src/lib.rs -Z unstable-options --playground-url https://play.rust-lang.org/
|
||||
```
|
||||
|
||||
When rendering a crate's docs, this flag gives the base URL of the Rust Playground, to use for
|
||||
generating `Run` buttons. Unlike `--markdown-playground-url`, this argument works for standalone
|
||||
Markdown files *and* Rust crates. This works the same way as adding `#![doc(html_playground_url =
|
||||
"url")]` to your crate root, as mentioned in [the chapter about the `#[doc]`
|
||||
attribute][doc-playground]. Please be aware that the official Rust Playground at
|
||||
https://play.rust-lang.org does not have every crate available, so if your examples require your
|
||||
crate, make sure the playground you provide has your crate available.
|
||||
|
||||
[doc-playground]: the-doc-attribute.html#html_playground_url
|
||||
|
||||
If both `--playground-url` and `--markdown-playground-url` are present when rendering a standalone
|
||||
Markdown file, the URL given to `--markdown-playground-url` will take precedence. If both
|
||||
`--playground-url` and `#![doc(html_playground_url = "url")]` are present when rendering crate docs,
|
||||
the attribute will take precedence.
|
||||
|
||||
### `--crate-version`: control the crate version
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
```bash
|
||||
$ rustdoc src/lib.rs -Z unstable-options --crate-version 1.3.37
|
||||
```
|
||||
|
||||
When `rustdoc` receives this flag, it will print an extra "Version (version)" into the sidebar of
|
||||
the crate root's docs. You can use this flag to differentiate between different versions of your
|
||||
library's documentation.
|
||||
|
||||
### `--linker`: control the linker used for documentation tests
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
```bash
|
||||
$ rustdoc --test src/lib.rs -Z unstable-options --linker foo
|
||||
$ rustdoc --test README.md -Z unstable-options --linker foo
|
||||
```
|
||||
|
||||
When `rustdoc` runs your documentation tests, it needs to compile and link the tests as executables
|
||||
before running them. This flag can be used to change the linker used on these executables. It's
|
||||
equivalent to passing `-C linker=foo` to `rustc`.
|
||||
|
||||
### `--sort-modules-by-appearance`: control how items on module pages are sorted
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
```bash
|
||||
$ rustdoc src/lib.rs -Z unstable-options --sort-modules-by-appearance
|
||||
```
|
||||
|
||||
Ordinarily, when `rustdoc` prints items in module pages, it will sort them alphabetically (taking
|
||||
some consideration for their stability, and names that end in a number). Giving this flag to
|
||||
`rustdoc` will disable this sorting and instead make it print the items in the order they appear in
|
||||
the source.
|
||||
|
||||
### `--themes`: provide additional themes
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
```bash
|
||||
$ rustdoc src/lib.rs -Z unstable-options --themes theme.css
|
||||
```
|
||||
|
||||
Giving this flag to `rustdoc` will make it copy your theme into the generated crate docs and enable
|
||||
it in the theme selector. Note that `rustdoc` will reject your theme file if it doesn't style
|
||||
everything the "light" theme does. See `--theme-checker` below for details.
|
||||
|
||||
### `--theme-checker`: verify theme CSS for validity
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
```bash
|
||||
$ rustdoc -Z unstable-options --theme-checker theme.css
|
||||
```
|
||||
|
||||
Before including your theme in crate docs, `rustdoc` will compare all the CSS rules it contains
|
||||
against the "light" theme included by default. Using this flag will allow you to see which rules are
|
||||
missing if `rustdoc` rejects your theme.
|
||||
|
||||
### `--resource-suffix`: modifying the name of CSS/JavaScript in crate docs
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
```bash
|
||||
$ rustdoc src/lib.rs -Z unstable-options --resource-suffix suf
|
||||
```
|
||||
|
||||
When rendering docs, `rustdoc` creates several CSS and JavaScript files as part of the output. Since
|
||||
all these files are linked from every page, changing where they are can be cumbersome if you need to
|
||||
specially cache them. This flag will rename all these files in the output to include the suffix in
|
||||
the filename. For example, `light.css` would become `light-suf.css` with the above command.
|
||||
|
||||
### `--display-warnings`: display warnings when documenting or running documentation tests
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
```bash
|
||||
$ rustdoc src/lib.rs -Z unstable-options --display-warnings
|
||||
$ rustdoc --test src/lib.rs -Z unstable-options --display-warnings
|
||||
```
|
||||
|
||||
The intent behind this flag is to allow the user to see warnings that occur within their library or
|
||||
their documentation tests, which are usually suppressed. However, [due to a
|
||||
bug][issue-display-warnings], this flag doesn't 100% work as intended. See the linked issue for
|
||||
details.
|
||||
|
||||
[issue-display-warnings]: https://github.com/rust-lang/rust/issues/41574
|
||||
|
||||
### `--edition`: control the edition of docs and doctests
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
```bash
|
||||
$ rustdoc src/lib.rs -Z unstable-options --edition 2018
|
||||
$ rustdoc --test src/lib.rs -Z unstable-options --edition 2018
|
||||
```
|
||||
|
||||
This flag allows rustdoc to treat your rust code as the given edition. It will compile doctests with
|
||||
the given edition as well. As with `rustc`, the default edition that `rustdoc` will use is `2015`
|
||||
(the first edition).
|
||||
|
||||
### `-Z force-unstable-if-unmarked`
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
```bash
|
||||
$ rustdoc src/lib.rs -Z force-unstable-if-unmarked
|
||||
```
|
||||
|
||||
This is an internal flag intended for the standard library and compiler that applies an
|
||||
`#[unstable]` attribute to any dependent crate that doesn't have another stability attribute. This
|
||||
allows `rustdoc` to be able to generate documentation for the compiler crates and the standard
|
||||
library, as an equivalent command-line argument is provided to `rustc` when building those crates.
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
# `conservative_impl_trait`
|
||||
|
||||
The tracking issue for this feature is: [#34511]
|
||||
|
||||
[#34511]: https://github.com/rust-lang/rust/issues/34511
|
||||
|
||||
------------------------
|
||||
|
||||
The `conservative_impl_trait` feature allows a conservative form of abstract
|
||||
return types.
|
||||
|
||||
Abstract return types allow a function to hide a concrete return type behind a
|
||||
trait interface similar to trait objects, while still generating the same
|
||||
statically dispatched code as with concrete types.
|
||||
|
||||
## Examples
|
||||
|
||||
```rust
|
||||
#![feature(conservative_impl_trait)]
|
||||
|
||||
fn even_iter() -> impl Iterator<Item=u32> {
|
||||
(0..).map(|n| n * 2)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let first_four_even_numbers = even_iter().take(4).collect::<Vec<_>>();
|
||||
assert_eq!(first_four_even_numbers, vec![0, 2, 4, 6]);
|
||||
}
|
||||
```
|
||||
|
||||
## Background
|
||||
|
||||
In today's Rust, you can write function signatures like:
|
||||
|
||||
````rust,ignore
|
||||
fn consume_iter_static<I: Iterator<Item=u8>>(iter: I) { }
|
||||
|
||||
fn consume_iter_dynamic(iter: Box<Iterator<Item=u8>>) { }
|
||||
````
|
||||
|
||||
In both cases, the function does not depend on the exact type of the argument.
|
||||
The type held is "abstract", and is assumed only to satisfy a trait bound.
|
||||
|
||||
* In the `_static` version using generics, each use of the function is
|
||||
specialized to a concrete, statically-known type, giving static dispatch,
|
||||
inline layout, and other performance wins.
|
||||
* In the `_dynamic` version using trait objects, the concrete argument type is
|
||||
only known at runtime using a vtable.
|
||||
|
||||
On the other hand, while you can write:
|
||||
|
||||
````rust,ignore
|
||||
fn produce_iter_dynamic() -> Box<Iterator<Item=u8>> { }
|
||||
````
|
||||
|
||||
...but you _cannot_ write something like:
|
||||
|
||||
````rust,ignore
|
||||
fn produce_iter_static() -> Iterator<Item=u8> { }
|
||||
````
|
||||
|
||||
That is, in today's Rust, abstract return types can only be written using trait
|
||||
objects, which can be a significant performance penalty. This RFC proposes
|
||||
"unboxed abstract types" as a way of achieving signatures like
|
||||
`produce_iter_static`. Like generics, unboxed abstract types guarantee static
|
||||
dispatch and inline data layout.
|
||||
|
|
@ -36,11 +36,11 @@ fn main() {
|
|||
return "foo"
|
||||
};
|
||||
|
||||
match generator.resume() {
|
||||
match unsafe { generator.resume() } {
|
||||
GeneratorState::Yielded(1) => {}
|
||||
_ => panic!("unexpected value from resume"),
|
||||
}
|
||||
match generator.resume() {
|
||||
match unsafe { generator.resume() } {
|
||||
GeneratorState::Complete("foo") => {}
|
||||
_ => panic!("unexpected value from resume"),
|
||||
}
|
||||
|
|
@ -69,9 +69,9 @@ fn main() {
|
|||
};
|
||||
|
||||
println!("1");
|
||||
generator.resume();
|
||||
unsafe { generator.resume() };
|
||||
println!("3");
|
||||
generator.resume();
|
||||
unsafe { generator.resume() };
|
||||
println!("5");
|
||||
}
|
||||
```
|
||||
|
|
@ -92,7 +92,7 @@ The `Generator` trait in `std::ops` currently looks like:
|
|||
pub trait Generator {
|
||||
type Yield;
|
||||
type Return;
|
||||
fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;
|
||||
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -175,8 +175,8 @@ fn main() {
|
|||
return ret
|
||||
};
|
||||
|
||||
generator.resume();
|
||||
generator.resume();
|
||||
unsafe { generator.resume() };
|
||||
unsafe { generator.resume() };
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -200,7 +200,7 @@ fn main() {
|
|||
type Yield = i32;
|
||||
type Return = &'static str;
|
||||
|
||||
fn resume(&mut self) -> GeneratorState<i32, &'static str> {
|
||||
unsafe fn resume(&mut self) -> GeneratorState<i32, &'static str> {
|
||||
use std::mem;
|
||||
match mem::replace(self, __Generator::Done) {
|
||||
__Generator::Start(s) => {
|
||||
|
|
@ -223,8 +223,8 @@ fn main() {
|
|||
__Generator::Start(ret)
|
||||
};
|
||||
|
||||
generator.resume();
|
||||
generator.resume();
|
||||
unsafe { generator.resume() };
|
||||
unsafe { generator.resume() };
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
# `i128_type`
|
||||
|
||||
The tracking issue for this feature is: [#35118]
|
||||
|
||||
[#35118]: https://github.com/rust-lang/rust/issues/35118
|
||||
|
||||
------------------------
|
||||
|
||||
The `i128_type` feature adds support for 128 bit signed and unsigned integer
|
||||
types.
|
||||
|
||||
```rust
|
||||
#![feature(i128_type)]
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1u128 + 1u128, 2u128);
|
||||
assert_eq!(u128::min_value(), 0);
|
||||
assert_eq!(u128::max_value(), 340282366920938463463374607431768211455);
|
||||
|
||||
assert_eq!(1i128 - 2i128, -1i128);
|
||||
assert_eq!(i128::min_value(), -170141183460469231731687303715884105728);
|
||||
assert_eq!(i128::max_value(), 170141183460469231731687303715884105727);
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
# `match_default_bindings`
|
||||
|
||||
The tracking issue for this feature is: [#42640]
|
||||
|
||||
[#42640]: https://github.com/rust-lang/rust/issues/42640
|
||||
|
||||
------------------------
|
||||
|
||||
Match default bindings (also called "default binding modes in match") improves ergonomics for
|
||||
pattern-matching on references by introducing automatic dereferencing (and a corresponding shift
|
||||
in binding modes) for large classes of patterns that would otherwise not compile.
|
||||
|
||||
For example, under match default bindings,
|
||||
|
||||
```rust
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
fn main() {
|
||||
let x: &Option<_> = &Some(0);
|
||||
|
||||
match x {
|
||||
Some(y) => {
|
||||
println!("y={}", *y);
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
compiles and is equivalent to either of the below:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x: &Option<_> = &Some(0);
|
||||
|
||||
match *x {
|
||||
Some(ref y) => {
|
||||
println!("y={}", *y);
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x: &Option<_> = &Some(0);
|
||||
|
||||
match x {
|
||||
&Some(ref y) => {
|
||||
println!("y={}", *y);
|
||||
},
|
||||
&None => {},
|
||||
}
|
||||
}
|
||||
```
|
||||
18
src/doc/unstable-book/src/language-features/repr128.md
Normal file
18
src/doc/unstable-book/src/language-features/repr128.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# `repr128`
|
||||
|
||||
The tracking issue for this feature is: [#35118]
|
||||
|
||||
[#35118]: https://github.com/rust-lang/rust/issues/35118
|
||||
|
||||
------------------------
|
||||
|
||||
The `repr128` feature adds support for `#[repr(u128)]` on `enum`s.
|
||||
|
||||
```rust
|
||||
#![feature(repr128)]
|
||||
|
||||
#[repr(u128)]
|
||||
enum Foo {
|
||||
Bar(u64),
|
||||
}
|
||||
```
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
# `universal_impl_trait`
|
||||
|
||||
The tracking issue for this feature is: [#34511].
|
||||
|
||||
[#34511]: https://github.com/rust-lang/rust/issues/34511
|
||||
|
||||
--------------------
|
||||
|
||||
The `universal_impl_trait` feature extends the [`conservative_impl_trait`]
|
||||
feature allowing the `impl Trait` syntax in arguments (universal
|
||||
quantification).
|
||||
|
||||
[`conservative_impl_trait`]: ./language-features/conservative-impl-trait.html
|
||||
|
||||
## Examples
|
||||
|
||||
```rust
|
||||
#![feature(universal_impl_trait)]
|
||||
use std::ops::Not;
|
||||
|
||||
fn any_zero(values: impl IntoIterator<Item = i32>) -> bool {
|
||||
for val in values { if val == 0 { return true; } }
|
||||
false
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let test1 = -5..;
|
||||
let test2 = vec![1, 8, 42, -87, 60];
|
||||
assert!(any_zero(test1));
|
||||
assert!(bool::not(any_zero(test2)));
|
||||
}
|
||||
```
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
# `splice`
|
||||
|
||||
The tracking issue for this feature is: [#44643]
|
||||
|
||||
[#44643]: https://github.com/rust-lang/rust/issues/44643
|
||||
|
||||
------------------------
|
||||
|
||||
The `splice()` method on `String` allows you to replace a range
|
||||
of values in a string with another range of values.
|
||||
|
||||
A simple example:
|
||||
|
||||
```rust
|
||||
#![feature(splice)]
|
||||
let mut s = String::from("α is alpha, β is beta");
|
||||
let beta_offset = s.find('β').unwrap_or(s.len());
|
||||
|
||||
// Replace the range up until the β from the string
|
||||
s.splice(..beta_offset, "Α is capital alpha; ");
|
||||
assert_eq!(s, "Α is capital alpha; β is beta");
|
||||
```
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
# `string_retain`
|
||||
|
||||
The tracking issue for this feature is: [#43874]
|
||||
|
||||
[#43874]: https://github.com/rust-lang/rust/issues/43874
|
||||
|
||||
------------------------
|
||||
|
||||
Retains only the characters specified by the predicate.
|
||||
|
||||
In other words, remove all characters `c` such that `f(c)` returns `false`.
|
||||
This method operates in place and preserves the order of the retained
|
||||
characters.
|
||||
|
||||
```rust
|
||||
#![feature(string_retain)]
|
||||
|
||||
let mut s = String::from("f_o_ob_ar");
|
||||
|
||||
s.retain(|c| c != '_');
|
||||
|
||||
assert_eq!(s, "foobar");
|
||||
```
|
||||
|
|
@ -63,6 +63,11 @@ done
|
|||
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
# use gnu version of tool if available (for bsd)
|
||||
if command -v "g${GREPPER}"; then
|
||||
GREPPER="g${GREPPER}"
|
||||
fi
|
||||
|
||||
LOG=$(mktemp -t cgrep.XXXXXX)
|
||||
trap "rm -f $LOG" EXIT
|
||||
|
||||
|
|
|
|||
|
|
@ -1400,7 +1400,6 @@ nonblock_expr
|
|||
| BREAK lifetime { $$ = mk_node("ExprBreak", 1, $2); }
|
||||
| YIELD { $$ = mk_node("ExprYield", 0); }
|
||||
| YIELD expr { $$ = mk_node("ExprYield", 1, $2); }
|
||||
| nonblock_expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); }
|
||||
| nonblock_expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); }
|
||||
| nonblock_expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
|
||||
| nonblock_expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
|
||||
|
|
@ -1463,7 +1462,6 @@ expr
|
|||
| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); }
|
||||
| YIELD { $$ = mk_node("ExprYield", 0); }
|
||||
| YIELD expr { $$ = mk_node("ExprYield", 1, $2); }
|
||||
| expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); }
|
||||
| expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); }
|
||||
| expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
|
||||
| expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
|
||||
|
|
@ -1527,7 +1525,6 @@ expr_nostruct
|
|||
| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); }
|
||||
| YIELD { $$ = mk_node("ExprYield", 0); }
|
||||
| YIELD expr { $$ = mk_node("ExprYield", 1, $2); }
|
||||
| expr_nostruct LARROW expr_nostruct { $$ = mk_node("ExprInPlace", 2, $1, $3); }
|
||||
| expr_nostruct '=' expr_nostruct { $$ = mk_node("ExprAssign", 2, $1, $3); }
|
||||
| expr_nostruct SHLEQ expr_nostruct { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
|
||||
| expr_nostruct SHREQ expr_nostruct { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
|
|||
use core::borrow;
|
||||
use core::fmt;
|
||||
use core::cmp::Ordering;
|
||||
use core::heap::{Alloc, Layout};
|
||||
use core::intrinsics::abort;
|
||||
use core::mem::{self, align_of_val, size_of_val, uninitialized};
|
||||
use core::ops::Deref;
|
||||
|
|
@ -31,7 +32,7 @@ use core::hash::{Hash, Hasher};
|
|||
use core::{isize, usize};
|
||||
use core::convert::From;
|
||||
|
||||
use heap::{Heap, Alloc, Layout, box_free};
|
||||
use heap::{Heap, box_free};
|
||||
use boxed::Box;
|
||||
use string::String;
|
||||
use vec::Vec;
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@
|
|||
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(i128_type)]
|
||||
#![cfg_attr(stage0, feature(i128_type))]
|
||||
#![feature(rand)]
|
||||
#![feature(repr_simd)]
|
||||
#![feature(slice_sort_by_cached_key)]
|
||||
#![feature(test)]
|
||||
|
||||
extern crate rand;
|
||||
|
|
|
|||
|
|
@ -284,6 +284,17 @@ macro_rules! sort_expensive {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! sort_lexicographic {
|
||||
($f:ident, $name:ident, $gen:expr, $len:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let v = $gen($len);
|
||||
b.iter(|| v.clone().$f(|x| x.to_string()));
|
||||
b.bytes = $len * mem::size_of_val(&$gen(1)[0]) as u64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort!(sort, sort_small_ascending, gen_ascending, 10);
|
||||
sort!(sort, sort_small_descending, gen_descending, 10);
|
||||
sort!(sort, sort_small_random, gen_random, 10);
|
||||
|
|
@ -312,6 +323,10 @@ sort!(sort_unstable, sort_unstable_large_big, gen_big_random, 10000);
|
|||
sort_strings!(sort_unstable, sort_unstable_large_strings, gen_strings, 10000);
|
||||
sort_expensive!(sort_unstable_by, sort_unstable_large_expensive, gen_random, 10000);
|
||||
|
||||
sort_lexicographic!(sort_by_key, sort_by_key_lexicographic, gen_random, 10000);
|
||||
sort_lexicographic!(sort_unstable_by_key, sort_unstable_by_key_lexicographic, gen_random, 10000);
|
||||
sort_lexicographic!(sort_by_cached_key, sort_by_cached_key_lexicographic, gen_random, 10000);
|
||||
|
||||
macro_rules! reverse {
|
||||
($name:ident, $ty:ty, $f:expr) => {
|
||||
#[bench]
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@
|
|||
#![allow(missing_docs)]
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use core::ops::{Deref, DerefMut, Place, Placer, InPlace};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::iter::{FromIterator, FusedIterator};
|
||||
use core::mem::{swap, size_of};
|
||||
use core::ptr;
|
||||
|
|
@ -509,6 +509,31 @@ impl<T: Ord> BinaryHeap<T> {
|
|||
self.data.shrink_to_fit();
|
||||
}
|
||||
|
||||
/// Discards capacity with a lower bound.
|
||||
///
|
||||
/// The capacity will remain at least as large as both the length
|
||||
/// and the supplied value.
|
||||
///
|
||||
/// Panics if the current capacity is smaller than the supplied
|
||||
/// minimum capacity.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(shrink_to)]
|
||||
/// use std::collections::BinaryHeap;
|
||||
/// let mut heap: BinaryHeap<i32> = BinaryHeap::with_capacity(100);
|
||||
///
|
||||
/// assert!(heap.capacity() >= 100);
|
||||
/// heap.shrink_to(10);
|
||||
/// assert!(heap.capacity() >= 10);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "shrink_to", reason = "new API", issue="0")]
|
||||
pub fn shrink_to(&mut self, min_capacity: usize) {
|
||||
self.data.shrink_to(min_capacity)
|
||||
}
|
||||
|
||||
/// Removes the greatest item from the binary heap and returns it, or `None` if it
|
||||
/// is empty.
|
||||
///
|
||||
|
|
@ -1170,67 +1195,3 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap<T> {
|
|||
self.extend(iter.into_iter().cloned());
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
pub struct BinaryHeapPlace<'a, T: 'a>
|
||||
where T: Clone + Ord {
|
||||
heap: *mut BinaryHeap<T>,
|
||||
place: vec::PlaceBack<'a, T>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T: Clone + Ord + fmt::Debug> fmt::Debug for BinaryHeapPlace<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("BinaryHeapPlace")
|
||||
.field(&self.place)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T: 'a> Placer<T> for &'a mut BinaryHeap<T>
|
||||
where T: Clone + Ord {
|
||||
type Place = BinaryHeapPlace<'a, T>;
|
||||
|
||||
fn make_place(self) -> Self::Place {
|
||||
let ptr = self as *mut BinaryHeap<T>;
|
||||
let place = Placer::make_place(self.data.place_back());
|
||||
BinaryHeapPlace {
|
||||
heap: ptr,
|
||||
place,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
unsafe impl<'a, T> Place<T> for BinaryHeapPlace<'a, T>
|
||||
where T: Clone + Ord {
|
||||
fn pointer(&mut self) -> *mut T {
|
||||
self.place.pointer()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T> InPlace<T> for BinaryHeapPlace<'a, T>
|
||||
where T: Clone + Ord {
|
||||
type Owner = &'a T;
|
||||
|
||||
unsafe fn finalize(self) -> &'a T {
|
||||
self.place.finalize();
|
||||
|
||||
let heap: &mut BinaryHeap<T> = &mut *self.heap;
|
||||
let len = heap.len();
|
||||
let i = heap.sift_up(0, len - 1);
|
||||
heap.data.get_unchecked(i)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ pub trait ToOwned {
|
|||
/// let vv: Vec<i32> = v.to_owned();
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[must_use = "cloning is often expensive and is not expected to have side effects"]
|
||||
fn to_owned(&self) -> Self::Owned;
|
||||
|
||||
/// Uses borrowed data to replace owned data, usually by cloning.
|
||||
|
|
|
|||
|
|
@ -55,54 +55,21 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use heap::{Heap, Layout, Alloc};
|
||||
use raw_vec::RawVec;
|
||||
|
||||
use core::any::Any;
|
||||
use core::borrow;
|
||||
use core::cmp::Ordering;
|
||||
use core::fmt;
|
||||
use core::hash::{self, Hash, Hasher};
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::iter::FusedIterator;
|
||||
use core::marker::{self, Unpin, Unsize};
|
||||
use core::marker::{Unpin, Unsize};
|
||||
use core::mem::{self, Pin};
|
||||
use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState};
|
||||
use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer};
|
||||
use core::ptr::{self, NonNull, Unique};
|
||||
use core::convert::From;
|
||||
use str::from_boxed_utf8_unchecked;
|
||||
|
||||
/// A value that represents the heap. This is the default place that the `box`
|
||||
/// keyword allocates into when no place is supplied.
|
||||
///
|
||||
/// The following two examples are equivalent:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(box_heap)]
|
||||
///
|
||||
/// #![feature(box_syntax, placement_in_syntax)]
|
||||
/// use std::boxed::HEAP;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let foo: Box<i32> = in HEAP { 5 };
|
||||
/// let foo = box 5;
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "box_heap",
|
||||
reason = "may be renamed; uncertain about custom allocator design",
|
||||
issue = "27779")]
|
||||
pub const HEAP: ExchangeHeapSingleton = ExchangeHeapSingleton { _force_singleton: () };
|
||||
|
||||
/// This the singleton type used solely for `boxed::HEAP`.
|
||||
#[unstable(feature = "box_heap",
|
||||
reason = "may be renamed; uncertain about custom allocator design",
|
||||
issue = "27779")]
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ExchangeHeapSingleton {
|
||||
_force_singleton: (),
|
||||
}
|
||||
|
||||
/// A pointer type for heap allocation.
|
||||
///
|
||||
/// See the [module-level documentation](../../std/boxed/index.html) for more.
|
||||
|
|
@ -111,121 +78,6 @@ pub struct ExchangeHeapSingleton {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Box<T: ?Sized>(Unique<T>);
|
||||
|
||||
/// `IntermediateBox` represents uninitialized backing storage for `Box`.
|
||||
///
|
||||
/// FIXME (pnkfelix): Ideally we would just reuse `Box<T>` instead of
|
||||
/// introducing a separate `IntermediateBox<T>`; but then you hit
|
||||
/// issues when you e.g. attempt to destructure an instance of `Box`,
|
||||
/// since it is a lang item and so it gets special handling by the
|
||||
/// compiler. Easier just to make this parallel type for now.
|
||||
///
|
||||
/// FIXME (pnkfelix): Currently the `box` protocol only supports
|
||||
/// creating instances of sized types. This IntermediateBox is
|
||||
/// designed to be forward-compatible with a future protocol that
|
||||
/// supports creating instances of unsized types; that is why the type
|
||||
/// parameter has the `?Sized` generalization marker, and is also why
|
||||
/// this carries an explicit size. However, it probably does not need
|
||||
/// to carry the explicit alignment; that is just a work-around for
|
||||
/// the fact that the `align_of` intrinsic currently requires the
|
||||
/// input type to be Sized (which I do not think is strictly
|
||||
/// necessary).
|
||||
#[unstable(feature = "placement_in",
|
||||
reason = "placement box design is still being worked out.",
|
||||
issue = "27779")]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct IntermediateBox<T: ?Sized> {
|
||||
ptr: *mut u8,
|
||||
layout: Layout,
|
||||
marker: marker::PhantomData<*mut T>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "placement_in",
|
||||
reason = "placement box design is still being worked out.",
|
||||
issue = "27779")]
|
||||
unsafe impl<T> Place<T> for IntermediateBox<T> {
|
||||
fn pointer(&mut self) -> *mut T {
|
||||
self.ptr as *mut T
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn finalize<T>(b: IntermediateBox<T>) -> Box<T> {
|
||||
let p = b.ptr as *mut T;
|
||||
mem::forget(b);
|
||||
Box::from_raw(p)
|
||||
}
|
||||
|
||||
fn make_place<T>() -> IntermediateBox<T> {
|
||||
let layout = Layout::new::<T>();
|
||||
|
||||
let p = if layout.size() == 0 {
|
||||
mem::align_of::<T>() as *mut u8
|
||||
} else {
|
||||
unsafe {
|
||||
Heap.alloc(layout.clone()).unwrap_or_else(|err| {
|
||||
Heap.oom(err)
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
IntermediateBox {
|
||||
ptr: p,
|
||||
layout,
|
||||
marker: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "placement_in",
|
||||
reason = "placement box design is still being worked out.",
|
||||
issue = "27779")]
|
||||
impl<T> BoxPlace<T> for IntermediateBox<T> {
|
||||
fn make_place() -> IntermediateBox<T> {
|
||||
make_place()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "placement_in",
|
||||
reason = "placement box design is still being worked out.",
|
||||
issue = "27779")]
|
||||
impl<T> InPlace<T> for IntermediateBox<T> {
|
||||
type Owner = Box<T>;
|
||||
unsafe fn finalize(self) -> Box<T> {
|
||||
finalize(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "placement_new_protocol", issue = "27779")]
|
||||
impl<T> Boxed for Box<T> {
|
||||
type Data = T;
|
||||
type Place = IntermediateBox<T>;
|
||||
unsafe fn finalize(b: IntermediateBox<T>) -> Box<T> {
|
||||
finalize(b)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "placement_in",
|
||||
reason = "placement box design is still being worked out.",
|
||||
issue = "27779")]
|
||||
impl<T> Placer<T> for ExchangeHeapSingleton {
|
||||
type Place = IntermediateBox<T>;
|
||||
|
||||
fn make_place(self) -> IntermediateBox<T> {
|
||||
make_place()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "placement_in",
|
||||
reason = "placement box design is still being worked out.",
|
||||
issue = "27779")]
|
||||
impl<T: ?Sized> Drop for IntermediateBox<T> {
|
||||
fn drop(&mut self) {
|
||||
if self.layout.size() > 0 {
|
||||
unsafe {
|
||||
Heap.dealloc(self.ptr, self.layout.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Box<T> {
|
||||
/// Allocates memory on the heap and then places `x` into it.
|
||||
///
|
||||
|
|
@ -508,7 +360,7 @@ impl<T: ?Sized + Eq> Eq for Box<T> {}
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized + Hash> Hash for Box<T> {
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
|
@ -892,7 +744,7 @@ impl<T> Generator for Box<T>
|
|||
{
|
||||
type Yield = T::Yield;
|
||||
type Return = T::Return;
|
||||
fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {
|
||||
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {
|
||||
(**self).resume()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ use core::fmt::Debug;
|
|||
use core::hash::{Hash, Hasher};
|
||||
use core::iter::{FromIterator, Peekable, FusedIterator};
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::Bound::{Excluded, Included, Unbounded};
|
||||
use core::ops::Index;
|
||||
use core::ops::RangeBounds;
|
||||
use core::{fmt, intrinsics, mem, ptr};
|
||||
|
||||
use borrow::Borrow;
|
||||
use Bound::{Excluded, Included, Unbounded};
|
||||
use range::RangeArgument;
|
||||
|
||||
use super::node::{self, Handle, NodeRef, marker};
|
||||
use super::search;
|
||||
|
|
@ -576,6 +576,33 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the key-value pair corresponding to the supplied key.
|
||||
///
|
||||
/// The supplied key may be any borrowed form of the map's key type, but the ordering
|
||||
/// on the borrowed form *must* match the ordering on the key type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_get_key_value)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
/// map.insert(1, "a");
|
||||
/// assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
|
||||
/// assert_eq!(map.get_key_value(&2), None);
|
||||
/// ```
|
||||
#[unstable(feature = "map_get_key_value", issue = "49347")]
|
||||
pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
|
||||
where K: Borrow<Q>,
|
||||
Q: Ord
|
||||
{
|
||||
match search::search_tree(self.root.as_ref(), k) {
|
||||
Found(handle) => Some(handle.into_kv()),
|
||||
GoDown(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the map contains a value for the specified key.
|
||||
///
|
||||
/// The key may be any borrowed form of the map's key type, but the ordering
|
||||
|
|
@ -777,7 +804,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
|||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::collections::Bound::Included;
|
||||
/// use std::ops::Bound::Included;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
/// map.insert(3, "a");
|
||||
|
|
@ -790,7 +817,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
|||
/// ```
|
||||
#[stable(feature = "btree_range", since = "1.17.0")]
|
||||
pub fn range<T: ?Sized, R>(&self, range: R) -> Range<K, V>
|
||||
where T: Ord, K: Borrow<T>, R: RangeArgument<T>
|
||||
where T: Ord, K: Borrow<T>, R: RangeBounds<T>
|
||||
{
|
||||
let root1 = self.root.as_ref();
|
||||
let root2 = self.root.as_ref();
|
||||
|
|
@ -830,7 +857,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
|||
/// ```
|
||||
#[stable(feature = "btree_range", since = "1.17.0")]
|
||||
pub fn range_mut<T: ?Sized, R>(&mut self, range: R) -> RangeMut<K, V>
|
||||
where T: Ord, K: Borrow<T>, R: RangeArgument<T>
|
||||
where T: Ord, K: Borrow<T>, R: RangeBounds<T>
|
||||
{
|
||||
let root1 = self.root.as_mut();
|
||||
let root2 = unsafe { ptr::read(&root1) };
|
||||
|
|
@ -1785,7 +1812,7 @@ fn last_leaf_edge<BorrowType, K, V>
|
|||
}
|
||||
}
|
||||
|
||||
fn range_search<BorrowType, K, V, Q: ?Sized, R: RangeArgument<Q>>(
|
||||
fn range_search<BorrowType, K, V, Q: ?Sized, R: RangeBounds<Q>>(
|
||||
root1: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
|
||||
root2: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
|
||||
range: R
|
||||
|
|
|
|||
|
|
@ -41,14 +41,14 @@
|
|||
// - A node of length `n` has `n` keys, `n` values, and (in an internal node) `n + 1` edges.
|
||||
// This implies that even an empty internal node has at least one edge.
|
||||
|
||||
use core::heap::{Alloc, Layout};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
use core::nonzero::NonZero;
|
||||
use core::ptr::{self, Unique};
|
||||
use core::ptr::{self, Unique, NonNull};
|
||||
use core::slice;
|
||||
|
||||
use boxed::Box;
|
||||
use heap::{Heap, Alloc, Layout};
|
||||
use heap::Heap;
|
||||
|
||||
const B: usize = 6;
|
||||
pub const MIN_LEN: usize = B - 1;
|
||||
|
|
@ -149,14 +149,12 @@ impl<K, V> BoxedNode<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn from_ptr(ptr: NonZero<*const LeafNode<K, V>>) -> Self {
|
||||
BoxedNode { ptr: Unique::new_unchecked(ptr.get() as *mut LeafNode<K, V>) }
|
||||
unsafe fn from_ptr(ptr: NonNull<LeafNode<K, V>>) -> Self {
|
||||
BoxedNode { ptr: Unique::from(ptr) }
|
||||
}
|
||||
|
||||
fn as_ptr(&self) -> NonZero<*const LeafNode<K, V>> {
|
||||
unsafe {
|
||||
NonZero::from(self.ptr.as_ref())
|
||||
}
|
||||
fn as_ptr(&self) -> NonNull<LeafNode<K, V>> {
|
||||
NonNull::from(self.ptr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -276,7 +274,7 @@ impl<K, V> Root<K, V> {
|
|||
/// `NodeRef` could be pointing to either type of node.
|
||||
pub struct NodeRef<BorrowType, K, V, Type> {
|
||||
height: usize,
|
||||
node: NonZero<*const LeafNode<K, V>>,
|
||||
node: NonNull<LeafNode<K, V>>,
|
||||
// This is null unless the borrow type is `Mut`
|
||||
root: *const Root<K, V>,
|
||||
_marker: PhantomData<(BorrowType, Type)>
|
||||
|
|
@ -302,7 +300,7 @@ unsafe impl<K: Send, V: Send, Type> Send
|
|||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
|
||||
fn as_internal(&self) -> &InternalNode<K, V> {
|
||||
unsafe {
|
||||
&*(self.node.get() as *const InternalNode<K, V>)
|
||||
&*(self.node.as_ptr() as *mut InternalNode<K, V>)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -310,7 +308,7 @@ impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
|
|||
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
||||
fn as_internal_mut(&mut self) -> &mut InternalNode<K, V> {
|
||||
unsafe {
|
||||
&mut *(self.node.get() as *mut InternalNode<K, V>)
|
||||
&mut *(self.node.as_ptr() as *mut InternalNode<K, V>)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -352,7 +350,7 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
|
|||
|
||||
fn as_leaf(&self) -> &LeafNode<K, V> {
|
||||
unsafe {
|
||||
&*self.node.get()
|
||||
self.node.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -382,7 +380,8 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
|
|||
>,
|
||||
Self
|
||||
> {
|
||||
if let Some(non_zero) = NonZero::new(self.as_leaf().parent as *const LeafNode<K, V>) {
|
||||
let parent_as_leaf = self.as_leaf().parent as *const LeafNode<K, V>;
|
||||
if let Some(non_zero) = NonNull::new(parent_as_leaf as *mut _) {
|
||||
Ok(Handle {
|
||||
node: NodeRef {
|
||||
height: self.height + 1,
|
||||
|
|
@ -498,7 +497,7 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
|
|||
|
||||
fn as_leaf_mut(&mut self) -> &mut LeafNode<K, V> {
|
||||
unsafe {
|
||||
&mut *(self.node.get() as *mut LeafNode<K, V>)
|
||||
self.node.as_mut()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1241,12 +1240,12 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
|
|||
}
|
||||
|
||||
Heap.dealloc(
|
||||
right_node.node.get() as *mut u8,
|
||||
right_node.node.as_ptr() as *mut u8,
|
||||
Layout::new::<InternalNode<K, V>>(),
|
||||
);
|
||||
} else {
|
||||
Heap.dealloc(
|
||||
right_node.node.get() as *mut u8,
|
||||
right_node.node.as_ptr() as *mut u8,
|
||||
Layout::new::<LeafNode<K, V>>(),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,11 @@ use core::cmp::{min, max};
|
|||
use core::fmt::Debug;
|
||||
use core::fmt;
|
||||
use core::iter::{Peekable, FromIterator, FusedIterator};
|
||||
use core::ops::{BitOr, BitAnd, BitXor, Sub};
|
||||
use core::ops::{BitOr, BitAnd, BitXor, Sub, RangeBounds};
|
||||
|
||||
use borrow::Borrow;
|
||||
use btree_map::{BTreeMap, Keys};
|
||||
use super::Recover;
|
||||
use range::RangeArgument;
|
||||
|
||||
// FIXME(conventions): implement bounded iterators
|
||||
|
||||
|
|
@ -240,7 +239,7 @@ impl<T: Ord> BTreeSet<T> {
|
|||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
/// use std::collections::Bound::Included;
|
||||
/// use std::ops::Bound::Included;
|
||||
///
|
||||
/// let mut set = BTreeSet::new();
|
||||
/// set.insert(3);
|
||||
|
|
@ -253,7 +252,7 @@ impl<T: Ord> BTreeSet<T> {
|
|||
/// ```
|
||||
#[stable(feature = "btree_range", since = "1.17.0")]
|
||||
pub fn range<K: ?Sized, R>(&self, range: R) -> Range<T>
|
||||
where K: Ord, T: Borrow<K>, R: RangeArgument<K>
|
||||
where K: Ord, T: Borrow<K>, R: RangeBounds<K>
|
||||
{
|
||||
Range { iter: self.map.range(range) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@
|
|||
//! sign := '+' | '-'
|
||||
//! width := count
|
||||
//! precision := count | '*'
|
||||
//! type := identifier | ''
|
||||
//! type := identifier | '?' | ''
|
||||
//! count := parameter | integer
|
||||
//! parameter := argument '$'
|
||||
//! ```
|
||||
|
|
@ -516,17 +516,17 @@ pub use core::fmt::rt;
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::fmt::{Formatter, Result, Write};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::fmt::{Octal, Binary};
|
||||
pub use core::fmt::{Binary, Octal};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::fmt::{Display, Debug};
|
||||
pub use core::fmt::{Debug, Display};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::fmt::{LowerHex, UpperHex, Pointer};
|
||||
pub use core::fmt::{LowerHex, Pointer, UpperHex};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::fmt::{LowerExp, UpperExp};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::fmt::Error;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::fmt::{ArgumentV1, Arguments, write};
|
||||
pub use core::fmt::{write, ArgumentV1, Arguments};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple};
|
||||
|
||||
|
|
@ -563,7 +563,8 @@ use string;
|
|||
pub fn format(args: Arguments) -> string::String {
|
||||
let capacity = args.estimated_capacity();
|
||||
let mut output = string::String::with_capacity(capacity);
|
||||
output.write_fmt(args)
|
||||
.expect("a formatting trait implementation returned an error");
|
||||
output
|
||||
.write_fmt(args)
|
||||
.expect("a formatting trait implementation returned an error");
|
||||
output
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use core::intrinsics::{min_align_of_val, size_of_val};
|
|||
use core::mem::{self, ManuallyDrop};
|
||||
use core::usize;
|
||||
|
||||
pub use allocator::*;
|
||||
pub use core::heap::*;
|
||||
#[doc(hidden)]
|
||||
pub mod __core {
|
||||
pub use core::*;
|
||||
|
|
|
|||
|
|
@ -76,11 +76,11 @@
|
|||
#![deny(missing_debug_implementations)]
|
||||
|
||||
#![cfg_attr(test, allow(deprecated))] // rand
|
||||
#![cfg_attr(test, feature(placement_in))]
|
||||
#![cfg_attr(not(test), feature(core_float))]
|
||||
#![cfg_attr(not(test), feature(exact_size_is_empty))]
|
||||
#![cfg_attr(not(test), feature(generator_trait))]
|
||||
#![cfg_attr(test, feature(rand, test))]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(allow_internal_unstable)]
|
||||
#![feature(ascii_ctype)]
|
||||
#![feature(box_into_raw_non_null)]
|
||||
|
|
@ -88,6 +88,7 @@
|
|||
#![feature(box_syntax)]
|
||||
#![feature(cfg_target_has_atomic)]
|
||||
#![feature(coerce_unsized)]
|
||||
#![feature(collections_range)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(custom_attribute)]
|
||||
|
|
@ -96,9 +97,8 @@
|
|||
#![feature(fmt_internals)]
|
||||
#![feature(from_ref)]
|
||||
#![feature(fundamental)]
|
||||
#![feature(generic_param_attrs)]
|
||||
#![feature(i128_type)]
|
||||
#![feature(iter_rfold)]
|
||||
#![cfg_attr(stage0, feature(generic_param_attrs))]
|
||||
#![cfg_attr(stage0, feature(i128_type))]
|
||||
#![feature(lang_items)]
|
||||
#![feature(needs_allocator)]
|
||||
#![feature(nonzero)]
|
||||
|
|
@ -106,8 +106,6 @@
|
|||
#![feature(optin_builtin_traits)]
|
||||
#![feature(pattern)]
|
||||
#![feature(pin)]
|
||||
#![feature(placement_in_syntax)]
|
||||
#![feature(placement_new_protocol)]
|
||||
#![feature(ptr_internals)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(slice_get_slice)]
|
||||
|
|
@ -126,8 +124,8 @@
|
|||
#![feature(pointer_methods)]
|
||||
#![feature(inclusive_range_fields)]
|
||||
|
||||
#![cfg_attr(not(test), feature(fn_traits, placement_new_protocol, swap_with_slice, i128))]
|
||||
#![cfg_attr(test, feature(test, box_heap))]
|
||||
#![cfg_attr(not(test), feature(fn_traits, swap_with_slice, i128))]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
|
||||
// Allow testing this library
|
||||
|
||||
|
|
@ -145,9 +143,9 @@ extern crate std_unicode;
|
|||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
// Allocator trait and helper struct definitions
|
||||
|
||||
pub mod allocator;
|
||||
#[rustc_deprecated(since = "1.27.0", reason = "use the heap module in core, alloc, or std instead")]
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub use core::heap as allocator;
|
||||
|
||||
// Heaps provided for low-level allocation strategies
|
||||
|
||||
|
|
@ -157,13 +155,12 @@ pub mod heap;
|
|||
|
||||
// Need to conditionally define the mod from `boxed.rs` to avoid
|
||||
// duplicating the lang-items when building in test cfg; but also need
|
||||
// to allow code to have `use boxed::HEAP;`
|
||||
// and `use boxed::Box;` declarations.
|
||||
// to allow code to have `use boxed::Box;` declarations.
|
||||
#[cfg(not(test))]
|
||||
pub mod boxed;
|
||||
#[cfg(test)]
|
||||
mod boxed {
|
||||
pub use std::boxed::{Box, IntermediateBox, HEAP};
|
||||
pub use std::boxed::Box;
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod boxed_test;
|
||||
|
|
@ -178,7 +175,6 @@ mod btree;
|
|||
pub mod borrow;
|
||||
pub mod fmt;
|
||||
pub mod linked_list;
|
||||
pub mod range;
|
||||
pub mod slice;
|
||||
pub mod str;
|
||||
pub mod string;
|
||||
|
|
@ -204,57 +200,6 @@ mod std {
|
|||
pub use core::ops; // RangeFull
|
||||
}
|
||||
|
||||
/// An endpoint of a range of keys.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// `Bound`s are range endpoints:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(collections_range)]
|
||||
///
|
||||
/// use std::collections::range::RangeArgument;
|
||||
/// use std::collections::Bound::*;
|
||||
///
|
||||
/// assert_eq!((..100).start(), Unbounded);
|
||||
/// assert_eq!((1..12).start(), Included(&1));
|
||||
/// assert_eq!((1..12).end(), Excluded(&12));
|
||||
/// ```
|
||||
///
|
||||
/// Using a tuple of `Bound`s as an argument to [`BTreeMap::range`].
|
||||
/// Note that in most cases, it's better to use range syntax (`1..5`) instead.
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::collections::Bound::{Excluded, Included, Unbounded};
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
/// map.insert(3, "a");
|
||||
/// map.insert(5, "b");
|
||||
/// map.insert(8, "c");
|
||||
///
|
||||
/// for (key, value) in map.range((Excluded(3), Included(8))) {
|
||||
/// println!("{}: {}", key, value);
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(Some((&3, &"a")), map.range((Unbounded, Included(5))).next());
|
||||
/// ```
|
||||
///
|
||||
/// [`BTreeMap::range`]: btree_map/struct.BTreeMap.html#method.range
|
||||
#[stable(feature = "collections_bound", since = "1.17.0")]
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||
pub enum Bound<T> {
|
||||
/// An inclusive bound.
|
||||
#[stable(feature = "collections_bound", since = "1.17.0")]
|
||||
Included(#[stable(feature = "collections_bound", since = "1.17.0")] T),
|
||||
/// An exclusive bound.
|
||||
#[stable(feature = "collections_bound", since = "1.17.0")]
|
||||
Excluded(#[stable(feature = "collections_bound", since = "1.17.0")] T),
|
||||
/// An infinite endpoint. Indicates that there is no bound in this direction.
|
||||
#[stable(feature = "collections_bound", since = "1.17.0")]
|
||||
Unbounded,
|
||||
}
|
||||
|
||||
/// An intermediate trait for specialization of `Extend`.
|
||||
#[doc(hidden)]
|
||||
trait SpecExtend<I: IntoIterator> {
|
||||
|
|
|
|||
|
|
@ -28,10 +28,9 @@ use core::hash::{Hasher, Hash};
|
|||
use core::iter::{FromIterator, FusedIterator};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
use core::ops::{BoxPlace, InPlace, Place, Placer};
|
||||
use core::ptr::{self, NonNull};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use boxed::{Box, IntermediateBox};
|
||||
use boxed::Box;
|
||||
use super::SpecExtend;
|
||||
|
||||
/// A doubly-linked list with owned nodes.
|
||||
|
|
@ -786,62 +785,6 @@ impl<T> LinkedList<T> {
|
|||
old_len: old_len,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a place for insertion at the front of the list.
|
||||
///
|
||||
/// Using this method with placement syntax is equivalent to
|
||||
/// [`push_front`](#method.push_front), but may be more efficient.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(collection_placement)]
|
||||
/// #![feature(placement_in_syntax)]
|
||||
///
|
||||
/// use std::collections::LinkedList;
|
||||
///
|
||||
/// let mut list = LinkedList::new();
|
||||
/// list.front_place() <- 2;
|
||||
/// list.front_place() <- 4;
|
||||
/// assert!(list.iter().eq(&[4, 2]));
|
||||
/// ```
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "method name and placement protocol are subject to change",
|
||||
issue = "30172")]
|
||||
pub fn front_place(&mut self) -> FrontPlace<T> {
|
||||
FrontPlace {
|
||||
list: self,
|
||||
node: IntermediateBox::make_place(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a place for insertion at the back of the list.
|
||||
///
|
||||
/// Using this method with placement syntax is equivalent to [`push_back`](#method.push_back),
|
||||
/// but may be more efficient.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(collection_placement)]
|
||||
/// #![feature(placement_in_syntax)]
|
||||
///
|
||||
/// use std::collections::LinkedList;
|
||||
///
|
||||
/// let mut list = LinkedList::new();
|
||||
/// list.back_place() <- 2;
|
||||
/// list.back_place() <- 4;
|
||||
/// assert!(list.iter().eq(&[2, 4]));
|
||||
/// ```
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "method name and placement protocol are subject to change",
|
||||
issue = "30172")]
|
||||
pub fn back_place(&mut self) -> BackPlace<T> {
|
||||
BackPlace {
|
||||
list: self,
|
||||
node: IntermediateBox::make_place(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1242,123 +1185,6 @@ impl<T: Hash> Hash for LinkedList<T> {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn finalize<T>(node: IntermediateBox<Node<T>>) -> Box<Node<T>> {
|
||||
let mut node = node.finalize();
|
||||
ptr::write(&mut node.next, None);
|
||||
ptr::write(&mut node.prev, None);
|
||||
node
|
||||
}
|
||||
|
||||
/// A place for insertion at the front of a `LinkedList`.
|
||||
///
|
||||
/// See [`LinkedList::front_place`](struct.LinkedList.html#method.front_place) for details.
|
||||
#[must_use = "places do nothing unless written to with `<-` syntax"]
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "struct name and placement protocol are subject to change",
|
||||
issue = "30172")]
|
||||
pub struct FrontPlace<'a, T: 'a> {
|
||||
list: &'a mut LinkedList<T>,
|
||||
node: IntermediateBox<Node<T>>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "struct name and placement protocol are subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for FrontPlace<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("FrontPlace")
|
||||
.field(&self.list)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T> Placer<T> for FrontPlace<'a, T> {
|
||||
type Place = Self;
|
||||
|
||||
fn make_place(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
unsafe impl<'a, T> Place<T> for FrontPlace<'a, T> {
|
||||
fn pointer(&mut self) -> *mut T {
|
||||
unsafe { &mut (*self.node.pointer()).element }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T> InPlace<T> for FrontPlace<'a, T> {
|
||||
type Owner = ();
|
||||
|
||||
unsafe fn finalize(self) {
|
||||
let FrontPlace { list, node } = self;
|
||||
list.push_front_node(finalize(node));
|
||||
}
|
||||
}
|
||||
|
||||
/// A place for insertion at the back of a `LinkedList`.
|
||||
///
|
||||
/// See [`LinkedList::back_place`](struct.LinkedList.html#method.back_place) for details.
|
||||
#[must_use = "places do nothing unless written to with `<-` syntax"]
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "struct name and placement protocol are subject to change",
|
||||
issue = "30172")]
|
||||
pub struct BackPlace<'a, T: 'a> {
|
||||
list: &'a mut LinkedList<T>,
|
||||
node: IntermediateBox<Node<T>>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "struct name and placement protocol are subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for BackPlace<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("BackPlace")
|
||||
.field(&self.list)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T> Placer<T> for BackPlace<'a, T> {
|
||||
type Place = Self;
|
||||
|
||||
fn make_place(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
unsafe impl<'a, T> Place<T> for BackPlace<'a, T> {
|
||||
fn pointer(&mut self) -> *mut T {
|
||||
unsafe { &mut (*self.node.pointer()).element }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T> InPlace<T> for BackPlace<'a, T> {
|
||||
type Owner = ();
|
||||
|
||||
unsafe fn finalize(self) {
|
||||
let BackPlace { list, node } = self;
|
||||
list.push_back_node(finalize(node));
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters.
|
||||
#[allow(dead_code)]
|
||||
fn assert_covariance() {
|
||||
|
|
|
|||
|
|
@ -1,152 +0,0 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
#![unstable(feature = "collections_range",
|
||||
reason = "waiting for dust to settle on inclusive ranges",
|
||||
issue = "30877")]
|
||||
|
||||
//! Range syntax.
|
||||
|
||||
use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive};
|
||||
use Bound::{self, Excluded, Included, Unbounded};
|
||||
|
||||
/// `RangeArgument` is implemented by Rust's built-in range types, produced
|
||||
/// by range syntax like `..`, `a..`, `..b` or `c..d`.
|
||||
pub trait RangeArgument<T: ?Sized> {
|
||||
/// Start index bound.
|
||||
///
|
||||
/// Returns the start value as a `Bound`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(alloc)]
|
||||
/// #![feature(collections_range)]
|
||||
///
|
||||
/// extern crate alloc;
|
||||
///
|
||||
/// # fn main() {
|
||||
/// use alloc::range::RangeArgument;
|
||||
/// use alloc::Bound::*;
|
||||
///
|
||||
/// assert_eq!((..10).start(), Unbounded);
|
||||
/// assert_eq!((3..10).start(), Included(&3));
|
||||
/// # }
|
||||
/// ```
|
||||
fn start(&self) -> Bound<&T>;
|
||||
|
||||
/// End index bound.
|
||||
///
|
||||
/// Returns the end value as a `Bound`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(alloc)]
|
||||
/// #![feature(collections_range)]
|
||||
///
|
||||
/// extern crate alloc;
|
||||
///
|
||||
/// # fn main() {
|
||||
/// use alloc::range::RangeArgument;
|
||||
/// use alloc::Bound::*;
|
||||
///
|
||||
/// assert_eq!((3..).end(), Unbounded);
|
||||
/// assert_eq!((3..10).end(), Excluded(&10));
|
||||
/// # }
|
||||
/// ```
|
||||
fn end(&self) -> Bound<&T>;
|
||||
}
|
||||
|
||||
// FIXME add inclusive ranges to RangeArgument
|
||||
|
||||
impl<T: ?Sized> RangeArgument<T> for RangeFull {
|
||||
fn start(&self) -> Bound<&T> {
|
||||
Unbounded
|
||||
}
|
||||
fn end(&self) -> Bound<&T> {
|
||||
Unbounded
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RangeArgument<T> for RangeFrom<T> {
|
||||
fn start(&self) -> Bound<&T> {
|
||||
Included(&self.start)
|
||||
}
|
||||
fn end(&self) -> Bound<&T> {
|
||||
Unbounded
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RangeArgument<T> for RangeTo<T> {
|
||||
fn start(&self) -> Bound<&T> {
|
||||
Unbounded
|
||||
}
|
||||
fn end(&self) -> Bound<&T> {
|
||||
Excluded(&self.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RangeArgument<T> for Range<T> {
|
||||
fn start(&self) -> Bound<&T> {
|
||||
Included(&self.start)
|
||||
}
|
||||
fn end(&self) -> Bound<&T> {
|
||||
Excluded(&self.end)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||
impl<T> RangeArgument<T> for RangeInclusive<T> {
|
||||
fn start(&self) -> Bound<&T> {
|
||||
Included(&self.start)
|
||||
}
|
||||
fn end(&self) -> Bound<&T> {
|
||||
Included(&self.end)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||
impl<T> RangeArgument<T> for RangeToInclusive<T> {
|
||||
fn start(&self) -> Bound<&T> {
|
||||
Unbounded
|
||||
}
|
||||
fn end(&self) -> Bound<&T> {
|
||||
Included(&self.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RangeArgument<T> for (Bound<T>, Bound<T>) {
|
||||
fn start(&self) -> Bound<&T> {
|
||||
match *self {
|
||||
(Included(ref start), _) => Included(start),
|
||||
(Excluded(ref start), _) => Excluded(start),
|
||||
(Unbounded, _) => Unbounded,
|
||||
}
|
||||
}
|
||||
|
||||
fn end(&self) -> Bound<&T> {
|
||||
match *self {
|
||||
(_, Included(ref end)) => Included(end),
|
||||
(_, Excluded(ref end)) => Excluded(end),
|
||||
(_, Unbounded) => Unbounded,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + 'a> RangeArgument<T> for (Bound<&'a T>, Bound<&'a T>) {
|
||||
fn start(&self) -> Bound<&T> {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn end(&self) -> Bound<&T> {
|
||||
self.1
|
||||
}
|
||||
}
|
||||
|
|
@ -9,11 +9,12 @@
|
|||
// except according to those terms.
|
||||
|
||||
use core::cmp;
|
||||
use core::heap::{Alloc, Layout};
|
||||
use core::mem;
|
||||
use core::ops::Drop;
|
||||
use core::ptr::{self, Unique};
|
||||
use core::slice;
|
||||
use heap::{Alloc, Layout, Heap};
|
||||
use heap::Heap;
|
||||
use super::boxed::Box;
|
||||
use super::allocator::CollectionAllocErr;
|
||||
use super::allocator::CollectionAllocErr::*;
|
||||
|
|
|
|||
|
|
@ -250,6 +250,7 @@ use core::cell::Cell;
|
|||
use core::cmp::Ordering;
|
||||
use core::fmt;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::heap::{Alloc, Layout};
|
||||
use core::intrinsics::abort;
|
||||
use core::marker;
|
||||
use core::marker::{Unsize, PhantomData};
|
||||
|
|
@ -259,7 +260,7 @@ use core::ops::CoerceUnsized;
|
|||
use core::ptr::{self, NonNull};
|
||||
use core::convert::From;
|
||||
|
||||
use heap::{Heap, Alloc, Layout, box_free};
|
||||
use heap::{Heap, box_free};
|
||||
use string::String;
|
||||
use vec::Vec;
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ use core::mem::size_of;
|
|||
use core::mem;
|
||||
use core::ptr;
|
||||
use core::slice as core_slice;
|
||||
use core::{u8, u16, u32};
|
||||
|
||||
use borrow::{Borrow, BorrowMut, ToOwned};
|
||||
use boxed::Box;
|
||||
|
|
@ -1302,7 +1303,8 @@ impl<T> [T] {
|
|||
|
||||
/// Sorts the slice with a key extraction function.
|
||||
///
|
||||
/// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case.
|
||||
/// This sort is stable (i.e. does not reorder equal elements) and `O(m n log(m n))`
|
||||
/// worst-case, where the key function is `O(m)`.
|
||||
///
|
||||
/// When applicable, unstable sorting is preferred because it is generally faster than stable
|
||||
/// sorting and it doesn't allocate auxiliary memory.
|
||||
|
|
@ -1328,12 +1330,82 @@ impl<T> [T] {
|
|||
/// ```
|
||||
#[stable(feature = "slice_sort_by_key", since = "1.7.0")]
|
||||
#[inline]
|
||||
pub fn sort_by_key<B, F>(&mut self, mut f: F)
|
||||
where F: FnMut(&T) -> B, B: Ord
|
||||
pub fn sort_by_key<K, F>(&mut self, mut f: F)
|
||||
where F: FnMut(&T) -> K, K: Ord
|
||||
{
|
||||
merge_sort(self, |a, b| f(a).lt(&f(b)));
|
||||
}
|
||||
|
||||
/// Sorts the slice with a key extraction function.
|
||||
///
|
||||
/// During sorting, the key function is called only once per element.
|
||||
///
|
||||
/// This sort is stable (i.e. does not reorder equal elements) and `O(m n + n log n)`
|
||||
/// worst-case, where the key function is `O(m)`.
|
||||
///
|
||||
/// For simple key functions (e.g. functions that are property accesses or
|
||||
/// basic operations), [`sort_by_key`](#method.sort_by_key) is likely to be
|
||||
/// faster.
|
||||
///
|
||||
/// # Current implementation
|
||||
///
|
||||
/// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
|
||||
/// which combines the fast average case of randomized quicksort with the fast worst case of
|
||||
/// heapsort, while achieving linear time on slices with certain patterns. It uses some
|
||||
/// randomization to avoid degenerate cases, but with a fixed seed to always provide
|
||||
/// deterministic behavior.
|
||||
///
|
||||
/// In the worst case, the algorithm allocates temporary storage in a `Vec<(K, usize)>` the
|
||||
/// length of the slice.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_sort_by_cached_key)]
|
||||
/// let mut v = [-5i32, 4, 32, -3, 2];
|
||||
///
|
||||
/// v.sort_by_cached_key(|k| k.to_string());
|
||||
/// assert!(v == [-3, -5, 2, 32, 4]);
|
||||
/// ```
|
||||
///
|
||||
/// [pdqsort]: https://github.com/orlp/pdqsort
|
||||
#[unstable(feature = "slice_sort_by_cached_key", issue = "34447")]
|
||||
#[inline]
|
||||
pub fn sort_by_cached_key<K, F>(&mut self, f: F)
|
||||
where F: FnMut(&T) -> K, K: Ord
|
||||
{
|
||||
// Helper macro for indexing our vector by the smallest possible type, to reduce allocation.
|
||||
macro_rules! sort_by_key {
|
||||
($t:ty, $slice:ident, $f:ident) => ({
|
||||
let mut indices: Vec<_> =
|
||||
$slice.iter().map($f).enumerate().map(|(i, k)| (k, i as $t)).collect();
|
||||
// The elements of `indices` are unique, as they are indexed, so any sort will be
|
||||
// stable with respect to the original slice. We use `sort_unstable` here because
|
||||
// it requires less memory allocation.
|
||||
indices.sort_unstable();
|
||||
for i in 0..$slice.len() {
|
||||
let mut index = indices[i].1;
|
||||
while (index as usize) < i {
|
||||
index = indices[index as usize].1;
|
||||
}
|
||||
indices[i].1 = index;
|
||||
$slice.swap(i, index as usize);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let sz_u8 = mem::size_of::<(K, u8)>();
|
||||
let sz_u16 = mem::size_of::<(K, u16)>();
|
||||
let sz_u32 = mem::size_of::<(K, u32)>();
|
||||
let sz_usize = mem::size_of::<(K, usize)>();
|
||||
|
||||
let len = self.len();
|
||||
if sz_u8 < sz_u16 && len <= ( u8::MAX as usize) { return sort_by_key!( u8, self, f) }
|
||||
if sz_u16 < sz_u32 && len <= (u16::MAX as usize) { return sort_by_key!(u16, self, f) }
|
||||
if sz_u32 < sz_usize && len <= (u32::MAX as usize) { return sort_by_key!(u32, self, f) }
|
||||
sort_by_key!(usize, self, f)
|
||||
}
|
||||
|
||||
/// Sorts the slice, but may not preserve the order of equal elements.
|
||||
///
|
||||
/// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),
|
||||
|
|
@ -1410,7 +1482,7 @@ impl<T> [T] {
|
|||
/// elements.
|
||||
///
|
||||
/// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),
|
||||
/// and `O(n log n)` worst-case.
|
||||
/// and `O(m n log(m n))` worst-case, where the key function is `O(m)`.
|
||||
///
|
||||
/// # Current implementation
|
||||
///
|
||||
|
|
@ -1420,9 +1492,6 @@ impl<T> [T] {
|
|||
/// randomization to avoid degenerate cases, but with a fixed seed to always provide
|
||||
/// deterministic behavior.
|
||||
///
|
||||
/// It is typically faster than stable sorting, except in a few special cases, e.g. when the
|
||||
/// slice consists of several concatenated sorted sequences.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -1435,9 +1504,8 @@ impl<T> [T] {
|
|||
/// [pdqsort]: https://github.com/orlp/pdqsort
|
||||
#[stable(feature = "sort_unstable", since = "1.20.0")]
|
||||
#[inline]
|
||||
pub fn sort_unstable_by_key<B, F>(&mut self, f: F)
|
||||
where F: FnMut(&T) -> B,
|
||||
B: Ord
|
||||
pub fn sort_unstable_by_key<K, F>(&mut self, f: F)
|
||||
where F: FnMut(&T) -> K, K: Ord
|
||||
{
|
||||
core_slice::SliceExt::sort_unstable_by_key(self, f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2122,6 +2122,48 @@ impl str {
|
|||
unsafe { String::from_utf8_unchecked(buf) }
|
||||
}
|
||||
|
||||
/// Returns true if this `str` is entirely whitespace, and false otherwise.
|
||||
///
|
||||
/// 'Whitespace' is defined according to the terms of the Unicode Derived Core
|
||||
/// Property `White_Space`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// assert!(" \t ".is_whitespace());
|
||||
///
|
||||
/// // a non-breaking space
|
||||
/// assert!("\u{A0}".is_whitespace());
|
||||
///
|
||||
/// assert!(!" 越".is_whitespace());
|
||||
/// ```
|
||||
#[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")]
|
||||
#[inline]
|
||||
pub fn is_whitespace(&self) -> bool {
|
||||
UnicodeStr::is_whitespace(self)
|
||||
}
|
||||
|
||||
/// Returns true if this `str` is entirely alphanumeric, and false otherwise.
|
||||
///
|
||||
/// 'Alphanumeric'-ness is defined in terms of the Unicode General Categories
|
||||
/// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// assert!("٣7৬Kو藏".is_alphanumeric());
|
||||
/// assert!(!"¾①".is_alphanumeric());
|
||||
/// ```
|
||||
#[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")]
|
||||
#[inline]
|
||||
pub fn is_alphanumeric(&self) -> bool {
|
||||
UnicodeStr::is_alphanumeric(self)
|
||||
}
|
||||
|
||||
/// Checks if all characters in this string are within the ASCII range.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
|||
|
|
@ -59,15 +59,14 @@
|
|||
use core::fmt;
|
||||
use core::hash;
|
||||
use core::iter::{FromIterator, FusedIterator};
|
||||
use core::ops::{self, Add, AddAssign, Index, IndexMut};
|
||||
use core::ops::Bound::{Excluded, Included, Unbounded};
|
||||
use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds};
|
||||
use core::ptr;
|
||||
use core::str::pattern::Pattern;
|
||||
use std_unicode::lossy;
|
||||
use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER};
|
||||
|
||||
use borrow::{Cow, ToOwned};
|
||||
use range::RangeArgument;
|
||||
use Bound::{Excluded, Included, Unbounded};
|
||||
use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars};
|
||||
use vec::Vec;
|
||||
use boxed::Box;
|
||||
|
|
@ -1015,6 +1014,34 @@ impl String {
|
|||
self.vec.shrink_to_fit()
|
||||
}
|
||||
|
||||
/// Shrinks the capacity of this `String` with a lower bound.
|
||||
///
|
||||
/// The capacity will remain at least as large as both the length
|
||||
/// and the supplied value.
|
||||
///
|
||||
/// Panics if the current capacity is smaller than the supplied
|
||||
/// minimum capacity.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(shrink_to)]
|
||||
/// let mut s = String::from("foo");
|
||||
///
|
||||
/// s.reserve(100);
|
||||
/// assert!(s.capacity() >= 100);
|
||||
///
|
||||
/// s.shrink_to(10);
|
||||
/// assert!(s.capacity() >= 10);
|
||||
/// s.shrink_to(0);
|
||||
/// assert!(s.capacity() >= 3);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "shrink_to", reason = "new API", issue="0")]
|
||||
pub fn shrink_to(&mut self, min_capacity: usize) {
|
||||
self.vec.shrink_to(min_capacity)
|
||||
}
|
||||
|
||||
/// Appends the given [`char`] to the end of this `String`.
|
||||
///
|
||||
/// [`char`]: ../../std/primitive.char.html
|
||||
|
|
@ -1177,8 +1204,6 @@ impl String {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(string_retain)]
|
||||
///
|
||||
/// let mut s = String::from("f_o_ob_ar");
|
||||
///
|
||||
/// s.retain(|c| c != '_');
|
||||
|
|
@ -1186,7 +1211,7 @@ impl String {
|
|||
/// assert_eq!(s, "foobar");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "string_retain", issue = "43874")]
|
||||
#[stable(feature = "string_retain", since = "1.26.0")]
|
||||
pub fn retain<F>(&mut self, mut f: F)
|
||||
where F: FnMut(char) -> bool
|
||||
{
|
||||
|
|
@ -1458,7 +1483,7 @@ impl String {
|
|||
/// ```
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
pub fn drain<R>(&mut self, range: R) -> Drain
|
||||
where R: RangeArgument<usize>
|
||||
where R: RangeBounds<usize>
|
||||
{
|
||||
// Memory safety
|
||||
//
|
||||
|
|
@ -1492,7 +1517,7 @@ impl String {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a splicing iterator that removes the specified range in the string,
|
||||
/// Removes the specified range in the string,
|
||||
/// and replaces it with the given string.
|
||||
/// The given string doesn't need to be the same length as the range.
|
||||
///
|
||||
|
|
@ -1512,21 +1537,20 @@ impl String {
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(splice)]
|
||||
/// let mut s = String::from("α is alpha, β is beta");
|
||||
/// let beta_offset = s.find('β').unwrap_or(s.len());
|
||||
///
|
||||
/// // Replace the range up until the β from the string
|
||||
/// s.splice(..beta_offset, "Α is capital alpha; ");
|
||||
/// s.replace_range(..beta_offset, "Α is capital alpha; ");
|
||||
/// assert_eq!(s, "Α is capital alpha; β is beta");
|
||||
/// ```
|
||||
#[unstable(feature = "splice", reason = "recently added", issue = "44643")]
|
||||
pub fn splice<R>(&mut self, range: R, replace_with: &str)
|
||||
where R: RangeArgument<usize>
|
||||
#[stable(feature = "splice", since = "1.27.0")]
|
||||
pub fn replace_range<R>(&mut self, range: R, replace_with: &str)
|
||||
where R: RangeBounds<usize>
|
||||
{
|
||||
// Memory safety
|
||||
//
|
||||
// The String version of Splice does not have the memory safety issues
|
||||
// Replace_range does not have the memory safety issues of a vector Splice.
|
||||
// of the vector version. The data is just plain bytes.
|
||||
|
||||
match range.start() {
|
||||
|
|
@ -1576,7 +1600,6 @@ impl FromUtf8Error {
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(from_utf8_error_as_bytes)]
|
||||
/// // some invalid bytes, in a vector
|
||||
/// let bytes = vec![0, 159];
|
||||
///
|
||||
|
|
@ -1584,7 +1607,7 @@ impl FromUtf8Error {
|
|||
///
|
||||
/// assert_eq!(&[0, 159], value.unwrap_err().as_bytes());
|
||||
/// ```
|
||||
#[unstable(feature = "from_utf8_error_as_bytes", reason = "recently added", issue = "40895")]
|
||||
#[stable(feature = "from_utf8_error_as_bytes", since = "1.26.0")]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.bytes[..]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -278,26 +278,6 @@ fn test_extend_specialization() {
|
|||
assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_placement() {
|
||||
let mut a = BinaryHeap::new();
|
||||
&mut a <- 2;
|
||||
&mut a <- 4;
|
||||
&mut a <- 3;
|
||||
assert_eq!(a.peek(), Some(&4));
|
||||
assert_eq!(a.len(), 3);
|
||||
&mut a <- 1;
|
||||
assert_eq!(a.into_sorted_vec(), vec![1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_placement_panic() {
|
||||
let mut heap = BinaryHeap::from(vec![1, 2, 3]);
|
||||
fn mkpanic() -> usize { panic!() }
|
||||
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { &mut heap <- mkpanic(); }));
|
||||
assert_eq!(heap.len(), 3);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn assert_covariance() {
|
||||
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
// except according to those terms.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::Bound::{self, Excluded, Included, Unbounded};
|
||||
use std::collections::btree_map::Entry::{Occupied, Vacant};
|
||||
use std::ops::Bound::{self, Excluded, Included, Unbounded};
|
||||
use std::rc::Rc;
|
||||
|
||||
use std::iter::FromIterator;
|
||||
|
|
|
|||
|
|
@ -15,14 +15,13 @@
|
|||
#![feature(attr_literals)]
|
||||
#![feature(box_syntax)]
|
||||
#![cfg_attr(stage0, feature(inclusive_range_syntax))]
|
||||
#![feature(collection_placement)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(iterator_step_by)]
|
||||
#![feature(pattern)]
|
||||
#![feature(placement_in_syntax)]
|
||||
#![feature(rand)]
|
||||
#![feature(slice_sort_by_cached_key)]
|
||||
#![feature(splice)]
|
||||
#![feature(str_escape)]
|
||||
#![feature(string_retain)]
|
||||
|
|
|
|||
|
|
@ -425,6 +425,14 @@ fn test_sort() {
|
|||
v.sort_by(|a, b| b.cmp(a));
|
||||
assert!(v.windows(2).all(|w| w[0] >= w[1]));
|
||||
|
||||
// Sort in lexicographic order.
|
||||
let mut v1 = orig.clone();
|
||||
let mut v2 = orig.clone();
|
||||
v1.sort_by_key(|x| x.to_string());
|
||||
v2.sort_by_cached_key(|x| x.to_string());
|
||||
assert!(v1.windows(2).all(|w| w[0].to_string() <= w[1].to_string()));
|
||||
assert!(v1 == v2);
|
||||
|
||||
// Sort with many pre-sorted runs.
|
||||
let mut v = orig.clone();
|
||||
v.sort();
|
||||
|
|
@ -477,7 +485,7 @@ fn test_sort_stability() {
|
|||
// the second item represents which occurrence of that
|
||||
// number this element is, i.e. the second elements
|
||||
// will occur in sorted order.
|
||||
let mut v: Vec<_> = (0..len)
|
||||
let mut orig: Vec<_> = (0..len)
|
||||
.map(|_| {
|
||||
let n = thread_rng().gen::<usize>() % 10;
|
||||
counts[n] += 1;
|
||||
|
|
@ -485,16 +493,21 @@ fn test_sort_stability() {
|
|||
})
|
||||
.collect();
|
||||
|
||||
// only sort on the first element, so an unstable sort
|
||||
let mut v = orig.clone();
|
||||
// Only sort on the first element, so an unstable sort
|
||||
// may mix up the counts.
|
||||
v.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
|
||||
|
||||
// this comparison includes the count (the second item
|
||||
// This comparison includes the count (the second item
|
||||
// of the tuple), so elements with equal first items
|
||||
// will need to be ordered with increasing
|
||||
// counts... i.e. exactly asserting that this sort is
|
||||
// stable.
|
||||
assert!(v.windows(2).all(|w| w[0] <= w[1]));
|
||||
|
||||
let mut v = orig.clone();
|
||||
v.sort_by_cached_key(|&(x, _)| x);
|
||||
assert!(v.windows(2).all(|w| w[0] <= w[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1351,7 +1364,7 @@ fn test_copy_from_slice_dst_shorter() {
|
|||
const MAX_LEN: usize = 80;
|
||||
|
||||
static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [
|
||||
// FIXME #5244: AtomicUsize is not Copy.
|
||||
// FIXME(RFC 1109): AtomicUsize is not Copy.
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
|
|
|
|||
|
|
@ -443,53 +443,53 @@ fn test_drain() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_splice() {
|
||||
fn test_replace_range() {
|
||||
let mut s = "Hello, world!".to_owned();
|
||||
s.splice(7..12, "世界");
|
||||
s.replace_range(7..12, "世界");
|
||||
assert_eq!(s, "Hello, 世界!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_splice_char_boundary() {
|
||||
fn test_replace_range_char_boundary() {
|
||||
let mut s = "Hello, 世界!".to_owned();
|
||||
s.splice(..8, "");
|
||||
s.replace_range(..8, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_splice_inclusive_range() {
|
||||
fn test_replace_range_inclusive_range() {
|
||||
let mut v = String::from("12345");
|
||||
v.splice(2..=3, "789");
|
||||
v.replace_range(2..=3, "789");
|
||||
assert_eq!(v, "127895");
|
||||
v.splice(1..=2, "A");
|
||||
v.replace_range(1..=2, "A");
|
||||
assert_eq!(v, "1A895");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_splice_out_of_bounds() {
|
||||
fn test_replace_range_out_of_bounds() {
|
||||
let mut s = String::from("12345");
|
||||
s.splice(5..6, "789");
|
||||
s.replace_range(5..6, "789");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_splice_inclusive_out_of_bounds() {
|
||||
fn test_replace_range_inclusive_out_of_bounds() {
|
||||
let mut s = String::from("12345");
|
||||
s.splice(5..=5, "789");
|
||||
s.replace_range(5..=5, "789");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_splice_empty() {
|
||||
fn test_replace_range_empty() {
|
||||
let mut s = String::from("12345");
|
||||
s.splice(1..2, "");
|
||||
s.replace_range(1..2, "");
|
||||
assert_eq!(s, "1345");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_splice_unbounded() {
|
||||
fn test_replace_range_unbounded() {
|
||||
let mut s = String::from("12345");
|
||||
s.splice(.., "");
|
||||
s.replace_range(.., "");
|
||||
assert_eq!(s, "");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
use std::borrow::Cow;
|
||||
use std::mem::size_of;
|
||||
use std::{usize, isize, panic};
|
||||
use std::{usize, isize};
|
||||
use std::vec::{Drain, IntoIter};
|
||||
use std::collections::CollectionAllocErr::*;
|
||||
|
||||
|
|
@ -753,24 +753,6 @@ fn assert_covariance() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_placement() {
|
||||
let mut vec = vec![1];
|
||||
assert_eq!(vec.place_back() <- 2, &2);
|
||||
assert_eq!(vec.len(), 2);
|
||||
assert_eq!(vec.place_back() <- 3, &3);
|
||||
assert_eq!(vec.len(), 3);
|
||||
assert_eq!(&vec, &[1, 2, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_placement_panic() {
|
||||
let mut vec = vec![1, 2, 3];
|
||||
fn mkpanic() -> usize { panic!() }
|
||||
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { vec.place_back() <- mkpanic(); }));
|
||||
assert_eq!(vec.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_into_inner() {
|
||||
let vec = vec![1, 2, 3];
|
||||
|
|
|
|||
|
|
@ -1004,28 +1004,6 @@ fn test_is_empty() {
|
|||
assert!(v.into_iter().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_placement_in() {
|
||||
let mut buf: VecDeque<isize> = VecDeque::new();
|
||||
buf.place_back() <- 1;
|
||||
buf.place_back() <- 2;
|
||||
assert_eq!(buf, [1,2]);
|
||||
|
||||
buf.place_front() <- 3;
|
||||
buf.place_front() <- 4;
|
||||
assert_eq!(buf, [4,3,1,2]);
|
||||
|
||||
{
|
||||
let ptr_head = buf.place_front() <- 5;
|
||||
assert_eq!(*ptr_head, 5);
|
||||
}
|
||||
{
|
||||
let ptr_tail = buf.place_back() <- 6;
|
||||
assert_eq!(*ptr_tail, 6);
|
||||
}
|
||||
assert_eq!(buf, [5,4,3,1,2,6]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reserve_exact_2() {
|
||||
// This is all the same as test_reserve
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use core::cmp::Ordering;
|
||||
use core::cmp::{self, Ordering};
|
||||
use core::fmt;
|
||||
use core::hash::{self, Hash};
|
||||
use core::intrinsics::{arith_offset, assume};
|
||||
|
|
@ -75,7 +75,8 @@ use core::marker::PhantomData;
|
|||
use core::mem;
|
||||
#[cfg(not(test))]
|
||||
use core::num::Float;
|
||||
use core::ops::{InPlace, Index, IndexMut, Place, Placer};
|
||||
use core::ops::Bound::{Excluded, Included, Unbounded};
|
||||
use core::ops::{Index, IndexMut, RangeBounds};
|
||||
use core::ops;
|
||||
use core::ptr;
|
||||
use core::ptr::NonNull;
|
||||
|
|
@ -85,9 +86,7 @@ use borrow::ToOwned;
|
|||
use borrow::Cow;
|
||||
use boxed::Box;
|
||||
use raw_vec::RawVec;
|
||||
use super::range::RangeArgument;
|
||||
use super::allocator::CollectionAllocErr;
|
||||
use Bound::{Excluded, Included, Unbounded};
|
||||
|
||||
/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector'.
|
||||
///
|
||||
|
|
@ -334,9 +333,10 @@ impl<T> Vec<T> {
|
|||
/// The vector will be able to hold exactly `capacity` elements without
|
||||
/// reallocating. If `capacity` is 0, the vector will not allocate.
|
||||
///
|
||||
/// It is important to note that this function does not specify the *length*
|
||||
/// of the returned vector, but only the *capacity*. For an explanation of
|
||||
/// the difference between length and capacity, see *[Capacity and reallocation]*.
|
||||
/// It is important to note that although the returned vector has the
|
||||
/// *capacity* specified, the vector will have a zero *length*. For an
|
||||
/// explanation of the difference between length and capacity, see
|
||||
/// *[Capacity and reallocation]*.
|
||||
///
|
||||
/// [Capacity and reallocation]: #capacity-and-reallocation
|
||||
///
|
||||
|
|
@ -586,6 +586,31 @@ impl<T> Vec<T> {
|
|||
self.buf.shrink_to_fit(self.len);
|
||||
}
|
||||
|
||||
/// Shrinks the capacity of the vector with a lower bound.
|
||||
///
|
||||
/// The capacity will remain at least as large as both the length
|
||||
/// and the supplied value.
|
||||
///
|
||||
/// Panics if the current capacity is smaller than the supplied
|
||||
/// minimum capacity.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(shrink_to)]
|
||||
/// let mut vec = Vec::with_capacity(10);
|
||||
/// vec.extend([1, 2, 3].iter().cloned());
|
||||
/// assert_eq!(vec.capacity(), 10);
|
||||
/// vec.shrink_to(4);
|
||||
/// assert!(vec.capacity() >= 4);
|
||||
/// vec.shrink_to(0);
|
||||
/// assert!(vec.capacity() >= 3);
|
||||
/// ```
|
||||
#[unstable(feature = "shrink_to", reason = "new API", issue="0")]
|
||||
pub fn shrink_to(&mut self, min_capacity: usize) {
|
||||
self.buf.shrink_to_fit(cmp::max(self.len, min_capacity));
|
||||
}
|
||||
|
||||
/// Converts the vector into [`Box<[T]>`][owned slice].
|
||||
///
|
||||
/// Note that this will drop any excess capacity.
|
||||
|
|
@ -1040,29 +1065,6 @@ impl<T> Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns a place for insertion at the back of the `Vec`.
|
||||
///
|
||||
/// Using this method with placement syntax is equivalent to [`push`](#method.push),
|
||||
/// but may be more efficient.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(collection_placement)]
|
||||
/// #![feature(placement_in_syntax)]
|
||||
///
|
||||
/// let mut vec = vec![1, 2];
|
||||
/// vec.place_back() <- 3;
|
||||
/// vec.place_back() <- 4;
|
||||
/// assert_eq!(&vec, &[1, 2, 3, 4]);
|
||||
/// ```
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
pub fn place_back(&mut self) -> PlaceBack<T> {
|
||||
PlaceBack { vec: self }
|
||||
}
|
||||
|
||||
/// Removes the last element from a vector and returns it, or [`None`] if it
|
||||
/// is empty.
|
||||
///
|
||||
|
|
@ -1150,7 +1152,7 @@ impl<T> Vec<T> {
|
|||
/// ```
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
pub fn drain<R>(&mut self, range: R) -> Drain<T>
|
||||
where R: RangeArgument<usize>
|
||||
where R: RangeBounds<usize>
|
||||
{
|
||||
// Memory safety
|
||||
//
|
||||
|
|
@ -1281,6 +1283,49 @@ impl<T> Vec<T> {
|
|||
}
|
||||
other
|
||||
}
|
||||
|
||||
/// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
|
||||
///
|
||||
/// If `new_len` is greater than `len`, the `Vec` is extended by the
|
||||
/// difference, with each additional slot filled with the result of
|
||||
/// calling the closure `f`. The return values from `f` will end up
|
||||
/// in the `Vec` in the order they have been generated.
|
||||
///
|
||||
/// If `new_len` is less than `len`, the `Vec` is simply truncated.
|
||||
///
|
||||
/// This method uses a closure to create new values on every push. If
|
||||
/// you'd rather [`Clone`] a given value, use [`resize`]. If you want
|
||||
/// to use the [`Default`] trait to generate values, you can pass
|
||||
/// [`Default::default()`] as the second argument..
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(vec_resize_with)]
|
||||
///
|
||||
/// let mut vec = vec![1, 2, 3];
|
||||
/// vec.resize_with(5, Default::default);
|
||||
/// assert_eq!(vec, [1, 2, 3, 0, 0]);
|
||||
///
|
||||
/// let mut vec = vec![];
|
||||
/// let mut p = 1;
|
||||
/// vec.resize_with(4, || { p *= 2; p });
|
||||
/// assert_eq!(vec, [2, 4, 8, 16]);
|
||||
/// ```
|
||||
///
|
||||
/// [`resize`]: #method.resize
|
||||
/// [`Clone`]: ../../std/clone/trait.Clone.html
|
||||
#[unstable(feature = "vec_resize_with", issue = "41758")]
|
||||
pub fn resize_with<F>(&mut self, new_len: usize, f: F)
|
||||
where F: FnMut() -> T
|
||||
{
|
||||
let len = self.len();
|
||||
if new_len > len {
|
||||
self.extend_with(new_len - len, ExtendFunc(f));
|
||||
} else {
|
||||
self.truncate(new_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Vec<T> {
|
||||
|
|
@ -1291,8 +1336,8 @@ impl<T: Clone> Vec<T> {
|
|||
/// If `new_len` is less than `len`, the `Vec` is simply truncated.
|
||||
///
|
||||
/// This method requires [`Clone`] to be able clone the passed value. If
|
||||
/// you'd rather create a value with [`Default`] instead, see
|
||||
/// [`resize_default`].
|
||||
/// you need more flexibility (or want to rely on [`Default`] instead of
|
||||
/// [`Clone`]), use [`resize_with`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1308,7 +1353,7 @@ impl<T: Clone> Vec<T> {
|
|||
///
|
||||
/// [`Clone`]: ../../std/clone/trait.Clone.html
|
||||
/// [`Default`]: ../../std/default/trait.Default.html
|
||||
/// [`resize_default`]: #method.resize_default
|
||||
/// [`resize_with`]: #method.resize_with
|
||||
#[stable(feature = "vec_resize", since = "1.5.0")]
|
||||
pub fn resize(&mut self, new_len: usize, value: T) {
|
||||
let len = self.len();
|
||||
|
|
@ -1387,24 +1432,31 @@ impl<T: Default> Vec<T> {
|
|||
|
||||
// This code generalises `extend_with_{element,default}`.
|
||||
trait ExtendWith<T> {
|
||||
fn next(&self) -> T;
|
||||
fn next(&mut self) -> T;
|
||||
fn last(self) -> T;
|
||||
}
|
||||
|
||||
struct ExtendElement<T>(T);
|
||||
impl<T: Clone> ExtendWith<T> for ExtendElement<T> {
|
||||
fn next(&self) -> T { self.0.clone() }
|
||||
fn next(&mut self) -> T { self.0.clone() }
|
||||
fn last(self) -> T { self.0 }
|
||||
}
|
||||
|
||||
struct ExtendDefault;
|
||||
impl<T: Default> ExtendWith<T> for ExtendDefault {
|
||||
fn next(&self) -> T { Default::default() }
|
||||
fn next(&mut self) -> T { Default::default() }
|
||||
fn last(self) -> T { Default::default() }
|
||||
}
|
||||
|
||||
struct ExtendFunc<F>(F);
|
||||
impl<T, F: FnMut() -> T> ExtendWith<T> for ExtendFunc<F> {
|
||||
fn next(&mut self) -> T { (self.0)() }
|
||||
fn last(mut self) -> T { (self.0)() }
|
||||
}
|
||||
|
||||
impl<T> Vec<T> {
|
||||
/// Extend the vector by `n` values, using the given generator.
|
||||
fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, value: E) {
|
||||
fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) {
|
||||
self.reserve(n);
|
||||
|
||||
unsafe {
|
||||
|
|
@ -1542,40 +1594,69 @@ impl SpecFromElem for u8 {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_spec_from_elem {
|
||||
($t: ty, $is_zero: expr) => {
|
||||
impl SpecFromElem for $t {
|
||||
#[inline]
|
||||
fn from_elem(elem: $t, n: usize) -> Vec<$t> {
|
||||
if $is_zero(elem) {
|
||||
return Vec {
|
||||
buf: RawVec::with_capacity_zeroed(n),
|
||||
len: n,
|
||||
}
|
||||
}
|
||||
let mut v = Vec::with_capacity(n);
|
||||
v.extend_with(n, ExtendElement(elem));
|
||||
v
|
||||
impl<T: Clone + IsZero> SpecFromElem for T {
|
||||
#[inline]
|
||||
fn from_elem(elem: T, n: usize) -> Vec<T> {
|
||||
if elem.is_zero() {
|
||||
return Vec {
|
||||
buf: RawVec::with_capacity_zeroed(n),
|
||||
len: n,
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut v = Vec::with_capacity(n);
|
||||
v.extend_with(n, ExtendElement(elem));
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
impl_spec_from_elem!(i8, |x| x == 0);
|
||||
impl_spec_from_elem!(i16, |x| x == 0);
|
||||
impl_spec_from_elem!(i32, |x| x == 0);
|
||||
impl_spec_from_elem!(i64, |x| x == 0);
|
||||
impl_spec_from_elem!(i128, |x| x == 0);
|
||||
impl_spec_from_elem!(isize, |x| x == 0);
|
||||
unsafe trait IsZero {
|
||||
/// Whether this value is zero
|
||||
fn is_zero(&self) -> bool;
|
||||
}
|
||||
|
||||
impl_spec_from_elem!(u16, |x| x == 0);
|
||||
impl_spec_from_elem!(u32, |x| x == 0);
|
||||
impl_spec_from_elem!(u64, |x| x == 0);
|
||||
impl_spec_from_elem!(u128, |x| x == 0);
|
||||
impl_spec_from_elem!(usize, |x| x == 0);
|
||||
macro_rules! impl_is_zero {
|
||||
($t: ty, $is_zero: expr) => {
|
||||
unsafe impl IsZero for $t {
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool {
|
||||
$is_zero(*self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_is_zero!(i8, |x| x == 0);
|
||||
impl_is_zero!(i16, |x| x == 0);
|
||||
impl_is_zero!(i32, |x| x == 0);
|
||||
impl_is_zero!(i64, |x| x == 0);
|
||||
impl_is_zero!(i128, |x| x == 0);
|
||||
impl_is_zero!(isize, |x| x == 0);
|
||||
|
||||
impl_is_zero!(u16, |x| x == 0);
|
||||
impl_is_zero!(u32, |x| x == 0);
|
||||
impl_is_zero!(u64, |x| x == 0);
|
||||
impl_is_zero!(u128, |x| x == 0);
|
||||
impl_is_zero!(usize, |x| x == 0);
|
||||
|
||||
impl_is_zero!(char, |x| x == '\0');
|
||||
|
||||
impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
|
||||
impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
|
||||
|
||||
unsafe impl<T: ?Sized> IsZero for *const T {
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool {
|
||||
(*self).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized> IsZero for *mut T {
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool {
|
||||
(*self).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
impl_spec_from_elem!(f32, |x: f32| x == 0. && x.is_sign_positive());
|
||||
impl_spec_from_elem!(f64, |x: f64| x == 0. && x.is_sign_positive());
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Common trait implementations for Vec
|
||||
|
|
@ -1924,7 +2005,7 @@ impl<T> Vec<T> {
|
|||
#[inline]
|
||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||
pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<I::IntoIter>
|
||||
where R: RangeArgument<usize>, I: IntoIterator<Item=T>
|
||||
where R: RangeBounds<usize>, I: IntoIterator<Item=T>
|
||||
{
|
||||
Splice {
|
||||
drain: self.drain(range),
|
||||
|
|
@ -2467,57 +2548,6 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> {
|
|||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
impl<'a, T> FusedIterator for Drain<'a, T> {}
|
||||
|
||||
/// A place for insertion at the back of a `Vec`.
|
||||
///
|
||||
/// See [`Vec::place_back`](struct.Vec.html#method.place_back) for details.
|
||||
#[must_use = "places do nothing unless written to with `<-` syntax"]
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "struct name and placement protocol are subject to change",
|
||||
issue = "30172")]
|
||||
#[derive(Debug)]
|
||||
pub struct PlaceBack<'a, T: 'a> {
|
||||
vec: &'a mut Vec<T>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T> Placer<T> for PlaceBack<'a, T> {
|
||||
type Place = PlaceBack<'a, T>;
|
||||
|
||||
fn make_place(self) -> Self {
|
||||
// This will panic or abort if we would allocate > isize::MAX bytes
|
||||
// or if the length increment would overflow for zero-sized types.
|
||||
if self.vec.len == self.vec.buf.cap() {
|
||||
self.vec.buf.double();
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
unsafe impl<'a, T> Place<T> for PlaceBack<'a, T> {
|
||||
fn pointer(&mut self) -> *mut T {
|
||||
unsafe { self.vec.as_mut_ptr().offset(self.vec.len as isize) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T> InPlace<T> for PlaceBack<'a, T> {
|
||||
type Owner = &'a mut T;
|
||||
|
||||
unsafe fn finalize(mut self) -> &'a mut T {
|
||||
let ptr = self.pointer();
|
||||
self.vec.len += 1;
|
||||
&mut *ptr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A splicing iterator for `Vec`.
|
||||
///
|
||||
/// This struct is created by the [`splice()`] method on [`Vec`]. See its
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue