Merge branch 'master' of https://github.com/rust-lang/rust into e0389
This commit is contained in:
commit
1b06fe1ef5
2862 changed files with 33811 additions and 21923 deletions
44
.travis.yml
44
.travis.yml
|
|
@ -30,7 +30,6 @@ matrix:
|
|||
SRC=.
|
||||
DEPLOY_ALT=1
|
||||
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
|
||||
SCCACHE_ERROR_LOG=/tmp/sccache.log
|
||||
MACOSX_DEPLOYMENT_TARGET=10.7
|
||||
NO_LLVM_ASSERTIONS=1
|
||||
NO_DEBUG_ASSERTIONS=1
|
||||
|
|
@ -50,13 +49,12 @@ matrix:
|
|||
RUST_CONFIGURE_ARGS="--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler"
|
||||
SRC=.
|
||||
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
|
||||
SCCACHE_ERROR_LOG=/tmp/sccache.log
|
||||
MACOSX_DEPLOYMENT_TARGET=10.8
|
||||
MACOSX_STD_DEPLOYMENT_TARGET=10.7
|
||||
NO_LLVM_ASSERTIONS=1
|
||||
NO_DEBUG_ASSERTIONS=1
|
||||
os: osx
|
||||
osx_image: xcode9.2
|
||||
osx_image: xcode9.3-moar
|
||||
if: branch = auto
|
||||
|
||||
- env: >
|
||||
|
|
@ -64,13 +62,12 @@ matrix:
|
|||
RUST_CONFIGURE_ARGS=--build=i686-apple-darwin
|
||||
SRC=.
|
||||
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
|
||||
SCCACHE_ERROR_LOG=/tmp/sccache.log
|
||||
MACOSX_DEPLOYMENT_TARGET=10.8
|
||||
MACOSX_STD_DEPLOYMENT_TARGET=10.7
|
||||
NO_LLVM_ASSERTIONS=1
|
||||
NO_DEBUG_ASSERTIONS=1
|
||||
os: osx
|
||||
osx_image: xcode9.2
|
||||
osx_image: xcode9.3-moar
|
||||
if: branch = auto
|
||||
|
||||
# OSX builders producing releases. These do not run the full test suite and
|
||||
|
|
@ -85,7 +82,6 @@ matrix:
|
|||
SRC=.
|
||||
DEPLOY=1
|
||||
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
|
||||
SCCACHE_ERROR_LOG=/tmp/sccache.log
|
||||
MACOSX_DEPLOYMENT_TARGET=10.7
|
||||
NO_LLVM_ASSERTIONS=1
|
||||
NO_DEBUG_ASSERTIONS=1
|
||||
|
|
@ -99,7 +95,6 @@ matrix:
|
|||
SRC=.
|
||||
DEPLOY=1
|
||||
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
|
||||
SCCACHE_ERROR_LOG=/tmp/sccache.log
|
||||
MACOSX_DEPLOYMENT_TARGET=10.7
|
||||
NO_LLVM_ASSERTIONS=1
|
||||
NO_DEBUG_ASSERTIONS=1
|
||||
|
|
@ -176,14 +171,11 @@ matrix:
|
|||
if: branch = auto
|
||||
- env: IMAGE=x86_64-gnu-distcheck
|
||||
if: branch = auto
|
||||
- env: IMAGE=x86_64-gnu-incremental
|
||||
if: branch = auto
|
||||
|
||||
- stage: publish toolstate
|
||||
if: branch = master AND type = push
|
||||
before_install: []
|
||||
install: []
|
||||
cache: false
|
||||
sudo: false
|
||||
script:
|
||||
MESSAGE_FILE=$(mktemp -t msg.XXXXXX);
|
||||
|
|
@ -201,7 +193,12 @@ env:
|
|||
- secure: "cFh8thThqEJLC98XKI5pfqflUzOlxsYPRW20AWRaYOOgYHPTiGWypTXiPbGSKaeAXTZoOA+DpQtEmefc0U6lt9dHc7a/MIaK6isFurjlnKYiLOeTruzyu1z7PWCeZ/jKXsU2RK/88DBtlNwfMdaMIeuKj14IVfpepPPL71ETbuk="
|
||||
|
||||
before_install:
|
||||
- zcat $HOME/docker/rust-ci.tar.gz | docker load || true
|
||||
# We'll use the AWS cli to download/upload cached docker layers, so install
|
||||
# that here.
|
||||
- if [ "$TRAVIS_OS_NAME" = linux ]; then
|
||||
pip install --user awscli;
|
||||
export PATH=$PATH:$HOME/.local/bin;
|
||||
fi
|
||||
- mkdir -p $HOME/rustsrc
|
||||
# FIXME(#46924): these two commands are required to enable IPv6,
|
||||
# they shouldn't exist, please revert once more official solutions appeared.
|
||||
|
|
@ -223,7 +220,7 @@ install:
|
|||
travis_retry brew update &&
|
||||
travis_retry brew install xz;
|
||||
fi &&
|
||||
travis_retry 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-apple-darwin &&
|
||||
travis_retry curl -fo /usr/local/bin/sccache https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-02-sccache-x86_64-apple-darwin &&
|
||||
chmod +x /usr/local/bin/sccache &&
|
||||
travis_retry curl -fo /usr/local/bin/stamp https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin &&
|
||||
chmod +x /usr/local/bin/stamp
|
||||
|
|
@ -264,44 +261,25 @@ after_failure:
|
|||
df -h;
|
||||
du . | sort -nr | head -n100
|
||||
|
||||
# One of these is the linux sccache log, one is the OSX sccache log. Instead
|
||||
# of worrying about what system we are just cat both. One of these commands
|
||||
# will fail but that's ok, they'll both get executed.
|
||||
- cat obj/tmp/sccache.log
|
||||
- cat /tmp/sccache.log
|
||||
|
||||
# Random attempt at debugging currently. Just poking around in here to see if
|
||||
# anything shows up.
|
||||
- ls -lat $HOME/Library/Logs/DiagnosticReports/
|
||||
- find $HOME/Library/Logs/DiagnosticReports
|
||||
-type f
|
||||
-name '*.crash'
|
||||
-not -name '*.stage2-*.crash'
|
||||
-not -name 'com.apple.CoreSimulator.CoreSimulatorService-*.crash'
|
||||
-exec printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" {} \;
|
||||
-exec head -750 {} \;
|
||||
-exec echo travis_fold":"end:crashlog \;
|
||||
-exec echo travis_fold":"end:crashlog \; || true
|
||||
|
||||
# attempt to debug anything killed by the oom killer on linux, just to see if
|
||||
# it happened
|
||||
- dmesg | grep -i kill
|
||||
|
||||
# Save tagged docker images we created and load them if they're available
|
||||
# Travis saves caches whether the build failed or not, nuke rustsrc if
|
||||
# the failure was while updating it (as it may be in a bad state)
|
||||
# https://github.com/travis-ci/travis-ci/issues/4472
|
||||
before_cache:
|
||||
- docker history -q rust-ci |
|
||||
grep -v missing |
|
||||
xargs docker save |
|
||||
gzip > $HOME/docker/rust-ci.tar.gz
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/docker
|
||||
|
||||
before_deploy:
|
||||
- mkdir -p deploy/$TRAVIS_COMMIT
|
||||
- >
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ A version of this document [can be found online](https://www.rust-lang.org/condu
|
|||
* Please be kind and courteous. There's no need to be mean or rude.
|
||||
* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
|
||||
* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
|
||||
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behaviour. We interpret the term "harassment" as including the definition in the <a href="http://citizencodeofconduct.org/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
|
||||
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the <a href="http://citizencodeofconduct.org/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
|
||||
* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
|
||||
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behaviour is not welcome.
|
||||
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
|
||||
|
||||
## Moderation
|
||||
|
||||
|
|
|
|||
|
|
@ -26,10 +26,10 @@ As a reminder, all contributors are expected to follow our [Code of Conduct][coc
|
|||
## Feature Requests
|
||||
[feature-requests]: #feature-requests
|
||||
|
||||
To request a change to the way that the Rust language works, please open an
|
||||
issue in the [RFCs repository](https://github.com/rust-lang/rfcs/issues/new)
|
||||
rather than this one. New features and other significant language changes
|
||||
must go through the RFC process.
|
||||
To request a change to the way the Rust language works, please head over
|
||||
to the [RFCs repository](https://github.com/rust-lang/rfcs) and view the
|
||||
[README](https://github.com/rust-lang/rfcs/blob/master/README.md)
|
||||
for instructions.
|
||||
|
||||
## Bug Reports
|
||||
[bug-reports]: #bug-reports
|
||||
|
|
@ -594,7 +594,7 @@ If you're looking for somewhere to start, check out the [E-easy][eeasy] tag.
|
|||
[inom]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AI-nominated
|
||||
[eeasy]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy
|
||||
[lru]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc
|
||||
[rfcbot]: https://github.com/dikaiosune/rust-dashboard/blob/master/RFCBOT.md
|
||||
[rfcbot]: https://github.com/anp/rfcbot-rs/
|
||||
|
||||
## Out-of-tree Contributions
|
||||
[out-of-tree-contributions]: #out-of-tree-contributions
|
||||
|
|
|
|||
112
RELEASES.md
112
RELEASES.md
|
|
@ -1,3 +1,115 @@
|
|||
Version 1.25.0 (2018-03-29)
|
||||
==========================
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Stabilised `#[repr(align(x))]`.][47006] [RFC 1358]
|
||||
- [You can now use nested groups of imports.][47948]
|
||||
e.g. `use std::{fs::File, io::Read, path::{Path, PathBuf}};`
|
||||
- [You can now have `|` at the start of a match arm.][47947] e.g.
|
||||
```rust
|
||||
enum Foo { A, B, C }
|
||||
|
||||
fn main() {
|
||||
let x = Foo::A;
|
||||
match x {
|
||||
| Foo::A
|
||||
| Foo::B => println!("AB"),
|
||||
| Foo::C => println!("C"),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [Upgraded to LLVM 6.][47828]
|
||||
- [Added `-C lto=val` option.][47521]
|
||||
- [Added `i586-unknown-linux-musl` target][47282]
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [Impl Send for `process::Command` on Unix.][47760]
|
||||
- [Impl PartialEq and Eq for `ParseCharError`.][47790]
|
||||
- [`UnsafeCell::into_inner` is now safe.][47204]
|
||||
- [Implement libstd for CloudABI.][47268]
|
||||
- [`Float::{from_bits, to_bits}` is now available in libcore.][46931]
|
||||
- [Implement `AsRef<Path>` for Component][46985]
|
||||
- [Implemented `Write` for `Cursor<&mut Vec<u8>>`][46830]
|
||||
- [Moved `Duration` to libcore.][46666]
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
- [`Location::column`]
|
||||
- [`ptr::NonNull`]
|
||||
|
||||
The following functions can now be used in a constant expression.
|
||||
eg. `static MINUTE: Duration = Duration::from_secs(60);`
|
||||
- [`Duration::new`][47300]
|
||||
- [`Duration::from_secs`][47300]
|
||||
- [`Duration::from_millis`][47300]
|
||||
|
||||
Cargo
|
||||
-----
|
||||
- [`cargo new` no longer removes `rust` or `rs` prefixs/suffixs.][cargo/5013]
|
||||
- [`cargo new` now defaults to creating a binary crate, instead of a
|
||||
library crate.][cargo/5029]
|
||||
|
||||
Misc
|
||||
----
|
||||
- [Rust by example is now shipped with new releases][46196]
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [Deprecated `net::lookup_host`.][47510]
|
||||
- [`rustdoc` has switched to pulldown as the default markdown renderer.][47398]
|
||||
- The borrow checker was sometimes incorrectly permitting overlapping borrows
|
||||
around indexing operations (see [#47349][47349]). This has been fixed (which also
|
||||
enabled some correct code that used to cause errors (e.g. [#33903][33903] and [#46095][46095]).
|
||||
- [Removed deprecated unstable attribute `#[simd]`.][47251]
|
||||
|
||||
[33903]: https://github.com/rust-lang/rust/pull/33903
|
||||
[47947]: https://github.com/rust-lang/rust/pull/47947
|
||||
[47948]: https://github.com/rust-lang/rust/pull/47948
|
||||
[47760]: https://github.com/rust-lang/rust/pull/47760
|
||||
[47790]: https://github.com/rust-lang/rust/pull/47790
|
||||
[47828]: https://github.com/rust-lang/rust/pull/47828
|
||||
[47398]: https://github.com/rust-lang/rust/pull/47398
|
||||
[47510]: https://github.com/rust-lang/rust/pull/47510
|
||||
[47521]: https://github.com/rust-lang/rust/pull/47521
|
||||
[47204]: https://github.com/rust-lang/rust/pull/47204
|
||||
[47251]: https://github.com/rust-lang/rust/pull/47251
|
||||
[47268]: https://github.com/rust-lang/rust/pull/47268
|
||||
[47282]: https://github.com/rust-lang/rust/pull/47282
|
||||
[47300]: https://github.com/rust-lang/rust/pull/47300
|
||||
[47349]: https://github.com/rust-lang/rust/pull/47349
|
||||
[46931]: https://github.com/rust-lang/rust/pull/46931
|
||||
[46985]: https://github.com/rust-lang/rust/pull/46985
|
||||
[47006]: https://github.com/rust-lang/rust/pull/47006
|
||||
[46830]: https://github.com/rust-lang/rust/pull/46830
|
||||
[46095]: https://github.com/rust-lang/rust/pull/46095
|
||||
[46666]: https://github.com/rust-lang/rust/pull/46666
|
||||
[46196]: https://github.com/rust-lang/rust/pull/46196
|
||||
[cargo/5013]: https://github.com/rust-lang/cargo/pull/5013
|
||||
[cargo/5029]: https://github.com/rust-lang/cargo/pull/5029
|
||||
[RFC 1358]: https://github.com/rust-lang/rfcs/pull/1358
|
||||
[`Location::column`]: https://doc.rust-lang.org/std/panic/struct.Location.html#method.column
|
||||
[`ptr::NonNull`]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html
|
||||
|
||||
|
||||
Version 1.24.1 (2018-03-01)
|
||||
==========================
|
||||
|
||||
- [Do not abort when unwinding through FFI][48251]
|
||||
- [Emit UTF-16 files for linker arguments on Windows][48318]
|
||||
- [Make the error index generator work again][48308]
|
||||
- [Cargo will warn on Windows 7 if an update is needed][cargo/5069].
|
||||
|
||||
[48251]: https://github.com/rust-lang/rust/issues/48251
|
||||
[48308]: https://github.com/rust-lang/rust/issues/48308
|
||||
[48318]: https://github.com/rust-lang/rust/issues/48318
|
||||
[cargo/5069]: https://github.com/rust-lang/cargo/pull/5069
|
||||
|
||||
|
||||
Version 1.24.0 (2018-02-15)
|
||||
==========================
|
||||
|
||||
|
|
|
|||
18
appveyor.yml
18
appveyor.yml
|
|
@ -20,10 +20,10 @@ environment:
|
|||
SCRIPT: python x.py test
|
||||
- MSYS_BITS: 32
|
||||
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
|
||||
SCRIPT: python x.py test --exclude src/test/run-pass --exclude src/test/compile-fail
|
||||
SCRIPT: make appveyor-subset-1
|
||||
- MSYS_BITS: 32
|
||||
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
|
||||
SCRIPT: python x.py test src/test/run-pass src/test/compile-fail
|
||||
SCRIPT: make appveyor-subset-2
|
||||
|
||||
# MSVC aux tests
|
||||
- MSYS_BITS: 64
|
||||
|
|
@ -53,13 +53,13 @@ environment:
|
|||
# SourceForge is notoriously flaky, so we mirror it on our own infrastructure.
|
||||
- MSYS_BITS: 32
|
||||
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
|
||||
SCRIPT: python x.py test --exclude src/test/run-pass --exclude src/test/compile-fail
|
||||
SCRIPT: make appveyor-subset-1
|
||||
MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
|
||||
MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
|
||||
MINGW_DIR: mingw32
|
||||
- MSYS_BITS: 32
|
||||
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
|
||||
SCRIPT: python x.py test src/test/run-pass src/test/compile-fail
|
||||
SCRIPT: make appveyor-subset-2
|
||||
MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
|
||||
MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
|
||||
MINGW_DIR: mingw32
|
||||
|
|
@ -152,8 +152,8 @@ install:
|
|||
- set PATH=C:\Python27;%PATH%
|
||||
|
||||
# Download and install sccache
|
||||
- appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-05-12-sccache-x86_64-pc-windows-msvc
|
||||
- mv 2017-05-12-sccache-x86_64-pc-windows-msvc sccache.exe
|
||||
- appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-02-sccache-x86_64-pc-windows-msvc
|
||||
- mv 2018-04-02-sccache-x86_64-pc-windows-msvc sccache.exe
|
||||
- set PATH=%PATH%;%CD%
|
||||
|
||||
# Download and install ninja
|
||||
|
|
@ -176,9 +176,6 @@ install:
|
|||
- set PATH=%PATH%;%CD%\handle
|
||||
- handle.exe -accepteula -help
|
||||
|
||||
# Attempt to debug sccache failures
|
||||
- set SCCACHE_ERROR_LOG=%CD%/sccache.log
|
||||
|
||||
test_script:
|
||||
- if not exist C:\cache\rustsrc\NUL mkdir C:\cache\rustsrc
|
||||
- sh src/ci/init_repo.sh . /c/cache/rustsrc
|
||||
|
|
@ -186,9 +183,6 @@ test_script:
|
|||
- set NO_CCACHE=1
|
||||
- sh src/ci/run.sh
|
||||
|
||||
on_failure:
|
||||
- cat %CD%\sccache.log || exit 0
|
||||
|
||||
branches:
|
||||
only:
|
||||
- auto
|
||||
|
|
|
|||
|
|
@ -118,6 +118,10 @@
|
|||
# Indicate whether submodules are managed and updated automatically.
|
||||
#submodules = true
|
||||
|
||||
# Update submodules only when the checked out commit in the submodules differs
|
||||
# from what is committed in the main rustc repo.
|
||||
#fast-submodules = true
|
||||
|
||||
# The path to (or name of) the GDB executable to use. This is only used for
|
||||
# executing the debuginfo test suite.
|
||||
#gdb = "gdb"
|
||||
|
|
@ -182,6 +186,10 @@
|
|||
# essentially skipping stage0 as the local compiler is recompiling itself again.
|
||||
#local-rebuild = false
|
||||
|
||||
# Print out how long each rustbuild step took (mostly intended for CI and
|
||||
# tracking over time)
|
||||
#print-step-timings = false
|
||||
|
||||
# =============================================================================
|
||||
# General install configuration options
|
||||
# =============================================================================
|
||||
|
|
@ -239,11 +247,6 @@
|
|||
# compiler.
|
||||
#codegen-units = 1
|
||||
|
||||
# Whether to enable ThinLTO (and increase the codegen units to either a default
|
||||
# or the configured value). On by default. If we want the fastest possible
|
||||
# compiler, we should disable this.
|
||||
#thinlto = true
|
||||
|
||||
# Whether or not debug assertions are enabled for the compiler and standard
|
||||
# library. Also enables compilation of debug! and trace! logging macros.
|
||||
#debug-assertions = false
|
||||
|
|
@ -268,6 +271,9 @@
|
|||
# Whether or not `panic!`s generate backtraces (RUST_BACKTRACE)
|
||||
#backtrace = true
|
||||
|
||||
# Build rustc with experimental parallelization
|
||||
#experimental-parallel-queries = false
|
||||
|
||||
# The default linker that will be hard-coded into the generated compiler for
|
||||
# targets that don't specify linker explicitly in their target specifications.
|
||||
# Note that this is not the linker used to link said compiler.
|
||||
|
|
|
|||
1406
src/Cargo.lock
generated
1406
src/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -72,3 +72,4 @@ cargo = { path = "tools/cargo" }
|
|||
# RLS depends on `rustfmt` from crates.io, so we put this in a `[patch]` section
|
||||
# for crates.io
|
||||
rustfmt-nightly = { path = "tools/rustfmt" }
|
||||
clippy_lints = { path = "tools/clippy/clippy_lints" }
|
||||
|
|
|
|||
|
|
@ -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,12 +92,12 @@ 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));
|
||||
let mut dylib_path = bootstrap::util::dylib_path();
|
||||
dylib_path.insert(0, PathBuf::from(libdir));
|
||||
dylib_path.insert(0, PathBuf::from(&libdir));
|
||||
|
||||
let mut cmd = Command::new(rustc);
|
||||
cmd.args(&args)
|
||||
|
|
@ -103,11 +105,12 @@ 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
|
||||
// actually downloaded, so we just always pass the `--sysroot` option.
|
||||
cmd.arg("--sysroot").arg(sysroot);
|
||||
cmd.arg("--sysroot").arg(&sysroot);
|
||||
|
||||
// When we build Rust dylibs they're all intended for intermediate
|
||||
// usage, so make sure we pass the -Cprefer-dynamic flag instead of
|
||||
|
|
@ -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
|
||||
|
|
@ -175,9 +179,6 @@ fn main() {
|
|||
if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") {
|
||||
cmd.arg("-C").arg(format!("codegen-units={}", s));
|
||||
}
|
||||
if env::var("RUSTC_THINLTO").is_ok() {
|
||||
cmd.arg("-Ccodegen-units=16").arg("-Zthinlto");
|
||||
}
|
||||
|
||||
// Emit save-analysis info.
|
||||
if env::var("RUSTC_SAVE_ANALYSIS") == Ok("api".to_string()) {
|
||||
|
|
@ -280,33 +281,56 @@ fn main() {
|
|||
|
||||
if verbose > 1 {
|
||||
eprintln!("rustc command: {:?}", cmd);
|
||||
eprintln!("sysroot: {:?}", sysroot);
|
||||
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
|
||||
|
|
@ -597,10 +597,8 @@ class RustBuild(object):
|
|||
self.cargo()))
|
||||
args = [self.cargo(), "build", "--manifest-path",
|
||||
os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")]
|
||||
if self.verbose:
|
||||
for _ in range(1, self.verbose):
|
||||
args.append("--verbose")
|
||||
if self.verbose > 1:
|
||||
args.append("--verbose")
|
||||
if self.use_locked_deps:
|
||||
args.append("--locked")
|
||||
if self.use_vendored_sources:
|
||||
|
|
@ -614,20 +612,55 @@ class RustBuild(object):
|
|||
return config
|
||||
return default_build_triple()
|
||||
|
||||
def check_submodule(self, module, slow_submodules):
|
||||
if not slow_submodules:
|
||||
checked_out = subprocess.Popen(["git", "rev-parse", "HEAD"],
|
||||
cwd=os.path.join(self.rust_root, module),
|
||||
stdout=subprocess.PIPE)
|
||||
return checked_out
|
||||
else:
|
||||
return None
|
||||
|
||||
def update_submodule(self, module, checked_out, recorded_submodules):
|
||||
module_path = os.path.join(self.rust_root, module)
|
||||
|
||||
if checked_out != None:
|
||||
default_encoding = sys.getdefaultencoding()
|
||||
checked_out = checked_out.communicate()[0].decode(default_encoding).strip()
|
||||
if recorded_submodules[module] == checked_out:
|
||||
return
|
||||
|
||||
print("Updating submodule", module)
|
||||
|
||||
run(["git", "submodule", "-q", "sync", module],
|
||||
cwd=self.rust_root, verbose=self.verbose)
|
||||
run(["git", "submodule", "update",
|
||||
"--init", "--recursive", module],
|
||||
cwd=self.rust_root, verbose=self.verbose)
|
||||
run(["git", "reset", "-q", "--hard"],
|
||||
cwd=module_path, verbose=self.verbose)
|
||||
run(["git", "clean", "-qdfx"],
|
||||
cwd=module_path, verbose=self.verbose)
|
||||
|
||||
def update_submodules(self):
|
||||
"""Update submodules"""
|
||||
if (not os.path.exists(os.path.join(self.rust_root, ".git"))) or \
|
||||
self.get_toml('submodules') == "false":
|
||||
return
|
||||
print('Updating submodules')
|
||||
slow_submodules = self.get_toml('fast-submodules') == "false"
|
||||
start_time = time()
|
||||
if slow_submodules:
|
||||
print('Unconditionally updating all submodules')
|
||||
else:
|
||||
print('Updating only changed submodules')
|
||||
default_encoding = sys.getdefaultencoding()
|
||||
run(["git", "submodule", "-q", "sync"], cwd=self.rust_root, verbose=self.verbose)
|
||||
submodules = [s.split(' ', 1)[1] for s in subprocess.check_output(
|
||||
["git", "config", "--file",
|
||||
os.path.join(self.rust_root, ".gitmodules"),
|
||||
"--get-regexp", "path"]
|
||||
).decode(default_encoding).splitlines()]
|
||||
filtered_submodules = []
|
||||
submodules_names = []
|
||||
for module in submodules:
|
||||
if module.endswith("llvm"):
|
||||
if self.get_toml('llvm-config'):
|
||||
|
|
@ -645,16 +678,19 @@ class RustBuild(object):
|
|||
config = self.get_toml('lld')
|
||||
if config is None or config == 'false':
|
||||
continue
|
||||
filtered_submodules.append(module)
|
||||
run(["git", "submodule", "update",
|
||||
"--init", "--recursive"] + filtered_submodules,
|
||||
cwd=self.rust_root, verbose=self.verbose)
|
||||
run(["git", "submodule", "-q", "foreach", "git",
|
||||
"reset", "-q", "--hard"],
|
||||
cwd=self.rust_root, verbose=self.verbose)
|
||||
run(["git", "submodule", "-q", "foreach", "git",
|
||||
"clean", "-qdfx"],
|
||||
cwd=self.rust_root, verbose=self.verbose)
|
||||
check = self.check_submodule(module, slow_submodules)
|
||||
filtered_submodules.append((module, check))
|
||||
submodules_names.append(module)
|
||||
recorded = subprocess.Popen(["git", "ls-tree", "HEAD"] + submodules_names,
|
||||
cwd=self.rust_root, stdout=subprocess.PIPE)
|
||||
recorded = recorded.communicate()[0].decode(default_encoding).strip().splitlines()
|
||||
recorded_submodules = {}
|
||||
for data in recorded:
|
||||
data = data.split()
|
||||
recorded_submodules[data[3]] = data[2]
|
||||
for module in filtered_submodules:
|
||||
self.update_submodule(module[0], module[1], recorded_submodules)
|
||||
print("Submodules updated in %.2f seconds" % (time() - start_time))
|
||||
|
||||
def set_dev_environment(self):
|
||||
"""Set download URL for development environment"""
|
||||
|
|
@ -674,14 +710,16 @@ 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='store_true')
|
||||
parser.add_argument('-v', '--verbose', action='count', default=0)
|
||||
|
||||
args = [a for a in sys.argv if a != '-h' and a != '--help']
|
||||
args, _ = parser.parse_known_args(args)
|
||||
|
||||
# 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
|
||||
|
||||
|
|
@ -691,10 +729,9 @@ def bootstrap(help_triggered):
|
|||
except (OSError, IOError):
|
||||
pass
|
||||
|
||||
if '\nverbose = 2' in build.config_toml:
|
||||
build.verbose = 2
|
||||
elif '\nverbose = 1' in build.config_toml:
|
||||
build.verbose = 1
|
||||
match = re.search(r'\nverbose = (\d+)', build.config_toml)
|
||||
if match is not None:
|
||||
build.verbose = max(build.verbose, int(match.group(1)))
|
||||
|
||||
build.use_vendored_sources = '\nvendor = true' in build.config_toml
|
||||
|
||||
|
|
@ -753,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> {
|
||||
|
|
@ -60,12 +70,6 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash {
|
|||
/// Run this rule for all hosts without cross compiling.
|
||||
const ONLY_HOSTS: bool = false;
|
||||
|
||||
/// Run this rule for all targets, but only with the native host.
|
||||
const ONLY_BUILD_TARGETS: bool = false;
|
||||
|
||||
/// Only run this step with the build triple as host and target.
|
||||
const ONLY_BUILD: bool = false;
|
||||
|
||||
/// Primary function to execute this rule. Can call `builder.ensure(...)`
|
||||
/// with other steps to run those.
|
||||
fn run(self, builder: &Builder) -> Self::Output;
|
||||
|
|
@ -101,8 +105,6 @@ pub struct RunConfig<'a> {
|
|||
struct StepDescription {
|
||||
default: bool,
|
||||
only_hosts: bool,
|
||||
only_build_targets: bool,
|
||||
only_build: bool,
|
||||
should_run: fn(ShouldRun) -> ShouldRun,
|
||||
make_run: fn(RunConfig),
|
||||
name: &'static str,
|
||||
|
|
@ -138,8 +140,6 @@ impl StepDescription {
|
|||
StepDescription {
|
||||
default: S::DEFAULT,
|
||||
only_hosts: S::ONLY_HOSTS,
|
||||
only_build_targets: S::ONLY_BUILD_TARGETS,
|
||||
only_build: S::ONLY_BUILD,
|
||||
should_run: S::should_run,
|
||||
make_run: S::make_run,
|
||||
name: unsafe { ::std::intrinsics::type_name::<S>() },
|
||||
|
|
@ -155,18 +155,12 @@ impl StepDescription {
|
|||
self.name, builder.config.exclude);
|
||||
}
|
||||
let build = builder.build;
|
||||
let hosts = if self.only_build_targets || self.only_build {
|
||||
build.build_triple()
|
||||
} else {
|
||||
&build.hosts
|
||||
};
|
||||
let hosts = &build.hosts;
|
||||
|
||||
// Determine the targets participating in this rule.
|
||||
let targets = if self.only_hosts {
|
||||
if build.config.run_host_only {
|
||||
&[]
|
||||
} else if self.only_build {
|
||||
build.build_triple()
|
||||
if !build.config.run_host_only {
|
||||
return; // don't run anything
|
||||
} else {
|
||||
&build.hosts
|
||||
}
|
||||
|
|
@ -324,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::Crate, test::CrateLibrustc, test::Rustdoc, test::Linkcheck, test::Cargotest,
|
||||
test::Cargo, test::Rls, test::ErrorIndex, test::Distcheck,
|
||||
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),
|
||||
}
|
||||
|
|
@ -359,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;
|
||||
|
|
@ -375,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[..]),
|
||||
|
|
@ -387,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
|
||||
|
|
@ -562,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);
|
||||
}
|
||||
|
||||
|
|
@ -678,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
|
||||
|
|
@ -775,9 +793,11 @@ impl<'a> Builder<'a> {
|
|||
// be resolved because MinGW has the import library. The downside is we
|
||||
// don't get newer functions from Windows, but we don't use any of them
|
||||
// anyway.
|
||||
cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1");
|
||||
if mode != Mode::Tool {
|
||||
cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1");
|
||||
}
|
||||
|
||||
if self.is_very_verbose() {
|
||||
for _ in 1..self.verbosity {
|
||||
cargo.arg("-v");
|
||||
}
|
||||
|
||||
|
|
@ -792,17 +812,6 @@ impl<'a> Builder<'a> {
|
|||
if cmd != "bench" {
|
||||
cargo.arg("--release");
|
||||
}
|
||||
|
||||
if self.config.rust_codegen_units.is_none() &&
|
||||
self.build.is_rust_llvm(compiler.host) &&
|
||||
self.config.rust_thinlto {
|
||||
cargo.env("RUSTC_THINLTO", "1");
|
||||
} else if self.config.rust_codegen_units.is_none() {
|
||||
// Generally, if ThinLTO has been disabled for some reason, we
|
||||
// want to set the codegen units to 1. However, we shouldn't do
|
||||
// this if the option was specifically set by the user.
|
||||
cargo.env("RUSTC_CODEGEN_UNITS", "1");
|
||||
}
|
||||
}
|
||||
|
||||
if self.config.locked_deps {
|
||||
|
|
@ -838,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");
|
||||
|
|
@ -854,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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ pub fn find(build: &mut Build) {
|
|||
.collect::<HashSet<_>>();
|
||||
for target in targets.into_iter() {
|
||||
let mut cfg = cc::Build::new();
|
||||
cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false)
|
||||
cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false)
|
||||
.target(&target).host(&build.build);
|
||||
if target.contains("msvc") {
|
||||
cfg.static_crt(true);
|
||||
|
|
@ -109,7 +109,7 @@ pub fn find(build: &mut Build) {
|
|||
let hosts = build.hosts.iter().cloned().chain(iter::once(build.build)).collect::<HashSet<_>>();
|
||||
for host in hosts.into_iter() {
|
||||
let mut cfg = cc::Build::new();
|
||||
cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false).cpp(true)
|
||||
cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false).cpp(true)
|
||||
.target(&host).host(&build.build);
|
||||
let config = build.config.target_config.get(&host);
|
||||
if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -86,7 +88,6 @@ pub struct Config {
|
|||
// rust codegen options
|
||||
pub rust_optimize: bool,
|
||||
pub rust_codegen_units: Option<u32>,
|
||||
pub rust_thinlto: bool,
|
||||
pub rust_debug_assertions: bool,
|
||||
pub rust_debuginfo: bool,
|
||||
pub rust_debuginfo_lines: bool,
|
||||
|
|
@ -122,11 +123,13 @@ 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>,
|
||||
pub prefix: Option<PathBuf>,
|
||||
pub sysconfdir: Option<PathBuf>,
|
||||
pub datadir: Option<PathBuf>,
|
||||
pub docdir: Option<PathBuf>,
|
||||
pub bindir: Option<PathBuf>,
|
||||
pub libdir: 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.
|
||||
|
|
@ -212,13 +219,13 @@ struct Build {
|
|||
struct Install {
|
||||
prefix: Option<String>,
|
||||
sysconfdir: Option<String>,
|
||||
datadir: Option<String>,
|
||||
docdir: Option<String>,
|
||||
bindir: Option<String>,
|
||||
libdir: Option<String>,
|
||||
mandir: Option<String>,
|
||||
|
||||
// standard paths, currently unused
|
||||
datadir: Option<String>,
|
||||
infodir: Option<String>,
|
||||
localstatedir: Option<String>,
|
||||
}
|
||||
|
|
@ -269,7 +276,6 @@ impl Default for StringOrBool {
|
|||
struct Rust {
|
||||
optimize: Option<bool>,
|
||||
codegen_units: Option<u32>,
|
||||
thinlto: Option<bool>,
|
||||
debug_assertions: Option<bool>,
|
||||
debuginfo: Option<bool>,
|
||||
debuginfo_lines: Option<bool>,
|
||||
|
|
@ -314,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;
|
||||
|
|
@ -327,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();
|
||||
|
|
@ -337,17 +341,40 @@ 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();
|
||||
config.run_host_only = !(flags.host.is_empty() && !flags.target.is_empty());
|
||||
|
||||
let toml = file.map(|file| {
|
||||
let mut f = t!(File::open(&file));
|
||||
|
|
@ -364,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);
|
||||
|
|
@ -403,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);
|
||||
|
|
@ -414,11 +437,13 @@ 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 {
|
||||
config.prefix = install.prefix.clone().map(PathBuf::from);
|
||||
config.sysconfdir = install.sysconfdir.clone().map(PathBuf::from);
|
||||
config.datadir = install.datadir.clone().map(PathBuf::from);
|
||||
config.docdir = install.docdir.clone().map(PathBuf::from);
|
||||
config.bindir = install.bindir.clone().map(PathBuf::from);
|
||||
config.libdir = install.libdir.clone().map(PathBuf::from);
|
||||
|
|
@ -427,7 +452,6 @@ impl Config {
|
|||
|
||||
// Store off these values as options because if they're not provided
|
||||
// we'll infer default values for them later
|
||||
let mut thinlto = None;
|
||||
let mut llvm_assertions = None;
|
||||
let mut debuginfo_lines = None;
|
||||
let mut debuginfo_only_std = None;
|
||||
|
|
@ -471,7 +495,6 @@ impl Config {
|
|||
optimize = rust.optimize;
|
||||
ignore_git = rust.ignore_git;
|
||||
debug_jemalloc = rust.debug_jemalloc;
|
||||
thinlto = rust.thinlto;
|
||||
set(&mut config.rust_optimize_tests, rust.optimize_tests);
|
||||
set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests);
|
||||
set(&mut config.codegen_tests, rust.codegen_tests);
|
||||
|
|
@ -509,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);
|
||||
|
|
@ -536,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);
|
||||
|
||||
|
|
@ -559,7 +572,6 @@ impl Config {
|
|||
"stable" | "beta" | "nightly" => true,
|
||||
_ => false,
|
||||
};
|
||||
config.rust_thinlto = thinlto.unwrap_or(true);
|
||||
config.rust_debuginfo_lines = debuginfo_lines.unwrap_or(default);
|
||||
config.rust_debuginfo_only_std = debuginfo_only_std.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")
|
||||
|
|
@ -71,7 +72,6 @@ o("full-tools", None, "enable all tools")
|
|||
# Optimization and debugging options. These may be overridden by the release
|
||||
# channel, etc.
|
||||
o("optimize", "rust.optimize", "build optimized rust code")
|
||||
o("thinlto", "rust.thinlto", "build Rust with ThinLTO enabled")
|
||||
o("optimize-llvm", "llvm.optimize", "build optimized LLVM")
|
||||
o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")
|
||||
o("debug-assertions", "rust.debug-assertions", "build with debugging assertions")
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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;
|
||||
|
|
@ -29,21 +28,20 @@ use cache::{Interned, INTERNER};
|
|||
|
||||
/// Deserialized version of all flags for this compile.
|
||||
pub struct Flags {
|
||||
pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
|
||||
pub verbose: usize, // number of -v args; each extra -v after the first is passed to Cargo
|
||||
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,22 +63,25 @@ 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");
|
||||
let docdir_default = PathBuf::from("share/doc/rust");
|
||||
let datadir_default = PathBuf::from("share");
|
||||
let docdir_default = datadir_default.join("doc/rust");
|
||||
let bindir_default = PathBuf::from("bin");
|
||||
let libdir_default = PathBuf::from("lib");
|
||||
let mandir_default = PathBuf::from("share/man");
|
||||
let mandir_default = datadir_default.join("man");
|
||||
let prefix = build.config.prefix.as_ref().unwrap_or(&prefix_default);
|
||||
let sysconfdir = build.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
|
||||
let datadir = build.config.datadir.as_ref().unwrap_or(&datadir_default);
|
||||
let docdir = build.config.docdir.as_ref().unwrap_or(&docdir_default);
|
||||
let bindir = build.config.bindir.as_ref().unwrap_or(&bindir_default);
|
||||
let libdir = build.config.libdir.as_ref().unwrap_or(&libdir_default);
|
||||
let mandir = build.config.mandir.as_ref().unwrap_or(&mandir_default);
|
||||
|
||||
let sysconfdir = prefix.join(sysconfdir);
|
||||
let datadir = prefix.join(datadir);
|
||||
let docdir = prefix.join(docdir);
|
||||
let bindir = prefix.join(bindir);
|
||||
let libdir = prefix.join(libdir);
|
||||
|
|
@ -88,6 +91,7 @@ fn install_sh(
|
|||
|
||||
let prefix = add_destdir(&prefix, &destdir);
|
||||
let sysconfdir = add_destdir(&sysconfdir, &destdir);
|
||||
let datadir = add_destdir(&datadir, &destdir);
|
||||
let docdir = add_destdir(&docdir, &destdir);
|
||||
let bindir = add_destdir(&bindir, &destdir);
|
||||
let libdir = add_destdir(&libdir, &destdir);
|
||||
|
|
@ -107,6 +111,7 @@ fn install_sh(
|
|||
.arg(sanitize_sh(&tmpdir(build).join(&package_name).join("install.sh")))
|
||||
.arg(format!("--prefix={}", sanitize_sh(&prefix)))
|
||||
.arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
|
||||
.arg(format!("--datadir={}", sanitize_sh(&datadir)))
|
||||
.arg(format!("--docdir={}", sanitize_sh(&docdir)))
|
||||
.arg(format!("--bindir={}", sanitize_sh(&bindir)))
|
||||
.arg(format!("--libdir={}", sanitize_sh(&libdir)))
|
||||
|
|
@ -161,7 +166,6 @@ macro_rules! install {
|
|||
impl Step for $name {
|
||||
type Output = ();
|
||||
const DEFAULT: bool = true;
|
||||
const ONLY_BUILD_TARGETS: bool = true;
|
||||
const ONLY_HOSTS: bool = $only_hosts;
|
||||
$(const $c: bool = true;)*
|
||||
|
||||
|
|
@ -174,7 +178,7 @@ macro_rules! install {
|
|||
run.builder.ensure($name {
|
||||
stage: run.builder.top_stage,
|
||||
target: run.target,
|
||||
host: run.host,
|
||||
host: run.builder.build.build,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -208,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, {
|
||||
|
|
@ -216,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, {
|
||||
|
|
@ -226,10 +231,6 @@ install!((self, builder, _config),
|
|||
});
|
||||
install_analysis(builder, self.stage, self.target);
|
||||
};
|
||||
Src, "src", Self::should_build(_config) , only_hosts: true, {
|
||||
builder.ensure(dist::Src);
|
||||
install_src(builder, self.stage);
|
||||
}, ONLY_BUILD;
|
||||
Rustc, "src/librustc", true, only_hosts: true, {
|
||||
builder.ensure(dist::Rustc {
|
||||
compiler: builder.compiler(self.stage, self.target),
|
||||
|
|
@ -237,3 +238,32 @@ install!((self, builder, _config),
|
|||
install_rustc(builder, self.stage, self.target);
|
||||
};
|
||||
);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Src {
|
||||
pub stage: u32,
|
||||
}
|
||||
|
||||
impl Step for Src {
|
||||
type Output = ();
|
||||
const DEFAULT: bool = true;
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun) -> ShouldRun {
|
||||
let config = &run.builder.config;
|
||||
let cond = config.extended &&
|
||||
config.tools.as_ref().map_or(true, |t| t.contains("src"));
|
||||
run.path("src").default_condition(cond)
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig) {
|
||||
run.builder.ensure(Src {
|
||||
stage: run.builder.top_stage,
|
||||
});
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder) {
|
||||
builder.ensure(dist::Src);
|
||||
install_src(builder, self.stage);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,8 +113,9 @@
|
|||
//! More documentation can be found in each respective module below, and you can
|
||||
//! also check out the `src/bootstrap/README.md` file for more information.
|
||||
|
||||
//#![deny(warnings)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![deny(warnings)]
|
||||
#![feature(conservative_impl_trait, fs_read_write, core_intrinsics)]
|
||||
#![feature(slice_concat_ext)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate build_helper;
|
||||
|
|
@ -130,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;
|
||||
|
|
@ -137,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};
|
||||
|
||||
|
|
@ -197,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>,
|
||||
|
|
@ -253,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)]
|
||||
|
|
@ -304,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) => {
|
||||
|
|
@ -322,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,
|
||||
|
|
@ -352,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>] {
|
||||
|
|
@ -371,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();
|
||||
|
|
@ -510,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"))
|
||||
|
|
@ -575,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)
|
||||
}
|
||||
|
|
@ -589,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)
|
||||
}
|
||||
|
|
@ -597,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)
|
||||
}
|
||||
|
|
@ -605,10 +652,6 @@ impl Build {
|
|||
self.verbosity > 0
|
||||
}
|
||||
|
||||
pub fn is_very_verbose(&self) -> bool {
|
||||
self.verbosity > 1
|
||||
}
|
||||
|
||||
/// Prints a message if this build is configured in verbose mode.
|
||||
fn verbose(&self, msg: &str) {
|
||||
if self.is_verbose() {
|
||||
|
|
@ -616,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 {
|
||||
|
|
@ -702,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 {
|
||||
|
|
@ -923,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
|
||||
|
|
@ -971,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)
|
||||
|
|
@ -245,7 +245,7 @@ impl Step for Rls {
|
|||
let host = self.host;
|
||||
let compiler = builder.compiler(stage, host);
|
||||
|
||||
builder.ensure(tool::Rls { compiler, target: self.host });
|
||||
builder.ensure(tool::Rls { compiler, target: self.host, extra_features: Vec::new() });
|
||||
let mut cargo = tool::prepare_tool_cargo(builder,
|
||||
compiler,
|
||||
host,
|
||||
|
|
@ -291,7 +291,7 @@ impl Step for Rustfmt {
|
|||
let host = self.host;
|
||||
let compiler = builder.compiler(stage, host);
|
||||
|
||||
builder.ensure(tool::Rustfmt { compiler, target: self.host });
|
||||
builder.ensure(tool::Rustfmt { compiler, target: self.host, extra_features: Vec::new() });
|
||||
let mut cargo = tool::prepare_tool_cargo(builder,
|
||||
compiler,
|
||||
host,
|
||||
|
|
@ -339,7 +339,12 @@ impl Step for Miri {
|
|||
let host = self.host;
|
||||
let compiler = builder.compiler(stage, host);
|
||||
|
||||
if let Some(miri) = builder.ensure(tool::Miri { compiler, target: self.host }) {
|
||||
let miri = builder.ensure(tool::Miri {
|
||||
compiler,
|
||||
target: self.host,
|
||||
extra_features: Vec::new(),
|
||||
});
|
||||
if let Some(miri) = miri {
|
||||
let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
|
||||
cargo.arg("--manifest-path").arg(build.src.join("src/tools/miri/Cargo.toml"));
|
||||
|
||||
|
|
@ -391,7 +396,12 @@ impl Step for Clippy {
|
|||
let host = self.host;
|
||||
let compiler = builder.compiler(stage, host);
|
||||
|
||||
if let Some(clippy) = builder.ensure(tool::Clippy { compiler, target: self.host }) {
|
||||
let clippy = builder.ensure(tool::Clippy {
|
||||
compiler,
|
||||
target: self.host,
|
||||
extra_features: Vec::new(),
|
||||
});
|
||||
if let Some(clippy) = clippy {
|
||||
let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
|
||||
cargo.arg("--manifest-path").arg(build.src.join("src/tools/clippy/Cargo.toml"));
|
||||
|
||||
|
|
@ -499,33 +509,27 @@ 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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Tidy {
|
||||
host: Interned<String>,
|
||||
}
|
||||
pub struct Tidy;
|
||||
|
||||
impl Step for Tidy {
|
||||
type Output = ();
|
||||
const DEFAULT: bool = true;
|
||||
const ONLY_HOSTS: bool = true;
|
||||
const ONLY_BUILD: bool = true;
|
||||
|
||||
/// Runs the `tidy` tool as compiled in `stage` by the `host` compiler.
|
||||
/// Runs the `tidy` tool.
|
||||
///
|
||||
/// This tool in `src/tools` checks up on various bits and pieces of style and
|
||||
/// otherwise just implements a few lint-like checks that are specific to the
|
||||
/// compiler itself.
|
||||
fn run(self, builder: &Builder) {
|
||||
let build = builder.build;
|
||||
let host = self.host;
|
||||
|
||||
let _folder = build.fold_output(|| "tidy");
|
||||
println!("tidy check ({})", host);
|
||||
let mut cmd = builder.tool_cmd(Tool::Tidy);
|
||||
cmd.arg(build.src.join("src"));
|
||||
cmd.arg(&build.initial_cargo);
|
||||
|
|
@ -535,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);
|
||||
}
|
||||
|
||||
|
|
@ -543,9 +550,7 @@ impl Step for Tidy {
|
|||
}
|
||||
|
||||
fn make_run(run: RunConfig) {
|
||||
run.builder.ensure(Tidy {
|
||||
host: run.builder.build.build,
|
||||
});
|
||||
run.builder.ensure(Tidy);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -755,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,
|
||||
|
|
@ -823,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 });
|
||||
}
|
||||
|
||||
|
|
@ -832,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
|
||||
|
|
@ -845,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));
|
||||
}
|
||||
|
||||
|
|
@ -919,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))
|
||||
|
|
@ -940,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("")
|
||||
|
|
@ -994,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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1029,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()));
|
||||
|
|
@ -1048,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
|
||||
|
|
@ -1138,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");
|
||||
|
|
@ -1396,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.
|
||||
//
|
||||
|
|
@ -1432,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"));
|
||||
|
|
@ -1442,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
|
||||
|
|
@ -1461,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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1509,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");
|
||||
}
|
||||
|
|
@ -1528,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);
|
||||
}
|
||||
|
|
@ -1575,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 });
|
||||
|
|
@ -1610,7 +1634,6 @@ pub struct Distcheck;
|
|||
|
||||
impl Step for Distcheck {
|
||||
type Output = ();
|
||||
const ONLY_BUILD: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun) -> ShouldRun {
|
||||
run.path("distcheck")
|
||||
|
|
@ -1624,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));
|
||||
|
|
@ -1648,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));
|
||||
|
|
@ -1676,7 +1699,6 @@ impl Step for Bootstrap {
|
|||
type Output = ();
|
||||
const DEFAULT: bool = true;
|
||||
const ONLY_HOSTS: bool = true;
|
||||
const ONLY_BUILD: bool = true;
|
||||
|
||||
/// Test the build system itself
|
||||
fn run(self, builder: &Builder) {
|
||||
|
|
@ -1684,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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,12 @@ use std::fs;
|
|||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, exit};
|
||||
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;
|
||||
|
|
@ -74,7 +75,7 @@ impl Step for CleanTools {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
struct ToolBuild {
|
||||
compiler: Compiler,
|
||||
target: Interned<String>,
|
||||
|
|
@ -82,6 +83,7 @@ struct ToolBuild {
|
|||
path: &'static str,
|
||||
mode: Mode,
|
||||
is_ext_tool: bool,
|
||||
extra_features: Vec<String>,
|
||||
}
|
||||
|
||||
impl Step for ToolBuild {
|
||||
|
|
@ -110,11 +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);
|
||||
let is_expected = build.try_run(&mut cargo);
|
||||
cargo.arg("--features").arg(self.extra_features.join(" "));
|
||||
|
||||
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 {
|
||||
|
|
@ -131,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)
|
||||
}
|
||||
}
|
||||
|
|
@ -242,6 +318,7 @@ macro_rules! tool {
|
|||
mode: $mode,
|
||||
path: $path,
|
||||
is_ext_tool: false,
|
||||
extra_features: Vec::new(),
|
||||
}).expect("expected to build -- essential tool")
|
||||
}
|
||||
}
|
||||
|
|
@ -291,6 +368,7 @@ impl Step for RemoteTestServer {
|
|||
mode: Mode::Libstd,
|
||||
path: "src/tools/remote-test-server",
|
||||
is_ext_tool: false,
|
||||
extra_features: Vec::new(),
|
||||
}).expect("expected to build -- essential tool")
|
||||
}
|
||||
}
|
||||
|
|
@ -333,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,
|
||||
|
|
@ -347,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.
|
||||
|
|
@ -361,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
|
||||
|
|
@ -409,6 +492,7 @@ impl Step for Cargo {
|
|||
mode: Mode::Librustc,
|
||||
path: "src/tools/cargo",
|
||||
is_ext_tool: false,
|
||||
extra_features: Vec::new(),
|
||||
}).expect("expected to build -- essential tool")
|
||||
}
|
||||
}
|
||||
|
|
@ -421,10 +505,11 @@ macro_rules! tool_extended {
|
|||
$tool_name:expr,
|
||||
$extra_deps:block;)+) => {
|
||||
$(
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct $name {
|
||||
pub compiler: Compiler,
|
||||
pub target: Interned<String>,
|
||||
pub extra_features: Vec<String>,
|
||||
}
|
||||
|
||||
impl Step for $name {
|
||||
|
|
@ -441,10 +526,12 @@ macro_rules! tool_extended {
|
|||
run.builder.ensure($name {
|
||||
compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
|
||||
target: run.target,
|
||||
extra_features: Vec::new(),
|
||||
});
|
||||
}
|
||||
|
||||
fn run($sel, $builder: &Builder) -> Option<PathBuf> {
|
||||
#[allow(unused_mut)]
|
||||
fn run(mut $sel, $builder: &Builder) -> Option<PathBuf> {
|
||||
$extra_deps
|
||||
$builder.ensure(ToolBuild {
|
||||
compiler: $sel.compiler,
|
||||
|
|
@ -452,6 +539,7 @@ macro_rules! tool_extended {
|
|||
tool: $tool_name,
|
||||
mode: Mode::Librustc,
|
||||
path: $path,
|
||||
extra_features: $sel.extra_features,
|
||||
is_ext_tool: true,
|
||||
})
|
||||
}
|
||||
|
|
@ -472,6 +560,14 @@ tool_extended!((self, builder),
|
|||
};
|
||||
Miri, miri, "src/tools/miri", "miri", {};
|
||||
Rls, rls, "src/tools/rls", "rls", {
|
||||
let clippy = builder.ensure(Clippy {
|
||||
compiler: self.compiler,
|
||||
target: self.target,
|
||||
extra_features: Vec::new(),
|
||||
});
|
||||
if clippy.is_some() {
|
||||
self.extra_features.push("clippy".to_owned());
|
||||
}
|
||||
builder.ensure(native::Openssl {
|
||||
target: self.target,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,11 @@ ENV EM_CONFIG=/emsdk-portable/.emscripten
|
|||
|
||||
ENV TARGETS=asmjs-unknown-emscripten
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-emscripten
|
||||
ENV RUST_CONFIGURE_ARGS --enable-emscripten --disable-optimize-tests
|
||||
|
||||
ENV SCRIPT python2.7 ../x.py test --target $TARGETS
|
||||
ENV SCRIPT python2.7 ../x.py test --target $TARGETS \
|
||||
src/test/run-pass \
|
||||
src/test/run-fail \
|
||||
src/libstd \
|
||||
src/liballoc \
|
||||
src/libcore
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -46,7 +48,6 @@ export RUST_RELEASE_CHANNEL=nightly
|
|||
if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-thinlto"
|
||||
|
||||
if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
|
||||
|
|
@ -73,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
|
||||
|
|
@ -91,11 +99,19 @@ make check-bootstrap
|
|||
travis_fold end check-bootstrap
|
||||
travis_time_finish
|
||||
|
||||
# Display the CPU and memory information. This helps us know why the CI timing
|
||||
# is fluctuating.
|
||||
travis_fold start log-system-info
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
system_profiler SPHardwareDataType || true
|
||||
sysctl hw || true
|
||||
ncpus=$(sysctl -n hw.ncpu)
|
||||
else
|
||||
cat /proc/cpuinfo || true
|
||||
cat /proc/meminfo || true
|
||||
ncpus=$(grep processor /proc/cpuinfo | wc -l)
|
||||
fi
|
||||
travis_fold end log-system-info
|
||||
|
||||
if [ ! -z "$SCRIPT" ]; then
|
||||
sh -x -c "$SCRIPT"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -19,18 +19,38 @@ running `rustdoc --test foo.rs` will extract this example, and then run it as a
|
|||
Please note that by default, if no language is set for the block code, `rustdoc`
|
||||
assumes it is `Rust` code. So the following:
|
||||
|
||||
``````markdown
|
||||
```rust
|
||||
let x = 5;
|
||||
```
|
||||
``````
|
||||
|
||||
is strictly equivalent to:
|
||||
|
||||
``````markdown
|
||||
```
|
||||
let x = 5;
|
||||
```
|
||||
``````
|
||||
|
||||
There's some subtlety though! Read on for more details.
|
||||
|
||||
## Passing or failing a doctest
|
||||
|
||||
Like regular unit tests, regular doctests are considered to "pass"
|
||||
if they compile and run without panicking.
|
||||
So if you want to demonstrate that some computation gives a certain result,
|
||||
the `assert!` family of macros works the same as other Rust code:
|
||||
|
||||
```rust
|
||||
let foo = "foo";
|
||||
|
||||
assert_eq!(foo, "foo");
|
||||
```
|
||||
|
||||
This way, if the computation ever returns something different,
|
||||
the code panics and the doctest fails.
|
||||
|
||||
## Pre-processing examples
|
||||
|
||||
In the example above, you'll note something strange: there's no `main`
|
||||
|
|
|
|||
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,35 +0,0 @@
|
|||
# `advanced_slice_patterns`
|
||||
|
||||
The tracking issue for this feature is: [#23121]
|
||||
|
||||
[#23121]: https://github.com/rust-lang/rust/issues/23121
|
||||
|
||||
See also [`slice_patterns`](language-features/slice-patterns.html).
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
The `advanced_slice_patterns` gate lets you use `..` to indicate any number of
|
||||
elements inside a pattern matching a slice. This wildcard can only be used once
|
||||
for a given array. If there's an identifier before the `..`, the result of the
|
||||
slice will be bound to that name. For example:
|
||||
|
||||
```rust
|
||||
#![feature(advanced_slice_patterns, slice_patterns)]
|
||||
|
||||
fn is_symmetric(list: &[u32]) -> bool {
|
||||
match list {
|
||||
&[] | &[_] => true,
|
||||
&[x, ref inside.., y] if x == y => is_symmetric(inside),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let sym = &[0, 1, 4, 2, 4, 1, 0];
|
||||
assert!(is_symmetric(sym));
|
||||
|
||||
let not_sym = &[0, 1, 7, 2, 4, 1, 0];
|
||||
assert!(!is_symmetric(not_sym));
|
||||
}
|
||||
```
|
||||
|
|
@ -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,20 +0,0 @@
|
|||
# `inclusive_range_syntax`
|
||||
|
||||
The tracking issue for this feature is: [#28237]
|
||||
|
||||
[#28237]: https://github.com/rust-lang/rust/issues/28237
|
||||
|
||||
------------------------
|
||||
|
||||
To get a range that goes from 0 to 10 and includes the value 10, you
|
||||
can write `0..=10`:
|
||||
|
||||
```rust
|
||||
#![feature(inclusive_range_syntax)]
|
||||
|
||||
fn main() {
|
||||
for i in 0..=10 {
|
||||
println!("{}", i);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -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),
|
||||
}
|
||||
```
|
||||
|
|
@ -4,25 +4,29 @@ The tracking issue for this feature is: [#23121]
|
|||
|
||||
[#23121]: https://github.com/rust-lang/rust/issues/23121
|
||||
|
||||
See also
|
||||
[`advanced_slice_patterns`](language-features/advanced-slice-patterns.html).
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
If you want to match against a slice or array, you can use `&` with the
|
||||
`slice_patterns` feature:
|
||||
The `slice_patterns` feature gate lets you use `..` to indicate any number of
|
||||
elements inside a pattern matching a slice. This wildcard can only be used once
|
||||
for a given array. If there's an pattern before the `..`, the subslice will be
|
||||
matched against that pattern. For example:
|
||||
|
||||
```rust
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
fn main() {
|
||||
let v = vec!["match_this", "1"];
|
||||
|
||||
match &v[..] {
|
||||
&["match_this", second] => println!("The second element is {}", second),
|
||||
_ => {},
|
||||
fn is_symmetric(list: &[u32]) -> bool {
|
||||
match list {
|
||||
&[] | &[_] => true,
|
||||
&[x, ref inside.., y] if x == y => is_symmetric(inside),
|
||||
&[..] => false,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
fn main() {
|
||||
let sym = &[0, 1, 4, 2, 4, 1, 0];
|
||||
assert!(is_symmetric(sym));
|
||||
|
||||
let not_sym = &[0, 1, 7, 2, 4, 1, 0];
|
||||
assert!(!is_symmetric(not_sym));
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ core = { path = "../libcore" }
|
|||
std_unicode = { path = "../libstd_unicode" }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.3"
|
||||
rand = "0.4"
|
||||
|
||||
[[test]]
|
||||
name = "collectionstests"
|
||||
|
|
|
|||
|
|
@ -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, Unsize};
|
||||
use core::mem;
|
||||
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,104 @@ 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()
|
||||
}
|
||||
}
|
||||
|
||||
/// A pinned, heap allocated reference.
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
#[fundamental]
|
||||
pub struct PinBox<T: ?Sized> {
|
||||
inner: Box<T>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<T> PinBox<T> {
|
||||
/// Allocate memory on the heap, move the data into it and pin it.
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
pub fn new(data: T) -> PinBox<T> {
|
||||
PinBox { inner: Box::new(data) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<T: ?Sized> PinBox<T> {
|
||||
/// Get a pinned reference to the data in this PinBox.
|
||||
pub fn as_pin<'a>(&'a mut self) -> Pin<'a, T> {
|
||||
unsafe { Pin::new_unchecked(&mut *self.inner) }
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the data inside this PinBox.
|
||||
///
|
||||
/// This function is unsafe. Users must guarantee that the data is never
|
||||
/// moved out of this reference.
|
||||
pub unsafe fn get_mut<'a>(this: &'a mut PinBox<T>) -> &'a mut T {
|
||||
&mut *this.inner
|
||||
}
|
||||
|
||||
/// Convert this PinBox into an unpinned Box.
|
||||
///
|
||||
/// This function is unsafe. Users must guarantee that the data is never
|
||||
/// moved out of the box.
|
||||
pub unsafe fn unpin(this: PinBox<T>) -> Box<T> {
|
||||
this.inner
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<T: ?Sized> From<Box<T>> for PinBox<T> {
|
||||
fn from(boxed: Box<T>) -> PinBox<T> {
|
||||
PinBox { inner: boxed }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<T: Unpin + ?Sized> From<PinBox<T>> for Box<T> {
|
||||
fn from(pinned: PinBox<T>) -> Box<T> {
|
||||
pinned.inner
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<T: ?Sized> Deref for PinBox<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&*self.inner
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<T: Unpin + ?Sized> DerefMut for PinBox<T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
&mut *self.inner
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<T: fmt::Display + ?Sized> fmt::Display for PinBox<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&*self.inner, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<T: fmt::Debug + ?Sized> fmt::Debug for PinBox<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&*self.inner, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<T: ?Sized> fmt::Pointer for PinBox<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// It's not possible to extract the inner Uniq directly from the Box,
|
||||
// instead we cast it to a *const which aliases the Unique
|
||||
let ptr: *const T = &*self.inner;
|
||||
fmt::Pointer::fmt(&ptr, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<PinBox<U>> for PinBox<T> {}
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,6 +113,8 @@
|
|||
//!
|
||||
//! * *nothing* ⇒ [`Display`]
|
||||
//! * `?` ⇒ [`Debug`]
|
||||
//! * `x?` ⇒ [`Debug`] with lower-case hexadecimal integers
|
||||
//! * `X?` ⇒ [`Debug`] with upper-case hexadecimal integers
|
||||
//! * `o` ⇒ [`Octal`](trait.Octal.html)
|
||||
//! * `x` ⇒ [`LowerHex`](trait.LowerHex.html)
|
||||
//! * `X` ⇒ [`UpperHex`](trait.UpperHex.html)
|
||||
|
|
@ -324,7 +326,7 @@
|
|||
//! sign := '+' | '-'
|
||||
//! width := count
|
||||
//! precision := count | '*'
|
||||
//! type := identifier | ''
|
||||
//! type := identifier | '?' | ''
|
||||
//! count := parameter | integer
|
||||
//! parameter := argument '$'
|
||||
//! ```
|
||||
|
|
@ -514,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};
|
||||
|
||||
|
|
@ -561,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::*;
|
||||
|
|
@ -228,14 +228,6 @@ unsafe impl Alloc for Heap {
|
|||
}
|
||||
}
|
||||
|
||||
/// An arbitrary non-null address to represent zero-size allocations.
|
||||
///
|
||||
/// This preserves the non-null invariant for types like `Box<T>`. The address
|
||||
/// may overlap with non-zero-size memory allocations.
|
||||
#[rustc_deprecated(since = "1.19.0", reason = "Use Unique/NonNull::empty() instead")]
|
||||
#[unstable(feature = "heap_api", issue = "27700")]
|
||||
pub const EMPTY: *mut () = 1 as *mut ();
|
||||
|
||||
/// The allocator for unique pointers.
|
||||
// This function must not unwind. If it does, MIR trans will fail.
|
||||
#[cfg(not(test))]
|
||||
|
|
|
|||
|
|
@ -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,27 +97,24 @@
|
|||
#![feature(fmt_internals)]
|
||||
#![feature(from_ref)]
|
||||
#![feature(fundamental)]
|
||||
#![feature(generic_param_attrs)]
|
||||
#![feature(i128_type)]
|
||||
#![feature(inclusive_range)]
|
||||
#![feature(iter_rfold)]
|
||||
#![cfg_attr(stage0, feature(generic_param_attrs))]
|
||||
#![cfg_attr(stage0, feature(i128_type))]
|
||||
#![feature(lang_items)]
|
||||
#![feature(needs_allocator)]
|
||||
#![feature(nonzero)]
|
||||
#![feature(offset_to)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(pattern)]
|
||||
#![feature(placement_in_syntax)]
|
||||
#![feature(placement_new_protocol)]
|
||||
#![feature(pin)]
|
||||
#![feature(ptr_internals)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(slice_get_slice)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(slice_rsplit)]
|
||||
#![feature(specialization)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(str_internals)]
|
||||
#![feature(trusted_len)]
|
||||
#![feature(try_reserve)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unicode)]
|
||||
#![feature(unsize)]
|
||||
|
|
@ -124,9 +122,10 @@
|
|||
#![feature(on_unimplemented)]
|
||||
#![feature(exact_chunks)]
|
||||
#![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
|
||||
|
||||
|
|
@ -144,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
|
||||
|
||||
|
|
@ -156,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;
|
||||
|
|
@ -177,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;
|
||||
|
|
@ -203,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() {
|
||||
|
|
|
|||
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