New upstream version 1.15.0+dfsg1

This commit is contained in:
Sylvestre Ledru 2017-02-03 15:09:23 +01:00
parent c30ab7b35a
commit 476ff2be50
1709 changed files with 96735 additions and 23524 deletions

View File

@ -86,13 +86,17 @@ 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].
The build system lives in [the `src/bootstrap` directory][bootstrap] in the
project root. Our build system is itself written in Rust and is based on Cargo
to actually build all the compiler's crates. 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/
[bootstrap]: https://github.com/rust-lang/rust/tree/master/src/bootstrap/
> **Note**: the build system was recently rewritten from a jungle of makefiles
> to the current incarnation you'll see in `src/bootstrap`. If you experience
> bugs you can temporarily revert back to the makefiles with
> `--disable-rustbuild` passed to `./configure`.
### Configuration
@ -119,42 +123,112 @@ configuration used later in the build process. Some options to note:
To see a full list of options, run `./configure --help`.
### Useful Targets
### Building
Some common make targets are:
Although the `./configure` script will generate a `Makefile`, this is actually
just a thin veneer over the actual build system driver, `x.py`. This file, at
the root of the repository, is used to build, test, and document various parts
of the compiler. You can execute it as:
- `make tips` - show useful targets, variables and other tips for working with
the build system.
- `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 $host/stage1/bin/rustc` - Where $host is a target triple like x86_64-unknown-linux-gnu.
This will build just rustc, without libstd. This is the fastest way to recompile after
you changed only rustc source code. Note however that the resulting rustc binary
won't have a stdlib to link against by default. You can build libstd once with
`make rustc-stage1`, rustc will pick it up afterwards. libstd is only guaranteed to
work if recompiled, so if there are any issues recompile it.
- `make check` - build the full compiler & run all tests (takes a while). This
```sh
python x.py build
```
On some systems you can also use the shorter version:
```sh
./x.py build
```
To learn more about the driver and top-level targets, you can execute:
```sh
python x.py --help
```
The general format for the driver script is:
```sh
python x.py <command> [<directory>]
```
Some example commands are `build`, `test`, and `doc`. These will build, test,
and document the specified directory. The second argument, `<directory>`, is
optional and defaults to working over the entire compiler. If specified,
however, only that specific directory will be built. For example:
```sh
# build the entire compiler
python x.py build
# build all documentation
python x.py doc
# run all test suites
python x.py test
# build only the standard library
python x.py build src/libstd
# test only one particular test suite
python x.py test src/test/rustdoc
# build only the stage0 libcore library
python x.py build src/libcore --stage 0
```
You can explore the build system throught the various `--help` pages for each
subcommand. For example to learn more about a command you can run:
```
python x.py build --help
```
To learn about all possible rules you can execute, run:
```
python x.py build --help --verbose
```
### Useful commands
Some common invocations of `x.py` are:
- `x.py build --help` - show the help message and explain the subcommand
- `x.py build src/libtest --stage 1` - 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.
- `x.py build src/rustc --stage 1` - This will build just rustc, without libstd.
This is the fastest way to recompile after you changed only rustc source code.
Note however that the resulting rustc binary won't have a stdlib to link
against by default. You can build libstd once with `x.py build src/libstd`,
but it is is only guaranteed to work if recompiled, so if there are any issues
recompile it.
- `x.py test` - 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.
- `x.py test src/libstd --stage 1` - test the standard library without
recompiling stage 2.
- `x.py test src/test/run-pass --test-args TESTNAME` - 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`.
- `make tidy` - Check that the source code is in compliance with Rust's style
guidelines. There is no official document describing Rust's full guidelines
as of yet, but basic rules like 4 spaces for indentation and no more than 99
characters in a single line should be kept in mind when writing code.
- `x.py test src/test/run-pass --stage 1 --test-args <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 directory argument to run all stage1 test
types.
- `x.py test src/libcore --stage 1` - Run stage1 tests in `libcore`.
- `x.py test src/tools/tidy` - Check that the source code is in compliance with
Rust's style guidelines. There is no official document describing Rust's full
guidelines as of yet, but basic rules like 4 spaces for indentation and no
more than 99 characters in a single line should be kept in mind when writing
code.
## Pull Requests
@ -172,19 +246,17 @@ amount of time you have to wait. You need to have built the compiler at least
once before running these will work, but thats only one full build rather than
one each time.
$ make -j8 rustc-stage1 && make check-stage1
$ python x.py test --stage 1
is one such example, which builds just `rustc`, and then runs the tests. If
youre adding something to the standard library, try
$ make -j8 check-stage1-std NO_REBUILD=1
This will not rebuild the compiler, but will run the tests.
$ python x.py test src/libstd --stage 1
Please make sure your pull request is in compliance with Rust's style
guidelines by running
$ make tidy
$ python x.py test src/tools/tidy
Make this check before every pull request (and every new commit in a pull
request) ; you can add [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)
@ -213,7 +285,7 @@ been approved. The PR then enters the [merge queue][merge-queue], where @bors
will run all the tests on every platform we support. If it all works out,
@bors will merge your code into `master` and close the pull request.
[merge-queue]: http://buildbot.rust-lang.org/homu/queue/rust
[merge-queue]: https://buildbot.rust-lang.org/homu/queue/rust
Speaking of tests, Rust has a comprehensive test suite. More information about
it can be found
@ -332,4 +404,4 @@ are:
[tlgba]: http://tomlee.co/2014/04/a-more-detailed-tour-of-the-rust-compiler/
[ro]: http://www.rustaceans.org/
[rctd]: ./COMPILER_TESTS.md
[cheatsheet]: http://buildbot.rust-lang.org/homu/
[cheatsheet]: https://buildbot.rust-lang.org/homu/

View File

