mirror of
https://git.proxmox.com/git/rustc
synced 2025-08-05 07:55:32 +00:00
New upstream version 1.15.0+dfsg1
This commit is contained in:
parent
c30ab7b35a
commit
476ff2be50
152
CONTRIBUTING.md
152
CONTRIBUTING.md
@ -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 that’s 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
|
||||
you’re 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/
|
||||
|
50
README.md
50
README.md
@ -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 don’t 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.
|
||||
|
||||
|
717
RELEASES.md
717
RELEASES.md
@ -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
100
configure
vendored
@ -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
|
||||
|
26
mk/cfg/armv5te-unknown-linux-gnueabi.mk
Normal file
26
mk/cfg/armv5te-unknown-linux-gnueabi.mk
Normal 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
|
24
mk/cfg/i686-unknown-openbsd.mk
Normal file
24
mk/cfg/i686-unknown-openbsd.mk
Normal 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
|
@ -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):
|
||||
|
24
mk/crates.mk
24
mk/crates.mk
@ -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"'
|
||||
|
@ -65,7 +65,8 @@ PKG_FILES := \
|
||||
stage0.txt \
|
||||
rust-installer \
|
||||
tools \
|
||||
test) \
|
||||
test \
|
||||
vendor) \
|
||||
$(PKG_GITMODULES) \
|
||||
$(filter-out config.stamp, \
|
||||
$(MKFILES_FOR_TARBALL))
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
14
mk/main.mk
14
mk/main.mk
@ -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
|
||||
|
@ -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
686
src/Cargo.lock
generated
Normal 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
30
src/Cargo.toml
Normal 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
|
@ -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"
|
||||
|
@ -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!
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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(),
|
||||
|
@ -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());
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
||||
# Don’t 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
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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>>,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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\
|
||||
|
54
src/ci/docker/arm-android/Dockerfile
Normal file
54
src/ci/docker/arm-android/Dockerfile
Normal 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
|
15
src/ci/docker/arm-android/accept-licenses.sh
Executable file
15
src/ci/docker/arm-android/accept-licenses.sh
Executable 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
|
||||
}
|
45
src/ci/docker/arm-android/install-ndk.sh
Normal file
45
src/ci/docker/arm-android/install-ndk.sh
Normal 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
|
33
src/ci/docker/arm-android/install-sdk.sh
Normal file
33
src/ci/docker/arm-android/install-sdk.sh
Normal 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
|
15
src/ci/docker/arm-android/start-emulator.sh
Executable file
15
src/ci/docker/arm-android/start-emulator.sh
Executable 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 "$@"
|
75
src/ci/docker/cross/Dockerfile
Normal file
75
src/ci/docker/cross/Dockerfile
Normal 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
|
29
src/ci/docker/i686-gnu-nopt/Dockerfile
Normal file
29
src/ci/docker/i686-gnu-nopt/Dockerfile
Normal 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
|
29
src/ci/docker/i686-gnu/Dockerfile
Normal file
29
src/ci/docker/i686-gnu/Dockerfile
Normal 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
46
src/ci/docker/run.sh
Executable 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
|
37
src/ci/docker/x86_64-freebsd/Dockerfile
Normal file
37
src/ci/docker/x86_64-freebsd/Dockerfile
Normal 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
|
96
src/ci/docker/x86_64-freebsd/build-toolchain.sh
Normal file
96
src/ci/docker/x86_64-freebsd/build-toolchain.sh
Normal 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
|
30
src/ci/docker/x86_64-gnu-cargotest/Dockerfile
Normal file
30
src/ci/docker/x86_64-gnu-cargotest/Dockerfile
Normal 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
|
32
src/ci/docker/x86_64-gnu-debug/Dockerfile
Normal file
32
src/ci/docker/x86_64-gnu-debug/Dockerfile
Normal 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
|
34
src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile
Normal file
34
src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile
Normal 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
|
29
src/ci/docker/x86_64-gnu-make/Dockerfile
Normal file
29
src/ci/docker/x86_64-gnu-make/Dockerfile
Normal 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
|
29
src/ci/docker/x86_64-gnu-nopt/Dockerfile
Normal file
29
src/ci/docker/x86_64-gnu-nopt/Dockerfile
Normal 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
|
29
src/ci/docker/x86_64-gnu/Dockerfile
Normal file
29
src/ci/docker/x86_64-gnu/Dockerfile
Normal 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
|
38
src/ci/docker/x86_64-musl/Dockerfile
Normal file
38
src/ci/docker/x86_64-musl/Dockerfile
Normal 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
|
33
src/ci/docker/x86_64-musl/build-musl.sh
Normal file
33
src/ci/docker/x86_64-musl/build-musl.sh
Normal 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
52
src/ci/run.sh
Executable 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
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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)
|
||||
});
|
||||
```
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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.
|
||||
```
|
||||
|
||||
|
||||
|
@ -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;
|
||||
```
|
||||
|
@ -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 it’s
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
```
|
||||
|
@ -33,13 +33,13 @@ automatically coerce to a `&T`. Here’s 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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
||||
It’s important to be mindful of `panic!`s when working with FFI. A `panic!`
|
||||
across an FFI boundary is undefined behavior. If you’re writing code that may
|
||||
panic, you should run it in another thread, so that the panic doesn’t 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
|
||||
|
@ -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;
|
||||
```
|
||||
|
||||
|
@ -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`.
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -4,112 +4,25 @@ This first chapter of the book will get us going with Rust and its tooling.
|
||||
First, we’ll install Rust. Then, the classic ‘Hello World’ program. Finally,
|
||||
we’ll talk about Cargo, Rust’s build system and package manager.
|
||||
|
||||
# Installing Rust
|
||||
|
||||
The first step to using Rust is to install it. Generally speaking, you’ll need
|
||||
an Internet connection to run the commands in this section, as we’ll be
|
||||
downloading Rust from the Internet.
|
||||
|
||||
We’ll 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. We’ll 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, you’ll need
|
||||
an Internet connection to run the commands in this section, as we’ll 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
|
||||
|
||||
|
@ -19,6 +19,7 @@ has a command that does that for us. Let’s 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 @@ Let’s 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. We’ll 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 @@ we’ll 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 haven’t used the `Result` value. This warning comes from
|
||||
@ -321,6 +327,7 @@ Anyway, that’s 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, let’s 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, we’ll get different output:
|
||||
|
||||
```bash
|
||||
$ cargo build
|
||||
Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
|
||||
```
|
||||
|
||||
That’s right, no output! Cargo knows that our project has been built, and that
|
||||
That’s right, nothing was done! Cargo knows that our project has been built, and that
|
||||
all of its dependencies are built, and so there’s 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, we’ll only see one line:
|
||||
make a trivial change, and then save it again, we’ll 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 you’ll 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, we’ll stay at `0.3.8`
|
||||
have a repeatable build automatically. In other words, we’ll 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 we’ve 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 won’t quite compile yet, though. Let’s 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 @@ Let’s 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! Let’s 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
|
||||
|
@ -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")))]
|
||||
|
@ -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]
|
||||
|
@ -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 didn’t?
|
||||
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ try to use something after we’ve passed it as an argument:
|
||||
|
||||
```rust,ignore
|
||||
fn take(v: Vec<i32>) {
|
||||
// what happens here isn’t important.
|
||||
// What happens here isn’t 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)
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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`.
|
||||
```
|
||||
|
||||
Here’s 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]`. We’ll 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
|
||||
|
213
src/doc/book/procedural-macros.md
Normal file
213
src/doc/book/procedural-macros.md
Normal 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!
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
```
|
||||
|
||||
There’s no problem. Our mutable borrow goes out of scope before we create an
|
||||
|
@ -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`.
|
||||
|
@ -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;
|
||||
```
|
||||
|
@ -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 haven’t 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
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -243,28 +243,22 @@ to know more about [operator traits][operators-and-overloading].
|
||||
# Rules for implementing traits
|
||||
|
||||
So far, we’ve 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 isn’t defined in your scope, it doesn’t apply. Here’s an
|
||||
@ -276,9 +270,9 @@ won’t have its methods:
|
||||
|
||||
```rust,ignore
|
||||
let mut f = std::fs::File::create("foo.txt").expect("Couldn’t 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.
|
||||
```
|
||||
|
||||
Here’s the error:
|
||||
@ -297,7 +291,7 @@ use std::io::Write;
|
||||
let mut f = std::fs::File::create("foo.txt").expect("Couldn’t 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
Loading…
Reference in New Issue
Block a user