Imported Upstream version 1.8.0+dfsg1

This commit is contained in:
Sylvestre Ledru 2016-04-15 11:58:01 +02:00
parent 9cc50fc6f5
commit 7453a54e52
1522 changed files with 51117 additions and 119922 deletions

View File

@ -6,6 +6,7 @@ links to the major sections:
* [Feature Requests](#feature-requests)
* [Bug Reports](#bug-reports)
* [The Build System](#the-build-system)
* [Pull Requests](#pull-requests)
* [Writing Documentation](#writing-documentation)
* [Issue Triage](#issue-triage)
@ -77,6 +78,70 @@ to do this is to invoke `rustc` like this:
$ RUST_BACKTRACE=1 rustc ...
```
## The Build System
Rust's build system allows you to bootstrap the compiler, run tests &
benchmarks, generate documentation, install a fresh build of Rust, and more.
It's your best friend when working on Rust, allowing you to compile & test
your contributions before submission.
All the configuration for the build system lives in [the `mk` directory][mkdir]
in the project root. It can be hard to follow in places, as it uses some
advanced Make features which make for some challenging reading. If you have
questions on the build system internals, try asking in
[`#rust-internals`][pound-rust-internals].
[mkdir]: https://github.com/rust-lang/rust/tree/master/mk/
### Configuration
Before you can start building the compiler you need to configure the build for
your system. In most cases, that will just mean using the defaults provided
for Rust. Configuring involves invoking the `configure` script in the project
root.
```
./configure
```
There are large number of options accepted by this script to alter the
configuration used later in the build process. Some options to note:
- `--enable-debug` - Build a debug version of the compiler (disables optimizations)
- `--enable-optimize` - Enable optimizations (can be used with `--enable-debug`
to make a debug build with optimizations)
- `--disable-valgrind-rpass` - Don't run tests with valgrind
- `--enable-clang` - Prefer clang to gcc for building dependencies (e.g., LLVM)
- `--enable-ccache` - Invoke clang/gcc with ccache to re-use object files between builds
- `--enable-compiler-docs` - Build compiler documentation
To see a full list of options, run `./configure --help`.
### Useful Targets
Some common make targets are:
- `make rustc-stage1` - build up to (and including) the first stage. For most
cases we don't need to build the stage2 compiler, so we can save time by not
building it. The stage1 compiler is a fully functioning compiler and
(probably) will be enough to determine if your change works as expected.
- `make check` - build the full compiler & run all tests (takes a while). This
is what gets run by the continuous integration system against your pull
request. You should run this before submitting to make sure your tests pass
& everything builds in the correct manner.
- `make check-stage1-std NO_REBUILD=1` - test the standard library without
rebuilding the entire compiler
- `make check TESTNAME=<substring-of-test-name>` - Run a matching set of tests.
- `TESTNAME` should be a substring of the tests to match against e.g. it could
be the fully qualified test name, or just a part of it.
`TESTNAME=collections::hash::map::test_map::test_capacity_not_less_than_len`
or `TESTNAME=test_capacity_not_less_than_len`.
- `make check-stage1-rpass TESTNAME=<substring-of-test-name>` - Run a single
rpass test with the stage1 compiler (this will be quicker than running the
command above as we only build the stage1 compiler, not the entire thing).
You can also leave off the `-rpass` to run all stage1 test types.
- `make check-stage1-coretest` - Run stage1 tests in `libcore`.
## Pull Requests
Pull requests are the primary mechanism we use to change Rust. GitHub itself

View File

@ -6,8 +6,8 @@ terms.
Longer version:
The Rust Project is copyright 2016, The Rust Project
Developers (given in the file AUTHORS.txt).
The Rust Project is copyright 2010, The Rust Project
Developers.
Licensed under the Apache License, Version 2.0
<LICENSE-APACHE or

View File

@ -1,4 +1,4 @@
Copyright (c) 2016 The Rust Project Developers
Copyright (c) 2010 The Rust Project Developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated

View File

@ -100,6 +100,10 @@
# // Having trouble figuring out which test is failing? Turn off parallel tests
# make check-stage1-std RUST_TEST_THREADS=1
#
# // To make debug!() and other logging calls visible, reconfigure:
# ./configure --enable-debug-assertions
# make ....
#
# If you really feel like getting your hands dirty, then:
#
# run `make nitty-gritty`
@ -220,19 +224,12 @@ endif
# The test suite
ifneq ($(strip $(findstring check,$(MAKECMDGOALS)) \
$(findstring test,$(MAKECMDGOALS)) \
$(findstring perf,$(MAKECMDGOALS)) \
$(findstring tidy,$(MAKECMDGOALS))),)
CFG_INFO := $(info cfg: including test rules)
include $(CFG_SRC_DIR)mk/tests.mk
include $(CFG_SRC_DIR)mk/grammar.mk
endif
# Performance and benchmarking
ifneq ($(findstring perf,$(MAKECMDGOALS)),)
CFG_INFO := $(info cfg: including perf rules)
include $(CFG_SRC_DIR)mk/perf.mk
endif
# Copy all the distributables to another directory for binary install
ifneq ($(strip $(findstring prepare,$(MAKECMDGOALS)) \
$(findstring dist,$(MAKECMDGOALS)) \

View File

@ -9,7 +9,7 @@ and documentation.
Read ["Installing Rust"] from [The Book].
["Installing Rust"]: https://doc.rust-lang.org/book/installing-rust.html
["Installing Rust"]: https://doc.rust-lang.org/book/getting-started.html#installing-rust
[The Book]: https://doc.rust-lang.org/book/index.html
## Building from Source
@ -17,7 +17,7 @@ Read ["Installing Rust"] from [The Book].
1. Make sure you have installed the dependencies:
* `g++` 4.7 or `clang++` 3.x
* `python` 2.7 or later (but not 3.x)
* `python` 2.7 (but not 3.x)
* GNU `make` 3.81 or later
* `curl`
* `git`

View File

@ -1,6 +1,224 @@
Version 1.8.0 (2016-04-14)
==========================
Language
--------
* Rust supports overloading of compound assignment statements like
`+=` by implementing the [`AddAssign`], [`SubAssign`],
[`MulAssign`], [`DivAssign`], [`RemAssign`], [`BitAndAssign`],
[`BitOrAssign`], [`BitXorAssign`], [`ShlAssign`], or [`ShrAssign`]
traits. [RFC 953].
* Empty structs can be defined with braces, as in `struct Foo { }`, in
addition to the non-braced form, `struct Foo;`. [RFC 218].
Libraries
---------
* Stabilized APIs:
* [`str::encode_utf16`][] (renamed from `utf16_units`)
* [`str::EncodeUtf16`][] (renamed from `Utf16Units`)
* [`Ref::map`]
* [`RefMut::map`]
* [`ptr::drop_in_place`]
* [`time::Instant`]
* [`time::SystemTime`]
* [`Instant::now`]
* [`Instant::duration_since`][] (renamed from `duration_from_earlier`)
* [`Instant::elapsed`]
* [`SystemTime::now`]
* [`SystemTime::duration_since`][] (renamed from `duration_from_earlier`)
* [`SystemTime::elapsed`]
* Various `Add`/`Sub` impls for `Time` and `SystemTime`
* [`SystemTimeError`]
* [`SystemTimeError::duration`]
* Various impls for `SystemTimeError`
* [`UNIX_EPOCH`]
* [`AddAssign`], [`SubAssign`], [`MulAssign`], [`DivAssign`],
[`RemAssign`], [`BitAndAssign`], [`BitOrAssign`],
[`BitXorAssign`], [`ShlAssign`], [`ShrAssign`].
* [The `write!` and `writeln!` macros correctly emit errors if any of
their arguments can't be formatted][1.8w].
* [Various I/O functions support large files on 32-bit Linux][1.8l].
* [The Unix-specific `raw` modules, which contain a number of
redefined C types are deprecated][1.8r], including `os::raw::unix`,
`os::raw::macos`, and `os::raw::linux`. These modules defined types
such as `ino_t` and `dev_t`. The inconsistency of these definitions
across platforms was making it difficult to implement `std`
correctly. Those that need these definitions should use the `libc`
crate. [RFC 1415].
* The Unix-specific `MetadataExt` traits, including
`os::unix::fs::MetadataExt`, which expose values such as inode
numbers [no longer return platform-specific types][1.8r], but
instead return widened integers. [RFC 1415].
* [`btree_set::{IntoIter, Iter, Range}` are covariant][1.8cv].
* [Atomic loads and stores are not volatile][1.8a].
* [All types in `sync::mpsc` implement `fmt::Debug`][1.8mp].
Performance
-----------
* [Inlining hash functions lead to a 3% compile-time improvement in
some workloads][1.8h].
* When using jemalloc, its symbols are [unprefixed so that it
overrides the libc malloc implementation][1.8h]. This means that for
rustc, LLVM is now using jemalloc, which results in a 6%
compile-time improvement on a specific workload.
* [Avoid quadratic growth in function size due to cleanups][1.8cu].
Misc
----
* [32-bit MSVC builds finally implement unwinding][1.8ms].
i686-pc-windows-msvc is now considered a tier-1 platform.
* [The `--print targets` flag prints a list of supported targets][1.8t].
* [The `--print cfg` flag prints the `cfg`s defined for the current
target][1.8cf].
* [`rustc` can be built with an new Cargo-based build system, written
in Rust][1.8b]. It will eventually replace Rust's Makefile-based
build system. To enable it configure with `configure --rustbuild`.
* [Errors for non-exhaustive `match` patterns now list up to 3 missing
variants while also indicating the total number of missing variants
if more than 3][1.8m].
* [Executable stacks are disabled on Linux and BSD][1.8nx].
* The Rust Project now publishes binary releases of the standard
library for a number of tier-2 targets:
`armv7-unknown-linux-gnueabihf`, `powerpc-unknown-linux-gnu`,
`powerpc64-unknown-linux-gnu`, `powerpc64le-unknown-linux-gnu`
`x86_64-rumprun-netbsd`. These can be installed with
tools such as [multirust][1.8mr].
Cargo
-----
* [`cargo init` creates a new Cargo project in the current
directory][1.8ci]. It is otherwise like `cargo new`.
* [Cargo has configuration keys for `-v` and
`--color`][1.8cc]. `verbose` and `color`, respectively, go in the
`[term]` section of `.cargo/config`.
* [Configuration keys that evaluate to strings or integers can be set
via environment variables][1.8ce]. For example the `build.jobs` key
can be set via `CARGO_BUILD_JOBS`. Environment variables take
precedence over config files.
* [Target-specific dependencies support Rust `cfg` syntax for
describing targets][1.8cfg] so that dependencies for multiple
targets can be specified together. [RFC 1361].
* [The environment variables `CARGO_TARGET_ROOT`, `RUSTC`, and
`RUSTDOC` take precedence over the `build.target-dir`,
`build.rustc`, and `build.rustdoc` configuration values][1.8cv].
* [The child process tree is killed on Windows when Cargo is
killed][1.8ck].
* [The `build.target` configuration value sets the target platform,
like `--target`][1.8ct].
Compatibility Notes
-------------------
* [Unstable compiler flags have been further restricted][1.8u]. Since
1.0 `-Z` flags have been considered unstable, and other flags that
were considered unstable additionally required passing `-Z
unstable-options` to access. Unlike unstable language and library
features though, these options have been accessible on the stable
release channel. Going forward, *new unstable flags will not be
available on the stable release channel*, and old unstable flags
will warn about their usage. In the future, all unstable flags will
be unavailable on the stable release channel.
* [It is no longer possible to `match` on empty enum variants using
the `Variant(..)` syntax][1.8v]. This has been a warning since 1.6.
* The Unix-specific `MetadataExt` traits, including
`os::unix::fs::MetadataExt`, which expose values such as inode
numbers [no longer return platform-specific types][1.8r], but
instead return widened integers. [RFC 1415].
* [Modules sourced from the filesystem cannot appear within arbitrary
blocks, but only within other modules][1.8m].
* [`--cfg` compiler flags are parsed strictly as identifiers][1.8c].
* On Unix, [stack overflow triggers a runtime abort instead of a
SIGSEGV][1.8so].
* [`Command::spawn` and its equivalents return an error if any of
its command-line arguments contain interior `NUL`s][1.8n].
* [Tuple and unit enum variants from other crates are in the type
namespace][1.8tn].
* [On Windows `rustc` emits `.lib` files for the `staticlib` library
type instead of `.a` files][1.8st]. Additionally, for the MSVC
toolchain, `rustc` emits import libraries named `foo.dll.lib`
instead of `foo.lib`.
[1.8a]: https://github.com/rust-lang/rust/pull/30962
[1.8b]: https://github.com/rust-lang/rust/pull/31123
[1.8c]: https://github.com/rust-lang/rust/pull/31530
[1.8cc]: https://github.com/rust-lang/cargo/pull/2397
[1.8ce]: https://github.com/rust-lang/cargo/pull/2398
[1.8cf]: https://github.com/rust-lang/rust/pull/31278
[1.8cfg]: https://github.com/rust-lang/cargo/pull/2328
[1.8ci]: https://github.com/rust-lang/cargo/pull/2081
[1.8ck]: https://github.com/rust-lang/cargo/pull/2370
[1.8ct]: https://github.com/rust-lang/cargo/pull/2335
[1.8cu]: https://github.com/rust-lang/rust/pull/31390
[1.8cv]: https://github.com/rust-lang/cargo/issues/2365
[1.8cv]: https://github.com/rust-lang/rust/pull/30998
[1.8h]: https://github.com/rust-lang/rust/pull/31460
[1.8l]: https://github.com/rust-lang/rust/pull/31668
[1.8m]: https://github.com/rust-lang/rust/pull/31020
[1.8m]: https://github.com/rust-lang/rust/pull/31534
[1.8mp]: https://github.com/rust-lang/rust/pull/30894
[1.8mr]: https://users.rust-lang.org/t/multirust-0-8-with-cross-std-installation/4901
[1.8ms]: https://github.com/rust-lang/rust/pull/30448
[1.8n]: https://github.com/rust-lang/rust/pull/31056
[1.8nx]: https://github.com/rust-lang/rust/pull/30859
[1.8r]: https://github.com/rust-lang/rust/pull/31551
[1.8so]: https://github.com/rust-lang/rust/pull/31333
[1.8st]: https://github.com/rust-lang/rust/pull/29520
[1.8t]: https://github.com/rust-lang/rust/pull/31358
[1.8tn]: https://github.com/rust-lang/rust/pull/30882
[1.8u]: https://github.com/rust-lang/rust/pull/31793
[1.8v]: https://github.com/rust-lang/rust/pull/31757
[1.8w]: https://github.com/rust-lang/rust/pull/31904
[RFC 1361]: https://github.com/rust-lang/rfcs/blob/master/text/1361-cargo-cfg-dependencies.md
[RFC 1415]: https://github.com/rust-lang/rfcs/blob/master/text/1415-trim-std-os.md
[RFC 218]: https://github.com/rust-lang/rfcs/blob/master/text/0218-empty-struct-with-braces.md
[RFC 953]: https://github.com/rust-lang/rfcs/blob/master/text/0953-op-assign.md
[`AddAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.AddAssign.html
[`BitAndAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.BitAndAssign.html
[`BitOrAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.BitOrAssign.html
[`BitXorAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.BitXorAssign.html
[`DivAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.DivAssign.html
[`Instant::duration_since`]: http://doc.rust-lang.org/nightly/std/time/struct.Instant.html#method.duration_since
[`Instant::elapsed`]: http://doc.rust-lang.org/nightly/std/time/struct.Instant.html#method.elapsed
[`Instant::now`]: http://doc.rust-lang.org/nightly/std/time/struct.Instant.html#method.now
[`MulAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.MulAssign.html
[`Ref::map`]: http://doc.rust-lang.org/nightly/std/cell/struct.Ref.html#method.map
[`RefMut::map`]: http://doc.rust-lang.org/nightly/std/cell/struct.RefMut.html#method.map
[`RemAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.RemAssign.html
[`ShlAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.ShlAssign.html
[`ShrAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.ShrAssign.html
[`SubAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.SubAssign.html
[`SystemTime::duration_since`]: http://doc.rust-lang.org/nightly/std/time/struct.SystemTime.html#method.duration_since
[`SystemTime::elapsed`]: http://doc.rust-lang.org/nightly/std/time/struct.SystemTime.html#method.elapsed
[`SystemTime::now`]: http://doc.rust-lang.org/nightly/std/time/struct.SystemTime.html#method.now
[`SystemTimeError::duration`]: http://doc.rust-lang.org/nightly/std/time/struct.SystemTimeError.html#method.duration
[`SystemTimeError`]: http://doc.rust-lang.org/nightly/std/time/struct.SystemTimeError.html
[`UNIX_EPOCH`]: http://doc.rust-lang.org/nightly/std/time/constant.UNIX_EPOCH.html
[`ptr::drop_in_place`]: http://doc.rust-lang.org/nightly/std/ptr/fn.drop_in_place.html
[`str::EncodeUtf16`]: http://doc.rust-lang.org/nightly/std/str/struct.EncodeUtf16.html
[`str::encode_utf16`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.encode_utf16
[`time::Instant`]: http://doc.rust-lang.org/nightly/std/time/struct.Instant.html
[`time::SystemTime`]: http://doc.rust-lang.org/nightly/std/time/struct.SystemTime.html
Version 1.7.0 (2016-03-03)
==========================
Language
--------
* Soundness fixes to the interactions between associated types and
lifetimes, specified in [RFC 1214], [now generate errors][1.7sf] for
code that violates the new rules. This is a significant change that
is known to break existing code, so it has emitted warnings for the
new error cases since 1.4 to give crate authors time to adapt. The
details of what is changing are subtle; read the RFC for more.
Libraries
---------
@ -49,17 +267,6 @@ Libraries
* [`IntoStringError::into_cstring`]
* [`IntoStringError::utf8_error`]
* `Error for IntoStringError`
* Hashing
* [`std::hash::BuildHasher`]
* [`BuildHasher::Hasher`]
* [`BuildHasher::build_hasher`]
* [`std::hash::BuildHasherDefault`]
* [`HashMap::with_hasher`]
* [`HashMap::with_capacity_and_hasher`]
* [`HashSet::with_hasher`]
* [`HashSet::with_capacity_and_hasher`]
* [`std::collections::hash_map::RandomState`]
* [`RandomState::new`]
* [Validating UTF-8 is faster by a factor of between 7 and 14x for
ASCII input][1.7utf8]. This means that creating `String`s and `str`s
from bytes is faster.
@ -81,6 +288,9 @@ Libraries
Misc
----
* [The `--error-format=json` flag to `rustc` causes it to emit errors
in JSON format][1.7j]. This is an unstable flag and so also requires
the `-Z unstable-options` flag.
* [When running tests with `--test`, rustdoc will pass `--cfg`
arguments to the compiler][1.7dt].
* [The compiler is built with RPATH information by default][1.7rpa].
@ -102,12 +312,6 @@ Cargo
Compatibility Notes
-------------------
* Soundness fixes to the interactions between associated types and
lifetimes, specified in [RFC 1214], [now generate errors][1.7sf] for
code that violates the new rules. This is a significant change that
is known to break existing code, so it has emitted warnings for the
new error cases since 1.4 to give crate authors time to adapt. The
details of what is changing are subtle; read the RFC for more.
* [Several bugs in the compiler's visibility calculations were
fixed][1.7v]. Since this was found to break significant amounts of
code, the new errors will be emitted as warnings for several release
@ -130,6 +334,7 @@ Compatibility Notes
[1.7dta]: https://github.com/rust-lang/rust/pull/30394
[1.7f]: https://github.com/rust-lang/rust/pull/30672
[1.7h]: https://github.com/rust-lang/rust/pull/30818
[1.7j]: https://github.com/rust-lang/rust/pull/30711
[1.7ll]: https://github.com/rust-lang/rust/pull/30663
[1.7m]: https://github.com/rust-lang/rust/pull/30381
[1.7p]: https://github.com/rust-lang/rust/pull/30681
@ -140,15 +345,11 @@ Compatibility Notes
[1.7utf8]: https://github.com/rust-lang/rust/pull/30740
[1.7v]: https://github.com/rust-lang/rust/pull/29973
[RFC 1214]: https://github.com/rust-lang/rfcs/blob/master/text/1214-projections-lifetimes-and-wf.md
[`BuildHasher::Hasher`]: http://doc.rust-lang.org/nightly/std/hash/trait.Hasher.html
[`BuildHasher::build_hasher`]: http://doc.rust-lang.org/nightly/std/hash/trait.BuildHasher.html#tymethod.build_hasher
[`clone_from_slice`]: http://doc.rust-lang.org/nightly/std/primitive.slice.html#method.clone_from_slice
[`sort_by_key`]: http://doc.rust-lang.org/nightly/std/primitive.slice.html#method.sort_by_key
[`CString::into_bytes_with_nul`]: http://doc.rust-lang.org/nightly/std/ffi/struct.CString.html#method.into_bytes_with_nul
[`CString::into_bytes`]: http://doc.rust-lang.org/nightly/std/ffi/struct.CString.html#method.into_bytes
[`CString::into_string`]: http://doc.rust-lang.org/nightly/std/ffi/struct.CString.html#method.into_string
[`HashMap::with_capacity_and_hasher`]: http://doc.rust-lang.org/nightly/std/collections/struct.HashMap.html#method.with_capacity_and_hasher
[`HashMap::with_hasher`]: http://doc.rust-lang.org/nightly/std/collections/struct.HashMap.html#method.with_hasher
[`HashSet::with_capacity_and_hasher`]: http://doc.rust-lang.org/nightly/std/collections/struct.HashSet.html#method.with_capacity_and_hasher
[`HashSet::with_hasher`]: http://doc.rust-lang.org/nightly/std/collections/struct.HashSet.html#method.with_hasher
[`IntoStringError::into_cstring`]: http://doc.rust-lang.org/nightly/std/ffi/struct.IntoStringError.html#method.into_cstring
[`IntoStringError::utf8_error`]: http://doc.rust-lang.org/nightly/std/ffi/struct.IntoStringError.html#method.utf8_error
[`Ipv4Addr::is_broadcast`]: http://doc.rust-lang.org/nightly/std/net/struct.Ipv4Addr.html#method.is_broadcast
@ -161,12 +362,10 @@ Compatibility Notes
[`Ipv6Addr::is_multicast`]: http://doc.rust-lang.org/nightly/std/net/struct.Ipv6Addr.html#method.is_multicast
[`Ipv6Addr::is_unspecified`]: http://doc.rust-lang.org/nightly/std/net/struct.Ipv6Addr.html#method.is_unspecified
[`Path::strip_prefix`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.strip_prefix
[`RandomState::new`]: http://doc.rust-lang.org/nightly/std/collections/hash_map/struct.RandomState.html#method.new
[`String::as_mut_str`]: http://doc.rust-lang.org/nightly/std/string/struct.String.html#method.as_mut_str
[`String::as_str`]: http://doc.rust-lang.org/nightly/std/string/struct.String.html#method.as_str
[`Vec::as_mut_slice`]: http://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.as_mut_slice
[`Vec::as_slice`]: http://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.as_slice
[`clone_from_slice`]: http://doc.rust-lang.org/nightly/std/primitive.slice.html#method.clone_from_slice
[`ffi::IntoStringError`]: http://doc.rust-lang.org/nightly/std/ffi/struct.IntoStringError.html
[`i32::checked_neg`]: http://doc.rust-lang.org/nightly/std/primitive.i32.html#method.checked_neg
[`i32::checked_rem`]: http://doc.rust-lang.org/nightly/std/primitive.i32.html#method.checked_rem
@ -182,10 +381,6 @@ Compatibility Notes
[`i32::overflowing_sub`]: http://doc.rust-lang.org/nightly/std/primitive.i32.html#method.overflowing_sub
[`i32::saturating_mul`]: http://doc.rust-lang.org/nightly/std/primitive.i32.html#method.saturating_mul
[`path::StripPrefixError`]: http://doc.rust-lang.org/nightly/std/path/struct.StripPrefixError.html
[`sort_by_key`]: http://doc.rust-lang.org/nightly/std/primitive.slice.html#method.sort_by_key
[`std::collections::hash_map::RandomState`]: http://doc.rust-lang.org/nightly/std/collections/hash_map/struct.RandomState.html
[`std::hash::BuildHasherDefault`]: http://doc.rust-lang.org/nightly/std/hash/struct.BuildHasherDefault.html
[`std::hash::BuildHasher`]: http://doc.rust-lang.org/nightly/std/hash/trait.BuildHasher.html
[`u32::checked_neg`]: http://doc.rust-lang.org/nightly/std/primitive.u32.html#method.checked_neg
[`u32::checked_rem`]: http://doc.rust-lang.org/nightly/std/primitive.u32.html#method.checked_rem
[`u32::checked_shl`]: http://doc.rust-lang.org/nightly/std/primitive.u32.html#method.checked_shl

226
configure vendored
View File

@ -1,5 +1,13 @@
#!/bin/sh
# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/bash is.
if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then
POSIX_SHELL="true"
export POSIX_SHELL
exec /usr/bin/env bash $0 "$@"
fi
unset POSIX_SHELL # clear it so if we invoke other scripts, they run as bash as well
msg() {
echo "configure: $*"
}
@ -334,14 +342,6 @@ enable_if_not_disabled() {
fi
}
to_llvm_triple() {
case $1 in
i686-w64-mingw32) echo i686-pc-windows-gnu ;;
x86_64-w64-mingw32) echo x86_64-pc-windows-gnu ;;
*) echo $1 ;;
esac
}
to_gnu_triple() {
case $1 in
i686-pc-windows-gnu) echo i686-w64-mingw32 ;;
@ -424,6 +424,11 @@ case $CFG_OSTYPE in
CFG_OSTYPE=apple-darwin
;;
SunOS)
CFG_OSTYPE=sun-solaris
CFG_CPUTYPE=$(isainfo -n)
;;
MINGW*)
# msys' `uname` does not print gcc configuration, but prints msys
# configuration. so we cannot believe `uname -m`:
@ -550,7 +555,7 @@ CFG_SELF="$0"
CFG_CONFIGURE_ARGS="$@"
case "${CFG_SRC_DIR}" in
case "${CFG_SRC_DIR}" in
*\ * )
err "The path to the rust source directory contains spaces, which is not supported"
;;
@ -601,6 +606,7 @@ opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0"
opt dist-host-only 0 "only install bins for the host architecture"
opt inject-std-version 1 "inject the current compiler version of libstd into programs"
opt llvm-version-check 1 "check if the LLVM version is supported, build anyway"
opt rustbuild 0 "use the rust and cargo based build system"
# Optimization and debugging options. These may be overridden by the release channel, etc.
opt_nosave optimize 1 "build optimized rust code"
@ -620,7 +626,7 @@ valopt llvm-root "" "set LLVM root"
valopt python "" "set path to python"
valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
valopt android-cross-path "/opt/ndk_standalone" "Android NDK standalone path (deprecated)"
valopt android-cross-path "" "Android NDK standalone path (deprecated)"
valopt i686-linux-android-ndk "" "i686-linux-android NDK standalone path"
valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path"
valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path"
@ -646,12 +652,6 @@ valopt_nosave host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples"
valopt_nosave target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples"
valopt_nosave mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
# Temporarily support old triples until buildbots get updated
CFG_BUILD=$(to_llvm_triple $CFG_BUILD)
putvar CFG_BUILD # Yes, this creates a duplicate entry, but the last one wins.
CFG_HOST=$(to_llvm_triple $CFG_HOST)
CFG_TARGET=$(to_llvm_triple $CFG_TARGET)
# On Windows this determines root of the subtree for target libraries.
# Host runtime libs always go to 'bin'.
valopt libdir "${CFG_PREFIX}/lib" "install libraries"
@ -729,12 +729,12 @@ step_msg "looking for build programs"
probe_need CFG_CURLORWGET curl wget
if [ -z "$CFG_PYTHON_PROVIDED" ]; then
probe_need CFG_PYTHON python2.7 python2.6 python2 python
probe_need CFG_PYTHON python2.7 python2 python
fi
python_version=$($CFG_PYTHON -V 2>&1)
if [ $(echo $python_version | grep -c '^Python 2\.[4567]') -ne 1 ]; then
err "Found $python_version, but LLVM requires Python 2.4-2.7"
if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then
err "Found $python_version, but Python 2.7 is required"
fi
# If we have no git directory then we are probably a tarball distribution
@ -865,9 +865,8 @@ fi
# Force bitrig to build with clang; gcc doesn't like us there
if [ $CFG_OSTYPE = unknown-bitrig ]
then
step_msg "on Bitrig, forcing use of clang, disabling jemalloc"
step_msg "on Bitrig, forcing use of clang"
CFG_ENABLE_CLANG=1
CFG_DISABLE_JEMALLOC=1
fi
# default gcc version under OpenBSD maybe too old, try using egcc, which is a
@ -887,9 +886,6 @@ then
CXX="${CXX:-eg++}"
fi
fi
step_msg "on OpenBSD, disabling jemalloc"
CFG_DISABLE_JEMALLOC=1
fi
# OS X 10.9, gcc is actually clang. This can cause some confusion in the build
@ -1044,7 +1040,7 @@ then
esac
else
case $CFG_CLANG_VERSION in
(3.2* | 3.3* | 3.4* | 3.5* | 3.6* | 3.7* | 3.8*)
(3.2* | 3.3* | 3.4* | 3.5* | 3.6* | 3.7* | 3.8* | 3.9*)
step_msg "found ok version of CLANG: $CFG_CLANG_VERSION"
;;
(*)
@ -1171,7 +1167,7 @@ do
;;
*-musl)
x86_64-*-musl)
if [ ! -f $CFG_MUSL_ROOT/lib/libc.a ]
then
err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found"
@ -1179,12 +1175,6 @@ do
;;
*-msvc)
# Currently the build system is not configured to build jemalloc
# with MSVC, so we omit this optional dependency.
step_msg "targeting MSVC, disabling jemalloc"
CFG_DISABLE_JEMALLOC=1
putvar CFG_DISABLE_JEMALLOC
# There are some MSYS python builds which will auto-translate
# windows-style paths to MSYS-style paths in Python itself.
# Unfortunately this breaks LLVM's build system as somewhere along
@ -1293,12 +1283,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
putvar CFG_MSVC_LIB_PATH_${bits}
;;
*-rumprun-netbsd)
step_msg "targeting rumprun-netbsd, disabling jemalloc"
CFG_DISABLE_JEMALLOC=1
putvar CFG_DISABLE_JEMALLOC
;;
*)
;;
esac
@ -1314,96 +1298,107 @@ then
fi
fi
step_msg "making directories"
if [ -z "$CFG_ENABLE_RUSTBUILD" ]; then
for i in \
doc doc/std doc/extra \
dl tmp dist
do
make_dir $i
done
step_msg "making directories"
for t in $CFG_HOST
do
make_dir $t/llvm
done
for t in $CFG_HOST
do
make_dir $t/rustllvm
done
for t in $CFG_TARGET
do
make_dir $t/rt
for s in 0 1 2 3
for i in \
doc doc/std doc/extra \
dl tmp dist
do
make_dir $t/rt/stage$s
make_dir $t/rt/jemalloc
make_dir $t/rt/compiler-rt
for i in \
isaac sync test \
arch/i386 arch/x86_64 arch/arm arch/aarch64 arch/mips arch/powerpc
make_dir $i
done
for t in $CFG_HOST
do
make_dir $t/llvm
done
for t in $CFG_HOST
do
make_dir $t/rustllvm
done
for t in $CFG_TARGET
do
make_dir $t/rt
for s in 0 1 2 3
do
make_dir $t/rt/stage$s/$i
make_dir $t/rt/stage$s
make_dir $t/rt/jemalloc
make_dir $t/rt/compiler-rt
for i in \
isaac sync test \
arch/i386 arch/x86_64 arch/arm arch/aarch64 arch/mips arch/powerpc
do
make_dir $t/rt/stage$s/$i
done
done
done
done
for h in $CFG_HOST
do
for t in $CFG_TARGET
do
# host lib dir stage0
make_dir $h/stage0/lib
for h in $CFG_HOST
do
for t in $CFG_TARGET
do
# host bin dir stage0
make_dir $h/stage0/bin
# target bin dir stage0
make_dir $h/stage0/lib/rustlib/$t/bin
# host lib dir stage0
make_dir $h/stage0/lib
# target lib dir stage0
make_dir $h/stage0/lib/rustlib/$t/lib
# host test dir stage0
make_dir $h/stage0/test
for i in 0 1 2 3
do
# host bin dir
make_dir $h/stage$i/bin
# target bin dir stage0
make_dir $h/stage0/lib/rustlib/$t/bin
# host lib dir
make_dir $h/stage$i/$CFG_LIBDIR_RELATIVE
# target lib dir stage0
make_dir $h/stage0/lib/rustlib/$t/lib
# host test dir
make_dir $h/stage$i/test
for i in 1 2 3
do
# host bin dir
make_dir $h/stage$i/bin
# target bin dir
make_dir $h/stage$i/$CFG_LIBDIR_RELATIVE/rustlib/$t/bin
# host lib dir
make_dir $h/stage$i/$CFG_LIBDIR_RELATIVE
# target lib dir
make_dir $h/stage$i/$CFG_LIBDIR_RELATIVE/rustlib/$t/lib
done
done
# host test dir
make_dir $h/stage$i/test
make_dir $h/test/run-pass
make_dir $h/test/run-pass-valgrind
make_dir $h/test/run-pass-fulldeps
make_dir $h/test/run-fail
make_dir $h/test/run-fail-fulldeps
make_dir $h/test/compile-fail
make_dir $h/test/parse-fail
make_dir $h/test/compile-fail-fulldeps
make_dir $h/test/bench
make_dir $h/test/perf
make_dir $h/test/pretty
make_dir $h/test/debuginfo-gdb
make_dir $h/test/debuginfo-lldb
make_dir $h/test/codegen
make_dir $h/test/rustdoc
done
# target bin dir
make_dir $h/stage$i/$CFG_LIBDIR_RELATIVE/rustlib/$t/bin
# target lib dir
make_dir $h/stage$i/$CFG_LIBDIR_RELATIVE/rustlib/$t/lib
done
done
make_dir $h/test/run-pass
make_dir $h/test/run-pass-valgrind
make_dir $h/test/run-pass-fulldeps
make_dir $h/test/run-fail
make_dir $h/test/run-fail-fulldeps
make_dir $h/test/compile-fail
make_dir $h/test/parse-fail
make_dir $h/test/compile-fail-fulldeps
make_dir $h/test/bench
make_dir $h/test/perf
make_dir $h/test/pretty
make_dir $h/test/debuginfo-gdb
make_dir $h/test/debuginfo-lldb
make_dir $h/test/codegen
make_dir $h/test/codegen-units
make_dir $h/test/rustdoc
done
fi
# Configure submodules
step_msg "configuring submodules"
# Have to be in the top of src directory for this
if [ -z $CFG_DISABLE_MANAGE_SUBMODULES ]
if [ -z $CFG_DISABLE_MANAGE_SUBMODULES ] && [ -z $CFG_ENABLE_RUSTBUILD ]
then
cd ${CFG_SRC_DIR}
@ -1462,7 +1457,11 @@ do
;;
esac
if [ -z $CFG_LLVM_ROOT ]
if [ -n "$CFG_ENABLE_RUSTBUILD" ]
then
msg "not configuring LLVM, rustbuild in use"
do_reconfigure=0
elif [ -z $CFG_LLVM_ROOT ]
then
LLVM_BUILD_DIR=${CFG_BUILD_DIR}$t/llvm
if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]
@ -1793,8 +1792,15 @@ do
putvar $CFG_LLVM_INST_DIR
done
if [ -n "$CFG_ENABLE_RUSTBUILD" ]
then
INPUT_MAKEFILE=src/bootstrap/mk/Makefile.in
else
INPUT_MAKEFILE=Makefile.in
fi
msg
copy_if_changed ${CFG_SRC_DIR}Makefile.in ./Makefile
copy_if_changed ${CFG_SRC_DIR}${INPUT_MAKEFILE} ./Makefile
move_if_changed config.tmp config.mk
rm -f config.tmp
touch config.stamp

View File

@ -6,9 +6,7 @@ rustc \- The Rust compiler
[\fIOPTIONS\fR] \fIINPUT\fR
.SH DESCRIPTION
This program is a compiler for the Rust language, available at
.UR https://www.rust\-lang.org
.UE .
This program is a compiler for the Rust language, available at https://www.rust\-lang.org.
.SH OPTIONS
@ -53,10 +51,9 @@ Comma separated list of types of crates for the compiler to emit.
Specify the name of the crate being built.
.TP
\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info][=\fIPATH\fR]
Configure the output that \fBrustc\fR will produce.
Each emission may also have an optional explicit output \fIPATH\fR specified for that particular
emission kind. This path takes precedence over the \fB-o\fR option.
Configure the output that \fBrustc\fR will produce. Each emission may also have
an optional explicit output \fIPATH\fR specified for that particular emission
kind. This path takes precedence over the \fB-o\fR option.
.TP
\fB\-\-print\fR [crate\-name|file\-names|sysroot]
Comma separated list of compiler information to print on stdout.
@ -68,13 +65,11 @@ Equivalent to \fI\-C\ debuginfo=2\fR.
Equivalent to \fI\-C\ opt\-level=2\fR.
.TP
\fB\-o\fR \fIFILENAME\fR
Write output to \fIFILENAME\fR.
Ignored if multiple \fI\-\-emit\fR outputs are specified which don't have an
explicit path otherwise.
Write output to \fIFILENAME\fR. Ignored if multiple \fI\-\-emit\fR outputs are specified which
don't have an explicit path otherwise.
.TP
\fB\-\-out\-dir\fR \fIDIR\fR
Write output to compiler\[hy]chosen filename in \fIDIR\fR.
Ignored if \fI\-o\fR is specified.
Write output to compiler\[hy]chosen filename in \fIDIR\fR. Ignored if \fI\-o\fR is specified.
Defaults to the current directory.
.TP
\fB\-\-explain\fR \fIOPT\fR
@ -83,12 +78,26 @@ Provide a detailed explanation of an error message.
\fB\-\-test\fR
Build a test harness.
.TP
\fB\-\-target\fR \fITRIPLE\fR
Target triple \fIcpu\fR\-\fImanufacturer\fR\-\fIkernel\fR[\-\fIos\fR]
to compile for (see chapter 3.4 of
.UR http://www.sourceware.org/autobook/
.UE
for details).
\fB\-\-target\fR \fITARGET\fR
Target triple for which the code is compiled. This option defaults to the hosts target
triple. The target triple has the general format <arch><sub>\-<vendor>\-<sys>\-<abi>, where:
.RS
.TP
.B <arch>
x86, arm, thumb, mips, etc.
.TP
.B <sub>
for example on ARM: v5, v6m, v7a, v7m, etc.
.TP
.B <vendor>
pc, apple, nvidia, ibm, etc.
.TP
.B <sys>
none, linux, win32, darwin, cuda, etc.
.TP
.B <abi>
eabi, gnu, android, macho, elf, etc.
.RE
.TP
\fB\-W help\fR
Print 'lint' options and default settings.
@ -287,10 +296,7 @@ To build an executable with debug info:
.BR rustdoc (1)
.SH "BUGS"
See
.UR https://github.com/rust\-lang/rust/issues
.UE
for issues.
See https://github.com/rust\-lang/rust/issues for issues.
.SH "AUTHOR"
See \fIAUTHORS.txt\fR in the Rust source distribution.

View File

@ -8,10 +8,8 @@ rustdoc \- generate documentation from Rust source code
.SH DESCRIPTION
This tool generates API reference documentation by extracting comments from
source code written in the Rust language, available at
.UR https://www.rust\-lang.org
.UE .
It accepts several input formats and provides several output formats
for the generated documentation.
<\fBhttps://www.rust-lang.org\fR>. It accepts several input formats and
provides several output formats for the generated documentation.
.SH OPTIONS
@ -131,9 +129,7 @@ The generated HTML can be viewed with any standard web browser.
.BR rustc (1)
.SH "BUGS"
See
.UR https://github.com/rust\-lang/rust/issues
.UE
See <\fBhttps://github.com/rust\-lang/rust/issues\fR>
for issues.
.SH "AUTHOR"

View File

@ -8,8 +8,8 @@ CFG_LIB_NAME_arm-unknown-linux-gnueabi=lib$(1).so
CFG_STATIC_LIB_NAME_arm-unknown-linux-gnueabi=lib$(1).a
CFG_LIB_GLOB_arm-unknown-linux-gnueabi=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_arm-unknown-linux-gnueabi=lib$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabi := -D__arm__ -mfloat-abi=soft $(CFLAGS)
CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__ -mfloat-abi=soft $(CFLAGS)
CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabi := -D__arm__ -mfloat-abi=soft $(CFLAGS) -march=armv6 -marm
CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__ -mfloat-abi=soft $(CFLAGS) -march=armv6 -marm
CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabi := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabi := -shared -fPIC -g
CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabi := -Wl,--export-dynamic,--dynamic-list=

View File

@ -8,8 +8,8 @@ CFG_LIB_NAME_arm-unknown-linux-gnueabihf=lib$(1).so
CFG_STATIC_LIB_NAME_arm-unknown-linux-gnueabihf=lib$(1).a
CFG_LIB_GLOB_arm-unknown-linux-gnueabihf=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_arm-unknown-linux-gnueabihf=lib$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabihf := -D__arm__ $(CFLAGS)
CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabihf := -Wall -g -fPIC -D__arm__ $(CFLAGS)
CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabihf := -D__arm__ $(CFLAGS) -march=armv6 -marm
CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabihf := -Wall -g -fPIC -D__arm__ $(CFLAGS) -march=armv6 -marm
CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabihf := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabihf := -shared -fPIC -g
CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabihf := -Wl,--export-dynamic,--dynamic-list=

View File

@ -0,0 +1,26 @@
# armv7-unknown-linux-gnueabihf configuration
CROSS_PREFIX_armv7-unknown-linux-gnueabihf=arm-linux-gnueabihf-
CC_armv7-unknown-linux-gnueabihf=gcc
CXX_armv7-unknown-linux-gnueabihf=g++
CPP_armv7-unknown-linux-gnueabihf=gcc -E
AR_armv7-unknown-linux-gnueabihf=ar
CFG_LIB_NAME_armv7-unknown-linux-gnueabihf=lib$(1).so
CFG_STATIC_LIB_NAME_armv7-unknown-linux-gnueabihf=lib$(1).a
CFG_LIB_GLOB_armv7-unknown-linux-gnueabihf=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_armv7-unknown-linux-gnueabihf=lib$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_armv7-unknown-linux-gnueabihf := -D__arm__ $(CFLAGS) -march=armv7-a
CFG_GCCISH_CFLAGS_armv7-unknown-linux-gnueabihf := -Wall -g -fPIC -D__arm__ $(CFLAGS) -march=armv7-a
CFG_GCCISH_CXXFLAGS_armv7-unknown-linux-gnueabihf := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_armv7-unknown-linux-gnueabihf := -shared -fPIC -g
CFG_GCCISH_DEF_FLAG_armv7-unknown-linux-gnueabihf := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_armv7-unknown-linux-gnueabihf :=
CFG_INSTALL_NAME_ar,-unknown-linux-gnueabihf =
CFG_EXE_SUFFIX_armv7-unknown-linux-gnueabihf :=
CFG_WINDOWSY_armv7-unknown-linux-gnueabihf :=
CFG_UNIXY_armv7-unknown-linux-gnueabihf := 1
CFG_LDPATH_armv7-unknown-linux-gnueabihf :=
CFG_RUN_armv7-unknown-linux-gnueabihf=$(2)
CFG_RUN_TARG_armv7-unknown-linux-gnueabihf=$(call CFG_RUN_armv7-unknown-linux-gnueabihf,,$(2))
RUSTC_FLAGS_armv7-unknown-linux-gnueabihf :=
RUSTC_CROSS_FLAGS_armv7-unknown-linux-gnueabihf :=
CFG_GNU_TRIPLE_armv7-unknown-linux-gnueabihf := armv7-unknown-linux-gnueabihf

View File

@ -14,8 +14,8 @@ CFG_LIB_GLOB_armv7s-apple-ios = lib$(1)-*.a
CFG_INSTALL_ONLY_RLIB_armv7s-apple-ios = 1
CFG_STATIC_LIB_NAME_armv7s-apple-ios=lib$(1).a
CFG_LIB_DSYM_GLOB_armv7s-apple-ios = lib$(1)-*.a.dSYM
CFG_JEMALLOC_CFLAGS_armv7s-apple-ios := -arch armv7s -mfpu=vfp4 $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios)
CFG_GCCISH_CFLAGS_armv7s-apple-ios := -Wall -Werror -g -fPIC $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios) -mfpu=vfp4 -arch armv7s
CFG_JEMALLOC_CFLAGS_armv7s-apple-ios := -arch armv7s $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios)
CFG_GCCISH_CFLAGS_armv7s-apple-ios := -Wall -Werror -g -fPIC $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios) -arch armv7s
CFG_GCCISH_CXXFLAGS_armv7s-apple-ios := -fno-rtti $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios) -I$(CFG_IOS_SDK_armv7s-apple-ios)/usr/include/c++/4.2.1
CFG_GCCISH_LINK_FLAGS_armv7s-apple-ios := -lpthread -syslibroot $(CFG_IOS_SDK_armv7s-apple-ios) -Wl,-no_compact_unwind
CFG_GCCISH_DEF_FLAG_armv7s-apple-ios := -Wl,-exported_symbols_list,