@ -36,16 +36,14 @@ Read ["Installing Rust"] from [The Book].
```sh
$ ./configure
$ make && make install
$ make && sudo make install
```
> ***Note:*** You may need to use `sudo make install` if you do not
> normally have permission to modify the destination directory. The
> install locations can be adjusted by passing a `--prefix` argument
> to `configure`. Various other options are also supported pass
> ***Note:*** Install locations can be adjusted by passing a `--prefix`
> argument to `configure`. Various other options are also supported pass
> `--help` for more information on them.
When complete, `make install` will place several programs into
When complete, `sudo make install` will place several programs into
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
API-documentation tool. This install does not include [Cargo],
Rust's package manager, which you may also want to build.
@ -108,30 +106,22 @@ MSVC builds of Rust additionally require an installation of Visual Studio 2013
(or later) so `rustc` can use its linker. Make sure to check the “C++ tools”
option.
With these dependencies installed, the build takes two steps:
With these dependencies installed, you can build the compiler in a `cmd.exe`
shell with:
```sh
$ ./configure
> python x.py build
```
If you're running inside of an msys shell, however, you can run:
```sh
$ ./configure --build=x86_64-pc-windows-msvc
$ make && make install
```
#### MSVC with rustbuild
The old build system, based on makefiles, is currently being rewritten into a
Rust-based build system called rustbuild. This can be used to bootstrap the
compiler on MSVC without needing to install MSYS or MinGW. All you need are
[Python 2](https://www.python.org/downloads/),
[CMake](https://cmake.org/download/), and
[Git](https://git-scm.com/downloads) in your PATH (make sure you do not use the
ones from MSYS if you have it installed). You'll also need Visual Studio 2013 or
newer with the C++ tools. Then all you need to do is to kick off rustbuild.
```
python x.py build
```
Currently rustbuild only works with some known versions of Visual Studio. If you
have a more recent version installed that a part of rustbuild doesn't understand
Currently building Rust only works with some known versions of Visual Studio. If
you have a more recent version installed the build system doesn't understand
then you may need to force rustbuild to use an older version. This can be done
by manually calling the appropriate vcvars file before running the bootstrap.
@ -149,16 +139,6 @@ $ ./configure
$ make docs
```
Building the documentation requires building the compiler, so the above
details will apply. Once you have the compiler built, you can
```sh
$ make docs NO_REBUILD=1
```
To make sure you dont re-build the compiler because you made a change
to some documentation.
The generated documentation will appear in a top-level `doc` directory,
created by the `make` rule.

View File

@ -1,3 +1,720 @@
Version 1.15.0 (2017-02-02)
===========================
Language
--------
* Basic procedural macros allowing custom `#[derive]`, aka "macros 1.1", are
stable. This allows popular code-generating crates like Serde and Diesel to
work ergonomically. [RFC 1681].
* [Tuple structs may be empty. Unary and empty tuple structs may be instantiated
with curly braces][36868]. Part of [RFC 1506].
* [A number of minor changes to name resolution have been activated][37127].
They add up to more consistent semantics, allowing for future evolution of
Rust macros. Specified in [RFC 1560], see its section on ["changes"] for
details of what is different. The breaking changes here have been transitioned
through the [`legacy_imports`] lint since 1.14, with no known regressions.
* [In `macro_rules`, `path` fragments can now be parsed as type parameter
bounds][38279]
* [`?Sized` can be used in `where` clauses][37791]
* [There is now a limit on the size of monomorphized types and it can be
modified with the `#![type_size_limit]` crate attribute, similarly to
the `#![recursion_limit]` attribute][37789]
Compiler
--------
* [On Windows, the compiler will apply dllimport attributes when linking to
extern functions][37973]. Additional attributes and flags can control which
library kind is linked and its name. [RFC 1717].
* [Rust-ABI symbols are no longer exported from cdylibs][38117]
* [The `--test` flag works with procedural macro crates][38107]
* [Fix `extern "aapcs" fn` ABI][37814]
* [The `-C no-stack-check` flag is deprecated][37636]. It does nothing.
* [The `format!` expander recognizes incorrect `printf` and shell-style
formatting directives and suggests the correct format][37613].
* [Only report one error for all unused imports in an import list][37456]
Compiler Performance
--------------------
* [Avoid unnecessary `mk_ty` calls in `Ty::super_fold_with`][37705]
* [Avoid more unnecessary `mk_ty` calls in `Ty::super_fold_with`][37979]
* [Don't clone in `UnificationTable::probe`][37848]
* [Remove `scope_auxiliary` to cut RSS by 10%][37764]
* [Use small vectors in type walker][37760]
* [Macro expansion performance was improved][37701]
* [Change `HirVec<P<T>>` to `HirVec<T>` in `hir::Expr`][37642]
* [Replace FNV with a faster hash function][37229]
Stabilized APIs
---------------
* [`std::iter::Iterator::min_by`]
* [`std::iter::Iterator::max_by`]
* [`std::os::*::fs::FileExt`]
* [`std::sync::atomic::Atomic*::get_mut`]
* [`std::sync::atomic::Atomic*::into_inner`]
* [`std::vec::IntoIter::as_slice`]
* [`std::vec::IntoIter::as_mut_slice`]
* [`std::sync::mpsc::Receiver::try_iter`]
* [`std::os::unix::process::CommandExt::before_exec`]
* [`std::rc::Rc::strong_count`]
* [`std::rc::Rc::weak_count`]
* [`std::sync::Arc::strong_count`]
* [`std::sync::Arc::weak_count`]
* [`std::char::encode_utf8`]
* [`std::char::encode_utf16`]
* [`std::cell::Ref::clone`]
* [`std::io::Take::into_inner`]
Libraries
---------
* [The standard sorting algorithm has been rewritten for dramatic performance
improvements][38192]. It is a hybrid merge sort, drawing influences from
Timsort. Previously it was a naive merge sort.
* [`Iterator::nth` no longer has a `Sized` bound][38134]
* [`Extend<&T>` is specialized for `Vec` where `T: Copy`][38182] to improve
performance.
* [`chars().count()` is much faster][37888] and so are [`chars().last()`
and `char_indices().last()`][37882]
* [Fix ARM Objective-C ABI in `std::env::args`][38146]
* [Chinese characters display correctly in `fmt::Debug`][37855]
* [Derive `Default` for `Duration`][37699]
* [Support creation of anonymous pipes on WinXP/2k][37677]
* [`mpsc::RecvTimeoutError` implements `Error`][37527]
* [Don't pass overlapped handles to processes][38835]
Cargo
-----
* [In this release, Cargo build scripts no longer have access to the `OUT_DIR`
environment variable at build time via `env!("OUT_DIR")`][cargo/3368]. They
should instead check the variable at runtime with `std::env`. That the value
was set at build time was a bug, and incorrect when cross-compiling. This
change is known to cause breakage.
* [Add `--all` flag to `cargo test`][cargo/3221]
* [Compile statically against the MSVC CRT][cargo/3363]
* [Mix feature flags into fingerprint/metadata shorthash][cargo/3102]
* [Link OpenSSL statically on OSX][cargo/3311]
* [Apply new fingerprinting to build dir outputs][cargo/3310]
* [Test for bad path overrides with summaries][cargo/3336]
* [Require `cargo install --vers` to take a semver version][cargo/3338]
* [Fix retrying crate downloads for network errors][cargo/3348]
* [Implement string lookup for `build.rustflags` config key][cargo/3356]
* [Emit more info on --message-format=json][cargo/3319]
* [Assume `build.rs` in the same directory as `Cargo.toml` is a build script][cargo/3361]
* [Don't ignore errors in workspace manifest][cargo/3409]
* [Fix `--message-format JSON` when rustc emits non-JSON warnings][cargo/3410]
Tooling
-------
* [Test runners (binaries built with `--test`) now support a `--list` argument
that lists the tests it contains][38185]
* [Test runners now support a `--exact` argument that makes the test filter
match exactly, instead of matching only a substring of the test name][38181]
* [rustdoc supports a `--playground-url` flag][37763]
* [rustdoc provides more details about `#[should_panic]` errors][37749]
Misc
----
* [The Rust build system is now written in Rust][37817]. The Makefiles may
continue to be used in this release by passing `--disable-rustbuild` to the
configure script, but they will be deleted soon. Note that the new build
system uses a different on-disk layout that will likely affect any scripts
building Rust.
* [Rust supports i686-unknown-openbsd][38086]. Tier 3 support. No testing or
releases.
* [Rust supports the MSP430][37627]. Tier 3 support. No testing or releases.
* [Rust supports the ARMv5TE architecture][37615]. Tier 3 support. No testing or
releases.
Compatibility Notes
-------------------
* [A number of minor changes to name resolution have been activated][37127].
They add up to more consistent semantics, allowing for future evolution of
Rust macros. Specified in [RFC 1560], see its section on ["changes"] for
details of what is different. The breaking changes here have been transitioned
through the [`legacy_imports`] lint since 1.14, with no known regressions.
* [In this release, Cargo build scripts no longer have access to the `OUT_DIR`
environment variable at build time via `env!("OUT_DIR")`][cargo/3368]. They
should instead check the variable at runtime with `std::env`. That the value
was set at build time was a bug, and incorrect when cross-compiling. This
change is known to cause breakage.
* [Higher-ranked lifetimes are no longer allowed to appear _only_ in associated
types][33685]. The [`hr_lifetime_in_assoc_type` lint] has been a warning since
1.10 and is now an error by default. It will become a hard error in the near
future.
* [The semantics relating modules to file system directories are changing in
minor ways][37602]. This is captured in the new `legacy_directory_ownership`
lint, which is a warning in this release, and will become a hard error in the
future.
* [Rust-ABI symbols are no longer exported from cdylibs][38117]
* [Once `Peekable` peeks a `None` it will return that `None` without re-querying
the underlying iterator][37834]
["changes"]: https://github.com/rust-lang/rfcs/blob/master/text/1560-name-resolution.md#changes-to-name-resolution-rules
[33685]: https://github.com/rust-lang/rust/issues/33685
[36868]: https://github.com/rust-lang/rust/pull/36868
[37127]: https://github.com/rust-lang/rust/pull/37127
[37229]: https://github.com/rust-lang/rust/pull/37229
[37456]: https://github.com/rust-lang/rust/pull/37456
[37527]: https://github.com/rust-lang/rust/pull/37527
[37602]: https://github.com/rust-lang/rust/pull/37602
[37613]: https://github.com/rust-lang/rust/pull/37613
[37615]: https://github.com/rust-lang/rust/pull/37615
[37636]: https://github.com/rust-lang/rust/pull/37636
[37642]: https://github.com/rust-lang/rust/pull/37642
[37677]: https://github.com/rust-lang/rust/pull/37677
[37699]: https://github.com/rust-lang/rust/pull/37699
[37701]: https://github.com/rust-lang/rust/pull/37701
[37705]: https://github.com/rust-lang/rust/pull/37705
[37749]: https://github.com/rust-lang/rust/pull/37749
[37760]: https://github.com/rust-lang/rust/pull/37760
[37763]: https://github.com/rust-lang/rust/pull/37763
[37764]: https://github.com/rust-lang/rust/pull/37764
[37789]: https://github.com/rust-lang/rust/pull/37789
[37791]: https://github.com/rust-lang/rust/pull/37791
[37814]: https://github.com/rust-lang/rust/pull/37814
[37817]: https://github.com/rust-lang/rust/pull/37817
[37834]: https://github.com/rust-lang/rust/pull/37834
[37848]: https://github.com/rust-lang/rust/pull/37848
[37855]: https://github.com/rust-lang/rust/pull/37855
[37882]: https://github.com/rust-lang/rust/pull/37882
[37888]: https://github.com/rust-lang/rust/pull/37888
[37973]: https://github.com/rust-lang/rust/pull/37973
[37979]: https://github.com/rust-lang/rust/pull/37979
[38086]: https://github.com/rust-lang/rust/pull/38086
[38107]: https://github.com/rust-lang/rust/pull/38107
[38117]: https://github.com/rust-lang/rust/pull/38117
[38134]: https://github.com/rust-lang/rust/pull/38134
[38146]: https://github.com/rust-lang/rust/pull/38146
[38181]: https://github.com/rust-lang/rust/pull/38181
[38182]: https://github.com/rust-lang/rust/pull/38182
[38185]: https://github.com/rust-lang/rust/pull/38185
[38192]: https://github.com/rust-lang/rust/pull/38192
[38279]: https://github.com/rust-lang/rust/pull/38279
[38835]: https://github.com/rust-lang/rust/pull/38835
[RFC 1492]: https://github.com/rust-lang/rfcs/blob/master/text/1492-dotdot-in-patterns.md
[RFC 1506]: https://github.com/rust-lang/rfcs/blob/master/text/1506-adt-kinds.md
[RFC 1560]: https://github.com/rust-lang/rfcs/blob/master/text/1560-name-resolution.md
[RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md
[RFC 1717]: https://github.com/rust-lang/rfcs/blob/master/text/1717-dllimport.md
[`hr_lifetime_in_assoc_type` lint]: https://github.com/rust-lang/rust/issues/33685
[`legacy_imports`]: https://github.com/rust-lang/rust/pull/38271
[cargo/3102]: https://github.com/rust-lang/cargo/pull/3102
[cargo/3221]: https://github.com/rust-lang/cargo/pull/3221
[cargo/3310]: https://github.com/rust-lang/cargo/pull/3310
[cargo/3311]: https://github.com/rust-lang/cargo/pull/3311
[cargo/3319]: https://github.com/rust-lang/cargo/pull/3319
[cargo/3336]: https://github.com/rust-lang/cargo/pull/3336
[cargo/3338]: https://github.com/rust-lang/cargo/pull/3338
[cargo/3348]: https://github.com/rust-lang/cargo/pull/3348
[cargo/3356]: https://github.com/rust-lang/cargo/pull/3356
[cargo/3361]: https://github.com/rust-lang/cargo/pull/3361
[cargo/3363]: https://github.com/rust-lang/cargo/pull/3363
[cargo/3368]: https://github.com/rust-lang/cargo/issues/3368
[cargo/3409]: https://github.com/rust-lang/cargo/pull/3409
[cargo/3410]: https://github.com/rust-lang/cargo/pull/3410
[`std::iter::Iterator::min_by`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min_by
[`std::iter::Iterator::max_by`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max_by
[`std::os::*::fs::FileExt`]: https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html
[`std::sync::atomic::Atomic*::get_mut`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicU8.html#method.get_mut
[`std::sync::atomic::Atomic*::into_inner`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicU8.html#method.into_inner
[`std::vec::IntoIter::as_slice`]: https://doc.rust-lang.org/std/vec/struct.IntoIter.html#method.as_slice
[`std::vec::IntoIter::as_mut_slice`]: https://doc.rust-lang.org/std/vec/struct.IntoIter.html#method.as_mut_slice
[`std::sync::mpsc::Receiver::try_iter`]: https://doc.rust-lang.org/std/sync/mpsc/struct.Receiver.html#method.try_iter
[`std::os::unix::process::CommandExt::before_exec`]: https://doc.rust-lang.org/std/os/unix/process/trait.CommandExt.html#tymethod.before_exec
[`std::rc::Rc::strong_count`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.strong_count
[`std::rc::Rc::weak_count`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.weak_count
[`std::sync::Arc::strong_count`]: https://doc.rust-lang.org/std/sync/struct.Arc.html#method.strong_count
[`std::sync::Arc::weak_count`]: https://doc.rust-lang.org/std/sync/struct.Arc.html#method.weak_count
[`std::char::encode_utf8`]: https://doc.rust-lang.org/std/primitive.char.html#method.encode_utf8
[`std::char::encode_utf16`]: https://doc.rust-lang.org/std/primitive.char.html#method.encode_utf16
[`std::cell::Ref::clone`]: https://doc.rust-lang.org/std/cell/struct.Ref.html#method.clone
[`std::io::Take::into_inner`]: https://doc.rust-lang.org/std/io/struct.Take.html#method.into_inner
Version 1.14.0 (2016-12-22)
===========================
Language
--------
* [`..` matches multiple tuple fields in enum variants, structs
and tuples][36843]. [RFC 1492].
* [Safe `fn` items can be coerced to `unsafe fn` pointers][37389]
* [`use *` and `use ::*` both glob-import from the crate root][37367]
* [It's now possible to call a `Vec<Box<Fn()>>` without explicit
dereferencing][36822]
Compiler
--------
* [Mark enums with non-zero discriminant as non-zero][37224]
* [Lower-case `static mut` names are linted like other
statics and consts][37162]
* [Fix ICE on some macros in const integer positions
(e.g. `[u8; m!()]`)][36819]
* [Improve error message and snippet for "did you mean `x`"][36798]
* [Add a panic-strategy field to the target specification][36794]
* [Include LLVM version in `--version --verbose`][37200]
Compile-time Optimizations
--------------------------
* [Improve macro expansion performance][37569]
* [Shrink `Expr_::ExprInlineAsm`][37445]
* [Replace all uses of SHA-256 with BLAKE2b][37439]
* [Reduce the number of bytes hashed by `IchHasher`][37427]
* [Avoid more allocations when compiling html5ever][37373]
* [Use `SmallVector` in `CombineFields::instantiate`][37322]
* [Avoid some allocations in the macro parser][37318]
* [Use a faster deflate setting][37298]
* [Add `ArrayVec` and `AccumulateVec` to reduce heap allocations
during interning of slices][37270]
* [Optimize `write_metadata`][37267]
* [Don't process obligation forest cycles when stalled][37231]
* [Avoid many `CrateConfig` clones][37161]
* [Optimize `Substs::super_fold_with`][37108]
* [Optimize `ObligationForest`'s `NodeState` handling][36993]
* [Speed up `plug_leaks`][36917]
Libraries
---------
* [`println!()`, with no arguments, prints newline][36825].
Previously, an empty string was required to achieve the same.
* [`Wrapping` impls standard binary and unary operators, as well as
the `Sum` and `Product` iterators][37356]
* [Implement `From<Cow<str>> for String` and `From<Cow<[T]>> for
Vec<T>`][37326]
* [Improve `fold` performance for `chain`, `cloned`, `map`, and
`VecDeque` iterators][37315]
* [Improve `SipHasher` performance on small values][37312]
* [Add Iterator trait TrustedLen to enable better FromIterator /
Extend][37306]
* [Expand `.zip()` specialization to `.map()` and `.cloned()`][37230]
* [`ReadDir` implements `Debug`][37221]
* [Implement `RefUnwindSafe` for atomic types][37178]
* [Specialize `Vec::extend` to `Vec::extend_from_slice`][37094]
* [Avoid allocations in `Decoder::read_str`][37064]
* [`io::Error` implements `From<io::ErrorKind>`][37037]
* [Impl `Debug` for raw pointers to unsized data][36880]
* [Don't reuse `HashMap` random seeds][37470]
* [The internal memory layout of `HashMap` is more cache-friendly, for
significant improvements in some operations][36692]
* [`HashMap` uses less memory on 32-bit architectures][36595]
* [Impl `Add<{str, Cow<str>}>` for `Cow<str>`][36430]
Cargo
-----
* [Expose rustc cfg values to build scripts][cargo/3243]
* [Allow cargo to work with read-only `CARGO_HOME`][cargo/3259]
* [Fix passing --features when testing multiple packages][cargo/3280]
* [Use a single profile set per workspace][cargo/3249]
* [Load `replace` sections from lock files][cargo/3220]
* [Ignore `panic` configuration for test/bench profiles][cargo/3175]
Tooling
-------
* [rustup is the recommended Rust installation method][1.14rustup]
* This release includes host (rustc) builds for Linux on MIPS, PowerPC, and
S390x. These are [tier 2] platforms and may have major defects. Follow the
instructions on the website to install, or add the targets to an existing
installation with `rustup target add`. The new target triples are:
- `mips-unknown-linux-gnu`
- `mipsel-unknown-linux-gnu`
- `mips64-unknown-linux-gnuabi64`
- `mips64el-unknown-linux-gnuabi64 `
- `powerpc-unknown-linux-gnu`
- `powerpc64-unknown-linux-gnu`
- `powerpc64le-unknown-linux-gnu`
- `s390x-unknown-linux-gnu `
* This release includes target (std) builds for ARM Linux running MUSL
libc. These are [tier 2] platforms and may have major defects. Add the
following triples to an existing rustup installation with `rustup target add`:
- `arm-unknown-linux-musleabi`
- `arm-unknown-linux-musleabihf`
- `armv7-unknown-linux-musleabihf`
* This release includes [experimental support for WebAssembly][1.14wasm], via
the `wasm32-unknown-emscripten` target. This target is known to have major
defects. Please test, report, and fix.
* rustup no longer installs documentation by default. Run `rustup
component add rust-docs` to install.
* [Fix line stepping in debugger][37310]
* [Enable line number debuginfo in releases][37280]
Misc
----
* [Disable jemalloc on aarch64/powerpc/mips][37392]
* [Add support for Fuchsia OS][37313]
* [Detect local-rebuild by only MAJOR.MINOR version][37273]
Compatibility Notes
-------------------
* [A number of forward-compatibility lints used by the compiler
to gradually introduce language changes have been converted
to deny by default][36894]:
- ["use of inaccessible extern crate erroneously allowed"][36886]
- ["type parameter default erroneously allowed in invalid location"][36887]
- ["detects super or self keywords at the beginning of global path"][36888]
- ["two overlapping inherent impls define an item with the same name
were erroneously allowed"][36889]
- ["floating-point constants cannot be used in patterns"][36890]
- ["constants of struct or enum type can only be used in a pattern if
the struct or enum has `#[derive(PartialEq, Eq)]`"][36891]
- ["lifetimes or labels named `'_` were erroneously allowed"][36892]
* [Prohibit patterns in trait methods without bodies][37378]
* [The atomic `Ordering` enum may not be matched exhaustively][37351]
* [Future-proofing `#[no_link]` breaks some obscure cases][37247]
* [The `$crate` macro variable is accepted in fewer locations][37213]
* [Impls specifying extra region requirements beyond the trait
they implement are rejected][37167]
* [Enums may not be unsized][37111]. Unsized enums are intended to
work but never have. For now they are forbidden.
* [Enforce the shadowing restrictions from RFC 1560 for today's macros][36767]
[tier 2]: https://forge.rust-lang.org/platform-support.html
[1.14rustup]: https://internals.rust-lang.org/t/beta-testing-rustup-rs/3316/204
[1.14wasm]: https://users.rust-lang.org/t/compiling-to-the-web-with-rust-and-emscripten/7627
[36430]: https://github.com/rust-lang/rust/pull/36430
[36595]: https://github.com/rust-lang/rust/pull/36595
[36595]: https://github.com/rust-lang/rust/pull/36595
[36692]: https://github.com/rust-lang/rust/pull/36692
[36767]: https://github.com/rust-lang/rust/pull/36767
[36794]: https://github.com/rust-lang/rust/pull/36794
[36798]: https://github.com/rust-lang/rust/pull/36798
[36819]: https://github.com/rust-lang/rust/pull/36819
[36822]: https://github.com/rust-lang/rust/pull/36822
[36825]: https://github.com/rust-lang/rust/pull/36825
[36843]: https://github.com/rust-lang/rust/pull/36843
[36880]: https://github.com/rust-lang/rust/pull/36880
[36886]: https://github.com/rust-lang/rust/issues/36886
[36887]: https://github.com/rust-lang/rust/issues/36887
[36888]: https://github.com/rust-lang/rust/issues/36888
[36889]: https://github.com/rust-lang/rust/issues/36889
[36890]: https://github.com/rust-lang/rust/issues/36890
[36891]: https://github.com/rust-lang/rust/issues/36891
[36892]: https://github.com/rust-lang/rust/issues/36892
[36894]: https://github.com/rust-lang/rust/pull/36894
[36917]: https://github.com/rust-lang/rust/pull/36917
[36993]: https://github.com/rust-lang/rust/pull/36993
[37037]: https://github.com/rust-lang/rust/pull/37037
[37064]: https://github.com/rust-lang/rust/pull/37064
[37094]: https://github.com/rust-lang/rust/pull/37094
[37108]: https://github.com/rust-lang/rust/pull/37108
[37111]: https://github.com/rust-lang/rust/pull/37111
[37161]: https://github.com/rust-lang/rust/pull/37161
[37162]: https://github.com/rust-lang/rust/pull/37162
[37167]: https://github.com/rust-lang/rust/pull/37167
[37178]: https://github.com/rust-lang/rust/pull/37178
[37200]: https://github.com/rust-lang/rust/pull/37200
[37213]: https://github.com/rust-lang/rust/pull/37213
[37221]: https://github.com/rust-lang/rust/pull/37221
[37224]: https://github.com/rust-lang/rust/pull/37224
[37230]: https://github.com/rust-lang/rust/pull/37230
[37231]: https://github.com/rust-lang/rust/pull/37231
[37247]: https://github.com/rust-lang/rust/pull/37247
[37267]: https://github.com/rust-lang/rust/pull/37267
[37270]: https://github.com/rust-lang/rust/pull/37270
[37273]: https://github.com/rust-lang/rust/pull/37273
[37280]: https://github.com/rust-lang/rust/pull/37280
[37298]: https://github.com/rust-lang/rust/pull/37298
[37306]: https://github.com/rust-lang/rust/pull/37306
[37310]: https://github.com/rust-lang/rust/pull/37310
[37312]: https://github.com/rust-lang/rust/pull/37312
[37313]: https://github.com/rust-lang/rust/pull/37313
[37315]: https://github.com/rust-lang/rust/pull/37315
[37318]: https://github.com/rust-lang/rust/pull/37318
[37322]: https://github.com/rust-lang/rust/pull/37322
[37326]: https://github.com/rust-lang/rust/pull/37326
[37351]: https://github.com/rust-lang/rust/pull/37351
[37356]: https://github.com/rust-lang/rust/pull/37356
[37367]: https://github.com/rust-lang/rust/pull/37367
[37373]: https://github.com/rust-lang/rust/pull/37373
[37378]: https://github.com/rust-lang/rust/pull/37378
[37389]: https://github.com/rust-lang/rust/pull/37389
[37392]: https://github.com/rust-lang/rust/pull/37392
[37427]: https://github.com/rust-lang/rust/pull/37427
[37439]: https://github.com/rust-lang/rust/pull/37439
[37445]: https://github.com/rust-lang/rust/pull/37445
[37470]: https://github.com/rust-lang/rust/pull/37470
[37569]: https://github.com/rust-lang/rust/pull/37569
[RFC 1492]: https://github.com/rust-lang/rfcs/blob/master/text/1492-dotdot-in-patterns.md
[cargo/3175]: https://github.com/rust-lang/cargo/pull/3175
[cargo/3220]: https://github.com/rust-lang/cargo/pull/3220
[cargo/3243]: https://github.com/rust-lang/cargo/pull/3243
[cargo/3249]: https://github.com/rust-lang/cargo/pull/3249
[cargo/3259]: https://github.com/rust-lang/cargo/pull/3259
[cargo/3280]: https://github.com/rust-lang/cargo/pull/3280
Version 1.13.0 (2016-11-10)
===========================
Language
--------
* [Stabilize the `?` operator][36995]. `?` is a simple way to propagate
errors, like the `try!` macro, described in [RFC 0243].
* [Stabilize macros in type position][36014]. Described in [RFC 873].
* [Stabilize attributes on statements][36995]. Described in [RFC 0016].
* [Fix `#[derive]` for empty tuple structs/variants][35728]
* [Fix lifetime rules for 'if' conditions][36029]
* [Avoid loading and parsing unconfigured non-inline modules][36482]
Compiler
--------
* [Add the `-C link-arg` argument][36574]
* [Remove the old AST-based backend from rustc_trans][35764]
* [Don't enable NEON by default on armv7 Linux][35814]
* [Fix debug line number info for macro expansions][35238]
* [Do not emit "class method" debuginfo for types that are not
DICompositeType][36008]
* [Warn about multiple conflicting #[repr] hints][34623]
* [When sizing DST, don't double-count nested struct prefixes][36351]
* [Default RUST_MIN_STACK to 16MiB for now][36505]
* [Improve rlib metadata format][36551]. Reduces rlib size significantly.
* [Reject macros with empty repetitions to avoid infinite loop][36721]
* [Expand macros without recursing to avoid stack overflows][36214]
Diagnostics
-----------
* [Replace macro backtraces with labeled local uses][35702]
* [Improve error message for missplaced doc comments][33922]
* [Buffer unix and lock windows to prevent message interleaving][35975]
* [Update lifetime errors to specifically note temporaries][36171]
* [Special case a few colors for Windows][36178]
* [Suggest `use self` when such an import resolves][36289]
* [Be more specific when type parameter shadows primitive type][36338]
* Many minor improvements
Compile-time Optimizations
--------------------------
* [Compute and cache HIR hashes at beginning][35854]
* [Don't hash types in loan paths][36004]
* [Cache projections in trans][35761]
* [Optimize the parser's last token handling][36527]
* [Only instantiate #[inline] functions in codegen units referencing
them][36524]. This leads to big improvements in cases where crates export
define many inline functions without using them directly.
* [Lazily allocate TypedArena's first chunk][36592]
* [Don't allocate during default HashSet creation][36734]
Stabilized APIs
---------------
* [`checked_abs`]
* [`wrapping_abs`]
* [`overflowing_abs`]
* [`RefCell::try_borrow`]
* [`RefCell::try_borrow_mut`]
Libraries
---------
* [Add `assert_ne!` and `debug_assert_ne!`][35074]
* [Make `vec_deque::Drain`, `hash_map::Drain`, and `hash_set::Drain`
covariant][35354]
* [Implement `AsRef<[T]>` for `std::slice::Iter`][35559]
* [Implement `Debug` for `std::vec::IntoIter`][35707]
* [`CString`: avoid excessive growth just to 0-terminate][35871]
* [Implement `CoerceUnsized` for `{Cell, RefCell, UnsafeCell}`][35627]
* [Use arc4rand on FreeBSD][35884]
* [memrchr: Correct aligned offset computation][35969]
* [Improve Demangling of Rust Symbols][36059]
* [Use monotonic time in condition variables][35048]
* [Implement `Debug` for `std::path::{Components,Iter}`][36101]
* [Implement conversion traits for `char`][35755]
* [Fix illegal instruction caused by overflow in channel cloning][36104]
* [Zero first byte of CString on drop][36264]
* [Inherit overflow checks for sum and product][36372]
* [Add missing Eq implementations][36423]
* [Implement `Debug` for `DirEntry`][36631]
* [When `getaddrinfo` returns `EAI_SYSTEM` retrieve actual error from
`errno`][36754]
* [`SipHasher`] is deprecated. Use [`DefaultHasher`].
* [Implement more traits for `std::io::ErrorKind`][35911]
* [Optimize BinaryHeap bounds checking][36072]
* [Work around pointer aliasing issue in `Vec::extend_from_slice`,
`extend_with_element`][36355]
* [Fix overflow checking in unsigned pow()][34942]
Cargo
-----
* This release includes security fixes to both curl and OpenSSL.
* [Fix transitive doctests when panic=abort][cargo/3021]
* [Add --all-features flag to cargo][cargo/3038]
* [Reject path-based dependencies in `cargo package`][cargo/3060]
* [Don't parse the home directory more than once][cargo/3078]
* [Don't try to generate Cargo.lock on empty workspaces][cargo/3092]
* [Update OpenSSL to 1.0.2j][cargo/3121]
* [Add license and license_file to cargo metadata output][cargo/3110]
* [Make crates-io registry URL optional in config; ignore all changes to
source.crates-io][cargo/3089]
* [Don't download dependencies from other platforms][cargo/3123]
* [Build transitive dev-dependencies when needed][cargo/3125]
* [Add support for per-target rustflags in .cargo/config][cargo/3157]
* [Avoid updating registry when adding existing deps][cargo/3144]
* [Warn about path overrides that won't work][cargo/3136]
* [Use workspaces during `cargo install`][cargo/3146]
* [Leak mspdbsrv.exe processes on Windows][cargo/3162]
* [Add --message-format flag][cargo/3000]
* [Pass target environment for rustdoc][cargo/3205]
* [Use `CommandExt::exec` for `cargo run` on Unix][cargo/2818]
* [Update curl and curl-sys][cargo/3241]
* [Call rustdoc test with the correct cfg flags of a package][cargo/3242]
Tooling
-------
* [rustdoc: Add the `--sysroot` argument][36586]
* [rustdoc: Fix a couple of issues with the search results][35655]
* [rustdoc: remove the `!` from macro URLs and titles][35234]
* [gdb: Fix pretty-printing special-cased Rust types][35585]
* [rustdoc: Filter more incorrect methods inherited through Deref][36266]
Misc
----
* [Remove unmaintained style guide][35124]
* [Add s390x support][36369]
* [Initial work at Haiku OS support][36727]
* [Add mips-uclibc targets][35734]
* [Crate-ify compiler-rt into compiler-builtins][35021]
* [Add rustc version info (git hash + date) to dist tarball][36213]
* Many documentation improvements
Compatibility Notes
-------------------
* [`SipHasher`] is deprecated. Use [`DefaultHasher`].
* [Deny (by default) transmuting from fn item types to pointer-sized
types][34923]. Continuing the long transition to zero-sized fn items,
per [RFC 401].
* [Fix `#[derive]` for empty tuple structs/variants][35728].
Part of [RFC 1506].
* [Issue deprecation warnings for safe accesses to extern statics][36173]
* [Fix lifetime rules for 'if' conditions][36029].
* [Inherit overflow checks for sum and product][36372].
* [Forbid user-defined macros named "macro_rules"][36730].
[33922]: https://github.com/rust-lang/rust/pull/33922
[34623]: https://github.com/rust-lang/rust/pull/34623
[34923]: https://github.com/rust-lang/rust/pull/34923
[34942]: https://github.com/rust-lang/rust/pull/34942
[34982]: https://github.com/rust-lang/rust/pull/34982
[35021]: https://github.com/rust-lang/rust/pull/35021
[35048]: https://github.com/rust-lang/rust/pull/35048
[35074]: https://github.com/rust-lang/rust/pull/35074
[35124]: https://github.com/rust-lang/rust/pull/35124
[35234]: https://github.com/rust-lang/rust/pull/35234
[35238]: https://github.com/rust-lang/rust/pull/35238
[35354]: https://github.com/rust-lang/rust/pull/35354
[35559]: https://github.com/rust-lang/rust/pull/35559
[35585]: https://github.com/rust-lang/rust/pull/35585
[35627]: https://github.com/rust-lang/rust/pull/35627
[35655]: https://github.com/rust-lang/rust/pull/35655
[35702]: https://github.com/rust-lang/rust/pull/35702
[35707]: https://github.com/rust-lang/rust/pull/35707
[35728]: https://github.com/rust-lang/rust/pull/35728
[35734]: https://github.com/rust-lang/rust/pull/35734
[35755]: https://github.com/rust-lang/rust/pull/35755
[35761]: https://github.com/rust-lang/rust/pull/35761
[35764]: https://github.com/rust-lang/rust/pull/35764
[35814]: https://github.com/rust-lang/rust/pull/35814
[35854]: https://github.com/rust-lang/rust/pull/35854
[35871]: https://github.com/rust-lang/rust/pull/35871
[35884]: https://github.com/rust-lang/rust/pull/35884
[35911]: https://github.com/rust-lang/rust/pull/35911
[35969]: https://github.com/rust-lang/rust/pull/35969
[35975]: https://github.com/rust-lang/rust/pull/35975
[36004]: https://github.com/rust-lang/rust/pull/36004
[36008]: https://github.com/rust-lang/rust/pull/36008
[36014]: https://github.com/rust-lang/rust/pull/36014
[36029]: https://github.com/rust-lang/rust/pull/36029
[36059]: https://github.com/rust-lang/rust/pull/36059
[36072]: https://github.com/rust-lang/rust/pull/36072
[36101]: https://github.com/rust-lang/rust/pull/36101
[36104]: https://github.com/rust-lang/rust/pull/36104
[36171]: https://github.com/rust-lang/rust/pull/36171
[36173]: https://github.com/rust-lang/rust/pull/36173
[36178]: https://github.com/rust-lang/rust/pull/36178
[36213]: https://github.com/rust-lang/rust/pull/36213
[36214]: https://github.com/rust-lang/rust/pull/36214
[36264]: https://github.com/rust-lang/rust/pull/36264
[36266]: https://github.com/rust-lang/rust/pull/36266
[36289]: https://github.com/rust-lang/rust/pull/36289
[36338]: https://github.com/rust-lang/rust/pull/36338
[36351]: https://github.com/rust-lang/rust/pull/36351
[36355]: https://github.com/rust-lang/rust/pull/36355
[36369]: https://github.com/rust-lang/rust/pull/36369
[36372]: https://github.com/rust-lang/rust/pull/36372
[36423]: https://github.com/rust-lang/rust/pull/36423
[36482]: https://github.com/rust-lang/rust/pull/36482
[36505]: https://github.com/rust-lang/rust/pull/36505
[36524]: https://github.com/rust-lang/rust/pull/36524
[36527]: https://github.com/rust-lang/rust/pull/36527
[36551]: https://github.com/rust-lang/rust/pull/36551
[36574]: https://github.com/rust-lang/rust/pull/36574
[36586]: https://github.com/rust-lang/rust/pull/36586
[36592]: https://github.com/rust-lang/rust/pull/36592
[36631]: https://github.com/rust-lang/rust/pull/36631
[36639]: https://github.com/rust-lang/rust/pull/36639
[36721]: https://github.com/rust-lang/rust/pull/36721
[36727]: https://github.com/rust-lang/rust/pull/36727
[36730]: https://github.com/rust-lang/rust/pull/36730
[36734]: https://github.com/rust-lang/rust/pull/36734
[36754]: https://github.com/rust-lang/rust/pull/36754
[36995]: https://github.com/rust-lang/rust/pull/36995
[RFC 0016]: https://github.com/rust-lang/rfcs/blob/master/text/0016-more-attributes.md
[RFC 0243]: https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md
[RFC 1506]: https://github.com/rust-lang/rfcs/blob/master/text/1506-adt-kinds.md
[RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
[RFC 873]: https://github.com/rust-lang/rfcs/blob/master/text/0873-type-macros.md
[cargo/2818]: https://github.com/rust-lang/cargo/pull/2818
[cargo/3000]: https://github.com/rust-lang/cargo/pull/3000
[cargo/3021]: https://github.com/rust-lang/cargo/pull/3021
[cargo/3038]: https://github.com/rust-lang/cargo/pull/3038
[cargo/3060]: https://github.com/rust-lang/cargo/pull/3060
[cargo/3078]: https://github.com/rust-lang/cargo/pull/3078
[cargo/3089]: https://github.com/rust-lang/cargo/pull/3089
[cargo/3092]: https://github.com/rust-lang/cargo/pull/3092
[cargo/3110]: https://github.com/rust-lang/cargo/pull/3110
[cargo/3121]: https://github.com/rust-lang/cargo/pull/3121
[cargo/3123]: https://github.com/rust-lang/cargo/pull/3123
[cargo/3125]: https://github.com/rust-lang/cargo/pull/3125
[cargo/3136]: https://github.com/rust-lang/cargo/pull/3136
[cargo/3144]: https://github.com/rust-lang/cargo/pull/3144
[cargo/3146]: https://github.com/rust-lang/cargo/pull/3146
[cargo/3157]: https://github.com/rust-lang/cargo/pull/3157
[cargo/3162]: https://github.com/rust-lang/cargo/pull/3162
[cargo/3205]: https://github.com/rust-lang/cargo/pull/3205
[cargo/3241]: https://github.com/rust-lang/cargo/pull/3241
[cargo/3242]: https://github.com/rust-lang/cargo/pull/3242
[rustup]: https://www.rustup.rs
[`checked_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.checked_abs
[`wrapping_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_abs
[`overflowing_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.overflowing_abs
[`RefCell::try_borrow`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow
[`RefCell::try_borrow_mut`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow_mut
[`SipHasher`]: https://doc.rust-lang.org/std/hash/struct.SipHasher.html
[`DefaultHasher`]: https://doc.rust-lang.org/std/collections/hash_map/struct.DefaultHasher.html
Version 1.12.1 (2016-10-20)
===========================

100
configure vendored
View File

@ -621,19 +621,22 @@ opt llvm-assertions 0 "build LLVM with assertions"
opt debug-assertions 0 "build with debugging assertions"
opt fast-make 0 "use .gitmodules as timestamp for submodule deps"
opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds"
opt sccache 0 "invoke gcc/clang via sccache to reuse object files between builds"
opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
opt local-rebuild 0 "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version"
opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM"
opt llvm-link-shared 0 "prefer shared linking to LLVM (llvm-config --link-shared)"
opt rpath 1 "build rpaths into rustc itself"
opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0"
# This is used by the automation to produce single-target nightlies
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"
opt rustbuild 1 "use the rust and cargo based build system"
opt codegen-tests 1 "run the src/test/codegen tests"
opt option-checking 1 "complain about unrecognized options in this configure script"
opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)"
opt vendor 0 "enable usage of vendored Rust crates"
# Optimization and debugging options. These may be overridden by the release channel, etc.
opt_nosave optimize 1 "build optimized rust code"
@ -641,8 +644,10 @@ opt_nosave optimize-cxx 1 "build optimized C++ code"
opt_nosave optimize-llvm 1 "build optimized LLVM"
opt_nosave llvm-assertions 0 "build LLVM with assertions"
opt_nosave debug-assertions 0 "build with debugging assertions"
opt_nosave llvm-release-debuginfo 0 "build LLVM with debugger metadata"
opt_nosave debuginfo 0 "build with debugger metadata"
opt_nosave debuginfo-lines 0 "build with line number debugger metadata"
opt_nosave debuginfo-only-std 0 "build only libstd with debugging information"
opt_nosave debug-jemalloc 0 "build jemalloc with --enable-debug --enable-fill"
valopt localstatedir "/var/lib" "local state directory"
@ -661,11 +666,11 @@ valopt armv7-linux-androideabi-ndk "" "armv7-linux-androideabi NDK standalone pa
valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path"
valopt nacl-cross-path "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!"
valopt musl-root "/usr/local" "MUSL root installation directory (deprecated)"
valopt musl-root-x86_64 "/usr/local" "x86_64-unknown-linux-musl install directory"
valopt musl-root-i686 "/usr/local" "i686-unknown-linux-musl install directory"
valopt musl-root-arm "/usr/local" "arm-unknown-linux-musleabi install directory"
valopt musl-root-armhf "/usr/local" "arm-unknown-linux-musleabihf install directory"
valopt musl-root-armv7 "/usr/local" "armv7-unknown-linux-musleabihf install directory"
valopt musl-root-x86_64 "" "x86_64-unknown-linux-musl install directory"
valopt musl-root-i686 "" "i686-unknown-linux-musl install directory"
valopt musl-root-arm "" "arm-unknown-linux-musleabi install directory"
valopt musl-root-armhf "" "arm-unknown-linux-musleabihf install directory"
valopt musl-root-armv7 "" "armv7-unknown-linux-musleabihf install directory"
valopt extra-filename "" "Additional data that is hashed and passed to the -C extra-filename flag"
if [ -e ${CFG_SRC_DIR}.git ]
@ -728,15 +733,17 @@ case "$CFG_RELEASE_CHANNEL" in
nightly )
msg "overriding settings for $CFG_RELEASE_CHANNEL"
CFG_ENABLE_LLVM_ASSERTIONS=1
# FIXME(#37364) shouldn't have to disable this on windows-gnu
# FIXME(stage0) re-enable this on the next stage0 now that #35566 is
# fixed
case "$CFG_BUILD" in
*-pc-windows-gnu)
;;
*)
CFG_ENABLE_DEBUGINFO_LINES=1
CFG_ENABLE_DEBUGINFO_LINES=1
CFG_ENABLE_DEBUGINFO_ONLY_STD=1
;;
esac
;;
beta | stable)
msg "overriding settings for $CFG_RELEASE_CHANNEL"
@ -744,7 +751,8 @@ case "$CFG_RELEASE_CHANNEL" in
*-pc-windows-gnu)
;;
*)
CFG_ENABLE_DEBUGINFO_LINES=1
CFG_ENABLE_DEBUGINFO_LINES=1
CFG_ENABLE_DEBUGINFO_ONLY_STD=1
;;
esac
;;
@ -777,8 +785,10 @@ if [ -n "$CFG_DISABLE_OPTIMIZE_CXX" ]; then putvar CFG_DISABLE_OPTIMIZE_CXX; fi
if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then putvar CFG_DISABLE_OPTIMIZE_LLVM; fi
if [ -n "$CFG_ENABLE_LLVM_ASSERTIONS" ]; then putvar CFG_ENABLE_LLVM_ASSERTIONS; fi
if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTIONS; fi
if [ -n "$CFG_ENABLE_LLVM_RELEASE_DEBUGINFO" ]; then putvar CFG_ENABLE_LLVM_RELEASE_DEBUGINFO; fi
if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi
if [ -n "$CFG_ENABLE_DEBUGINFO_LINES" ]; then putvar CFG_ENABLE_DEBUGINFO_LINES; fi
if [ -n "$CFG_ENABLE_DEBUGINFO_ONLY_STD" ]; then putvar CFG_ENABLE_DEBUGINFO_ONLY_STD; fi
if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi
step_msg "looking for build programs"
@ -844,13 +854,22 @@ then
fi
# For building LLVM
probe_need CFG_CMAKE cmake
if [ -z "$CFG_LLVM_ROOT" ]
then
probe_need CFG_CMAKE cmake
fi
# On MacOS X, invoking `javac` pops up a dialog if the JDK is not
# installed. Since `javac` is only used if `antlr4` is available,
# probe for it only in this case.
if [ -n "$CFG_ANTLR4" ]
then
CFG_ANTLR4_JAR="\"$(find /usr/ -name antlr-complete.jar 2>/dev/null | head -n 1)\""
if [ "x" = "x$CFG_ANTLR4_JAR" ]
then
CFG_ANTLR4_JAR="\"$(find ~ -name antlr-complete.jar 2>/dev/null | head -n 1)\""
fi
putvar CFG_ANTLR4_JAR $CFG_ANTLR4_JAR
probe CFG_JAVAC javac
fi
@ -1361,7 +1380,7 @@ then
fi
fi
if [ -z "$CFG_ENABLE_RUSTBUILD" ]; then
if [ -n "$CFG_DISABLE_RUSTBUILD" ]; then
step_msg "making directories"
@ -1461,7 +1480,7 @@ fi
step_msg "configuring submodules"
# Have to be in the top of src directory for this
if [ -z $CFG_DISABLE_MANAGE_SUBMODULES ] && [ -z $CFG_ENABLE_RUSTBUILD ]
if [ -z "$CFG_DISABLE_MANAGE_SUBMODULES" ] && [ -n "$CFG_DISABLE_RUSTBUILD" ]
then
cd ${CFG_SRC_DIR}
@ -1533,11 +1552,11 @@ do
;;
esac
if [ -n "$CFG_ENABLE_RUSTBUILD" ]
if [ -z "$CFG_DISABLE_RUSTBUILD" ]
then
msg "not configuring LLVM, rustbuild in use"
do_reconfigure=0
elif [ -z $CFG_LLVM_ROOT ]
elif [ -z "$CFG_LLVM_ROOT" ]
then
LLVM_BUILD_DIR=${CFG_BUILD_DIR}$t/llvm
LLVM_INST_DIR=$LLVM_BUILD_DIR
@ -1664,11 +1683,23 @@ do
LLVM_CC_64_ARG1="gcc"
;;
("gcc")
LLVM_CXX_32="g++"
LLVM_CC_32="gcc"
if [ -z "$CFG_ENABLE_SCCACHE" ]; then
LLVM_CXX_32="g++"
LLVM_CC_32="gcc"
LLVM_CXX_64="g++"
LLVM_CC_64="gcc"
LLVM_CXX_64="g++"
LLVM_CC_64="gcc"
else
LLVM_CXX_32="sccache"
LLVM_CC_32="sccache"
LLVM_CXX_32_ARG1="g++"
LLVM_CC_32_ARG1="gcc"
LLVM_CXX_64="sccache"
LLVM_CC_64="sccache"
LLVM_CXX_64_ARG1="g++"
LLVM_CC_64_ARG1="gcc"
fi
;;
(*)
@ -1771,6 +1802,8 @@ do
if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then
CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug"
elif [ -n "$CFG_ENABLE_LLVM_RELEASE_DEBUGINFO" ]; then
CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=RelWithDebInfo"
else
CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release"
fi
@ -1781,7 +1814,7 @@ do
CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON"
fi
CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend'"
CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430'"
CMAKE_ARGS="$CMAKE_ARGS -G '$CFG_CMAKE_GENERATOR'"
CMAKE_ARGS="$CMAKE_ARGS $CFG_LLVM_SRC_DIR"
@ -1856,7 +1889,7 @@ do
putvar $CFG_LLVM_INST_DIR
done
if [ -n "$CFG_ENABLE_RUSTBUILD" ]
if [ -z "$CFG_DISABLE_RUSTBUILD" ]
then
INPUT_MAKEFILE=src/bootstrap/mk/Makefile.in
else
@ -1875,5 +1908,28 @@ else
step_msg "complete"
fi
msg "run \`make help\`"
if [ "$CFG_SRC_DIR" = `pwd` ]; then
X_PY=x.py
else
X_PY=${CFG_SRC_DIR_RELATIVE}x.py
fi
if [ -z "$CFG_DISABLE_RUSTBUILD" ]; then
msg "NOTE you have now configured rust to use a rewritten build system"
msg " called rustbuild, and as a result this may have bugs that "
msg " you did not see before. If you experience any issues you can"
msg " go back to the old build system with --disable-rustbuild and"
msg " please feel free to report any bugs!"
msg ""
msg "run \`python ${X_PY} --help\`"
else
warn "the makefile-based build system is deprecated in favor of rustbuild"
msg ""
msg "It is recommended you avoid passing --disable-rustbuild to get your"
msg "build working as the makefiles will be deleted on 2017-02-02. If you"
msg "encounter bugs with rustbuild please file issues against rust-lang/rust"
msg ""
msg "run \`make help\`"
fi
msg

View File

@ -0,0 +1,26 @@
# armv5-unknown-linux-gnueabi configuration
CROSS_PREFIX_armv5te-unknown-linux-gnueabi=arm-linux-gnueabi-
CC_armv5te-unknown-linux-gnueabi=gcc
CXX_armv5te-unknown-linux-gnueabi=g++
CPP_armv5te-unknown-linux-gnueabi=gcc -E
AR_armv5te-unknown-linux-gnueabi=ar
CFG_LIB_NAME_armv5te-unknown-linux-gnueabi=lib$(1).so
CFG_STATIC_LIB_NAME_armv5te-unknown-linux-gnueabi=lib$(1).a
CFG_LIB_GLOB_armv5te-unknown-linux-gnueabi=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_armv5te-unknown-linux-gnueabi=lib$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_armv5te-unknown-linux-gnueabi := -D__arm__ -mfloat-abi=soft $(CFLAGS) -march=armv5te -marm
CFG_GCCISH_CFLAGS_armv5te-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__ -mfloat-abi=soft $(CFLAGS) -march=armv5te -marm
CFG_GCCISH_CXXFLAGS_armv5te-unknown-linux-gnueabi := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_armv5te-unknown-linux-gnueabi := -shared -fPIC -g
CFG_GCCISH_DEF_FLAG_armv5te-unknown-linux-gnueabi := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_armv5te-unknown-linux-gnueabi :=
CFG_INSTALL_NAME_ar,-unknown-linux-gnueabi =
CFG_EXE_SUFFIX_armv5te-unknown-linux-gnueabi :=
CFG_WINDOWSY_armv5te-unknown-linux-gnueabi :=
CFG_UNIXY_armv5te-unknown-linux-gnueabi := 1
CFG_LDPATH_armv5te-unknown-linux-gnueabi :=
CFG_RUN_armv5te-unknown-linux-gnueabi=$(2)
CFG_RUN_TARG_armv5te-unknown-linux-gnueabi=$(call CFG_RUN_armv5te-unknown-linux-gnueabi,,$(2))
RUSTC_FLAGS_armv5te-unknown-linux-gnueabi :=
RUSTC_CROSS_FLAGS_armv5te-unknown-linux-gnueabi :=
CFG_GNU_TRIPLE_armv5te-unknown-linux-gnueabi := armv5te-unknown-linux-gnueabi

View File

@ -0,0 +1,24 @@
# i686-unknown-openbsd configuration
CC_i686-unknown-openbsd=$(CC)
CXX_i686-unknown-openbsd=$(CXX)
CPP_i686-unknown-openbsd=$(CPP)
AR_i686-unknown-openbsd=$(AR)
CFG_LIB_NAME_i686-unknown-openbsd=lib$(1).so
CFG_STATIC_LIB_NAME_i686-unknown-openbsd=lib$(1).a
CFG_LIB_GLOB_i686-unknown-openbsd=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_i686-unknown-openbsd=$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_i686-unknown-openbsd := -m32 -I/usr/include $(CFLAGS)
CFG_GCCISH_CFLAGS_i686-unknown-openbsd := -g -fPIC -m32 -I/usr/include $(CFLAGS)
CFG_GCCISH_LINK_FLAGS_i686-unknown-openbsd := -shared -fPIC -g -pthread -m32
CFG_GCCISH_DEF_FLAG_i686-unknown-openbsd := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_i686-unknown-openbsd :=
CFG_INSTALL_NAME_i686-unknown-openbsd =
CFG_EXE_SUFFIX_i686-unknown-openbsd :=
CFG_WINDOWSY_i686-unknown-openbsd :=
CFG_UNIXY_i686-unknown-openbsd := 1
CFG_LDPATH_i686-unknown-openbsd :=
CFG_RUN_i686-unknown-openbsd=$(2)
CFG_RUN_TARG_i686-unknown-openbsd=$(call CFG_RUN_i686-unknown-openbsd,,$(2))
CFG_GNU_TRIPLE_i686-unknown-openbsd := i686-unknown-openbsd
RUSTC_FLAGS_i686-unknown-openbsd=-C linker=$(call FIND_COMPILER,$(CC))
CFG_DISABLE_JEMALLOC_i686-unknown-openbsd := 1

View File

@ -35,7 +35,7 @@ clean-all: clean clean-llvm
clean-llvm: $(CLEAN_LLVM_RULES)
clean: clean-misc $(CLEAN_STAGE_RULES)
clean: clean-misc clean-grammar $(CLEAN_STAGE_RULES)
clean-misc:
@$(call E, cleaning)
@ -47,6 +47,9 @@ clean-misc:
$(Q)rm -Rf dist/*
$(Q)rm -Rf doc
clean-grammar:
@$(call E, cleaning grammar verification)
$(Q)rm -Rf grammar
define CLEAN_GENERIC
clean-generic-$(2)-$(1):

View File

@ -52,7 +52,7 @@
TARGET_CRATES := libc std term \
getopts collections test rand \
compiler_builtins core alloc \
rustc_unicode rustc_bitflags \
std_unicode rustc_bitflags \
alloc_system alloc_jemalloc \
panic_abort panic_unwind unwind
RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
@ -65,27 +65,23 @@ HOST_CRATES := syntax syntax_ext proc_macro_tokens proc_macro_plugin syntax_pos
TOOLS := compiletest rustdoc rustc rustbook error_index_generator
DEPS_core :=
DEPS_compiler_builtins := core
DEPS_compiler_builtins := core native:compiler-rt
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_collections := core alloc std_unicode
DEPS_libc := core
DEPS_rand := core
DEPS_rustc_bitflags := core
DEPS_rustc_unicode := core
DEPS_std_unicode := core
DEPS_panic_abort := libc alloc
DEPS_panic_unwind := libc alloc unwind
DEPS_unwind := libc
RUSTFLAGS_compiler_builtins := -lstatic=compiler-rt
RUSTFLAGS_panic_abort := -C panic=abort
# FIXME(stage0): change this to just `RUSTFLAGS_panic_abort := ...`
RUSTFLAGS1_panic_abort := -C panic=abort
RUSTFLAGS2_panic_abort := -C panic=abort
RUSTFLAGS3_panic_abort := -C panic=abort
DEPS_std := core libc rand alloc collections compiler_builtins rustc_unicode \
DEPS_std := core libc rand alloc collections compiler_builtins std_unicode \
native:backtrace \
alloc_system panic_abort panic_unwind unwind
DEPS_arena := std
@ -100,7 +96,7 @@ DEPS_serialize := std log
DEPS_term := std
DEPS_test := std getopts term native:rust_test_helpers
DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos
DEPS_syntax := std term serialize log arena libc rustc_bitflags std_unicode rustc_errors syntax_pos rustc_data_structures
DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros proc_macro
DEPS_syntax_pos := serialize
DEPS_proc_macro_tokens := syntax syntax_pos log
@ -140,7 +136,7 @@ DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
DEPS_rustc_incremental := rustc syntax_pos serialize rustc_data_structures
DEPS_rustc_save_analysis := rustc log syntax syntax_pos serialize
DEPS_rustc_typeck := rustc syntax syntax_pos rustc_platform_intrinsics rustc_const_math \
rustc_const_eval rustc_errors
rustc_const_eval rustc_errors rustc_data_structures
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts test \
rustc_lint rustc_const_eval syntax_pos rustc_data_structures
@ -162,7 +158,7 @@ ONLY_RLIB_libc := 1
ONLY_RLIB_alloc := 1
ONLY_RLIB_rand := 1
ONLY_RLIB_collections := 1
ONLY_RLIB_rustc_unicode := 1
ONLY_RLIB_std_unicode := 1
ONLY_RLIB_rustc_bitflags := 1
ONLY_RLIB_alloc_system := 1
ONLY_RLIB_alloc_jemalloc := 1
@ -173,7 +169,7 @@ ONLY_RLIB_unwind := 1
TARGET_SPECIFIC_alloc_jemalloc := 1
# Documented-by-default crates
DOC_CRATES := std alloc collections core libc rustc_unicode
DOC_CRATES := std alloc collections core libc std_unicode
ifeq ($(CFG_DISABLE_JEMALLOC),)
RUSTFLAGS_rustc_back := --cfg 'feature="jemalloc"'

View File

@ -65,7 +65,8 @@ PKG_FILES := \
stage0.txt \
rust-installer \
tools \
test) \
test \
vendor) \
$(PKG_GITMODULES) \
$(filter-out config.stamp, \
$(MKFILES_FOR_TARBALL))

View File

@ -37,7 +37,7 @@ $(BG):
$(BG)RustLexer.class: $(BG) $(SG)RustLexer.g4
$(Q)$(CFG_ANTLR4) -o $(BG) $(SG)RustLexer.g4
$(Q)$(CFG_JAVAC) -d $(BG) $(BG)RustLexer.java
$(Q)$(CFG_JAVAC) -d $(BG) -classpath $(CFG_ANTLR4_JAR) $(BG)RustLexer.java
check-build-lexer-verifier: $(BG)verify

View File

@ -21,6 +21,8 @@ endif
ifdef CFG_DISABLE_OPTIMIZE_LLVM
LLVM_BUILD_CONFIG_MODE := Debug
else ifdef CFG_ENABLE_LLVM_RELEASE_DEBUGINFO
LLVM_BUILD_CONFIG_MODE := RelWithDebInfo
else
LLVM_BUILD_CONFIG_MODE := Release
endif

View File

@ -13,7 +13,7 @@
######################################################################
# The version number
CFG_RELEASE_NUM=1.14.0
CFG_RELEASE_NUM=1.15.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
@ -285,7 +285,7 @@ endif
# LLVM macros
######################################################################
LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend
LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend msp430
LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \
interpreter instrumentation
@ -372,15 +372,12 @@ CFG_INFO := $(info cfg: disabling unstable features (CFG_DISABLE_UNSTABLE_FEATUR
# Turn on feature-staging
export CFG_DISABLE_UNSTABLE_FEATURES
# Subvert unstable feature lints to do the self-build
export RUSTC_BOOTSTRAP=1
endif
ifdef CFG_MUSL_ROOT
export CFG_MUSL_ROOT
endif
# FIXME: Transitionary measure to bootstrap using the old bootstrap logic.
# Remove this once the bootstrap compiler uses the new login in Issue #36548.
export RUSTC_BOOTSTRAP_KEY=62b3e239
export RUSTC_BOOTSTRAP := 1
######################################################################
# Per-stage targets and runner
@ -443,10 +440,7 @@ endif
TSREQ$(1)_T_$(2)_H_$(3) = \
$$(HSREQ$(1)_H_$(3)) \
$$(foreach obj,$$(REQUIRED_OBJECTS_$(2)),\
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \
$$(TLIB0_T_$(2)_H_$(3))/$$(call CFG_STATIC_LIB_NAME_$(2),compiler-rt)
# ^ This copies `libcompiler-rt.a` to the stage0 sysroot
# ^ TODO(stage0) update this to not copy `libcompiler-rt.a` to stage0
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj))
# Prerequisites for a working stageN compiler and libraries, for a specific
# target

View File

@ -15,14 +15,14 @@
# The names of crates that must be tested
# libcore/librustc_unicode tests are in a separate crate
# libcore/libstd_unicode tests are in a separate crate
DEPS_coretest :=
$(eval $(call RUST_CRATE,coretest))
DEPS_collectionstest :=
$(eval $(call RUST_CRATE,collectionstest))
TEST_TARGET_CRATES = $(filter-out core rustc_unicode alloc_system libc \
TEST_TARGET_CRATES = $(filter-out core std_unicode alloc_system libc \
alloc_jemalloc panic_unwind \
panic_abort,$(TARGET_CRATES)) \
collectionstest coretest
@ -697,6 +697,8 @@ CTEST_DEPS_ui_$(1)-T-$(2)-H-$(3) = $$(UI_TESTS)
CTEST_DEPS_mir-opt_$(1)-T-$(2)-H-$(3) = $$(MIR_OPT_TESTS)
CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
$$(CSREQ$(1)_T_$(3)_H_$(3)) \
$$(SREQ$(1)_T_$(3)_H_$(3)) \
$(S)src/etc/htmldocck.py
endef

686
src/Cargo.lock generated Normal file
View File

@ -0,0 +1,686 @@
[root]
name = "unwind"
version = "0.0.0"
dependencies = [
"core 0.0.0",
"libc 0.0.0",
]
[[package]]
name = "alloc"
version = "0.0.0"
dependencies = [
"core 0.0.0",
]
[[package]]
name = "alloc_jemalloc"
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
"core 0.0.0",
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.0.0",
]
[[package]]
name = "alloc_system"
version = "0.0.0"
dependencies = [
"core 0.0.0",
"libc 0.0.0",
]
[[package]]
name = "arena"
version = "0.0.0"
[[package]]
name = "bootstrap"
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
"cmake 0.1.18 (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.40 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "build_helper"
version = "0.1.0"
[[package]]
name = "cargotest"
version = "0.1.0"
[[package]]
name = "cmake"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "collections"
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
"core 0.0.0",
"std_unicode 0.0.0",
]
[[package]]
name = "compiler_builtins"
version = "0.0.0"
dependencies = [
"core 0.0.0",
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "compiletest"
version = "0.0.0"
dependencies = [
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serialize 0.0.0",
]
[[package]]
name = "core"
version = "0.0.0"
[[package]]
name = "env_logger"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "error_index_generator"
version = "0.0.0"
[[package]]
name = "filetime"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "flate"
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fmt_macros"
version = "0.0.0"
[[package]]
name = "gcc"
version = "0.3.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "getopts"
version = "0.0.0"
[[package]]
name = "getopts"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "graphviz"
version = "0.0.0"
[[package]]
name = "libc"
version = "0.0.0"
dependencies = [
"core 0.0.0",
]
[[package]]
name = "libc"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "linkchecker"
version = "0.1.0"
[[package]]
name = "log"
version = "0.0.0"
[[package]]
name = "log"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num_cpus"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "panic_abort"
version = "0.0.0"
dependencies = [
"core 0.0.0",
"libc 0.0.0",
]
[[package]]
name = "panic_unwind"
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
"core 0.0.0",
"libc 0.0.0",
"unwind 0.0.0",
]
[[package]]
name = "proc_macro"
version = "0.0.0"
dependencies = [
"syntax 0.0.0",
]
[[package]]
name = "proc_macro_plugin"
version = "0.0.0"
dependencies = [
"log 0.0.0",
"proc_macro_tokens 0.0.0",
"rustc_plugin 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "proc_macro_tokens"
version = "0.0.0"
dependencies = [
"log 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rand"
version = "0.0.0"
dependencies = [
"core 0.0.0",
]
[[package]]
name = "rustbook"
version = "0.0.0"
[[package]]
name = "rustc"
version = "0.0.0"
dependencies = [
"arena 0.0.0",
"flate 0.0.0",
"fmt_macros 0.0.0",
"graphviz 0.0.0",
"log 0.0.0",
"rustc_back 0.0.0",
"rustc_bitflags 0.0.0",
"rustc_const_math 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"rustc_llvm 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc-main"
version = "0.0.0"
dependencies = [
"rustc_back 0.0.0",
"rustc_driver 0.0.0",
"rustdoc 0.0.0",
]
[[package]]
name = "rustc-serialize"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc_back"
version = "0.0.0"
dependencies = [
"log 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
]
[[package]]
name = "rustc_bitflags"
version = "0.0.0"
[[package]]
name = "rustc_borrowck"
version = "0.0.0"
dependencies = [
"graphviz 0.0.0",
"log 0.0.0",
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"rustc_mir 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_const_eval"
version = "0.0.0"
dependencies = [
"arena 0.0.0",
"graphviz 0.0.0",
"log 0.0.0",
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_const_math 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_const_math"
version = "0.0.0"
dependencies = [
"log 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
]
[[package]]
name = "rustc_data_structures"
version = "0.0.0"
dependencies = [
"log 0.0.0",
"serialize 0.0.0",
]
[[package]]
name = "rustc_driver"
version = "0.0.0"
dependencies = [
"arena 0.0.0",
"flate 0.0.0",
"graphviz 0.0.0",
"log 0.0.0",
"proc_macro_plugin 0.0.0",
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_borrowck 0.0.0",
"rustc_const_eval 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"rustc_incremental 0.0.0",
"rustc_lint 0.0.0",
"rustc_llvm 0.0.0",
"rustc_metadata 0.0.0",
"rustc_mir 0.0.0",
"rustc_passes 0.0.0",
"rustc_plugin 0.0.0",
"rustc_privacy 0.0.0",
"rustc_resolve 0.0.0",
"rustc_save_analysis 0.0.0",
"rustc_trans 0.0.0",
"rustc_typeck 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_ext 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_errors"
version = "0.0.0"
dependencies = [
"log 0.0.0",
"serialize 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_incremental"
version = "0.0.0"
dependencies = [
"graphviz 0.0.0",
"log 0.0.0",
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_lint"
version = "0.0.0"
dependencies = [
"log 0.0.0",
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_const_eval 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_llvm"
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_bitflags 0.0.0",
]
[[package]]
name = "rustc_metadata"
version = "0.0.0"
dependencies = [
"flate 0.0.0",
"log 0.0.0",
"proc_macro 0.0.0",
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_const_math 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"rustc_llvm 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_ext 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_mir"
version = "0.0.0"
dependencies = [
"graphviz 0.0.0",
"log 0.0.0",
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_bitflags 0.0.0",
"rustc_const_eval 0.0.0",
"rustc_const_math 0.0.0",
"rustc_data_structures 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_passes"
version = "0.0.0"
dependencies = [
"log 0.0.0",
"rustc 0.0.0",
"rustc_const_eval 0.0.0",
"rustc_const_math 0.0.0",
"rustc_errors 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_platform_intrinsics"
version = "0.0.0"
[[package]]
name = "rustc_plugin"
version = "0.0.0"
dependencies = [
"log 0.0.0",
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_bitflags 0.0.0",
"rustc_errors 0.0.0",
"rustc_metadata 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_privacy"
version = "0.0.0"
dependencies = [
"rustc 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_resolve"
version = "0.0.0"
dependencies = [
"arena 0.0.0",
"log 0.0.0",
"rustc 0.0.0",
"rustc_errors 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_save_analysis"
version = "0.0.0"
dependencies = [
"log 0.0.0",
"rustc 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_trans"
version = "0.0.0"
dependencies = [
"arena 0.0.0",
"flate 0.0.0",
"graphviz 0.0.0",
"log 0.0.0",
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_bitflags 0.0.0",
"rustc_const_eval 0.0.0",
"rustc_const_math 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"rustc_incremental 0.0.0",
"rustc_llvm 0.0.0",
"rustc_platform_intrinsics 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_typeck"
version = "0.0.0"
dependencies = [
"arena 0.0.0",
"fmt_macros 0.0.0",
"log 0.0.0",
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_const_eval 0.0.0",
"rustc_const_math 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"rustc_platform_intrinsics 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustdoc"
version = "0.0.0"
dependencies = [
"arena 0.0.0",
"build_helper 0.1.0",
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.0.0",
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_const_eval 0.0.0",
"rustc_const_math 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_driver 0.0.0",
"rustc_errors 0.0.0",
"rustc_lint 0.0.0",
"rustc_metadata 0.0.0",
"rustc_resolve 0.0.0",
"rustc_trans 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "serialize"
version = "0.0.0"
dependencies = [
"log 0.0.0",
]
[[package]]
name = "std"
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
"alloc_jemalloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
"collections 0.0.0",
"compiler_builtins 0.0.0",
"core 0.0.0",
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.0.0",
"panic_abort 0.0.0",
"panic_unwind 0.0.0",
"rand 0.0.0",
"std_unicode 0.0.0",
"unwind 0.0.0",
]
[[package]]
name = "std_shim"
version = "0.1.0"
dependencies = [
"core 0.0.0",
"std 0.0.0",
]
[[package]]
name = "std_unicode"
version = "0.0.0"
dependencies = [
"core 0.0.0",
]
[[package]]
name = "syntax"
version = "0.0.0"
dependencies = [
"log 0.0.0",
"rustc_bitflags 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"serialize 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "syntax_ext"
version = "0.0.0"
dependencies = [
"fmt_macros 0.0.0",
"log 0.0.0",
"proc_macro 0.0.0",
"rustc_errors 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "syntax_pos"
version = "0.0.0"
dependencies = [
"serialize 0.0.0",
]
[[package]]
name = "term"
version = "0.0.0"
[[package]]
name = "test"
version = "0.0.0"
dependencies = [
"getopts 0.0.0",
"term 0.0.0",
]
[[package]]
name = "test_shim"
version = "0.1.0"
dependencies = [
"test 0.0.0",
]
[[package]]
name = "tidy"
version = "0.1.0"
[[package]]
name = "toml"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0e5bcf27e097a184c1df4437654ed98df3d7a516e8508a6ba45d8b092bbdf283"
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
"checksum gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "872db9e59486ef2b14f8e8c10e9ef02de2bccef6363d7f34835dedb386b3d950"
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
"checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
"checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3"
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
"checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796"

30
src/Cargo.toml Normal file
View File

@ -0,0 +1,30 @@
[workspace]
members = [
"bootstrap",
"rustc",
"rustc/std_shim",
"rustc/test_shim",
"tools/cargotest",
"tools/compiletest",
"tools/error_index_generator",
"tools/linkchecker",
"tools/rustbook",
"tools/tidy",
]
# Curiously, compiletest will segfault if compiled with opt-level=3 on 64-bit
# MSVC when running the compile-fail test suite when a should-fail test panics.
# But hey if this is removed and it gets past the bots, sounds good to me.
[profile.release]
opt-level = 2
[profile.bench]
opt-level = 2
# These options are controlled from our rustc wrapper script, so turn them off
# here and have them controlled elsewhere.
[profile.dev]
debug = false
debug-assertions = false
[profile.test]
debug = false
debug-assertions = false

View File

@ -27,10 +27,5 @@ num_cpus = "0.2"
toml = "0.1"
getopts = "0.2"
rustc-serialize = "0.3"
gcc = "0.3.36"
gcc = "0.3.38"
libc = "0.2"
md5 = "0.1"
[target.'cfg(windows)'.dependencies]
winapi = "0.2"
kernel32-sys = "0.2"

View File

@ -22,7 +22,7 @@ Note that if you're on Unix you should be able to execute the script directly:
./x.py build
```
The script accepts commands, flags, and filters to determine what to do:
The script accepts commands, flags, and arguments to determine what to do:
* `build` - a general purpose command for compiling code. Alone `build` will
bootstrap the entire compiler, and otherwise arguments passed indicate what to
@ -32,7 +32,7 @@ The script accepts commands, flags, and filters to determine what to do:
# build the whole compiler
./x.py build
# build the stage1 compier
# build the stage1 compiler
./x.py build --stage 1
# build stage0 libstd
@ -42,6 +42,15 @@ The script accepts commands, flags, and filters to determine what to do:
./x.py build --stage 0 src/libtest
```
If files are dirty that would normally be rebuilt from stage 0, that can be
overidden using `--keep-stage 0`. Using `--keep-stage n` will skip all steps
that belong to stage n or earlier:
```
# keep old build products for stage 0 and build stage 1
./x.py build --keep-stage 0 --stage 1
```
* `test` - a command for executing unit tests. Like the `build` command this
will execute the entire test suite by default, and otherwise it can be used to
select which test suite is run:
@ -54,7 +63,7 @@ The script accepts commands, flags, and filters to determine what to do:
./x.py test src/test/run-pass
# execute only some tests in the run-pass test suite
./x.py test src/test/run-pass --filter my-filter
./x.py test src/test/run-pass --test-args substring-of-test-name
# execute tests in the standard library in stage0
./x.py test --stage 0 src/libstd
@ -66,17 +75,6 @@ The script accepts commands, flags, and filters to determine what to do:
* `doc` - a command for building documentation. Like above can take arguments
for what to document.
If you're more used to `./configure` and `make`, however, then you can also
configure the build system to use rustbuild instead of the old makefiles:
```
./configure --enable-rustbuild
make
```
Afterwards the `Makefile` which is generated will have a few commands like
`make check`, `make tidy`, etc.
## Configuring rustbuild
There are currently two primary methods for configuring the rustbuild build
@ -90,6 +88,13 @@ be found at `src/bootstrap/config.toml.example`, and the configuration file
can also be passed as `--config path/to/config.toml` if the build system is
being invoked manually (via the python script).
Finally, rustbuild makes use of the [gcc-rs crate] which has [its own
method][env-vars] of configuring C compilers and C flags via environment
variables.
[gcc-rs crate]: https://github.com/alexcrichton/gcc-rs
[env-vars]: https://github.com/alexcrichton/gcc-rs#external-configuration-via-environment-variables
## Build stages
The rustbuild build system goes through a few phases to actually build the
@ -273,16 +278,17 @@ After that, each module in rustbuild should have enough documentation to keep
you up and running. Some general areas that you may be interested in modifying
are:
* Adding a new build tool? Take a look at `build/step.rs` for examples of other
tools, as well as `build/mod.rs`.
* Adding a new build tool? Take a look at `bootstrap/step.rs` for examples of
other tools.
* Adding a new compiler crate? Look no further! Adding crates can be done by
adding a new directory with `Cargo.toml` followed by configuring all
`Cargo.toml` files accordingly.
* Adding a new dependency from crates.io? We're still working on that, so hold
off on that for now.
* Adding a new configuration option? Take a look at `build/config.rs` or perhaps
`build/flags.rs` and then modify the build elsewhere to read that option.
* Adding a sanity check? Take a look at `build/sanity.rs`.
* Adding a new configuration option? Take a look at `bootstrap/config.rs` or
perhaps `bootstrap/flags.rs` and then modify the build elsewhere to read that
option.
* Adding a sanity check? Take a look at `bootstrap/sanity.rs`.
If you have any questions feel free to reach out on `#rust-internals` on IRC or
open an issue in the bug tracker!

View File

@ -30,7 +30,7 @@ extern crate bootstrap;
use std::env;
use std::ffi::OsString;
use std::path::PathBuf;
use std::process::Command;
use std::process::{Command, ExitStatus};
fn main() {
let args = env::args_os().skip(1).collect::<Vec<_>>();
@ -125,6 +125,11 @@ fn main() {
cmd.arg("-C").arg(format!("codegen-units={}", s));
}
// Emit save-analysis info.
if env::var("RUSTC_SAVE_ANALYSIS") == Ok("api".to_string()) {
cmd.arg("-Zsave-analysis-api");
}
// Dealing with rpath here is a little special, so let's go into some
// detail. First off, `-rpath` is a linker option on Unix platforms
// which adds to the runtime dynamic loader path when looking for
@ -153,6 +158,15 @@ fn main() {
// to change a flag in a binary?
if env::var("RUSTC_RPATH") == Ok("true".to_string()) {
let rpath = if target.contains("apple") {
// Note that we need to take one extra step on OSX to also pass
// `-Wl,-instal_name,@rpath/...` to get things to work right. To
// do that we pass a weird flag to the compiler to get it to do
// so. Note that this is definitely a hack, and we should likely
// flesh out rpath support more fully in the future.
if stage != "0" {
cmd.arg("-Z").arg("osx-rpath-install-name");
}
Some("-Wl,-rpath,@loader_path/../lib")
} else if !target.contains("windows") {
Some("-Wl,-rpath,$ORIGIN/../lib")
@ -166,8 +180,19 @@ fn main() {
}
// Actually run the compiler!
std::process::exit(match cmd.status() {
Ok(s) => s.code().unwrap_or(1),
std::process::exit(match exec_cmd(&mut cmd) {
Ok(s) => s.code().unwrap_or(0xfe),
Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),
})
}
#[cfg(unix)]
fn exec_cmd(cmd: &mut Command) -> ::std::io::Result<ExitStatus> {
use std::os::unix::process::CommandExt;
Err(cmd.exec())
}
#[cfg(not(unix))]
fn exec_cmd(cmd: &mut Command) -> ::std::io::Result<ExitStatus> {
cmd.status()
}

View File

@ -30,32 +30,37 @@ def get(url, path, verbose=False):
sha_path = sha_file.name
try:
download(sha_path, sha_url, verbose)
download(sha_path, sha_url, False, verbose)
if os.path.exists(path):
if verify(path, sha_path, False):
print("using already-download file " + path)
if verbose:
print("using already-download file " + path)
return
else:
print("ignoring already-download file " + path + " due to failed verification")
if verbose:
print("ignoring already-download file " + path + " due to failed verification")
os.unlink(path)
download(temp_path, url, verbose)
if not verify(temp_path, sha_path, True):
download(temp_path, url, True, verbose)
if not verify(temp_path, sha_path, verbose):
raise RuntimeError("failed verification")
print("moving {} to {}".format(temp_path, path))
if verbose:
print("moving {} to {}".format(temp_path, path))
shutil.move(temp_path, path)
finally:
delete_if_present(sha_path)
delete_if_present(temp_path)
delete_if_present(sha_path, verbose)
delete_if_present(temp_path, verbose)
def delete_if_present(path):
def delete_if_present(path, verbose):
if os.path.isfile(path):
print("removing " + path)
if verbose:
print("removing " + path)
os.unlink(path)
def download(path, url, verbose):
print("downloading {} to {}".format(url, path))
def download(path, url, probably_big, verbose):
if probably_big or verbose:
print("downloading {}".format(url))
# see http://serverfault.com/questions/301128/how-to-download
if sys.platform == 'win32':
run(["PowerShell.exe", "/nologo", "-Command",
@ -63,17 +68,22 @@ def download(path, url, verbose):
".DownloadFile('{}', '{}')".format(url, path)],
verbose=verbose)
else:
run(["curl", "-o", path, url], verbose=verbose)
if probably_big or verbose:
option = "-#"
else:
option = "-s"
run(["curl", option, "-Sf", "-o", path, url], verbose=verbose)
def verify(path, sha_path, verbose):
print("verifying " + path)
if verbose:
print("verifying " + path)
with open(path, "rb") as f:
found = hashlib.sha256(f.read()).hexdigest()
with open(sha_path, "r") as f:
expected, _ = f.readline().split()
expected = f.readline().split()[0]
verified = found == expected
if not verified and verbose:
if not verified:
print("invalid checksum:\n"
" found: {}\n"
" expected: {}".format(found, expected))
@ -136,7 +146,7 @@ class RustBuild(object):
def download_stage0(self):
cache_dst = os.path.join(self.build_dir, "cache")
rustc_cache = os.path.join(cache_dst, self.stage0_rustc_date())
cargo_cache = os.path.join(cache_dst, self.stage0_cargo_date())
cargo_cache = os.path.join(cache_dst, self.stage0_cargo_rev())
if not os.path.exists(rustc_cache):
os.makedirs(rustc_cache)
if not os.path.exists(cargo_cache):
@ -144,6 +154,7 @@ class RustBuild(object):
if self.rustc().startswith(self.bin_root()) and \
(not os.path.exists(self.rustc()) or self.rustc_out_of_date()):
self.print_what_it_means_to_bootstrap()
if os.path.exists(self.bin_root()):
shutil.rmtree(self.bin_root())
channel = self.stage0_rustc_channel()
@ -167,21 +178,18 @@ class RustBuild(object):
if self.cargo().startswith(self.bin_root()) and \
(not os.path.exists(self.cargo()) or self.cargo_out_of_date()):
channel = self.stage0_cargo_channel()
filename = "cargo-{}-{}.tar.gz".format(channel, self.build)
url = "https://static.rust-lang.org/cargo-dist/" + self.stage0_cargo_date()
self.print_what_it_means_to_bootstrap()
filename = "cargo-nightly-{}.tar.gz".format(self.build)
url = "https://s3.amazonaws.com/rust-lang-ci/cargo-builds/" + self.stage0_cargo_rev()
tarball = os.path.join(cargo_cache, filename)
if not os.path.exists(tarball):
get("{}/{}".format(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.stage0_cargo_date())
f.write(self.stage0_cargo_rev())
def stage0_cargo_date(self):
return self._cargo_date
def stage0_cargo_channel(self):
return self._cargo_channel
def stage0_cargo_rev(self):
return self._cargo_rev
def stage0_rustc_date(self):
return self._rustc_date
@ -205,7 +213,7 @@ class RustBuild(object):
if not os.path.exists(self.cargo_stamp()) or self.clean:
return True
with open(self.cargo_stamp(), 'r') as f:
return self.stage0_cargo_date() != f.read()
return self.stage0_cargo_rev() != f.read()
def bin_root(self):
return os.path.join(self.build_dir, self.build, "stage0")
@ -226,13 +234,16 @@ class RustBuild(object):
config = self.get_toml('cargo')
if config:
return config
config = self.get_mk('CFG_LOCAL_RUST_ROOT')
if config:
return config + '/bin/cargo' + self.exe_suffix()
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')
config = self.get_mk('CFG_LOCAL_RUST_ROOT')
if config:
return config + '/bin/rustc' + self.exe_suffix()
return os.path.join(self.bin_root(), "bin/rustc" + self.exe_suffix())
@ -248,7 +259,27 @@ class RustBuild(object):
else:
return ''
def print_what_it_means_to_bootstrap(self):
if hasattr(self, 'printed'):
return
self.printed = True
if os.path.exists(self.bootstrap_binary()):
return
if not '--help' in sys.argv or len(sys.argv) == 1:
return
print('info: the build system for Rust is written in Rust, so this')
print(' script is now going to download a stage0 rust compiler')
print(' and then compile the build system itself')
print('')
print('info: in the meantime you can read more about rustbuild at')
print(' src/bootstrap/README.md before the download finishes')
def bootstrap_binary(self):
return os.path.join(self.build_dir, "bootstrap/debug/bootstrap")
def build_bootstrap(self):
self.print_what_it_means_to_bootstrap()
build_dir = os.path.join(self.build_dir, "bootstrap")
if self.clean and os.path.exists(build_dir):
shutil.rmtree(build_dir)
@ -259,9 +290,11 @@ class RustBuild(object):
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)
args = [self.cargo(), "build", "--manifest-path",
os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")]
if self.use_vendored_sources:
args.append("--frozen")
self.run(args, env)
def run(self, args, env):
proc = subprocess.Popen(args, env=env)
@ -400,9 +433,37 @@ def main():
except:
pass
rb.use_vendored_sources = '\nvendor = true' in rb.config_toml or \
'CFG_ENABLE_VENDOR' in rb.config_mk
if 'SUDO_USER' in os.environ:
if os.environ['USER'] != os.environ['SUDO_USER']:
rb.use_vendored_sources = True
print('info: looks like you are running this command under `sudo`')
print(' and so in order to preserve your $HOME this will now')
print(' use vendored sources by default. Note that if this')
print(' does not work you should run a normal build first')
print(' before running a command like `sudo make intall`')
if rb.use_vendored_sources:
if not os.path.exists('.cargo'):
os.makedirs('.cargo')
with open('.cargo/config','w') as f:
f.write("""
[source.crates-io]
replace-with = 'vendored-sources'
registry = 'https://example.com'
[source.vendored-sources]
directory = '{}/src/vendor'
""".format(rb.rust_root))
else:
if os.path.exists('.cargo'):
shutil.rmtree('.cargo')
data = stage0_data(rb.rust_root)
rb._rustc_channel, rb._rustc_date = data['rustc'].split('-', 1)
rb._cargo_channel, rb._cargo_date = data['cargo'].split('-', 1)
rb._cargo_rev = data['cargo']
start_time = time()
@ -414,7 +475,7 @@ def main():
sys.stdout.flush()
# Run the bootstrap
args = [os.path.join(rb.build_dir, "bootstrap/debug/bootstrap")]
args = [rb.bootstrap_binary()]
args.extend(sys.argv[1:])
env = os.environ.copy()
env["BUILD"] = rb.build

View File

@ -51,7 +51,7 @@ pub fn find(build: &mut Build) {
if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
cfg.compiler(cc);
} else {
set_compiler(&mut cfg, "gcc", target, config);
set_compiler(&mut cfg, "gcc", target, config, build);
}
let compiler = cfg.get_compiler();
@ -72,7 +72,7 @@ pub fn find(build: &mut Build) {
if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
cfg.compiler(cxx);
} else {
set_compiler(&mut cfg, "g++", host, config);
set_compiler(&mut cfg, "g++", host, config, build);
}
let compiler = cfg.get_compiler();
build.verbose(&format!("CXX_{} = {:?}", host, compiler.path()));
@ -83,7 +83,8 @@ pub fn find(build: &mut Build) {
fn set_compiler(cfg: &mut gcc::Config,
gnu_compiler: &str,
target: &str,
config: Option<&Target>) {
config: Option<&Target>,
build: &Build) {
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
@ -119,6 +120,22 @@ fn set_compiler(cfg: &mut gcc::Config,
}
}
"mips-unknown-linux-musl" => {
cfg.compiler("mips-linux-musl-gcc");
}
"mipsel-unknown-linux-musl" => {
cfg.compiler("mipsel-linux-musl-gcc");
}
t if t.contains("musl") => {
if let Some(root) = build.musl_root(target) {
let guess = root.join("bin/musl-gcc");
if guess.exists() {
cfg.compiler(guess);
}
}
}
_ => {}
}
}

View File

@ -15,12 +15,11 @@
//! `package_vers`, and otherwise indicating to the compiler what it should
//! print out as part of its version information.
use std::fs::{self, File};
use std::fs::File;
use std::io::prelude::*;
use std::process::Command;
use build_helper::output;
use md5;
use Build;
@ -70,7 +69,7 @@ pub fn collect(build: &mut Build) {
// If we have a git directory, add in some various SHA information of what
// commit this compiler was compiled from.
if fs::metadata(build.src.join(".git")).is_ok() {
if build.src.join(".git").is_dir() {
let ver_date = output(Command::new("git").current_dir(&build.src)
.arg("log").arg("-1")
.arg("--date=short")
@ -91,20 +90,4 @@ pub fn collect(build: &mut Build) {
build.ver_hash = Some(ver_hash);
build.short_ver_hash = Some(short_ver_hash);
}
// Calculate this compiler's bootstrap key, which is currently defined as
// the first 8 characters of the md5 of the release string.
let key = md5::compute(build.release.as_bytes());
build.bootstrap_key = format!("{:02x}{:02x}{:02x}{:02x}",
key[0], key[1], key[2], key[3]);
// Slurp up the stage0 bootstrap key as we're bootstrapping from an
// otherwise stable compiler.
let mut s = String::new();
t!(t!(File::open(build.src.join("src/stage0.txt"))).read_to_string(&mut s));
if let Some(line) = s.lines().find(|l| l.starts_with("rustc_key")) {
if let Some(key) = line.split(": ").nth(1) {
build.bootstrap_key_stage0 = key.to_string();
}
}
}

View File

@ -8,13 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation of the various `check-*` targets of the build system.
//! Implementation of the test-related targets of the build system.
//!
//! This file implements the various regression test suites that we execute on
//! our CI.
extern crate build_helper;
use std::collections::HashSet;
use std::env;
use std::fmt;
use std::fs;
use std::path::{PathBuf, Path};
use std::process::Command;
@ -22,10 +25,39 @@ use std::process::Command;
use build_helper::output;
use {Build, Compiler, Mode};
use dist;
use util::{self, dylib_path, dylib_path_var};
const ADB_TEST_DIR: &'static str = "/data/tmp";
/// The two modes of the test runner; tests or benchmarks.
#[derive(Copy, Clone)]
pub enum TestKind {
/// Run `cargo test`
Test,
/// Run `cargo bench`
Bench,
}
impl TestKind {
// Return the cargo subcommand for this test kind
fn subcommand(self) -> &'static str {
match self {
TestKind::Test => "test",
TestKind::Bench => "bench",
}
}
}
impl fmt::Display for TestKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
TestKind::Test => "Testing",
TestKind::Bench => "Benchmarking",
})
}
}
/// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
///
/// This tool in `src/tools` will verify the validity of all our links in the
@ -33,6 +65,8 @@ const ADB_TEST_DIR: &'static str = "/data/tmp";
pub fn linkcheck(build: &Build, stage: u32, host: &str) {
println!("Linkcheck stage{} ({})", stage, host);
let compiler = Compiler::new(stage, host);
let _time = util::timeit();
build.run(build.tool_cmd(&compiler, "linkchecker")
.arg(build.out.join(host).join("doc")));
}
@ -58,6 +92,7 @@ pub fn cargotest(build: &Build, stage: u32, host: &str) {
let out_dir = build.out.join("ct");
t!(fs::create_dir_all(&out_dir));
let _time = util::timeit();
build.run(build.tool_cmd(compiler, "cargotest")
.env("PATH", newpath)
.arg(&build.cargo)
@ -90,7 +125,8 @@ pub fn compiletest(build: &Build,
target: &str,
mode: &str,
suite: &str) {
println!("Check compiletest {} ({} -> {})", suite, compiler.host, target);
println!("Check compiletest suite={} mode={} ({} -> {})",
suite, mode, compiler.host, target);
let mut cmd = build.tool_cmd(compiler, "compiletest");
// compiletest currently has... a lot of arguments, so let's just pass all
@ -130,9 +166,7 @@ pub fn compiletest(build: &Build,
build.test_helpers_out(target).display()));
cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
// FIXME: CFG_PYTHON should probably be detected more robustly elsewhere
let python_default = "python";
cmd.arg("--docck-python").arg(python_default);
cmd.arg("--docck-python").arg(build.python());
if build.config.build.ends_with("apple-darwin") {
// Force /usr/bin/python on OSX for LLDB tests because we're loading the
@ -140,7 +174,7 @@ pub fn compiletest(build: &Build,
// (namely not Homebrew-installed python)
cmd.arg("--lldb-python").arg("/usr/bin/python");
} else {
cmd.arg("--lldb-python").arg(python_default);
cmd.arg("--lldb-python").arg(build.python());
}
if let Some(ref gdb) = build.config.gdb {
@ -186,6 +220,9 @@ pub fn compiletest(build: &Build,
// Running a C compiler on MSVC requires a few env vars to be set, to be
// sure to set them here.
//
// Note that if we encounter `PATH` we make sure to append to our own `PATH`
// rather than stomp over it.
if target.contains("msvc") {
for &(ref k, ref v) in build.cc[target].0.env() {
if k != "PATH" {
@ -193,7 +230,8 @@ pub fn compiletest(build: &Build,
}
}
}
build.add_bootstrap_key(&mut cmd);
cmd.env("RUSTC_BOOTSTRAP", "1");
build.add_rust_test_threads(&mut cmd);
cmd.arg("--adb-path").arg("adb");
cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
@ -205,6 +243,7 @@ pub fn compiletest(build: &Build,
cmd.arg("--android-cross-path").arg("");
}
let _time = util::timeit();
build.run(&mut cmd);
}
@ -217,6 +256,7 @@ pub fn docs(build: &Build, compiler: &Compiler) {
// Do a breadth-first traversal of the `src/doc` directory and just run
// tests for all files that end in `*.md`
let mut stack = vec![build.src.join("src/doc")];
let _time = util::timeit();
while let Some(p) = stack.pop() {
if p.is_dir() {
@ -242,7 +282,11 @@ pub fn docs(build: &Build, compiler: &Compiler) {
pub fn error_index(build: &Build, compiler: &Compiler) {
println!("Testing error-index stage{}", compiler.stage);
let output = testdir(build, compiler.host).join("error-index.md");
let dir = testdir(build, compiler.host);
t!(fs::create_dir_all(&dir));
let output = dir.join("error-index.md");
let _time = util::timeit();
build.run(build.tool_cmd(compiler, "error_index_generator")
.arg("markdown")
.arg(&output)
@ -254,8 +298,10 @@ pub fn error_index(build: &Build, compiler: &Compiler) {
fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
let mut cmd = Command::new(build.rustdoc(compiler));
build.add_rustc_lib_path(compiler, &mut cmd);
build.add_rust_test_threads(&mut cmd);
cmd.arg("--test");
cmd.arg(markdown);
cmd.env("RUSTC_BOOTSTRAP", "1");
let mut test_args = build.flags.cmd.test_args().join(" ");
if build.config.quiet_tests {
@ -278,6 +324,7 @@ pub fn krate(build: &Build,
compiler: &Compiler,
target: &str,
mode: Mode,
test_kind: TestKind,
krate: Option<&str>) {
let (name, path, features, root) = match mode {
Mode::Libstd => {
@ -291,7 +338,7 @@ pub fn krate(build: &Build,
}
_ => panic!("can only test libraries"),
};
println!("Testing {} stage{} ({} -> {})", name, compiler.stage,
println!("{} {} stage{} ({} -> {})", test_kind, name, compiler.stage,
compiler.host, target);
// Build up the base `cargo test` command.
@ -299,7 +346,7 @@ pub fn krate(build: &Build,
// Pass in some standard flags then iterate over the graph we've discovered
// in `cargo metadata` with the maps above and figure out what `-p`
// arguments need to get passed.
let mut cargo = build.cargo(compiler, mode, target, "test");
let mut cargo = build.cargo(compiler, mode, target, test_kind.subcommand());
cargo.arg("--manifest-path")
.arg(build.src.join(path).join("Cargo.toml"))
.arg("--features").arg(features);
@ -336,16 +383,25 @@ pub fn krate(build: &Build,
dylib_path.insert(0, build.sysroot_libdir(compiler, target));
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
if target.contains("android") {
cargo.arg("--no-run");
} else if target.contains("emscripten") {
cargo.arg("--no-run");
}
cargo.arg("--");
if build.config.quiet_tests {
cargo.arg("--");
cargo.arg("--quiet");
}
let _time = util::timeit();
if target.contains("android") {
build.run(cargo.arg("--no-run"));
build.run(&mut cargo);
krate_android(build, compiler, target, mode);
} else if target.contains("emscripten") {
build.run(cargo.arg("--no-run"));
build.run(&mut cargo);
krate_emscripten(build, compiler, target, mode);
} else {
cargo.args(&build.flags.cmd.test_args());
@ -372,14 +428,17 @@ fn krate_android(build: &Build,
target,
compiler.host,
test_file_name);
let quiet = if build.config.quiet_tests { "--quiet" } else { "" };
let program = format!("(cd {dir}; \
LD_LIBRARY_PATH=./{target} ./{test} \
--logfile {log} \
{quiet} \
{args})",
dir = ADB_TEST_DIR,
target = target,
test = test_file_name,
log = log,
quiet = quiet,
args = build.flags.cmd.test_args().join(" "));
let output = output(Command::new("adb").arg("shell").arg(&program));
@ -408,18 +467,12 @@ fn krate_emscripten(build: &Build,
let test_file_name = test.to_string_lossy().into_owned();
println!("running {}", test_file_name);
let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured");
let status = Command::new(nodejs)
.arg(&test_file_name)
.stderr(::std::process::Stdio::inherit())
.status();
match status {
Ok(status) => {
if !status.success() {
panic!("some tests failed");
}
}
Err(e) => panic!(format!("failed to execute command: {}", e)),
};
let mut cmd = Command::new(nodejs);
cmd.arg(&test_file_name);
if build.config.quiet_tests {
cmd.arg("--quiet");
}
build.run(&mut cmd);
}
}
@ -467,3 +520,32 @@ pub fn android_copy_libs(build: &Build,
}
}
}
/// Run "distcheck", a 'make check' from a tarball
pub fn distcheck(build: &Build) {
if build.config.build != "x86_64-unknown-linux-gnu" {
return
}
if !build.config.host.iter().any(|s| s == "x86_64-unknown-linux-gnu") {
return
}
if !build.config.target.iter().any(|s| s == "x86_64-unknown-linux-gnu") {
return
}
let dir = build.out.join("tmp").join("distcheck");
let _ = fs::remove_dir_all(&dir);
t!(fs::create_dir_all(&dir));
let mut cmd = Command::new("tar");
cmd.arg("-xzf")
.arg(dist::rust_src_location(build))
.arg("--strip-components=1")
.current_dir(&dir);
build.run(&mut cmd);
build.run(Command::new("./configure")
.current_dir(&dir));
build.run(Command::new(build_helper::make(&build.config.build))
.arg("check")
.current_dir(&dir));
}

View File

@ -46,6 +46,9 @@ fn rm_rf(build: &Build, path: &Path) {
if !path.exists() {
return
}
if path.is_file() {
return do_op(path, "remove file", |p| fs::remove_file(p));
}
for file in t!(fs::read_dir(path)) {
let file = t!(file).path();

View File

@ -120,8 +120,8 @@ fn build_startup_objects(build: &Build, target: &str, into: &Path) {
for file in t!(fs::read_dir(build.src.join("src/rtstartup"))) {
let file = t!(file);
let mut cmd = Command::new(&compiler_path);
build.add_bootstrap_key(&mut cmd);
build.run(cmd.arg("--target").arg(target)
build.run(cmd.env("RUSTC_BOOTSTRAP", "1")
.arg("--target").arg(target)
.arg("--emit=obj")
.arg("--out-dir").arg(into)
.arg(file.path()));
@ -190,6 +190,13 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
.env("CFG_PREFIX", build.config.prefix.clone().unwrap_or(String::new()))
.env("CFG_LIBDIR_RELATIVE", "lib");
// If we're not building a compiler with debugging information then remove
// these two env vars which would be set otherwise.
if build.config.rust_debuginfo_only_std {
cargo.env_remove("RUSTC_DEBUGINFO");
cargo.env_remove("RUSTC_DEBUGINFO_LINES");
}
if let Some(ref ver_date) = build.ver_date {
cargo.env("CFG_VER_DATE", ver_date);
}
@ -212,6 +219,9 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
cargo.env("LLVM_STATIC_STDCPP",
compiler_file(build.cxx(target), "libstdc++.a"));
}
if build.config.llvm_link_shared {
cargo.env("LLVM_LINK_SHARED", "1");
}
if let Some(ref s) = build.config.rustc_default_linker {
cargo.env("CFG_DEFAULT_LINKER", s);
}

View File

@ -38,19 +38,22 @@ use util::push_exe_path;
/// `src/bootstrap/config.toml.example`.
#[derive(Default)]
pub struct Config {
pub ccache: bool,
pub ccache: Option<String>,
pub ninja: bool,
pub verbose: bool,
pub submodules: bool,
pub compiler_docs: bool,
pub docs: bool,
pub vendor: bool,
pub target_config: HashMap<String, Target>,
// llvm codegen options
pub llvm_assertions: bool,
pub llvm_optimize: bool,
pub llvm_release_debuginfo: bool,
pub llvm_version_check: bool,
pub llvm_static_stdcpp: bool,
pub llvm_link_shared: bool,
// rust codegen options
pub rust_optimize: bool,
@ -58,6 +61,7 @@ pub struct Config {
pub rust_debug_assertions: bool,
pub rust_debuginfo: bool,
pub rust_debuginfo_lines: bool,
pub rust_debuginfo_only_std: bool,
pub rust_rpath: bool,
pub rustc_default_linker: Option<String>,
pub rustc_default_ar: Option<String>,
@ -88,6 +92,7 @@ pub struct Config {
pub codegen_tests: bool,
pub nodejs: Option<PathBuf>,
pub gdb: Option<PathBuf>,
pub python: Option<PathBuf>,
}
/// Per-target configuration stored in the global configuration structure.
@ -126,19 +131,35 @@ struct Build {
docs: Option<bool>,
submodules: Option<bool>,
gdb: Option<String>,
vendor: Option<bool>,
nodejs: Option<String>,
python: Option<String>,
}
/// TOML representation of how the LLVM build is configured.
#[derive(RustcDecodable, Default)]
struct Llvm {
ccache: Option<bool>,
ccache: Option<StringOrBool>,
ninja: Option<bool>,
assertions: Option<bool>,
optimize: Option<bool>,
release_debuginfo: Option<bool>,
version_check: Option<bool>,
static_libstdcpp: Option<bool>,
}
#[derive(RustcDecodable)]
enum StringOrBool {
String(String),
Bool(bool),
}
impl Default for StringOrBool {
fn default() -> StringOrBool {
StringOrBool::Bool(false)
}
}
/// TOML representation of how the Rust build is configured.
#[derive(RustcDecodable, Default)]
struct Rust {
@ -147,6 +168,7 @@ struct Rust {
debug_assertions: Option<bool>,
debuginfo: Option<bool>,
debuginfo_lines: Option<bool>,
debuginfo_only_std: Option<bool>,
debug_jemalloc: Option<bool>,
use_jemalloc: Option<bool>,
backtrace: Option<bool>,
@ -230,16 +252,28 @@ impl Config {
}
config.rustc = build.rustc.map(PathBuf::from);
config.cargo = build.cargo.map(PathBuf::from);
config.nodejs = build.nodejs.map(PathBuf::from);
config.gdb = build.gdb.map(PathBuf::from);
config.python = build.python.map(PathBuf::from);
set(&mut config.compiler_docs, build.compiler_docs);
set(&mut config.docs, build.docs);
set(&mut config.submodules, build.submodules);
set(&mut config.vendor, build.vendor);
if let Some(ref llvm) = toml.llvm {
set(&mut config.ccache, llvm.ccache);
match llvm.ccache {
Some(StringOrBool::String(ref s)) => {
config.ccache = Some(s.to_string())
}
Some(StringOrBool::Bool(true)) => {
config.ccache = Some("ccache".to_string());
}
Some(StringOrBool::Bool(false)) | None => {}
}
set(&mut config.ninja, llvm.ninja);
set(&mut config.llvm_assertions, llvm.assertions);
set(&mut config.llvm_optimize, llvm.optimize);
set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo);
set(&mut config.llvm_version_check, llvm.version_check);
set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp);
}
@ -247,6 +281,7 @@ impl Config {
set(&mut config.rust_debug_assertions, rust.debug_assertions);
set(&mut config.rust_debuginfo, rust.debuginfo);
set(&mut config.rust_debuginfo_lines, rust.debuginfo_lines);
set(&mut config.rust_debuginfo_only_std, rust.debuginfo_only_std);
set(&mut config.rust_optimize, rust.optimize);
set(&mut config.rust_optimize_tests, rust.optimize_tests);
set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests);
@ -326,18 +361,20 @@ impl Config {
}
check! {
("CCACHE", self.ccache),
("MANAGE_SUBMODULES", self.submodules),
("COMPILER_DOCS", self.compiler_docs),
("DOCS", self.docs),
("LLVM_ASSERTIONS", self.llvm_assertions),
("LLVM_RELEASE_DEBUGINFO", self.llvm_release_debuginfo),
("OPTIMIZE_LLVM", self.llvm_optimize),
("LLVM_VERSION_CHECK", self.llvm_version_check),
("LLVM_STATIC_STDCPP", self.llvm_static_stdcpp),
("LLVM_LINK_SHARED", self.llvm_link_shared),
("OPTIMIZE", self.rust_optimize),
("DEBUG_ASSERTIONS", self.rust_debug_assertions),
("DEBUGINFO", self.rust_debuginfo),
("DEBUGINFO_LINES", self.rust_debuginfo_lines),
("DEBUGINFO_ONLY_STD", self.rust_debuginfo_only_std),
("JEMALLOC", self.use_jemalloc),
("DEBUG_JEMALLOC", self.debug_jemalloc),
("RPATH", self.rust_rpath),
@ -347,6 +384,7 @@ impl Config {
("LOCAL_REBUILD", self.local_rebuild),
("NINJA", self.ninja),
("CODEGEN_TESTS", self.codegen_tests),
("VENDOR", self.vendor),
}
match key {
@ -456,6 +494,16 @@ impl Config {
self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"]));
self.cargo = Some(push_exe_path(path, &["bin", "cargo"]));
}
"CFG_PYTHON" if value.len() > 0 => {
let path = parse_configure_path(value);
self.python = Some(path);
}
"CFG_ENABLE_CCACHE" if value == "1" => {
self.ccache = Some("ccache".to_string());
}
"CFG_ENABLE_SCCACHE" if value == "1" => {
self.ccache = Some("sccache".to_string());
}
_ => {}
}
}

View File

@ -17,11 +17,16 @@
# Indicates whether the LLVM build is a Release or Debug build
#optimize = true
# Indicates whether an LLVM Release build should include debug info
#release-debuginfo = false
# Indicates whether the LLVM assertions are enabled or not
#assertions = false
# Indicates whether ccache is used when building LLVM
#ccache = false
# or alternatively ...
#ccache = "/path/to/ccache"
# If an external LLVM root is specified, we automatically check the version by
# default to make sure it's within the range that we're expecting, but setting
@ -79,9 +84,22 @@
# Indicate whether submodules are managed and updated automatically.
#submodules = true
# The path to (or name of) the GDB executable to use
# The path to (or name of) the GDB executable to use. This is only used for
# executing the debuginfo test suite.
#gdb = "gdb"
# The node.js executable to use. Note that this is only used for the emscripten
# target when running tests, otherwise this can be omitted.
#nodejs = "node"
# Python interpreter to use for various tasks throughout the build, notably
# rustdoc tests, the lldb python interpreter, and some dist bits and pieces.
# Note that Python 2 is currently required.
#python = "python2.7"
# Indicate whether the vendored sources are used for Rust dependencies or not
#vendor = false
# =============================================================================
# Options for compiling Rust code itself
# =============================================================================
@ -105,6 +123,11 @@
# Whether or not line number debug information is emitted
#debuginfo-lines = false
# Whether or not to only build debuginfo for the standard library if enabled.
# If enabled, this will not compile the compiler with debuginfo, just the
# standard library.
#debuginfo-only-std = false
# Whether or not jemalloc is built and enabled
#use-jemalloc = true

View File

@ -23,7 +23,7 @@ use std::io::Write;
use std::path::{PathBuf, Path};
use std::process::Command;
use {Build, Compiler};
use {Build, Compiler, Mode};
use util::{cp_r, libdir, is_dylib, cp_filtered, copy};
pub fn package_vers(build: &Build) -> &str {
@ -48,6 +48,11 @@ pub fn tmpdir(build: &Build) -> PathBuf {
/// Slurps up documentation from the `stage`'s `host`.
pub fn docs(build: &Build, stage: u32, host: &str) {
println!("Dist docs stage{} ({})", stage, host);
if !build.config.docs {
println!("\tskipping - docs disabled");
return
}
let name = format!("rust-docs-{}", package_vers(build));
let image = tmpdir(build).join(format!("{}-{}-image", name, name));
let _ = fs::remove_dir_all(&image);
@ -92,6 +97,7 @@ pub fn mingw(build: &Build, host: &str) {
let name = format!("rust-mingw-{}", package_vers(build));
let image = tmpdir(build).join(format!("{}-{}-image", name, host));
let _ = fs::remove_dir_all(&image);
t!(fs::create_dir_all(&image));
// The first argument to the script is a "temporary directory" which is just
// thrown away (this contains the runtime DLLs included in the rustc package
@ -99,7 +105,7 @@ pub fn mingw(build: &Build, host: &str) {
// (which is what we want).
//
// FIXME: this script should be rewritten into Rust
let mut cmd = Command::new("python");
let mut cmd = Command::new(build.python());
cmd.arg(build.src.join("src/etc/make-win-dist.py"))
.arg(tmpdir(build))
.arg(&image)
@ -159,7 +165,7 @@ pub fn rustc(build: &Build, stage: u32, host: &str) {
//
// FIXME: this script should be rewritten into Rust
if host.contains("pc-windows-gnu") {
let mut cmd = Command::new("python");
let mut cmd = Command::new(build.python());
cmd.arg(build.src.join("src/etc/make-win-dist.py"))
.arg(&image)
.arg(tmpdir(build))
@ -260,6 +266,14 @@ pub fn debugger_scripts(build: &Build,
pub fn std(build: &Build, compiler: &Compiler, target: &str) {
println!("Dist std stage{} ({} -> {})", compiler.stage, compiler.host,
target);
// The only true set of target libraries came from the build triple, so
// let's reduce redundant work by only producing archives from that host.
if compiler.host != build.config.build {
println!("\tskipping, not a build host");
return
}
let name = format!("rust-std-{}", package_vers(build));
let image = tmpdir(build).join(format!("{}-{}-image", name, target));
let _ = fs::remove_dir_all(&image);
@ -284,6 +298,53 @@ pub fn std(build: &Build, compiler: &Compiler, target: &str) {
t!(fs::remove_dir_all(&image));
}
pub fn rust_src_location(build: &Build) -> PathBuf {
let plain_name = format!("rustc-{}-src", package_vers(build));
distdir(build).join(&format!("{}.tar.gz", plain_name))
}
/// Creates a tarball of save-analysis metadata, if available.
pub fn analysis(build: &Build, compiler: &Compiler, target: &str) {
println!("Dist analysis");
if build.config.channel != "nightly" {
println!("\tskipping - not on nightly channel");
return;
}
if compiler.host != build.config.build {
println!("\tskipping - not a build host");
return
}
if compiler.stage != 2 {
println!("\tskipping - not stage2");
return
}
let name = format!("rust-analysis-{}", package_vers(build));
let image = tmpdir(build).join(format!("{}-{}-image", name, target));
let src = build.stage_out(compiler, Mode::Libstd).join(target).join("release").join("deps");
let image_src = src.join("save-analysis");
let dst = image.join("lib/rustlib").join(target).join("analysis");
t!(fs::create_dir_all(&dst));
cp_r(&image_src, &dst);
let mut cmd = Command::new("sh");
cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh")))
.arg("--product-name=Rust")
.arg("--rel-manifest-dir=rustlib")
.arg("--success-message=save-analysis-saved.")
.arg(format!("--image-dir={}", sanitize_sh(&image)))
.arg(format!("--work-dir={}", sanitize_sh(&tmpdir(build))))
.arg(format!("--output-dir={}", sanitize_sh(&distdir(build))))
.arg(format!("--package-name={}-{}", name, target))
.arg(format!("--component-name=rust-analysis-{}", target))
.arg("--legacy-manifest-dirs=rustlib,cargo");
build.run(&mut cmd);
t!(fs::remove_dir_all(&image));
}
/// Creates the `rust-src` installer component and the plain source tarball
pub fn rust_src(build: &Build) {
println!("Dist src");
@ -330,6 +391,13 @@ pub fn rust_src(build: &Build) {
}
}
// If we're inside the vendor directory then we need to preserve
// everything as Cargo's vendoring support tracks all checksums and we
// want to be sure we don't accidentally leave out a file.
if spath.contains("vendor") {
return true
}
let excludes = [
"CVS", "RCS", "SCCS", ".git", ".gitignore", ".gitmodules",
".gitattributes", ".cvsignore", ".svn", ".arch-ids", "{arch}",
@ -374,7 +442,7 @@ pub fn rust_src(build: &Build) {
// Create plain source tarball
let mut cmd = Command::new("tar");
cmd.arg("-czf").arg(sanitize_sh(&distdir(build).join(&format!("{}.tar.gz", plain_name))))
cmd.arg("-czf").arg(sanitize_sh(&rust_src_location(build)))
.arg(&plain_name)
.current_dir(&dst);
build.run(&mut cmd);

View File

@ -146,7 +146,17 @@ pub fn std(build: &Build, stage: u32, target: &str) {
let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc");
cargo.arg("--manifest-path")
.arg(build.src.join("src/rustc/std_shim/Cargo.toml"))
.arg("--features").arg(build.std_features());
.arg("--features").arg(build.std_features())
.arg("--no-deps");
for krate in &["alloc", "collections", "core", "std", "std_unicode"] {
cargo.arg("-p").arg(krate);
// Create all crate output directories first to make sure rustdoc uses
// relative links.
// FIXME: Cargo should probably do this itself.
t!(fs::create_dir_all(out_dir.join(krate)));
}
build.run(&mut cargo);
cp_r(&out_dir, &out)
}

View File

@ -29,6 +29,7 @@ use step;
pub struct Flags {
pub verbose: bool,
pub stage: Option<u32>,
pub keep_stage: Option<u32>,
pub build: String,
pub host: Vec<String>,
pub target: Vec<String>,
@ -49,6 +50,10 @@ pub enum Subcommand {
paths: Vec<PathBuf>,
test_args: Vec<String>,
},
Bench {
paths: Vec<PathBuf>,
test_args: Vec<String>,
},
Clean,
Dist {
install: bool,
@ -64,6 +69,7 @@ impl Flags {
opts.optmulti("", "host", "host targets to build", "HOST");
opts.optmulti("", "target", "target targets to build", "TARGET");
opts.optopt("", "stage", "stage to build", "N");
opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
opts.optflag("h", "help", "print this help message");
@ -104,7 +110,6 @@ Arguments:
tests that should be compiled and run. For example:
./x.py test src/test/run-pass
./x.py test src/test/run-pass/assert-*
./x.py test src/libstd --test-args hash_map
./x.py test src/libstd --stage 0
@ -141,6 +146,7 @@ Arguments:
command == "dist" ||
command == "doc" ||
command == "test" ||
command == "bench" ||
command == "clean" {
println!("Available invocations:");
if args.iter().any(|a| a == "-v") {
@ -163,6 +169,7 @@ println!("\
Subcommands:
build Compile either the compiler or libraries
test Build and run some test suites
bench Build and run some benchmarks
doc Build documentation
clean Clean out build directories
dist Build and/or install distribution artifacts
@ -210,6 +217,14 @@ To learn more about a subcommand, run `./x.py <command> -h`
test_args: m.opt_strs("test-args"),
}
}
"bench" => {
opts.optmulti("", "test-args", "extra arguments", "ARGS");
m = parse(&opts);
Subcommand::Bench {
paths: remaining_as_path(&m),
test_args: m.opt_strs("test-args"),
}
}
"clean" => {
m = parse(&opts);
if m.free.len() > 0 {
@ -225,6 +240,7 @@ To learn more about a subcommand, run `./x.py <command> -h`
install: m.opt_present("install"),
}
}
"--help" => usage(0, &opts),
cmd => {
println!("unknown command: {}", cmd);
usage(1, &opts);
@ -243,6 +259,7 @@ To learn more about a subcommand, run `./x.py <command> -h`
Flags {
verbose: m.opt_present("v"),
stage: m.opt_str("stage").map(|j| j.parse().unwrap()),
keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()),
build: m.opt_str("build").unwrap_or_else(|| {
env::var("BUILD").unwrap()
}),
@ -259,7 +276,8 @@ To learn more about a subcommand, run `./x.py <command> -h`
impl Subcommand {
pub fn test_args(&self) -> Vec<&str> {
match *self {
Subcommand::Test { ref test_args, .. } => {
Subcommand::Test { ref test_args, .. } |
Subcommand::Bench { ref test_args, .. } => {
test_args.iter().flat_map(|s| s.split_whitespace()).collect()
}
_ => Vec::new(),

View File

@ -37,17 +37,95 @@
//! 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;
#![allow(bad_style, dead_code)]
use std::env;
use std::io;
use std::mem;
use self::winapi::*;
use self::kernel32::*;
type HANDLE = *mut u8;
type BOOL = i32;
type DWORD = u32;
type LPHANDLE = *mut HANDLE;
type LPVOID = *mut u8;
type JOBOBJECTINFOCLASS = i32;
type SIZE_T = usize;
type LARGE_INTEGER = i64;
type UINT = u32;
type ULONG_PTR = usize;
type ULONGLONG = u64;
const FALSE: BOOL = 0;
const DUPLICATE_SAME_ACCESS: DWORD = 0x2;
const PROCESS_DUP_HANDLE: DWORD = 0x40;
const JobObjectExtendedLimitInformation: JOBOBJECTINFOCLASS = 9;
const JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE: DWORD = 0x2000;
const SEM_FAILCRITICALERRORS: UINT = 0x0001;
const SEM_NOGPFAULTERRORBOX: UINT = 0x0002;
extern "system" {
fn CreateJobObjectW(lpJobAttributes: *mut u8, lpName: *const u8) -> HANDLE;
fn CloseHandle(hObject: HANDLE) -> BOOL;
fn GetCurrentProcess() -> HANDLE;
fn OpenProcess(dwDesiredAccess: DWORD,
bInheritHandle: BOOL,
dwProcessId: DWORD) -> HANDLE;
fn DuplicateHandle(hSourceProcessHandle: HANDLE,
hSourceHandle: HANDLE,
hTargetProcessHandle: HANDLE,
lpTargetHandle: LPHANDLE,
dwDesiredAccess: DWORD,
bInheritHandle: BOOL,
dwOptions: DWORD) -> BOOL;
fn AssignProcessToJobObject(hJob: HANDLE, hProcess: HANDLE) -> BOOL;
fn SetInformationJobObject(hJob: HANDLE,
JobObjectInformationClass: JOBOBJECTINFOCLASS,
lpJobObjectInformation: LPVOID,
cbJobObjectInformationLength: DWORD) -> BOOL;
fn SetErrorMode(mode: UINT) -> UINT;
}
#[repr(C)]
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION {
BasicLimitInformation: JOBOBJECT_BASIC_LIMIT_INFORMATION,
IoInfo: IO_COUNTERS,
ProcessMemoryLimit: SIZE_T,
JobMemoryLimit: SIZE_T,
PeakProcessMemoryUsed: SIZE_T,
PeakJobMemoryUsed: SIZE_T,
}
#[repr(C)]
struct IO_COUNTERS {
ReadOperationCount: ULONGLONG,
WriteOperationCount: ULONGLONG,
OtherOperationCount: ULONGLONG,
ReadTransferCount: ULONGLONG,
WriteTransferCount: ULONGLONG,
OtherTransferCount: ULONGLONG,
}
#[repr(C)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION {
PerProcessUserTimeLimit: LARGE_INTEGER,
PerJobUserTimeLimit: LARGE_INTEGER,
LimitFlags: DWORD,
MinimumWorkingsetSize: SIZE_T,
MaximumWorkingsetSize: SIZE_T,
ActiveProcessLimit: DWORD,
Affinity: ULONG_PTR,
PriorityClass: DWORD,
SchedulingClass: DWORD,
}
pub unsafe fn setup() {
// Tell Windows to not show any UI on errors (such as not finding a required dll
// during startup or terminating abnormally). This is important for running tests,
// since some of them use abnormal termination by design.
// This mode is inherited by all child processes.
let mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags
SetErrorMode(mode | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
// 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());

View File

@ -13,22 +13,69 @@
//! This module, and its descendants, are the implementation of the Rust build
//! system. Most of this build system is backed by Cargo but the outer layer
//! here serves as the ability to orchestrate calling Cargo, sequencing Cargo
//! builds, building artifacts like LLVM, etc.
//! builds, building artifacts like LLVM, etc. The goals of rustbuild are:
//!
//! More documentation can be found in each respective module below.
//! * To be an easily understandable, easily extensible, and maintainable build
//! system.
//! * Leverage standard tools in the Rust ecosystem to build the compiler, aka
//! crates.io and Cargo.
//! * A standard interface to build across all platforms, including MSVC
//!
//! ## Architecture
//!
//! Although this build system defers most of the complicated logic to Cargo
//! itself, it still needs to maintain a list of targets and dependencies which
//! it can itself perform. Rustbuild is made up of a list of rules with
//! dependencies amongst them (created in the `step` module) and then knows how
//! to execute each in sequence. Each time rustbuild is invoked, it will simply
//! iterate through this list of steps and execute each serially in turn. For
//! each step rustbuild relies on the step internally being incremental and
//! parallel. Note, though, that the `-j` parameter to rustbuild gets forwarded
//! to appropriate test harnesses and such.
//!
//! Most of the "meaty" steps that matter are backed by Cargo, which does indeed
//! have its own parallelism and incremental management. Later steps, like
//! tests, aren't incremental and simply run the entire suite currently.
//!
//! When you execute `x.py build`, the steps which are executed are:
//!
//! * First, the python script is run. This will automatically download the
//! stage0 rustc and cargo according to `src/stage0.txt`, or using the cached
//! versions if they're available. These are then used to compile rustbuild
//! itself (using Cargo). Finally, control is then transferred to rustbuild.
//!
//! * Rustbuild takes over, performs sanity checks, probes the environment,
//! reads configuration, builds up a list of steps, and then starts executing
//! them.
//!
//! * The stage0 libstd is compiled
//! * The stage0 libtest is compiled
//! * The stage0 librustc is compiled
//! * The stage1 compiler is assembled
//! * The stage1 libstd, libtest, librustc are compiled
//! * The stage2 compiler is assembled
//! * The stage2 libstd, libtest, librustc are compiled
//!
//! Each step is driven by a separate Cargo project and rustbuild orchestrates
//! copying files between steps and otherwise preparing for Cargo to run.
//!
//! ## Further information
//!
//! More documentation can be found in each respective module below, and you can
//! also check out the `src/bootstrap/README.md` file for more information.
extern crate build_helper;
extern crate cmake;
extern crate filetime;
extern crate gcc;
extern crate getopts;
extern crate md5;
extern crate num_cpus;
extern crate rustc_serialize;
extern crate toml;
use std::collections::HashMap;
use std::env;
use std::ffi::OsString;
use std::fs::{self, File};
use std::path::{Component, PathBuf, Path};
use std::process::Command;
@ -120,8 +167,6 @@ pub struct Build {
version: String,
package_vers: String,
local_rebuild: bool,
bootstrap_key: String,
bootstrap_key_stage0: String,
// Probed tools at runtime
lldb_version: Option<String>,
@ -131,6 +176,7 @@ pub struct Build {
cc: HashMap<String, (gcc::Tool, Option<PathBuf>)>,
cxx: HashMap<String, gcc::Tool>,
crates: HashMap<String, Crate>,
is_sudo: bool,
}
#[derive(Debug)]
@ -141,6 +187,7 @@ struct Crate {
doc_step: String,
build_step: String,
test_step: String,
bench_step: String,
}
/// The various "modes" of invoking Cargo.
@ -189,6 +236,16 @@ impl Build {
};
let local_rebuild = config.local_rebuild;
let is_sudo = match env::var_os("SUDO_USER") {
Some(sudo_user) => {
match env::var_os("USER") {
Some(user) => user != sudo_user,
None => false,
}
}
None => false,
};
Build {
flags: flags,
config: config,
@ -204,14 +261,13 @@ impl Build {
ver_date: None,
version: String::new(),
local_rebuild: local_rebuild,
bootstrap_key: String::new(),
bootstrap_key_stage0: String::new(),
package_vers: String::new(),
cc: HashMap::new(),
cxx: HashMap::new(),
crates: HashMap::new(),
lldb_version: None,
lldb_python_dir: None,
is_sudo: is_sudo,
}
}
@ -418,7 +474,7 @@ impl Build {
// how the actual compiler itself is called.
//
// These variables are primarily all read by
// src/bootstrap/{rustc,rustdoc.rs}
// src/bootstrap/bin/{rustc.rs,rustdoc.rs}
cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc"))
.env("RUSTC_REAL", self.compiler_path(compiler))
.env("RUSTC_STAGE", stage.to_string())
@ -437,7 +493,9 @@ impl Build {
.env("RUSTDOC_REAL", self.rustdoc(compiler))
.env("RUSTC_FLAGS", self.rustc_flags(target).join(" "));
self.add_bootstrap_key(&mut cargo);
// Enable usage of unstable features
cargo.env("RUSTC_BOOTSTRAP", "1");
self.add_rust_test_threads(&mut cargo);
// Specify some various options for build scripts used throughout
// the build.
@ -449,6 +507,10 @@ impl Build {
.env(format!("CFLAGS_{}", target), self.cflags(target).join(" "));
}
if self.config.channel == "nightly" && compiler.stage == 2 {
cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
}
// Environment variables *required* needed throughout the build
//
// FIXME: should update code to not require this env var
@ -457,9 +519,13 @@ impl Build {
if self.config.verbose || self.flags.verbose {
cargo.arg("-v");
}
if self.config.rust_optimize {
// FIXME: cargo bench does not accept `--release`
if self.config.rust_optimize && cmd != "bench" {
cargo.arg("--release");
}
if self.config.vendor || self.is_sudo {
cargo.arg("--frozen");
}
return cargo
}
@ -491,12 +557,30 @@ impl Build {
fn tool_cmd(&self, compiler: &Compiler, tool: &str) -> Command {
let mut cmd = Command::new(self.tool(&compiler, tool));
let host = compiler.host;
let paths = vec![
let mut paths = vec![
self.cargo_out(compiler, Mode::Libstd, host).join("deps"),
self.cargo_out(compiler, Mode::Libtest, host).join("deps"),
self.cargo_out(compiler, Mode::Librustc, host).join("deps"),
self.cargo_out(compiler, Mode::Tool, host).join("deps"),
];
// On MSVC a tool may invoke a C compiler (e.g. compiletest in run-make
// mode) and that C compiler may need some extra PATH modification. Do
// so here.
if compiler.host.contains("msvc") {
let curpaths = env::var_os("PATH").unwrap_or(OsString::new());
let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>();
for &(ref k, ref v) in self.cc[compiler.host].0.env() {
if k != "PATH" {
continue
}
for path in env::split_paths(v) {
if !curpaths.contains(&path) {
paths.push(path);
}
}
}
}
add_lib_path(paths, &mut cmd);
return cmd
}
@ -504,7 +588,7 @@ impl Build {
/// Get the space-separated set of activated features for the standard
/// library.
fn std_features(&self) -> String {
let mut features = String::new();
let mut features = "panic-unwind".to_string();
if self.config.debug_jemalloc {
features.push_str(" debug-jemalloc");
}
@ -650,12 +734,11 @@ impl Build {
add_lib_path(vec![self.rustc_libdir(compiler)], cmd);
}
/// Adds the compiler's bootstrap key to the environment of `cmd`.
fn add_bootstrap_key(&self, cmd: &mut Command) {
cmd.env("RUSTC_BOOTSTRAP", "1");
// FIXME: Transitionary measure to bootstrap using the old bootstrap logic.
// Remove this once the bootstrap compiler uses the new login in Issue #36548.
cmd.env("RUSTC_BOOTSTRAP_KEY", "62b3e239");
/// Adds the `RUST_TEST_THREADS` env var if necessary
fn add_rust_test_threads(&self, cmd: &mut Command) {
if env::var_os("RUST_TEST_THREADS").is_none() {
cmd.env("RUST_TEST_THREADS", self.jobs().to_string());
}
}
/// Returns the compiler's libdir where it stores the dynamic libraries that
@ -771,6 +854,11 @@ impl Build {
.or(self.config.musl_root.as_ref())
.map(|p| &**p)
}
/// Path to the python interpreter to use
fn python(&self) -> &Path {
self.config.python.as_ref().unwrap()
}
}
impl<'a> Compiler<'a> {

View File

@ -70,6 +70,7 @@ fn build_krate(build: &mut Build, krate: &str) {
build_step: format!("build-crate-{}", package.name),
doc_step: format!("doc-crate-{}", package.name),
test_step: format!("test-crate-{}", package.name),
bench_step: format!("bench-crate-{}", package.name),
name: package.name,
deps: Vec::new(),
path: path,

View File

@ -1,4 +1,4 @@
# Copyright 20126 The Rust Project Developers. See the COPYRIGHT
# 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.
#
@ -23,9 +23,14 @@ all:
$(Q)$(BOOTSTRAP) build $(BOOTSTRAP_ARGS)
$(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS)
# Dont use $(Q) here, always show how to invoke the bootstrap script directly
help:
$(BOOTSTRAP) --help
$(Q)echo 'Welcome to the rustbuild build system!'
$(Q)echo
$(Q)echo This makefile is a thin veneer over the ./x.py script located
$(Q)echo in this directory. To get the full power of the build system
$(Q)echo you can run x.py directly.
$(Q)echo
$(Q)echo To learn more run \`./x.py --help\`
clean:
$(Q)$(BOOTSTRAP) clean $(BOOTSTRAP_ARGS)
@ -50,13 +55,18 @@ check-cargotest:
$(Q)$(BOOTSTRAP) test src/tools/cargotest $(BOOTSTRAP_ARGS)
dist:
$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
distcheck:
$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
$(Q)$(BOOTSTRAP) test distcheck $(BOOTSTRAP_ARGS)
install:
ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
$(Q)echo "'sudo make install' is not supported currently."
else
$(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS)
endif
tidy:
$(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS)
$(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS) --stage 0
check-stage2-T-arm-linux-androideabi-H-x86_64-unknown-linux-gnu:
$(Q)$(BOOTSTRAP) test --target arm-linux-androideabi
check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu:
$(Q)$(BOOTSTRAP) test --target x86_64-unknown-linux-gnu
.PHONY: dist

View File

@ -28,7 +28,7 @@ use cmake;
use gcc;
use Build;
use util::up_to_date;
use util::{self, up_to_date};
/// Compile LLVM for `target`.
pub fn llvm(build: &Build, target: &str) {
@ -58,6 +58,7 @@ pub fn llvm(build: &Build, target: &str) {
println!("Building LLVM for {}", target);
let _time = util::timeit();
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"};
@ -67,12 +68,20 @@ pub fn llvm(build: &Build, target: &str) {
if build.config.ninja {
cfg.generator("Ninja");
}
let profile = match (build.config.llvm_optimize, build.config.llvm_release_debuginfo) {
(false, _) => "Debug",
(true, false) => "Release",
(true, true) => "RelWithDebInfo",
};
cfg.target(target)
.host(&build.config.build)
.out_dir(&dst)
.profile(if build.config.llvm_optimize {"Release"} else {"Debug"})
.profile(profile)
.define("LLVM_ENABLE_ASSERTIONS", assertions)
.define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend")
.define("LLVM_TARGETS_TO_BUILD",
"X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430")
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
.define("LLVM_INCLUDE_TESTS", "OFF")
.define("LLVM_INCLUDE_DOCS", "OFF")
@ -100,10 +109,10 @@ pub fn llvm(build: &Build, target: &str) {
// MSVC handles compiler business itself
if !target.contains("msvc") {
if build.config.ccache {
cfg.define("CMAKE_C_COMPILER", "ccache")
if let Some(ref ccache) = 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", ccache)
.define("CMAKE_CXX_COMPILER_ARG1", build.cxx(target));
} else {
cfg.define("CMAKE_C_COMPILER", build.cc(target))
@ -150,6 +159,17 @@ pub fn test_helpers(build: &Build, target: &str) {
println!("Building test helpers");
t!(fs::create_dir_all(&dst));
let mut cfg = gcc::Config::new();
// We may have found various cross-compilers a little differently due to our
// extra configuration, so inform gcc of these compilers. Note, though, that
// on MSVC we still need gcc's detection of env vars (ugh).
if !target.contains("msvc") {
if let Some(ar) = build.ar(target) {
cfg.archiver(ar);
}
cfg.compiler(build.cc(target));
}
cfg.cargo_metadata(false)
.out_dir(&dst)
.target(target)

View File

@ -41,10 +41,14 @@ pub fn check(build: &mut Build) {
}
}
let have_cmd = |cmd: &OsStr| {
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 Some(path);
for path in env::split_paths(&path) {
let target = path.join(cmd);
let mut cmd_alt = cmd.to_os_string();
cmd_alt.push(".exe");
if target.exists() ||
target.with_extension("exe").exists() ||
target.join(cmd_alt).exists() {
return Some(target);
}
}
return None;
@ -79,17 +83,28 @@ pub fn check(build: &mut Build) {
break
}
need_cmd("python".as_ref());
// Look for the nodejs command, needed for emscripten testing
if let Some(node) = have_cmd("node".as_ref()) {
build.config.nodejs = Some(node);
} else if let Some(node) = have_cmd("nodejs".as_ref()) {
build.config.nodejs = Some(node);
if build.config.python.is_none() {
build.config.python = have_cmd("python2.7".as_ref());
}
if build.config.python.is_none() {
build.config.python = have_cmd("python2".as_ref());
}
if build.config.python.is_none() {
need_cmd("python".as_ref());
build.config.python = Some("python".into());
}
need_cmd(build.config.python.as_ref().unwrap().as_ref());
if let Some(ref s) = build.config.nodejs {
need_cmd(s.as_ref());
} else {
// Look for the nodejs command, needed for emscripten testing
if let Some(node) = have_cmd("node".as_ref()) {
build.config.nodejs = Some(node);
} else if let Some(node) = have_cmd("nodejs".as_ref()) {
build.config.nodejs = Some(node);
}
}
if let Some(ref gdb) = build.config.gdb {
@ -208,4 +223,8 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
if build.lldb_version.is_some() {
build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
}
if let Some(ref s) = build.config.ccache {
need_cmd(s.as_ref());
}
}

View File

@ -8,10 +8,28 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Definition of steps of the build system.
//!
//! This is where some of the real meat of rustbuild is located, in how we
//! define targets and the dependencies amongst them. This file can sort of be
//! viewed as just defining targets in a makefile which shell out to predefined
//! functions elsewhere about how to execute the target.
//!
//! The primary function here you're likely interested in is the `build_rules`
//! function. This will create a `Rules` structure which basically just lists
//! everything that rustbuild can do. Each rule has a human-readable name, a
//! path associated with it, some dependencies, and then a closure of how to
//! actually perform the rule.
//!
//! All steps below are defined in self-contained units, so adding a new target
//! to the build system should just involve adding the meta information here
//! along with the actual implementation elsewhere. You can find more comments
//! about how to define rules themselves below.
use std::collections::{HashMap, HashSet};
use std::mem;
use check;
use check::{self, TestKind};
use compile;
use dist;
use doc;
@ -20,36 +38,6 @@ use install;
use native;
use {Compiler, Build, Mode};
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
struct Step<'a> {
name: &'a str,
stage: u32,
host: &'a str,
target: &'a str,
}
impl<'a> Step<'a> {
fn name(&self, name: &'a str) -> Step<'a> {
Step { name: name, ..*self }
}
fn stage(&self, stage: u32) -> Step<'a> {
Step { stage: stage, ..*self }
}
fn host(&self, host: &'a str) -> Step<'a> {
Step { host: host, ..*self }
}
fn target(&self, target: &'a str) -> Step<'a> {
Step { target: target, ..*self }
}
fn compiler(&self) -> Compiler<'a> {
Compiler::new(self.stage, self.host)
}
}
pub fn run(build: &Build) {
let rules = build_rules(build);
let steps = rules.plan();
@ -57,14 +45,91 @@ pub fn run(build: &Build) {
}
pub fn build_rules(build: &Build) -> Rules {
let mut rules: Rules = Rules::new(build);
let mut rules = Rules::new(build);
// This is the first rule that we're going to define for rustbuild, which is
// used to compile LLVM itself. All rules are added through the `rules`
// structure created above and are configured through a builder-style
// interface.
//
// First up we see the `build` method. This represents a rule that's part of
// the top-level `build` subcommand. For example `./x.py build` is what this
// is associating with. Note that this is normally only relevant if you flag
// a rule as `default`, which we'll talk about later.
//
// Next up we'll see two arguments to this method:
//
// * `llvm` - this is the "human readable" name of this target. This name is
// not accessed anywhere outside this file itself (e.g. not in
// the CLI nor elsewhere in rustbuild). The purpose of this is to
// easily define dependencies between rules. That is, other rules
// will depend on this with the name "llvm".
// * `src/llvm` - this is the relevant path to the rule that we're working
// with. This path is the engine behind how commands like
// `./x.py build src/llvm` work. This should typically point
// to the relevant component, but if there's not really a
// path to be assigned here you can pass something like
// `path/to/nowhere` to ignore it.
//
// After we create the rule with the `build` method we can then configure
// various aspects of it. For example this LLVM rule uses `.host(true)` to
// flag that it's a rule only for host targets. In other words, LLVM isn't
// compiled for targets configured through `--target` (e.g. those we're just
// building a standard library for).
//
// Next up the `dep` method will add a dependency to this rule. The closure
// is yielded the step that represents executing the `llvm` rule itself
// (containing information like stage, host, target, ...) and then it must
// return a target that the step depends on. Here LLVM is actually
// interesting where a cross-compiled LLVM depends on the host LLVM, but
// otherwise it has no dependencies.
//
// To handle this we do a bit of dynamic dispatch to see what the dependency
// is. If we're building a LLVM for the build triple, then we don't actually
// have any dependencies! To do that we return a dependency on the "dummy"
// target which does nothing.
//
// If we're build a cross-compiled LLVM, however, we need to assemble the
// libraries from the previous compiler. This step has the same name as
// ours (llvm) but we want it for a different target, so we use the
// builder-style methods on `Step` to configure this target to the build
// triple.
//
// Finally, to finish off this rule, we define how to actually execute it.
// That logic is all defined in the `native` module so we just delegate to
// the relevant function there. The argument to the closure passed to `run`
// is a `Step` (defined below) which encapsulates information like the
// stage, target, host, etc.
rules.build("llvm", "src/llvm")
.host(true)
.dep(move |s| {
if s.target == build.config.build {
dummy(s, build)
} else {
s.target(&build.config.build)
}
})
.run(move |s| native::llvm(build, s.target));
// Ok! After that example rule that's hopefully enough to explain what's
// going on here. You can check out the API docs below and also see a bunch
// more examples of rules directly below as well.
// dummy rule to do nothing, useful when a dep maps to no deps
rules.build("dummy", "path/to/nowhere");
fn dummy<'a>(s: &Step<'a>, build: &'a Build) -> Step<'a> {
s.name("dummy").stage(0)
.target(&build.config.build)
.host(&build.config.build)
}
// the compiler with no target libraries ready to go
rules.build("rustc", "src/rustc")
.dep(move |s| {
if s.stage == 0 {
dummy(s, build)
} else {
s.name("librustc")
.host(&build.config.build)
.stage(s.stage - 1)
}
})
.run(move |s| compile::assemble_rustc(build, s.stage, s.target));
// Helper for loading an entire DAG of crates, rooted at `name`
let krates = |name: &str| {
@ -85,21 +150,6 @@ pub fn build_rules(build: &Build) -> Rules {
return ret
};
rules.build("rustc", "path/to/nowhere")
.dep(move |s| {
if s.stage == 0 {
dummy(s, build)
} else {
s.name("librustc")
.host(&build.config.build)
.stage(s.stage - 1)
}
})
.run(move |s| compile::assemble_rustc(build, s.stage, s.target));
rules.build("llvm", "src/llvm")
.host(true)
.run(move |s| native::llvm(build, s.target));
// ========================================================================
// Crate compilations
//
@ -268,37 +318,55 @@ pub fn build_rules(build: &Build) -> Rules {
rules.test(&krate.test_step, path)
.dep(|s| s.name("libtest"))
.run(move |s| check::krate(build, &s.compiler(), s.target,
Mode::Libstd, Some(&krate.name)));
Mode::Libstd, TestKind::Test,
Some(&krate.name)));
}
rules.test("check-std-all", "path/to/nowhere")
.dep(|s| s.name("libtest"))
.default(true)
.run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libstd,
None));
.run(move |s| check::krate(build, &s.compiler(), s.target,
Mode::Libstd, TestKind::Test, None));
// std benchmarks
for (krate, path, _default) in krates("std_shim") {
rules.bench(&krate.bench_step, path)
.dep(|s| s.name("libtest"))
.run(move |s| check::krate(build, &s.compiler(), s.target,
Mode::Libstd, TestKind::Bench,
Some(&krate.name)));
}
rules.bench("bench-std-all", "path/to/nowhere")
.dep(|s| s.name("libtest"))
.default(true)
.run(move |s| check::krate(build, &s.compiler(), s.target,
Mode::Libstd, TestKind::Bench, None));
for (krate, path, _default) in krates("test_shim") {
rules.test(&krate.test_step, path)
.dep(|s| s.name("libtest"))
.run(move |s| check::krate(build, &s.compiler(), s.target,
Mode::Libtest, Some(&krate.name)));
Mode::Libtest, TestKind::Test,
Some(&krate.name)));
}
rules.test("check-test-all", "path/to/nowhere")
.dep(|s| s.name("libtest"))
.default(true)
.run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libtest,
None));
.run(move |s| check::krate(build, &s.compiler(), s.target,
Mode::Libtest, TestKind::Test, None));
for (krate, path, _default) in krates("rustc-main") {
rules.test(&krate.test_step, path)
.dep(|s| s.name("librustc"))
.host(true)
.run(move |s| check::krate(build, &s.compiler(), s.target,
Mode::Librustc, Some(&krate.name)));
Mode::Librustc, TestKind::Test,
Some(&krate.name)));
}
rules.test("check-rustc-all", "path/to/nowhere")
.dep(|s| s.name("librustc"))
.default(true)
.host(true)
.run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Librustc,
None));
.run(move |s| check::krate(build, &s.compiler(), s.target,
Mode::Librustc, TestKind::Test, None));
rules.test("check-linkchecker", "src/tools/linkchecker")
.dep(|s| s.name("tool-linkchecker"))
@ -312,10 +380,10 @@ pub fn build_rules(build: &Build) -> Rules {
.host(true)
.run(move |s| check::cargotest(build, s.stage, s.target));
rules.test("check-tidy", "src/tools/tidy")
.dep(|s| s.name("tool-tidy"))
.dep(|s| s.name("tool-tidy").stage(0))
.default(true)
.host(true)
.run(move |s| check::tidy(build, s.stage, s.target));
.run(move |s| check::tidy(build, 0, s.target));
rules.test("check-error-index", "src/tools/error_index_generator")
.dep(|s| s.name("libstd"))
.dep(|s| s.name("tool-error-index").host(s.host))
@ -327,6 +395,10 @@ pub fn build_rules(build: &Build) -> Rules {
.default(true)
.host(true)
.run(move |s| check::docs(build, &s.compiler()));
rules.test("check-distcheck", "distcheck")
.dep(|s| s.name("dist-src"))
.run(move |_| check::distcheck(build));
rules.build("test-helpers", "src/rt/rust_test_helpers.c")
.run(move |s| native::test_helpers(build, s.target));
@ -386,7 +458,7 @@ pub fn build_rules(build: &Build) -> Rules {
for (krate, path, default) in krates("test_shim") {
rules.doc(&krate.doc_step, path)
.dep(|s| s.name("libtest"))
.default(default && build.config.docs)
.default(default && build.config.compiler_docs)
.run(move |s| doc::test(build, s.stage, s.target));
}
for (krate, path, default) in krates("rustc-main") {
@ -418,7 +490,12 @@ pub fn build_rules(build: &Build) -> Rules {
.default(true)
.run(move |s| dist::std(build, &s.compiler(), s.target));
rules.dist("dist-mingw", "path/to/nowhere")
.run(move |s| dist::mingw(build, s.target));
.default(true)
.run(move |s| {
if s.target.contains("pc-windows-gnu") {
dist::mingw(build, s.target)
}
});
rules.dist("dist-src", "src")
.default(true)
.host(true)
@ -427,21 +504,98 @@ pub fn build_rules(build: &Build) -> Rules {
.default(true)
.dep(|s| s.name("default:doc"))
.run(move |s| dist::docs(build, s.stage, s.target));
rules.dist("dist-analysis", "analysis")
.dep(|s| s.name("dist-std"))
.default(true)
.run(move |s| dist::analysis(build, &s.compiler(), s.target));
rules.dist("install", "src")
.dep(|s| s.name("default:dist"))
.run(move |s| install::install(build, s.stage, s.target));
rules.verify();
return rules
return rules;
fn dummy<'a>(s: &Step<'a>, build: &'a Build) -> Step<'a> {
s.name("dummy").stage(0)
.target(&build.config.build)
.host(&build.config.build)
}
}
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
struct Step<'a> {
/// Human readable name of the rule this step is executing. Possible names
/// are all defined above in `build_rules`.
name: &'a str,
/// The stage this step is executing in. This is typically 0, 1, or 2.
stage: u32,
/// This step will likely involve a compiler, and the target that compiler
/// itself is built for is called the host, this variable. Typically this is
/// the target of the build machine itself.
host: &'a str,
/// The target that this step represents generating. If you're building a
/// standard library for a new suite of targets, for example, this'll be set
/// to those targets.
target: &'a str,
}
impl<'a> Step<'a> {
/// Creates a new step which is the same as this, except has a new name.
fn name(&self, name: &'a str) -> Step<'a> {
Step { name: name, ..*self }
}
/// Creates a new step which is the same as this, except has a new stage.
fn stage(&self, stage: u32) -> Step<'a> {
Step { stage: stage, ..*self }
}
/// Creates a new step which is the same as this, except has a new host.
fn host(&self, host: &'a str) -> Step<'a> {
Step { host: host, ..*self }
}
/// Creates a new step which is the same as this, except has a new target.
fn target(&self, target: &'a str) -> Step<'a> {
Step { target: target, ..*self }
}
/// Returns the `Compiler` structure that this step corresponds to.
fn compiler(&self) -> Compiler<'a> {
Compiler::new(self.stage, self.host)
}
}
struct Rule<'a> {
/// The human readable name of this target, defined in `build_rules`.
name: &'a str,
/// The path associated with this target, used in the `./x.py` driver for
/// easy and ergonomic specification of what to do.
path: &'a str,
/// The "kind" of top-level command that this rule is associated with, only
/// relevant if this is a default rule.
kind: Kind,
/// List of dependencies this rule has. Each dependency is a function from a
/// step that's being executed to another step that should be executed.
deps: Vec<Box<Fn(&Step<'a>) -> Step<'a> + 'a>>,
/// How to actually execute this rule. Takes a step with contextual
/// information and then executes it.
run: Box<Fn(&Step<'a>) + 'a>,
/// Whether or not this is a "default" rule. That basically means that if
/// you run, for example, `./x.py test` whether it's included or not.
default: bool,
/// Whether or not this is a "host" rule, or in other words whether this is
/// only intended for compiler hosts and not for targets that are being
/// generated.
host: bool,
}
@ -449,6 +603,7 @@ struct Rule<'a> {
enum Kind {
Build,
Test,
Bench,
Dist,
Doc,
}
@ -467,6 +622,8 @@ impl<'a> Rule<'a> {
}
}
/// Builder pattern returned from the various methods on `Rules` which will add
/// the rule to the internal list on `Drop`.
struct RuleBuilder<'a: 'b, 'b> {
rules: &'b mut Rules<'a>,
rule: Rule<'a>,
@ -528,21 +685,35 @@ impl<'a> Rules<'a> {
}
}
/// Creates a new rule of `Kind::Build` with the specified human readable
/// name and path associated with it.
///
/// The builder returned should be configured further with information such
/// as how to actually run this rule.
fn build<'b>(&'b mut self, name: &'a str, path: &'a str)
-> RuleBuilder<'a, 'b> {
self.rule(name, path, Kind::Build)
}
/// Same as `build`, but for `Kind::Test`.
fn test<'b>(&'b mut self, name: &'a str, path: &'a str)
-> RuleBuilder<'a, 'b> {
self.rule(name, path, Kind::Test)
}
/// Same as `build`, but for `Kind::Bench`.
fn bench<'b>(&'b mut self, name: &'a str, path: &'a str)
-> RuleBuilder<'a, 'b> {
self.rule(name, path, Kind::Bench)
}
/// Same as `build`, but for `Kind::Doc`.
fn doc<'b>(&'b mut self, name: &'a str, path: &'a str)
-> RuleBuilder<'a, 'b> {
self.rule(name, path, Kind::Doc)
}
/// Same as `build`, but for `Kind::Dist`.
fn dist<'b>(&'b mut self, name: &'a str, path: &'a str)
-> RuleBuilder<'a, 'b> {
self.rule(name, path, Kind::Dist)
@ -583,6 +754,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
"build" => Kind::Build,
"doc" => Kind::Doc,
"test" => Kind::Test,
"bench" => Kind::Bench,
"dist" => Kind::Dist,
_ => return,
};
@ -602,10 +774,36 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
/// Construct the top-level build steps that we're going to be executing,
/// given the subcommand that our build is performing.
fn plan(&self) -> Vec<Step<'a>> {
// Ok, the logic here is pretty subtle, and involves quite a few
// conditionals. The basic idea here is to:
//
// 1. First, filter all our rules to the relevant ones. This means that
// the command specified corresponds to one of our `Kind` variants,
// and we filter all rules based on that.
//
// 2. Next, we determine which rules we're actually executing. If a
// number of path filters were specified on the command line we look
// for those, otherwise we look for anything tagged `default`.
//
// 3. Finally, we generate some steps with host and target information.
//
// The last step is by far the most complicated and subtle. The basic
// thinking here is that we want to take the cartesian product of
// specified hosts and targets and build rules with that. The list of
// hosts and targets, if not specified, come from the how this build was
// configured. If the rule we're looking at is a host-only rule the we
// ignore the list of targets and instead consider the list of hosts
// also the list of targets.
//
// Once the host and target lists are generated we take the cartesian
// product of the two and then create a step based off them. Note that
// the stage each step is associated was specified with the `--step`
// flag on the command line.
let (kind, paths) = match self.build.flags.cmd {
Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
Subcommand::Test { ref paths, test_args: _ } => (Kind::Test, &paths[..]),
Subcommand::Bench { ref paths, test_args: _ } => (Kind::Bench, &paths[..]),
Subcommand::Dist { install } => {
if install {
return vec![self.sbuild.name("install")]
@ -631,7 +829,18 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
} else {
&self.build.config.target
};
let arr = if rule.host {hosts} else {targets};
// If --target was specified but --host wasn't specified, don't run
// any host-only tests
let arr = if rule.host {
if self.build.flags.target.len() > 0 &&
self.build.flags.host.len() == 0 {
&hosts[..0]
} else {
hosts
}
} else {
targets
};
hosts.iter().flat_map(move |host| {
arr.iter().map(move |target| {
@ -667,11 +876,24 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
// And finally, iterate over everything and execute it.
for step in order.iter() {
if self.build.flags.keep_stage.map_or(false, |s| step.stage <= s) {
self.build.verbose(&format!("keeping step {:?}", step));
continue;
}
self.build.verbose(&format!("executing step {:?}", step));
(self.rules[step.name].run)(step);
}
}
/// Performs topological sort of dependencies rooted at the `step`
/// specified, pushing all results onto the `order` vector provided.
///
/// In other words, when this method returns, the `order` vector will
/// contain a list of steps which if executed in order will eventually
/// complete the `step` specified as well.
///
/// The `added` set specified here is the set of steps that are already
/// present in `order` (and hence don't need to be added again).
fn fill(&self,
step: Step<'a>,
order: &mut Vec<Step<'a>>,

View File

@ -18,6 +18,7 @@ use std::ffi::OsString;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::Instant;
use filetime::FileTime;
@ -40,6 +41,12 @@ pub fn mtime(path: &Path) -> FileTime {
/// Copies a file from `src` to `dst`, attempting to use hard links and then
/// falling back to an actually filesystem copy if necessary.
pub fn copy(src: &Path, dst: &Path) {
// A call to `hard_link` will fail if `dst` exists, so remove it if it
// already exists so we can try to help `hard_link` succeed.
let _ = fs::remove_file(&dst);
// Attempt to "easy copy" by creating a hard link (symlinks don't work on
// windows), but if that fails just fall back to a slow `copy` operation.
let res = fs::hard_link(src, dst);
let res = res.or_else(|_| fs::copy(src, dst).map(|_| ()));
if let Err(e) = res {
@ -189,3 +196,19 @@ pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf {
buf
}
pub struct TimeIt(Instant);
/// Returns an RAII structure that prints out how long it took to drop.
pub fn timeit() -> TimeIt {
TimeIt(Instant::now())
}
impl Drop for TimeIt {
fn drop(&mut self) {
let time = self.0.elapsed();
println!("\tfinished in {}.{:03}",
time.as_secs(),
time.subsec_nanos() / 1_000_000);
}
}

View File

@ -21,7 +21,8 @@ pub fn run(cmd: &mut Command) {
pub fn run_silent(cmd: &mut Command) {
let status = match cmd.status() {
Ok(status) => status,
Err(e) => fail(&format!("failed to execute command: {}", e)),
Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
cmd, e)),
};
if !status.success() {
fail(&format!("command did not execute successfully: {:?}\n\
@ -46,6 +47,8 @@ pub fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
None
} else if target.contains("musl") {
Some(PathBuf::from("ar"))
} else if target.contains("openbsd") {
Some(PathBuf::from("ar"))
} else {
let parent = cc.parent().unwrap();
let file = cc.file_name().unwrap().to_str().unwrap();
@ -60,10 +63,21 @@ pub fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
}
}
pub fn make(host: &str) -> PathBuf {
if host.contains("bitrig") || host.contains("dragonfly") ||
host.contains("freebsd") || host.contains("netbsd") ||
host.contains("openbsd") {
PathBuf::from("gmake")
} else {
PathBuf::from("make")
}
}
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)),
Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
cmd, e)),
};
if !output.status.success() {
panic!("command did not execute successfully: {:?}\n\

View File

@ -0,0 +1,54 @@
FROM ubuntu:16.04
RUN dpkg --add-architecture i386 && \
apt-get update && \
apt-get install -y --no-install-recommends \
g++ \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
ccache \
unzip \
expect \
openjdk-9-jre \
sudo \
libstdc++6:i386 \
xz-utils
WORKDIR /android/
ENV PATH=$PATH:/android/ndk-arm-9/bin:/android/sdk/tools:/android/sdk/platform-tools
COPY install-ndk.sh install-sdk.sh accept-licenses.sh /android/
RUN sh /android/install-ndk.sh
RUN sh /android/install-sdk.sh
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
COPY start-emulator.sh /android/
ENTRYPOINT ["/usr/bin/dumb-init", "--", "/android/start-emulator.sh"]
ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
tar xJf - -C /usr/local/bin --strip-components=1
ENV TARGETS=arm-linux-androideabi
ENV TARGETS=$TARGETS,i686-linux-android
ENV TARGETS=$TARGETS,aarch64-linux-android
ENV TARGETS=$TARGETS,armv7-linux-androideabi
ENV RUST_CONFIGURE_ARGS \
--target=$TARGETS \
--arm-linux-androideabi-ndk=/android/ndk-arm-9 \
--armv7-linux-androideabi-ndk=/android/ndk-arm-9 \
--i686-linux-android-ndk=/android/ndk-x86-9 \
--aarch64-linux-android-ndk=/android/ndk-aarch64
ENV XPY_CHECK test --target arm-linux-androideabi
RUN mkdir /tmp/obj
RUN chmod 777 /tmp/obj

View File

@ -0,0 +1,15 @@
#!/usr/bin/expect -f
# ignore-license
set timeout 1800
set cmd [lindex $argv 0]
set licenses [lindex $argv 1]
spawn {*}$cmd
expect {
"Do you accept the license '*'*" {
exp_send "y\r"
exp_continue
}
eof
}

View File

@ -0,0 +1,45 @@
#!/bin/sh
# 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.
set -ex
cpgdb() {
cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb /android/$1/bin/$2-gdb
cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb-orig /android/$1/bin/gdb-orig
cp -r android-ndk-r11c/prebuilt/linux-x86_64/share /android/$1/share
}
# Prep the Android NDK
#
# See https://github.com/servo/servo/wiki/Building-for-Android
curl -O https://dl.google.com/android/repository/android-ndk-r11c-linux-x86_64.zip
unzip -q android-ndk-r11c-linux-x86_64.zip
bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
--platform=android-9 \
--toolchain=arm-linux-androideabi-4.9 \
--install-dir=/android/ndk-arm-9 \
--ndk-dir=/android/android-ndk-r11c \
--arch=arm
cpgdb ndk-arm-9 arm-linux-androideabi
bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
--platform=android-21 \
--toolchain=aarch64-linux-android-4.9 \
--install-dir=/android/ndk-aarch64 \
--ndk-dir=/android/android-ndk-r11c \
--arch=arm64
bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
--platform=android-9 \
--toolchain=x86-4.9 \
--install-dir=/android/ndk-x86-9 \
--ndk-dir=/android/android-ndk-r11c \
--arch=x86
rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c

View File

@ -0,0 +1,33 @@
#!/bin/sh
# 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.
set -ex
# Prep the SDK and emulator
#
# Note that the update process requires that we accept a bunch of licenses, and
# we can't just pipe `yes` into it for some reason, so we take the same strategy
# located in https://github.com/appunite/docker by just wrapping it in a script
# which apparently magically accepts the licenses.
mkdir sdk
curl https://dl.google.com/android/android-sdk_r24.4-linux.tgz | \
tar xzf - -C sdk --strip-components=1
filter="platform-tools,android-18"
filter="$filter,sys-img-armeabi-v7a-android-18"
./accept-licenses.sh "android - update sdk -a --no-ui --filter $filter"
echo "no" | android create avd \
--name arm-18 \
--target android-18 \
--abi armeabi-v7a

View File

@ -0,0 +1,15 @@
#!/bin/sh
# 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.
set -ex
ANDROID_EMULATOR_FORCE_32BIT=true \
emulator @arm-18 -no-window -partition-size 2047 &
exec "$@"

View File

@ -0,0 +1,75 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
ccache \
sudo \
gcc-aarch64-linux-gnu libc6-dev-arm64-cross \
gcc-arm-linux-gnueabi libc6-dev-armel-cross \
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross \
gcc-mips-linux-gnu libc6-dev-mips-cross \
gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \
gcc-mips64-linux-gnuabi64 libc6-dev-mips64-cross \
gcc-mips64el-linux-gnuabi64 libc6-dev-mips64el-cross \
gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \
gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \
gcc-s390x-linux-gnu libc6-dev-s390x-cross \
xz-utils
ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
tar xJf - -C /usr/local/bin --strip-components=1
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
ENV TARGETS=aarch64-unknown-linux-gnu
ENV TARGETS=$TARGETS,arm-unknown-linux-gnueabi
ENV TARGETS=$TARGETS,arm-unknown-linux-gnueabihf
ENV TARGETS=$TARGETS,armv7-unknown-linux-gnueabihf
ENV TARGETS=$TARGETS,asmjs-unknown-emscripten
ENV TARGETS=$TARGETS,mips-unknown-linux-gnu
ENV TARGETS=$TARGETS,mips64-unknown-linux-gnuabi64
ENV TARGETS=$TARGETS,mips64el-unknown-linux-gnuabi64
ENV TARGETS=$TARGETS,mipsel-unknown-linux-gnu
ENV TARGETS=$TARGETS,powerpc-unknown-linux-gnu
ENV TARGETS=$TARGETS,powerpc64-unknown-linux-gnu
ENV TARGETS=$TARGETS,powerpc64le-unknown-linux-gnu
ENV TARGETS=$TARGETS,s390x-unknown-linux-gnu
ENV TARGETS=$TARGETS,wasm32-unknown-emscripten
#ENV TARGETS=$TARGETS,mips-unknown-linux-musl
#ENV TARGETS=$TARGETS,arm-unknown-linux-musleabi
#ENV TARGETS=$TARGETS,arm-unknown-linux-musleabihf
#ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf
#ENV TARGETS=$TARGETS,x86_64-rumprun-netbsd
ENV RUST_CONFIGURE_ARGS \
--target=$TARGETS \
--enable-rustbuild
ENV RUST_CHECK_TARGET ""
ENV AR_s390x_unknown_linux_gnu=s390x-linux-gnu-ar \
CC_s390x_unknown_linux_gnu=s390x-linux-gnu-gcc \
AR_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-ar \
CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \
AR_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-ar \
CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \
AR_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-ar \
CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc
# FIXME(rust-lang/rust#36150): powerpc unfortunately aborts right now
ENV NO_LLVM_ASSERTIONS=1
RUN mkdir /tmp/obj
RUN chmod 777 /tmp/obj

View File

@ -0,0 +1,29 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++-multilib \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
ccache \
sudo \
gdb \
xz-utils
ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
tar xJf - -C /usr/local/bin --strip-components=1
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
ENV RUST_CHECK_TARGET check
RUN mkdir /tmp/obj
RUN chmod 777 /tmp/obj

View File

@ -0,0 +1,29 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++-multilib \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
ccache \
sudo \
gdb \
xz-utils
ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
tar xJf - -C /usr/local/bin --strip-components=1
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu
ENV RUST_CHECK_TARGET check
RUN mkdir /tmp/obj
RUN chmod 777 /tmp/obj

46
src/ci/docker/run.sh Executable file
View File

@ -0,0 +1,46 @@
#!/bin/sh
# 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.
set -e
script=`cd $(dirname $0) && pwd`/`basename $0`
image=$1
docker_dir="`dirname $script`"
ci_dir="`dirname $docker_dir`"
src_dir="`dirname $ci_dir`"
root_dir="`dirname $src_dir`"
docker \
build \
--rm \
-t rust-ci \
"`dirname "$script"`/$image"
mkdir -p $HOME/.cargo
mkdir -p $root_dir/obj
exec docker \
run \
--volume "$root_dir:/checkout:ro" \
--volume "$root_dir/obj:/checkout/obj" \
--workdir /checkout/obj \
--env SRC=/checkout \
--env SCCACHE_BUCKET=$SCCACHE_BUCKET \
--env AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
--env AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
--env CARGO_HOME=/cargo \
--env LOCAL_USER_ID=`id -u` \
--volume "$HOME/.cargo:/cargo" \
--interactive \
--tty \
rust-ci \
/checkout/src/ci/run.sh

View File

@ -0,0 +1,37 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
ccache \
sudo \
bzip2 \
xz-utils \
wget
COPY build-toolchain.sh /tmp/
RUN sh /tmp/build-toolchain.sh
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
tar xJf - -C /usr/local/bin --strip-components=1
ENV \
AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \
CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc
ENV RUST_CONFIGURE_ARGS --target=x86_64-unknown-freebsd
ENV RUST_CHECK_TARGET ""
RUN mkdir /tmp/obj
RUN chmod 777 /tmp/obj

View File

@ -0,0 +1,96 @@
#!/bin/bash
# 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.
set -ex
ARCH=x86_64
BINUTILS=2.25.1
GCC=5.3.0
mkdir binutils
cd binutils
# First up, build binutils
curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf -
mkdir binutils-build
cd binutils-build
../binutils-$BINUTILS/configure \
--target=$ARCH-unknown-freebsd10
make -j10
make install
cd ../..
rm -rf binutils
# Next, download the FreeBSD libc and relevant header files
mkdir freebsd
case "$ARCH" in
x86_64)
URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.2-RELEASE/base.txz
;;
i686)
URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.2-RELEASE/base.txz
;;
esac
curl $URL | tar xJf - -C freebsd ./usr/include ./usr/lib ./lib
dst=/usr/local/$ARCH-unknown-freebsd10
cp -r freebsd/usr/include $dst/
cp freebsd/usr/lib/crt1.o $dst/lib
cp freebsd/usr/lib/Scrt1.o $dst/lib
cp freebsd/usr/lib/crti.o $dst/lib
cp freebsd/usr/lib/crtn.o $dst/lib
cp freebsd/usr/lib/libc.a $dst/lib
cp freebsd/usr/lib/libutil.a $dst/lib
cp freebsd/usr/lib/libutil_p.a $dst/lib
cp freebsd/usr/lib/libm.a $dst/lib
cp freebsd/usr/lib/librt.so.1 $dst/lib
cp freebsd/usr/lib/libexecinfo.so.1 $dst/lib
cp freebsd/lib/libc.so.7 $dst/lib
cp freebsd/lib/libm.so.5 $dst/lib
cp freebsd/lib/libutil.so.9 $dst/lib
cp freebsd/lib/libthr.so.3 $dst/lib/libpthread.so
ln -s libc.so.7 $dst/lib/libc.so
ln -s libm.so.5 $dst/lib/libm.so
ln -s librt.so.1 $dst/lib/librt.so
ln -s libutil.so.9 $dst/lib/libutil.so
ln -s libexecinfo.so.1 $dst/lib/libexecinfo.so
rm -rf freebsd
# Finally, download and build gcc to target FreeBSD
mkdir gcc
cd gcc
curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf -
cd gcc-$GCC
./contrib/download_prerequisites
mkdir ../gcc-build
cd ../gcc-build
../gcc-$GCC/configure \
--enable-languages=c \
--target=$ARCH-unknown-freebsd10 \
--disable-multilib \
--disable-nls \
--disable-libgomp \
--disable-libquadmath \
--disable-libssp \
--disable-libvtv \
--disable-libcilkrts \
--disable-libada \
--disable-libsanitizer \
--disable-libquadmath-support \
--disable-lto
make -j10
make install
cd ../..
rm -rf gcc

View File

@ -0,0 +1,30 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
ccache \
libssl-dev \
sudo \
xz-utils
ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
tar xJf - -C /usr/local/bin --strip-components=1
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
ENV RUST_CHECK_TARGET check-cargotest
ENV NO_VENDOR 1
RUN mkdir /tmp/obj
RUN chmod 777 /tmp/obj

View File

@ -0,0 +1,32 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
ccache \
sudo \
gdb \
xz-utils
ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
tar xJf - -C /usr/local/bin --strip-components=1
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
--enable-debug \
--enable-optimize
ENV RUST_CHECK_TARGET ""
RUN mkdir /tmp/obj
RUN chmod 777 /tmp/obj

View File

@ -0,0 +1,34 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
ccache \
sudo \
gdb \
llvm-3.7-tools \
libedit-dev \
zlib1g-dev \
xz-utils
ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
tar xJf - -C /usr/local/bin --strip-components=1
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
--llvm-root=/usr/lib/llvm-3.7
ENV RUST_CHECK_TARGET check
RUN mkdir /tmp/obj
RUN chmod 777 /tmp/obj

View File

@ -0,0 +1,29 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
ccache \
sudo \
gdb \
xz-utils
ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
tar xJf - -C /usr/local/bin --strip-components=1
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --disable-rustbuild
ENV RUST_CHECK_TARGET check
RUN mkdir /tmp/obj
RUN chmod 777 /tmp/obj

View File

@ -0,0 +1,29 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
ccache \
sudo \
gdb \
xz-utils
ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
tar xJf - -C /usr/local/bin --strip-components=1
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --disable-optimize-tests
ENV RUST_CHECK_TARGET check
RUN mkdir /tmp/obj
RUN chmod 777 /tmp/obj

View File

@ -0,0 +1,29 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
ccache \
sudo \
gdb \
xz-utils
ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
tar xJf - -C /usr/local/bin --strip-components=1
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
ENV RUST_CHECK_TARGET check
RUN mkdir /tmp/obj
RUN chmod 777 /tmp/obj

View File

@ -0,0 +1,38 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
ccache \
xz-utils \
sudo \
gdb
WORKDIR /build/
COPY build-musl.sh /build/
RUN sh /build/build-musl.sh && rm -rf /build
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
tar xJf - -C /usr/local/bin --strip-components=1
ENV RUST_CONFIGURE_ARGS \
--target=x86_64-unknown-linux-musl \
--musl-root-x86_64=/musl-x86_64
ENV RUST_CHECK_TARGET check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu
ENV PATH=$PATH:/musl-x86_64/bin
ENV XPY_CHECK test --target x86_64-unknown-linux-musl
RUN mkdir /tmp/obj
RUN chmod 777 /tmp/obj

View File

@ -0,0 +1,33 @@
#!/bin/sh
# 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.
set -ex
export CFLAGS="-fPIC"
MUSL=musl-1.1.14
curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
cd $MUSL
./configure --prefix=/musl-x86_64 --disable-shared
make -j10
make install
make clean
cd ..
# To build MUSL we're going to need a libunwind lying around, so acquire that
# here and build it.
curl -L https://github.com/llvm-mirror/llvm/archive/release_37.tar.gz | tar xzf -
curl -L https://github.com/llvm-mirror/libunwind/archive/release_37.tar.gz | tar xzf -
mkdir libunwind-build
cd libunwind-build
cmake ../libunwind-release_37 -DLLVM_PATH=/build/llvm-release_37 \
-DLIBUNWIND_ENABLE_SHARED=0
make -j10
cp lib/libunwind.a /musl-x86_64/lib

52
src/ci/run.sh Executable file
View File

@ -0,0 +1,52 @@
#!/bin/sh
# 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.
set -e
if [ "$LOCAL_USER_ID" != "" ]; then
useradd --shell /bin/bash -u $LOCAL_USER_ID -o -c "" -m user
export HOME=/home/user
unset LOCAL_USER_ID
exec su --preserve-environment -c "env PATH=$PATH \"$0\"" user
fi
if [ "$NO_LLVM_ASSERTIONS" = "" ]; then
ENABLE_LLVM_ASSERTIONS=--enable-llvm-assertions
fi
if [ "$NO_VENDOR" = "" ]; then
ENABLE_VENDOR=--enable-vendor
fi
set -ex
$SRC/configure \
--disable-manage-submodules \
--enable-debug-assertions \
--enable-quiet-tests \
--enable-sccache \
$ENABLE_VENDOR \
$ENABLE_LLVM_ASSERTIONS \
$RUST_CONFIGURE_ARGS
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
ncpus=$(sysctl -n hw.ncpu)
else
ncpus=$(nproc)
fi
make -j $ncpus tidy
make -j $ncpus
if [ ! -z "$XPY_CHECK" ]; then
exec python2.7 $SRC/x.py $XPY_CHECK
else
exec make $RUST_CHECK_TARGET -j $ncpus
fi

View File

@ -72,6 +72,28 @@
/* Include internal utility function declarations. */
#include "int_util.h"
/*
* Workaround for LLVM bug 11663. Prevent endless recursion in
* __c?zdi2(), where calls to __builtin_c?z() are expanded to
* __c?zdi2() instead of __c?zsi2().
*
* Instead of placing this workaround in c?zdi2.c, put it in this
* global header to prevent other C files from making the detour
* through __c?zdi2() as well.
*
* This problem has been observed on FreeBSD for sparc64 and
* mips64 with GCC 4.2.1, and for riscv with GCC 5.2.0.
* Presumably it's any version of GCC, and targeting an arch that
* does not have dedicated bit counting instructions.
*/
#if (defined(__sparc64__) || defined(__mips_n64) || defined(__mips_o64) || defined(__riscv__) \
|| (defined(_MIPS_SIM) && ((_MIPS_SIM == _ABI64) || (_MIPS_SIM == _ABIO64))))
si_int __clzsi2(si_int);
si_int __ctzsi2(si_int);
#define __builtin_clz __clzsi2
#define __builtin_ctz __ctzsi2
#endif /* sparc64 || mips_n64 || mips_o64 || riscv */
COMPILER_RT_ABI si_int __paritysi2(si_int a);
COMPILER_RT_ABI si_int __paritydi2(di_int a);

View File

@ -52,6 +52,7 @@
* [Borrow and AsRef](borrow-and-asref.md)
* [Release Channels](release-channels.md)
* [Using Rust without the standard library](using-rust-without-the-standard-library.md)
* [Procedural Macros (and custom derive)](procedural-macros.md)
* [Nightly Rust](nightly-rust.md)
* [Compiler Plugins](compiler-plugins.md)
* [Inline Assembly](inline-assembly.md)

View File

@ -11,7 +11,7 @@ this:
trait Graph<N, E> {
fn has_edge(&self, &N, &N) -> bool;
fn edges(&self, &N) -> Vec<E>;
// etc
// Etc.
}
```
@ -36,7 +36,7 @@ trait Graph {
fn has_edge(&self, &Self::N, &Self::N) -> bool;
fn edges(&self, &Self::N) -> Vec<Self::E>;
// etc
// Etc.
}
```

View File

@ -110,7 +110,7 @@ computation entirely. This could be done for the example above by adjusting the
# struct X;
# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
b.iter(|| {
// note lack of `;` (could also use an explicit `return`).
// Note lack of `;` (could also use an explicit `return`).
(0..1000).fold(0, |old, new| old ^ new)
});
```

View File

@ -38,7 +38,7 @@ so as to avoid copying a large data structure. For example:
struct BigStruct {
one: i32,
two: i32,
// etc
// Etc.
one_hundred: i32,
}
@ -68,7 +68,7 @@ This is an antipattern in Rust. Instead, write this:
struct BigStruct {
one: i32,
two: i32,
// etc
// Etc.
one_hundred: i32,
}

View File

@ -106,7 +106,7 @@ from integers, and to cast between pointers to different types subject to
some constraints. It is only unsafe to dereference the pointer:
```rust
let a = 300 as *const char; // a pointer to location 300
let a = 300 as *const char; // `a` is a pointer to location 300.
let b = a as u32;
```
@ -135,14 +135,14 @@ cast four bytes into a `u32`:
```rust,ignore
let a = [0u8, 0u8, 0u8, 0u8];
let b = a as u32; // four u8s makes a u32
let b = a as u32; // Four u8s makes a u32.
```
This errors with:
```text
error: non-scalar cast: `[u8; 4]` as `u32`
let b = a as u32; // four u8s makes a u32
let b = a as u32; // Four u8s makes a u32.
^~~~~~~~
```
@ -170,7 +170,7 @@ fn main() {
let a = [0u8, 1u8, 0u8, 0u8];
let b = mem::transmute::<[u8; 4], u32>(a);
println!("{}", b); // 256
// or, more concisely:
// Or, more concisely:
let c: u32 = mem::transmute(a);
println!("{}", c); // 256
}

View File

@ -25,7 +25,7 @@ the following:
```rust
let x = Box::new(1);
let y = x;
// x no longer accessible here
// `x` is no longer accessible here.
```
Here, the box was _moved_ into `y`. As `x` no longer owns it, the compiler will no longer allow the
@ -291,9 +291,9 @@ the inner data (mutably), and the lock will be released when the guard goes out
```rust,ignore
{
let guard = mutex.lock();
// guard dereferences mutably to the inner type
// `guard` dereferences mutably to the inner type.
*guard += 1;
} // lock released when destructor runs
} // Lock is released when destructor runs.
```

View File

@ -116,7 +116,7 @@ let mut num = 5;
{
let plus_num = |x: i32| x + num;
} // plus_num goes out of scope, borrow of num ends
} // `plus_num` goes out of scope; borrow of `num` ends.
let y = &mut num;
```

View File

@ -10,7 +10,7 @@ and *doc comments*.
```rust
// Line comments are anything after // and extend to the end of the line.
let x = 5; // this is also a line comment.
let x = 5; // This is also a line comment.
// If you have a long explanation for something, you can put line comments next
// to each other. Put a space between the // and your comment so that its

View File

@ -48,7 +48,7 @@ extern crate rustc_plugin;
use syntax::parse::token;
use syntax::tokenstream::TokenTree;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder; // trait for expr_usize
use syntax::ext::build::AstBuilder; // A trait for expr_usize.
use syntax::ext::quote::rt::Span;
use rustc_plugin::Registry;

View File

@ -213,10 +213,10 @@ fn main() {
let mut data = Rc::new(vec![1, 2, 3]);
for i in 0..3 {
// create a new owned reference
// Create a new owned reference:
let data_ref = data.clone();
// use it in a thread
// Use it in a thread:
thread::spawn(move || {
data_ref[0] += i;
});
@ -390,8 +390,8 @@ use std::sync::mpsc;
fn main() {
let data = Arc::new(Mutex::new(0));
// `tx` is the "transmitter" or "sender"
// `rx` is the "receiver"
// `tx` is the "transmitter" or "sender".
// `rx` is the "receiver".
let (tx, rx) = mpsc::channel();
for _ in 0..10 {

View File

@ -126,7 +126,7 @@ Instead of declaring a module like this:
```rust,ignore
mod english {
// contents of our module go here
// Contents of our module go here.
}
```

View File

@ -41,7 +41,7 @@ which allocator is in use is done simply by linking to the desired allocator:
extern crate alloc_system;
fn main() {
let a = Box::new(4); // allocates from the system allocator
let a = Box::new(4); // Allocates from the system allocator.
println!("{}", a);
}
```
@ -57,7 +57,7 @@ uses jemalloc by default one would write:
extern crate alloc_jemalloc;
pub fn foo() {
let a = Box::new(4); // allocates from jemalloc
let a = Box::new(4); // Allocates from jemalloc.
println!("{}", a);
}
# fn main() {}
@ -72,11 +72,11 @@ crate which implements the allocator API (e.g. the same as `alloc_system` or
annotated version of `alloc_system`
```rust,no_run
# // only needed for rustdoc --test down below
# // Only needed for rustdoc --test down below.
# #![feature(lang_items)]
// The compiler needs to be instructed that this crate is an allocator in order
// to realize that when this is linked in another allocator like jemalloc should
// not be linked in
// not be linked in.
#![feature(allocator)]
#![allocator]
@ -85,7 +85,7 @@ annotated version of `alloc_system`
// however, can use all of libcore.
#![no_std]
// Let's give a unique name to our custom allocator
// Let's give a unique name to our custom allocator:
#![crate_name = "my_allocator"]
#![crate_type = "rlib"]
@ -126,7 +126,7 @@ pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize,
#[no_mangle]
pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize,
_size: usize, _align: usize) -> usize {
old_size // this api is not supported by libc
old_size // This api is not supported by libc.
}
#[no_mangle]
@ -134,7 +134,7 @@ pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
size
}
# // only needed to get rustdoc to test this
# // Only needed to get rustdoc to test this:
# fn main() {}
# #[lang = "panic_fmt"] fn panic_fmt() {}
# #[lang = "eh_personality"] fn eh_personality() {}
@ -149,7 +149,7 @@ After we compile this crate, it can be used as follows:
extern crate my_allocator;
fn main() {
let a = Box::new(8); // allocates memory via our custom allocator crate
let a = Box::new(8); // Allocates memory via our custom allocator crate.
println!("{}", a);
}
```

View File

@ -33,13 +33,13 @@ automatically coerce to a `&T`. Heres an example:
```rust
fn foo(s: &str) {
// borrow a string for a second
// Borrow a string for a second.
}
// String implements Deref<Target=str>
// String implements Deref<Target=str>.
let owned = "Hello".to_string();
// therefore, this works:
// Therefore, this works:
foo(&owned);
```
@ -55,14 +55,14 @@ type implements `Deref<Target=T>`, so this works:
use std::rc::Rc;
fn foo(s: &str) {
// borrow a string for a second
// Borrow a string for a second.
}
// String implements Deref<Target=str>
// String implements Deref<Target=str>.
let owned = "Hello".to_string();
let counted = Rc::new(owned);
// therefore, this works:
// Therefore, this works:
foo(&counted);
```
@ -76,10 +76,10 @@ Another very common implementation provided by the standard library is:
```rust
fn foo(s: &[i32]) {
// borrow a slice for a second
// Borrow a slice for a second.
}
// Vec<T> implements Deref<Target=[T]>
// Vec<T> implements Deref<Target=[T]>.
let owned = vec![1, 2, 3];
foo(&owned);

View File

@ -28,7 +28,7 @@ code. You can use documentation comments for this purpose:
/// let five = Rc::new(5);
/// ```
pub fn new(value: T) -> Rc<T> {
// implementation goes here
// Implementation goes here.
}
```
@ -483,7 +483,7 @@ you have a module in `foo.rs`, you'll often open its code and see this:
```rust
//! A module for using `foo`s.
//!
//! The `foo` module contains a lot of useful functionality blah blah blah
//! The `foo` module contains a lot of useful functionality blah blah blah...
```
### Crate documentation

View File

@ -18,9 +18,9 @@ impl Drop for HasDrop {
fn main() {
let x = HasDrop;
// do stuff
// Do stuff.
} // x goes out of scope here
} // `x` goes out of scope here.
```
When `x` goes out of scope at the end of `main()`, the code for `Drop` will

View File

@ -51,7 +51,7 @@ possible variants:
```rust,ignore
fn process_color_change(msg: Message) {
let Message::ChangeColor(r, g, b) = msg; // compile-time error
let Message::ChangeColor(r, g, b) = msg; // This causes a compile-time error.
}
```

View File

@ -65,7 +65,7 @@ and in most cases, the entire program aborts.) Here's an example:
```rust,should_panic
// Guess a number between 1 and 10.
// If it matches the number we had in mind, return true. Else, return false.
// If it matches the number we had in mind, return `true`. Else, return `false`.
fn guess(n: i32) -> bool {
if n < 1 || n > 10 {
panic!("Invalid number: {}", n);
@ -350,7 +350,7 @@ fn file_path_ext_explicit(file_path: &str) -> Option<&str> {
}
fn file_name(file_path: &str) -> Option<&str> {
// implementation elided
// Implementation elided.
unimplemented!()
}
```
@ -360,7 +360,7 @@ 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
file_name(file_path).map(|x| extension(x)) // This causes a compilation error.
}
```
@ -1235,11 +1235,11 @@ use std::fs;
use std::io;
use std::num;
// We have to jump through some hoops to actually get error values.
// We have to jump through some hoops to actually get error values:
let io_err: io::Error = io::Error::last_os_error();
let parse_err: num::ParseIntError = "not a number".parse::<i32>().unwrap_err();
// OK, here are the conversions.
// OK, here are the conversions:
let err1: Box<Error> = From::from(io_err);
let err2: Box<Error> = From::from(parse_err);
```
@ -1609,7 +1609,7 @@ fn main() {
let data_path = &matches.free[0];
let city: &str = &matches.free[1];
// Do stuff with information
// Do stuff with information.
}
```
@ -1747,7 +1747,7 @@ simply ignoring that row.
use std::path::Path;
struct Row {
// unchanged
// This struct remains unchanged.
}
struct PopulationCount {
@ -1769,7 +1769,7 @@ fn search<P: AsRef<Path>>(file_path: P, city: &str) -> Vec<PopulationCount> {
for row in rdr.decode::<Row>() {
let row = row.unwrap();
match row.population {
None => { } // skip it
None => { } // Skip it.
Some(count) => if row.city == city {
found.push(PopulationCount {
city: row.city,
@ -1825,7 +1825,7 @@ Let's try it:
```rust,ignore
use std::error::Error;
// The rest of the code before this is unchanged
// The rest of the code before this is unchanged.
fn search<P: AsRef<Path>>
(file_path: P, city: &str)
@ -1836,7 +1836,7 @@ fn search<P: AsRef<Path>>
for row in rdr.decode::<Row>() {
let row = try!(row);
match row.population {
None => { } // skip it
None => { } // Skip it.
Some(count) => if row.city == city {
found.push(PopulationCount {
city: row.city,
@ -1957,7 +1957,7 @@ that it is generic on some type parameter `R` that satisfies
```rust,ignore
use std::io;
// The rest of the code before this is unchanged
// The rest of the code before this is unchanged.
fn search<P: AsRef<Path>>
(file_path: &Option<P>, city: &str)
@ -2070,7 +2070,7 @@ fn search<P: AsRef<Path>>
for row in rdr.decode::<Row>() {
let row = try!(row);
match row.population {
None => { } // skip it
None => { } // Skip it.
Some(count) => if row.city == city {
found.push(PopulationCount {
city: row.city,

View File

@ -95,7 +95,7 @@ internal details.
Wrapping the functions which expect buffers involves using the `slice::raw` module to manipulate Rust
vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous block of memory. The
length is number of elements currently contained, and the capacity is the total size in elements of
length is the number of elements currently contained, and the capacity is the total size in elements of
the allocated memory. The length is less than or equal to the capacity.
```rust
@ -277,7 +277,7 @@ extern {
fn main() {
unsafe {
register_callback(callback);
trigger_callback(); // Triggers the callback
trigger_callback(); // Triggers the callback.
}
}
```
@ -294,7 +294,7 @@ int32_t register_callback(rust_callback callback) {
}
void trigger_callback() {
cb(7); // Will call callback(7) in Rust
cb(7); // Will call callback(7) in Rust.
}
```
@ -320,13 +320,13 @@ Rust code:
#[repr(C)]
struct RustObject {
a: i32,
// other members
// Other members...
}
extern "C" fn callback(target: *mut RustObject, a: i32) {
println!("I'm called from C with value {0}", a);
unsafe {
// Update the value in RustObject with the value received from the callback
// Update the value in RustObject with the value received from the callback:
(*target).a = a;
}
}
@ -339,7 +339,7 @@ extern {
}
fn main() {
// Create the object that will be referenced in the callback
// Create the object that will be referenced in the callback:
let mut rust_object = Box::new(RustObject { a: 5 });
unsafe {
@ -363,7 +363,7 @@ int32_t register_callback(void* callback_target, rust_callback callback) {
}
void trigger_callback() {
cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust
cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust.
}
```
@ -606,7 +606,7 @@ use libc::c_int;
# #[cfg(hidden)]
extern "C" {
/// Register the callback.
/// Registers the callback.
fn register(cb: Option<extern "C" fn(Option<extern "C" fn(c_int) -> c_int>, c_int) -> c_int>);
}
# unsafe fn register(_: Option<extern "C" fn(Option<extern "C" fn(c_int) -> c_int>,
@ -662,26 +662,31 @@ attribute turns off Rust's name mangling, so that it is easier to link to.
Its important to be mindful of `panic!`s when working with FFI. A `panic!`
across an FFI boundary is undefined behavior. If youre writing code that may
panic, you should run it in another thread, so that the panic doesnt bubble up
to C:
panic, you should run it in a closure with [`catch_unwind()`]:
```rust
use std::thread;
use std::panic::catch_unwind;
#[no_mangle]
pub extern fn oh_no() -> i32 {
let h = thread::spawn(|| {
let result = catch_unwind(|| {
panic!("Oops!");
});
match h.join() {
Ok(_) => 1,
Err(_) => 0,
match result {
Ok(_) => 0,
Err(_) => 1,
}
}
# fn main() {}
fn main() {}
```
Please note that [`catch_unwind()`] will only catch unwinding panics, not
those who abort the process. See the documentation of [`catch_unwind()`]
for more information.
[`catch_unwind()`]: https://doc.rust-lang.org/std/panic/fn.catch_unwind.html
# Representing opaque structs
Sometimes, a C library wants to provide a pointer to something, but not let you

View File

@ -135,7 +135,7 @@ In Rust, however, using `let` to introduce a binding is _not_ an expression. The
following will produce a compile-time error:
```rust,ignore
let x = (let y = 5); // expected identifier, found keyword `let`
let x = (let y = 5); // Expected identifier, found keyword `let`.
```
The compiler is telling us here that it was expecting to see the beginning of
@ -151,7 +151,7 @@ other returned value would be too surprising:
```rust
let mut y = 5;
let x = (y = 6); // x has the value `()`, not `6`
let x = (y = 6); // `x` has the value `()`, not `6`.
```
The second kind of statement in Rust is the *expression statement*. Its
@ -183,7 +183,7 @@ But what about early returns? Rust does have a keyword for that, `return`:
fn foo(x: i32) -> i32 {
return x;
// we never run this code!
// We never run this code!
x + 1
}
```
@ -307,10 +307,10 @@ fn plus_one(i: i32) -> i32 {
i + 1
}
// without type inference
// Without type inference:
let f: fn(i32) -> i32 = plus_one;
// with type inference
// With type inference:
let f = plus_one;
```

View File

@ -78,7 +78,7 @@ We can write functions that take generic types with a similar syntax:
```rust
fn takes_anything<T>(x: T) {
// do something with x
// Do something with `x`.
}
```

View File

@ -4,112 +4,25 @@ This first chapter of the book will get us going with Rust and its tooling.
First, well install Rust. Then, the classic Hello World program. Finally,
well talk about Cargo, Rusts build system and package manager.
# Installing Rust
The first step to using Rust is to install it. Generally speaking, youll need
an Internet connection to run the commands in this section, as well be
downloading Rust from the Internet.
Well be showing off a number of commands using a terminal, and those lines all
start with `$`. You don't need to type in the `$`s, they are there to indicate
the start of each command. Well see many tutorials and examples around the web
that follow this convention: `$` for commands run as our regular user, and `#`
for commands we should be running as an administrator.
## Platform support
# Installing Rust
The Rust compiler runs on, and compiles to, a great number of platforms, though
not all platforms are equally supported. Rust's support levels are organized
into three tiers, each with a different set of guarantees.
The first step to using Rust is to install it. Generally speaking, youll need
an Internet connection to run the commands in this section, as well be
downloading Rust from the Internet.
Platforms are identified by their "target triple" which is the string to inform
the compiler what kind of output should be produced. The columns below indicate
whether the corresponding component works on the specified platform.
The Rust compiler runs on, and compiles to, a great number of platforms, but is
best supported on Linux, Mac, and Windows, on the x86 and x86-64 CPU
architecture. There are official builds of the Rust compiler and standard
library for these platforms and more. [For full details on Rust platform support
see the website][platform-support].
### Tier 1
Tier 1 platforms can be thought of as "guaranteed to build and work".
Specifically they will each satisfy the following requirements:
* Automated testing is set up to run tests for the platform.
* Landing changes to the `rust-lang/rust` repository's master branch is gated on
tests passing.
* Official release artifacts are provided for the platform.
* Documentation for how to use and how to build the platform is available.
| Target | std |rustc|cargo| notes |
|-------------------------------|-----|-----|-----|----------------------------|
| `i686-apple-darwin` | ✓ | ✓ | ✓ | 32-bit OSX (10.7+, Lion+) |
| `i686-pc-windows-gnu` | ✓ | ✓ | ✓ | 32-bit MinGW (Windows 7+) |
| `i686-pc-windows-msvc` | ✓ | ✓ | ✓ | 32-bit MSVC (Windows 7+) |
| `i686-unknown-linux-gnu` | ✓ | ✓ | ✓ | 32-bit Linux (2.6.18+) |
| `x86_64-apple-darwin` | ✓ | ✓ | ✓ | 64-bit OSX (10.7+, Lion+) |
| `x86_64-pc-windows-gnu` | ✓ | ✓ | ✓ | 64-bit MinGW (Windows 7+) |
| `x86_64-pc-windows-msvc` | ✓ | ✓ | ✓ | 64-bit MSVC (Windows 7+) |
| `x86_64-unknown-linux-gnu` | ✓ | ✓ | ✓ | 64-bit Linux (2.6.18+) |
### Tier 2
Tier 2 platforms can be thought of as "guaranteed to build". Automated tests
are not run so it's not guaranteed to produce a working build, but platforms
often work to quite a good degree and patches are always welcome! Specifically,
these platforms are required to have each of the following:
* Automated building is set up, but may not be running tests.
* Landing changes to the `rust-lang/rust` repository's master branch is gated on
platforms **building**. Note that this means for some platforms only the
standard library is compiled, but for others the full bootstrap is run.
* Official release artifacts are provided for the platform.
| Target | std |rustc|cargo| notes |
|-------------------------------|-----|-----|-----|----------------------------|
| `aarch64-apple-ios` | ✓ | | | ARM64 iOS |
| `aarch64-unknown-linux-gnu` | ✓ | ✓ | ✓ | ARM64 Linux (2.6.18+) |
| `arm-linux-androideabi` | ✓ | | | ARM Android |
| `arm-unknown-linux-gnueabi` | ✓ | ✓ | ✓ | ARM Linux (2.6.18+) |
| `arm-unknown-linux-gnueabihf` | ✓ | ✓ | ✓ | ARM Linux (2.6.18+) |
| `armv7-apple-ios` | ✓ | | | ARM iOS |
|`armv7-unknown-linux-gnueabihf`| ✓ | ✓ | ✓ | ARMv7 Linux (2.6.18+) |
| `armv7s-apple-ios` | ✓ | | | ARM iOS |
| `i386-apple-ios` | ✓ | | | 32-bit x86 iOS |
| `i586-pc-windows-msvc` | ✓ | | | 32-bit Windows w/o SSE |
| `mips-unknown-linux-gnu` | ✓ | | | MIPS Linux (2.6.18+) |
| `mips-unknown-linux-musl` | ✓ | | | MIPS Linux with MUSL |
| `mipsel-unknown-linux-gnu` | ✓ | | | MIPS (LE) Linux (2.6.18+) |
| `mipsel-unknown-linux-musl` | ✓ | | | MIPS (LE) Linux with MUSL |
| `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+) |
| `x86_64-apple-ios` | ✓ | | | 64-bit x86 iOS |
| `x86_64-rumprun-netbsd` | ✓ | | | 64-bit NetBSD Rump Kernel |
| `x86_64-unknown-freebsd` | ✓ | ✓ | ✓ | 64-bit FreeBSD |
| `x86_64-unknown-linux-musl` | ✓ | | | 64-bit Linux with MUSL |
| `x86_64-unknown-netbsd` | ✓ | ✓ | ✓ | 64-bit NetBSD |
### Tier 3
Tier 3 platforms are those which Rust has support for, but landing changes is
not gated on the platform either building or passing tests. Working builds for
these platforms may be spotty as their reliability is often defined in terms of
community contributions. Additionally, release artifacts and installers are not
provided, but there may be community infrastructure producing these in
unofficial locations.
| Target | std |rustc|cargo| notes |
|-------------------------------|-----|-----|-----|----------------------------|
| `aarch64-linux-android` | ✓ | | | ARM64 Android |
| `armv7-linux-androideabi` | ✓ | | | ARM-v7a Android |
| `i686-linux-android` | ✓ | | | 32-bit x86 Android |
| `i686-pc-windows-msvc` (XP) | ✓ | | | Windows XP support |
| `i686-unknown-freebsd` | ✓ | ✓ | ✓ | 32-bit FreeBSD |
| `x86_64-pc-windows-msvc` (XP) | ✓ | | | Windows XP support |
| `x86_64-sun-solaris` | ✓ | ✓ | | 64-bit Solaris/SunOS |
| `x86_64-unknown-bitrig` | ✓ | ✓ | | 64-bit Bitrig |
| `x86_64-unknown-dragonfly` | ✓ | ✓ | | 64-bit DragonFlyBSD |
| `x86_64-unknown-openbsd` | ✓ | ✓ | | 64-bit OpenBSD |
Note that this table can be expanded over time, this isn't the exhaustive set of
tier 3 platforms that will ever be!
[platform-support]: https://forge.rust-lang.org/platform-support.html
## Installing Rust

View File

@ -19,6 +19,7 @@ has a command that does that for us. Lets give it a shot:
```bash
$ cd ~/projects
$ cargo new guessing_game --bin
Created binary (application) `guessing_game` project
$ cd guessing_game
```
@ -51,6 +52,7 @@ Lets try compiling what Cargo gave us:
```{bash}
$ cargo build
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Finished debug [unoptimized + debuginfo] target(s) in 0.53 secs
```
Excellent! Open up your `src/main.rs` again. Well be writing all of
@ -61,6 +63,7 @@ Remember the `run` command from last chapter? Try it out again here:
```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/guessing_game`
Hello, world!
```
@ -155,8 +158,8 @@ take a name on the left hand side of the assignment, it actually accepts a
to use for now:
```rust
let foo = 5; // immutable.
let mut bar = 5; // mutable
let foo = 5; // `foo` is immutable.
let mut bar = 5; // `bar` is mutable.
```
[immutable]: mutability.html
@ -282,10 +285,13 @@ well get a warning:
```bash
$ cargo build
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
src/main.rs:10:5: 10:39 warning: unused result which must be used,
#[warn(unused_must_use)] on by default
src/main.rs:10 io::stdin().read_line(&mut guess);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
warning: unused result which must be used, #[warn(unused_must_use)] on by default
--> src/main.rs:10:5
|
10 | io::stdin().read_line(&mut guess);
| ^
Finished debug [unoptimized + debuginfo] target(s) in 0.42 secs
```
Rust warns us that we havent used the `Result` value. This warning comes from
@ -321,6 +327,7 @@ Anyway, thats the tour. We can run what we have with `cargo run`:
```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Finished debug [unoptimized + debuginfo] target(s) in 0.44 secs
Running `target/debug/guessing_game`
Guess the number!
Please input your guess.
@ -373,11 +380,12 @@ Now, without changing any of our code, lets build our project:
```bash
$ cargo build
Updating registry `https://github.com/rust-lang/crates.io-index`
Downloading rand v0.3.8
Downloading libc v0.1.6
Compiling libc v0.1.6
Compiling rand v0.3.8
Downloading rand v0.3.14
Downloading libc v0.2.17
Compiling libc v0.2.17
Compiling rand v0.3.14
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Finished debug [unoptimized + debuginfo] target(s) in 5.88 secs
```
(You may see different versions, of course.)
@ -399,22 +407,24 @@ If we run `cargo build` again, well get different output:
```bash
$ cargo build
Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
```
Thats right, no output! Cargo knows that our project has been built, and that
Thats right, nothing was done! Cargo knows that our project has been built, and that
all of its dependencies are built, and so theres no reason to do all that
stuff. With nothing to do, it simply exits. If we open up `src/main.rs` again,
make a trivial change, and then save it again, well only see one line:
make a trivial change, and then save it again, well only see two lines:
```bash
$ cargo build
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Finished debug [unoptimized + debuginfo] target(s) in 0.45 secs
```
So, we told Cargo we wanted any `0.3.x` version of `rand`, and so it fetched the latest
version at the time this was written, `v0.3.8`. But what happens when next
week, version `v0.3.9` comes out, with an important bugfix? While getting
bugfixes is important, what if `0.3.9` contains a regression that breaks our
version at the time this was written, `v0.3.14`. But what happens when next
week, version `v0.3.15` comes out, with an important bugfix? While getting
bugfixes is important, what if `0.3.15` contains a regression that breaks our
code?
The answer to this problem is the `Cargo.lock` file youll now find in your
@ -423,11 +433,11 @@ figures out all of the versions that fit your criteria, and then writes them
to the `Cargo.lock` file. When you build your project in the future, Cargo
will see that the `Cargo.lock` file exists, and then use that specific version
rather than do all the work of figuring out versions again. This lets you
have a repeatable build automatically. In other words, well stay at `0.3.8`
have a repeatable build automatically. In other words, well stay at `0.3.14`
until we explicitly upgrade, and so will anyone who we share our code with,
thanks to the lock file.
What about when we _do_ want to use `v0.3.9`? Cargo has another command,
What about when we _do_ want to use `v0.3.15`? Cargo has another command,
`update`, which says ignore the lock, figure out all the latest versions that
fit what weve specified. If that works, write those versions out to the lock
file. But, by default, Cargo will only look for versions larger than `0.3.0`
@ -510,6 +520,7 @@ Try running our new program a few times:
```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Finished debug [unoptimized + debuginfo] target(s) in 0.55 secs
Running `target/debug/guessing_game`
Guess the number!
The secret number is: 7
@ -517,6 +528,7 @@ Please input your guess.
4
You guessed: 4
$ cargo run
Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/guessing_game`
Guess the number!
The secret number is: 83
@ -618,15 +630,20 @@ I did mention that this wont quite compile yet, though. Lets try it:
```bash
$ cargo build
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
src/main.rs:28:21: 28:35 error: mismatched types:
expected `&collections::string::String`,
found `&_`
(expected struct `collections::string::String`,
found integral variable) [E0308]
src/main.rs:28 match guess.cmp(&secret_number) {
^~~~~~~~~~~~~~
error[E0308]: mismatched types
--> src/main.rs:23:21
|
23 | match guess.cmp(&secret_number) {
| ^^^^^^^^^^^^^^ expected struct `std::string::String`, found integral variable
|
= note: expected type `&std::string::String`
= note: found type `&{integer}`
error: aborting due to previous error
Could not compile `guessing_game`.
error: Could not compile `guessing_game`.
To learn more, run the command again with --verbose.
```
Whew! This is a big error. The core of it is that we have mismatched types.
@ -722,6 +739,7 @@ Lets try our program out!
```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Finished debug [unoptimized + debuginfo] target(s) in 0.57 secs
Running `target/guessing_game`
Guess the number!
The secret number is: 58
@ -785,6 +803,7 @@ and quit. Observe:
```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Finished debug [unoptimized + debuginfo] target(s) in 0.58 secs
Running `target/guessing_game`
Guess the number!
The secret number is: 59
@ -919,6 +938,7 @@ Now we should be good! Lets try:
```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Finished debug [unoptimized + debuginfo] target(s) in 0.57 secs
Running `target/guessing_game`
Guess the number!
The secret number is: 61

View File

@ -34,7 +34,7 @@ fn foo() {
}
}
// other platforms
// Other platforms:
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn foo() { /* ... */ }
@ -130,7 +130,7 @@ stay valid.
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
// Put the value 0x200 in eax
// Put the value 0x200 in eax:
asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
# } }
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]

View File

@ -32,7 +32,7 @@ pub struct Box<T>(*mut T);
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
let p = libc::malloc(size as libc::size_t) as *mut u8;
// malloc failed
// Check if `malloc` failed:
if p as usize == 0 {
abort();
}
@ -46,8 +46,8 @@ unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
}
#[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>());
unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
deallocate(ptr as *mut u8, ::core::mem::size_of_val(&*ptr), ::core::mem::align_of_val(&*ptr));
}
#[start]

View File

@ -54,13 +54,13 @@ dangling pointer or use after free, when the resource is memory. A small
example of such a situation would be:
```rust,compile_fail
let r; // Introduce reference: r
let r; // Introduce reference: `r`.
{
let i = 1; // Introduce scoped value: i
r = &i; // Store reference of i in r
} // i goes out of scope and is dropped.
let i = 1; // Introduce scoped value: `i`.
r = &i; // Store reference of `i` in `r`.
} // `i` goes out of scope and is dropped.
println!("{}", r); // r still refers to i
println!("{}", r); // `r` still refers to `i`.
```
To fix this, we have to make sure that step four never happens after step
@ -81,9 +81,9 @@ let lang = "en";
let v;
{
let p = format!("lang:{}=", lang); // -+ p goes into scope
let p = format!("lang:{}=", lang); // -+ `p` comes into scope.
v = skip_prefix(line, p.as_str()); // |
} // -+ p goes out of scope
} // -+ `p` goes out of scope.
println!("{}", v);
```
@ -191,7 +191,7 @@ struct Foo<'a> {
}
fn main() {
let y = &5; // this is the same as `let _y = 5; let y = &_y;`
let y = &5; // This is the same as `let _y = 5; let y = &_y;`.
let f = Foo { x: y };
println!("{}", f.x);
@ -233,7 +233,7 @@ impl<'a> Foo<'a> {
}
fn main() {
let y = &5; // this is the same as `let _y = 5; let y = &_y;`
let y = &5; // This is the same as `let _y = 5; let y = &_y;`.
let f = Foo { x: y };
println!("x is: {}", f.x());
@ -274,11 +274,11 @@ valid for. For example:
```rust
fn main() {
let y = &5; // -+ y goes into scope
let y = &5; // -+ `y` comes into scope.
// |
// stuff // |
// Stuff... // |
// |
} // -+ y goes out of scope
} // -+ `y` goes out of scope.
```
Adding in our `Foo`:
@ -289,11 +289,12 @@ struct Foo<'a> {
}
fn main() {
let y = &5; // -+ y goes into scope
let f = Foo { x: y }; // -+ f goes into scope
// stuff // |
let y = &5; // -+ `y` comes into scope.
let f = Foo { x: y }; // -+ `f` comes into scope.
// |
} // -+ f and y go out of scope
// Stuff... // |
// |
} // -+ `f` and `y` go out of scope.
```
Our `f` lives within the scope of `y`, so everything works. What if it didnt?
@ -305,16 +306,16 @@ struct Foo<'a> {
}
fn main() {
let x; // -+ x goes into scope
let x; // -+ `x` comes into scope.
// |
{ // |
let y = &5; // ---+ y goes into scope
let f = Foo { x: y }; // ---+ f goes into scope
x = &f.x; // | | error here
} // ---+ f and y go out of scope
let y = &5; // ---+ `y` comes into scope.
let f = Foo { x: y }; // ---+ `f` comes into scope.
x = &f.x; // | | This causes an error.
} // ---+ `f` and y go out of scope.
// |
println!("{}", x); // |
} // -+ x goes out of scope
} // -+ `x` goes out of scope.
```
Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope
@ -351,7 +352,7 @@ to it.
Rust supports powerful local type inference in the bodies of functions but not in their item signatures.
It's forbidden to allow reasoning about types based on the item signature alone.
However, for ergonomic reasons, a very restricted secondary inference algorithm called
“lifetime elision” does apply when judging lifetimes. Lifetime elision is concerned solely to infer
“lifetime elision” does apply when judging lifetimes. Lifetime elision is concerned solely with inferring
lifetime parameters using three easily memorizable and unambiguous rules. This means lifetime elision
acts as a shorthand for writing an item signature, while not hiding
away the actual types involved as full local inference would if applied to it.

View File

@ -202,8 +202,8 @@ of the outer loops, you can use labels to specify which loop the `break` or
```rust
'outer: for x in 0..10 {
'inner: for y in 0..10 {
if x % 2 == 0 { continue 'outer; } // continues the loop over x
if y % 2 == 0 { continue 'inner; } // continues the loop over y
if x % 2 == 0 { continue 'outer; } // Continues the loop over `x`.
if y % 2 == 0 { continue 'inner; } // Continues the loop over `y`.
println!("x: {}, y: {}", x, y);
}
}

View File

@ -533,33 +533,33 @@ An example:
```rust
macro_rules! m1 { () => (()) }
// visible here: m1
// Visible here: `m1`.
mod foo {
// visible here: m1
// Visible here: `m1`.
#[macro_export]
macro_rules! m2 { () => (()) }
// visible here: m1, m2
// Visible here: `m1`, `m2`.
}
// visible here: m1
// Visible here: `m1`.
macro_rules! m3 { () => (()) }
// visible here: m1, m3
// Visible here: `m1`, `m3`.
#[macro_use]
mod bar {
// visible here: m1, m3
// Visible here: `m1`, `m3`.
macro_rules! m4 { () => (()) }
// visible here: m1, m3, m4
// Visible here: `m1`, `m3`, `m4`.
}
// visible here: m1, m3, m4
// Visible here: `m1`, `m3`, `m4`.
# fn main() { }
```
@ -644,7 +644,7 @@ macro_rules! bct {
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
=> (bct!($($ps),*, 1, $p ; $($ds),*));
// halt on empty data string
// Halt on empty data string:
( $($ps:tt),* ; )
=> (());
}
@ -694,7 +694,7 @@ Like this:
assert!(true);
assert_eq!(5, 3 + 2);
// nope :(
// Nope :(
assert!(5 < 3);
assert_eq!(5, 3);

View File

@ -6,7 +6,7 @@ status:
```rust,ignore
let x = 5;
x = 6; // error!
x = 6; // Error!
```
We can introduce mutability with the `mut` keyword:
@ -14,7 +14,7 @@ We can introduce mutability with the `mut` keyword:
```rust
let mut x = 5;
x = 6; // no problem!
x = 6; // No problem!
```
This is a mutable [variable binding][vb]. When a binding is mutable, it means
@ -136,7 +136,7 @@ some fields mutable and some immutable:
```rust,ignore
struct Point {
x: i32,
mut y: i32, // nope
mut y: i32, // Nope.
}
```
@ -154,7 +154,7 @@ a.x = 10;
let b = Point { x: 5, y: 6};
b.x = 10; // error: cannot assign to immutable field `b.x`
b.x = 10; // Error: cannot assign to immutable field `b.x`.
```
[struct]: structs.html

View File

@ -41,10 +41,10 @@ in the same format as C:
#![feature(start)]
#![no_std]
// Pull in the system libc library for what crt0.o likely requires
// Pull in the system libc library for what crt0.o likely requires.
extern crate libc;
// Entry point for this program
// Entry point for this program.
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
@ -84,10 +84,10 @@ compiler's name mangling too:
#![no_std]
#![no_main]
// Pull in the system libc library for what crt0.o likely requires
// Pull in the system libc library for what crt0.o likely requires.
extern crate libc;
// Entry point for this program
// Entry point for this program.
#[no_mangle] // ensure that this symbol is called `main` in the output
pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {
0

View File

@ -69,7 +69,7 @@ impl Add<i32> for Point {
type Output = f64;
fn add(self, rhs: i32) -> f64 {
// add an i32 to a Point and get an f64
// Add an i32 to a Point and get an f64.
# 1.0
}
}

View File

@ -107,7 +107,7 @@ try to use something after weve passed it as an argument:
```rust,ignore
fn take(v: Vec<i32>) {
// what happens here isnt important.
// What happens here isnt important.
}
let v = vec![1, 2, 3];
@ -264,9 +264,9 @@ Of course, if we had to hand ownership back with every function we wrote:
```rust
fn foo(v: Vec<i32>) -> Vec<i32> {
// do stuff with v
// Do stuff with `v`.
// hand back ownership
// Hand back ownership.
v
}
```
@ -275,9 +275,9 @@ This would get very tedious. It gets worse the more things we want to take owner
```rust
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
// do stuff with v1 and v2
// Do stuff with `v1` and `v2`.
// hand back ownership, and the result of our function
// Hand back ownership, and the result of our function.
(v1, v2, 42)
}

View File

@ -163,7 +163,7 @@ ignore parts of a larger structure:
```rust
fn coordinate() -> (i32, i32, i32) {
// generate and return some sort of triple tuple
// Generate and return some sort of triple tuple.
# (1, 2, 3)
}
@ -182,7 +182,7 @@ 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`"
// The next line would give "error: use of partially moved value: `tuple`".
// println!("Tuple is: {:?}", tuple);
// However,

View File

@ -54,9 +54,9 @@ bigger numbers.
If a number literal has nothing to cause its type to be inferred, it defaults:
```rust
let x = 42; // x has type i32
let x = 42; // `x` has type `i32`.
let y = 1.0; // y has type f64
let y = 1.0; // `y` has type `f64`.
```
Heres a list of the different numeric types, with links to their documentation
@ -177,8 +177,8 @@ length of the slice:
```rust
let a = [0, 1, 2, 3, 4];
let complete = &a[..]; // A slice containing all of the elements in a
let middle = &a[1..4]; // A slice of a: only the elements 1, 2, and 3
let complete = &a[..]; // A slice containing all of the elements in `a`.
let middle = &a[1..4]; // A slice of `a`: only the elements `1`, `2`, and `3`.
```
Slices have type `&[T]`. Well talk about that `T` when we cover
@ -264,8 +264,8 @@ You can disambiguate a single-element tuple from a value in parentheses with a
comma:
```rust
(0,); // single-element tuple
(0); // zero in parentheses
(0,); // A single-element tuple.
(0); // A zero in parentheses.
```
## Tuple Indexing

View File

@ -0,0 +1,213 @@
% Procedural Macros (and custom Derive)
As you've seen throughout the rest of the book, Rust provides a mechanism
called "derive" that lets you implement traits easily. For example,
```rust
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
```
is a lot simpler than
```rust
struct Point {
x: i32,
y: i32,
}
use std::fmt;
impl fmt::Debug for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y)
}
}
```
Rust includes several traits that you can derive, but it also lets you define
your own. We can accomplish this task through a feature of Rust called
"procedural macros." Eventually, procedural macros will allow for all sorts of
advanced metaprogramming in Rust, but today, they're only for custom derive.
Let's build a very simple trait, and derive it with custom derive.
## Hello World
So the first thing we need to do is start a new crate for our project.
```bash
$ cargo new --bin hello-world
```
All we want is to be able to call `hello_world()` on a derived type. Something
like this:
```rust,ignore
#[derive(HelloWorld)]
struct Pancakes;
fn main() {
Pancakes::hello_world();
}
```
With some kind of nice output, like `Hello, World! My name is Pancakes.`.
Let's go ahead and write up what we think our macro will look like from a user
perspective. In `src/main.rs` we write:
```rust,ignore
#[macro_use]
extern crate hello_world_derive;
trait HelloWorld {
fn hello_world();
}
#[derive(HelloWorld)]
struct FrenchToast;
#[derive(HelloWorld)]
struct Waffles;
fn main() {
FrenchToast::hello_world();
Waffles::hello_world();
}
```
Great. So now we just need to actually write the procedural macro. At the
moment, procedural macros need to be in their own crate. Eventually, this
restriction may be lifted, but for now, it's required. As such, there's a
convention; for a crate named `foo`, a custom derive procedural macro is called
`foo-derive`. Let's start a new crate called `hello-world-derive` inside our
`hello-world` project.
```bash
$ cargo new hello-world-derive
```
To make sure that our `hello-world` crate is able to find this new crate we've
created, we'll add it to our toml:
```toml
[dependencies]
hello-world-derive = { path = "hello-world-derive" }
```
As for our the source of our `hello-world-derive` crate, here's an example:
```rust,ignore
extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
use proc_macro::TokenStream;
#[proc_macro_derive(HelloWorld)]
pub fn hello_world(input: TokenStream) -> TokenStream {
// Construct a string representation of the type definition
let s = input.to_string();
// Parse the string representation
let ast = syn::parse_macro_input(&s).unwrap();
// Build the impl
let gen = impl_hello_world(&ast);
// Return the generated impl
gen.parse().unwrap()
}
```
So there is a lot going on here. We have introduced two new crates: [`syn`] and
[`quote`]. As you may have noticed, `input: TokenSteam` is immediately converted
to a `String`. This `String` is a string representation of the Rust code for which
we are deriving `HelloWorld` for. At the moment, the only thing you can do with a
`TokenStream` is convert it to a string. A richer API will exist in the future.
So what we really need is to be able to _parse_ Rust code into something
usable. This is where `syn` comes to play. `syn` is a crate for parsing Rust
code. The other crate we've introduced is `quote`. It's essentially the dual of
`syn` as it will make generating Rust code really easy. We could write this
stuff on our own, but it's much simpler to use these libraries. Writing a full
parser for Rust code is no simple task.
[`syn`]: https://crates.io/crates/syn
[`quote`]: https://crates.io/crates/quote
The comments seem to give us a pretty good idea of our overall strategy. We
are going to take a `String` of the Rust code for the type we are deriving, parse
it using `syn`, construct the implementation of `hello_world` (using `quote`),
then pass it back to Rust compiler.
One last note: you'll see some `unwrap()`s there. If you want to provide an
error for a procedural macro, then you should `panic!` with the error message.
In this case, we're keeping it as simple as possible.
Great, so let's write `impl_hello_world(&ast)`.
```rust,ignore
fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens {
let name = &ast.ident;
quote! {
impl HelloWorld for #name {
fn hello_world() {
println!("Hello, World! My name is {}", stringify!(#name));
}
}
}
}
```
So this is where quotes comes in. The `ast` argument is a struct that gives us
a representation of our type (which can be either a `struct` or an `enum`).
Check out the [docs](https://docs.rs/syn/0.10.5/syn/struct.MacroInput.html),
there is some useful information there. We are able to get the name of the
type using `ast.ident`. The `quote!` macro let's us write up the Rust code
that we wish to return and convert it into `Tokens`. `quote!` let's us use some
really cool templating mechanics; we simply write `#name` and `quote!` will
replace it with the variable named `name`. You can even do some repetition
similar to regular macros work. You should check out the
[docs](https://docs.rs/quote) for a good introduction.
So I think that's it. Oh, well, we do need to add dependencies for `syn` and
`quote` in the `cargo.toml` for `hello-world-derive`.
```toml
[dependencies]
syn = "0.10.5"
quote = "0.3.10"
```
That should be it. Let's try to compile `hello-world`.
```bash
error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
--> hello-world-derive/src/lib.rs:8:3
|
8 | #[proc_macro_derive(HelloWorld)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```
Oh, so it appears that we need to declare that our `hello-world-derive` crate is
a `proc-macro` crate type. How do we do this? Like this:
```toml
[lib]
proc-macro = true
```
Ok so now, let's compile `hello-world`. Executing `cargo run` now yields:
```bash
Hello, World! My name is FrenchToast
Hello, World! My name is Waffles
```
We've done it!

View File

@ -101,11 +101,11 @@ programmer *must* guarantee this.
The recommended method for the conversion is:
```rust
// explicit cast
// Explicit cast:
let i: u32 = 1;
let p_imm: *const u32 = &i as *const u32;
// implicit coercion
// Implicit coercion:
let mut m: u32 = 2;
let p_mut: *mut u32 = &mut m;

View File

@ -46,9 +46,9 @@ like this:
```rust
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
// do stuff with v1 and v2
// Do stuff with `v1` and `v2`.
// hand back ownership, and the result of our function
// Hand back ownership, and the result of our function.
(v1, v2, 42)
}
@ -63,9 +63,9 @@ the first step:
```rust
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
// do stuff with v1 and v2
// Do stuff with `v1` and `v2`.
// return the answer
// Return the answer.
42
}
@ -74,7 +74,7 @@ let v2 = vec![1, 2, 3];
let answer = foo(&v1, &v2);
// we can use v1 and v2 here!
// We can use `v1` and `v2` here!
```
A more concrete example:
@ -88,10 +88,10 @@ fn main() {
// Borrow two vectors and sum them.
// This kind of borrowing does not allow mutation through the borrowed reference.
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
// do stuff with v1 and v2
// Do stuff with `v1` and `v2`.
let s1 = sum_vec(v1);
let s2 = sum_vec(v2);
// return the answer
// Return the answer.
s1 + s2
}
@ -248,12 +248,12 @@ scopes look like this:
fn main() {
let mut x = 5;
let y = &mut x; // -+ &mut borrow of x starts here
let y = &mut x; // -+ &mut borrow of `x` starts here.
// |
*y += 1; // |
// |
println!("{}", x); // -+ - try to borrow x here
} // -+ &mut borrow of x ends here
println!("{}", x); // -+ - Try to borrow `x` here.
} // -+ &mut borrow of `x` ends here.
```
@ -265,11 +265,11 @@ So when we add the curly braces:
let mut x = 5;
{
let y = &mut x; // -+ &mut borrow starts here
let y = &mut x; // -+ &mut borrow starts here.
*y += 1; // |
} // -+ ... and ends here
} // -+ ... and ends here.
println!("{}", x); // <- try to borrow x here
println!("{}", x); // <- Try to borrow `x` here.
```
Theres no problem. Our mutable borrow goes out of scope before we create an

View File

@ -83,10 +83,10 @@ converted using `&*`.
```rust,no_run
use std::net::TcpStream;
TcpStream::connect("192.168.0.1:3000"); // &str parameter
TcpStream::connect("192.168.0.1:3000"); // Parameter is of type &str.
let addr_string = "192.168.0.1:3000".to_string();
TcpStream::connect(&*addr_string); // convert addr_string to &str
TcpStream::connect(&*addr_string); // Convert `addr_string` to &str.
```
Viewing a `String` as a `&str` is cheap, but converting the `&str` to a
@ -138,7 +138,7 @@ You can get something similar to an index like this:
```rust
# let hachiko = "忠犬ハチ公";
let dog = hachiko.chars().nth(1); // kinda like hachiko[1]
let dog = hachiko.chars().nth(1); // Kinda like `hachiko[1]`.
```
This emphasizes that we have to walk from the beginning of the list of `chars`.

View File

@ -61,7 +61,7 @@ write something like this:
```rust,ignore
struct Point {
mut x: i32,
mut x: i32, // This causes an error.
y: i32,
}
```
@ -82,9 +82,9 @@ fn main() {
point.x = 5;
let point = point; // now immutable
let point = point; // `point` is now immutable.
point.y = 6; // this causes an error
point.y = 6; // This causes an error.
}
```
@ -234,10 +234,10 @@ rather than positions.
You can define a `struct` with no members at all:
```rust
struct Electron {} // use empty braces...
struct Proton; // ...or just a semicolon
struct Electron {} // Use empty braces...
struct Proton; // ...or just a semicolon.
// whether you declared the struct with braces or not, do the same when creating one
// Whether you declared the struct with braces or not, do the same when creating one.
let x = Electron {};
let y = Proton;
```

View File

@ -23,7 +23,11 @@ $ cd adder
Cargo will automatically generate a simple test when you make a new project.
Here's the contents of `src/lib.rs`:
```rust
```rust,ignore
# // The next line exists to trick play.rust-lang.org into running our code as a
# // test:
# // fn main
#
#[cfg(test)]
mod tests {
#[test]
@ -32,6 +36,18 @@ mod tests {
}
```
For now, let's remove the `mod` bit, and focus on just the function:
```rust,ignore
# // The next line exists to trick play.rust-lang.org into running our code as a
# // test:
# // fn main
#
#[test]
fn it_works() {
}
```
Note the `#[test]`. This attribute indicates that this is a test function. It
currently has no body. That's good enough to pass! We can run the tests with
`cargo test`:
@ -39,10 +55,11 @@ currently has no body. That's good enough to pass! We can run the tests with
```bash
$ cargo test
Compiling adder v0.1.0 (file:///home/you/projects/adder)
Running target/debug/deps/adder-91b3e234d4ed382a
Finished debug [unoptimized + debuginfo] target(s) in 0.15 secs
Running target/debug/deps/adder-941f01916ca4a642
running 1 test
test tests::it_works ... ok
test it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
@ -58,13 +75,15 @@ for the test we wrote, and another for documentation tests. We'll talk about
those later. For now, see this line:
```text
test tests::it_works ... ok
test it_works ... ok
```
Note the `it_works`. This comes from the name of our function:
```rust
# fn main() {
fn it_works() {
}
# }
```
@ -77,8 +96,11 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
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() {}
```rust,ignore
# // The next line exists to trick play.rust-lang.org into running our code as a
# // test:
# // fn main
#
#[test]
fn it_works() {
assert!(false);
@ -92,19 +114,21 @@ run our tests again:
```bash
$ cargo test
Compiling adder v0.1.0 (file:///home/you/projects/adder)
Running target/debug/deps/adder-91b3e234d4ed382a
Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs
Running target/debug/deps/adder-941f01916ca4a642
running 1 test
test tests::it_works ... FAILED
test it_works ... FAILED
failures:
---- test::it_works stdout ----
thread 'tests::it_works' panicked at 'assertion failed: false', src/lib.rs:5
---- it_works stdout ----
thread 'it_works' panicked at 'assertion failed: false', src/lib.rs:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.
failures:
tests::it_works
it_works
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
@ -114,7 +138,7 @@ error: test failed
Rust indicates that our test failed:
```text
test tests::it_works ... FAILED
test it_works ... FAILED
```
And that's reflected in the summary line:
@ -147,8 +171,11 @@ 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() {}
```rust,ignore
# // The next line exists to trick play.rust-lang.org into running our code as a
# // test:
# // fn main
#
#[test]
#[should_panic]
fn it_works() {
@ -161,10 +188,11 @@ This test will now succeed if we `panic!` and fail if we complete. Let's try it:
```bash
$ cargo test
Compiling adder v0.1.0 (file:///home/you/projects/adder)
Running target/debug/deps/adder-91b3e234d4ed382a
Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs
Running target/debug/deps/adder-941f01916ca4a642
running 1 test
test tests::it_works ... ok
test it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
@ -178,8 +206,11 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
Rust provides another macro, `assert_eq!`, that compares two arguments for
equality:
```rust
# fn main() {}
```rust,ignore
# // The next line exists to trick play.rust-lang.org into running our code as a
# // test:
# // fn main
#
#[test]
#[should_panic]
fn it_works() {
@ -193,10 +224,11 @@ passes:
```bash
$ cargo test
Compiling adder v0.1.0 (file:///home/you/projects/adder)
Running target/debug/deps/adder-91b3e234d4ed382a
Finished debug [unoptimized + debuginfo] target(s) in 0.21 secs
Running target/debug/deps/adder-941f01916ca4a642
running 1 test
test tests::it_works ... ok
test it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
@ -213,8 +245,11 @@ parameter can be added to the `should_panic` attribute. The test harness will
make sure that the failure message contains the provided text. A safer version
of the example above would be:
```rust
# fn main() {}
```rust,ignore
# // The next line exists to trick play.rust-lang.org into running our code as a
# // test:
# // fn main
#
#[test]
#[should_panic(expected = "assertion failed")]
fn it_works() {
@ -225,7 +260,10 @@ fn it_works() {
That's all there is to the basics! Let's write one 'real' test:
```rust,ignore
# fn main() {}
# // The next line exists to trick play.rust-lang.org into running our code as a
# // test:
# // fn main
#
pub fn add_two(a: i32) -> i32 {
a + 2
}
@ -244,8 +282,15 @@ some known arguments and compare it to the expected output.
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() {}
```rust,ignore
# // The next line exists to trick play.rust-lang.org into running our code as a
# // test:
# // fn main
#
pub fn add_two(a: i32) -> i32 {
a + 2
}
#[test]
fn it_works() {
assert_eq!(4, add_two(2));
@ -254,7 +299,7 @@ fn it_works() {
#[test]
#[ignore]
fn expensive_test() {
// code that takes an hour to run
// Code that takes an hour to run...
}
```
@ -264,7 +309,8 @@ not:
```bash
$ cargo test
Compiling adder v0.1.0 (file:///home/you/projects/adder)
Running target/debug/deps/adder-91b3e234d4ed382a
Finished debug [unoptimized + debuginfo] target(s) in 0.20 secs
Running target/debug/deps/adder-941f01916ca4a642
running 2 tests
test expensive_test ... ignored
@ -283,7 +329,8 @@ The expensive tests can be run explicitly using `cargo test -- --ignored`:
```bash
$ cargo test -- --ignored
Running target/debug/deps/adder-91b3e234d4ed382a
Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
Running target/debug/deps/adder-941f01916ca4a642
running 1 test
test expensive_test ... ok
@ -310,7 +357,10 @@ was missing from our last example. Let's explain what this does.
The idiomatic way of writing our example looks like this:
```rust,ignore
# fn main() {}
# // The next line exists to trick play.rust-lang.org into running our code as a
# // test:
# // fn main
#
pub fn add_two(a: i32) -> i32 {
a + 2
}
@ -339,7 +389,10 @@ 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() {}
# // The next line exists to trick play.rust-lang.org into running our code as a
# // test:
# // fn main
#
pub fn add_two(a: i32) -> i32 {
a + 2
}
@ -389,9 +442,14 @@ To write an integration test, let's make a `tests` directory and
put a `tests/integration_test.rs` file inside with this as its contents:
```rust,ignore
# // The next line exists to trick play.rust-lang.org into running our code as a
# // test:
# // fn main
#
# // Sadly, this code will not work in play.rust-lang.org, because we have no
# // crate adder to import. You'll need to try this part on your own machine.
extern crate adder;
# fn main() {}
#[test]
fn it_works() {
assert_eq!(4, adder::add_two(2));
@ -452,7 +510,10 @@ 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 next line exists to trick play.rust-lang.org into running our code as a
# // test:
# // fn main
#
//! The `adder` crate provides functions that add numbers to other numbers.
//!
//! # Examples
@ -525,3 +586,45 @@ you add more examples.
We havent covered all of the details with writing documentation tests. For more,
please see the [Documentation chapter](documentation.html).
# Testing and concurrency
One thing that is important to note when writing tests is that they may be run
concurrently using threads. For this reason you should take care that your tests
are written in such a way as to not depend on each-other, or on any shared
state. "Shared state" can also include the environment, such as the current
working directory, or environment variables.
If this is an issue it is possible to control this concurrency, either by
setting the environment variable `RUST_TEST_THREADS`, or by passing the argument
`--test-threads` to the tests:
```bash
$ RUST_TEST_THREADS=1 cargo test # Run tests with no concurrency
...
$ cargo test -- --test-threads=1 # Same as above
...
```
# Test output
By default Rust's test library captures and discards output to standard
out/error, e.g. output from `println!()`. This too can be controlled using the
environment or a switch:
```bash
$ RUST_TEST_NOCAPTURE=1 cargo test # Preserve stdout/stderr
...
$ cargo test -- --nocapture # Same as above
...
```
However a better method avoiding capture is to use logging rather than raw
output. Rust has a [standard logging API][log], which provides a frontend to
multiple logging implementations. This can be used in conjunction with the
default [env_logger] to output any debugging information in a manner that can be
controlled at runtime.
[log]: https://crates.io/crates/log
[env_logger]: https://crates.io/crates/env_logger

View File

@ -221,8 +221,8 @@ struct FooVtable {
// u8:
fn call_method_on_u8(x: *const ()) -> String {
// the compiler guarantees that this function is only called
// with `x` pointing to a u8
// The compiler guarantees that this function is only called
// with `x` pointing to a u8.
let byte: &u8 = unsafe { &*(x as *const u8) };
byte.method()
@ -233,7 +233,7 @@ static Foo_for_u8_vtable: FooVtable = FooVtable {
size: 1,
align: 1,
// cast to a function pointer
// Cast to a function pointer:
method: call_method_on_u8 as fn(*const ()) -> String,
};
@ -241,8 +241,8 @@ static Foo_for_u8_vtable: FooVtable = FooVtable {
// String:
fn call_method_on_String(x: *const ()) -> String {
// the compiler guarantees that this function is only called
// with `x` pointing to a String
// The compiler guarantees that this function is only called
// with `x` pointing to a String.
let string: &String = unsafe { &*(x as *const String) };
string.method()
@ -250,7 +250,7 @@ fn call_method_on_String(x: *const ()) -> String {
static Foo_for_String_vtable: FooVtable = FooVtable {
destructor: /* compiler magic */,
// values for a 64-bit computer, halve them for 32-bit ones
// Values for a 64-bit computer, halve them for 32-bit ones.
size: 24,
align: 8,
@ -278,17 +278,17 @@ let x: u8 = 1;
// let b: &Foo = &a;
let b = TraitObject {
// store the data
// Store the data:
data: &a,
// store the methods
// Store the methods:
vtable: &Foo_for_String_vtable
};
// let y: &Foo = x;
let y = TraitObject {
// store the data
// Store the data:
data: &x,
// store the methods
// Store the methods:
vtable: &Foo_for_u8_vtable
};

View File

@ -243,28 +243,22 @@ to know more about [operator traits][operators-and-overloading].
# Rules for implementing traits
So far, weve only added trait implementations to structs, but you can
implement a trait for any type. So technically, we _could_ implement `HasArea`
for `i32`:
implement a trait for any type such as `f32`:
```rust
trait HasArea {
fn area(&self) -> f64;
trait ApproxEqual {
fn approx_equal(&self, other: &Self) -> bool;
}
impl HasArea for i32 {
fn area(&self) -> f64 {
println!("this is silly");
*self as f64
impl ApproxEqual for f32 {
fn approx_equal(&self, other: &Self) -> bool {
// Appropriate for `self` and `other` being close to 1.0.
(self - other).abs() <= ::std::f32::EPSILON
}
}
5.area();
println!("{}", 1.0.approx_equal(&1.00000001));
```
It is considered poor style to implement methods on such primitive types, even
though it is possible.
This may seem like the Wild West, but there are two restrictions around
implementing traits that prevent this from getting out of hand. The first is
that if the trait isnt defined in your scope, it doesnt apply. Heres an
@ -276,9 +270,9 @@ wont have its methods:
```rust,ignore
let mut f = std::fs::File::create("foo.txt").expect("Couldnt create foo.txt");
let buf = b"whatever"; // byte string literal. buf: &[u8; 8]
let buf = b"whatever"; // buf: &[u8; 8], a byte string literal.
let result = f.write(buf);
# result.unwrap(); // ignore the error
# result.unwrap(); // Ignore the error.
```
Heres the error:
@ -297,7 +291,7 @@ use std::io::Write;
let mut f = std::fs::File::create("foo.txt").expect("Couldnt create foo.txt");
let buf = b"whatever";
let result = f.write(buf);
# result.unwrap(); // ignore the error
# result.unwrap(); // Ignore the error.
```
This will compile without error.
@ -419,14 +413,14 @@ impl ConvertTo<i64> for i32 {
fn convert(&self) -> i64 { *self as i64 }
}
// can be called with T == i32
// Can be called with T == i32.
fn normal<T: ConvertTo<i64>>(x: &T) -> i64 {
x.convert()
}
// can be called with T == i64
// Can be called with T == i64.
fn inverse<T>(x: i32) -> T
// this is using ConvertTo as if it were "ConvertTo<i64>"
// This is using ConvertTo as if it were "ConvertTo<i64>".
where i32: ConvertTo<T> {
x.convert()
}
@ -476,15 +470,15 @@ impl Foo for OverrideDefault {
fn is_invalid(&self) -> bool {
println!("Called OverrideDefault.is_invalid!");
true // overrides the expected value of is_invalid()
true // Overrides the expected value of `is_invalid()`.
}
}
let default = UseDefault;
assert!(!default.is_invalid()); // prints "Called UseDefault.is_valid."
assert!(!default.is_invalid()); // Prints "Called UseDefault.is_valid."
let over = OverrideDefault;
assert!(over.is_invalid()); // prints "Called OverrideDefault.is_invalid!"
assert!(over.is_invalid()); // Prints "Called OverrideDefault.is_invalid!"
```
# Inheritance

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