View File

@ -0,0 +1,24 @@
# asmjs-unknown-emscripten configuration
CC_asmjs-unknown-emscripten=emcc
CXX_asmjs-unknown-emscripten=em++
CPP_asmjs-unknown-emscripten=$(CPP)
AR_asmjs-unknown-emscripten=emar
CFG_LIB_NAME_asmjs-unknown-emscripten=lib$(1).so
CFG_STATIC_LIB_NAME_asmjs-unknown-emscripten=lib$(1).a
CFG_LIB_GLOB_asmjs-unknown-emscripten=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_asmjs-unknown-emscripten=lib$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_asmjs-unknown-emscripten := -m32 $(CFLAGS)
CFG_GCCISH_CFLAGS_asmjs-unknown-emscripten := -Wall -Werror -g -fPIC -m32 $(CFLAGS)
CFG_GCCISH_CXXFLAGS_asmjs-unknown-emscripten := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_asmjs-unknown-emscripten := -shared -fPIC -ldl -pthread -lrt -g -m32
CFG_GCCISH_DEF_FLAG_asmjs-unknown-emscripten := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_asmjs-unknown-emscripten :=
CFG_INSTALL_NAME_asmjs-unknown-emscripten =
CFG_EXE_SUFFIX_asmjs-unknown-emscripten =
CFG_WINDOWSY_asmjs-unknown-emscripten :=
CFG_UNIXY_asmjs-unknown-emscripten := 1
CFG_LDPATH_asmjs-unknown-emscripten :=
CFG_RUN_asmjs-unknown-emscripten=$(2)
CFG_RUN_TARG_asmjs-unknown-emscripten=$(call CFG_RUN_asmjs-unknown-emscripten,,$(2))
CFG_GNU_TRIPLE_asmjs-unknown-emscripten := asmjs-unknown-emscripten
CFG_DISABLE_JEMALLOC_asmjs-unknown-emscripten := 1

View File

@ -0,0 +1,23 @@
# i586-unknown-linux-gnu configuration
CC_i586-unknown-linux-gnu=$(CC)
CXX_i586-unknown-linux-gnu=$(CXX)
CPP_i586-unknown-linux-gnu=$(CPP)
AR_i586-unknown-linux-gnu=$(AR)
CFG_LIB_NAME_i586-unknown-linux-gnu=lib$(1).so
CFG_STATIC_LIB_NAME_i586-unknown-linux-gnu=lib$(1).a
CFG_LIB_GLOB_i586-unknown-linux-gnu=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_i586-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_i586-unknown-linux-gnu := -m32 $(CFLAGS)
CFG_GCCISH_CFLAGS_i586-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32 $(CFLAGS)
CFG_GCCISH_CXXFLAGS_i586-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_i586-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m32
CFG_GCCISH_DEF_FLAG_i586-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_i586-unknown-linux-gnu :=
CFG_INSTALL_NAME_i586-unknown-linux-gnu =
CFG_EXE_SUFFIX_i586-unknown-linux-gnu =
CFG_WINDOWSY_i586-unknown-linux-gnu :=
CFG_UNIXY_i586-unknown-linux-gnu := 1
CFG_LDPATH_i586-unknown-linux-gnu :=
CFG_RUN_i586-unknown-linux-gnu=$(2)
CFG_RUN_TARG_i586-unknown-linux-gnu=$(call CFG_RUN_i586-unknown-linux-gnu,,$(2))
CFG_GNU_TRIPLE_i586-unknown-linux-gnu := i586-unknown-linux-gnu

View File

@ -25,3 +25,5 @@ CFG_GNU_TRIPLE_i686-pc-windows-gnu := i686-w64-mingw32
CFG_THIRD_PARTY_OBJECTS_i686-pc-windows-gnu := crt2.o dllcrt2.o
CFG_INSTALLED_OBJECTS_i686-pc-windows-gnu := crt2.o dllcrt2.o rsbegin.o rsend.o
CFG_RUSTRT_HAS_STARTUP_OBJS_i686-pc-windows-gnu := 1
# FIXME(#31030) - there's not a great reason to disable jemalloc here
CFG_DISABLE_JEMALLOC_i686-pc-windows-gnu := 1

View File

@ -22,3 +22,7 @@ CFG_LDPATH_i686-pc-windows-msvc :=
CFG_RUN_i686-pc-windows-msvc=$(2)
CFG_RUN_TARG_i686-pc-windows-msvc=$(call CFG_RUN_i686-pc-windows-msvc,,$(2))
CFG_GNU_TRIPLE_i686-pc-windows-msvc := i686-pc-win32
# Currently the build system is not configured to build jemalloc
# with MSVC, so we omit this optional dependency.
CFG_DISABLE_JEMALLOC_i686-pc-windows-msvc := 1

View File

@ -0,0 +1,28 @@
# i686-unknown-linux-musl configuration
CC_i686-unknown-linux-musl=$(CFG_MUSL_ROOT)/bin/musl-gcc
CXX_i686-unknown-linux-musl=notaprogram
CPP_i686-unknown-linux-musl=$(CFG_MUSL_ROOT)/bin/musl-gcc -E
AR_i686-unknown-linux-musl=$(AR)
CFG_INSTALL_ONLY_RLIB_i686-unknown-linux-musl = 1
CFG_LIB_NAME_i686-unknown-linux-musl=lib$(1).so
CFG_STATIC_LIB_NAME_i686-unknown-linux-musl=lib$(1).a
CFG_LIB_GLOB_i686-unknown-linux-musl=lib$(1)-*.so
CFG_JEMALLOC_CFLAGS_i686-unknown-linux-musl := -m32 -Wl,-melf_i386
CFG_GCCISH_CFLAGS_i686-unknown-linux-musl := -Wall -Werror -g -fPIC -m32 -Wl,-melf_i386
CFG_GCCISH_CXXFLAGS_i686-unknown-linux-musl :=
CFG_GCCISH_LINK_FLAGS_i686-unknown-linux-musl :=
CFG_GCCISH_DEF_FLAG_i686-unknown-linux-musl :=
CFG_LLC_FLAGS_i686-unknown-linux-musl :=
CFG_INSTALL_NAME_i686-unknown-linux-musl =
CFG_EXE_SUFFIX_i686-unknown-linux-musl =
CFG_WINDOWSY_i686-unknown-linux-musl :=
CFG_UNIXY_i686-unknown-linux-musl := 1
CFG_LDPATH_i686-unknown-linux-musl :=
CFG_RUN_i686-unknown-linux-musl=$(2)
CFG_RUN_TARG_i686-unknown-linux-musl=$(call CFG_RUN_i686-unknown-linux-musl,,$(2))
CFG_GNU_TRIPLE_i686-unknown-linux-musl := i686-unknown-linux-musl
CFG_THIRD_PARTY_OBJECTS_i686-unknown-linux-musl := crt1.o crti.o crtn.o
CFG_INSTALLED_OBJECTS_i686-unknown-linux-musl := crt1.o crti.o crtn.o
NATIVE_DEPS_libc_T_i686-unknown-linux-musl += libc.a
NATIVE_DEPS_std_T_i686-unknown-linux-musl += libunwind.a crt1.o crti.o crtn.o

View File

@ -20,5 +20,5 @@ CFG_UNIXY_mips-unknown-linux-gnu := 1
CFG_LDPATH_mips-unknown-linux-gnu :=
CFG_RUN_mips-unknown-linux-gnu=
CFG_RUN_TARG_mips-unknown-linux-gnu=
RUSTC_FLAGS_mips-unknown-linux-gnu := -C target-cpu=mips32r2 -C target-feature="+mips32r2" -C soft-float
RUSTC_FLAGS_mips-unknown-linux-gnu :=
CFG_GNU_TRIPLE_mips-unknown-linux-gnu := mips-unknown-linux-gnu

View File

@ -0,0 +1,24 @@
# mips-unknown-linux-musl configuration
CC_mips-unknown-linux-musl=mips-linux-musl-gcc
CXX_mips-unknown-linux-musl=mips-linux-musl-g++
CPP_mips-unknown-linux-musl=mips-linux-musl-gcc -E
AR_mips-unknown-linux-musl=mips-linux-musl-ar
CFG_LIB_NAME_mips-unknown-linux-musl=lib$(1).so
CFG_STATIC_LIB_NAME_mips-unknown-linux-musl=lib$(1).a
CFG_LIB_GLOB_mips-unknown-linux-musl=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_mips-unknown-linux-musl=lib$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_mips-unknown-linux-musl := -mips32r2 -msoft-float -mabi=32 $(CFLAGS)
CFG_GCCISH_CFLAGS_mips-unknown-linux-musl := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 $(CFLAGS)
CFG_GCCISH_CXXFLAGS_mips-unknown-linux-musl := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-musl := -shared -fPIC -g -mips32r2 -msoft-float -mabi=32
CFG_GCCISH_DEF_FLAG_mips-unknown-linux-musl := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_mips-unknown-linux-musl :=
CFG_INSTALL_NAME_mips-unknown-linux-musl =
CFG_EXE_SUFFIX_mips-unknown-linux-musl =
CFG_WINDOWSY_mips-unknown-linux-musl :=
CFG_UNIXY_mips-unknown-linux-musl := 1
CFG_LDPATH_mips-unknown-linux-musl :=
CFG_RUN_mips-unknown-linux-musl=
CFG_RUN_TARG_mips-unknown-linux-musl=
RUSTC_FLAGS_mips-unknown-linux-musl :=
CFG_GNU_TRIPLE_mips-unknown-linux-musl := mips-unknown-linux-musl

View File

@ -20,5 +20,5 @@ CFG_UNIXY_mipsel-unknown-linux-gnu := 1
CFG_LDPATH_mipsel-unknown-linux-gnu :=
CFG_RUN_mipsel-unknown-linux-gnu=
CFG_RUN_TARG_mipsel-unknown-linux-gnu=
RUSTC_FLAGS_mipsel-unknown-linux-gnu := -C target-cpu=mips32 -C target-feature="+mips32"
RUSTC_FLAGS_mipsel-unknown-linux-gnu :=
CFG_GNU_TRIPLE_mipsel-unknown-linux-gnu := mipsel-unknown-linux-gnu

View File

@ -0,0 +1,24 @@
# mipsel-unknown-linux-musl configuration
CC_mipsel-unknown-linux-musl=mipsel-linux-musl-gcc
CXX_mipsel-unknown-linux-musl=mipsel-linux-musl-g++
CPP_mipsel-unknown-linux-musl=mipsel-linux-musl-gcc
AR_mipsel-unknown-linux-musl=mipsel-linux-musl-ar
CFG_LIB_NAME_mipsel-unknown-linux-musl=lib$(1).so
CFG_STATIC_LIB_NAME_mipsel-unknown-linux-musl=lib$(1).a
CFG_LIB_GLOB_mipsel-unknown-linux-musl=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_mipsel-unknown-linux-musl=lib$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_mipsel-unknown-linux-musl := -mips32 -mabi=32 $(CFLAGS)
CFG_GCCISH_CFLAGS_mipsel-unknown-linux-musl := -Wall -g -fPIC -mips32 -mabi=32 $(CFLAGS)
CFG_GCCISH_CXXFLAGS_mipsel-unknown-linux-musl := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_mipsel-unknown-linux-musl := -shared -fPIC -g -mips32
CFG_GCCISH_DEF_FLAG_mipsel-unknown-linux-musl := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_mipsel-unknown-linux-musl :=
CFG_INSTALL_NAME_mipsel-unknown-linux-musl =
CFG_EXE_SUFFIX_mipsel-unknown-linux-musl :=
CFG_WINDOWSY_mipsel-unknown-linux-musl :=
CFG_UNIXY_mipsel-unknown-linux-musl := 1
CFG_LDPATH_mipsel-unknown-linux-musl :=
CFG_RUN_mipsel-unknown-linux-musl=
CFG_RUN_TARG_mipsel-unknown-linux-musl=
RUSTC_FLAGS_mipsel-unknown-linux-musl :=
CFG_GNU_TRIPLE_mipsel-unknown-linux-musl := mipsel-unknown-linux-musl

View File

@ -1,5 +1,5 @@
# powerpc64-unknown-linux-gnu configuration
CROSS_PREFIX_powerpc64-unknown-linux-gnu=powerpc64-linux-gnu-
CROSS_PREFIX_powerpc64-unknown-linux-gnu=powerpc-linux-gnu-
CC_powerpc64-unknown-linux-gnu=$(CC)
CXX_powerpc64-unknown-linux-gnu=$(CXX)
CPP_powerpc64-unknown-linux-gnu=$(CPP)
@ -8,6 +8,7 @@ CFG_LIB_NAME_powerpc64-unknown-linux-gnu=lib$(1).so
CFG_STATIC_LIB_NAME_powerpc64-unknown-linux-gnu=lib$(1).a
CFG_LIB_GLOB_powerpc64-unknown-linux-gnu=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_powerpc64-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_powerpc64-unknown-linux-gnu := -m64
CFG_CFLAGS_powerpc64-unknown-linux-gnu := -m64 $(CFLAGS)
CFG_GCCISH_CFLAGS_powerpc64-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64 $(CFLAGS)
CFG_GCCISH_CXXFLAGS_powerpc64-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)

View File

@ -25,3 +25,5 @@ CFG_GNU_TRIPLE_x86_64-pc-windows-gnu := x86_64-w64-mingw32
CFG_THIRD_PARTY_OBJECTS_x86_64-pc-windows-gnu := crt2.o dllcrt2.o
CFG_INSTALLED_OBJECTS_x86_64-pc-windows-gnu := crt2.o dllcrt2.o rsbegin.o rsend.o
CFG_RUSTRT_HAS_STARTUP_OBJS_x86_64-pc-windows-gnu := 1
# FIXME(#31030) - there's not a great reason to disable jemalloc here
CFG_DISABLE_JEMALLOC_x86_64-pc-windows-gnu := 1

View File

@ -22,3 +22,7 @@ CFG_LDPATH_x86_64-pc-windows-msvc :=
CFG_RUN_x86_64-pc-windows-msvc=$(2)
CFG_RUN_TARG_x86_64-pc-windows-msvc=$(call CFG_RUN_x86_64-pc-windows-msvc,,$(2))
CFG_GNU_TRIPLE_x86_64-pc-windows-msvc := x86_64-pc-win32
# Currently the build system is not configured to build jemalloc
# with MSVC, so we omit this optional dependency.
CFG_DISABLE_JEMALLOC_x86_64-pc-windows-msvc := 1

View File

@ -22,3 +22,4 @@ CFG_LDPATH_x86_64-rumprun-netbsd :=
CFG_RUN_x86_64-rumprun-netbsd=$(2)
CFG_RUN_TARG_x86_64-rumprun-netbsd=$(call CFG_RUN_x86_64-rumprun-netbsd,,$(2))
CFG_GNU_TRIPLE_x86_64-rumprun-netbsd := x86_64-rumprun-netbsd
CFG_DISABLE_JEMALLOC_x86_64-rumprun-netbsd := 1

View File

@ -0,0 +1,23 @@
# x86_64-sun-solaris configuration
CROSS_PREFIX_x86_64-sun-solaris=x86_64-sun-solaris2.11-
CC_x86_64-sun-solaris=$(CC)
CXX_x86_64-sun-solaris=$(CXX)
CPP_x86_64-sun-solaris=$(CPP)
AR_x86_64-sun-solaris=$(AR)
CFG_LIB_NAME_x86_64-sun-solaris=lib$(1).so
CFG_STATIC_LIB_NAME_x86_64-sun-solaris=lib$(1).a
CFG_LIB_GLOB_x86_64-sun-solaris=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_x86_64-sun-solaris=$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_x86_64-sun-solaris := -I/usr/local/include $(CFLAGS)
CFG_GCCISH_CFLAGS_x86_64-sun-solaris := -Wall -Werror -g -D_POSIX_PTHREAD_SEMANTICS -fPIC -I/usr/local/include $(CFLAGS)
CFG_GCCISH_LINK_FLAGS_x86_64-sun-solaris := -shared -fPIC -g -pthread -lrt
CFG_GCCISH_DEF_FLAG_x86_64-sun-solaris := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_x86_64-sun-solaris :=
CFG_INSTALL_NAME_x86_64-sun-solaris =
CFG_EXE_SUFFIX_x86_64-sun-solaris :=
CFG_WINDOWSY_x86_64-sun-solaris :=
CFG_UNIXY_x86_64-sun-solaris := 1
CFG_LDPATH_x86_64-sun-solaris :=
CFG_RUN_x86_64-sun-solaris=$(2)
CFG_RUN_TARG_x86_64-sun-solaris=$(call CFG_RUN_x86_64-sun-solaris,,$(2))
CFG_GNU_TRIPLE_x86_64-sun-solaris := x86_64-sun-solaris

View File

@ -20,3 +20,4 @@ CFG_LDPATH_x86_64-unknown-bitrig :=
CFG_RUN_x86_64-unknown-bitrig=$(2)
CFG_RUN_TARG_x86_64-unknown-bitrig=$(call CFG_RUN_x86_64-unknown-bitrig,,$(2))
CFG_GNU_TRIPLE_x86_64-unknown-bitrig := x86_64-unknown-bitrig
CFG_DISABLE_JEMALLOC_x86_64-unknown-bitrig := 1

View File

@ -21,3 +21,4 @@ CFG_RUN_x86_64-unknown-openbsd=$(2)
CFG_RUN_TARG_x86_64-unknown-openbsd=$(call CFG_RUN_x86_64-unknown-openbsd,,$(2))
CFG_GNU_TRIPLE_x86_64-unknown-openbsd := x86_64-unknown-openbsd
RUSTC_FLAGS_x86_64-unknown-openbsd=-C linker=$(call FIND_COMPILER,$(CC))
CFG_DISABLE_JEMALLOC_x86_64-unknown-openbsd := 1

View File

@ -53,17 +53,18 @@ TARGET_CRATES := libc std flate arena term \
serialize getopts collections test rand \
log graphviz core rbml alloc \
rustc_unicode rustc_bitflags \
alloc_system
alloc_system alloc_jemalloc
RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
rustc_data_structures rustc_front rustc_platform_intrinsics \
rustc_plugin rustc_metadata rustc_passes
HOST_CRATES := syntax syntax_ext $(RUSTC_CRATES) rustdoc fmt_macros
TOOLS := compiletest rustdoc rustc rustbook error-index-generator
TOOLS := compiletest rustdoc rustc rustbook error_index_generator
DEPS_core :=
DEPS_alloc := core libc alloc_system
DEPS_alloc_system := core libc
DEPS_alloc_jemalloc := core libc native:jemalloc
DEPS_collections := core alloc rustc_unicode
DEPS_libc := core
DEPS_rand := core
@ -102,11 +103,11 @@ DEPS_rustc_front := std syntax log serialize
DEPS_rustc_lint := rustc log syntax
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
DEPS_rustc_metadata := rustc rustc_front syntax rbml
DEPS_rustc_passes := syntax rustc core
DEPS_rustc_passes := syntax rustc core rustc_front
DEPS_rustc_mir := rustc rustc_front syntax
DEPS_rustc_resolve := arena rustc rustc_front log syntax
DEPS_rustc_platform_intrinsics := rustc rustc_llvm
DEPS_rustc_plugin := rustc rustc_metadata syntax
DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
DEPS_rustc_privacy := rustc rustc_front log syntax
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics
@ -120,12 +121,12 @@ TOOL_DEPS_compiletest := test getopts
TOOL_DEPS_rustdoc := rustdoc
TOOL_DEPS_rustc := rustc_driver
TOOL_DEPS_rustbook := std rustdoc
TOOL_DEPS_error-index-generator := rustdoc syntax serialize
TOOL_DEPS_error_index_generator := rustdoc syntax serialize
TOOL_SOURCE_compiletest := $(S)src/compiletest/compiletest.rs
TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs
TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
TOOL_SOURCE_rustbook := $(S)src/rustbook/main.rs
TOOL_SOURCE_error-index-generator := $(S)src/error-index-generator/main.rs
TOOL_SOURCE_error_index_generator := $(S)src/error_index_generator/main.rs
ONLY_RLIB_core := 1
ONLY_RLIB_libc := 1
@ -135,17 +136,15 @@ ONLY_RLIB_collections := 1
ONLY_RLIB_rustc_unicode := 1
ONLY_RLIB_rustc_bitflags := 1
ONLY_RLIB_alloc_system := 1
ONLY_RLIB_alloc_jemalloc := 1
TARGET_SPECIFIC_alloc_jemalloc := 1
# Documented-by-default crates
DOC_CRATES := std alloc collections core libc rustc_unicode
ifeq ($(CFG_DISABLE_JEMALLOC),)
TARGET_CRATES += alloc_jemalloc
DEPS_std += alloc_jemalloc
DEPS_alloc_jemalloc := core libc native:jemalloc
ONLY_RLIB_alloc_jemalloc := 1
else
RUSTFLAGS_rustc_back := --cfg disable_jemalloc
RUSTFLAGS_rustc_back := --cfg 'feature="jemalloc"'
endif
################################################################################
@ -161,12 +160,32 @@ CRATES := $(TARGET_CRATES) $(HOST_CRATES)
define RUST_CRATE
CRATEFILE_$(1) := $$(SREL)src/lib$(1)/lib.rs
RSINPUTS_$(1) := $$(call rwildcard,$(S)src/lib$(1)/,*.rs)
RUST_DEPS_$(1) := $$(filter-out native:%,$$(DEPS_$(1)))
NATIVE_DEPS_$(1) := $$(patsubst native:%,%,$$(filter native:%,$$(DEPS_$(1))))
endef
$(foreach crate,$(CRATES),$(eval $(call RUST_CRATE,$(crate))))
# $(1) - crate
# $(2) - target
define RUST_CRATE_DEPS
RUST_DEPS_$(1)_T_$(2) := $$(filter-out native:%,$$(DEPS_$(1)))
endef
$(foreach target,$(CFG_TARGET),\
$(foreach crate,$(CRATES),$(eval $(call RUST_CRATE_DEPS,$(crate),$(target)))))
# $(1) - target
# $(2) - crate
define DEFINE_TARGET_CRATES
ifndef TARGET_SPECIFIC_$(2)
TARGET_CRATES_$(1) += $(2)
endif
endef
$(foreach target,$(CFG_TARGET),\
$(foreach crate,$(TARGET_CRATES),\
$(eval $(call DEFINE_TARGET_CRATES,$(target),$(crate)))))
# Similar to the macro above for crates, this macro is for tools
#
# $(1) is the crate to generate variables for

View File

@ -48,11 +48,13 @@ PKG_FILES := \
$(S)configure $(S)Makefile.in \
$(S)man \
$(addprefix $(S)src/, \
bootstrap \
build_helper \
compiletest \
doc \
driver \
etc \
error-index-generator \
error_index_generator \
$(foreach crate,$(CRATES),lib$(crate)) \
libcollectionstest \
libcoretest \
@ -60,6 +62,7 @@ PKG_FILES := \
rt \
rtstartup \
rustllvm \
rustc \
snapshots.txt \
rust-installer \
rustbook \

View File

@ -59,9 +59,10 @@ RUSTBOOK_EXE = $(HBIN2_H_$(CFG_BUILD))/rustbook$(X_$(CFG_BUILD))
# ./configure
RUSTBOOK = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(RUSTBOOK_EXE)
# The error-index-generator executable...
ERR_IDX_GEN_EXE = $(HBIN2_H_$(CFG_BUILD))/error-index-generator$(X_$(CFG_BUILD))
# The error_index_generator executable...
ERR_IDX_GEN_EXE = $(HBIN2_H_$(CFG_BUILD))/error_index_generator$(X_$(CFG_BUILD))
ERR_IDX_GEN = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(ERR_IDX_GEN_EXE)
ERR_IDX_GEN_MD = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(ERR_IDX_GEN_EXE) markdown
D := $(S)src/doc
@ -157,9 +158,9 @@ LIB_DOC_DEP_$(1) = \
$$(CRATEFILE_$(1)) \
$$(RSINPUTS_$(1)) \
$$(RUSTDOC_EXE) \
$$(foreach dep,$$(RUST_DEPS_$(1)), \
$$(foreach dep,$$(RUST_DEPS_$(1)_T_$(CFG_BUILD)), \
$$(TLIB2_T_$(CFG_BUILD)_H_$(CFG_BUILD))/stamp.$$(dep)) \
$$(foreach dep,$$(filter $$(DOC_CRATES), $$(RUST_DEPS_$(1))), \
$$(foreach dep,$$(filter $$(DOC_CRATES), $$(RUST_DEPS_$(1)_T_$(CFG_BUILD))), \
doc/$$(dep)/)
else
LIB_DOC_DEP_$(1) = $$(CRATEFILE_$(1)) $$(RSINPUTS_$(1))
@ -217,6 +218,12 @@ doc/style/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/style/*.md) | doc/
error-index: doc/error-index.html
doc/error-index.html: $(ERR_IDX_GEN_EXE) | doc/
$(Q)$(call E, error-index-generator: $@)
# Metadata used to generate the index is created as a side effect of
# the build so this depends on every crate being up to date.
doc/error-index.html: $(ERR_IDX_GEN_EXE) $(CSREQ$(2)_T_$(CFG_BUILD)_H_$(CFG_BUILD)) | doc/
$(Q)$(call E, error_index_generator: $@)
$(Q)$(ERR_IDX_GEN)
doc/error-index.md: $(ERR_IDX_GEN_EXE) $(CSREQ$(2)_T_$(CFG_BUILD)_H_$(CFG_BUILD)) | doc/
$(Q)$(call E, error_index_generator: $@)
$(Q)$(ERR_IDX_GEN_MD)

View File

@ -21,7 +21,7 @@ define CP_HOST_STAGE_N_CRATE
ifeq ($$(ONLY_RLIB_$(5)),)
$$(HLIB$(2)_H_$(4))/stamp.$(5): \
$$(TLIB$(1)_T_$(3)_H_$(4))/stamp.$(5) \
$$(RUST_DEPS_$(5):%=$$(HLIB$(2)_H_$(4))/stamp.%) \
$$(RUST_DEPS_$(5)_T_$(3):%=$$(HLIB$(2)_H_$(4))/stamp.%) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$(@D)/lib$(5))
$$(call REMOVE_ALL_OLD_GLOB_MATCHES, \

View File

@ -108,7 +108,7 @@ endif
define INSTALL_RUNTIME_TARGET_N
install-runtime-target-$(1)-host-$(2): $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(SREQ$$(ISTAGE)_T_$(1)_H_$(2))
$$(Q)$$(call ADB_SHELL,mkdir,$(CFG_RUNTIME_PUSH_DIR))
$$(Q)$$(foreach crate,$$(TARGET_CRATES), \
$$(Q)$$(foreach crate,$$(TARGET_CRATES_$(1)), \
$$(call ADB_PUSH,$$(TL$(1)$(2))/$$(call CFG_LIB_GLOB_$(1),$$(crate)), \
$$(CFG_RUNTIME_PUSH_DIR));)
endef
@ -116,7 +116,7 @@ endef
define INSTALL_RUNTIME_TARGET_CLEANUP_N
install-runtime-target-$(1)-cleanup:
$$(Q)$$(call ADB,remount)
$$(Q)$$(foreach crate,$$(TARGET_CRATES), \
$$(Q)$$(foreach crate,$$(TARGET_CRATES_$(1)), \
$$(call ADB_SHELL,rm,$$(CFG_RUNTIME_PUSH_DIR)/$$(call CFG_LIB_GLOB_$(1),$$(crate)));)
endef

View File

@ -102,7 +102,7 @@ $(foreach host,$(CFG_HOST), \
define LLVM_LINKAGE_DEPS
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.rustc_llvm: $$(LLVM_LINKAGE_PATH_$(2))
RUSTFLAGS$(1)_rustc_llvm_T_$(2) += $$(shell echo $$(LLVM_ALL_COMPONENTS_$(2)) | tr '-' '_' |\
sed -e 's/^ //;s/\([^ ]*\)/\-\-cfg have_component_\1/g')
sed -e 's/^ //;s/\([^ ]*\)/\-\-cfg "llvm_component=\\"\1\\""/g')
endef
$(foreach source,$(CFG_HOST), \

View File

@ -13,12 +13,12 @@
######################################################################
# The version number
CFG_RELEASE_NUM=1.7.0
CFG_RELEASE_NUM=1.8.0
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
# NB Make sure it starts with a dot to conform to semver pre-release
# versions (section 9)
CFG_PRERELEASE_VERSION=.4
CFG_PRERELEASE_VERSION=.2
# Append a version-dependent hash to each library, so we can install different
# versions in the same place
@ -361,6 +361,9 @@ export CFG_DISABLE_UNSTABLE_FEATURES
export RUSTC_BOOTSTRAP_KEY:=$(CFG_BOOTSTRAP_KEY)
endif
export CFG_BOOTSTRAP_KEY
ifdef CFG_MUSL_ROOT
export CFG_MUSL_ROOT
endif
######################################################################
# Per-stage targets and runner
@ -429,7 +432,7 @@ TSREQ$(1)_T_$(2)_H_$(3) = \
# target
SREQ$(1)_T_$(2)_H_$(3) = \
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
$$(foreach dep,$$(TARGET_CRATES), \
$$(foreach dep,$$(TARGET_CRATES_$(2)), \
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
tmp/install-debugger-scripts$(1)_T_$(2)_H_$(3)-$$(call TRIPLE_TO_DEBUGGER_SCRIPT_SETTING,$(2)).done
@ -438,7 +441,7 @@ SREQ$(1)_T_$(2)_H_$(3) = \
CSREQ$(1)_T_$(2)_H_$(3) = \
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
$$(foreach dep,$$(CRATES),$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep))
$$(foreach dep,$$(HOST_CRATES),$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep))
ifeq ($(1),0)
# Don't run the stage0 compiler under valgrind - that ship has sailed
@ -522,14 +525,6 @@ STAGE$(1)_T_$(2)_H_$(3) := \
$$(CFG_RUSTC_FLAGS) $$(EXTRAFLAGS_STAGE$(1)) --target=$(2)) \
$$(RUSTC_FLAGS_$(2))
PERF_STAGE$(1)_T_$(2)_H_$(3) := \
$$(Q)$$(call CFG_RUN_TARG_$(3),$(1), \
$$(CFG_PERF_TOOL) \
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
--cfg $$(CFGFLAG$(1)_T_$(2)_H_$(3)) \
$$(CFG_RUSTC_FLAGS) $$(EXTRAFLAGS_STAGE$(1)) --target=$(2)) \
$$(RUSTC_FLAGS_$(2))
endef
$(foreach build,$(CFG_HOST), \

View File

@ -1,25 +0,0 @@
# Copyright 2012 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
ifdef CFG_PERF_TOOL
rustc-perf$(X): $(CFG_BUILD)/stage2/bin/rustc$(X_$(CFG_BUILD))
@$(call E, perf compile: $@)
$(PERF_STAGE2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) \
-o $@ $(COMPILER_CRATE) >rustc-perf.err 2>&1
$(Q)rm -f $(LIBRUSTC_GLOB)
else
rustc-perf$(X): $(CFG_BUILD)/stage2/bin/rustc$(X_$(CFG_BUILD))
$(Q)touch $@
endif
perf: check-stage2-perf rustc-perf$(X_$(CFG_BUILD))
$(Q)find $(CFG_BUILD)/test/perf -name \*.err | xargs cat
$(Q)cat rustc-perf.err

View File

@ -77,23 +77,6 @@ define DEF_GOOD_VALGRIND
endef
$(foreach t,$(CFG_TARGET),$(eval $(call DEF_GOOD_VALGRIND,$(t))))
ifneq ($(findstring linux,$(CFG_OSTYPE)),)
ifdef CFG_PERF
ifneq ($(CFG_PERF_WITH_LOGFD),)
CFG_PERF_TOOL := $(CFG_PERF) stat -r 3 --log-fd 2
else
CFG_PERF_TOOL := $(CFG_PERF) stat -r 3
endif
else
ifdef CFG_VALGRIND
CFG_PERF_TOOL := \
$(CFG_VALGRIND) --tool=cachegrind --cache-sim=yes --branch-sim=yes
else
CFG_PERF_TOOL := /usr/bin/time --verbose
endif
endif
endif
AR := ar
define SET_FROM_CFG
@ -135,6 +118,18 @@ endef
$(foreach target,$(CFG_TARGET), \
$(eval $(call DEFINE_LINKER,$(target))))
define ADD_JEMALLOC_DEP
ifndef CFG_DISABLE_JEMALLOC_$(1)
ifndef CFG_DISABLE_JEMALLOC
RUST_DEPS_std_T_$(1) += alloc_jemalloc
TARGET_CRATES_$(1) += alloc_jemalloc
endif
endif
endef
$(foreach target,$(CFG_TARGET), \
$(eval $(call ADD_JEMALLOC_DEP,$(target))))
# The -Qunused-arguments sidesteps spurious warnings from clang
define FILTER_FLAGS
ifeq ($$(CFG_USING_CLANG),1)

View File

@ -82,7 +82,7 @@ define PREPARE_MAN
endef
PREPARE_TOOLS = $(filter-out compiletest rustbook error-index-generator, $(TOOLS))
PREPARE_TOOLS = $(filter-out compiletest rustbook error_index_generator, $(TOOLS))
# $(1) is tool
@ -122,7 +122,7 @@ prepare-host-lib-$(1)-$(2)-$(3)-$(4): \
prepare-host-lib-$(1)-$(2)-$(3)-$(4): \
PREPARE_WORKING_DEST_LIB_DIR=$$(PREPARE_DEST_DIR)/$$(call PREPARE_TAR_LIB_DIR,$$(HLIB_RELATIVE$(2)_H_$(3)))
prepare-host-lib-$(1)-$(2)-$(3)-$(4): prepare-maybe-clean-$(4) \
$$(foreach dep,$$(RUST_DEPS_$(1)),prepare-host-lib-$$(dep)-$(2)-$(3)-$(4)) \
$$(foreach dep,$$(RUST_DEPS_$(1)_T_$(3)),prepare-host-lib-$$(dep)-$(2)-$(3)-$(4)) \
$$(HLIB$(2)_H_$(3))/stamp.$(1) \
prepare-host-dirs-$(4)
$$(if $$(findstring $(2), $$(PREPARE_STAGE)), \
@ -147,7 +147,7 @@ prepare-target-$(2)-host-$(3)-$(1)-$(4): \
prepare-target-$(2)-host-$(3)-$(1)-$(4): \
PREPARE_DEST_BIN_DIR=$$(PREPARE_DEST_LIB_DIR)/rustlib/$(3)/bin
prepare-target-$(2)-host-$(3)-$(1)-$(4): prepare-maybe-clean-$(4) \
$$(foreach crate,$$(TARGET_CRATES), \
$$(foreach crate,$$(TARGET_CRATES_$(2)), \
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(crate)) \
$$(if $$(findstring $(2),$$(CFG_HOST)), \
$$(foreach crate,$$(HOST_CRATES), \
@ -161,7 +161,7 @@ prepare-target-$(2)-host-$(3)-$(1)-$(4): prepare-maybe-clean-$(4) \
$$(if $$(findstring $(3), $$(PREPARE_HOST)), \
$$(call PREPARE_DIR,$$(PREPARE_WORKING_DEST_LIB_DIR)) \
$$(call PREPARE_DIR,$$(PREPARE_DEST_BIN_DIR)) \
$$(foreach crate,$$(TARGET_CRATES), \
$$(foreach crate,$$(TARGET_CRATES_$(2)), \
$$(if $$(or $$(findstring 1, $$(ONLY_RLIB_$$(crate))),$$(findstring 1,$$(CFG_INSTALL_ONLY_RLIB_$(2)))),, \
$$(call PREPARE_LIB,$$(call CFG_LIB_GLOB_$(2),$$(crate)))) \
$$(call PREPARE_LIB,$$(call CFG_RLIB_GLOB,$$(crate)))) \

View File

@ -148,7 +148,15 @@ ifeq ($$(CFG_WINDOWSY_$(1)),1)
else ifeq ($(OSTYPE_$(1)), apple-ios)
JEMALLOC_ARGS_$(1) := --disable-tls
else ifeq ($(findstring android, $(OSTYPE_$(1))), android)
JEMALLOC_ARGS_$(1) := --disable-tls
# We force android to have prefixed symbols because apparently replacement of
# the libc allocator doesn't quite work. When this was tested (unprefixed
# symbols), it was found that the `realpath` function in libc would allocate
# with libc malloc (not jemalloc malloc), and then the standard library would
# free with jemalloc free, causing a segfault.
#
# If the test suite passes, however, without symbol prefixes then we should be
# good to go!
JEMALLOC_ARGS_$(1) := --disable-tls --with-jemalloc-prefix=je_
endif
ifdef CFG_ENABLE_DEBUG_JEMALLOC
@ -186,7 +194,7 @@ JEMALLOC_LOCAL_$(1) := $$(JEMALLOC_BUILD_DIR_$(1))/lib/$$(JEMALLOC_REAL_NAME_$(1
$$(JEMALLOC_LOCAL_$(1)): $$(JEMALLOC_DEPS) $$(MKFILE_DEPS)
@$$(call E, make: jemalloc)
cd "$$(JEMALLOC_BUILD_DIR_$(1))"; "$(S)src/jemalloc/configure" \
$$(JEMALLOC_ARGS_$(1)) --with-jemalloc-prefix=je_ $(CFG_JEMALLOC_FLAGS) \
$$(JEMALLOC_ARGS_$(1)) $(CFG_JEMALLOC_FLAGS) \
--build=$$(CFG_GNU_TRIPLE_$(CFG_BUILD)) --host=$$(CFG_GNU_TRIPLE_$(1)) \
CC="$$(CC_$(1)) $$(CFG_JEMALLOC_CFLAGS_$(1))" \
AR="$$(AR_$(1))" \
@ -245,7 +253,7 @@ COMPRT_AR_$(1) := $$(AR_$(1))
# We chomp -Werror here because GCC warns about the type signature of
# builtins not matching its own and the build fails. It's a bit hacky,
# but what can we do, we're building libclang-rt using GCC ......
COMPRT_CFLAGS_$(1) := $$(subst -Werror,,$$(CFG_GCCISH_CFLAGS_$(1))) -std=c99
COMPRT_CFLAGS_$(1) := $$(filter-out -Werror -Werror=*,$$(CFG_GCCISH_CFLAGS_$(1))) -std=c99
# FreeBSD Clang's packaging is problematic; it doesn't copy unwind.h to
# the standard include directory. This should really be in our changes to
@ -254,6 +262,15 @@ ifeq ($$(findstring freebsd,$(1)),freebsd)
COMPRT_CFLAGS_$(1) += -I/usr/include/c++/v1
endif
ifeq ($$(findstring emscripten,$(1)),emscripten)
# FIXME: emscripten doesn't use compiler-rt and can't build it without
# further hacks
$$(COMPRT_LIB_$(1)):
touch $$@
else
$$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS)
@$$(call E, make: compiler-rt)
$$(Q)$$(MAKE) -C "$(S)src/compiler-rt" \
@ -266,7 +283,10 @@ $$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS)
TargetTriple=$(1) \
triple-builtins
$$(Q)cp $$(COMPRT_BUILD_DIR_$(1))/triple/builtins/libcompiler_rt.a $$@
endif # if emscripten
endif
################################################################################
# libbacktrace
#
@ -301,6 +321,12 @@ $$(BACKTRACE_LIB_$(1)):
touch $$@
else
ifeq ($$(findstring emscripten,$(1)),emscripten)
# FIXME: libbacktrace doesn't understand the emscripten triple
$$(BACKTRACE_LIB_$(1)):
touch $$@
else
ifdef CFG_ENABLE_FAST_MAKE
BACKTRACE_DEPS := $(S)/.gitmodules
else
@ -348,6 +374,7 @@ $$(BACKTRACE_LIB_$(1)): $$(BACKTRACE_BUILD_DIR_$(1))/Makefile $$(MKFILE_DEPS)
INCDIR=$(S)src/libbacktrace
$$(Q)cp $$(BACKTRACE_BUILD_DIR_$(1))/.libs/libbacktrace.a $$@
endif # endif for emscripten
endif # endif for msvc
endif # endif for ios
endif # endif for darwin

View File

@ -17,14 +17,6 @@ export CFG_COMPILER_HOST_TRIPLE
export CFG_DEFAULT_LINKER
export CFG_DEFAULT_AR
# The standard libraries should be held up to a higher standard than any old
# code, make sure that these common warnings are denied by default. These can
# be overridden during development temporarily. For stage0, we allow warnings
# which may be bugs in stage0 (should be fixed in stage1+)
RUST_LIB_FLAGS_ST0 += -W warnings
RUST_LIB_FLAGS_ST1 += -D warnings
RUST_LIB_FLAGS_ST2 += -D warnings
# Macro that generates the full list of dependencies for a crate at a particular
# stage/target/host tuple.
#
@ -36,7 +28,7 @@ define RUST_CRATE_FULLDEPS
CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4) := \
$$(CRATEFILE_$(4)) \
$$(RSINPUTS_$(4)) \
$$(foreach dep,$$(RUST_DEPS_$(4)), \
$$(foreach dep,$$(RUST_DEPS_$(4)_T_$(2)), \
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
$$(foreach dep,$$(NATIVE_DEPS_$(4)), \
$$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),$$(dep))) \
@ -155,7 +147,7 @@ ifeq ($$(CFG_RUSTRT_HAS_STARTUP_OBJS_$(2)), 1)
# Add dependencies on Rust startup objects to all crates that depend on core.
# This ensures that they are built after core (since they depend on it),
# but before everything else (since they are needed for linking dylib crates).
$$(foreach crate, $$(TARGET_CRATES), \
$$(foreach crate, $$(TARGET_CRATES_$(2)), \
$$(if $$(findstring core,$$(DEPS_$$(crate))), \
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(crate))) : $$(TLIB$(1)_T_$(2)_H_$(3))/$(4).o
endif

View File

@ -45,16 +45,11 @@ ifdef CHECK_IGNORED
TESTARGS += --ignored
endif
# Arguments to the cfail/rfail/rpass/bench tests
# Arguments to the cfail/rfail/rpass tests
ifdef CFG_VALGRIND
CTEST_RUNTOOL = --runtool "$(CFG_VALGRIND)"
endif
# Arguments to the perf tests
ifdef CFG_PERF_TOOL
CTEST_PERF_RUNTOOL = --runtool "$(CFG_PERF_TOOL)"
endif
CTEST_TESTARGS := $(TESTARGS)
# --bench is only relevant for crate tests, not for the compile tests
@ -70,12 +65,6 @@ endif
# This prevents tests from failing with some locales (fixes #17423).
export LC_ALL=C
# If we're running perf then set this environment variable
# to put the benchmarks into 'hard mode'
ifeq ($(MAKECMDGOALS),perf)
export RUST_BENCH=1
endif
TEST_LOG_FILE=tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).log
TEST_OK_FILE=tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).ok
@ -146,7 +135,7 @@ $(info check: android device test dir $(CFG_ADB_TEST_DIR) ready \
$(foreach target,$(CFG_TARGET), \
$(if $(findstring android, $(target)), \
$(shell $(CFG_ADB) shell mkdir $(CFG_ADB_TEST_DIR)/$(target)) \
$(foreach crate,$(TARGET_CRATES), \
$(foreach crate,$(TARGET_CRATES_$(target)), \
$(shell $(CFG_ADB) push $(TLIB2_T_$(target)_H_$(CFG_BUILD))/$(call CFG_LIB_GLOB_$(target),$(crate)) \
$(CFG_ADB_TEST_DIR)/$(target))), \
)))
@ -309,18 +298,18 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
check-stage$(1)-T-$(2)-H-$(3)-rfail-exec \
check-stage$(1)-T-$(2)-H-$(3)-cfail-exec \
check-stage$(1)-T-$(2)-H-$(3)-pfail-exec \
check-stage$(1)-T-$(2)-H-$(3)-rpass-valgrind-exec \
check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \
check-stage$(1)-T-$(2)-H-$(3)-rfail-full-exec \
check-stage$(1)-T-$(2)-H-$(3)-rpass-valgrind-exec \
check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \
check-stage$(1)-T-$(2)-H-$(3)-rfail-full-exec \
check-stage$(1)-T-$(2)-H-$(3)-cfail-full-exec \
check-stage$(1)-T-$(2)-H-$(3)-rmake-exec \
check-stage$(1)-T-$(2)-H-$(3)-rustdocck-exec \
check-stage$(1)-T-$(2)-H-$(3)-crates-exec \
check-stage$(1)-T-$(2)-H-$(3)-doc-crates-exec \
check-stage$(1)-T-$(2)-H-$(3)-bench-exec \
check-stage$(1)-T-$(2)-H-$(3)-crates-exec \
check-stage$(1)-T-$(2)-H-$(3)-doc-crates-exec \
check-stage$(1)-T-$(2)-H-$(3)-debuginfo-gdb-exec \
check-stage$(1)-T-$(2)-H-$(3)-debuginfo-lldb-exec \
check-stage$(1)-T-$(2)-H-$(3)-codegen-exec \
check-stage$(1)-T-$(2)-H-$(3)-codegen-units-exec \
check-stage$(1)-T-$(2)-H-$(3)-doc-exec \
check-stage$(1)-T-$(2)-H-$(3)-pretty-exec
@ -354,7 +343,6 @@ check-stage$(1)-T-$(2)-H-$(3)-pretty-exec: \
check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-full-exec \
check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-exec \
check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-full-exec \
check-stage$(1)-T-$(2)-H-$(3)-pretty-bench-exec \
check-stage$(1)-T-$(2)-H-$(3)-pretty-pretty-exec
endef
@ -376,7 +364,7 @@ define TEST_RUNNER
# parent crates.
ifeq ($(NO_REBUILD),)
TESTDEP_$(1)_$(2)_$(3)_$(4) = $$(SREQ$(1)_T_$(2)_H_$(3)) \
$$(foreach crate,$$(TARGET_CRATES), \
$$(foreach crate,$$(TARGET_CRATES_$(2)), \
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(crate)) \
$$(CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4))
@ -470,25 +458,22 @@ $(foreach host,$(CFG_HOST), \
# Rules for the compiletest tests (rpass, rfail, etc.)
######################################################################
RPASS_RS := $(wildcard $(S)src/test/run-pass/*.rs)
RPASS_VALGRIND_RS := $(wildcard $(S)src/test/run-pass-valgrind/*.rs)
RPASS_FULL_RS := $(wildcard $(S)src/test/run-pass-fulldeps/*.rs)
RFAIL_FULL_RS := $(wildcard $(S)src/test/run-fail-fulldeps/*.rs)
CFAIL_FULL_RS := $(wildcard $(S)src/test/compile-fail-fulldeps/*.rs)
RFAIL_RS := $(wildcard $(S)src/test/run-fail/*.rs)
CFAIL_RS := $(wildcard $(S)src/test/compile-fail/*.rs)
PFAIL_RS := $(wildcard $(S)src/test/parse-fail/*.rs)
BENCH_RS := $(wildcard $(S)src/test/bench/*.rs)
PRETTY_RS := $(wildcard $(S)src/test/pretty/*.rs)
DEBUGINFO_GDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
DEBUGINFO_LLDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
CODEGEN_RS := $(wildcard $(S)src/test/codegen/*.rs)
CODEGEN_CC := $(wildcard $(S)src/test/codegen/*.cc)
RUSTDOCCK_RS := $(wildcard $(S)src/test/rustdoc/*.rs)
# perf tests are the same as bench tests only they run under
# a performance monitor.
PERF_RS := $(wildcard $(S)src/test/bench/*.rs)
RPASS_RS := $(call rwildcard,$(S)src/test/run-pass/,*.rs)
RPASS_VALGRIND_RS := $(call rwildcard,$(S)src/test/run-pass-valgrind/,*.rs)
RPASS_FULL_RS := $(call rwildcard,$(S)src/test/run-pass-fulldeps/,*.rs)
RFAIL_FULL_RS := $(call rwildcard,$(S)src/test/run-fail-fulldeps/,*.rs)
CFAIL_FULL_RS := $(call rwildcard,$(S)src/test/compile-fail-fulldeps/,*.rs)
RFAIL_RS := $(call rwildcard,$(S)src/test/run-fail/,*.rs)
RFAIL_RS := $(call rwildcard,$(S)src/test/run-fail/,*.rs)
CFAIL_RS := $(call rwildcard,$(S)src/test/compile-fail/,*.rs)
PFAIL_RS := $(call rwildcard,$(S)src/test/parse-fail/,*.rs)
PRETTY_RS := $(call rwildcard,$(S)src/test/pretty/,*.rs)
DEBUGINFO_GDB_RS := $(call rwildcard,$(S)src/test/debuginfo/,*.rs)
DEBUGINFO_LLDB_RS := $(call rwildcard,$(S)src/test/debuginfo/,*.rs)
CODEGEN_RS := $(call rwildcard,$(S)src/test/codegen/,*.rs)
CODEGEN_CC := $(call rwildcard,$(S)src/test/codegen/,*.cc)
CODEGEN_UNITS_RS := $(call rwildcard,$(S)src/test/codegen-units/,*.rs)
RUSTDOCCK_RS := $(call rwildcard,$(S)src/test/rustdoc/,*.rs)
RPASS_TESTS := $(RPASS_RS)
RPASS_VALGRIND_TESTS := $(RPASS_VALGRIND_RS)
@ -498,12 +483,11 @@ CFAIL_FULL_TESTS := $(CFAIL_FULL_RS)
RFAIL_TESTS := $(RFAIL_RS)
CFAIL_TESTS := $(CFAIL_RS)
PFAIL_TESTS := $(PFAIL_RS)
BENCH_TESTS := $(BENCH_RS)
PERF_TESTS := $(PERF_RS)
PRETTY_TESTS := $(PRETTY_RS)
DEBUGINFO_GDB_TESTS := $(DEBUGINFO_GDB_RS)
DEBUGINFO_LLDB_TESTS := $(DEBUGINFO_LLDB_RS)
CODEGEN_TESTS := $(CODEGEN_RS) $(CODEGEN_CC)
CODEGEN_UNITS_TESTS := $(CODEGEN_UNITS_RS)
RUSTDOCCK_TESTS := $(RUSTDOCCK_RS)
CTEST_SRC_BASE_rpass = run-pass
@ -546,16 +530,6 @@ CTEST_BUILD_BASE_pfail = parse-fail
CTEST_MODE_pfail = parse-fail
CTEST_RUNTOOL_pfail = $(CTEST_RUNTOOL)
CTEST_SRC_BASE_bench = bench
CTEST_BUILD_BASE_bench = bench
CTEST_MODE_bench = run-pass
CTEST_RUNTOOL_bench = $(CTEST_RUNTOOL)
CTEST_SRC_BASE_perf = bench
CTEST_BUILD_BASE_perf = perf
CTEST_MODE_perf = run-pass
CTEST_RUNTOOL_perf = $(CTEST_PERF_RUNTOOL)
CTEST_SRC_BASE_debuginfo-gdb = debuginfo
CTEST_BUILD_BASE_debuginfo-gdb = debuginfo-gdb
CTEST_MODE_debuginfo-gdb = debuginfo-gdb
@ -571,6 +545,11 @@ CTEST_BUILD_BASE_codegen = codegen
CTEST_MODE_codegen = codegen
CTEST_RUNTOOL_codegen = $(CTEST_RUNTOOL)
CTEST_SRC_BASE_codegen-units = codegen-units
CTEST_BUILD_BASE_codegen-units = codegen-units
CTEST_MODE_codegen-units = codegen-units
CTEST_RUNTOOL_codegen-units = $(CTEST_RUNTOOL)
CTEST_SRC_BASE_rustdocck = rustdoc
CTEST_BUILD_BASE_rustdocck = rustdoc
CTEST_MODE_rustdocck = rustdoc
@ -625,7 +604,7 @@ TEST_SREQ$(1)_T_$(2)_H_$(3) = \
$$(HBIN$(1)_H_$(3))/compiletest$$(X_$(3)) \
$$(SREQ$(1)_T_$(2)_H_$(3))
# Rules for the cfail/rfail/rpass/bench/perf test runner
# Rules for the cfail/rfail/rpass test runner
# The tests select when to use debug configuration on their own;
# remove directive, if present, from CFG_RUSTC_FLAGS (issue #7898).
@ -688,16 +667,15 @@ CTEST_DEPS_cfail-full_$(1)-T-$(2)-H-$(3) = $$(CFAIL_FULL_TESTS) $$(CSREQ$(1)_T_$
CTEST_DEPS_rfail_$(1)-T-$(2)-H-$(3) = $$(RFAIL_TESTS)
CTEST_DEPS_cfail_$(1)-T-$(2)-H-$(3) = $$(CFAIL_TESTS)
CTEST_DEPS_pfail_$(1)-T-$(2)-H-$(3) = $$(PFAIL_TESTS)
CTEST_DEPS_bench_$(1)-T-$(2)-H-$(3) = $$(BENCH_TESTS)
CTEST_DEPS_perf_$(1)-T-$(2)-H-$(3) = $$(PERF_TESTS)
CTEST_DEPS_debuginfo-gdb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_GDB_TESTS)
CTEST_DEPS_debuginfo-lldb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_LLDB_TESTS) \
$(S)src/etc/lldb_batchmode.py \
$(S)src/etc/lldb_rust_formatters.py
CTEST_DEPS_codegen_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_TESTS)
CTEST_DEPS_codegen-units_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_UNITS_TESTS)
CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
$(S)src/etc/htmldocck.py
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
$(S)src/etc/htmldocck.py
endef
@ -761,7 +739,7 @@ endif
endef
CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \
bench perf debuginfo-gdb debuginfo-lldb codegen rustdocck
debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck
$(foreach host,$(CFG_HOST), \
$(eval $(foreach target,$(CFG_TARGET), \
@ -770,20 +748,18 @@ $(foreach host,$(CFG_HOST), \
$(eval $(call DEF_RUN_COMPILETEST,$(stage),$(target),$(host),$(name))))))))))
PRETTY_NAMES = pretty-rpass pretty-rpass-valgrind pretty-rpass-full pretty-rfail-full pretty-rfail \
pretty-bench pretty-pretty
pretty-pretty
PRETTY_DEPS_pretty-rpass = $(RPASS_TESTS)
PRETTY_DEPS_pretty-rpass-valgrind = $(RPASS_VALGRIND_TESTS)
PRETTY_DEPS_pretty-rpass-full = $(RPASS_FULL_TESTS)
PRETTY_DEPS_pretty-rfail-full = $(RFAIL_FULL_TESTS)
PRETTY_DEPS_pretty-rfail = $(RFAIL_TESTS)
PRETTY_DEPS_pretty-bench = $(BENCH_TESTS)
PRETTY_DEPS_pretty-pretty = $(PRETTY_TESTS)
PRETTY_DIRNAME_pretty-rpass = run-pass
PRETTY_DIRNAME_pretty-rpass-valgrind = run-pass-valgrind
PRETTY_DIRNAME_pretty-rpass-full = run-pass-fulldeps
PRETTY_DIRNAME_pretty-rfail-full = run-fail-fulldeps
PRETTY_DIRNAME_pretty-rfail = run-fail
PRETTY_DIRNAME_pretty-bench = bench
PRETTY_DIRNAME_pretty-pretty = pretty
define DEF_PRETTY_FULLDEPS
@ -917,6 +893,28 @@ $(foreach host,$(CFG_HOST), \
$(foreach crate,$(TEST_DOC_CRATES), \
$(eval $(call DEF_CRATE_DOC_TEST,$(stage),$(target),$(host),$(crate)))))))
define DEF_DOC_TEST_ERROR_INDEX
check-stage$(1)-T-$(2)-H-$(3)-doc-error-index-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),doc-error-index)
ifeq ($(2),$$(CFG_BUILD))
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-error-index): \
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
doc/error-index.md
$$(Q)touch $$@.start_time
$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --test doc/error-index.md
$$(Q)touch -r $$@.start_time $$@ && rm $$@.start_time
else
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-error-index):
$$(Q)touch $$@
endif
endef
$(foreach host,$(CFG_HOST), \
$(foreach target,$(CFG_TARGET), \
$(foreach stage,$(STAGES), \
$(eval $(call DEF_DOC_TEST_ERROR_INDEX,$(stage),$(target),$(host))))))
######################################################################
# Shortcut rules
######################################################################
@ -926,29 +924,27 @@ TEST_GROUPS = \
$(foreach crate,$(TEST_CRATES),$(crate)) \
$(foreach crate,$(TEST_DOC_CRATES),doc-crate-$(crate)) \
rpass \
rpass-valgrind \
rpass-valgrind \
rpass-full \
rfail-full \
cfail-full \
rfail \
cfail \
pfail \
bench \
perf \
rmake \
rustdocck \
debuginfo-gdb \
debuginfo-lldb \
codegen \
codegen-units \
doc \
$(foreach docname,$(DOC_NAMES),doc-$(docname)) \
pretty \
pretty-rpass \
pretty-rpass-valgrind \
pretty-rpass-valgrind \
pretty-rpass-full \
pretty-rfail-full \
pretty-rfail \
pretty-bench \
pretty-pretty \
$(NULL)
@ -1014,7 +1010,8 @@ define DEF_CHECK_DOC_FOR_STAGE
check-stage$(1)-docs: $$(foreach docname,$$(DOC_NAMES), \
check-stage$(1)-T-$$(CFG_BUILD)-H-$$(CFG_BUILD)-doc-$$(docname)) \
$$(foreach crate,$$(TEST_DOC_CRATES), \
check-stage$(1)-T-$$(CFG_BUILD)-H-$$(CFG_BUILD)-doc-crate-$$(crate))
check-stage$(1)-T-$$(CFG_BUILD)-H-$$(CFG_BUILD)-doc-crate-$$(crate)) \
check-stage$(1)-T-$$(CFG_BUILD)-H-$$(CFG_BUILD)-doc-error-index-exec
endef
$(foreach stage,$(STAGES), \
@ -1052,6 +1049,8 @@ $(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(3)))
$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(3)))
$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
export MSVC_LIB := "$$(CFG_MSVC_LIB_$$(HOST_$(3)))"
$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
$(S)src/test/run-make/%/Makefile \
$$(CSREQ$(1)_T_$(2)_H_$(3))
@ -1073,7 +1072,9 @@ $(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
$$(S) \
$(3) \
"$$(LLVM_LIBDIR_RUSTFLAGS_$(3))" \
"$$(LLVM_ALL_COMPONENTS_$(3))"
"$$(LLVM_ALL_COMPONENTS_$(3))" \
"$$(LLVM_CXXFLAGS_$(3))" \
'$$(CXX_$(3))'
@touch -r $$@.start_time $$@ && rm $$@.start_time
else
# FIXME #11094 - The above rule doesn't work right for multiple targets

92
src/bootstrap/Cargo.lock generated Normal file
View File

@ -0,0 +1,92 @@
[root]
name = "bootstrap"
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
"cmake 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "build_helper"
version = "0.1.0"
[[package]]
name = "cmake"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "filetime"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gcc"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "getopts"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "kernel32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num_cpus"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-serialize"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "toml"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

29
src/bootstrap/Cargo.toml Normal file
View File

@ -0,0 +1,29 @@
[package]
authors = ["The Rust Project Developers"]
name = "bootstrap"
version = "0.0.0"
[lib]
name = "bootstrap"
path = "lib.rs"
[[bin]]
name = "bootstrap"
path = "main.rs"
[[bin]]
name = "rustc"
path = "rustc.rs"
[dependencies]
build_helper = { path = "../build_helper" }
cmake = "0.1.10"
filetime = "0.1"
num_cpus = "0.2"
toml = "0.1"
getopts = "0.2"
rustc-serialize = "0.3"
winapi = "0.2"
kernel32-sys = "0.2"
gcc = "0.3.17"
libc = "0.2"

110
src/bootstrap/README.md Normal file
View File

@ -0,0 +1,110 @@
# Bootstrapping Rust
This is an in-progress README which is targeted at helping to explain how Rust
is bootstrapped and in general some of the technical details of the build
system.
> **Note**: This build system is currently under active development and is not
> intended to be the primarily used one just yet. The makefiles are currently
> the ones that are still "guaranteed to work" as much as possible at least.
## Using the new build system
When configuring Rust via `./configure`, pass the following to enable building
via this build system:
```
./configure --enable-rustbuild
```
## ...
## Directory Layout
This build system houses all output under the `target` directory, which looks
like this:
```
# Root folder of all output. Everything is scoped underneath here
build/
# Location where the stage0 compiler downloads are all cached. This directory
# only contains the tarballs themselves as they're extracted elsewhere.
cache/
2015-12-19/
2016-01-15/
2016-01-21/
...
# Output directory for building this build system itself. The stage0
# cargo/rustc are used to build the build system into this location.
bootstrap/
debug/
release/
# Each remaining directory is scoped by the "host" triple of compilation at
# hand.
x86_64-unknown-linux-gnu/
# The build artifacts for the `compiler-rt` library for the target this
# folder is under. The exact layout here will likely depend on the platform,
# and this is also built with CMake so the build system is also likely
# different.
compiler-rt/build/
# Output folder for LLVM if it is compiled for this target
llvm/
# build folder (e.g. the platform-specific build system). Like with
# compiler-rt this is compiled with CMake
build/
# Installation of LLVM. Note that we run the equivalent of 'make install'
# for LLVM to setup these folders.
bin/
lib/
include/
share/
...
# Location where the stage0 Cargo and Rust compiler are unpacked. This
# directory is purely an extracted and overlaid tarball of these two (done
# by the bootstrapy python script). In theory the build system does not
# modify anything under this directory afterwards.
stage0/
# These to build directories are the cargo output directories for builds of
# the standard library and compiler, respectively. Internally these may also
# have other target directories, which represent artifacts being compiled
# from the host to the specified target.
#
# Essentially, each of these directories is filled in by one `cargo`
# invocation. The build system instruments calling Cargo in the right order
# with the right variables to ensure these are filled in correctly.
stageN-std/
stageN-rustc/
# This is a special case of the above directories, **not** filled in via
# Cargo but rather the build system itself. The stage0 compiler already has
# a set of target libraries for its own host triple (in its own sysroot)
# inside of stage0/. When we run the stage0 compiler to bootstrap more
# things, however, we don't want to use any of these libraries (as those are
# the ones that we're building). So essentially, when the stage1 compiler is
# being compiled (e.g. after libstd has been built), *this* is used as the
# sysroot for the stage0 compiler being run.
#
# Basically this directory is just a temporary artifact use to configure the
# stage0 compiler to ensure that the libstd we just built is used to
# compile the stage1 compiler.
stage0-rustc/lib/
# These output directories are intended to be standalone working
# implementations of the compiler (corresponding to each stage). The build
# system will link (using hard links) output from stageN-{std,rustc} into
# each of these directories.
#
# In theory there is no extra build output in these directories.
stage1/
stage2/
stage3/
```

317
src/bootstrap/bootstrap.py Normal file
View File

@ -0,0 +1,317 @@
# Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
import argparse
import contextlib
import os
import shutil
import subprocess
import sys
import tarfile
def get(url, path, verbose=False):
print("downloading " + url)
# see http://serverfault.com/questions/301128/how-to-download
if sys.platform == 'win32':
run(["PowerShell.exe", "/nologo", "-Command",
"(New-Object System.Net.WebClient).DownloadFile('" + url +
"', '" + path + "')"], verbose=verbose)
else:
run(["curl", "-o", path, url], verbose=verbose)
def unpack(tarball, dst, verbose=False, match=None):
print("extracting " + tarball)
fname = os.path.basename(tarball).replace(".tar.gz", "")
with contextlib.closing(tarfile.open(tarball)) as tar:
for p in tar.getnames():
if "/" not in p:
continue
name = p.replace(fname + "/", "", 1)
if match is not None and not name.startswith(match):
continue
name = name[len(match) + 1:]
fp = os.path.join(dst, name)
if verbose:
print(" extracting " + p)
tar.extract(p, dst)
tp = os.path.join(dst, p)
if os.path.isdir(tp) and os.path.exists(fp):
continue
shutil.move(tp, fp)
shutil.rmtree(os.path.join(dst, fname))
def run(args, verbose=False):
if verbose:
print("running: " + ' '.join(args))
sys.stdout.flush()
# Use Popen here instead of call() as it apparently allows powershell on
# Windows to not lock up waiting for input presumably.
ret = subprocess.Popen(args)
code = ret.wait()
if code != 0:
if not verbose:
print("failed to run: " + ' '.join(args))
raise RuntimeError("failed to run command")
class RustBuild:
def download_rust_nightly(self):
cache_dst = os.path.join(self.build_dir, "cache")
rustc_cache = os.path.join(cache_dst, self.snap_rustc_date())
cargo_cache = os.path.join(cache_dst, self.snap_cargo_date())
if not os.path.exists(rustc_cache):
os.makedirs(rustc_cache)
if not os.path.exists(cargo_cache):
os.makedirs(cargo_cache)
if self.rustc().startswith(self.bin_root()) and \
(not os.path.exists(self.rustc()) or self.rustc_out_of_date()):
shutil.rmtree(self.bin_root())
filename = "rust-std-nightly-" + self.build + ".tar.gz"
url = "https://static.rust-lang.org/dist/" + self.snap_rustc_date()
tarball = os.path.join(rustc_cache, filename)
if not os.path.exists(tarball):
get(url + "/" + filename, tarball, verbose=self.verbose)
unpack(tarball, self.bin_root(),
match="rust-std-" + self.build,
verbose=self.verbose)
filename = "rustc-nightly-" + self.build + ".tar.gz"
url = "https://static.rust-lang.org/dist/" + self.snap_rustc_date()
tarball = os.path.join(rustc_cache, filename)
if not os.path.exists(tarball):
get(url + "/" + filename, tarball, verbose=self.verbose)
unpack(tarball, self.bin_root(), match="rustc", verbose=self.verbose)
with open(self.rustc_stamp(), 'w') as f:
f.write(self.snap_rustc_date())
if self.cargo().startswith(self.bin_root()) and \
(not os.path.exists(self.cargo()) or self.cargo_out_of_date()):
filename = "cargo-nightly-" + self.build + ".tar.gz"
url = "https://static.rust-lang.org/cargo-dist/" + self.snap_cargo_date()
tarball = os.path.join(cargo_cache, filename)
if not os.path.exists(tarball):
get(url + "/" + filename, tarball, verbose=self.verbose)
unpack(tarball, self.bin_root(), match="cargo", verbose=self.verbose)
with open(self.cargo_stamp(), 'w') as f:
f.write(self.snap_cargo_date())
def snap_cargo_date(self):
return self._cargo_date
def snap_rustc_date(self):
return self._rustc_date
def rustc_stamp(self):
return os.path.join(self.bin_root(), '.rustc-stamp')
def cargo_stamp(self):
return os.path.join(self.bin_root(), '.cargo-stamp')
def rustc_out_of_date(self):
if not os.path.exists(self.rustc_stamp()):
return True
with open(self.rustc_stamp(), 'r') as f:
return self.snap_rustc_date() != f.read()
def cargo_out_of_date(self):
if not os.path.exists(self.cargo_stamp()):
return True
with open(self.cargo_stamp(), 'r') as f:
return self.snap_cargo_date() != f.read()
def bin_root(self):
return os.path.join(self.build_dir, self.build, "stage0")
def get_toml(self, key):
for line in self.config_toml.splitlines():
if line.startswith(key + ' ='):
return self.get_string(line)
return None
def get_mk(self, key):
for line in iter(self.config_mk.splitlines()):
if line.startswith(key):
return line[line.find(':=') + 2:].strip()
return None
def cargo(self):
config = self.get_toml('cargo')
if config:
return config
return os.path.join(self.bin_root(), "bin/cargo" + self.exe_suffix())
def rustc(self):
config = self.get_toml('rustc')
if config:
return config
config = self.get_mk('CFG_LOCAL_RUST')
if config:
return config + '/bin/rustc' + self.exe_suffix()
return os.path.join(self.bin_root(), "bin/rustc" + self.exe_suffix())
def get_string(self, line):
start = line.find('"')
end = start + 1 + line[start+1:].find('"')
return line[start+1:end]
def exe_suffix(self):
if sys.platform == 'win32':
return '.exe'
else:
return ''
def parse_nightly_dates(self):
nightlies = os.path.join(self.rust_root, "src/nightlies.txt")
with open(nightlies, 'r') as nightlies:
rustc, cargo = nightlies.read().split("\n")[:2]
assert rustc.startswith("rustc: ")
assert cargo.startswith("cargo: ")
self._rustc_date = rustc[len("rustc: "):]
self._cargo_date = cargo[len("cargo: "):]
def build_bootstrap(self):
env = os.environ.copy()
env["CARGO_TARGET_DIR"] = os.path.join(self.build_dir, "bootstrap")
env["RUSTC"] = self.rustc()
env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib")
env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib")
env["PATH"] = os.path.join(self.bin_root(), "bin") + \
os.pathsep + env["PATH"]
self.run([self.cargo(), "build", "--manifest-path",
os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")],
env)
def run(self, args, env):
proc = subprocess.Popen(args, env = env)
ret = proc.wait()
if ret != 0:
sys.exit(ret)
def build_triple(self):
config = self.get_toml('build')
if config:
return config
config = self.get_mk('CFG_BUILD')
if config:
return config
try:
ostype = subprocess.check_output(['uname', '-s']).strip()
cputype = subprocess.check_output(['uname', '-m']).strip()
except FileNotFoundError:
if sys.platform == 'win32':
return 'x86_64-pc-windows-msvc'
else:
raise
# Darwin's `uname -s` lies and always returns i386. We have to use
# sysctl instead.
if ostype == 'Darwin' and cputype == 'i686':
sysctl = subprocess.check_output(['sysctl', 'hw.optional.x86_64'])
if sysctl.contains(': 1'):
cputype = 'x86_64'
# The goal here is to come up with the same triple as LLVM would,
# at least for the subset of platforms we're willing to target.
if ostype == 'Linux':
ostype = 'unknown-linux-gnu'
elif ostype == 'FreeBSD':
ostype = 'unknown-freebsd'
elif ostype == 'DragonFly':
ostype = 'unknown-dragonfly'
elif ostype == 'Bitrig':
ostype = 'unknown-bitrig'
elif ostype == 'OpenBSD':
ostype = 'unknown-openbsd'
elif ostype == 'NetBSD':
ostype = 'unknown-netbsd'
elif ostype == 'Darwin':
ostype = 'apple-darwin'
elif ostype.startswith('MINGW'):
# msys' `uname` does not print gcc configuration, but prints msys
# configuration. so we cannot believe `uname -m`:
# msys1 is always i686 and msys2 is always x86_64.
# instead, msys defines $MSYSTEM which is MINGW32 on i686 and
# MINGW64 on x86_64.
ostype = 'pc-windows-gnu'
cputype = 'i686'
if os.environ.get('MSYSTEM') == 'MINGW64':
cputype = 'x86_64'
elif ostype.startswith('MSYS'):
ostype = 'pc-windows-gnu'
elif ostype.startswith('CYGWIN_NT'):
cputype = 'i686'
if ostype.endswith('WOW64'):
cputype = 'x86_64'
ostype = 'pc-windows-gnu'
else:
raise ValueError("unknown OS type: " + ostype)
if cputype in {'i386', 'i486', 'i686', 'i786', 'x86'}:
cputype = 'i686'
elif cputype in {'xscale', 'arm'}:
cputype = 'arm'
elif cputype == 'armv7l':
cputype = 'arm'
ostype += 'eabihf'
elif cputype == 'aarch64':
cputype = 'aarch64'
elif cputype in {'powerpc', 'ppc', 'ppc64'}:
cputype = 'powerpc'
elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}:
cputype = 'x86_64'
else:
raise ValueError("unknown cpu type: " + cputype)
return cputype + '-' + ostype
parser = argparse.ArgumentParser(description='Build rust')
parser.add_argument('--config')
parser.add_argument('-v', '--verbose', action='store_true')
args = [a for a in sys.argv if a != '-h']
args, _ = parser.parse_known_args(args)
# Configure initial bootstrap
rb = RustBuild()
rb.config_toml = ''
rb.config_mk = ''
rb.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
rb.build_dir = os.path.join(os.getcwd(), "build")
rb.verbose = args.verbose
try:
with open(args.config or 'config.toml') as config:
rb.config_toml = config.read()
except:
pass
try:
rb.config_mk = open('config.mk').read()
except:
pass
# Fetch/build the bootstrap
rb.build = rb.build_triple()
rb.parse_nightly_dates()
rb.download_rust_nightly()
sys.stdout.flush()
rb.build_bootstrap()
sys.stdout.flush()
# Run the bootstrap
args = [os.path.join(rb.build_dir, "bootstrap/debug/bootstrap")]
args.extend(sys.argv[1:])
args.append('--src')
args.append(rb.rust_root)
args.append('--build')
args.append(rb.build)
env = os.environ.copy()
env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
rb.run(args, env)

98
src/bootstrap/build/cc.rs Normal file
View File

@ -0,0 +1,98 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::process::Command;
use build_helper::{cc2ar, output};
use gcc;
use build::Build;
use build::config::Target;
pub fn find(build: &mut Build) {
// For all targets we're going to need a C compiler for building some shims
// and such as well as for being a linker for Rust code.
for target in build.config.target.iter() {
let mut cfg = gcc::Config::new();
cfg.cargo_metadata(false).opt_level(0).debug(false)
.target(target).host(&build.config.build);
let config = build.config.target_config.get(target);
if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
cfg.compiler(cc);
} else {
set_compiler(&mut cfg, "gcc", target, config);
}
let compiler = cfg.get_compiler();
let ar = cc2ar(compiler.path(), target);
build.verbose(&format!("CC_{} = {:?}", target, compiler.path()));
build.verbose(&format!("AR_{} = {:?}", target, ar));
build.cc.insert(target.to_string(), (compiler, ar));
}
// For all host triples we need to find a C++ compiler as well
for host in build.config.host.iter() {
let mut cfg = gcc::Config::new();
cfg.cargo_metadata(false).opt_level(0).debug(false).cpp(true)
.target(host).host(&build.config.build);
let config = build.config.target_config.get(host);
if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
cfg.compiler(cxx);
} else {
set_compiler(&mut cfg, "g++", host, config);
}
let compiler = cfg.get_compiler();
build.verbose(&format!("CXX_{} = {:?}", host, compiler.path()));
build.cxx.insert(host.to_string(), compiler);
}
}
fn set_compiler(cfg: &mut gcc::Config,
gnu_compiler: &str,
target: &str,
config: Option<&Target>) {
match target {
// When compiling for android we may have the NDK configured in the
// config.toml in which case we look there. Otherwise the default
// compiler already takes into account the triple in question.
t if t.contains("android") => {
if let Some(ndk) = config.and_then(|c| c.ndk.as_ref()) {
let compiler = format!("{}-{}", target, gnu_compiler);
cfg.compiler(ndk.join("bin").join(compiler));
}
}
// The default gcc version from OpenBSD may be too old, try using egcc,
// which is a gcc version from ports, if this is the case.
t if t.contains("openbsd") => {
let c = cfg.get_compiler();
if !c.path().ends_with(gnu_compiler) {
return
}
let output = output(c.to_command().arg("--version"));
let i = match output.find(" 4.") {
Some(i) => i,
None => return,
};
match output[i + 3..].chars().next().unwrap() {
'0' ... '6' => {}
_ => return,
}
let alternative = format!("e{}", gnu_compiler);
if Command::new(&alternative).output().is_ok() {
cfg.compiler(alternative);
}
}
_ => {}
}
}

View File

@ -0,0 +1,82 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::Path;
use std::process::Command;
use build_helper::output;
use build::Build;
use build::util::mtime;
pub fn collect(build: &mut Build) {
let mut main_mk = String::new();
t!(t!(File::open(build.src.join("mk/main.mk"))).read_to_string(&mut main_mk));
let mut release_num = "";
let mut prerelease_version = "";
for line in main_mk.lines() {
if line.starts_with("CFG_RELEASE_NUM") {
release_num = line.split('=').skip(1).next().unwrap().trim();
}
if line.starts_with("CFG_PRERELEASE_VERSION") {
prerelease_version = line.split('=').skip(1).next().unwrap().trim();
}
}
// FIXME: this is duplicating makefile logic
match &build.config.channel[..] {
"stable" => {
build.release = release_num.to_string();
build.unstable_features = false;
}
"beta" => {
build.release = format!("{}-beta{}", release_num,
prerelease_version);
build.unstable_features = false;
}
"nightly" => {
build.release = format!("{}-nightly", release_num);
build.unstable_features = true;
}
_ => {
build.release = format!("{}-dev", release_num);
build.unstable_features = true;
}
}
build.version = build.release.clone();
if fs::metadata(build.src.join(".git")).is_ok() {
let ver_date = output(Command::new("git").current_dir(&build.src)
.arg("log").arg("-1")
.arg("--date=short")
.arg("--pretty=format:%cd"));
let ver_hash = output(Command::new("git").current_dir(&build.src)
.arg("rev-parse").arg("HEAD"));
let short_ver_hash = output(Command::new("git")
.current_dir(&build.src)
.arg("rev-parse")
.arg("--short=9")
.arg("HEAD"));
let ver_date = ver_date.trim().to_string();
let ver_hash = ver_hash.trim().to_string();
let short_ver_hash = short_ver_hash.trim().to_string();
build.version.push_str(&format!(" ({} {})", short_ver_hash,
ver_date));
build.ver_date = Some(ver_date.to_string());
build.ver_hash = Some(ver_hash);
build.short_ver_hash = Some(short_ver_hash);
}
build.bootstrap_key = mtime(Path::new("config.toml")).seconds()
.to_string();
}

View File

@ -0,0 +1,36 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::fs;
use std::path::Path;
use build::Build;
pub fn clean(build: &Build) {
for host in build.config.host.iter() {
let out = build.out.join(host);
rm_rf(build, &out.join("compiler-rt"));
for stage in 0..4 {
rm_rf(build, &out.join(format!("stage{}", stage)));
rm_rf(build, &out.join(format!("stage{}-std", stage)));
rm_rf(build, &out.join(format!("stage{}-rustc", stage)));
}
}
}
fn rm_rf(build: &Build, path: &Path) {
if path.exists() {
build.verbose(&format!("removing `{}`", path.display()));
t!(fs::remove_dir_all(path));
}
}

View File

@ -0,0 +1,287 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use build_helper::output;
use build::util::{exe, staticlib, libdir, mtime, is_dylib};
use build::{Build, Compiler};
/// Build the standard library.
///
/// This will build the standard library for a particular stage of the build
/// using the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
pub fn std<'a>(build: &'a Build, stage: u32, target: &str,
compiler: &Compiler<'a>) {
let host = compiler.host;
println!("Building stage{} std artifacts ({} -> {})", stage,
host, target);
// Move compiler-rt into place as it'll be required by the compiler when
// building the standard library to link the dylib of libstd
let libdir = build.sysroot_libdir(stage, &host, target);
let _ = fs::remove_dir_all(&libdir);
t!(fs::create_dir_all(&libdir));
t!(fs::hard_link(&build.compiler_rt_built.borrow()[target],
libdir.join(staticlib("compiler-rt", target))));
build_startup_objects(build, target, &libdir);
let out_dir = build.cargo_out(stage, &host, true, target);
build.clear_if_dirty(&out_dir, &build.compiler_path(compiler));
let mut cargo = build.cargo(stage, compiler, true, target, "build");
cargo.arg("--features").arg(build.std_features())
.arg("--manifest-path")
.arg(build.src.join("src/rustc/std_shim/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 let Some(ref p) = build.config.musl_root {
if target.contains("musl") {
cargo.env("MUSL_ROOT", p);
}
}
build.run(&mut cargo);
std_link(build, stage, target, compiler, host);
}
/// Link all libstd rlibs/dylibs into the sysroot location.
///
/// Links those artifacts generated in the given `stage` for `target` produced
/// by `compiler` into `host`'s sysroot.
pub fn std_link(build: &Build,
stage: u32,
target: &str,
compiler: &Compiler,
host: &str) {
let libdir = build.sysroot_libdir(stage, host, target);
let out_dir = build.cargo_out(stage, compiler.host, true, target);
// If we're linking one compiler host's output into another, then we weren't
// called from the `std` method above. In that case we clean out what's
// already there and then also link compiler-rt into place.
if host != compiler.host {
let _ = fs::remove_dir_all(&libdir);
t!(fs::create_dir_all(&libdir));
t!(fs::hard_link(&build.compiler_rt_built.borrow()[target],
libdir.join(staticlib("compiler-rt", target))));
}
add_to_sysroot(&out_dir, &libdir);
}
/// Build and prepare startup objects like rsbegin.o and rsend.o
///
/// These are primarily used on Windows right now for linking executables/dlls.
/// They don't require any library support as they're just plain old object
/// files, so we just use the nightly snapshot compiler to always build them (as
/// no other compilers are guaranteed to be available).
fn build_startup_objects(build: &Build, target: &str, into: &Path) {
if !target.contains("pc-windows-gnu") {
return
}
let compiler = Compiler::new(0, &build.config.build);
let compiler = build.compiler_path(&compiler);
for file in t!(fs::read_dir(build.src.join("src/rtstartup"))) {
let file = t!(file);
build.run(Command::new(&compiler)
.arg("--emit=obj")
.arg("--out-dir").arg(into)
.arg(file.path()));
}
for obj in ["crt2.o", "dllcrt2.o"].iter() {
t!(fs::copy(compiler_file(build.cc(target), obj), into.join(obj)));
}
}
/// Build the compiler.
///
/// This will build the compiler for a particular stage of the build using
/// the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
pub fn rustc<'a>(build: &'a Build, stage: u32, target: &str,
compiler: &Compiler<'a>) {
let host = compiler.host;
println!("Building stage{} compiler artifacts ({} -> {})", stage,
host, target);
let out_dir = build.cargo_out(stage, &host, false, target);
build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target));
let mut cargo = build.cargo(stage, compiler, false, target, "build");
cargo.arg("--features").arg(build.rustc_features(stage))
.arg("--manifest-path")
.arg(build.src.join("src/rustc/Cargo.toml"));
// In stage0 we may not need to build as many executables
if stage == 0 {
cargo.arg("--bin").arg("rustc");
}
// Set some configuration variables picked up by build scripts and
// the compiler alike
cargo.env("CFG_RELEASE", &build.release)
.env("CFG_RELEASE_CHANNEL", &build.config.channel)
.env("CFG_VERSION", &build.version)
.env("CFG_BOOTSTRAP_KEY", &build.bootstrap_key)
.env("CFG_PREFIX", build.config.prefix.clone().unwrap_or(String::new()))
.env("RUSTC_BOOTSTRAP_KEY", &build.bootstrap_key)
.env("CFG_LIBDIR_RELATIVE", "lib");
if let Some(ref ver_date) = build.ver_date {
cargo.env("CFG_VER_DATE", ver_date);
}
if let Some(ref ver_hash) = build.ver_hash {
cargo.env("CFG_VER_HASH", ver_hash);
}
if !build.unstable_features {
cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1");
}
let target_config = build.config.target_config.get(target);
if let Some(ref s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
cargo.env("LLVM_CONFIG", s);
} else {
let llvm_config = build.llvm_out(&build.config.build).join("bin")
.join(exe("llvm-config", target));
cargo.env("LLVM_CONFIG", llvm_config);
}
if build.config.llvm_static_stdcpp {
cargo.env("LLVM_STATIC_STDCPP",
compiler_file(build.cxx(target), "libstdc++.a"));
}
if let Some(ref s) = build.config.rustc_default_linker {
cargo.env("CFG_DEFAULT_LINKER", s);
}
if let Some(ref s) = build.config.rustc_default_ar {
cargo.env("CFG_DEFAULT_AR", s);
}
build.run(&mut cargo);
rustc_link(build, stage, target, compiler, compiler.host);
}
/// Link all librustc rlibs/dylibs into the sysroot location.
///
/// Links those artifacts generated in the given `stage` for `target` produced
/// by `compiler` into `host`'s sysroot.
pub fn rustc_link(build: &Build,
stage: u32,
target: &str,
compiler: &Compiler,
host: &str) {
let libdir = build.sysroot_libdir(stage, host, target);
let out_dir = build.cargo_out(stage, compiler.host, false, target);
add_to_sysroot(&out_dir, &libdir);
}
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
fn libstd_shim(build: &Build, stage: u32, host: &str, target: &str) -> PathBuf {
build.cargo_out(stage, host, true, target).join("libstd_shim.rlib")
}
fn compiler_file(compiler: &Path, file: &str) -> String {
output(Command::new(compiler)
.arg(format!("-print-file-name={}", file))).trim().to_string()
}
/// Prepare a new compiler from the artifacts in `stage`
///
/// This will assemble a compiler in `build/$host/stage$stage`. The compiler
/// must have been previously produced by the `stage - 1` build.config.build
/// compiler.
pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
assert!(stage > 0, "the stage0 compiler isn't assembled, it's downloaded");
// Clear out old files
let sysroot = build.sysroot(stage, host);
let _ = fs::remove_dir_all(&sysroot);
t!(fs::create_dir_all(&sysroot));
// Link in all dylibs to the libdir
let sysroot_libdir = sysroot.join(libdir(host));
t!(fs::create_dir_all(&sysroot_libdir));
let src_libdir = build.sysroot_libdir(stage - 1, &build.config.build, host);
for f in t!(fs::read_dir(&src_libdir)).map(|f| t!(f)) {
let filename = f.file_name().into_string().unwrap();
if is_dylib(&filename) {
t!(fs::hard_link(&f.path(), sysroot_libdir.join(&filename)));
}
}
let out_dir = build.cargo_out(stage - 1, &build.config.build, false, host);
// Link the compiler binary itself into place
let rustc = out_dir.join(exe("rustc", host));
let bindir = sysroot.join("bin");
t!(fs::create_dir_all(&bindir));
let compiler = build.compiler_path(&Compiler::new(stage, host));
let _ = fs::remove_file(&compiler);
t!(fs::hard_link(rustc, compiler));
// See if rustdoc exists to link it into place
let rustdoc = exe("rustdoc", host);
let rustdoc_src = out_dir.join(&rustdoc);
let rustdoc_dst = bindir.join(&rustdoc);
if fs::metadata(&rustdoc_src).is_ok() {
let _ = fs::remove_file(&rustdoc_dst);
t!(fs::hard_link(&rustdoc_src, &rustdoc_dst));
}
}
/// Link some files into a rustc sysroot.
///
/// For a particular stage this will link all of the contents of `out_dir`
/// into the sysroot of the `host` compiler, assuming the artifacts are
/// compiled for the specified `target`.
fn add_to_sysroot(out_dir: &Path, sysroot_dst: &Path) {
// Collect the set of all files in the dependencies directory, keyed
// off the name of the library. We assume everything is of the form
// `foo-<hash>.{rlib,so,...}`, and there could be multiple different
// `<hash>` values for the same name (of old builds).
let mut map = HashMap::new();
for file in t!(fs::read_dir(out_dir.join("deps"))).map(|f| t!(f)) {
let filename = file.file_name().into_string().unwrap();
// We're only interested in linking rlibs + dylibs, other things like
// unit tests don't get linked in
if !filename.ends_with(".rlib") &&
!filename.ends_with(".lib") &&
!is_dylib(&filename) {
continue
}
let file = file.path();
let dash = filename.find("-").unwrap();
let key = (filename[..dash].to_string(),
file.extension().unwrap().to_owned());
map.entry(key).or_insert(Vec::new())
.push(file.clone());
}
// For all hash values found, pick the most recent one to move into the
// sysroot, that should be the one we just built.
for (_, paths) in map {
let (_, path) = paths.iter().map(|path| {
(mtime(&path).seconds(), path)
}).max().unwrap();
t!(fs::hard_link(&path,
sysroot_dst.join(path.file_name().unwrap())));
}
}

View File

@ -0,0 +1,361 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;
use std::process;
use num_cpus;
use rustc_serialize::Decodable;
use toml::{Parser, Decoder, Value};
/// Global configuration for the entire build and/or bootstrap.
///
/// This structure is derived from a combination of both `config.toml` and
/// `config.mk`. As of the time of this writing it's unlikely that `config.toml`
/// is used all that much, so this is primarily filled out by `config.mk` which
/// is generated from `./configure`.
///
/// Note that this structure is not decoded directly into, but rather it is
/// filled out from the decoded forms of the structs below.
#[derive(Default)]
pub struct Config {
pub ccache: bool,
pub verbose: bool,
pub submodules: bool,
pub compiler_docs: bool,
pub docs: bool,
pub target_config: HashMap<String, Target>,
// llvm codegen options
pub llvm_assertions: bool,
pub llvm_optimize: bool,
pub llvm_version_check: bool,
pub llvm_static_stdcpp: bool,
// rust codegen options
pub rust_optimize: bool,
pub rust_codegen_units: u32,
pub rust_debug_assertions: bool,
pub rust_debuginfo: bool,
pub rust_rpath: bool,
pub rustc_default_linker: Option<String>,
pub rustc_default_ar: Option<String>,
pub build: String,
pub host: Vec<String>,
pub target: Vec<String>,
pub rustc: Option<String>,
pub cargo: Option<String>,
// libstd features
pub debug_jemalloc: bool,
pub use_jemalloc: bool,
// misc
pub channel: String,
pub musl_root: Option<PathBuf>,
pub prefix: Option<String>,
}
/// Per-target configuration stored in the global configuration structure.
#[derive(Default)]
pub struct Target {
pub llvm_config: Option<PathBuf>,
pub jemalloc: Option<PathBuf>,
pub cc: Option<PathBuf>,
pub cxx: Option<PathBuf>,
pub ndk: Option<PathBuf>,
}
/// Structure of the `config.toml` file that configuration is read from.
///
/// This structure uses `Decodable` to automatically decode a TOML configuration
/// file into this format, and then this is traversed and written into the above
/// `Config` structure.
#[derive(RustcDecodable, Default)]
struct TomlConfig {
build: Option<Build>,
llvm: Option<Llvm>,
rust: Option<Rust>,
target: Option<HashMap<String, TomlTarget>>,
}
/// TOML representation of various global build decisions.
#[derive(RustcDecodable, Default, Clone)]
struct Build {
build: Option<String>,
host: Vec<String>,
target: Vec<String>,
cargo: Option<String>,
rustc: Option<String>,
compiler_docs: Option<bool>,
docs: Option<bool>,
}
/// TOML representation of how the LLVM build is configured.
#[derive(RustcDecodable, Default)]
struct Llvm {
ccache: Option<bool>,
assertions: Option<bool>,
optimize: Option<bool>,
version_check: Option<bool>,
static_libstdcpp: Option<bool>,
}
/// TOML representation of how the Rust build is configured.
#[derive(RustcDecodable, Default)]
struct Rust {
optimize: Option<bool>,
codegen_units: Option<u32>,
debug_assertions: Option<bool>,
debuginfo: Option<bool>,
debug_jemalloc: Option<bool>,
use_jemalloc: Option<bool>,
default_linker: Option<String>,
default_ar: Option<String>,
channel: Option<String>,
musl_root: Option<String>,
rpath: Option<bool>,
}
/// TOML representation of how each build target is configured.
#[derive(RustcDecodable, Default)]
struct TomlTarget {
llvm_config: Option<String>,
jemalloc: Option<String>,
cc: Option<String>,
cxx: Option<String>,
android_ndk: Option<String>,
}
impl Config {
pub fn parse(build: &str, file: Option<PathBuf>) -> Config {
let mut config = Config::default();
config.llvm_optimize = true;
config.use_jemalloc = true;
config.rust_optimize = true;
config.submodules = true;
config.docs = true;
config.rust_rpath = true;
config.rust_codegen_units = 1;
config.build = build.to_string();
config.channel = "dev".to_string();
let toml = file.map(|file| {
let mut f = t!(File::open(&file));
let mut toml = String::new();
t!(f.read_to_string(&mut toml));
let mut p = Parser::new(&toml);
let table = match p.parse() {
Some(table) => table,
None => {
println!("failed to parse TOML configuration:");
for err in p.errors.iter() {
let (loline, locol) = p.to_linecol(err.lo);
let (hiline, hicol) = p.to_linecol(err.hi);
println!("{}:{}-{}:{}: {}", loline, locol, hiline,
hicol, err.desc);
}
process::exit(2);
}
};
let mut d = Decoder::new(Value::Table(table));
match Decodable::decode(&mut d) {
Ok(cfg) => cfg,
Err(e) => {
println!("failed to decode TOML: {}", e);
process::exit(2);
}
}
}).unwrap_or_else(|| TomlConfig::default());
let build = toml.build.clone().unwrap_or(Build::default());
set(&mut config.build, build.build.clone());
config.host.push(config.build.clone());
for host in build.host.iter() {
if !config.host.contains(host) {
config.host.push(host.clone());
}
}
for target in config.host.iter().chain(&build.target) {
if !config.target.contains(target) {
config.target.push(target.clone());
}
}
config.rustc = build.rustc;
config.cargo = build.cargo;
set(&mut config.compiler_docs, build.compiler_docs);
set(&mut config.docs, build.docs);
if let Some(ref llvm) = toml.llvm {
set(&mut config.ccache, llvm.ccache);
set(&mut config.llvm_assertions, llvm.assertions);
set(&mut config.llvm_optimize, llvm.optimize);
set(&mut config.llvm_optimize, llvm.optimize);
set(&mut config.llvm_version_check, llvm.version_check);
set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp);
}
if let Some(ref rust) = toml.rust {
set(&mut config.rust_debug_assertions, rust.debug_assertions);
set(&mut config.rust_debuginfo, rust.debuginfo);
set(&mut config.rust_optimize, rust.optimize);
set(&mut config.rust_rpath, rust.rpath);
set(&mut config.debug_jemalloc, rust.debug_jemalloc);
set(&mut config.use_jemalloc, rust.use_jemalloc);
set(&mut config.channel, rust.channel.clone());
config.rustc_default_linker = rust.default_linker.clone();
config.rustc_default_ar = rust.default_ar.clone();
config.musl_root = rust.musl_root.clone().map(PathBuf::from);
match rust.codegen_units {
Some(0) => config.rust_codegen_units = num_cpus::get() as u32,
Some(n) => config.rust_codegen_units = n,
None => {}
}
}
if let Some(ref t) = toml.target {
for (triple, cfg) in t {
let mut target = Target::default();
if let Some(ref s) = cfg.llvm_config {
target.llvm_config = Some(env::current_dir().unwrap().join(s));
}
if let Some(ref s) = cfg.jemalloc {
target.jemalloc = Some(env::current_dir().unwrap().join(s));
}
if let Some(ref s) = cfg.android_ndk {
target.ndk = Some(env::current_dir().unwrap().join(s));
}
target.cxx = cfg.cxx.clone().map(PathBuf::from);
target.cc = cfg.cc.clone().map(PathBuf::from);
config.target_config.insert(triple.clone(), target);
}
}
return config
}
pub fn update_with_config_mk(&mut self) {
let mut config = String::new();
File::open("config.mk").unwrap().read_to_string(&mut config).unwrap();
for line in config.lines() {
let mut parts = line.splitn(2, ":=").map(|s| s.trim());
let key = parts.next().unwrap();
let value = match parts.next() {
Some(n) if n.starts_with('\"') => &n[1..n.len() - 1],
Some(n) => n,
None => continue
};
macro_rules! check {
($(($name:expr, $val:expr),)*) => {
if value == "1" {
$(
if key == concat!("CFG_ENABLE_", $name) {
$val = true;
continue
}
if key == concat!("CFG_DISABLE_", $name) {
$val = false;
continue
}
)*
}
}
}
check! {
("CCACHE", self.ccache),
("MANAGE_SUBMODULES", self.submodules),
("COMPILER_DOCS", self.compiler_docs),
("DOCS", self.docs),
("LLVM_ASSERTIONS", self.llvm_assertions),
("OPTIMIZE_LLVM", self.llvm_optimize),
("LLVM_VERSION_CHECK", self.llvm_version_check),
("LLVM_STATIC_STDCPP", self.llvm_static_stdcpp),
("OPTIMIZE", self.rust_optimize),
("DEBUG_ASSERTIONS", self.rust_debug_assertions),
("DEBUGINFO", self.rust_debuginfo),
("JEMALLOC", self.use_jemalloc),
("DEBUG_JEMALLOC", self.debug_jemalloc),
("RPATH", self.rust_rpath),
}
match key {
"CFG_BUILD" => self.build = value.to_string(),
"CFG_HOST" => {
self.host = value.split(" ").map(|s| s.to_string())
.collect();
}
"CFG_TARGET" => {
self.target = value.split(" ").map(|s| s.to_string())
.collect();
}
"CFG_MUSL_ROOT" if value.len() > 0 => {
self.musl_root = Some(PathBuf::from(value));
}
"CFG_DEFAULT_AR" if value.len() > 0 => {
self.rustc_default_ar = Some(value.to_string());
}
"CFG_DEFAULT_LINKER" if value.len() > 0 => {
self.rustc_default_linker = Some(value.to_string());
}
"CFG_RELEASE_CHANNEL" => {
self.channel = value.to_string();
}
"CFG_PREFIX" => {
self.prefix = Some(value.to_string());
}
"CFG_LLVM_ROOT" if value.len() > 0 => {
let target = self.target_config.entry(self.build.clone())
.or_insert(Target::default());
let root = PathBuf::from(value);
target.llvm_config = Some(root.join("bin/llvm-config"));
}
"CFG_JEMALLOC_ROOT" if value.len() > 0 => {
let target = self.target_config.entry(self.build.clone())
.or_insert(Target::default());
target.jemalloc = Some(PathBuf::from(value));
}
"CFG_ARM_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => {
let target = "arm-linux-androideabi".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
target.ndk = Some(PathBuf::from(value));
}
"CFG_I686_LINUX_ANDROID_NDK" if value.len() > 0 => {
let target = "i686-linux-androideabi".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
target.ndk = Some(PathBuf::from(value));
}
"CFG_AARCH64_LINUX_ANDROID_NDK" if value.len() > 0 => {
let target = "aarch64-linux-androideabi".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
target.ndk = Some(PathBuf::from(value));
}
_ => {}
}
}
}
}
fn set<T>(field: &mut T, val: Option<T>) {
if let Some(v) = val {
*field = v;
}
}

104
src/bootstrap/build/doc.rs Normal file
View File

@ -0,0 +1,104 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::path::Path;
use std::fs::{self, File};
use std::io::prelude::*;
use build::{Build, Compiler};
use build::util::up_to_date;
pub fn rustbook(build: &Build, stage: u32, host: &str, name: &str, out: &Path) {
t!(fs::create_dir_all(out));
let out = out.join(name);
let compiler = Compiler::new(stage, host);
let src = build.src.join("src/doc").join(name);
let index = out.join("index.html");
let rustbook = build.tool(&compiler, "rustbook");
if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
return
}
println!("Rustbook stage{} ({}) - {}", stage, host, name);
let _ = fs::remove_dir_all(&out);
build.run(build.tool_cmd(&compiler, "rustbook")
.arg("build")
.arg(&src)
.arg(out));
}
pub fn standalone(build: &Build, stage: u32, host: &str, out: &Path) {
println!("Documenting stage{} standalone ({})", stage, host);
t!(fs::create_dir_all(out));
let compiler = Compiler::new(stage, host);
let favicon = build.src.join("src/doc/favicon.inc");
let footer = build.src.join("src/doc/footer.inc");
let full_toc = build.src.join("src/doc/full-toc.inc");
t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css")));
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) {
let mut info = String::new();
t!(t!(File::open(&version_input)).read_to_string(&mut info));
let blank = String::new();
let short = build.short_ver_hash.as_ref().unwrap_or(&blank);
let hash = build.ver_hash.as_ref().unwrap_or(&blank);
let info = info.replace("VERSION", &build.release)
.replace("SHORT_HASH", short)
.replace("STAMP", hash);
t!(t!(File::create(&version_info)).write_all(info.as_bytes()));
}
for file in t!(fs::read_dir(build.src.join("src/doc"))) {
let file = t!(file);
let path = file.path();
let filename = path.file_name().unwrap().to_str().unwrap();
if !filename.ends_with(".md") || filename == "README.md" {
continue
}
let html = out.join(filename).with_extension("html");
let rustdoc = build.tool(&compiler, "rustdoc");
if up_to_date(&path, &html) &&
up_to_date(&footer, &html) &&
up_to_date(&favicon, &html) &&
up_to_date(&full_toc, &html) &&
up_to_date(&version_info, &html) &&
up_to_date(&rustdoc, &html) {
continue
}
let mut cmd = build.tool_cmd(&compiler, "rustdoc");
cmd.arg("--html-after-content").arg(&footer)
.arg("--html-before-content").arg(&version_info)
.arg("--html-in-header").arg(&favicon)
.arg("--markdown-playground-url")
.arg("https://play.rust-lang.org/")
.arg("-o").arg(out)
.arg(&path);
if filename == "reference.md" {
cmd.arg("--html-in-header").arg(&full_toc);
}
if filename == "not_found.md" {
cmd.arg("--markdown-no-toc")
.arg("--markdown-css")
.arg("https://doc.rust-lang.org/rust.css");
} else {
cmd.arg("--markdown-css").arg("rust.css");
}
build.run(&mut cmd);
}
}

View File

@ -0,0 +1,102 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::fs;
use std::path::PathBuf;
use std::process;
use std::slice;
use getopts::Options;
pub struct Flags {
pub verbose: bool,
pub stage: Option<u32>,
pub build: String,
pub host: Filter,
pub target: Filter,
pub step: Vec<String>,
pub config: Option<PathBuf>,
pub src: Option<PathBuf>,
pub jobs: Option<u32>,
pub args: Vec<String>,
pub clean: bool,
}
pub struct Filter {
values: Vec<String>,
}
impl Flags {
pub fn parse(args: &[String]) -> Flags {
let mut opts = Options::new();
opts.optflag("v", "verbose", "use verbose output");
opts.optopt("", "config", "TOML configuration file for build", "FILE");
opts.optmulti("", "host", "host targets to build", "HOST");
opts.reqopt("", "build", "build target of the stage0 compiler", "BUILD");
opts.optmulti("", "target", "targets to build", "TARGET");
opts.optmulti("s", "step", "build step to execute", "STEP");
opts.optopt("", "stage", "stage to build", "N");
opts.optopt("", "src", "path to repo root", "DIR");
opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
opts.optflag("", "clean", "clean output directory");
opts.optflag("h", "help", "print this help message");
let usage = |n| -> ! {
let brief = format!("Usage: rust.py [options]");
print!("{}", opts.usage(&brief));
process::exit(n);
};
let m = opts.parse(args).unwrap_or_else(|e| {
println!("failed to parse options: {}", e);
usage(1);
});
if m.opt_present("h") {
usage(0);
}
if m.free.len() > 0 {
println!("free arguments are not currently accepted");
usage(1);
}
let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| {
if fs::metadata("config.toml").is_ok() {
Some(PathBuf::from("config.toml"))
} else {
None
}
});
Flags {
verbose: m.opt_present("v"),
clean: m.opt_present("clean"),
stage: m.opt_str("stage").map(|j| j.parse().unwrap()),
build: m.opt_str("build").unwrap(),
host: Filter { values: m.opt_strs("host") },
target: Filter { values: m.opt_strs("target") },
step: m.opt_strs("step"),
config: cfg_file,
src: m.opt_str("src").map(PathBuf::from),
jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()),
args: m.free.clone(),
}
}
}
impl Filter {
pub fn contains(&self, name: &str) -> bool {
self.values.len() == 0 || self.values.iter().any(|s| s == name)
}
pub fn iter(&self) -> slice::Iter<String> {
self.values.iter()
}
}

111
src/bootstrap/build/job.rs Normal file
View File

@ -0,0 +1,111 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Job management on Windows for bootstrapping
//!
//! Most of the time when you're running a build system (e.g. make) you expect
//! Ctrl-C or abnormal termination to actually terminate the entire tree of
//! process in play, not just the one at the top. This currently works "by
//! default" on Unix platforms because Ctrl-C actually sends a signal to the
//! *process group* rather than the parent process, so everything will get torn
//! down. On Windows, however, this does not happen and Ctrl-C just kills the
//! parent process.
//!
//! To achieve the same semantics on Windows we use Job Objects to ensure that
//! all processes die at the same time. Job objects have a mode of operation
//! where when all handles to the object are closed it causes all child
//! processes associated with the object to be terminated immediately.
//! Conveniently whenever a process in the job object spawns a new process the
//! child will be associated with the job object as well. This means if we add
//! ourselves to the job object we create then everything will get torn down!
//!
//! Unfortunately most of the time the build system is actually called from a
//! python wrapper (which manages things like building the build system) so this
//! all doesn't quite cut it so far. To go the last mile we duplicate the job
//! object handle into our parent process (a python process probably) and then
//! close our own handle. This means that the only handle to the job object
//! resides in the parent python process, so when python dies the whole build
//! system dies (as one would probably expect!).
//!
//! Note that this module has a #[cfg(windows)] above it as none of this logic
//! is required on Unix.
extern crate kernel32;
extern crate winapi;
use std::env;
use std::io;
use std::mem;
use self::winapi::*;
use self::kernel32::*;
pub unsafe fn setup() {
// Create a new job object for us to use
let job = CreateJobObjectW(0 as *mut _, 0 as *const _);
assert!(job != 0 as *mut _, "{}", io::Error::last_os_error());
// Indicate that when all handles to the job object are gone that all
// process in the object should be killed. Note that this includes our
// entire process tree by default because we've added ourselves and and our
// children will reside in the job by default.
let mut info = mem::zeroed::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>();
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
let r = SetInformationJobObject(job,
JobObjectExtendedLimitInformation,
&mut info as *mut _ as LPVOID,
mem::size_of_val(&info) as DWORD);
assert!(r != 0, "{}", io::Error::last_os_error());
// Assign our process to this job object. Note that if this fails, one very
// likely reason is that we are ourselves already in a job object! This can
// happen on the build bots that we've got for Windows, or if just anyone
// else is instrumenting the build. In this case we just bail out
// immediately and assume that they take care of it.
//
// Also note that nested jobs (why this might fail) are supported in recent
// versions of Windows, but the version of Windows that our bots are running
// at least don't support nested job objects.
let r = AssignProcessToJobObject(job, GetCurrentProcess());
if r == 0 {
CloseHandle(job);
return
}
// If we've got a parent process (e.g. the python script that called us)
// then move ownership of this job object up to them. That way if the python
// script is killed (e.g. via ctrl-c) then we'll all be torn down.
//
// If we don't have a parent (e.g. this was run directly) then we
// intentionally leak the job object handle. When our process exits
// (normally or abnormally) it will close the handle implicitly, causing all
// processes in the job to be cleaned up.
let pid = match env::var("BOOTSTRAP_PARENT_ID") {
Ok(s) => s,
Err(..) => return,
};
let parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid.parse().unwrap());
assert!(parent != 0 as *mut _, "{}", io::Error::last_os_error());
let mut parent_handle = 0 as *mut _;
let r = DuplicateHandle(GetCurrentProcess(), job,
parent, &mut parent_handle,
0, FALSE, DUPLICATE_SAME_ACCESS);
// If this failed, well at least we tried! An example of DuplicateHandle
// failing in the past has been when the wrong python2 package spawed this
// build system (e.g. the `python2` package in MSYS instead of
// `mingw-w64-x86_64-python2`. Not sure why it failed, but the "failure
// mode" here is that we only clean everything up when the build system
// dies, not when the python parent does, so not too bad.
if r != 0 {
CloseHandle(job);
}
}

475
src/bootstrap/build/mod.rs Normal file
View File

@ -0,0 +1,475 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cell::RefCell;
use std::collections::HashMap;
use std::env;
use std::fs::{self, File};
use std::path::{PathBuf, Path};
use std::process::Command;
use build_helper::{run_silent, output};
use gcc;
use num_cpus;
use build::util::{exe, mtime, libdir, add_lib_path};
macro_rules! t {
($e:expr) => (match $e {
Ok(e) => e,
Err(e) => panic!("{} failed with {}", stringify!($e), e),
})
}
mod cc;
mod channel;
mod clean;
mod compile;
mod config;
mod doc;
mod flags;
mod native;
mod sanity;
mod step;
mod util;
#[cfg(windows)]
mod job;
#[cfg(not(windows))]
mod job {
pub unsafe fn setup() {}
}
pub use build::config::Config;
pub use build::flags::Flags;
#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
pub struct Compiler<'a> {
stage: u32,
host: &'a str,
}
pub struct Build {
// User-specified configuration via config.toml
config: Config,
// User-specified configuration via CLI flags
flags: Flags,
// Derived properties from the above two configurations
cargo: PathBuf,
rustc: PathBuf,
src: PathBuf,
out: PathBuf,
release: String,
unstable_features: bool,
ver_hash: Option<String>,
short_ver_hash: Option<String>,
ver_date: Option<String>,
version: String,
bootstrap_key: String,
// Runtime state filled in later on
cc: HashMap<String, (gcc::Tool, PathBuf)>,
cxx: HashMap<String, gcc::Tool>,
compiler_rt_built: RefCell<HashMap<String, PathBuf>>,
}
impl Build {
pub fn new(flags: Flags, config: Config) -> Build {
let cwd = t!(env::current_dir());
let src = flags.src.clone().unwrap_or(cwd.clone());
let out = cwd.join("build");
let stage0_root = out.join(&config.build).join("stage0/bin");
let rustc = match config.rustc {
Some(ref s) => PathBuf::from(s),
None => stage0_root.join(exe("rustc", &config.build)),
};
let cargo = match config.cargo {
Some(ref s) => PathBuf::from(s),
None => stage0_root.join(exe("cargo", &config.build)),
};
Build {
flags: flags,
config: config,
cargo: cargo,
rustc: rustc,
src: src,
out: out,
release: String::new(),
unstable_features: false,
ver_hash: None,
short_ver_hash: None,
ver_date: None,
version: String::new(),
bootstrap_key: String::new(),
cc: HashMap::new(),
cxx: HashMap::new(),
compiler_rt_built: RefCell::new(HashMap::new()),
}
}
pub fn build(&mut self) {
use build::step::Source::*;
unsafe {
job::setup();
}
if self.flags.clean {
return clean::clean(self);
}
cc::find(self);
sanity::check(self);
channel::collect(self);
self.update_submodules();
for target in step::all(self) {
let doc_out = self.out.join(&target.target).join("doc");
match target.src {
Llvm { _dummy } => {
native::llvm(self, target.target);
}
CompilerRt { _dummy } => {
native::compiler_rt(self, target.target);
}
Libstd { stage, compiler } => {
compile::std(self, stage, target.target, &compiler);
}
Librustc { stage, compiler } => {
compile::rustc(self, stage, target.target, &compiler);
}
LibstdLink { stage, compiler, host } => {
compile::std_link(self, stage, target.target,
&compiler, host);
}
LibrustcLink { stage, compiler, host } => {
compile::rustc_link(self, stage, target.target,
&compiler, host);
}
Rustc { stage: 0 } => {
// nothing to do...
}
Rustc { stage } => {
compile::assemble_rustc(self, stage, target.target);
}
DocBook { stage } => {
doc::rustbook(self, stage, target.target, "book", &doc_out);
}
DocNomicon { stage } => {
doc::rustbook(self, stage, target.target, "nomicon",
&doc_out);
}
DocStyle { stage } => {
doc::rustbook(self, stage, target.target, "style",
&doc_out);
}
DocStandalone { stage } => {
doc::standalone(self, stage, target.target, &doc_out);
}
Doc { .. } => {} // pseudo-step
}
}
}
fn update_submodules(&self) {
if !self.config.submodules {
return
}
if fs::metadata(self.src.join(".git")).is_err() {
return
}
let git_submodule = || {
let mut cmd = Command::new("git");
cmd.current_dir(&self.src).arg("submodule");
return cmd
};
let out = output(git_submodule().arg("status"));
if !out.lines().any(|l| l.starts_with("+") || l.starts_with("-")) {
return
}
self.run(git_submodule().arg("sync"));
self.run(git_submodule().arg("init"));
self.run(git_submodule().arg("update"));
self.run(git_submodule().arg("update").arg("--recursive"));
self.run(git_submodule().arg("status").arg("--recursive"));
self.run(git_submodule().arg("foreach").arg("--recursive")
.arg("git").arg("clean").arg("-fdx"));
self.run(git_submodule().arg("foreach").arg("--recursive")
.arg("git").arg("checkout").arg("."));
}
/// Clear out `dir` if our build has been flagged as dirty, and also set
/// ourselves as dirty if `file` changes when `f` is executed.
fn clear_if_dirty(&self, dir: &Path, input: &Path) {
let stamp = dir.join(".stamp");
if mtime(&stamp) < mtime(input) {
self.verbose(&format!("Dirty - {}", dir.display()));
let _ = fs::remove_dir_all(dir);
}
t!(fs::create_dir_all(dir));
t!(File::create(stamp));
}
/// Prepares an invocation of `cargo` to be run.
///
/// This will create a `Command` that represents a pending execution of
/// Cargo for the specified stage, whether or not the standard library is
/// being built, and using the specified compiler targeting `target`.
// FIXME: aren't stage/compiler duplicated?
fn cargo(&self, stage: u32, compiler: &Compiler, is_std: bool,
target: &str, cmd: &str) -> Command {
let mut cargo = Command::new(&self.cargo);
let host = compiler.host;
let out_dir = self.stage_out(stage, host, is_std);
cargo.env("CARGO_TARGET_DIR", out_dir)
.arg(cmd)
.arg("--target").arg(target)
.arg("-j").arg(self.jobs().to_string());
// Customize the compiler we're running. Specify the compiler to cargo
// as our shim and then pass it some various options used to configure
// how the actual compiler itself is called.
cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc"))
.env("RUSTC_REAL", self.compiler_path(compiler))
.env("RUSTC_STAGE", self.stage_arg(stage, compiler).to_string())
.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string())
.env("RUSTC_CODEGEN_UNITS",
self.config.rust_codegen_units.to_string())
.env("RUSTC_DEBUG_ASSERTIONS",
self.config.rust_debug_assertions.to_string())
.env("RUSTC_SNAPSHOT", &self.rustc)
.env("RUSTC_SYSROOT", self.sysroot(stage, host))
.env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir())
.env("RUSTC_FLAGS", self.rustc_flags(target).join(" "))
.env("RUSTC_RPATH", self.config.rust_rpath.to_string())
.env("RUSTDOC", self.tool(compiler, "rustdoc"));
// Specify some variuos options for build scripts used throughout the
// build.
//
// FIXME: the guard against msvc shouldn't need to be here
if !target.contains("msvc") {
cargo.env(format!("CC_{}", target), self.cc(target))
.env(format!("AR_{}", target), self.ar(target))
.env(format!("CFLAGS_{}", target), self.cflags(target));
}
// Environment variables *required* needed throughout the build
//
// FIXME: should update code to not require this env vars
cargo.env("CFG_COMPILER_HOST_TRIPLE", target);
if self.config.verbose || self.flags.verbose {
cargo.arg("-v");
}
if self.config.rust_optimize {
cargo.arg("--release");
}
self.add_rustc_lib_path(compiler, &mut cargo);
return cargo
}
/// Get a path to the compiler specified.
fn compiler_path(&self, compiler: &Compiler) -> PathBuf {
if compiler.is_snapshot(self) {
self.rustc.clone()
} else {
self.sysroot(compiler.stage, compiler.host).join("bin")
.join(exe("rustc", compiler.host))
}
}
/// Get the specified tool next to the specified compiler
fn tool(&self, compiler: &Compiler, tool: &str) -> PathBuf {
if compiler.is_snapshot(self) {
assert!(tool == "rustdoc", "no tools other than rustdoc in stage0");
let mut rustdoc = self.rustc.clone();
rustdoc.pop();
rustdoc.push(exe("rustdoc", &self.config.build));
return rustdoc
}
let (stage, host) = (compiler.stage, compiler.host);
self.cargo_out(stage - 1, host, false, host).join(exe(tool, host))
}
/// Get a `Command` which is ready to run `tool` in `stage` built for
/// `host`.
#[allow(dead_code)] // this will be used soon
fn tool_cmd(&self, compiler: &Compiler, tool: &str) -> Command {
let mut cmd = Command::new(self.tool(&compiler, tool));
let host = compiler.host;
let stage = compiler.stage;
let paths = vec![
self.cargo_out(stage - 1, host, true, host).join("deps"),
self.cargo_out(stage - 1, host, false, host).join("deps"),
];
add_lib_path(paths, &mut cmd);
return cmd
}
fn stage_arg(&self, stage: u32, compiler: &Compiler) -> u32 {
if stage == 0 && compiler.host != self.config.build {1} else {stage}
}
/// Get the space-separated set of activated features for the standard
/// library.
fn std_features(&self) -> String {
let mut features = String::new();
if self.config.debug_jemalloc {
features.push_str(" debug-jemalloc");
}
if self.config.use_jemalloc {
features.push_str(" jemalloc");
}
return features
}
/// Get the space-separated set of activated features for the compiler.
fn rustc_features(&self, stage: u32) -> String {
let mut features = String::new();
if self.config.use_jemalloc {
features.push_str(" jemalloc");
}
if stage > 0 {
features.push_str(" rustdoc");
features.push_str(" rustbook");
}
return features
}
/// Component directory that Cargo will produce output into (e.g.
/// release/debug)
fn cargo_dir(&self) -> &'static str {
if self.config.rust_optimize {"release"} else {"debug"}
}
fn sysroot(&self, stage: u32, host: &str) -> PathBuf {
if stage == 0 {
self.stage_out(stage, host, false)
} else {
self.out.join(host).join(format!("stage{}", stage))
}
}
fn sysroot_libdir(&self, stage: u32, host: &str, target: &str) -> PathBuf {
self.sysroot(stage, host).join("lib").join("rustlib")
.join(target).join("lib")
}
/// Returns the root directory for all output generated in a particular
/// stage when running with a particular host compiler.
///
/// The `is_std` flag indicates whether the root directory is for the
/// bootstrap of the standard library or for the compiler.
fn stage_out(&self, stage: u32, host: &str, is_std: bool) -> PathBuf {
self.out.join(host)
.join(format!("stage{}{}", stage, if is_std {"-std"} else {"-rustc"}))
}
/// Returns the root output directory for all Cargo output in a given stage,
/// running a particular comipler, wehther or not we're building the
/// standard library, and targeting the specified architecture.
fn cargo_out(&self, stage: u32, host: &str, is_std: bool,
target: &str) -> PathBuf {
self.stage_out(stage, host, is_std).join(target).join(self.cargo_dir())
}
/// Root output directory for LLVM compiled for `target`
fn llvm_out(&self, target: &str) -> PathBuf {
self.out.join(target).join("llvm")
}
/// Root output directory for compiler-rt compiled for `target`
fn compiler_rt_out(&self, target: &str) -> PathBuf {
self.out.join(target).join("compiler-rt")
}
fn add_rustc_lib_path(&self, compiler: &Compiler, cmd: &mut Command) {
// Windows doesn't need dylib path munging because the dlls for the
// compiler live next to the compiler and the system will find them
// automatically.
if cfg!(windows) { return }
add_lib_path(vec![self.rustc_libdir(compiler)], cmd);
}
fn rustc_libdir(&self, compiler: &Compiler) -> PathBuf {
if compiler.is_snapshot(self) {
self.rustc_snapshot_libdir()
} else {
self.sysroot(compiler.stage, compiler.host)
.join(libdir(compiler.host))
}
}
fn rustc_snapshot_libdir(&self) -> PathBuf {
self.rustc.parent().unwrap().parent().unwrap()
.join(libdir(&self.config.build))
}
fn run(&self, cmd: &mut Command) {
self.verbose(&format!("running: {:?}", cmd));
run_silent(cmd)
}
fn verbose(&self, msg: &str) {
if self.flags.verbose || self.config.verbose {
println!("{}", msg);
}
}
fn jobs(&self) -> u32 {
self.flags.jobs.unwrap_or(num_cpus::get() as u32)
}
fn cc(&self, target: &str) -> &Path {
self.cc[target].0.path()
}
fn cflags(&self, target: &str) -> String {
self.cc[target].0.args().iter()
.map(|s| s.to_string_lossy())
.collect::<Vec<_>>()
.join(" ")
}
fn ar(&self, target: &str) -> &Path {
&self.cc[target].1
}
fn cxx(&self, target: &str) -> &Path {
self.cxx[target].path()
}
fn rustc_flags(&self, target: &str) -> Vec<String> {
let mut base = Vec::new();
if target != self.config.build && !target.contains("msvc") {
base.push(format!("-Clinker={}", self.cc(target).display()));
}
return base
}
}
impl<'a> Compiler<'a> {
fn new(stage: u32, host: &'a str) -> Compiler<'a> {
Compiler { stage: stage, host: host }
}
fn is_snapshot(&self, build: &Build) -> bool {
self.stage == 0 && self.host == build.config.build
}
}

View File

@ -0,0 +1,165 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::path::Path;
use std::process::Command;
use std::fs;
use build_helper::output;
use cmake;
use build::Build;
use build::util::{exe, staticlib};
pub fn llvm(build: &Build, target: &str) {
// If we're using a custom LLVM bail out here, but we can only use a
// custom LLVM for the build triple.
if let Some(config) = build.config.target_config.get(target) {
if let Some(ref s) = config.llvm_config {
return check_llvm_version(build, s);
}
}
// If the cleaning trigger is newer than our built artifacts (or if the
// artifacts are missing) then we keep going, otherwise we bail out.
let dst = build.llvm_out(target);
let stamp = build.src.join("src/rustllvm/llvm-auto-clean-trigger");
let llvm_config = dst.join("bin").join(exe("llvm-config", target));
build.clear_if_dirty(&dst, &stamp);
if fs::metadata(llvm_config).is_ok() {
return
}
let _ = fs::remove_dir_all(&dst.join("build"));
t!(fs::create_dir_all(&dst.join("build")));
let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"};
// http://llvm.org/docs/CMake.html
let mut cfg = cmake::Config::new(build.src.join("src/llvm"));
cfg.target(target)
.host(&build.config.build)
.out_dir(&dst)
.profile(if build.config.llvm_optimize {"Release"} else {"Debug"})
.define("LLVM_ENABLE_ASSERTIONS", assertions)
.define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC")
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
.define("LLVM_INCLUDE_TESTS", "OFF")
.define("LLVM_INCLUDE_DOCS", "OFF")
.define("LLVM_ENABLE_ZLIB", "OFF")
.define("WITH_POLLY", "OFF")
.define("LLVM_ENABLE_TERMINFO", "OFF")
.define("LLVM_ENABLE_LIBEDIT", "OFF")
.define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string());
if target.starts_with("i686") {
cfg.define("LLVM_BUILD_32_BITS", "ON");
}
// http://llvm.org/docs/HowToCrossCompileLLVM.html
if target != build.config.build {
// FIXME: if the llvm root for the build triple is overridden then we
// should use llvm-tblgen from there, also should verify that it
// actually exists most of the time in normal installs of LLVM.
let host = build.llvm_out(&build.config.build).join("bin/llvm-tblgen");
cfg.define("CMAKE_CROSSCOMPILING", "True")
.define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
.define("LLVM_TABLEGEN", &host)
.define("LLVM_DEFAULT_TARGET_TRIPLE", target);
}
// MSVC handles compiler business itself
if !target.contains("msvc") {
if build.config.ccache {
cfg.define("CMAKE_C_COMPILER", "ccache")
.define("CMAKE_C_COMPILER_ARG1", build.cc(target))
.define("CMAKE_CXX_COMPILER", "ccache")
.define("CMAKE_CXX_COMPILER_ARG1", build.cxx(target));
} else {
cfg.define("CMAKE_C_COMPILER", build.cc(target))
.define("CMAKE_CXX_COMPILER", build.cxx(target));
}
cfg.build_arg("-j").build_arg(build.jobs().to_string());
}
// FIXME: we don't actually need to build all LLVM tools and all 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.
cfg.build();
}
fn check_llvm_version(build: &Build, llvm_config: &Path) {
if !build.config.llvm_version_check {
return
}
let mut cmd = Command::new(llvm_config);
let version = output(cmd.arg("--version"));
if version.starts_with("3.5") || version.starts_with("3.6") ||
version.starts_with("3.7") {
return
}
panic!("\n\nbad LLVM version: {}, need >=3.5\n\n", version)
}
pub fn compiler_rt(build: &Build, target: &str) {
let dst = build.compiler_rt_out(target);
let arch = target.split('-').next().unwrap();
let mode = if build.config.rust_optimize {"Release"} else {"Debug"};
let (dir, build_target, libname) = if target.contains("linux") {
let os = if target.contains("android") {"-android"} else {""};
let arch = if arch.starts_with("arm") && target.contains("eabihf") {
"armhf"
} else {
arch
};
let target = format!("clang_rt.builtins-{}{}", arch, os);
("linux".to_string(), target.clone(), target)
} else if target.contains("darwin") {
let target = format!("clang_rt.builtins_{}_osx", arch);
("builtins".to_string(), target.clone(), target)
} else if target.contains("windows-gnu") {
let target = format!("clang_rt.builtins-{}", arch);
("windows".to_string(), target.clone(), target)
} else if target.contains("windows-msvc") {
(format!("windows/{}", mode),
"lib/builtins/builtins".to_string(),
format!("clang_rt.builtins-{}", arch.replace("i686", "i386")))
} else {
panic!("can't get os from target: {}", target)
};
let output = dst.join("build/lib").join(dir)
.join(staticlib(&libname, target));
build.compiler_rt_built.borrow_mut().insert(target.to_string(),
output.clone());
if fs::metadata(&output).is_ok() {
return
}
let _ = fs::remove_dir_all(&dst);
t!(fs::create_dir_all(&dst));
let build_llvm_config = build.llvm_out(&build.config.build)
.join("bin")
.join(exe("llvm-config", &build.config.build));
let mut cfg = cmake::Config::new(build.src.join("src/compiler-rt"));
cfg.target(target)
.host(&build.config.build)
.out_dir(&dst)
.profile(mode)
.define("LLVM_CONFIG_PATH", build_llvm_config)
.define("COMPILER_RT_DEFAULT_TARGET_TRIPLE", target)
.define("COMPILER_RT_BUILD_SANITIZERS", "OFF")
.define("COMPILER_RT_BUILD_EMUTLS", "OFF")
// inform about c/c++ compilers, the c++ compiler isn't actually used but
// it's needed to get the initial configure to work on all platforms.
.define("CMAKE_C_COMPILER", build.cc(target))
.define("CMAKE_CXX_COMPILER", build.cc(target))
.build_target(&build_target);
cfg.build();
}

View File

@ -0,0 +1,122 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::collections::HashSet;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::process::Command;
use build_helper::output;
use build::Build;
pub fn check(build: &mut Build) {
let mut checked = HashSet::new();
let path = env::var_os("PATH").unwrap_or(OsString::new());
let mut need_cmd = |cmd: &OsStr| {
if !checked.insert(cmd.to_owned()) {
return
}
for path in env::split_paths(&path).map(|p| p.join(cmd)) {
if fs::metadata(&path).is_ok() ||
fs::metadata(path.with_extension("exe")).is_ok() {
return
}
}
panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
};
// If we've got a git directory we're gona need git to update
// submodules and learn about various other aspects.
if fs::metadata(build.src.join(".git")).is_ok() {
need_cmd("git".as_ref());
}
// We need cmake, but only if we're actually building LLVM
for host in build.config.host.iter() {
if let Some(config) = build.config.target_config.get(host) {
if config.llvm_config.is_some() {
continue
}
}
need_cmd("cmake".as_ref());
break
}
need_cmd("python".as_ref());
// We're gonna build some custom C code here and there, host triples
// also build some C++ shims for LLVM so we need a C++ compiler.
for target in build.config.target.iter() {
need_cmd(build.cc(target).as_ref());
need_cmd(build.ar(target).as_ref());
}
for host in build.config.host.iter() {
need_cmd(build.cxx(host).as_ref());
}
for target in build.config.target.iter() {
// Either can't build or don't want to run jemalloc on these targets
if target.contains("rumprun") ||
target.contains("bitrig") ||
target.contains("openbsd") ||
target.contains("msvc") {
build.config.use_jemalloc = false;
}
// Can't compile for iOS unless we're on OSX
if target.contains("apple-ios") &&
!build.config.build.contains("apple-darwin") {
panic!("the iOS target is only supported on OSX");
}
// Make sure musl-root is valid if specified
if target.contains("musl") {
match build.config.musl_root {
Some(ref root) => {
if fs::metadata(root.join("lib/libc.a")).is_err() {
panic!("couldn't find libc.a in musl dir: {}",
root.join("lib").display());
}
if fs::metadata(root.join("lib/libunwind.a")).is_err() {
panic!("couldn't find libunwind.a in musl dir: {}",
root.join("lib").display());
}
}
None => {
panic!("when targeting MUSL the build.musl-root option \
must be specified in config.toml")
}
}
}
if target.contains("msvc") {
// There are three builds of cmake on windows: MSVC, MinGW, and
// Cygwin. The Cygwin build does not have generators for Visual
// Studio, so detect that here and error.
let out = output(Command::new("cmake").arg("--help"));
if !out.contains("Visual Studio") {
panic!("
cmake does not support Visual Studio generators.
This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.
If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:
$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
}
}
}
}

245
src/bootstrap/build/step.rs Normal file
View File

@ -0,0 +1,245 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::collections::HashSet;
use build::{Build, Compiler};
#[derive(Hash, Eq, PartialEq, Clone, Debug)]
pub struct Step<'a> {
pub src: Source<'a>,
pub target: &'a str,
}
macro_rules! targets {
($m:ident) => {
$m! {
// Step representing building the stageN compiler. This is just the
// compiler executable itself, not any of the support libraries
(rustc, Rustc { stage: u32 }),
// Steps for the two main cargo builds, one for the standard library
// and one for the compiler itself. These are parameterized over the
// stage output they're going to be placed in along with the
// compiler which is producing the copy of libstd or librustc
(libstd, Libstd { stage: u32, compiler: Compiler<'a> }),
(librustc, Librustc { stage: u32, compiler: Compiler<'a> }),
// Links the standard library/librustc produced by the compiler
// provided into the host's directory also provided.
(libstd_link, LibstdLink {
stage: u32,
compiler: Compiler<'a>,
host: &'a str
}),
(librustc_link, LibrustcLink {
stage: u32,
compiler: Compiler<'a>,
host: &'a str
}),
// Steps for long-running native builds. Ideally these wouldn't
// actually exist and would be part of build scripts, but for now
// these are here.
//
// There aren't really any parameters to this, but empty structs
// with braces are unstable so we just pick something that works.
(llvm, Llvm { _dummy: () }),
(compiler_rt, CompilerRt { _dummy: () }),
(doc, Doc { stage: u32 }),
(doc_book, DocBook { stage: u32 }),
(doc_nomicon, DocNomicon { stage: u32 }),
(doc_style, DocStyle { stage: u32 }),
(doc_standalone, DocStandalone { stage: u32 }),
}
}
}
macro_rules! item { ($a:item) => ($a) }
macro_rules! define_source {
($(($short:ident, $name:ident { $($args:tt)* }),)*) => {
item! {
#[derive(Hash, Eq, PartialEq, Clone, Debug)]
pub enum Source<'a> {
$($name { $($args)* }),*
}
}
}
}
targets!(define_source);
pub fn all(build: &Build) -> Vec<Step> {
let mut ret = Vec::new();
let mut all = HashSet::new();
for target in top_level(build) {
fill(build, &target, &mut ret, &mut all);
}
return ret;
fn fill<'a>(build: &'a Build,
target: &Step<'a>,
ret: &mut Vec<Step<'a>>,
set: &mut HashSet<Step<'a>>) {
if set.insert(target.clone()) {
for dep in target.deps(build) {
fill(build, &dep, ret, set);
}
ret.push(target.clone());
}
}
}
fn top_level(build: &Build) -> Vec<Step> {
let mut targets = Vec::new();
let stage = build.flags.stage.unwrap_or(2);
let host = Step {
src: Source::Llvm { _dummy: () },
target: build.flags.host.iter().next()
.unwrap_or(&build.config.build),
};
let target = Step {
src: Source::Llvm { _dummy: () },
target: build.flags.target.iter().next().map(|x| &x[..])
.unwrap_or(host.target)
};
add_steps(build, stage, &host, &target, &mut targets);
if targets.len() == 0 {
let t = Step {
src: Source::Llvm { _dummy: () },
target: &build.config.build,
};
targets.push(t.doc(stage));
for host in build.config.host.iter() {
if !build.flags.host.contains(host) {
continue
}
let host = t.target(host);
if host.target == build.config.build {
targets.push(host.librustc(stage, host.compiler(stage)));
} else {
targets.push(host.librustc_link(stage, t.compiler(stage),
host.target));
}
for target in build.config.target.iter() {
if !build.flags.target.contains(target) {
continue
}
if host.target == build.config.build {
targets.push(host.target(target)
.libstd(stage, host.compiler(stage)));
} else {
targets.push(host.target(target)
.libstd_link(stage, t.compiler(stage),
host.target));
}
}
}
}
return targets
}
fn add_steps<'a>(build: &'a Build,
stage: u32,
host: &Step<'a>,
target: &Step<'a>,
targets: &mut Vec<Step<'a>>) {
for step in build.flags.step.iter() {
let compiler = host.target(&build.config.build).compiler(stage);
match &step[..] {
"libstd" => targets.push(target.libstd(stage, compiler)),
"librustc" => targets.push(target.librustc(stage, compiler)),
"libstd-link" => targets.push(target.libstd_link(stage, compiler,
host.target)),
"librustc-link" => targets.push(target.librustc_link(stage, compiler,
host.target)),
"rustc" => targets.push(host.rustc(stage)),
"llvm" => targets.push(target.llvm(())),
"compiler-rt" => targets.push(target.compiler_rt(())),
"doc-style" => targets.push(host.doc_style(stage)),
"doc-standalone" => targets.push(host.doc_standalone(stage)),
"doc-nomicon" => targets.push(host.doc_nomicon(stage)),
"doc-book" => targets.push(host.doc_book(stage)),
"doc" => targets.push(host.doc(stage)),
_ => panic!("unknown build target: `{}`", step),
}
}
}
macro_rules! constructors {
($(($short:ident, $name:ident { $($arg:ident: $t:ty),* }),)*) => {$(
fn $short(&self, $($arg: $t),*) -> Step<'a> {
Step {
src: Source::$name { $($arg: $arg),* },
target: self.target,
}
}
)*}
}
impl<'a> Step<'a> {
fn compiler(&self, stage: u32) -> Compiler<'a> {
Compiler::new(stage, self.target)
}
fn target(&self, target: &'a str) -> Step<'a> {
Step { target: target, src: self.src.clone() }
}
targets!(constructors);
pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
match self.src {
Source::Rustc { stage: 0 } => {
Vec::new()
}
Source::Rustc { stage } => {
let compiler = Compiler::new(stage - 1, &build.config.build);
vec![self.librustc(stage - 1, compiler)]
}
Source::Librustc { stage, compiler } => {
vec![self.libstd(stage, compiler), self.llvm(())]
}
Source::Libstd { stage: _, compiler } => {
vec![self.compiler_rt(()),
self.rustc(compiler.stage).target(compiler.host)]
}
Source::LibrustcLink { stage, compiler, host } => {
vec![self.librustc(stage, compiler),
self.libstd_link(stage, compiler, host)]
}
Source::LibstdLink { stage, compiler, host } => {
vec![self.libstd(stage, compiler),
self.target(host).rustc(stage)]
}
Source::CompilerRt { _dummy } => {
vec![self.llvm(()).target(&build.config.build)]
}
Source::Llvm { _dummy } => Vec::new(),
Source::DocBook { stage } |
Source::DocNomicon { stage } |
Source::DocStyle { stage } |
Source::DocStandalone { stage } => {
vec![self.rustc(stage)]
}
Source::Doc { stage } => {
vec![self.doc_book(stage), self.doc_nomicon(stage),
self.doc_style(stage), self.doc_standalone(stage)]
}
}
}
}

View File

@ -0,0 +1,97 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::env;
use std::path::{Path, PathBuf};
use std::fs;
use std::process::Command;
use bootstrap::{dylib_path, dylib_path_var};
use filetime::FileTime;
pub fn staticlib(name: &str, target: &str) -> String {
if target.contains("windows-msvc") {
format!("{}.lib", name)
} else {
format!("lib{}.a", name)
}
}
pub fn mtime(path: &Path) -> FileTime {
fs::metadata(path).map(|f| {
FileTime::from_last_modification_time(&f)
}).unwrap_or(FileTime::zero())
}
#[allow(dead_code)] // this will be used soon
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() {
let _ = fs::remove_dir_all(&dst);
t!(fs::create_dir(&dst));
cp_r(&path, &dst);
} else {
let _ = fs::remove_file(&dst);
t!(fs::hard_link(&path, dst));
}
}
}
/// Given an executable called `name`, return the filename for the
/// executable for a particular target.
pub fn exe(name: &str, target: &str) -> String {
if target.contains("windows") {
format!("{}.exe", name)
} else {
name.to_string()
}
}
pub fn is_dylib(name: &str) -> bool {
name.ends_with(".dylib") || name.ends_with(".so") || name.ends_with(".dll")
}
pub fn libdir(target: &str) -> &'static str {
if target.contains("windows") {"bin"} else {"lib"}
}
pub fn add_lib_path(path: Vec<PathBuf>, cmd: &mut Command) {
let mut list = dylib_path();
for path in path {
list.insert(0, path);
}
cmd.env(dylib_path_var(), t!(env::join_paths(list)));
}
#[allow(dead_code)] // this will be used soon
pub fn up_to_date(src: &Path, dst: &Path) -> bool {
let threshold = mtime(dst);
let meta = t!(fs::metadata(src));
if meta.is_dir() {
dir_up_to_date(src, &threshold)
} else {
FileTime::from_last_modification_time(&meta) <= threshold
}
}
fn dir_up_to_date(src: &Path, threshold: &FileTime) -> 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
}
})
}

28
src/bootstrap/lib.rs Normal file
View File

@ -0,0 +1,28 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::env;
use std::ffi::OsString;
use std::path::PathBuf;
pub fn dylib_path_var() -> &'static str {
if cfg!(target_os = "windows") {
"PATH"
} else if cfg!(target_os = "macos") {
"DYLD_LIBRARY_PATH"
} else {
"LD_LIBRARY_PATH"
}
}
pub fn dylib_path() -> Vec<PathBuf> {
env::split_paths(&env::var_os(dylib_path_var()).unwrap_or(OsString::new()))
.collect()
}

38
src/bootstrap/main.rs Normal file
View File

@ -0,0 +1,38 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![deny(warnings)]
extern crate bootstrap;
extern crate build_helper;
extern crate cmake;
extern crate filetime;
extern crate gcc;
extern crate getopts;
extern crate libc;
extern crate num_cpus;
extern crate rustc_serialize;
extern crate toml;
use std::env;
use build::{Flags, Config, Build};
mod build;
fn main() {
let args = env::args().skip(1).collect::<Vec<_>>();
let flags = Flags::parse(&args);
let mut config = Config::parse(&flags.build, flags.config.clone());
if std::fs::metadata("config.mk").is_ok() {
config.update_with_config_mk();
}
Build::new(flags, config).build();
}

View File

@ -0,0 +1,38 @@
# Copyright 20126 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
include config.mk
include $(CFG_SRC_DIR)mk/util.mk
ifdef VERBOSE
BOOTSTRAP_ARGS := -v
else
BOOTSTRAP_ARGS :=
endif
BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py $(BOOTSTRAP_ARGS)
all:
$(Q)$(BOOTSTRAP)
clean:
$(Q)$(BOOTSTRAP) --clean
docs: doc
doc:
$(Q)$(BOOTSTRAP) --step doc
style:
$(Q)$(BOOTSTRAP) --step doc-style
nomicon:
$(Q)$(BOOTSTRAP) --step doc-nomicon
book:
$(Q)$(BOOTSTRAP) --step doc-book
standalone-docs:
$(Q)$(BOOTSTRAP) --step doc-standalone

91
src/bootstrap/rustc.rs Normal file
View File

@ -0,0 +1,91 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate bootstrap;
use std::env;
use std::ffi::OsString;
use std::path::PathBuf;
use std::process::Command;
fn main() {
let args = env::args_os().skip(1).collect::<Vec<_>>();
// Detect whether or not we're a build script depending on whether --target
// is passed (a bit janky...)
let is_build_script = args.iter()
.position(|i| i.to_str() == Some("--target"))
.is_none();
// Build scripts always use the snapshot compiler which is guaranteed to be
// able to produce an executable, whereas intermediate compilers may not
// have the standard library built yet and may not be able to produce an
// executable. Otherwise we just use the standard compiler we're
// bootstrapping with.
let rustc = if is_build_script {
env::var_os("RUSTC_SNAPSHOT").unwrap()
} else {
env::var_os("RUSTC_REAL").unwrap()
};
let mut cmd = Command::new(rustc);
cmd.args(&args)
.arg("--cfg").arg(format!("stage{}", env::var("RUSTC_STAGE").unwrap()));
if is_build_script {
// Build scripts are always built with the snapshot compiler, so we need
// to be sure to set up the right path information for the OS dynamic
// linker to find the libraries in question.
if let Some(p) = env::var_os("RUSTC_SNAPSHOT_LIBDIR") {
let mut path = bootstrap::dylib_path();
path.insert(0, PathBuf::from(p));
cmd.env(bootstrap::dylib_path_var(), env::join_paths(path).unwrap());
}
} else {
cmd.arg("--sysroot").arg(env::var_os("RUSTC_SYSROOT").unwrap());
// When we build Rust dylibs they're all intended for intermediate
// usage, so make sure we pass the -Cprefer-dynamic flag instead of
// linking all deps statically into the dylib.
cmd.arg("-Cprefer-dynamic");
if let Some(s) = env::var_os("MUSL_ROOT") {
let mut root = OsString::from("native=");
root.push(&s);
root.push("/lib");
cmd.arg("-L").arg(&root);
}
if let Ok(s) = env::var("RUSTC_FLAGS") {
cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::<Vec<_>>());
}
}
// Set various options from config.toml to configure how we're building
// code.
if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) {
cmd.arg("-g");
}
if env::var("RUSTC_RPATH") == Ok("true".to_string()) {
cmd.arg("-Crpath");
}
let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") {
Ok(s) => if s == "true" {"y"} else {"n"},
Err(..) => "n",
};
cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions));
if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") {
cmd.arg("-C").arg(format!("codegen-units={}", s));
}
// Actually run the compiler!
std::process::exit(match cmd.status() {
Ok(s) => s.code().unwrap_or(1),
Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),
})
}

View File

@ -0,0 +1,8 @@
[package]
name = "build_helper"
version = "0.1.0"
authors = ["The Rust Project Developers"]
[lib]
name = "build_helper"
path = "lib.rs"

68
src/build_helper/lib.rs Normal file
View File

@ -0,0 +1,68 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![deny(warnings)]
use std::process::{Command, Stdio};
use std::path::{Path, PathBuf};
pub fn run(cmd: &mut Command) {
println!("running: {:?}", cmd);
run_silent(cmd);
}
pub fn run_silent(cmd: &mut Command) {
let status = match cmd.status() {
Ok(status) => status,
Err(e) => fail(&format!("failed to execute command: {}", e)),
};
if !status.success() {
fail(&format!("command did not execute successfully: {:?}\n\
expected success, got: {}", cmd, status));
}
}
pub fn gnu_target(target: &str) -> String {
match target {
"i686-pc-windows-msvc" => "i686-pc-win32".to_string(),
"x86_64-pc-windows-msvc" => "x86_64-pc-win32".to_string(),
"i686-pc-windows-gnu" => "i686-w64-mingw32".to_string(),
"x86_64-pc-windows-gnu" => "x86_64-w64-mingw32".to_string(),
s => s.to_string(),
}
}
pub fn cc2ar(cc: &Path, target: &str) -> PathBuf {
if target.contains("musl") || target.contains("msvc") {
PathBuf::from("ar")
} else {
let file = cc.file_name().unwrap().to_str().unwrap();
cc.parent().unwrap().join(file.replace("gcc", "ar")
.replace("cc", "ar")
.replace("clang", "ar"))
}
}
pub fn output(cmd: &mut Command) -> String {
let output = match cmd.stderr(Stdio::inherit()).output() {
Ok(status) => status,
Err(e) => fail(&format!("failed to execute command: {}", e)),
};
if !output.status.success() {
panic!("command did not execute successfully: {:?}\n\
expected success, got: {}", cmd, output.status);
}
String::from_utf8(output.stdout).unwrap()
}
fn fail(s: &str) -> ! {
println!("\n\n{}\n\n", s);
std::process::exit(1);
}

View File

@ -25,6 +25,7 @@ pub enum Mode {
DebugInfoLldb,
Codegen,
Rustdoc,
CodegenUnits
}
impl FromStr for Mode {
@ -41,6 +42,7 @@ impl FromStr for Mode {
"debuginfo-gdb" => Ok(DebugInfoGdb),
"codegen" => Ok(Codegen),
"rustdoc" => Ok(Rustdoc),
"codegen-units" => Ok(CodegenUnits),
_ => Err(()),
}
}
@ -59,6 +61,7 @@ impl fmt::Display for Mode {
DebugInfoLldb => "debuginfo-lldb",
Codegen => "codegen",
Rustdoc => "rustdoc",
CodegenUnits => "codegen-units",
}, f)
}
}

View File

@ -28,10 +28,12 @@ extern crate log;
use std::env;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use getopts::{optopt, optflag, reqopt};
use common::Config;
use common::{Pretty, DebugInfoGdb, DebugInfoLldb};
use test::TestPaths;
use util::logv;
pub mod procsrv;
@ -267,15 +269,61 @@ pub fn make_tests(config: &Config) -> Vec<test::TestDescAndFn> {
debug!("making tests from {:?}",
config.src_base.display());
let mut tests = Vec::new();
let dirs = fs::read_dir(&config.src_base).unwrap();
for file in dirs {
let file = file.unwrap().path();
debug!("inspecting file {:?}", file.display());
if is_test(config, &file) {
tests.push(make_test(config, &file))
collect_tests_from_dir(config,
&config.src_base,
&config.src_base,
&PathBuf::new(),
&mut tests)
.unwrap();
tests
}
fn collect_tests_from_dir(config: &Config,
base: &Path,
dir: &Path,
relative_dir_path: &Path,
tests: &mut Vec<test::TestDescAndFn>)
-> io::Result<()> {
// Ignore directories that contain a file
// `compiletest-ignore-dir`.
for file in try!(fs::read_dir(dir)) {
let file = try!(file);
if file.file_name() == *"compiletest-ignore-dir" {
return Ok(());
}
}
tests
let dirs = try!(fs::read_dir(dir));
for file in dirs {
let file = try!(file);
let file_path = file.path();
debug!("inspecting file {:?}", file_path.display());
if is_test(config, &file_path) {
// If we find a test foo/bar.rs, we have to build the
// output directory `$build/foo` so we can write
// `$build/foo/bar` into it. We do this *now* in this
// sequential loop because otherwise, if we do it in the
// tests themselves, they race for the privilege of
// creating the directories and sometimes fail randomly.
let build_dir = config.build_base.join(&relative_dir_path);
fs::create_dir_all(&build_dir).unwrap();
let paths = TestPaths {
file: file_path,
base: base.to_path_buf(),
relative_dir: relative_dir_path.to_path_buf(),
};
tests.push(make_test(config, &paths))
} else if file_path.is_dir() {
let relative_file_path = relative_dir_path.join(file.file_name());
try!(collect_tests_from_dir(config,
base,
&file_path,
&relative_file_path,
tests));
}
}
Ok(())
}
pub fn is_test(config: &Config, testfile: &Path) -> bool {
@ -305,36 +353,33 @@ pub fn is_test(config: &Config, testfile: &Path) -> bool {
return valid;
}
pub fn make_test(config: &Config, testfile: &Path) -> test::TestDescAndFn
{
pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn {
test::TestDescAndFn {
desc: test::TestDesc {
name: make_test_name(config, testfile),
ignore: header::is_test_ignored(config, testfile),
name: make_test_name(config, testpaths),
ignore: header::is_test_ignored(config, &testpaths.file),
should_panic: test::ShouldPanic::No,
},
testfn: make_test_closure(config, &testfile),
testfn: make_test_closure(config, testpaths),
}
}
pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName {
// Try to elide redundant long paths
fn shorten(path: &Path) -> String {
let filename = path.file_name().unwrap().to_str();
let p = path.parent().unwrap();
let dir = p.file_name().unwrap().to_str();
format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
}
test::DynTestName(format!("[{}] {}", config.mode, shorten(testfile)))
pub fn make_test_name(config: &Config, testpaths: &TestPaths) -> test::TestName {
// Convert a complete path to something like
//
// run-pass/foo/bar/baz.rs
let path =
PathBuf::from(config.mode.to_string())
.join(&testpaths.relative_dir)
.join(&testpaths.file.file_name().unwrap());
test::DynTestName(format!("[{}] {}", config.mode, path.display()))
}
pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
let config = (*config).clone();
let testfile = testfile.to_path_buf();
pub fn make_test_closure(config: &Config, testpaths: &TestPaths) -> test::TestFn {
let config = config.clone();
let testpaths = testpaths.clone();
test::DynTestFn(Box::new(move || {
runtest::run(config, &testfile)
runtest::run(config, &testpaths)
}))
}

File diff suppressed because it is too large Load Diff

View File

@ -25,6 +25,8 @@ const OS_TABLE: &'static [(&'static str, &'static str)] = &[
("openbsd", "openbsd"),
("win32", "windows"),
("windows", "windows"),
("solaris", "solaris"),
("emscripten", "emscripten"),
];
const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[
@ -39,11 +41,11 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[
("msp430", "msp430"),
("powerpc", "powerpc"),
("powerpc64", "powerpc64"),
("powerpc64le", "powerpc64le"),
("s390x", "systemz"),
("sparc", "sparc"),
("x86_64", "x86_64"),
("xcore", "xcore"),
("asmjs", "asmjs"),
];
pub fn get_os(triple: &str) -> &'static str {

View File

@ -80,3 +80,4 @@ Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work
Rust](http://munksgaard.me/papers/laumann-munksgaard-larsen.pdf). Philip
Munksgaard's master's thesis. Research for Servo.
* [Ownership is Theft: Experiences Building an Embedded OS in Rust - Amit Levy, et. al.](http://amitlevy.com/papers/tock-plos2015.pdf)
* [You can't spell trust without Rust](https://raw.githubusercontent.com/Gankro/thesis/master/thesis.pdf). Alexis Beingessner's master's thesis.

View File

@ -259,7 +259,7 @@ thread::spawn(move || {
```
First, we call `lock()`, which acquires the mutex's lock. Because this may fail,
it returns an `Result<T, E>`, and because this is just an example, we `unwrap()`
it returns a `Result<T, E>`, and because this is just an example, we `unwrap()`
it to get a reference to the data. Real code would have more robust error handling
here. We're then free to mutate it, since we have the lock.
@ -286,6 +286,8 @@ use std::sync::mpsc;
fn main() {
let data = Arc::new(Mutex::new(0));
// `tx` is the "transmitter" or "sender"
// `rx` is the "receiver"
let (tx, rx) = mpsc::channel();
for _ in 0..10 {

View File

@ -64,16 +64,16 @@ unsafe {
[unsafe]: unsafe.html
Furthermore, any type stored in a `static` must be `Sync`, and may not have
Furthermore, any type stored in a `static` must be `Sync`, and must not have
a [`Drop`][drop] implementation.
[drop]: drop.html
# Initializing
Both `const` and `static` have requirements for giving them a value. They may
only be given a value thats a constant expression. In other words, you cannot
use the result of a function call or anything similarly complex or at runtime.
Both `const` and `static` have requirements for giving them a value. They must
be given a value thats a constant expression. In other words, you cannot use
the result of a function call or anything similarly complex or at runtime.
# Which construct should I use?

View File

@ -567,10 +567,11 @@ to it as "sayings". Similarly, the first `use` statement pulls in the
`ja_greetings` as opposed to simply `greetings`. This can help to avoid
ambiguity when importing similarly-named items from different places.
The second `use` statement uses a star glob to bring in _all_ symbols from the
`sayings::japanese::farewells` module. As you can see we can later refer to
The second `use` statement uses a star glob to bring in all public symbols from
the `sayings::japanese::farewells` module. As you can see we can later refer to
the Japanese `goodbye` function with no module qualifiers. This kind of glob
should be used sparingly.
should be used sparingly. Its worth noting that it only imports the public
symbols, even if the code doing the globbing is in the same module.
The third `use` statement bears more explanation. It's using "brace expansion"
globbing to compress three `use` statements into one (this sort of syntax

View File

@ -118,7 +118,7 @@ least. If your function has a non-trivial contract like this, that is
detected/enforced by panics, documenting it is very important.
```rust
/// # Failures
/// # Errors
# fn foo() {}
```
@ -319,7 +319,7 @@ our source code:
```text
First, we set `x` to five:
```text
```rust
let x = 5;
# let y = 6;
# println!("{}", x + y);
@ -327,7 +327,7 @@ our source code:
Next, we set `y` to six:
```text
```rust
# let x = 5;
let y = 6;
# println!("{}", x + y);
@ -335,7 +335,7 @@ our source code:
Finally, we print the sum of `x` and `y`:
```text
```rust
# let x = 5;
# let y = 6;
println!("{}", x + y);

View File

@ -265,6 +265,8 @@ fn map<F, T, A>(option: Option<T>, f: F) -> Option<A> where F: FnOnce(T) -> A {
```
Indeed, `map` is [defined as a method][2] on `Option<T>` in the standard library.
As a method, it has a slightly different signature: methods take `self`, `&self`,
or `&mut self` as their first argument.
Armed with our new combinator, we can rewrite our `extension_explicit` method
to get rid of the case analysis:
@ -294,6 +296,9 @@ fn unwrap_or<T>(option: Option<T>, default: T) -> T {
}
```
Like with `map` above, the standard library implementation is a method instead
of a free function.
The trick here is that the default value must have the same type as the value
that might be inside the `Option<T>`. Using it is dead simple in our case:
@ -351,11 +356,28 @@ fn file_name(file_path: &str) -> Option<&str> {
```
You might think that we could use the `map` combinator to reduce the case
analysis, but its type doesn't quite fit. Namely, `map` takes a function that
does something only with the inner value. The result of that function is then
*always* [rewrapped with `Some`](#code-option-map). Instead, we need something
like `map`, but which allows the caller to return another `Option`. Its generic
implementation is even simpler than `map`:
analysis, but its type doesn't quite fit...
```rust,ignore
fn file_path_ext(file_path: &str) -> Option<&str> {
file_name(file_path).map(|x| extension(x)) //Compilation error
}
```
The `map` function here wraps the value returned by the `extension` function
inside an `Option<_>` and since the `extension` function itself returns an
`Option<&str>` the expression `file_name(file_path).map(|x| extension(x))`
actually returns an `Option<Option<&str>>`.
But since `file_path_ext` just returns `Option<&str>` (and not
`Option<Option<&str>>`) we get a compilation error.
The result of the function taken by map as input is *always* [rewrapped with
`Some`](#code-option-map). Instead, we need something like `map`, but which
allows the caller to return a `Option<_>` directly without wrapping it in
another `Option<_>`.
Its generic implementation is even simpler than `map`:
```rust
fn and_then<F, T, A>(option: Option<T>, f: F) -> Option<A>
@ -377,6 +399,10 @@ fn file_path_ext(file_path: &str) -> Option<&str> {
}
```
Side note: Since `and_then` essentially works like `map` but returns an
`Option<_>` instead of an `Option<Option<_>>` it is known as `flatmap` in some
other languages.
The `Option` type has many other combinators [defined in the standard
library][5]. It is a good idea to skim this list and familiarize
yourself with what's available—they can often reduce case analysis
@ -1512,7 +1538,7 @@ and [`rustc-serialize`](https://crates.io/crates/rustc-serialize) crates.
We're not going to spend a lot of time on setting up a project with
Cargo because it is already covered well in [the Cargo
section](../book/hello-cargo.html) and [Cargo's documentation][14].
section](getting-started.html#hello-cargo) and [Cargo's documentation][14].
To get started from scratch, run `cargo new --bin city-pop` and make sure your
`Cargo.toml` looks something like this:
@ -1566,7 +1592,7 @@ fn print_usage(program: &str, opts: Options) {
fn main() {
let args: Vec<String> = env::args().collect();
let program = args[0].clone();
let program = &args[0];
let mut opts = Options::new();
opts.optflag("h", "help", "Show this usage message.");
@ -1579,10 +1605,10 @@ fn main() {
print_usage(&program, opts);
return;
}
let data_path = args[1].clone();
let city = args[2].clone();
let data_path = &args[1];
let city = &args[2];
// Do stuff with information
// Do stuff with information
}
```
@ -1614,7 +1640,6 @@ sure to add `extern crate csv;` to the top of your file.)
```rust,ignore
use std::fs::File;
use std::path::Path;
// This struct represents the data in each row of the CSV file.
// Type based decoding absolves us of a lot of the nitty gritty error
@ -1640,7 +1665,7 @@ fn print_usage(program: &str, opts: Options) {
fn main() {
let args: Vec<String> = env::args().collect();
let program = args[0].clone();
let program = &args[0];
let mut opts = Options::new();
opts.optflag("h", "help", "Show this usage message.");
@ -1652,25 +1677,24 @@ fn main() {
if matches.opt_present("h") {
print_usage(&program, opts);
return;
}
return;
}
let data_file = args[1].clone();
let data_path = Path::new(&data_file);
let city = args[2].clone();
let data_path = &args[1];
let city: &str = &args[2];
let file = File::open(data_path).unwrap();
let mut rdr = csv::Reader::from_reader(file);
let file = File::open(data_path).unwrap();
let mut rdr = csv::Reader::from_reader(file);
for row in rdr.decode::<Row>() {
let row = row.unwrap();
for row in rdr.decode::<Row>() {
let row = row.unwrap();
if row.city == city {
println!("{}, {}: {:?}",
row.city, row.country,
row.population.expect("population count"));
}
}
if row.city == city {
println!("{}, {}: {:?}",
row.city, row.country,
row.population.expect("population count"));
}
}
}
```
@ -1719,6 +1743,8 @@ Note that we opt to handle the possibility of a missing population count by
simply ignoring that row.
```rust,ignore
use std::path::Path;
struct Row {
// unchanged
}
@ -1756,27 +1782,26 @@ fn search<P: AsRef<Path>>(file_path: P, city: &str) -> Vec<PopulationCount> {
}
fn main() {
let args: Vec<String> = env::args().collect();
let program = args[0].clone();
let args: Vec<String> = env::args().collect();
let program = &args[0];
let mut opts = Options::new();
opts.optflag("h", "help", "Show this usage message.");
let mut opts = Options::new();
opts.optflag("h", "help", "Show this usage message.");
let matches = match opts.parse(&args[1..]) {
Ok(m) => { m }
Err(e) => { panic!(e.to_string()) }
};
if matches.opt_present("h") {
print_usage(&program, opts);
return;
}
let matches = match opts.parse(&args[1..]) {
Ok(m) => { m }
Err(e) => { panic!(e.to_string()) }
};
if matches.opt_present("h") {
print_usage(&program, opts);
return;
}
let data_file = args[1].clone();
let data_path = Path::new(&data_file);
let city = args[2].clone();
for pop in search(&data_path, &city) {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
}
let data_path = &args[1];
let city = &args[2];
for pop in search(data_path, city) {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
}
}
```
@ -1886,7 +1911,7 @@ First, here's the new usage:
```rust,ignore
fn print_usage(program: &str, opts: Options) {
println!("{}", opts.usage(&format!("Usage: {} [options] <city>", program)));
println!("{}", opts.usage(&format!("Usage: {} [options] <city>", program)));
}
```
The next part is going to be only a little harder:
@ -1898,16 +1923,16 @@ opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME"
opts.optflag("h", "help", "Show this usage message.");
...
let file = matches.opt_str("f");
let data_file = file.as_ref().map(Path::new);
let data_file = &file.as_ref().map(Path::new);
let city = if !matches.free.is_empty() {
matches.free[0].clone()
&matches.free[0]
} else {
print_usage(&program, opts);
return;
print_usage(&program, opts);
return;
};
match search(&data_file, &city) {
match search(data_file, city) {
Ok(pops) => {
for pop in pops {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);

View File

@ -68,7 +68,7 @@ You get this error:
```text
expected one of `!`, `:`, or `@`, found `)`
fn print_number(x, y) {
fn print_sum(x, y) {
```
This is a deliberate design decision. While full-program inference is possible,

View File

@ -39,6 +39,7 @@ Specifically they will each satisfy the following requirements:
| Target | std |rustc|cargo| notes |
|-------------------------------|-----|-----|-----|----------------------------|
| `i686-pc-windows-msvc` | ✓ | ✓ | ✓ | 32-bit MSVC (Windows 7+) |
| `x86_64-pc-windows-msvc` | ✓ | ✓ | ✓ | 64-bit MSVC (Windows 7+) |
| `i686-pc-windows-gnu` | ✓ | ✓ | ✓ | 32-bit MinGW (Windows 7+) |
| `x86_64-pc-windows-gnu` | ✓ | ✓ | ✓ | 64-bit MinGW (Windows 7+) |
@ -62,7 +63,6 @@ these platforms are required to have each of the following:
| Target | std |rustc|cargo| notes |
|-------------------------------|-----|-----|-----|----------------------------|
| `i686-pc-windows-msvc` | ✓ | ✓ | ✓ | 32-bit MSVC (Windows 7+) |
| `x86_64-unknown-linux-musl` | ✓ | | | 64-bit Linux with MUSL |
| `arm-linux-androideabi` | ✓ | | | ARM Android |
| `arm-unknown-linux-gnueabi` | ✓ | ✓ | | ARM Linux (2.6.18+) |
@ -85,6 +85,9 @@ unofficial locations.
| `i686-linux-android` | ✓ | | | 32-bit x86 Android |
| `aarch64-linux-android` | ✓ | | | ARM64 Android |
| `powerpc-unknown-linux-gnu` | ✓ | | | PowerPC Linux (2.6.18+) |
| `powerpc64-unknown-linux-gnu` | ✓ | | | PPC64 Linux (2.6.18+) |
|`powerpc64le-unknown-linux-gnu`| ✓ | | | PPC64LE Linux (2.6.18+) |
|`armv7-unknown-linux-gnueabihf`| ✓ | | | ARMv7 Linux (2.6.18+) |
| `i386-apple-ios` | ✓ | | | 32-bit x86 iOS |
| `x86_64-apple-ios` | ✓ | | | 64-bit x86 iOS |
| `armv7-apple-ios` | ✓ | | | ARM iOS |
@ -97,6 +100,7 @@ unofficial locations.
| `x86_64-unknown-bitrig` | ✓ | ✓ | | 64-bit Bitrig |
| `x86_64-unknown-dragonfly` | ✓ | ✓ | | 64-bit DragonFlyBSD |
| `x86_64-rumprun-netbsd` | ✓ | | | 64-bit NetBSD Rump Kernel |
| `x86_64-sun-solaris` | ✓ | ✓ | | 64-bit Solaris/SunOS |
| `i686-pc-windows-msvc` (XP) | ✓ | | | Windows XP support |
| `x86_64-pc-windows-msvc` (XP) | ✓ | | | Windows XP support |
@ -111,7 +115,7 @@ If we're on Linux or a Mac, all we need to do is open a terminal and type this:
$ curl -sSf https://static.rust-lang.org/rustup.sh | sh
```
This will download a script, and stat the installation. If it all goes well,
This will download a script, and start the installation. If it all goes well,
youll see this appear:
```text
@ -167,6 +171,10 @@ variable. If it isn't, run the installer again, select "Change" on the "Change,
repair, or remove installation" page and ensure "Add to PATH" is installed on
the local hard drive.
Rust does not do its own linking, and so youll need to have a linker
installed. Doing so will depend on your specific system, consult its
documentation for more details.
If not, there are a number of places where we can get help. The easiest is
[the #rust IRC channel on irc.mozilla.org][irc], which we can access through
[Mibbit][mibbit]. Click that link, and we'll be chatting with other Rustaceans
@ -511,15 +519,17 @@ programming languages. For complex projects composed of multiple crates, its
much easier to let Cargo coordinate the build. Using Cargo, you can run `cargo
build`, and it should work the right way.
## Building for Release
### Building for Release
When your project is finally ready for release, you can use `cargo build
When your project is ready for release, you can use `cargo build
--release` to compile your project with optimizations. These optimizations make
your Rust code run faster, but turning them on makes your program take longer
to compile. This is why there are two different profiles, one for development,
and one for building the final program youll give to a user.
Running this command also causes Cargo to create a new file called
### What Is That `Cargo.lock`?
Running `cargo build` also causes Cargo to create a new file called
*Cargo.lock*, which looks like this:
```toml
@ -563,7 +573,7 @@ executable application, as opposed to a library. Executables are often called
*binaries* (as in `/usr/bin`, if youre on a Unix system).
Cargo has generated two files and one directory for us: a `Cargo.toml` and a
*src* directory with a *main.rs* file inside. These should look familliar,
*src* directory with a *main.rs* file inside. These should look familiar,
theyre exactly what we created by hand, above.
This output is all you need to get started. First, open `Cargo.toml`. It should
@ -602,11 +612,11 @@ This chapter covered the basics that will serve you well through the rest of
this book, and the rest of your time with Rust. Now that youve got the tools
down, we'll cover more about the Rust language itself.
You have two options: Dive into a project with [Learn Rust][learnrust], or
You have two options: Dive into a project with [Tutorial: Guessing Game][guessinggame], or
start from the bottom and work your way up with [Syntax and
Semantics][syntax]. More experienced systems programmers will probably prefer
Learn Rust, while those from dynamic backgrounds may enjoy either. Different
Tutorial: Guessing Game, while those from dynamic backgrounds may enjoy either. Different
people learn differently! Choose whatevers right for you.
[learnrust]: learn-rust.html
[guessinggame]: guessing-game.html
[syntax]: syntax-and-semantics.html

View File

@ -258,7 +258,7 @@ done:
io::stdin().read_line(&mut guess).expect("failed to read line");
```
But that gets hard to read. So weve split it up, three lines for three method
But that gets hard to read. So weve split it up, two lines for two method
calls. We already talked about `read_line()`, but what about `expect()`? Well,
we already mentioned that `read_line()` puts what the user types into the `&mut
String` we pass it. But it also returns a value: in this case, an
@ -276,10 +276,10 @@ its called on, and if it isnt a successful one, [`panic!`][panic]s with a
message you passed it. A `panic!` like this will cause our program to crash,
displaying the message.
[expect]: ../std/option/enum.Option.html#method.expect
[expect]: ../std/result/enum.Result.html#method.expect
[panic]: error-handling.html
If we leave off calling these two methods, our program will compile, but
If we leave off calling this method, our program will compile, but
well get a warning:
```bash
@ -644,7 +644,7 @@ So far, that hasnt mattered, and so Rust defaults to an `i32`. However, here,
Rust doesnt know how to compare the `guess` and the `secret_number`. They
need to be the same type. Ultimately, we want to convert the `String` we
read as input into a real number type, for comparison. We can do that
with three more lines. Heres our new program:
with two more lines. Heres our new program:
```rust,ignore
extern crate rand;
@ -680,7 +680,7 @@ fn main() {
}
```
The new three lines:
The new two lines:
```rust,ignore
let guess: u32 = guess.trim().parse()
@ -906,16 +906,17 @@ let guess: u32 = match guess.trim().parse() {
Err(_) => continue,
};
```
This is how you generally move from crash on error to actually handle the
returned by `parse()` is an `enum` like `Ordering`, but in this case, each
variant has some data associated with it: `Ok` is a success, and `Err` is a
error, by switching from `expect()` to a `match` statement. A `Result` is
returned by `parse()`, this is an `enum` like `Ordering`, but in this case,
each variant has some data associated with it: `Ok` is a success, and `Err` is a
failure. Each contains more information: the successfully parsed integer, or an
error type. In this case, we `match` on `Ok(num)`, which sets the inner value
of the `Ok` to the name `num`, and then we return it on the right-hand
side. In the `Err` case, we dont care what kind of error it is, so we
use `_` instead of a name. This ignores the error, and `continue` causes us
to go to the next iteration of the `loop`.
error type. In this case, we `match` on `Ok(num)`, which sets the name `num` to
the unwrapped `Ok` value (ythe integer), and then we return it on the
right-hand side. In the `Err` case, we dont care what kind of error it is, so
we just use the catch all `_` instead of a name. This catches everything that
isn't `Ok`, and `continue` lets us move to the next iteration of the loop; in
effect, this enables us to ignore all errors and continue with our program.
Now we should be good! Lets try:

View File

@ -311,10 +311,12 @@ for i in (1..100).filter(|&x| x % 2 == 0) {
```
This will print all of the even numbers between one and a hundred.
(Note that because `filter` doesn't consume the elements that are
being iterated over, it is passed a reference to each element, and
thus the filter predicate uses the `&x` pattern to extract the integer
itself.)
(Note that, unlike `map`, the closure passed to `filter` is passed a reference
to the element instead of the element itself. The filter predicate here uses
the `&x` pattern to extract the integer. The filter closure is passed a
reference because it returns `true` or `false` instead of the element,
so the `filter` implementation must retain ownership to put the elements
into the newly constructed iterator.)
You can chain all three things together: start with an iterator, adapt it
a few times, and then consume the result. Check it out:

View File

@ -39,11 +39,17 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
p
}
#[lang = "exchange_free"]
unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
libc::free(ptr as *mut libc::c_void)
}
#[lang = "box_free"]
unsafe fn box_free<T>(ptr: *mut T) {
deallocate(ptr as *mut u8, ::core::mem::size_of::<T>(), ::core::mem::align_of::<T>());
}
#[start]
fn main(argc: isize, argv: *const *const u8) -> isize {
let x = box 1;

View File

@ -1,9 +0,0 @@
% Learn Rust
Welcome! This chapter has a few tutorials that teach you Rust through building
projects. Youll get a high-level overview, but well skim over the details.
If youd prefer a more from the ground up-style experience, check
out [Syntax and Semantics][ss].
[ss]: syntax-and-semantics.html

View File

@ -125,7 +125,8 @@ Don't forget to add the parentheses around the range.
#### On iterators:
```rust
# let lines = "hello\nworld".lines();
let lines = "hello\nworld".lines();
for (linenumber, line) in lines.enumerate() {
println!("{}: {}", linenumber, line);
}
@ -134,10 +135,8 @@ for (linenumber, line) in lines.enumerate() {
Outputs:
```text
0: Content of line one
1: Content of line two
2: Content of line three
3: Content of line four
0: hello
1: world
```
## Ending iteration early
@ -195,7 +194,7 @@ for x in 0..10 {
You may also encounter situations where you have nested loops and need to
specify which one your `break` or `continue` statement is for. Like most
other languages, by default a `break` or `continue` will apply to innermost
loop. In a situation where you would like to a `break` or `continue` for one
loop. In a situation where you would like to `break` or `continue` for one
of the outer loops, you can use labels to specify which loop the `break` or
`continue` statement applies to. This will only print when both `x` and `y` are
odd:

View File

@ -77,10 +77,11 @@ The compiler currently makes a few assumptions about symbols which are available
in the executable to call. Normally these functions are provided by the standard
library, but without it you must define your own.
The first of these two functions, `eh_personality`, is used by the
failure mechanisms of the compiler. This is often mapped to GCC's
personality function (see the
[libstd implementation](../std/rt/unwind/index.html) for more
information), but crates which do not trigger a panic can be assured
that this function is never called. The second function, `panic_fmt`, is
also used by the failure mechanisms of the compiler.
The first of these two functions, `eh_personality`, is used by the failure
mechanisms of the compiler. This is often mapped to GCC's personality function
(see the [libstd implementation][unwind] for more information), but crates
which do not trigger a panic can be assured that this function is never
called. The second function, `panic_fmt`, is also used by the failure
mechanisms of the compiler.
[unwind]: https://github.com/rust-lang/rust/blob/master/src/libstd/sys/common/unwind/gcc.rs

View File

@ -51,10 +51,11 @@ fn foo() {
}
```
When `v` comes into scope, a new [vector] is created, and it allocates space on
[the heap][heap] for each of its elements. When `v` goes out of scope at the
end of `foo()`, Rust will clean up everything related to the vector, even the
heap-allocated memory. This happens deterministically, at the end of the scope.
When `v` comes into scope, a new [vector] is created on [the stack][stack],
and it allocates space on [the heap][heap] for its elements. When `v` goes out
of scope at the end of `foo()`, Rust will clean up everything related to the
vector, even the heap-allocated memory. This happens deterministically, at the
end of the scope.
We'll cover [vectors] in detail later in this chapter; we only use them
here as an example of a type that allocates space on the heap at runtime. They
@ -67,6 +68,7 @@ Vectors have a [generic type][generics] `Vec<T>`, so in this example `v` will ha
[arrays]: primitive-types.html#arrays
[vectors]: vectors.html
[heap]: the-stack-and-the-heap.html
[stack]: the-stack-and-the-heap.html#the-stack
[bindings]: variable-bindings.html
[generics]: generics.html
@ -122,21 +124,65 @@ special annotation here, its the default thing that Rust does.
## The details
The reason that we cannot use a binding after weve moved it is subtle, but
important. When we write code like this:
important.
When we write code like this:
```rust
let x = 10;
```
Rust allocates memory for an integer [i32] on the [stack][sh], copies the bit
pattern representing the value of 10 to the allocated memory and binds the
variable name x to this memory region for future reference.
Now consider the following code fragment:
```rust
let v = vec![1, 2, 3];
let v2 = v;
let mut v2 = v;
```
The first line allocates memory for the vector object, `v`, and for the data it
contains. The vector object is stored on the [stack][sh] and contains a pointer
to the content (`[1, 2, 3]`) stored on the [heap][sh]. When we move `v` to `v2`,
it creates a copy of that pointer, for `v2`. Which means that there would be two
pointers to the content of the vector on the heap. It would violate Rusts
safety guarantees by introducing a data race. Therefore, Rust forbids using `v`
after weve done the move.
The first line allocates memory for the vector object `v` on the stack like
it does for `x` above. But in addition to that it also allocates some memory
on the [heap][sh] for the actual data (`[1, 2, 3]`). Rust copies the address
of this heap allocation to an internal pointer, which is part of the vector
object placed on the stack (let's call it the data pointer).
It is worth pointing out (even at the risk of stating the obvious) that the
vector object and its data live in separate memory regions instead of being a
single contiguous memory allocation (due to reasons we will not go into at
this point of time). These two parts of the vector (the one on the stack and
one on the heap) must agree with each other at all times with regards to
things like the length, capacity etc.
When we move `v` to `v2`, Rust actually does a bitwise copy of the vector
object `v` into the stack allocation represented by `v2`. This shallow copy
does not create a copy of the heap allocation containing the actual data.
Which means that there would be two pointers to the contents of the vector
both pointing to the same memory allocation on the heap. It would violate
Rusts safety guarantees by introducing a data race if one could access both
`v` and `v2` at the same time.
For example if we truncated the vector to just two elements through `v2`:
```rust
# let v = vec![1, 2, 3];
# let mut v2 = v;
v2.truncate(2);
```
and `v1` were still accessible we'd end up with an invalid vector since `v1`
would not know that the heap data has been truncated. Now, the part of the
vector `v1` on the stack does not agree with the corresponding part on the
heap. `v1` still thinks there are three elements in the vector and will
happily let us access the non existent element `v1[2]` but as you might
already know this is a recipe for disaster. Especially because it might lead
to a segmentation fault or worse allow an unauthorized user to read from
memory to which they don't have access.
This is why Rust forbids using `v` after weve done the move.
[sh]: the-stack-and-the-heap.html

View File

@ -173,7 +173,39 @@ let (x, _, z) = coordinate();
Here, we bind the first and last element of the tuple to `x` and `z`, but
ignore the middle element.
Similarly, you can use `..` in a pattern to disregard multiple values.
Its worth noting that using `_` never binds the value in the first place,
which means a value may not move:
```rust
let tuple: (u32, String) = (5, String::from("five"));
// Here, tuple is moved, because the String moved:
let (x, _s) = tuple;
// The next line would give "error: use of partially moved value: `tuple`"
// println!("Tuple is: {:?}", tuple);
// However,
let tuple = (5, String::from("five"));
// Here, tuple is _not_ moved, as the String was never moved, and u32 is Copy:
let (x, _) = tuple;
// That means this works:
println!("Tuple is: {:?}", tuple);
```
This also means that any temporary variables will be dropped at the end of the
statement:
```rust
// Here, the String created will be dropped immediately, as its not bound:
let _ = String::from(" hello ").trim();
```
You can also use `..` in a pattern to disregard multiple values:
```rust
enum OptionalTuple {
@ -271,7 +303,7 @@ struct Person {
}
let name = "Steve".to_string();
let mut x: Option<Person> = Some(Person { name: Some(name) });
let x: Option<Person> = Some(Person { name: Some(name) });
match x {
Some(Person { name: ref a @ Some(_), .. }) => println!("{:?}", a),
_ => {}

View File

@ -164,6 +164,9 @@ copying. For example, you might want to reference only one line of a file read
into memory. By nature, a slice is not created directly, but from an existing
variable binding. Slices have a defined length, can be mutable or immutable.
Internally, slices are represented as a pointer to the beginning of the data
and a length.
## Slicing syntax
You can use a combo of `&` and `[]` to create a slice from various things. The

View File

@ -39,7 +39,7 @@ The second, with a `\`, trims the spaces and the newline:
```rust
let s = "foo\
bar";
bar";
assert_eq!("foobar", s);
```

View File

@ -2,7 +2,7 @@
## Keywords
* `as`: primitive casting. See [Casting Between Types (`as`)].
* `as`: primitive casting, or disambiguating the specific trait containing an item. See [Casting Between Types (`as`)], [Universal Function Call Syntax (Angle-bracket Form)], [Associated Types].
* `break`: break out of loop. See [Loops (Ending Iteration Early)].
* `const`: constant items and constant raw pointers. See [`const` and `static`], [Raw Pointers].
* `continue`: continue to next loop iteration. See [Loops (Ending Iteration Early)].
@ -115,8 +115,11 @@
* `::path`: path relative to the crate root (*i.e.* an explicitly absolute path). See [Crates and Modules (Re-exporting with `pub use`)].
* `self::path`: path relative to the current module (*i.e.* an explicitly relative path). See [Crates and Modules (Re-exporting with `pub use`)].
* `super::path`: path relative to the parent of the current module. See [Crates and Modules (Re-exporting with `pub use`)].
* `type::ident`: associated constants, functions, and types. See [Associated Types].
* `type::ident`, `<type as trait>::ident`: associated constants, functions, and types. See [Associated Types].
* `<type>::…`: associated item for a type which cannot be directly named (*e.g.* `<&T>::…`, `<[T]>::…`, *etc.*). See [Associated Types].
* `trait::method(…)`: disambiguating a method call by naming the trait which defines it. See [Universal Function Call Syntax].
* `type::method(…)`: disambiguating a method call by naming the type for which it's defined. See [Universal Function Call Syntax].
* `<type as trait>::method(…)`: disambiguating a method call by naming the trait _and_ type. See [Universal Function Call Syntax (Angle-bracket Form)].
<!-- Generics -->
@ -132,7 +135,8 @@
<!-- Constraints -->
* `T: U`: generic parameter `T` constrained to types that implement `U`. See [Traits].
* `T: 'a`: generic type `T` must outlive lifetime `'a`.
* `T: 'a`: generic type `T` must outlive lifetime `'a`. When we say that a type 'outlives' the lifetime, we mean that it cannot transitively contain any references with lifetimes shorter than `'a`.
* `T : 'static`: The generic type `T` contains no borrowed references other than `'static` ones.
* `'b: 'a`: generic lifetime `'b` must outlive lifetime `'a`.
* `T: ?Sized`: allow generic type parameter to be a dynamically-sized type. See [Unsized Types (`?Sized`)].
* `'a + trait`, `trait + trait`: compound type constraint. See [Traits (Multiple Trait Bounds)].
@ -234,6 +238,8 @@
[Traits (`where` clause)]: traits.html#where-clause
[Traits (Multiple Trait Bounds)]: traits.html#multiple-trait-bounds
[Traits]: traits.html
[Universal Function Call Syntax]: ufcs.html
[Universal Function Call Syntax (Angle-bracket Form)]: ufcs.html#angle-bracket-form
[Unsafe]: unsafe.html
[Unsized Types (`?Sized`)]: unsized-types.html#sized
[Variable Bindings]: variable-bindings.html

View File

@ -24,6 +24,7 @@ Cargo will automatically generate a simple test when you make a new project.
Here's the contents of `src/lib.rs`:
```rust
# fn main() {}
#[test]
fn it_works() {
}
@ -75,6 +76,7 @@ So why does our do-nothing test pass? Any test which doesn't `panic!` passes,
and any test that does `panic!` fails. Let's make our test fail:
```rust
# fn main() {}
#[test]
fn it_works() {
assert!(false);
@ -145,6 +147,7 @@ This is useful if you want to integrate `cargo test` into other tooling.
We can invert our test's failure with another attribute: `should_panic`:
```rust
# fn main() {}
#[test]
#[should_panic]
fn it_works() {
@ -175,6 +178,7 @@ Rust provides another macro, `assert_eq!`, that compares two arguments for
equality:
```rust
# fn main() {}
#[test]
#[should_panic]
fn it_works() {
@ -209,6 +213,7 @@ make sure that the failure message contains the provided text. A safer version
of the example above would be:
```rust
# fn main() {}
#[test]
#[should_panic(expected = "assertion failed")]
fn it_works() {
@ -219,6 +224,7 @@ fn it_works() {
That's all there is to the basics! Let's write one 'real' test:
```rust,ignore
# fn main() {}
pub fn add_two(a: i32) -> i32 {
a + 2
}
@ -238,6 +244,7 @@ Sometimes a few specific tests can be very time-consuming to execute. These
can be disabled by default by using the `ignore` attribute:
```rust
# fn main() {}
#[test]
fn it_works() {
assert_eq!(4, add_two(2));
@ -299,6 +306,7 @@ missing the `tests` module. The idiomatic way of writing our example
looks like this:
```rust,ignore
# fn main() {}
pub fn add_two(a: i32) -> i32 {
a + 2
}
@ -327,6 +335,7 @@ a large module, and so this is a common use of globs. Let's change our
`src/lib.rs` to make use of it:
```rust,ignore
# fn main() {}
pub fn add_two(a: i32) -> i32 {
a + 2
}
@ -377,6 +386,7 @@ put a `tests/lib.rs` file inside, with this as its contents:
```rust,ignore
extern crate adder;
# fn main() {}
#[test]
fn it_works() {
assert_eq!(4, adder::add_two(2));
@ -432,6 +442,7 @@ running examples in your documentation (**note:** this only works in library
crates, not binary crates). Here's a fleshed-out `src/lib.rs` with examples:
```rust,ignore
# fn main() {}
//! The `adder` crate provides functions that add numbers to other numbers.
//!
//! # Examples

View File

@ -277,16 +277,22 @@ This will compile without error.
This means that even if someone does something bad like add methods to `i32`,
it wont affect you, unless you `use` that trait.
Theres one more restriction on implementing traits: either the trait, or the
type youre writing the `impl` for, must be defined by you. So, we could
implement the `HasArea` type for `i32`, because `HasArea` is in our code. But
if we tried to implement `ToString`, a trait provided by Rust, for `i32`, we could
not, because neither the trait nor the type are in our code.
Theres one more restriction on implementing traits: either the trait
or the type youre implementing it for must be defined by you. Or more
precisely, one of them must be defined in the same crate as the `impl`
you're writing. For more on Rust's module and package system, see the
chapter on [crates and modules][cm].
So, we could implement the `HasArea` type for `i32`, because we defined
`HasArea` in our code. But if we tried to implement `ToString`, a trait
provided by Rust, for `i32`, we could not, because neither the trait nor
the type are defined in our crate.
One last thing about traits: generic functions with a trait bound use
monomorphization (mono: one, morph: form), so they are statically dispatched.
Whats that mean? Check out the chapter on [trait objects][to] for more details.
[cm]: crates-and-modules.html
[to]: trait-objects.html
# Multiple trait bounds

View File

@ -11,7 +11,7 @@ dont want to use the standard library via an attribute: `#![no_std]`.
> For details on binaries without the standard library, see [the nightly
> chapter on `#![no_std]`](no-stdlib.html)
To use `#![no_std]`, add a it to your crate root:
To use `#![no_std]`, add it to your crate root:
```rust
#![no_std]
@ -25,7 +25,7 @@ Much of the functionality thats exposed in the standard library is also
available via the [`core` crate](../core/). When were using the standard
library, Rust automatically brings `std` into scope, allowing you to use
its features without an explicit import. By the same token, when using
`!#[no_std]`, Rust will bring `core` into scope for you, as well as [its
`#![no_std]`, Rust will bring `core` into scope for you, as well as [its
prelude](../core/prelude/v1/). This means that a lot of code will Just Work:
```rust

View File

@ -11,8 +11,8 @@ let v = vec![1, 2, 3, 4, 5]; // v: Vec<i32>
```
(Notice that unlike the `println!` macro weve used in the past, we use square
brackets `[]` with `vec!` macro. Rust allows you to use either in either situation,
this is just convention.)
brackets `[]` with `vec!` macro. Rust allows you to use either in either
situation, this is just convention.)
Theres an alternate form of `vec!` for repeating an initial value:
@ -20,6 +20,12 @@ Theres an alternate form of `vec!` for repeating an initial value:
let v = vec![0; 10]; // ten zeroes
```
Vectors store their contents as contiguous arrays of `T` on the heap. This means
that they must be able to know the size of `T` at compile time (that is, how
many bytes are needed to store a `T`?). The size of some things can't be known
at compile time. For these you'll have to store a pointer to that thing:
thankfully, the [`Box`][box] type works perfectly for this.
## Accessing elements
To get the value at a particular index in the vector, we use `[]`s:
@ -113,6 +119,7 @@ Vectors have many more useful methods, which you can read about in [their
API documentation][vec].
[vec]: ../std/vec/index.html
[box]: ../std/boxed/index.html
[generic]: generics.html
[panic]: concurrency.html#panics
[get]: http://doc.rust-lang.org/std/vec/struct.Vec.html#method.get

View File

@ -516,7 +516,7 @@ struct_expr : expr_path '{' ident ':' expr
### Block expressions
```antlr
block_expr : '{' [ stmt ';' | item ] *
block_expr : '{' [ stmt | item ] *
[ expr ] '}' ;
```

View File

@ -57,7 +57,7 @@ These reprs have no effect on a struct.
# repr(packed)
`repr(packed)` forces rust to strip any padding, and only align the type to a
`repr(packed)` forces Rust to strip any padding, and only align the type to a
byte. This may improve the memory footprint, but will likely have other negative
side-effects.

View File

@ -104,7 +104,7 @@ comments (`/** ... */`), are interpreted as a special syntax for `doc`
`#[doc="..."]` around the body of the comment, i.e., `/// Foo` turns into
`#[doc="Foo"]`.
Line comments beginning with `//!` and block comments `/*! ... !*/` are
Line comments beginning with `//!` and block comments `/*! ... */` are
doc comments that apply to the parent of the comment, rather than the item
that follows. That is, they are equivalent to writing `#![doc="..."]` around
the body of the comment. `//!` comments are usually used to document
@ -236,6 +236,8 @@ following forms:
* A _whitespace escape_ is one of the characters `U+006E` (`n`), `U+0072`
(`r`), or `U+0074` (`t`), denoting the Unicode values `U+000A` (LF),
`U+000D` (CR) or `U+0009` (HT) respectively.
* The _null escape_ is the character `U+0030` (`0`) and denotes the Unicode
value `U+0000` (NUL).
* The _backslash escape_ is the character `U+005C` (`\`) which must be
escaped in order to denote *itself*.
@ -297,6 +299,8 @@ following forms:
* A _whitespace escape_ is one of the characters `U+006E` (`n`), `U+0072`
(`r`), or `U+0074` (`t`), denoting the bytes values `0x0A` (ASCII LF),
`0x0D` (ASCII CR) or `0x09` (ASCII HT) respectively.
* The _null escape_ is the character `U+0030` (`0`) and denotes the byte
value `0x00` (ASCII NUL).
* The _backslash escape_ is the character `U+005C` (`\`) which must be
escaped in order to denote its ASCII encoding `0x5C`.
@ -841,8 +845,8 @@ extern crate std as ruststd; // linking to 'std' under another name
A _use declaration_ creates one or more local name bindings synonymous with
some other [path](#paths). Usually a `use` declaration is used to shorten the
path required to refer to a module item. These declarations may appear at the
top of [modules](#modules) and [blocks](grammar.html#block-expressions).
path required to refer to a module item. These declarations may appear in
[modules](#modules) and [blocks](grammar.html#block-expressions), usually at the top.
> **Note**: Unlike in many languages,
> `use` declarations in Rust do *not* declare linkage dependency with external crates.
@ -984,8 +988,8 @@ fn first((value, _): (i32, i32)) -> i32 { value }
#### Generic functions
A _generic function_ allows one or more _parameterized types_ to appear in its
signature. Each type parameter must be explicitly declared, in an
angle-bracket-enclosed, comma-separated list following the function name.
signature. Each type parameter must be explicitly declared in an
angle-bracket-enclosed and comma-separated list, following the function name.
```rust,ignore
// foo is generic over A and B
@ -1137,7 +1141,6 @@ the list of fields entirely. Such a struct implicitly defines a constant of
its type with the same name. For example:
```
# #![feature(braced_empty_structs)]
struct Cookie;
let c = [Cookie, Cookie {}, Cookie, Cookie {}];
```
@ -1145,7 +1148,6 @@ let c = [Cookie, Cookie {}, Cookie, Cookie {}];
is equivalent to
```
# #![feature(braced_empty_structs)]
struct Cookie {}
const Cookie: Cookie = Cookie {};
let c = [Cookie, Cookie {}, Cookie, Cookie {}];
@ -1179,7 +1181,7 @@ Enumeration constructors can have either named or unnamed fields:
```rust
enum Animal {
Dog (String, f64),
Cat { name: String, weight: f64 }
Cat { name: String, weight: f64 },
}
let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2);
@ -1237,12 +1239,12 @@ const STRING: &'static str = "bitstring";
struct BitsNStrings<'a> {
mybits: [u32; 2],
mystring: &'a str
mystring: &'a str,
}
const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings {
mybits: BITS,
mystring: STRING
mystring: STRING,
};
```
@ -1661,7 +1663,7 @@ struct Foo;
// Declare a public struct with a private field
pub struct Bar {
field: i32
field: i32,
}
// Declare a public enum with two public variants
@ -1764,7 +1766,7 @@ pub mod submodule {
# fn main() {}
```
For a rust program to pass the privacy checking pass, all paths must be valid
For a Rust program to pass the privacy checking pass, all paths must be valid
accesses given the two rules above. This includes all use statements,
expressions, types, etc.
@ -2044,7 +2046,7 @@ The following configurations must be defined by the implementation:
production. For example, it controls the behavior of the standard library's
`debug_assert!` macro.
* `target_arch = "..."` - Target CPU architecture, such as `"x86"`, `"x86_64"`
`"mips"`, `"powerpc"`, `"powerpc64"`, `"powerpc64le"`, `"arm"`, or `"aarch64"`.
`"mips"`, `"powerpc"`, `"powerpc64"`, `"arm"`, or `"aarch64"`.
* `target_endian = "..."` - Endianness of the target CPU, either `"little"` or
`"big"`.
* `target_env = ".."` - An option provided by the compiler by default
@ -2095,7 +2097,7 @@ along with their default settings. [Compiler
plugins](book/compiler-plugins.html#lint-plugins) can provide additional lint checks.
```{.ignore}
mod m1 {
pub mod m1 {
// Missing documentation is ignored here
#[allow(missing_docs)]
pub fn undocumented_one() -> i32 { 1 }
@ -2115,9 +2117,9 @@ check on and off:
```{.ignore}
#[warn(missing_docs)]
mod m2{
pub mod m2{
#[allow(missing_docs)]
mod nested {
pub mod nested {
// Missing documentation is ignored here
pub fn undocumented_one() -> i32 { 1 }
@ -2137,7 +2139,7 @@ that lint check:
```{.ignore}
#[forbid(missing_docs)]
mod m3 {
pub mod m3 {
// Attempting to toggle warning signals an error here
#[allow(missing_docs)]
/// Returns 2.
@ -2381,7 +2383,6 @@ The currently implemented features of the reference compiler are:
terms of encapsulation).
* - `default_type_parameter_fallback` - Allows type parameter defaults to
influence type inference.
* - `braced_empty_structs` - Allows use of empty structs and enum variants with braces.
* - `stmt_expr_attributes` - Allows attributes on expressions and
non-item statements.
@ -3036,7 +3037,7 @@ the case of a `while` loop, the head is the conditional expression controlling
the loop. In the case of a `for` loop, the head is the call-expression
controlling the loop. If the label is present, then `continue 'foo` returns
control to the head of the loop with label `'foo`, which need not be the
innermost label enclosing the `break` expression, but must enclose it.
innermost label enclosing the `continue` expression, but must enclose it.
A `continue` expression is only permitted in the body of a loop.
@ -3212,7 +3213,7 @@ may refer to the variables bound within the pattern they follow.
let message = match maybe_digit {
Some(x) if x < 10 => process_digit(x),
Some(x) => process_other(x),
None => panic!()
None => panic!(),
};
```
@ -3504,7 +3505,7 @@ An example of a `fn` type:
```
fn add(x: i32, y: i32) -> i32 {
return x + y;
x + y
}
let mut x = add(5,7);
@ -3564,8 +3565,9 @@ Each instance of a trait object includes:
each method of `SomeTrait` that `T` implements, a pointer to `T`'s
implementation (i.e. a function pointer).
The purpose of trait objects is to permit "late binding" of methods. A call to
a method on a trait object is only resolved to a vtable entry at compile time.
The purpose of trait objects is to permit "late binding" of methods. Calling a
method on a trait object results in virtual dispatch at runtime: that is, a
function pointer is loaded from the trait object vtable and invoked indirectly.
The actual implementation for each vtable entry can vary on an object-by-object
basis.
@ -4060,7 +4062,7 @@ the guarantee that these issues are never caused by safe code.
* Breaking the [pointer aliasing
rules](http://llvm.org/docs/LangRef.html#pointer-aliasing-rules)
with raw pointers (a subset of the rules used by C)
* `&mut` and `&` follow LLVMs scoped [noalias] model, except if the `&T`
* `&mut T` and `&T` follow LLVMs scoped [noalias] model, except if the `&T`
contains an `UnsafeCell<U>`. Unsafe code must not violate these aliasing
guarantees.
* Mutating non-mutable data (that is, data reached through a shared reference or

View File

@ -1,3 +1,5 @@
% Rustc UX guidelines
Don't forget the user. Whether human or another program, such as an IDE, a
good user experience with the compiler goes a long way into making developer
lives better. We don't want users to be baffled by compiler output or
@ -70,4 +72,4 @@ understandable compiler scripts.
* The `--verbose` flag is for adding verbose information to `rustc` output
when not compiling a program. For example, using it with the `--version` flag
gives information about the hashes of the code.
* Experimental flags and options must be guarded behind the `-Z unstable-options` flag.
* Experimental flags and options must be guarded behind the `-Z unstable-options` flag.

View File

@ -1,2 +0,0 @@
\usepackage{newunicodechar}
\newunicodechar{{$\bot$}}

View File

@ -1,5 +1,5 @@
<div id="versioninfo">
<img src="https://www.rust-lang.org/logos/rust-logo-32x32-blk.png" width="32" height="32" alt><br>
<img src="https://www.rust-lang.org/logos/rust-logo-32x32-blk.png" width="32" height="32" alt="Rust logo"><br>
<span class="white-sticker"><a href="https://www.rust-lang.org">Rust</a> VERSION</span><br>
<a href="https://github.com/rust-lang/rust/commit/STAMP"
class="hash white-sticker">SHORT_HASH</a>

View File

@ -1,117 +0,0 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(rustc_private, rustdoc)]
extern crate syntax;
extern crate rustdoc;
extern crate serialize as rustc_serialize;
use std::collections::BTreeMap;
use std::fs::{read_dir, File};
use std::io::{Read, Write};
use std::env;
use std::path::Path;
use std::error::Error;
use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap};
use rustdoc::html::markdown::Markdown;
use rustc_serialize::json;
/// Load all the metadata files from `metadata_dir` into an in-memory map.
fn load_all_errors(metadata_dir: &Path) -> Result<ErrorMetadataMap, Box<Error>> {
let mut all_errors = BTreeMap::new();
for entry in try!(read_dir(metadata_dir)) {
let path = try!(entry).path();
let mut metadata_str = String::new();
try!(File::open(&path).and_then(|mut f| f.read_to_string(&mut metadata_str)));
let some_errors: ErrorMetadataMap = try!(json::decode(&metadata_str));
for (err_code, info) in some_errors {
all_errors.insert(err_code, info);
}
}
Ok(all_errors)
}
/// Output an HTML page for the errors in `err_map` to `output_path`.
fn render_error_page(err_map: &ErrorMetadataMap, output_path: &Path) -> Result<(), Box<Error>> {
let mut output_file = try!(File::create(output_path));
try!(write!(&mut output_file,
r##"<!DOCTYPE html>
<html>
<head>
<title>Rust Compiler Error Index</title>
<meta charset="utf-8">
<!-- Include rust.css after main.css so its rules take priority. -->
<link rel="stylesheet" type="text/css" href="main.css"/>
<link rel="stylesheet" type="text/css" href="rust.css"/>
<style>
.error-undescribed {{
display: none;
}}
</style>
</head>
<body>
"##
));
try!(write!(&mut output_file, "<h1>Rust Compiler Error Index</h1>\n"));
for (err_code, info) in err_map {
// Enclose each error in a div so they can be shown/hidden en masse.
let desc_desc = match info.description {
Some(_) => "error-described",
None => "error-undescribed",
};
let use_desc = match info.use_site {
Some(_) => "error-used",
None => "error-unused",
};
try!(write!(&mut output_file, "<div class=\"{} {}\">", desc_desc, use_desc));
// Error title (with self-link).
try!(write!(&mut output_file,
"<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n",
err_code));
// Description rendered as markdown.
match info.description {
Some(ref desc) => try!(write!(&mut output_file, "{}", Markdown(desc))),
None => try!(write!(&mut output_file, "<p>No description.</p>\n")),
}
try!(write!(&mut output_file, "</div>\n"));
}
try!(write!(&mut output_file, "</body>\n</html>"));
Ok(())
}
fn main_with_result() -> Result<(), Box<Error>> {
let build_arch = try!(env::var("CFG_BUILD"));
let metadata_dir = get_metadata_dir(&build_arch);
let err_map = try!(load_all_errors(&metadata_dir));
try!(render_error_page(&err_map, Path::new("doc/error-index.html")));
Ok(())
}
fn main() {
if let Err(e) = main_with_result() {
panic!("{}", e.description());
}
}

View File

@ -0,0 +1,203 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(rustc_private, rustdoc)]
extern crate syntax;
extern crate rustdoc;
extern crate serialize as rustc_serialize;
use std::collections::BTreeMap;
use std::fs::{read_dir, File};
use std::io::{Read, Write};
use std::env;
use std::path::Path;
use std::error::Error;
use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
use rustdoc::html::markdown::Markdown;
use rustc_serialize::json;
enum OutputFormat {
HTML(HTMLFormatter),
Markdown(MarkdownFormatter),
Unknown(String),
}
impl OutputFormat {
fn from(format: &str) -> OutputFormat {
match &*format.to_lowercase() {
"html" => OutputFormat::HTML(HTMLFormatter),
"markdown" => OutputFormat::Markdown(MarkdownFormatter),
s => OutputFormat::Unknown(s.to_owned()),
}
}
}
trait Formatter {
fn header(&self, output: &mut Write) -> Result<(), Box<Error>>;
fn title(&self, output: &mut Write) -> Result<(), Box<Error>>;
fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
err_code: &str) -> Result<(), Box<Error>>;
fn footer(&self, output: &mut Write) -> Result<(), Box<Error>>;
}
struct HTMLFormatter;
struct MarkdownFormatter;
impl Formatter for HTMLFormatter {
fn header(&self, output: &mut Write) -> Result<(), Box<Error>> {
try!(write!(output, r##"<!DOCTYPE html>
<html>
<head>
<title>Rust Compiler Error Index</title>
<meta charset="utf-8">
<!-- Include rust.css after main.css so its rules take priority. -->
<link rel="stylesheet" type="text/css" href="main.css"/>
<link rel="stylesheet" type="text/css" href="rust.css"/>
<style>
.error-undescribed {{
display: none;
}}
</style>
</head>
<body>
"##));
Ok(())
}
fn title(&self, output: &mut Write) -> Result<(), Box<Error>> {
try!(write!(output, "<h1>Rust Compiler Error Index</h1>\n"));
Ok(())
}
fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
err_code: &str) -> Result<(), Box<Error>> {
// Enclose each error in a div so they can be shown/hidden en masse.
let desc_desc = match info.description {
Some(_) => "error-described",
None => "error-undescribed",
};
let use_desc = match info.use_site {
Some(_) => "error-used",
None => "error-unused",
};
try!(write!(output, "<div class=\"{} {}\">", desc_desc, use_desc));
// Error title (with self-link).
try!(write!(output,
"<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n",
err_code));
// Description rendered as markdown.
match info.description {
Some(ref desc) => try!(write!(output, "{}", Markdown(desc))),
None => try!(write!(output, "<p>No description.</p>\n")),
}
try!(write!(output, "</div>\n"));
Ok(())
}
fn footer(&self, output: &mut Write) -> Result<(), Box<Error>> {
try!(write!(output, "</body>\n</html>"));
Ok(())
}
}
impl Formatter for MarkdownFormatter {
#[allow(unused_variables)]
fn header(&self, output: &mut Write) -> Result<(), Box<Error>> {
Ok(())
}
fn title(&self, output: &mut Write) -> Result<(), Box<Error>> {
try!(write!(output, "# Rust Compiler Error Index\n"));
Ok(())
}
fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
err_code: &str) -> Result<(), Box<Error>> {
Ok(match info.description {
Some(ref desc) => try!(write!(output, "## {}\n{}\n", err_code, desc)),
None => (),
})
}
#[allow(unused_variables)]
fn footer(&self, output: &mut Write) -> Result<(), Box<Error>> {
Ok(())
}
}
/// Load all the metadata files from `metadata_dir` into an in-memory map.
fn load_all_errors(metadata_dir: &Path) -> Result<ErrorMetadataMap, Box<Error>> {
let mut all_errors = BTreeMap::new();
for entry in try!(read_dir(metadata_dir)) {
let path = try!(entry).path();
let mut metadata_str = String::new();
try!(File::open(&path).and_then(|mut f| f.read_to_string(&mut metadata_str)));
let some_errors: ErrorMetadataMap = try!(json::decode(&metadata_str));
for (err_code, info) in some_errors {
all_errors.insert(err_code, info);
}
}
Ok(all_errors)
}
/// Output an HTML page for the errors in `err_map` to `output_path`.
fn render_error_page<T: Formatter>(err_map: &ErrorMetadataMap, output_path: &Path,
formatter: T) -> Result<(), Box<Error>> {
let mut output_file = try!(File::create(output_path));
try!(formatter.header(&mut output_file));
try!(formatter.title(&mut output_file));
for (err_code, info) in err_map {
try!(formatter.error_code_block(&mut output_file, info, err_code));
}
formatter.footer(&mut output_file)
}
fn main_with_result(format: OutputFormat) -> Result<(), Box<Error>> {
let build_arch = try!(env::var("CFG_BUILD"));
let metadata_dir = get_metadata_dir(&build_arch);
let err_map = try!(load_all_errors(&metadata_dir));
match format {
OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s),
OutputFormat::HTML(h) => try!(render_error_page(&err_map,
Path::new("doc/error-index.html"),
h)),
OutputFormat::Markdown(m) => try!(render_error_page(&err_map,
Path::new("doc/error-index.md"),
m)),
}
Ok(())
}
fn parse_args() -> OutputFormat {
for arg in env::args().skip(1) {
return OutputFormat::from(&arg);
}
OutputFormat::from("html")
}
fn main() {
if let Err(e) = main_with_result(parse_args()) {
panic!("{}", e.description());
}
}

Some files were not shown because too many files have changed in this diff Show More