mirror of
https://git.proxmox.com/git/rustc
synced 2026-01-25 01:16:12 +00:00
New upstream version 1.13.0+dfsg1
This commit is contained in:
parent
c4e45e28a7
commit
9e0c209edc
@ -151,6 +151,10 @@ Some common make targets are:
|
||||
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.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
@ -177,6 +181,15 @@ you’re adding something to the standard library, try
|
||||
|
||||
This will not rebuild the compiler, but will run the tests.
|
||||
|
||||
Please make sure your pull request is in compliance with Rust's style
|
||||
guidelines by running
|
||||
|
||||
$ make 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)
|
||||
before every push to make sure you never forget to make this check.
|
||||
|
||||
All pull requests are reviewed by another person. We have a bot,
|
||||
@rust-highfive, that will automatically assign a random person to review your
|
||||
request.
|
||||
@ -230,7 +243,7 @@ To find documentation-related issues, sort by the [A-docs label][adocs].
|
||||
In many cases, you don't need a full `make doc`. You can use `rustdoc` directly
|
||||
to check small fixes. For example, `rustdoc src/doc/reference.md` will render
|
||||
reference to `doc/reference.html`. The CSS might be messed up, but you can
|
||||
verify that HTML is right.
|
||||
verify that the HTML is right.
|
||||
|
||||
## Issue Triage
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ Read ["Installing Rust"] from [The Book].
|
||||
* `g++` 4.7 or later or `clang++` 3.x
|
||||
* `python` 2.7 (but not 3.x)
|
||||
* GNU `make` 3.81 or later
|
||||
* `cmake` 2.8.8 or later
|
||||
* `cmake` 3.4.3 or later
|
||||
* `curl`
|
||||
* `git`
|
||||
|
||||
@ -170,7 +170,7 @@ fetch snapshots, and an OS that can execute the available snapshot binaries.
|
||||
|
||||
Snapshot binaries are currently built and tested on several platforms:
|
||||
|
||||
| Platform \ Architecture | x86 | x86_64 |
|
||||
| Platform / Architecture | x86 | x86_64 |
|
||||
|--------------------------------|-----|--------|
|
||||
| Windows (7, 8, Server 2008 R2) | ✓ | ✓ |
|
||||
| Linux (2.6.18 or later) | ✓ | ✓ |
|
||||
|
||||
291
RELEASES.md
291
RELEASES.md
@ -1,3 +1,287 @@
|
||||
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)
|
||||
===========================
|
||||
|
||||
Regression Fixes
|
||||
----------------
|
||||
|
||||
* [ICE: 'rustc' panicked at 'assertion failed: concrete_substs.is_normalized_for_trans()' #36381][36381]
|
||||
* [Confusion with double negation and booleans][36856]
|
||||
* [rustc 1.12.0 fails with SIGSEGV in release mode (syn crate 0.8.0)][36875]
|
||||
* [Rustc 1.12.0 Windows build of `ethcore` crate fails with LLVM error][36924]
|
||||
* [1.12.0: High memory usage when linking in release mode with debug info][36926]
|
||||
* [Corrupted memory after updated to 1.12][36936]
|
||||
* ["Let NullaryConstructor = something;" causes internal compiler error: "tried to overwrite interned AdtDef"][37026]
|
||||
* [Fix ICE: inject bitcast if types mismatch for invokes/calls/stores][37112]
|
||||
* [debuginfo: Handle spread_arg case in MIR-trans in a more stable way.][37153]
|
||||
|
||||
[36381]: https://github.com/rust-lang/rust/issues/36381
|
||||
[36856]: https://github.com/rust-lang/rust/issues/36856
|
||||
[36875]: https://github.com/rust-lang/rust/issues/36875
|
||||
[36924]: https://github.com/rust-lang/rust/issues/36924
|
||||
[36926]: https://github.com/rust-lang/rust/issues/36926
|
||||
[36936]: https://github.com/rust-lang/rust/issues/36936
|
||||
[37026]: https://github.com/rust-lang/rust/issues/37026
|
||||
[37112]: https://github.com/rust-lang/rust/issues/37112
|
||||
[37153]: https://github.com/rust-lang/rust/issues/37153
|
||||
|
||||
|
||||
Version 1.12.0 (2016-09-29)
|
||||
===========================
|
||||
|
||||
@ -27,7 +311,7 @@ Compiler
|
||||
was previously described [on the Rust blog]
|
||||
(https://blog.rust-lang.org/2016/04/19/MIR.html).
|
||||
* [Print the Rust target name, not the LLVM target name, with
|
||||
`--print-target-list`]
|
||||
`--print target-list`]
|
||||
(https://github.com/rust-lang/rust/pull/35489)
|
||||
* [The computation of `TypeId` is correct in some cases where it was previously
|
||||
producing inconsistent results]
|
||||
@ -74,7 +358,7 @@ Language
|
||||
useful]
|
||||
(https://github.com/rust-lang/rust/pull/34908)
|
||||
* [`macro_rules!` `stmt` matchers correctly consume the entire contents when
|
||||
insider non-braces invocations]
|
||||
inside non-braces invocations]
|
||||
(https://github.com/rust-lang/rust/pull/34886)
|
||||
* [Semicolons are properly required as statement delimeters inside
|
||||
`macro_rules!` invocations]
|
||||
@ -208,9 +492,6 @@ Cargo
|
||||
Performance
|
||||
-----------
|
||||
|
||||
* [`rustc` produces more compact code by more precisely identifying the live
|
||||
ranges of variables]
|
||||
(https://github.com/rust-lang/rust/pull/35409)
|
||||
* [`panic::catch_unwind` is more optimized]
|
||||
(https://github.com/rust-lang/rust/pull/35444)
|
||||
* [`panic::catch_unwind` no longer accesses thread-local storage on entry]
|
||||
|
||||
38
configure
vendored
38
configure
vendored
@ -360,6 +360,13 @@ abs_path() {
|
||||
(unset CDPATH && cd "$_path" > /dev/null && pwd)
|
||||
}
|
||||
|
||||
HELP=0
|
||||
for arg; do
|
||||
case "$arg" in
|
||||
--help) HELP=1;;
|
||||
esac
|
||||
done
|
||||
|
||||
msg "looking for configure programs"
|
||||
need_cmd cmp
|
||||
need_cmd mkdir
|
||||
@ -430,6 +437,10 @@ case $CFG_OSTYPE in
|
||||
CFG_CPUTYPE=$(isainfo -n)
|
||||
;;
|
||||
|
||||
Haiku)
|
||||
CFG_OSTYPE=unknown-haiku
|
||||
;;
|
||||
|
||||
MINGW*)
|
||||
# msys' `uname` does not print gcc configuration, but prints msys
|
||||
# configuration. so we cannot believe `uname -m`:
|
||||
@ -517,10 +528,18 @@ case $CFG_CPUTYPE in
|
||||
CFG_CPUTYPE=powerpc64le
|
||||
;;
|
||||
|
||||
s390x)
|
||||
CFG_CPUTYPE=s390x
|
||||
;;
|
||||
|
||||
x86_64 | x86-64 | x64 | amd64)
|
||||
CFG_CPUTYPE=x86_64
|
||||
;;
|
||||
|
||||
BePC)
|
||||
CFG_CPUTYPE=i686
|
||||
;;
|
||||
|
||||
*)
|
||||
err "unknown CPU type: $CFG_CPUTYPE"
|
||||
esac
|
||||
@ -566,11 +585,8 @@ esac
|
||||
|
||||
|
||||
OPTIONS=""
|
||||
HELP=0
|
||||
if [ "$1" = "--help" ]
|
||||
if [ "$HELP" -eq 1 ]
|
||||
then
|
||||
HELP=1
|
||||
shift
|
||||
echo
|
||||
echo "Usage: $CFG_SELF [options]"
|
||||
echo
|
||||
@ -609,7 +625,6 @@ 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 orbit 1 "get MIR where it belongs - everywhere; most importantly, in orbit"
|
||||
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)"
|
||||
@ -630,6 +645,7 @@ valopt datadir "${CFG_PREFIX}/share" "install data"
|
||||
valopt infodir "${CFG_PREFIX}/share/info" "install additional info"
|
||||
valopt llvm-root "" "set LLVM root"
|
||||
valopt python "" "set path to python"
|
||||
valopt nodejs "" "set path to nodejs"
|
||||
valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
|
||||
valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
|
||||
valopt android-cross-path "" "Android NDK standalone path (deprecated)"
|
||||
@ -668,6 +684,7 @@ valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary"
|
||||
valopt_nosave host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples"
|
||||
valopt_nosave target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples"
|
||||
valopt_nosave mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
|
||||
valopt_nosave docdir "${CFG_PREFIX}/share/doc/rust" "install documentation in PATH"
|
||||
|
||||
# On Windows this determines root of the subtree for target libraries.
|
||||
# Host runtime libs always go to 'bin'.
|
||||
@ -733,8 +750,6 @@ if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTION
|
||||
if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi
|
||||
if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi
|
||||
|
||||
if [ -n "$CFG_DISABLE_ORBIT" ]; then putvar CFG_DISABLE_ORBIT; fi
|
||||
|
||||
step_msg "looking for build programs"
|
||||
|
||||
probe_need CFG_CURL curl
|
||||
@ -747,6 +762,9 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then
|
||||
err "Found $python_version, but Python 2.7 is required"
|
||||
fi
|
||||
|
||||
# Checking for node, but not required
|
||||
probe CFG_NODEJS nodejs node
|
||||
|
||||
# If we have no git directory then we are probably a tarball distribution
|
||||
# and shouldn't attempt to load submodules
|
||||
if [ ! -e ${CFG_SRC_DIR}.git ]
|
||||
@ -899,7 +917,7 @@ then
|
||||
fi
|
||||
|
||||
CMD="${CFG_LOCAL_RUST_ROOT}/bin/rustc${BIN_SUF}"
|
||||
LRV=`$CMD --version`
|
||||
LRV=`LD_LIBRARY_PATH=${CFG_LOCAL_RUST_ROOT}/lib $CMD --version`
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
step_msg "failure while running $CMD --version"
|
||||
@ -1115,6 +1133,7 @@ putvar CFG_STDCPP_NAME
|
||||
# a little post-processing of various config values
|
||||
CFG_PREFIX=${CFG_PREFIX%/}
|
||||
CFG_MANDIR=${CFG_MANDIR%/}
|
||||
CFG_DOCDIR=${CFG_DOCDIR%/}
|
||||
CFG_HOST="$(echo $CFG_HOST | tr ',' ' ')"
|
||||
CFG_TARGET="$(echo $CFG_TARGET | tr ',' ' ')"
|
||||
CFG_SUPPORTED_TARGET=""
|
||||
@ -1749,7 +1768,7 @@ do
|
||||
CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON"
|
||||
fi
|
||||
|
||||
CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC'"
|
||||
CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ'"
|
||||
CMAKE_ARGS="$CMAKE_ARGS -G '$CFG_CMAKE_GENERATOR'"
|
||||
CMAKE_ARGS="$CMAKE_ARGS $CFG_LLVM_SRC_DIR"
|
||||
|
||||
@ -1796,6 +1815,7 @@ putvar CFG_ARMV7_LINUX_ANDROIDEABI_NDK
|
||||
putvar CFG_I686_LINUX_ANDROID_NDK
|
||||
putvar CFG_NACL_CROSS_PATH
|
||||
putvar CFG_MANDIR
|
||||
putvar CFG_DOCDIR
|
||||
putvar CFG_USING_LIBCPP
|
||||
|
||||
# Avoid spurious warnings from clang by feeding it original source on
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
.TH RUSTC "1" "August 2016" "rustc 1.12.0" "User Commands"
|
||||
.TH RUSTC "1" "September 2016" "rustc 1.13.0" "User Commands"
|
||||
.SH NAME
|
||||
rustc \- The Rust compiler
|
||||
.SH SYNOPSIS
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
.TH RUSTDOC "1" "August 2016" "rustdoc 1.12.0" "User Commands"
|
||||
.TH RUSTDOC "1" "September 2016" "rustdoc 1.13.0" "User Commands"
|
||||
.SH NAME
|
||||
rustdoc \- generate documentation from Rust source code
|
||||
.SH SYNOPSIS
|
||||
|
||||
27
mk/cfg/i686-unknown-haiku.mk
Normal file
27
mk/cfg/i686-unknown-haiku.mk
Normal file
@ -0,0 +1,27 @@
|
||||
# i686-unknown-haiku configuration
|
||||
CROSS_PREFIX_i686-unknown-haiku=i586-pc-haiku-
|
||||
CC_i686-unknown-haiku=$(CC)
|
||||
CXX_i686-unknown-haiku=$(CXX)
|
||||
CPP_i686-unknown-haiku=$(CPP)
|
||||
AR_i686-unknown-haiku=$(AR)
|
||||
CFG_LIB_NAME_i686-unknown-haiku=lib$(1).so
|
||||
CFG_STATIC_LIB_NAME_i686-unknown-haiku=lib$(1).a
|
||||
CFG_LIB_GLOB_i686-unknown-haiku=lib$(1)-*.so
|
||||
CFG_LIB_DSYM_GLOB_i686-unknown-haiku=lib$(1)-*.dylib.dSYM
|
||||
CFG_CFLAGS_i686-unknown-haiku := -m32 $(CFLAGS)
|
||||
CFG_GCCISH_CFLAGS_i686-unknown-haiku := -Wall -Werror -g -fPIC -m32 $(CFLAGS)
|
||||
CFG_GCCISH_CXXFLAGS_i686-unknown-haiku := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_i686-unknown-haiku := -shared -fPIC -ldl -pthread -lrt -g -m32
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_i686-unknown-haiku := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_i686-unknown-haiku := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_i686-unknown-haiku := .linux.def
|
||||
CFG_LLC_FLAGS_i686-unknown-haiku :=
|
||||
CFG_INSTALL_NAME_i686-unknown-haiku =
|
||||
CFG_EXE_SUFFIX_i686-unknown-haiku =
|
||||
CFG_WINDOWSY_i686-unknown-haiku :=
|
||||
CFG_UNIXY_i686-unknown-haiku := 1
|
||||
CFG_PATH_MUNGE_i686-unknown-haiku := true
|
||||
CFG_LDPATH_i686-unknown-haiku :=
|
||||
CFG_RUN_i686-unknown-haiku=$(2)
|
||||
CFG_RUN_TARG_i686-unknown-haiku=$(call CFG_RUN_i686-unknown-haiku,,$(2))
|
||||
CFG_GNU_TRIPLE_i686-unknown-haiku := i686-unknown-haiku
|
||||
1
mk/cfg/mips-unknown-linux-uclibc.mk
Normal file
1
mk/cfg/mips-unknown-linux-uclibc.mk
Normal file
@ -0,0 +1 @@
|
||||
# rustbuild-only target
|
||||
1
mk/cfg/mips64-unknown-linux-gnuabi64.mk
Normal file
1
mk/cfg/mips64-unknown-linux-gnuabi64.mk
Normal file
@ -0,0 +1 @@
|
||||
# rustbuild-only target
|
||||
1
mk/cfg/mips64el-unknown-linux-gnuabi64.mk
Normal file
1
mk/cfg/mips64el-unknown-linux-gnuabi64.mk
Normal file
@ -0,0 +1 @@
|
||||
# rustbuild-only target
|
||||
1
mk/cfg/mipsel-unknown-linux-uclibc.mk
Normal file
1
mk/cfg/mipsel-unknown-linux-uclibc.mk
Normal file
@ -0,0 +1 @@
|
||||
# rustbuild-only target
|
||||
24
mk/cfg/s390x-unknown-linux-gnu.mk
Normal file
24
mk/cfg/s390x-unknown-linux-gnu.mk
Normal file
@ -0,0 +1,24 @@
|
||||
# s390x-unknown-linux-gnu configuration
|
||||
CROSS_PREFIX_s390x-unknown-linux-gnu=s390x-linux-gnu-
|
||||
CC_s390x-unknown-linux-gnu=$(CC)
|
||||
CXX_s390x-unknown-linux-gnu=$(CXX)
|
||||
CPP_s390x-unknown-linux-gnu=$(CPP)
|
||||
AR_s390x-unknown-linux-gnu=$(AR)
|
||||
CFG_LIB_NAME_s390x-unknown-linux-gnu=lib$(1).so
|
||||
CFG_STATIC_LIB_NAME_s390x-unknown-linux-gnu=lib$(1).a
|
||||
CFG_LIB_GLOB_s390x-unknown-linux-gnu=lib$(1)-*.so
|
||||
CFG_LIB_DSYM_GLOB_s390x-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
|
||||
CFG_CFLAGS_s390x-unknown-linux-gnu := -m64 $(CFLAGS)
|
||||
CFG_GCCISH_CFLAGS_s390x-unknown-linux-gnu := -g -fPIC -m64 $(CFLAGS)
|
||||
CFG_GCCISH_CXXFLAGS_s390x-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_s390x-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m64
|
||||
CFG_GCCISH_DEF_FLAG_s390x-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_LLC_FLAGS_s390x-unknown-linux-gnu :=
|
||||
CFG_INSTALL_NAME_s390x-unknown-linux-gnu =
|
||||
CFG_EXE_SUFFIX_s390x-unknown-linux-gnu =
|
||||
CFG_WINDOWSY_s390x-unknown-linux-gnu :=
|
||||
CFG_UNIXY_s390x-unknown-linux-gnu := 1
|
||||
CFG_LDPATH_s390x-unknown-linux-gnu :=
|
||||
CFG_RUN_s390x-unknown-linux-gnu=$(2)
|
||||
CFG_RUN_TARG_s390x-unknown-linux-gnu=$(call CFG_RUN_s390x-unknown-linux-gnu,,$(2))
|
||||
CFG_GNU_TRIPLE_s390x-unknown-linux-gnu := s390x-unknown-linux-gnu
|
||||
27
mk/cfg/x86_64-unknown-haiku.mk
Normal file
27
mk/cfg/x86_64-unknown-haiku.mk
Normal file
@ -0,0 +1,27 @@
|
||||
# x86_64-unknown-haiku configuration
|
||||
CROSS_PREFIX_x86_64-unknown-haiku=x86_64-unknown-haiku-
|
||||
CC_x86_64-unknown-haiku=$(CC)
|
||||
CXX_x86_64-unknown-haiku=$(CXX)
|
||||
CPP_x86_64-unknown-haiku=$(CPP)
|
||||
AR_x86_64-unknown-haiku=$(AR)
|
||||
CFG_LIB_NAME_x86_64-unknown-haiku=lib$(1).so
|
||||
CFG_STATIC_LIB_NAME_x86_64-unknown-haiku=lib$(1).a
|
||||
CFG_LIB_GLOB_x86_64-unknown-haiku=lib$(1)-*.so
|
||||
CFG_LIB_DSYM_GLOB_x86_64-unknown-haiku=lib$(1)-*.dylib.dSYM
|
||||
CFG_CFLAGS_x86_64-unknown-haiku := -m64 $(CFLAGS)
|
||||
CFG_GCCISH_CFLAGS_x86_64-unknown-haiku := -Wall -Werror -g -fPIC -m64 $(CFLAGS)
|
||||
CFG_GCCISH_CXXFLAGS_x86_64-unknown-haiku := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-haiku := -shared -fPIC -ldl -pthread -lrt -g -m64
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-haiku := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-haiku := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_x86_64-unknown-haiku := .linux.def
|
||||
CFG_LLC_FLAGS_x86_64-unknown-haiku :=
|
||||
CFG_INSTALL_NAME_x86_64-unknown-haiku =
|
||||
CFG_EXE_SUFFIX_x86_64-unknown-haiku =
|
||||
CFG_WINDOWSY_x86_64-unknown-haiku :=
|
||||
CFG_UNIXY_x86_64-unknown-haiku := 1
|
||||
CFG_PATH_MUNGE_x86_64-unknown-haiku := true
|
||||
CFG_LDPATH_x86_64-unknown-haiku :=
|
||||
CFG_RUN_x86_64-unknown-haiku=$(2)
|
||||
CFG_RUN_TARG_x86_64-unknown-haiku=$(call CFG_RUN_x86_64-unknown-haiku,,$(2))
|
||||
CFG_GNU_TRIPLE_x86_64-unknown-haiku := x86_64-unknown-haiku
|
||||
@ -102,7 +102,6 @@ define CLEAN_TARGET_STAGE_N
|
||||
clean$(1)_T_$(2)_H_$(3): \
|
||||
$$(foreach crate,$$(CRATES),clean$(1)_T_$(2)_H_$(3)-lib-$$(crate)) \
|
||||
$$(foreach tool,$$(TOOLS) $$(DEBUGGER_BIN_SCRIPTS_ALL),clean$(1)_T_$(2)_H_$(3)-tool-$$(tool))
|
||||
$$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libcompiler-rt.a
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/librun_pass_stage* # For unix
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/run_pass_stage* # For windows
|
||||
|
||||
|
||||
40
mk/crates.mk
40
mk/crates.mk
@ -51,7 +51,7 @@
|
||||
|
||||
TARGET_CRATES := libc std term \
|
||||
getopts collections test rand \
|
||||
core alloc \
|
||||
compiler_builtins core alloc \
|
||||
rustc_unicode rustc_bitflags \
|
||||
alloc_system alloc_jemalloc \
|
||||
panic_abort panic_unwind unwind
|
||||
@ -59,12 +59,13 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_
|
||||
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
|
||||
rustc_data_structures rustc_platform_intrinsics rustc_errors \
|
||||
rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \
|
||||
rustc_const_eval rustc_const_math rustc_incremental
|
||||
HOST_CRATES := syntax syntax_ext syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \
|
||||
flate arena graphviz rbml log serialize
|
||||
rustc_const_eval rustc_const_math rustc_incremental rustc_macro
|
||||
HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \
|
||||
flate arena graphviz log serialize
|
||||
TOOLS := compiletest rustdoc rustc rustbook error_index_generator
|
||||
|
||||
DEPS_core :=
|
||||
DEPS_compiler_builtins := core
|
||||
DEPS_alloc := core libc alloc_system
|
||||
DEPS_alloc_system := core libc
|
||||
DEPS_alloc_jemalloc := core libc native:jemalloc
|
||||
@ -77,12 +78,14 @@ DEPS_panic_abort := libc alloc
|
||||
DEPS_panic_unwind := libc alloc unwind
|
||||
DEPS_unwind := libc
|
||||
|
||||
RUSTFLAGS_compiler_builtins := -lstatic=compiler-rt
|
||||
|
||||
# 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 rustc_unicode \
|
||||
DEPS_std := core libc rand alloc collections compiler_builtins rustc_unicode \
|
||||
native:backtrace \
|
||||
alloc_system panic_abort panic_unwind unwind
|
||||
DEPS_arena := std
|
||||
@ -93,34 +96,37 @@ DEPS_getopts := std
|
||||
DEPS_graphviz := std
|
||||
DEPS_log := std
|
||||
DEPS_num := std
|
||||
DEPS_rbml := std log serialize
|
||||
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_ext := syntax syntax_pos rustc_errors fmt_macros
|
||||
DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros rustc_macro
|
||||
DEPS_proc_macro := syntax syntax_pos rustc_plugin log
|
||||
DEPS_syntax_pos := serialize
|
||||
|
||||
DEPS_rustc_const_math := std syntax log serialize
|
||||
DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize \
|
||||
rustc_back graphviz syntax_pos
|
||||
|
||||
DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml \
|
||||
DEPS_rustc := syntax fmt_macros flate arena serialize getopts \
|
||||
log graphviz rustc_llvm rustc_back rustc_data_structures\
|
||||
rustc_const_math syntax_pos rustc_errors
|
||||
DEPS_rustc_back := std syntax flate log libc
|
||||
DEPS_rustc_borrowck := rustc log graphviz syntax syntax_pos rustc_errors rustc_mir
|
||||
DEPS_rustc_data_structures := std log serialize
|
||||
DEPS_rustc_data_structures := std log serialize libc
|
||||
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
|
||||
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
|
||||
rustc_trans rustc_privacy rustc_lint rustc_plugin \
|
||||
rustc_metadata syntax_ext rustc_passes rustc_save_analysis rustc_const_eval \
|
||||
rustc_incremental syntax_pos rustc_errors
|
||||
rustc_trans rustc_privacy rustc_lint rustc_plugin \
|
||||
rustc_metadata syntax_ext proc_macro \
|
||||
rustc_passes rustc_save_analysis rustc_const_eval \
|
||||
rustc_incremental syntax_pos rustc_errors rustc_macro
|
||||
DEPS_rustc_errors := log libc serialize syntax_pos
|
||||
DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval
|
||||
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
|
||||
DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rbml rustc_const_math
|
||||
DEPS_rustc_macro := std syntax
|
||||
DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rustc_const_math \
|
||||
rustc_macro syntax_ext
|
||||
DEPS_rustc_passes := syntax syntax_pos rustc core rustc_const_eval rustc_errors
|
||||
DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags
|
||||
DEPS_rustc_resolve := arena rustc log syntax syntax_pos rustc_errors
|
||||
@ -130,14 +136,13 @@ DEPS_rustc_privacy := rustc log syntax syntax_pos
|
||||
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
|
||||
log syntax serialize rustc_llvm rustc_platform_intrinsics \
|
||||
rustc_const_math rustc_const_eval rustc_incremental rustc_errors syntax_pos
|
||||
DEPS_rustc_incremental := rbml rustc syntax_pos serialize rustc_data_structures
|
||||
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
|
||||
|
||||
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
|
||||
test rustc_lint rustc_const_eval syntax_pos
|
||||
|
||||
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts test \
|
||||
rustc_lint rustc_const_eval syntax_pos rustc_data_structures
|
||||
|
||||
TOOL_DEPS_compiletest := test getopts log serialize
|
||||
TOOL_DEPS_rustdoc := rustdoc
|
||||
@ -150,6 +155,7 @@ TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
|
||||
TOOL_SOURCE_rustbook := $(S)src/tools/rustbook/main.rs
|
||||
TOOL_SOURCE_error_index_generator := $(S)src/tools/error_index_generator/main.rs
|
||||
|
||||
ONLY_RLIB_compiler_builtins := 1
|
||||
ONLY_RLIB_core := 1
|
||||
ONLY_RLIB_libc := 1
|
||||
ONLY_RLIB_alloc := 1
|
||||
|
||||
@ -76,6 +76,7 @@ tmp/dist/$$(SRC_PKG_NAME)-image: $(PKG_FILES)
|
||||
@$(call E, making src image)
|
||||
$(Q)rm -Rf tmp/dist/$(SRC_PKG_NAME)-image
|
||||
$(Q)mkdir -p tmp/dist/$(SRC_PKG_NAME)-image/lib/rustlib/src/rust
|
||||
$(Q)echo "$(CFG_VERSION)" > tmp/dist/$(SRC_PKG_NAME)-image/lib/rustlib/src/rust/version
|
||||
$(Q)tar \
|
||||
-C $(S) \
|
||||
-f - \
|
||||
|
||||
@ -66,7 +66,7 @@ ERR_IDX_GEN_MD = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(ERR_IDX_GEN_EXE)
|
||||
|
||||
D := $(S)src/doc
|
||||
|
||||
DOC_TARGETS := book nomicon style error-index
|
||||
DOC_TARGETS := book nomicon error-index
|
||||
COMPILER_DOC_TARGETS :=
|
||||
DOC_L10N_TARGETS :=
|
||||
|
||||
@ -209,13 +209,6 @@ doc/nomicon/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/nomicon/*.md) |
|
||||
$(Q)rm -rf doc/nomicon
|
||||
$(Q)$(RUSTBOOK) build $(S)src/doc/nomicon doc/nomicon
|
||||
|
||||
style: doc/style/index.html
|
||||
|
||||
doc/style/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/style/*.md) | doc/
|
||||
@$(call E, rustbook: $@)
|
||||
$(Q)rm -rf doc/style
|
||||
$(Q)$(RUSTBOOK) build $(S)src/doc/style doc/style
|
||||
|
||||
error-index: doc/error-index.html
|
||||
|
||||
# Metadata used to generate the index is created as a side effect of
|
||||
|
||||
@ -12,7 +12,8 @@ RUN_INSTALLER = cd tmp/empty_dir && \
|
||||
sh ../../tmp/dist/$(1)/install.sh \
|
||||
--prefix="$(DESTDIR)$(CFG_PREFIX)" \
|
||||
--libdir="$(DESTDIR)$(CFG_LIBDIR)" \
|
||||
--mandir="$(DESTDIR)$(CFG_MANDIR)"
|
||||
--mandir="$(DESTDIR)$(CFG_MANDIR)" \
|
||||
--docdir="$(DESTDIR)$(CFG_DOCDIR)"
|
||||
|
||||
install:
|
||||
ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
|
||||
|
||||
51
mk/main.mk
51
mk/main.mk
@ -13,12 +13,12 @@
|
||||
######################################################################
|
||||
|
||||
# The version number
|
||||
CFG_RELEASE_NUM=1.12.1
|
||||
CFG_RELEASE_NUM=1.13.0
|
||||
|
||||
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
|
||||
# NB Make sure it starts with a dot to conform to semver pre-release
|
||||
# versions (section 9)
|
||||
CFG_PRERELEASE_VERSION=.6
|
||||
CFG_PRERELEASE_VERSION=.3
|
||||
|
||||
ifeq ($(CFG_RELEASE_CHANNEL),stable)
|
||||
# This is the normal semver version string, e.g. "0.12.0", "0.12.0-nightly"
|
||||
@ -53,17 +53,6 @@ endif
|
||||
# versions in the same place
|
||||
CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE)$(CFG_EXTRA_FILENAME) | $(CFG_HASH_COMMAND))
|
||||
|
||||
# A magic value that allows the compiler to use unstable features during the
|
||||
# bootstrap even when doing so would normally be an error because of feature
|
||||
# staging or because the build turns on warnings-as-errors and unstable features
|
||||
# default to warnings. The build has to match this key in an env var.
|
||||
#
|
||||
# This value is keyed off the release to ensure that all compilers for one
|
||||
# particular release have the same bootstrap key. Note that this is
|
||||
# intentionally not "secure" by any definition, this is largely just a deterrent
|
||||
# from users enabling unstable features on the stable compiler.
|
||||
CFG_BOOTSTRAP_KEY=$(CFG_FILENAME_EXTRA)
|
||||
|
||||
# If local-rust is the same as the current version, then force a local-rebuild
|
||||
ifdef CFG_ENABLE_LOCAL_RUST
|
||||
ifeq ($(CFG_RELEASE),\
|
||||
@ -73,14 +62,6 @@ ifeq ($(CFG_RELEASE),\
|
||||
endif
|
||||
endif
|
||||
|
||||
# The stage0 compiler needs to use the previous key recorded in src/stage0.txt,
|
||||
# except for local-rebuild when it just uses the same current key.
|
||||
ifdef CFG_ENABLE_LOCAL_REBUILD
|
||||
CFG_BOOTSTRAP_KEY_STAGE0=$(CFG_BOOTSTRAP_KEY)
|
||||
else
|
||||
CFG_BOOTSTRAP_KEY_STAGE0=$(shell sed -ne 's/^rustc_key: //p' $(S)src/stage0.txt)
|
||||
endif
|
||||
|
||||
# The name of the package to use for creating tarballs, installers etc.
|
||||
CFG_PACKAGE_NAME=rustc-$(CFG_PACKAGE_VERS)
|
||||
|
||||
@ -162,12 +143,6 @@ ifdef CFG_ENABLE_DEBUGINFO
|
||||
CFG_RUSTC_FLAGS += -g
|
||||
endif
|
||||
|
||||
ifdef CFG_DISABLE_ORBIT
|
||||
$(info cfg: HOLD HOLD HOLD (CFG_DISABLE_ORBIT))
|
||||
RUSTFLAGS_STAGE1 += -Z orbit=off
|
||||
RUSTFLAGS_STAGE2 += -Z orbit=off
|
||||
endif
|
||||
|
||||
ifdef SAVE_TEMPS
|
||||
CFG_RUSTC_FLAGS += -C save-temps
|
||||
endif
|
||||
@ -306,7 +281,7 @@ endif
|
||||
# LLVM macros
|
||||
######################################################################
|
||||
|
||||
LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl
|
||||
LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz
|
||||
LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \
|
||||
interpreter instrumentation
|
||||
|
||||
@ -354,6 +329,7 @@ LLVM_AS_$(1)=$$(CFG_LLVM_INST_DIR_$(1))/bin/llvm-as$$(X_$(1))
|
||||
LLC_$(1)=$$(CFG_LLVM_INST_DIR_$(1))/bin/llc$$(X_$(1))
|
||||
|
||||
LLVM_ALL_COMPONENTS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --components)
|
||||
LLVM_VERSION_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --version)
|
||||
|
||||
endef
|
||||
|
||||
@ -392,13 +368,16 @@ 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_KEY:=$(CFG_BOOTSTRAP_KEY)
|
||||
export RUSTC_BOOTSTRAP=1
|
||||
endif
|
||||
export CFG_BOOTSTRAP_KEY
|
||||
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=5c6cf767
|
||||
|
||||
######################################################################
|
||||
# Per-stage targets and runner
|
||||
######################################################################
|
||||
@ -460,7 +439,10 @@ endif
|
||||
TSREQ$(1)_T_$(2)_H_$(3) = \
|
||||
$$(HSREQ$(1)_H_$(3)) \
|
||||
$$(foreach obj,$$(REQUIRED_OBJECTS_$(2)),\
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj))
|
||||
$$(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
|
||||
|
||||
# Prerequisites for a working stageN compiler and libraries, for a specific
|
||||
# target
|
||||
@ -514,10 +496,14 @@ ifeq ($$(OSTYPE_$(3)),apple-darwin)
|
||||
else
|
||||
ifeq ($$(CFG_WINDOWSY_$(3)),1)
|
||||
LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := PATH
|
||||
else
|
||||
ifeq ($$(OSTYPE_$(3)),unknown-haiku)
|
||||
LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := LIBRARY_PATH
|
||||
else
|
||||
LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := LD_LIBRARY_PATH
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
LD_LIBRARY_PATH_ENV_HOSTDIR$(1)_T_$(2)_H_$(3) := \
|
||||
$$(CURDIR)/$$(HLIB$(1)_H_$(3)):$$(CFG_LLVM_INST_DIR_$(3))/lib
|
||||
@ -635,7 +621,8 @@ ALL_TARGET_RULES = $(foreach target,$(CFG_TARGET), \
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
all-target-$(target)-host-$(host)))
|
||||
|
||||
all: $(ALL_TARGET_RULES) $(GENERATED) docs
|
||||
all-no-docs: $(ALL_TARGET_RULES) $(GENERATED)
|
||||
all: all-no-docs docs
|
||||
|
||||
######################################################################
|
||||
# Build system documentation
|
||||
|
||||
@ -102,8 +102,6 @@ include $(wildcard $(CFG_SRC_DIR)mk/cfg/*.mk)
|
||||
define ADD_INSTALLED_OBJECTS
|
||||
INSTALLED_OBJECTS_$(1) += $$(CFG_INSTALLED_OBJECTS_$(1))
|
||||
REQUIRED_OBJECTS_$(1) += $$(CFG_THIRD_PARTY_OBJECTS_$(1))
|
||||
INSTALLED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
|
||||
REQUIRED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
|
||||
endef
|
||||
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
|
||||
338
mk/rt.mk
338
mk/rt.mk
@ -37,6 +37,16 @@
|
||||
################################################################################
|
||||
NATIVE_LIBS := hoedown miniz rust_test_helpers
|
||||
|
||||
# A macro to add a generic implementation of intrinsics iff a arch optimized implementation is not
|
||||
# already in the list.
|
||||
# $(1) is the target
|
||||
# $(2) is the intrinsic
|
||||
define ADD_INTRINSIC
|
||||
ifeq ($$(findstring X,$$(foreach intrinsic,$$(COMPRT_OBJS_$(1)),$$(if $$(findstring $(2),$$(intrinsic)),X,))),)
|
||||
COMPRT_OBJS_$(1) += $(2)
|
||||
endif
|
||||
endef
|
||||
|
||||
# $(1) is the target triple
|
||||
define NATIVE_LIBRARIES
|
||||
|
||||
@ -230,167 +240,15 @@ COMPRT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
|
||||
COMPRT_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(COMPRT_NAME_$(1))
|
||||
COMPRT_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/compiler-rt
|
||||
|
||||
# GENERIC_SOURCES in CMakeLists.txt
|
||||
COMPRT_OBJS_$(1) := \
|
||||
absvdi2.o \
|
||||
absvsi2.o \
|
||||
adddf3.o \
|
||||
addsf3.o \
|
||||
addvdi3.o \
|
||||
addvsi3.o \
|
||||
apple_versioning.o \
|
||||
ashldi3.o \
|
||||
ashrdi3.o \
|
||||
clear_cache.o \
|
||||
clzdi2.o \
|
||||
clzsi2.o \
|
||||
cmpdi2.o \
|
||||
comparedf2.o \
|
||||
comparesf2.o \
|
||||
ctzdi2.o \
|
||||
ctzsi2.o \
|
||||
divdc3.o \
|
||||
divdf3.o \
|
||||
divdi3.o \
|
||||
divmoddi4.o \
|
||||
divmodsi4.o \
|
||||
divsc3.o \
|
||||
divsf3.o \
|
||||
divsi3.o \
|
||||
divxc3.o \
|
||||
extendsfdf2.o \
|
||||
extendhfsf2.o \
|
||||
ffsdi2.o \
|
||||
fixdfdi.o \
|
||||
fixdfsi.o \
|
||||
fixsfdi.o \
|
||||
fixsfsi.o \
|
||||
fixunsdfdi.o \
|
||||
fixunsdfsi.o \
|
||||
fixunssfdi.o \
|
||||
fixunssfsi.o \
|
||||
fixunsxfdi.o \
|
||||
fixunsxfsi.o \
|
||||
fixxfdi.o \
|
||||
floatdidf.o \
|
||||
floatdisf.o \
|
||||
floatdixf.o \
|
||||
floatsidf.o \
|
||||
floatsisf.o \
|
||||
floatundidf.o \
|
||||
floatundisf.o \
|
||||
floatundixf.o \
|
||||
floatunsidf.o \
|
||||
floatunsisf.o \
|
||||
int_util.o \
|
||||
lshrdi3.o \
|
||||
moddi3.o \
|
||||
modsi3.o \
|
||||
muldc3.o \
|
||||
muldf3.o \
|
||||
muldi3.o \
|
||||
mulodi4.o \
|
||||
mulosi4.o \
|
||||
muloti4.o \
|
||||
mulsc3.o \
|
||||
mulsf3.o \
|
||||
mulvdi3.o \
|
||||
mulvsi3.o \
|
||||
mulxc3.o \
|
||||
negdf2.o \
|
||||
negdi2.o \
|
||||
negsf2.o \
|
||||
negvdi2.o \
|
||||
negvsi2.o \
|
||||
paritydi2.o \
|
||||
paritysi2.o \
|
||||
popcountdi2.o \
|
||||
popcountsi2.o \
|
||||
powidf2.o \
|
||||
powisf2.o \
|
||||
powixf2.o \
|
||||
subdf3.o \
|
||||
subsf3.o \
|
||||
subvdi3.o \
|
||||
subvsi3.o \
|
||||
truncdfhf2.o \
|
||||
truncdfsf2.o \
|
||||
truncsfhf2.o \
|
||||
ucmpdi2.o \
|
||||
udivdi3.o \
|
||||
udivmoddi4.o \
|
||||
udivmodsi4.o \
|
||||
udivsi3.o \
|
||||
umoddi3.o \
|
||||
umodsi3.o
|
||||
# We must avoid compiling both a generic implementation (e.g. `floatdidf.c) and an arch optimized
|
||||
# implementation (e.g. `x86_64/floatdidf.S) of the same symbol (e.g. `floatdidf) because that causes
|
||||
# linker errors. To avoid that, we first add all the arch optimized implementations and then add the
|
||||
# generic implementations if and only if its arch optimized version is not already in the list. This
|
||||
# last part is handled by the ADD_INTRINSIC macro.
|
||||
|
||||
ifeq ($$(findstring ios,$(1)),)
|
||||
COMPRT_OBJS_$(1) += \
|
||||
absvti2.o \
|
||||
addtf3.o \
|
||||
addvti3.o \
|
||||
ashlti3.o \
|
||||
ashrti3.o \
|
||||
clzti2.o \
|
||||
cmpti2.o \
|
||||
ctzti2.o \
|
||||
divtf3.o \
|
||||
divti3.o \
|
||||
ffsti2.o \
|
||||
fixdfti.o \
|
||||
fixsfti.o \
|
||||
fixunsdfti.o \
|
||||
fixunssfti.o \
|
||||
fixunsxfti.o \
|
||||
fixxfti.o \
|
||||
floattidf.o \
|
||||
floattisf.o \
|
||||
floattixf.o \
|
||||
floatuntidf.o \
|
||||
floatuntisf.o \
|
||||
floatuntixf.o \
|
||||
lshrti3.o \
|
||||
modti3.o \
|
||||
multf3.o \
|
||||
multi3.o \
|
||||
mulvti3.o \
|
||||
negti2.o \
|
||||
negvti2.o \
|
||||
parityti2.o \
|
||||
popcountti2.o \
|
||||
powitf2.o \
|
||||
subtf3.o \
|
||||
subvti3.o \
|
||||
trampoline_setup.o \
|
||||
ucmpti2.o \
|
||||
udivmodti4.o \
|
||||
udivti3.o \
|
||||
umodti3.o
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring apple,$(1)),apple)
|
||||
COMPRT_OBJS_$(1) += \
|
||||
atomic_flag_clear.o \
|
||||
atomic_flag_clear_explicit.o \
|
||||
atomic_flag_test_and_set.o \
|
||||
atomic_flag_test_and_set_explicit.o \
|
||||
atomic_signal_fence.o \
|
||||
atomic_thread_fence.o
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($$(findstring windows,$(1)),)
|
||||
COMPRT_OBJS_$(1) += emutls.o
|
||||
endif
|
||||
COMPRT_OBJS_$(1) :=
|
||||
|
||||
ifeq ($$(findstring msvc,$(1)),)
|
||||
|
||||
ifeq ($$(findstring freebsd,$(1)),)
|
||||
COMPRT_OBJS_$(1) += gcc_personality_v0.o
|
||||
endif
|
||||
|
||||
COMPRT_OBJS_$(1) += emutls.o
|
||||
|
||||
ifeq ($$(findstring x86_64,$(1)),x86_64)
|
||||
COMPRT_OBJS_$(1) += \
|
||||
x86_64/chkstk.o \
|
||||
@ -540,9 +398,166 @@ COMPRT_OBJS_$(1) += \
|
||||
arm/unordsf2vfp.o
|
||||
endif
|
||||
|
||||
$(foreach intrinsic,absvdi2.o \
|
||||
absvsi2.o \
|
||||
adddf3.o \
|
||||
addsf3.o \
|
||||
addvdi3.o \
|
||||
addvsi3.o \
|
||||
apple_versioning.o \
|
||||
ashldi3.o \
|
||||
ashrdi3.o \
|
||||
clear_cache.o \
|
||||
clzdi2.o \
|
||||
clzsi2.o \
|
||||
cmpdi2.o \
|
||||
comparedf2.o \
|
||||
comparesf2.o \
|
||||
ctzdi2.o \
|
||||
ctzsi2.o \
|
||||
divdc3.o \
|
||||
divdf3.o \
|
||||
divdi3.o \
|
||||
divmoddi4.o \
|
||||
divmodsi4.o \
|
||||
divsc3.o \
|
||||
divsf3.o \
|
||||
divsi3.o \
|
||||
divxc3.o \
|
||||
extendsfdf2.o \
|
||||
extendhfsf2.o \
|
||||
ffsdi2.o \
|
||||
fixdfdi.o \
|
||||
fixdfsi.o \
|
||||
fixsfdi.o \
|
||||
fixsfsi.o \
|
||||
fixunsdfdi.o \
|
||||
fixunsdfsi.o \
|
||||
fixunssfdi.o \
|
||||
fixunssfsi.o \
|
||||
fixunsxfdi.o \
|
||||
fixunsxfsi.o \
|
||||
fixxfdi.o \
|
||||
floatdidf.o \
|
||||
floatdisf.o \
|
||||
floatdixf.o \
|
||||
floatsidf.o \
|
||||
floatsisf.o \
|
||||
floatundidf.o \
|
||||
floatundisf.o \
|
||||
floatundixf.o \
|
||||
floatunsidf.o \
|
||||
floatunsisf.o \
|
||||
int_util.o \
|
||||
lshrdi3.o \
|
||||
moddi3.o \
|
||||
modsi3.o \
|
||||
muldc3.o \
|
||||
muldf3.o \
|
||||
muldi3.o \
|
||||
mulodi4.o \
|
||||
mulosi4.o \
|
||||
muloti4.o \
|
||||
mulsc3.o \
|
||||
mulsf3.o \
|
||||
mulvdi3.o \
|
||||
mulvsi3.o \
|
||||
mulxc3.o \
|
||||
negdf2.o \
|
||||
negdi2.o \
|
||||
negsf2.o \
|
||||
negvdi2.o \
|
||||
negvsi2.o \
|
||||
paritydi2.o \
|
||||
paritysi2.o \
|
||||
popcountdi2.o \
|
||||
popcountsi2.o \
|
||||
powidf2.o \
|
||||
powisf2.o \
|
||||
powixf2.o \
|
||||
subdf3.o \
|
||||
subsf3.o \
|
||||
subvdi3.o \
|
||||
subvsi3.o \
|
||||
truncdfhf2.o \
|
||||
truncdfsf2.o \
|
||||
truncsfhf2.o \
|
||||
ucmpdi2.o \
|
||||
udivdi3.o \
|
||||
udivmoddi4.o \
|
||||
udivmodsi4.o \
|
||||
udivsi3.o \
|
||||
umoddi3.o \
|
||||
umodsi3.o,
|
||||
$(call ADD_INTRINSIC,$(1),$(intrinsic)))
|
||||
|
||||
ifeq ($$(findstring ios,$(1)),)
|
||||
$(foreach intrinsic,absvti2.o \
|
||||
addtf3.o \
|
||||
addvti3.o \
|
||||
ashlti3.o \
|
||||
ashrti3.o \
|
||||
clzti2.o \
|
||||
cmpti2.o \
|
||||
ctzti2.o \
|
||||
divtf3.o \
|
||||
divti3.o \
|
||||
ffsti2.o \
|
||||
fixdfti.o \
|
||||
fixsfti.o \
|
||||
fixunsdfti.o \
|
||||
fixunssfti.o \
|
||||
fixunsxfti.o \
|
||||
fixxfti.o \
|
||||
floattidf.o \
|
||||
floattisf.o \
|
||||
floattixf.o \
|
||||
floatuntidf.o \
|
||||
floatuntisf.o \
|
||||
floatuntixf.o \
|
||||
lshrti3.o \
|
||||
modti3.o \
|
||||
multf3.o \
|
||||
multi3.o \
|
||||
mulvti3.o \
|
||||
negti2.o \
|
||||
negvti2.o \
|
||||
parityti2.o \
|
||||
popcountti2.o \
|
||||
powitf2.o \
|
||||
subtf3.o \
|
||||
subvti3.o \
|
||||
trampoline_setup.o \
|
||||
ucmpti2.o \
|
||||
udivmodti4.o \
|
||||
udivti3.o \
|
||||
umodti3.o,
|
||||
$(call ADD_INTRINSIC,$(1),$(intrinsic)))
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring apple,$(1)),apple)
|
||||
$(foreach intrinsic,atomic_flag_clear.o \
|
||||
atomic_flag_clear_explicit.o \
|
||||
atomic_flag_test_and_set.o \
|
||||
atomic_flag_test_and_set_explicit.o \
|
||||
atomic_signal_fence.o \
|
||||
atomic_thread_fence.o,
|
||||
$(call ADD_INTRINSIC,$(1),$(intrinsic)))
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring windows,$(1)),)
|
||||
$(call ADD_INTRINSIC,$(1),emutls.o)
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring msvc,$(1)),)
|
||||
|
||||
ifeq ($$(findstring freebsd,$(1)),)
|
||||
$(call ADD_INTRINSIC,$(1),gcc_personality_v0.o)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring aarch64,$(1)),aarch64)
|
||||
COMPRT_OBJS_$(1) += \
|
||||
comparetf2.o \
|
||||
$(foreach intrinsic,comparetf2.o \
|
||||
extenddftf2.o \
|
||||
extendsftf2.o \
|
||||
fixtfdi.o \
|
||||
@ -557,7 +572,8 @@ COMPRT_OBJS_$(1) += \
|
||||
floatunsitf.o \
|
||||
multc3.o \
|
||||
trunctfdf2.o \
|
||||
trunctfsf2.o
|
||||
trunctfsf2.o,
|
||||
$(call ADD_INTRINSIC,$(1),$(intrinsic)))
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring msvc,$(1)),msvc)
|
||||
|
||||
21
mk/target.mk
21
mk/target.mk
@ -42,23 +42,6 @@ $(foreach host,$(CFG_HOST), \
|
||||
$(foreach crate,$(CRATES), \
|
||||
$(eval $(call RUST_CRATE_FULLDEPS,$(stage),$(target),$(host),$(crate)))))))
|
||||
|
||||
# $(1) stage
|
||||
# $(2) target
|
||||
# $(3) host
|
||||
define DEFINE_BOOTSTRAP_KEY
|
||||
BOOTSTRAP_KEY$(1)_T_$(2)_H_$(3) := $$(CFG_BOOTSTRAP_KEY)
|
||||
ifeq ($(1),0)
|
||||
ifeq ($(3),$$(CFG_BUILD))
|
||||
BOOTSTRAP_KEY$(1)_T_$(2)_H_$(3) := $$(CFG_BOOTSTRAP_KEY_STAGE0)
|
||||
endif
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach host,$(CFG_TARGET), \
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(foreach stage,$(STAGES), \
|
||||
$(eval $(call DEFINE_BOOTSTRAP_KEY,$(stage),$(target),$(host))))))
|
||||
|
||||
# RUST_TARGET_STAGE_N template: This defines how target artifacts are built
|
||||
# for all stage/target architecture combinations. This is one giant rule which
|
||||
# works as follows:
|
||||
@ -83,8 +66,6 @@ $(foreach host,$(CFG_TARGET), \
|
||||
define RUST_TARGET_STAGE_N
|
||||
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): CFG_COMPILER_HOST_TRIPLE = $(2)
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
|
||||
export RUSTC_BOOTSTRAP_KEY := $$(BOOTSTRAP_KEY$(1)_T_$(2)_H_$(3))
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
|
||||
$$(CRATEFILE_$(4)) \
|
||||
$$(CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4)) \
|
||||
@ -132,8 +113,6 @@ endef
|
||||
# $(4) - name of the tool being built
|
||||
define TARGET_TOOL
|
||||
|
||||
$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \
|
||||
export RUSTC_BOOTSTRAP_KEY := $$(BOOTSTRAP_KEY$(1)_T_$(2)_H_$(3))
|
||||
$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \
|
||||
$$(TOOL_SOURCE_$(4)) \
|
||||
$$(TOOL_INPUTS_$(4)) \
|
||||
|
||||
@ -27,7 +27,7 @@ TEST_TARGET_CRATES = $(filter-out core rustc_unicode alloc_system libc \
|
||||
panic_abort,$(TARGET_CRATES)) \
|
||||
collectionstest coretest
|
||||
TEST_DOC_CRATES = $(DOC_CRATES) arena flate fmt_macros getopts graphviz \
|
||||
log rand rbml serialize syntax term test
|
||||
log rand serialize syntax term test
|
||||
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve \
|
||||
rustc_trans rustc_lint,\
|
||||
$(HOST_CRATES))
|
||||
@ -649,6 +649,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) = \
|
||||
--lldb-python $$(CFG_LLDB_PYTHON) \
|
||||
--gdb-version="$(CFG_GDB_VERSION)" \
|
||||
--lldb-version="$(CFG_LLDB_VERSION)" \
|
||||
--llvm-version="$$(LLVM_VERSION_$(3))" \
|
||||
--android-cross-path=$(CFG_ARM_LINUX_ANDROIDEABI_NDK) \
|
||||
--adb-path=$(CFG_ADB) \
|
||||
--adb-test-dir=$(CFG_ADB_TEST_DIR) \
|
||||
|
||||
21
src/bootstrap/Cargo.lock
generated
21
src/bootstrap/Cargo.lock
generated
@ -157,3 +157,24 @@ name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9"
|
||||
"checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978"
|
||||
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
|
||||
"checksum gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)" = "<none>"
|
||||
"checksum gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)" = "cfe877476e53690ebb0ce7325d0bf43e198d9500291b54b3c65e518de5039b07"
|
||||
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "55f3730be7e803cf350d32061958171731c2395831fbd67a61083782808183e0"
|
||||
"checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db"
|
||||
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||
"checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09"
|
||||
"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2"
|
||||
"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199"
|
||||
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
|
||||
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
||||
"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d"
|
||||
"checksum toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "fcd27a04ca509aff336ba5eb2abc58d456f52c4ff64d9724d88acb85ead560b6"
|
||||
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
|
||||
"checksum winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfaaa8fbdaa618fa6914b59b2769d690dd7521920a18d84b42d254678dd5fd4"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
||||
@ -38,21 +38,27 @@ fn main() {
|
||||
// is passed (a bit janky...)
|
||||
let target = args.windows(2).find(|w| &*w[0] == "--target")
|
||||
.and_then(|w| w[1].to_str());
|
||||
let version = args.iter().find(|w| &**w == "-vV");
|
||||
|
||||
// Build scripts always use the snapshot compiler which is guaranteed to be
|
||||
// able to produce an executable, whereas intermediate compilers may not
|
||||
// have the standard library built yet and may not be able to produce an
|
||||
// executable. Otherwise we just use the standard compiler we're
|
||||
// bootstrapping with.
|
||||
let (rustc, libdir) = if target.is_none() {
|
||||
//
|
||||
// Also note that cargo will detect the version of the compiler to trigger
|
||||
// a rebuild when the compiler changes. If this happens, we want to make
|
||||
// sure to use the actual compiler instead of the snapshot compiler becase
|
||||
// that's the one that's actually changing.
|
||||
let (rustc, libdir) = if target.is_none() && version.is_none() {
|
||||
("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR")
|
||||
} else {
|
||||
("RUSTC_REAL", "RUSTC_LIBDIR")
|
||||
};
|
||||
let stage = env::var("RUSTC_STAGE").unwrap();
|
||||
let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
|
||||
|
||||
let rustc = env::var_os(rustc).unwrap();
|
||||
let libdir = env::var_os(libdir).unwrap();
|
||||
let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
|
||||
let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
|
||||
let mut dylib_path = bootstrap::util::dylib_path();
|
||||
dylib_path.insert(0, PathBuf::from(libdir));
|
||||
|
||||
@ -65,7 +71,7 @@ fn main() {
|
||||
if let Some(target) = target {
|
||||
// The stage0 compiler has a special sysroot distinct from what we
|
||||
// actually downloaded, so we just always pass the `--sysroot` option.
|
||||
cmd.arg("--sysroot").arg(env::var_os("RUSTC_SYSROOT").unwrap());
|
||||
cmd.arg("--sysroot").arg(env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"));
|
||||
|
||||
// When we build Rust dylibs they're all intended for intermediate
|
||||
// usage, so make sure we pass the -Cprefer-dynamic flag instead of
|
||||
|
||||
@ -20,15 +20,16 @@ use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
let args = env::args_os().skip(1).collect::<Vec<_>>();
|
||||
let rustdoc = env::var_os("RUSTDOC_REAL").unwrap();
|
||||
let libdir = env::var_os("RUSTC_LIBDIR").unwrap();
|
||||
let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set");
|
||||
let libdir = env::var_os("RUSTC_LIBDIR").expect("RUSTC_LIBDIR was not set");
|
||||
let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
|
||||
|
||||
let mut dylib_path = bootstrap::util::dylib_path();
|
||||
dylib_path.insert(0, PathBuf::from(libdir));
|
||||
|
||||
let mut cmd = Command::new(rustdoc);
|
||||
cmd.args(&args)
|
||||
.arg("--cfg").arg(format!("stage{}", env::var("RUSTC_STAGE").unwrap()))
|
||||
.arg("--cfg").arg(format!("stage{}", stage))
|
||||
.arg("--cfg").arg("dox")
|
||||
.env(bootstrap::util::dylib_path_var(),
|
||||
env::join_paths(&dylib_path).unwrap());
|
||||
@ -37,4 +38,3 @@ fn main() {
|
||||
Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -131,7 +131,8 @@ def stage0_data(rust_root):
|
||||
def format_build_time(duration):
|
||||
return str(datetime.timedelta(seconds=int(duration)))
|
||||
|
||||
class RustBuild:
|
||||
|
||||
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())
|
||||
@ -142,7 +143,7 @@ class RustBuild:
|
||||
os.makedirs(cargo_cache)
|
||||
|
||||
if self.rustc().startswith(self.bin_root()) and \
|
||||
(not os.path.exists(self.rustc()) or self.rustc_out_of_date()):
|
||||
(not os.path.exists(self.rustc()) or self.rustc_out_of_date()):
|
||||
if os.path.exists(self.bin_root()):
|
||||
shutil.rmtree(self.bin_root())
|
||||
channel = self.stage0_rustc_channel()
|
||||
@ -165,7 +166,7 @@ class RustBuild:
|
||||
f.write(self.stage0_rustc_date())
|
||||
|
||||
if self.cargo().startswith(self.bin_root()) and \
|
||||
(not os.path.exists(self.cargo()) or self.cargo_out_of_date()):
|
||||
(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()
|
||||
@ -238,8 +239,8 @@ class RustBuild:
|
||||
|
||||
def get_string(self, line):
|
||||
start = line.find('"')
|
||||
end = start + 1 + line[start+1:].find('"')
|
||||
return line[start+1:end]
|
||||
end = start + 1 + line[start + 1:].find('"')
|
||||
return line[start + 1:end]
|
||||
|
||||
def exe_suffix(self):
|
||||
if sys.platform == 'win32':
|
||||
@ -269,6 +270,7 @@ class RustBuild:
|
||||
sys.exit(ret)
|
||||
|
||||
def build_triple(self):
|
||||
default_encoding = sys.getdefaultencoding()
|
||||
config = self.get_toml('build')
|
||||
if config:
|
||||
return config
|
||||
@ -276,8 +278,8 @@ class RustBuild:
|
||||
if config:
|
||||
return config
|
||||
try:
|
||||
ostype = subprocess.check_output(['uname', '-s']).strip()
|
||||
cputype = subprocess.check_output(['uname', '-m']).strip()
|
||||
ostype = subprocess.check_output(['uname', '-s']).strip().decode(default_encoding)
|
||||
cputype = subprocess.check_output(['uname', '-m']).strip().decode(default_encoding)
|
||||
except (subprocess.CalledProcessError, WindowsError):
|
||||
if sys.platform == 'win32':
|
||||
return 'x86_64-pc-windows-msvc'
|
||||
@ -289,7 +291,8 @@ class RustBuild:
|
||||
# Darwin's `uname -s` lies and always returns i386. We have to use
|
||||
# sysctl instead.
|
||||
if ostype == 'Darwin' and cputype == 'i686':
|
||||
sysctl = subprocess.check_output(['sysctl', 'hw.optional.x86_64'])
|
||||
args = ['sysctl', 'hw.optional.x86_64']
|
||||
sysctl = subprocess.check_output(args).decode(default_encoding)
|
||||
if ': 1' in sysctl:
|
||||
cputype = 'x86_64'
|
||||
|
||||
|
||||
@ -148,6 +148,9 @@ pub fn compiletest(build: &Build,
|
||||
if let Some(ref dir) = build.lldb_python_dir {
|
||||
cmd.arg("--lldb-python-dir").arg(dir);
|
||||
}
|
||||
let llvm_config = build.llvm_config(target);
|
||||
let llvm_version = output(Command::new(&llvm_config).arg("--version"));
|
||||
cmd.arg("--llvm-version").arg(llvm_version);
|
||||
|
||||
cmd.args(&build.flags.args);
|
||||
|
||||
@ -158,7 +161,6 @@ pub fn compiletest(build: &Build,
|
||||
// Only pass correct values for these flags for the `run-make` suite as it
|
||||
// requires that a C++ compiler was configured which isn't always the case.
|
||||
if suite == "run-make" {
|
||||
let llvm_config = build.llvm_config(target);
|
||||
let llvm_components = output(Command::new(&llvm_config).arg("--components"));
|
||||
let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
|
||||
cmd.arg("--cc").arg(build.cc(target))
|
||||
@ -183,7 +185,7 @@ pub fn compiletest(build: &Build,
|
||||
}
|
||||
}
|
||||
}
|
||||
build.add_bootstrap_key(compiler, &mut cmd);
|
||||
build.add_bootstrap_key(&mut cmd);
|
||||
|
||||
cmd.arg("--adb-path").arg("adb");
|
||||
cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
|
||||
|
||||
@ -28,7 +28,6 @@ pub fn clean(build: &Build) {
|
||||
|
||||
let out = build.out.join(host);
|
||||
|
||||
rm_rf(build, &out.join("compiler-rt"));
|
||||
rm_rf(build, &out.join("doc"));
|
||||
|
||||
for stage in 0..4 {
|
||||
|
||||
@ -16,12 +16,14 @@
|
||||
//! compiler. This module is also responsible for assembling the sysroot as it
|
||||
//! goes along from the output of the previous stage.
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::fs::{self, File};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use build_helper::output;
|
||||
use filetime::FileTime;
|
||||
|
||||
use util::{exe, staticlib, libdir, mtime, is_dylib, copy};
|
||||
use {Build, Compiler, Mode};
|
||||
@ -35,13 +37,23 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
|
||||
compiler.host, target);
|
||||
|
||||
// Move compiler-rt into place as it'll be required by the compiler when
|
||||
// building the standard library to link the dylib of libstd
|
||||
let libdir = build.sysroot_libdir(compiler, target);
|
||||
let _ = fs::remove_dir_all(&libdir);
|
||||
t!(fs::create_dir_all(&libdir));
|
||||
copy(&build.compiler_rt_built.borrow()[target],
|
||||
&libdir.join(staticlib("compiler-rt", target)));
|
||||
// FIXME(stage0) remove this `if` after the next snapshot
|
||||
// The stage0 compiler still passes the `-lcompiler-rt` flag to the linker but now `bootstrap`
|
||||
// never builds a `libcopmiler-rt.a`! We'll fill the hole by simply copying stage0's
|
||||
// `libcompiler-rt.a` to where the stage1's one is expected (though we could as well just use
|
||||
// an empty `.a` archive). Note that the symbols of that stage0 `libcompiler-rt.a` won't make
|
||||
// it to the final binary because now `libcore.rlib` also contains the symbols that
|
||||
// `libcompiler-rt.a` provides. Since that rlib appears first in the linker arguments, its
|
||||
// symbols are used instead of `libcompiler-rt.a`'s.
|
||||
if compiler.stage == 0 {
|
||||
let rtlib = &staticlib("compiler-rt", target);
|
||||
let src = build.rustc.parent().unwrap().parent().unwrap().join("lib").join("rustlib")
|
||||
.join(target).join("lib").join(rtlib);
|
||||
copy(&src, &libdir.join(rtlib));
|
||||
}
|
||||
|
||||
// Some platforms have startup objects that may be required to produce the
|
||||
// libstd dynamic library, for example.
|
||||
@ -59,13 +71,14 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
cargo.env("JEMALLOC_OVERRIDE", jemalloc);
|
||||
}
|
||||
}
|
||||
if let Some(ref p) = build.config.musl_root {
|
||||
if target.contains("musl") {
|
||||
if target.contains("musl") {
|
||||
if let Some(p) = build.musl_root(target) {
|
||||
cargo.env("MUSL_ROOT", p);
|
||||
}
|
||||
}
|
||||
|
||||
build.run(&mut cargo);
|
||||
update_mtime(&libstd_stamp(build, compiler, target));
|
||||
std_link(build, target, compiler, compiler.host);
|
||||
}
|
||||
|
||||
@ -83,26 +96,24 @@ pub fn std_link(build: &Build,
|
||||
|
||||
// If we're linking one compiler host's output into another, then we weren't
|
||||
// called from the `std` method above. In that case we clean out what's
|
||||
// already there and then also link compiler-rt into place.
|
||||
// already there.
|
||||
if host != compiler.host {
|
||||
let _ = fs::remove_dir_all(&libdir);
|
||||
t!(fs::create_dir_all(&libdir));
|
||||
copy(&build.compiler_rt_built.borrow()[target],
|
||||
&libdir.join(staticlib("compiler-rt", target)));
|
||||
}
|
||||
add_to_sysroot(&out_dir, &libdir);
|
||||
|
||||
if target.contains("musl") && !target.contains("mips") {
|
||||
copy_third_party_objects(build, target, &libdir);
|
||||
copy_musl_third_party_objects(build, &libdir);
|
||||
}
|
||||
}
|
||||
|
||||
/// Copies the crt(1,i,n).o startup objects
|
||||
///
|
||||
/// Only required for musl targets that statically link to libc
|
||||
fn copy_third_party_objects(build: &Build, target: &str, into: &Path) {
|
||||
fn copy_musl_third_party_objects(build: &Build, into: &Path) {
|
||||
for &obj in &["crt1.o", "crti.o", "crtn.o"] {
|
||||
copy(&compiler_file(build.cc(target), obj), &into.join(obj));
|
||||
copy(&build.config.musl_root.as_ref().unwrap().join("lib").join(obj), &into.join(obj));
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,14 +128,16 @@ fn build_startup_objects(build: &Build, target: &str, into: &Path) {
|
||||
return
|
||||
}
|
||||
let compiler = Compiler::new(0, &build.config.build);
|
||||
let compiler = build.compiler_path(&compiler);
|
||||
let compiler_path = build.compiler_path(&compiler);
|
||||
|
||||
for file in t!(fs::read_dir(build.src.join("src/rtstartup"))) {
|
||||
let file = t!(file);
|
||||
build.run(Command::new(&compiler)
|
||||
.arg("--emit=obj")
|
||||
.arg("--out-dir").arg(into)
|
||||
.arg(file.path()));
|
||||
let mut cmd = Command::new(&compiler_path);
|
||||
build.add_bootstrap_key(&mut cmd);
|
||||
build.run(cmd.arg("--target").arg(target)
|
||||
.arg("--emit=obj")
|
||||
.arg("--out-dir").arg(into)
|
||||
.arg(file.path()));
|
||||
}
|
||||
|
||||
for obj in ["crt2.o", "dllcrt2.o"].iter() {
|
||||
@ -141,11 +154,12 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
|
||||
compiler.host, target);
|
||||
let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
|
||||
build.clear_if_dirty(&out_dir, &libstd_shim(build, compiler, target));
|
||||
build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
|
||||
let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build");
|
||||
cargo.arg("--manifest-path")
|
||||
.arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
|
||||
build.run(&mut cargo);
|
||||
update_mtime(&libtest_stamp(build, compiler, target));
|
||||
test_link(build, target, compiler, compiler.host);
|
||||
}
|
||||
|
||||
@ -173,7 +187,7 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
compiler.stage, compiler.host, target);
|
||||
|
||||
let out_dir = build.cargo_out(compiler, Mode::Librustc, target);
|
||||
build.clear_if_dirty(&out_dir, &libtest_shim(build, compiler, target));
|
||||
build.clear_if_dirty(&out_dir, &libtest_stamp(build, compiler, target));
|
||||
|
||||
let mut cargo = build.cargo(compiler, Mode::Librustc, target, "build");
|
||||
cargo.arg("--features").arg(build.rustc_features())
|
||||
@ -185,7 +199,6 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
cargo.env("CFG_RELEASE", &build.release)
|
||||
.env("CFG_RELEASE_CHANNEL", &build.config.channel)
|
||||
.env("CFG_VERSION", &build.version)
|
||||
.env("CFG_BOOTSTRAP_KEY", &build.bootstrap_key)
|
||||
.env("CFG_PREFIX", build.config.prefix.clone().unwrap_or(String::new()))
|
||||
.env("CFG_LIBDIR_RELATIVE", "lib");
|
||||
|
||||
@ -203,6 +216,10 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
cargo.env("LLVM_RUSTLLVM", "1");
|
||||
}
|
||||
cargo.env("LLVM_CONFIG", build.llvm_config(target));
|
||||
let target_config = build.config.target_config.get(target);
|
||||
if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
|
||||
cargo.env("CFG_LLVM_ROOT", s);
|
||||
}
|
||||
if build.config.llvm_static_stdcpp {
|
||||
cargo.env("LLVM_STATIC_STDCPP",
|
||||
compiler_file(build.cxx(target), "libstdc++.a"));
|
||||
@ -234,14 +251,14 @@ pub fn rustc_link(build: &Build,
|
||||
|
||||
/// Cargo's output path for the standard library in a given stage, compiled
|
||||
/// by a particular compiler for the specified target.
|
||||
fn libstd_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
|
||||
build.cargo_out(compiler, Mode::Libstd, target).join("libstd_shim.rlib")
|
||||
fn libstd_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
|
||||
build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp")
|
||||
}
|
||||
|
||||
/// Cargo's output path for libtest in a given stage, compiled by a particular
|
||||
/// compiler for the specified target.
|
||||
fn libtest_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
|
||||
build.cargo_out(compiler, Mode::Libtest, target).join("libtest_shim.rlib")
|
||||
fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
|
||||
build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp")
|
||||
}
|
||||
|
||||
fn compiler_file(compiler: &Path, file: &str) -> PathBuf {
|
||||
@ -354,10 +371,35 @@ pub fn tool(build: &Build, stage: u32, host: &str, tool: &str) {
|
||||
// Maybe when libstd is compiled it should clear out the rustc of the
|
||||
// corresponding stage?
|
||||
// let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target);
|
||||
// build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target));
|
||||
// build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target));
|
||||
|
||||
let mut cargo = build.cargo(&compiler, Mode::Tool, host, "build");
|
||||
cargo.arg("--manifest-path")
|
||||
.arg(build.src.join(format!("src/tools/{}/Cargo.toml", tool)));
|
||||
build.run(&mut cargo);
|
||||
}
|
||||
|
||||
/// Updates the mtime of a stamp file if necessary, only changing it if it's
|
||||
/// older than some other file in the same directory.
|
||||
///
|
||||
/// We don't know what file Cargo is going to output (because there's a hash in
|
||||
/// the file name) but we know where it's going to put it. We use this helper to
|
||||
/// detect changes to that output file by looking at the modification time for
|
||||
/// all files in a directory and updating the stamp if any are newer.
|
||||
fn update_mtime(path: &Path) {
|
||||
let mut max = None;
|
||||
if let Ok(entries) = path.parent().unwrap().read_dir() {
|
||||
for entry in entries.map(|e| t!(e)) {
|
||||
if t!(entry.file_type()).is_file() {
|
||||
let meta = t!(entry.metadata());
|
||||
let time = FileTime::from_last_modification_time(&meta);
|
||||
max = cmp::max(max, Some(time));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !max.is_none() && max <= Some(mtime(path)) {
|
||||
return
|
||||
}
|
||||
t!(File::create(path));
|
||||
}
|
||||
|
||||
@ -76,8 +76,11 @@ pub struct Config {
|
||||
|
||||
// misc
|
||||
pub channel: String,
|
||||
// Fallback musl-root for all targets
|
||||
pub musl_root: Option<PathBuf>,
|
||||
pub prefix: Option<String>,
|
||||
pub codegen_tests: bool,
|
||||
pub nodejs: Option<PathBuf>,
|
||||
}
|
||||
|
||||
/// Per-target configuration stored in the global configuration structure.
|
||||
@ -88,6 +91,7 @@ pub struct Target {
|
||||
pub cc: Option<PathBuf>,
|
||||
pub cxx: Option<PathBuf>,
|
||||
pub ndk: Option<PathBuf>,
|
||||
pub musl_root: Option<PathBuf>,
|
||||
}
|
||||
|
||||
/// Structure of the `config.toml` file that configuration is read from.
|
||||
@ -143,6 +147,7 @@ struct Rust {
|
||||
rpath: Option<bool>,
|
||||
optimize_tests: Option<bool>,
|
||||
debuginfo_tests: Option<bool>,
|
||||
codegen_tests: Option<bool>,
|
||||
}
|
||||
|
||||
/// TOML representation of how each build target is configured.
|
||||
@ -169,6 +174,7 @@ impl Config {
|
||||
config.rust_codegen_units = 1;
|
||||
config.build = build.to_string();
|
||||
config.channel = "dev".to_string();
|
||||
config.codegen_tests = true;
|
||||
|
||||
let toml = file.map(|file| {
|
||||
let mut f = t!(File::open(&file));
|
||||
@ -230,6 +236,7 @@ impl Config {
|
||||
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);
|
||||
set(&mut config.codegen_tests, rust.codegen_tests);
|
||||
set(&mut config.rust_rpath, rust.rpath);
|
||||
set(&mut config.debug_jemalloc, rust.debug_jemalloc);
|
||||
set(&mut config.use_jemalloc, rust.use_jemalloc);
|
||||
@ -322,6 +329,7 @@ impl Config {
|
||||
("DEBUGINFO_TESTS", self.rust_debuginfo_tests),
|
||||
("LOCAL_REBUILD", self.local_rebuild),
|
||||
("NINJA", self.ninja),
|
||||
("CODEGEN_TESTS", self.codegen_tests),
|
||||
}
|
||||
|
||||
match key {
|
||||
@ -388,6 +396,9 @@ impl Config {
|
||||
self.rustc = Some(PathBuf::from(value).join("bin/rustc"));
|
||||
self.cargo = Some(PathBuf::from(value).join("bin/cargo"));
|
||||
}
|
||||
"CFG_NODEJS" if value.len() > 0 => {
|
||||
self.nodejs = Some(PathBuf::from(value));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
# Sample TOML configuration file for building Rust.
|
||||
#
|
||||
# To configure rustbuild, copy this file to the directory from which you will be
|
||||
# running the build, and name it config.toml.
|
||||
#
|
||||
# All options are commented out by default in this file, and they're commented
|
||||
# out with their default values. The build system by default looks for
|
||||
# `config.toml` in the current directory of a build for build configuration, but
|
||||
@ -115,10 +118,6 @@
|
||||
# nightly features
|
||||
#channel = "dev"
|
||||
|
||||
# The root location of the MUSL installation directory. The library directory
|
||||
# will also need to contain libunwind.a for an unwinding implementation.
|
||||
#musl-root = "..."
|
||||
|
||||
# By default the `rustc` executable is built with `-Wl,-rpath` flags on Unix
|
||||
# platforms to ensure that the compiler is usable by default from the build
|
||||
# directory (as it links to a number of dynamic libraries). This may not be
|
||||
@ -130,6 +129,10 @@
|
||||
#optimize-tests = true
|
||||
#debuginfo-tests = true
|
||||
|
||||
# Flag indicating whether codegen tests will be run or not. If you get an error
|
||||
# saying that the FileCheck executable is missing, you may want to disable this.
|
||||
#codegen-tests = true
|
||||
|
||||
# =============================================================================
|
||||
# Options for specific targets
|
||||
#
|
||||
@ -160,3 +163,9 @@
|
||||
# the NDK for the target lives. This is used to find the C compiler to link and
|
||||
# build native code.
|
||||
#android-ndk = "/path/to/ndk"
|
||||
|
||||
# The root location of the MUSL installation directory. The library directory
|
||||
# will also need to contain libunwind.a for an unwinding implementation. Note
|
||||
# that this option only makes sense for MUSL targets that produce statically
|
||||
# linked binaries
|
||||
#musl-root = "..."
|
||||
|
||||
@ -388,6 +388,9 @@ pub fn rust_src(build: &Build) {
|
||||
// Rename directory, so that root folder of tarball has the correct name
|
||||
t!(fs::rename(&dst_src, &plain_dst_src));
|
||||
|
||||
// Create the version file
|
||||
write_file(&plain_dst_src.join("version"), build.version.as_bytes());
|
||||
|
||||
// Create plain source tarball
|
||||
let mut cmd = Command::new("tar");
|
||||
cmd.arg("-czf").arg(sanitize_sh(&distdir(build).join(&format!("{}.tar.gz", plain_name))))
|
||||
@ -431,3 +434,8 @@ fn sanitize_sh(path: &Path) -> String {
|
||||
Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
|
||||
}
|
||||
}
|
||||
|
||||
fn write_file(path: &Path, data: &[u8]) {
|
||||
let mut vf = t!(fs::File::create(path));
|
||||
t!(vf.write_all(data));
|
||||
}
|
||||
|
||||
@ -28,11 +28,10 @@ extern crate rustc_serialize;
|
||||
extern crate toml;
|
||||
extern crate regex;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::path::{Component, PathBuf, Path};
|
||||
use std::process::Command;
|
||||
|
||||
use build_helper::{run_silent, output};
|
||||
@ -46,7 +45,7 @@ use util::{exe, mtime, libdir, add_lib_path};
|
||||
/// * The error itself
|
||||
///
|
||||
/// This is currently used judiciously throughout the build system rather than
|
||||
/// using a `Result` with `try!`, but this may change on day...
|
||||
/// using a `Result` with `try!`, but this may change one day...
|
||||
macro_rules! t {
|
||||
($e:expr) => (match $e {
|
||||
Ok(e) => e,
|
||||
@ -131,7 +130,6 @@ pub struct Build {
|
||||
// Runtime state filled in later on
|
||||
cc: HashMap<String, (gcc::Tool, Option<PathBuf>)>,
|
||||
cxx: HashMap<String, gcc::Tool>,
|
||||
compiler_rt_built: RefCell<HashMap<String, PathBuf>>,
|
||||
}
|
||||
|
||||
/// The various "modes" of invoking Cargo.
|
||||
@ -198,7 +196,6 @@ impl Build {
|
||||
package_vers: String::new(),
|
||||
cc: HashMap::new(),
|
||||
cxx: HashMap::new(),
|
||||
compiler_rt_built: RefCell::new(HashMap::new()),
|
||||
gdb_version: None,
|
||||
lldb_version: None,
|
||||
lldb_python_dir: None,
|
||||
@ -246,15 +243,19 @@ impl Build {
|
||||
// Almost all of these are simple one-liners that shell out to the
|
||||
// corresponding functionality in the extra modules, where more
|
||||
// documentation can be found.
|
||||
for target in step::all(self) {
|
||||
let steps = step::all(self);
|
||||
|
||||
self.verbose("bootstrap build plan:");
|
||||
for step in &steps {
|
||||
self.verbose(&format!("{:?}", step));
|
||||
}
|
||||
|
||||
for target in steps {
|
||||
let doc_out = self.out.join(&target.target).join("doc");
|
||||
match target.src {
|
||||
Llvm { _dummy } => {
|
||||
native::llvm(self, target.target);
|
||||
}
|
||||
CompilerRt { _dummy } => {
|
||||
native::compiler_rt(self, target.target);
|
||||
}
|
||||
TestHelpers { _dummy } => {
|
||||
native::test_helpers(self, target.target);
|
||||
}
|
||||
@ -308,10 +309,6 @@ impl Build {
|
||||
doc::rustbook(self, stage, target.target, "nomicon",
|
||||
&doc_out);
|
||||
}
|
||||
DocStyle { stage } => {
|
||||
doc::rustbook(self, stage, target.target, "style",
|
||||
&doc_out);
|
||||
}
|
||||
DocStandalone { stage } => {
|
||||
doc::standalone(self, stage, target.target, &doc_out);
|
||||
}
|
||||
@ -394,8 +391,10 @@ impl Build {
|
||||
"mir-opt", "mir-opt");
|
||||
}
|
||||
CheckCodegen { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"codegen", "codegen");
|
||||
if self.config.codegen_tests {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"codegen", "codegen");
|
||||
}
|
||||
}
|
||||
CheckCodegenUnits { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
@ -479,12 +478,32 @@ impl Build {
|
||||
/// This will detect if any submodules are out of date an run the necessary
|
||||
/// commands to sync them all with upstream.
|
||||
fn update_submodules(&self) {
|
||||
struct Submodule<'a> {
|
||||
path: &'a Path,
|
||||
state: State,
|
||||
}
|
||||
|
||||
enum State {
|
||||
// The submodule may have staged/unstaged changes
|
||||
MaybeDirty,
|
||||
// Or could be initialized but never updated
|
||||
NotInitialized,
|
||||
// The submodule, itself, has extra commits but those changes haven't been commited to
|
||||
// the (outer) git repository
|
||||
OutOfSync,
|
||||
}
|
||||
|
||||
if !self.config.submodules {
|
||||
return
|
||||
}
|
||||
if fs::metadata(self.src.join(".git")).is_err() {
|
||||
return
|
||||
}
|
||||
let git = || {
|
||||
let mut cmd = Command::new("git");
|
||||
cmd.current_dir(&self.src);
|
||||
return cmd
|
||||
};
|
||||
let git_submodule = || {
|
||||
let mut cmd = Command::new("git");
|
||||
cmd.current_dir(&self.src).arg("submodule");
|
||||
@ -496,19 +515,67 @@ impl Build {
|
||||
// of detecting whether we need to run all the submodule commands
|
||||
// below.
|
||||
let out = output(git_submodule().arg("status"));
|
||||
if !out.lines().any(|l| l.starts_with("+") || l.starts_with("-")) {
|
||||
return
|
||||
let mut submodules = vec![];
|
||||
for line in out.lines() {
|
||||
// NOTE `git submodule status` output looks like this:
|
||||
//
|
||||
// -5066b7dcab7e700844b0e2ba71b8af9dc627a59b src/liblibc
|
||||
// +b37ef24aa82d2be3a3cc0fe89bf82292f4ca181c src/compiler-rt (remotes/origin/..)
|
||||
// e058ca661692a8d01f8cf9d35939dfe3105ce968 src/jemalloc (3.6.0-533-ge058ca6)
|
||||
//
|
||||
// The first character can be '-', '+' or ' ' and denotes the `State` of the submodule
|
||||
// Right next to this character is the SHA-1 of the submodule HEAD
|
||||
// And after that comes the path to the submodule
|
||||
let path = Path::new(line[1..].split(' ').skip(1).next().unwrap());
|
||||
let state = if line.starts_with('-') {
|
||||
State::NotInitialized
|
||||
} else if line.starts_with('+') {
|
||||
State::OutOfSync
|
||||
} else if line.starts_with(' ') {
|
||||
State::MaybeDirty
|
||||
} else {
|
||||
panic!("unexpected git submodule state: {:?}", line.chars().next());
|
||||
};
|
||||
|
||||
submodules.push(Submodule { path: path, state: state })
|
||||
}
|
||||
|
||||
self.run(git_submodule().arg("sync"));
|
||||
self.run(git_submodule().arg("init"));
|
||||
self.run(git_submodule().arg("update"));
|
||||
self.run(git_submodule().arg("update").arg("--recursive"));
|
||||
self.run(git_submodule().arg("status").arg("--recursive"));
|
||||
self.run(git_submodule().arg("foreach").arg("--recursive")
|
||||
.arg("git").arg("clean").arg("-fdx"));
|
||||
self.run(git_submodule().arg("foreach").arg("--recursive")
|
||||
.arg("git").arg("checkout").arg("."));
|
||||
|
||||
for submodule in submodules {
|
||||
// If using llvm-root then don't touch the llvm submodule.
|
||||
if submodule.path.components().any(|c| c == Component::Normal("llvm".as_ref())) &&
|
||||
self.config.target_config.get(&self.config.build)
|
||||
.and_then(|c| c.llvm_config.as_ref()).is_some()
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if submodule.path.components().any(|c| c == Component::Normal("jemalloc".as_ref())) &&
|
||||
!self.config.use_jemalloc
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
match submodule.state {
|
||||
State::MaybeDirty => {
|
||||
// drop staged changes
|
||||
self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"]));
|
||||
// drops unstaged changes
|
||||
self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"]));
|
||||
},
|
||||
State::NotInitialized => {
|
||||
self.run(git_submodule().arg("init").arg(submodule.path));
|
||||
self.run(git_submodule().arg("update").arg(submodule.path));
|
||||
},
|
||||
State::OutOfSync => {
|
||||
// drops submodule commits that weren't reported to the (outer) git repository
|
||||
self.run(git_submodule().arg("update").arg(submodule.path));
|
||||
self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"]));
|
||||
self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"]));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear out `dir` if `input` is newer.
|
||||
@ -519,6 +586,8 @@ impl Build {
|
||||
if mtime(&stamp) < mtime(input) {
|
||||
self.verbose(&format!("Dirty - {}", dir.display()));
|
||||
let _ = fs::remove_dir_all(dir);
|
||||
} else if stamp.exists() {
|
||||
return
|
||||
}
|
||||
t!(fs::create_dir_all(dir));
|
||||
t!(File::create(stamp));
|
||||
@ -543,6 +612,10 @@ impl Build {
|
||||
.arg("-j").arg(self.jobs().to_string())
|
||||
.arg("--target").arg(target);
|
||||
|
||||
// FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
|
||||
// Force cargo to output binaries with disambiguating hashes in the name
|
||||
cargo.env("__CARGO_DEFAULT_LIB_METADATA", "1");
|
||||
|
||||
let stage;
|
||||
if compiler.stage == 0 && self.local_rebuild {
|
||||
// Assume the local-rebuild rustc already has stage1 features.
|
||||
@ -574,7 +647,7 @@ impl Build {
|
||||
.env("RUSTDOC_REAL", self.rustdoc(compiler))
|
||||
.env("RUSTC_FLAGS", self.rustc_flags(target).join(" "));
|
||||
|
||||
self.add_bootstrap_key(compiler, &mut cargo);
|
||||
self.add_bootstrap_key(&mut cargo);
|
||||
|
||||
// Specify some various options for build scripts used throughout
|
||||
// the build.
|
||||
@ -769,11 +842,6 @@ impl Build {
|
||||
}
|
||||
}
|
||||
|
||||
/// Root output directory for compiler-rt compiled for `target`
|
||||
fn compiler_rt_out(&self, target: &str) -> PathBuf {
|
||||
self.out.join(target).join("compiler-rt")
|
||||
}
|
||||
|
||||
/// Root output directory for rust_test_helpers library compiled for
|
||||
/// `target`
|
||||
fn test_helpers_out(&self, target: &str) -> PathBuf {
|
||||
@ -794,16 +862,11 @@ impl Build {
|
||||
}
|
||||
|
||||
/// Adds the compiler's bootstrap key to the environment of `cmd`.
|
||||
fn add_bootstrap_key(&self, compiler: &Compiler, cmd: &mut Command) {
|
||||
// In stage0 we're using a previously released stable compiler, so we
|
||||
// use the stage0 bootstrap key. Otherwise we use our own build's
|
||||
// bootstrap key.
|
||||
let bootstrap_key = if compiler.is_snapshot(self) && !self.local_rebuild {
|
||||
&self.bootstrap_key_stage0
|
||||
} else {
|
||||
&self.bootstrap_key
|
||||
};
|
||||
cmd.env("RUSTC_BOOTSTRAP_KEY", bootstrap_key);
|
||||
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", "5c6cf767");
|
||||
}
|
||||
|
||||
/// Returns the compiler's libdir where it stores the dynamic libraries that
|
||||
@ -889,7 +952,11 @@ impl Build {
|
||||
/// Returns the path to the C++ compiler for the target specified, may panic
|
||||
/// if no C++ compiler was configured for the target.
|
||||
fn cxx(&self, target: &str) -> &Path {
|
||||
self.cxx[target].path()
|
||||
match self.cxx.get(target) {
|
||||
Some(p) => p.path(),
|
||||
None => panic!("\n\ntarget `{}` is not configured as a host,
|
||||
only as a target\n\n", target),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns flags to pass to the compiler to generate code for `target`.
|
||||
@ -907,6 +974,13 @@ impl Build {
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
/// Returns the "musl root" for this `target`, if defined
|
||||
fn musl_root(&self, target: &str) -> Option<&Path> {
|
||||
self.config.target_config[target].musl_root.as_ref()
|
||||
.or(self.config.musl_root.as_ref())
|
||||
.map(|p| &**p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Compiler<'a> {
|
||||
|
||||
@ -22,6 +22,10 @@ BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py $(BOOTSTRAP_
|
||||
all:
|
||||
$(Q)$(BOOTSTRAP)
|
||||
|
||||
# Don’t use $(Q) here, always show how to invoke the bootstrap script directly
|
||||
help:
|
||||
$(BOOTSTRAP) --help
|
||||
|
||||
clean:
|
||||
$(Q)$(BOOTSTRAP) --clean
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ use cmake;
|
||||
use gcc;
|
||||
|
||||
use Build;
|
||||
use util::{staticlib, up_to_date};
|
||||
use util::up_to_date;
|
||||
|
||||
/// Compile LLVM for `target`.
|
||||
pub fn llvm(build: &Build, target: &str) {
|
||||
@ -65,7 +65,7 @@ pub fn llvm(build: &Build, target: &str) {
|
||||
.out_dir(&dst)
|
||||
.profile(if build.config.llvm_optimize {"Release"} else {"Debug"})
|
||||
.define("LLVM_ENABLE_ASSERTIONS", assertions)
|
||||
.define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC")
|
||||
.define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ")
|
||||
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
|
||||
.define("LLVM_INCLUDE_TESTS", "OFF")
|
||||
.define("LLVM_INCLUDE_DOCS", "OFF")
|
||||
@ -131,401 +131,6 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) {
|
||||
panic!("\n\nbad LLVM version: {}, need >=3.5\n\n", version)
|
||||
}
|
||||
|
||||
/// Compiles the `compiler-rt` library, or at least the builtins part of it.
|
||||
///
|
||||
/// Note that while compiler-rt has a build system associated with it, we
|
||||
/// specifically don't use it here. The compiler-rt build system, written in
|
||||
/// CMake, is actually *very* difficult to work with in terms of getting it to
|
||||
/// compile on all the relevant platforms we want it to compile on. In the end
|
||||
/// it became so much pain to work with local patches, work around the oddities
|
||||
/// of the build system, etc, that we're just building everything by hand now.
|
||||
///
|
||||
/// In general compiler-rt is just a bunch of intrinsics that are in practice
|
||||
/// *very* stable. We just need to make sure that all the relevant functions and
|
||||
/// such are compiled somewhere and placed in an object file somewhere.
|
||||
/// Eventually, these should all be written in Rust!
|
||||
///
|
||||
/// So below you'll find a listing of every single file in the compiler-rt repo
|
||||
/// that we're compiling. We just reach in and compile with the `gcc` crate
|
||||
/// which should have all the relevant flags and such already configured.
|
||||
///
|
||||
/// The risk here is that if we update compiler-rt we may need to compile some
|
||||
/// new intrinsics, but to be honest we surely don't use all of the intrinsics
|
||||
/// listed below today so the likelihood of us actually needing a new intrinsic
|
||||
/// is quite low. The failure case is also just that someone reports a link
|
||||
/// error (if any) and then we just add it to the list. Overall, that cost is
|
||||
/// far far less than working with compiler-rt's build system over time.
|
||||
pub fn compiler_rt(build: &Build, target: &str) {
|
||||
let build_dir = build.compiler_rt_out(target);
|
||||
let output = build_dir.join(staticlib("compiler-rt", target));
|
||||
build.compiler_rt_built.borrow_mut().insert(target.to_string(),
|
||||
output.clone());
|
||||
t!(fs::create_dir_all(&build_dir));
|
||||
|
||||
let mut cfg = gcc::Config::new();
|
||||
cfg.cargo_metadata(false)
|
||||
.out_dir(&build_dir)
|
||||
.target(target)
|
||||
.host(&build.config.build)
|
||||
.opt_level(2)
|
||||
.debug(false);
|
||||
|
||||
if target.contains("msvc") {
|
||||
// Don't pull in extra libraries on MSVC
|
||||
cfg.flag("/Zl");
|
||||
|
||||
// Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP
|
||||
cfg.define("__func__", Some("__FUNCTION__"));
|
||||
} else {
|
||||
// Turn off various features of gcc and such, mostly copying
|
||||
// compiler-rt's build system already
|
||||
cfg.flag("-fno-builtin");
|
||||
cfg.flag("-fvisibility=hidden");
|
||||
cfg.flag("-fomit-frame-pointer");
|
||||
cfg.flag("-ffreestanding");
|
||||
}
|
||||
|
||||
let mut sources = vec![
|
||||
"absvdi2.c",
|
||||
"absvsi2.c",
|
||||
"adddf3.c",
|
||||
"addsf3.c",
|
||||
"addvdi3.c",
|
||||
"addvsi3.c",
|
||||
"apple_versioning.c",
|
||||
"ashldi3.c",
|
||||
"ashrdi3.c",
|
||||
"clear_cache.c",
|
||||
"clzdi2.c",
|
||||
"clzsi2.c",
|
||||
"cmpdi2.c",
|
||||
"comparedf2.c",
|
||||
"comparesf2.c",
|
||||
"ctzdi2.c",
|
||||
"ctzsi2.c",
|
||||
"divdc3.c",
|
||||
"divdf3.c",
|
||||
"divdi3.c",
|
||||
"divmoddi4.c",
|
||||
"divmodsi4.c",
|
||||
"divsc3.c",
|
||||
"divsf3.c",
|
||||
"divsi3.c",
|
||||
"divxc3.c",
|
||||
"extendsfdf2.c",
|
||||
"extendhfsf2.c",
|
||||
"ffsdi2.c",
|
||||
"fixdfdi.c",
|
||||
"fixdfsi.c",
|
||||
"fixsfdi.c",
|
||||
"fixsfsi.c",
|
||||
"fixunsdfdi.c",
|
||||
"fixunsdfsi.c",
|
||||
"fixunssfdi.c",
|
||||
"fixunssfsi.c",
|
||||
"fixunsxfdi.c",
|
||||
"fixunsxfsi.c",
|
||||
"fixxfdi.c",
|
||||
"floatdidf.c",
|
||||
"floatdisf.c",
|
||||
"floatdixf.c",
|
||||
"floatsidf.c",
|
||||
"floatsisf.c",
|
||||
"floatundidf.c",
|
||||
"floatundisf.c",
|
||||
"floatundixf.c",
|
||||
"floatunsidf.c",
|
||||
"floatunsisf.c",
|
||||
"int_util.c",
|
||||
"lshrdi3.c",
|
||||
"moddi3.c",
|
||||
"modsi3.c",
|
||||
"muldc3.c",
|
||||
"muldf3.c",
|
||||
"muldi3.c",
|
||||
"mulodi4.c",
|
||||
"mulosi4.c",
|
||||
"muloti4.c",
|
||||
"mulsc3.c",
|
||||
"mulsf3.c",
|
||||
"mulvdi3.c",
|
||||
"mulvsi3.c",
|
||||
"mulxc3.c",
|
||||
"negdf2.c",
|
||||
"negdi2.c",
|
||||
"negsf2.c",
|
||||
"negvdi2.c",
|
||||
"negvsi2.c",
|
||||
"paritydi2.c",
|
||||
"paritysi2.c",
|
||||
"popcountdi2.c",
|
||||
"popcountsi2.c",
|
||||
"powidf2.c",
|
||||
"powisf2.c",
|
||||
"powixf2.c",
|
||||
"subdf3.c",
|
||||
"subsf3.c",
|
||||
"subvdi3.c",
|
||||
"subvsi3.c",
|
||||
"truncdfhf2.c",
|
||||
"truncdfsf2.c",
|
||||
"truncsfhf2.c",
|
||||
"ucmpdi2.c",
|
||||
"udivdi3.c",
|
||||
"udivmoddi4.c",
|
||||
"udivmodsi4.c",
|
||||
"udivsi3.c",
|
||||
"umoddi3.c",
|
||||
"umodsi3.c",
|
||||
];
|
||||
|
||||
if !target.contains("ios") {
|
||||
sources.extend(vec![
|
||||
"absvti2.c",
|
||||
"addtf3.c",
|
||||
"addvti3.c",
|
||||
"ashlti3.c",
|
||||
"ashrti3.c",
|
||||
"clzti2.c",
|
||||
"cmpti2.c",
|
||||
"ctzti2.c",
|
||||
"divtf3.c",
|
||||
"divti3.c",
|
||||
"ffsti2.c",
|
||||
"fixdfti.c",
|
||||
"fixsfti.c",
|
||||
"fixunsdfti.c",
|
||||
"fixunssfti.c",
|
||||
"fixunsxfti.c",
|
||||
"fixxfti.c",
|
||||
"floattidf.c",
|
||||
"floattisf.c",
|
||||
"floattixf.c",
|
||||
"floatuntidf.c",
|
||||
"floatuntisf.c",
|
||||
"floatuntixf.c",
|
||||
"lshrti3.c",
|
||||
"modti3.c",
|
||||
"multf3.c",
|
||||
"multi3.c",
|
||||
"mulvti3.c",
|
||||
"negti2.c",
|
||||
"negvti2.c",
|
||||
"parityti2.c",
|
||||
"popcountti2.c",
|
||||
"powitf2.c",
|
||||
"subtf3.c",
|
||||
"subvti3.c",
|
||||
"trampoline_setup.c",
|
||||
"ucmpti2.c",
|
||||
"udivmodti4.c",
|
||||
"udivti3.c",
|
||||
"umodti3.c",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("apple") {
|
||||
sources.extend(vec![
|
||||
"atomic_flag_clear.c",
|
||||
"atomic_flag_clear_explicit.c",
|
||||
"atomic_flag_test_and_set.c",
|
||||
"atomic_flag_test_and_set_explicit.c",
|
||||
"atomic_signal_fence.c",
|
||||
"atomic_thread_fence.c",
|
||||
]);
|
||||
}
|
||||
|
||||
if !target.contains("windows") {
|
||||
sources.push("emutls.c");
|
||||
}
|
||||
|
||||
if target.contains("msvc") {
|
||||
if target.contains("x86_64") {
|
||||
sources.extend(vec![
|
||||
"x86_64/floatdidf.c",
|
||||
"x86_64/floatdisf.c",
|
||||
"x86_64/floatdixf.c",
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
if !target.contains("freebsd") {
|
||||
sources.push("gcc_personality_v0.c");
|
||||
}
|
||||
|
||||
if target.contains("x86_64") {
|
||||
sources.extend(vec![
|
||||
"x86_64/chkstk.S",
|
||||
"x86_64/chkstk2.S",
|
||||
"x86_64/floatdidf.c",
|
||||
"x86_64/floatdisf.c",
|
||||
"x86_64/floatdixf.c",
|
||||
"x86_64/floatundidf.S",
|
||||
"x86_64/floatundisf.S",
|
||||
"x86_64/floatundixf.S",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("i386") ||
|
||||
target.contains("i586") ||
|
||||
target.contains("i686") {
|
||||
sources.extend(vec![
|
||||
"i386/ashldi3.S",
|
||||
"i386/ashrdi3.S",
|
||||
"i386/chkstk.S",
|
||||
"i386/chkstk2.S",
|
||||
"i386/divdi3.S",
|
||||
"i386/floatdidf.S",
|
||||
"i386/floatdisf.S",
|
||||
"i386/floatdixf.S",
|
||||
"i386/floatundidf.S",
|
||||
"i386/floatundisf.S",
|
||||
"i386/floatundixf.S",
|
||||
"i386/lshrdi3.S",
|
||||
"i386/moddi3.S",
|
||||
"i386/muldi3.S",
|
||||
"i386/udivdi3.S",
|
||||
"i386/umoddi3.S",
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if target.contains("arm") && !target.contains("ios") {
|
||||
sources.extend(vec![
|
||||
"arm/aeabi_cdcmp.S",
|
||||
"arm/aeabi_cdcmpeq_check_nan.c",
|
||||
"arm/aeabi_cfcmp.S",
|
||||
"arm/aeabi_cfcmpeq_check_nan.c",
|
||||
"arm/aeabi_dcmp.S",
|
||||
"arm/aeabi_div0.c",
|
||||
"arm/aeabi_drsub.c",
|
||||
"arm/aeabi_fcmp.S",
|
||||
"arm/aeabi_frsub.c",
|
||||
"arm/aeabi_idivmod.S",
|
||||
"arm/aeabi_ldivmod.S",
|
||||
"arm/aeabi_memcmp.S",
|
||||
"arm/aeabi_memcpy.S",
|
||||
"arm/aeabi_memmove.S",
|
||||
"arm/aeabi_memset.S",
|
||||
"arm/aeabi_uidivmod.S",
|
||||
"arm/aeabi_uldivmod.S",
|
||||
"arm/bswapdi2.S",
|
||||
"arm/bswapsi2.S",
|
||||
"arm/clzdi2.S",
|
||||
"arm/clzsi2.S",
|
||||
"arm/comparesf2.S",
|
||||
"arm/divmodsi4.S",
|
||||
"arm/divsi3.S",
|
||||
"arm/modsi3.S",
|
||||
"arm/switch16.S",
|
||||
"arm/switch32.S",
|
||||
"arm/switch8.S",
|
||||
"arm/switchu8.S",
|
||||
"arm/sync_synchronize.S",
|
||||
"arm/udivmodsi4.S",
|
||||
"arm/udivsi3.S",
|
||||
"arm/umodsi3.S",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("armv7") {
|
||||
sources.extend(vec![
|
||||
"arm/sync_fetch_and_add_4.S",
|
||||
"arm/sync_fetch_and_add_8.S",
|
||||
"arm/sync_fetch_and_and_4.S",
|
||||
"arm/sync_fetch_and_and_8.S",
|
||||
"arm/sync_fetch_and_max_4.S",
|
||||
"arm/sync_fetch_and_max_8.S",
|
||||
"arm/sync_fetch_and_min_4.S",
|
||||
"arm/sync_fetch_and_min_8.S",
|
||||
"arm/sync_fetch_and_nand_4.S",
|
||||
"arm/sync_fetch_and_nand_8.S",
|
||||
"arm/sync_fetch_and_or_4.S",
|
||||
"arm/sync_fetch_and_or_8.S",
|
||||
"arm/sync_fetch_and_sub_4.S",
|
||||
"arm/sync_fetch_and_sub_8.S",
|
||||
"arm/sync_fetch_and_umax_4.S",
|
||||
"arm/sync_fetch_and_umax_8.S",
|
||||
"arm/sync_fetch_and_umin_4.S",
|
||||
"arm/sync_fetch_and_umin_8.S",
|
||||
"arm/sync_fetch_and_xor_4.S",
|
||||
"arm/sync_fetch_and_xor_8.S",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("eabihf") {
|
||||
sources.extend(vec![
|
||||
"arm/adddf3vfp.S",
|
||||
"arm/addsf3vfp.S",
|
||||
"arm/divdf3vfp.S",
|
||||
"arm/divsf3vfp.S",
|
||||
"arm/eqdf2vfp.S",
|
||||
"arm/eqsf2vfp.S",
|
||||
"arm/extendsfdf2vfp.S",
|
||||
"arm/fixdfsivfp.S",
|
||||
"arm/fixsfsivfp.S",
|
||||
"arm/fixunsdfsivfp.S",
|
||||
"arm/fixunssfsivfp.S",
|
||||
"arm/floatsidfvfp.S",
|
||||
"arm/floatsisfvfp.S",
|
||||
"arm/floatunssidfvfp.S",
|
||||
"arm/floatunssisfvfp.S",
|
||||
"arm/gedf2vfp.S",
|
||||
"arm/gesf2vfp.S",
|
||||
"arm/gtdf2vfp.S",
|
||||
"arm/gtsf2vfp.S",
|
||||
"arm/ledf2vfp.S",
|
||||
"arm/lesf2vfp.S",
|
||||
"arm/ltdf2vfp.S",
|
||||
"arm/ltsf2vfp.S",
|
||||
"arm/muldf3vfp.S",
|
||||
"arm/mulsf3vfp.S",
|
||||
"arm/negdf2vfp.S",
|
||||
"arm/negsf2vfp.S",
|
||||
"arm/nedf2vfp.S",
|
||||
"arm/nesf2vfp.S",
|
||||
"arm/restore_vfp_d8_d15_regs.S",
|
||||
"arm/save_vfp_d8_d15_regs.S",
|
||||
"arm/subdf3vfp.S",
|
||||
"arm/subsf3vfp.S",
|
||||
"arm/truncdfsf2vfp.S",
|
||||
"arm/unorddf2vfp.S",
|
||||
"arm/unordsf2vfp.S",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("aarch64") {
|
||||
sources.extend(vec![
|
||||
"comparetf2.c",
|
||||
"extenddftf2.c",
|
||||
"extendsftf2.c",
|
||||
"fixtfdi.c",
|
||||
"fixtfsi.c",
|
||||
"fixtfti.c",
|
||||
"fixunstfdi.c",
|
||||
"fixunstfsi.c",
|
||||
"fixunstfti.c",
|
||||
"floatditf.c",
|
||||
"floatsitf.c",
|
||||
"floatunditf.c",
|
||||
"floatunsitf.c",
|
||||
"multc3.c",
|
||||
"trunctfdf2.c",
|
||||
"trunctfsf2.c",
|
||||
]);
|
||||
}
|
||||
|
||||
let mut out_of_date = false;
|
||||
for src in sources {
|
||||
let src = build.src.join("src/compiler-rt/lib/builtins").join(src);
|
||||
out_of_date = out_of_date || !up_to_date(&src, &output);
|
||||
cfg.file(src);
|
||||
}
|
||||
if !out_of_date {
|
||||
return
|
||||
}
|
||||
cfg.compile("libcompiler-rt.a");
|
||||
}
|
||||
|
||||
/// Compiles the `rust_test_helpers.c` library which we used in various
|
||||
/// `run-pass` test suites for ABI testing.
|
||||
pub fn test_helpers(build: &Build, target: &str) {
|
||||
|
||||
@ -75,6 +75,12 @@ pub fn check(build: &mut Build) {
|
||||
|
||||
need_cmd("python".as_ref());
|
||||
|
||||
// If a manual nodejs was added to the config,
|
||||
// of if a nodejs install is detected through config, use it.
|
||||
if let Some(ref s) = build.config.nodejs {
|
||||
need_cmd(s.as_ref());
|
||||
}
|
||||
|
||||
// We're gonna build some custom C code here and there, host triples
|
||||
// also build some C++ shims for LLVM so we need a C++ compiler.
|
||||
for target in build.config.target.iter() {
|
||||
@ -89,7 +95,7 @@ pub fn check(build: &mut Build) {
|
||||
|
||||
// Externally configured LLVM requires FileCheck to exist
|
||||
let filecheck = build.llvm_filecheck(&build.config.build);
|
||||
if !filecheck.starts_with(&build.out) && !filecheck.exists() {
|
||||
if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
|
||||
panic!("filecheck executable {:?} does not exist", filecheck);
|
||||
}
|
||||
|
||||
@ -111,8 +117,8 @@ pub fn check(build: &mut Build) {
|
||||
|
||||
// Make sure musl-root is valid if specified
|
||||
if target.contains("musl") && !target.contains("mips") {
|
||||
match build.config.musl_root {
|
||||
Some(ref root) => {
|
||||
match build.musl_root(target) {
|
||||
Some(root) => {
|
||||
if fs::metadata(root.join("lib/libc.a")).is_err() {
|
||||
panic!("couldn't find libc.a in musl dir: {}",
|
||||
root.join("lib").display());
|
||||
@ -123,8 +129,9 @@ pub fn check(build: &mut Build) {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
panic!("when targeting MUSL the build.musl-root option \
|
||||
must be specified in config.toml")
|
||||
panic!("when targeting MUSL either the build.musl-root \
|
||||
option or the target.$TARGET.musl-root one must \
|
||||
be specified in config.toml")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +82,6 @@ macro_rules! targets {
|
||||
// There aren't really any parameters to this, but empty structs
|
||||
// with braces are unstable so we just pick something that works.
|
||||
(llvm, Llvm { _dummy: () }),
|
||||
(compiler_rt, CompilerRt { _dummy: () }),
|
||||
(test_helpers, TestHelpers { _dummy: () }),
|
||||
(debugger_scripts, DebuggerScripts { stage: u32 }),
|
||||
|
||||
@ -92,7 +91,6 @@ macro_rules! targets {
|
||||
(doc, Doc { stage: u32 }),
|
||||
(doc_book, DocBook { stage: u32 }),
|
||||
(doc_nomicon, DocNomicon { stage: u32 }),
|
||||
(doc_style, DocStyle { stage: u32 }),
|
||||
(doc_standalone, DocStandalone { stage: u32 }),
|
||||
(doc_std, DocStd { stage: u32 }),
|
||||
(doc_test, DocTest { stage: u32 }),
|
||||
@ -173,6 +171,8 @@ targets!(define_source);
|
||||
/// into a topologically sorted list which when executed left-to-right will
|
||||
/// correctly sequence the entire build.
|
||||
pub fn all(build: &Build) -> Vec<Step> {
|
||||
build.verbose("inferred build steps:");
|
||||
|
||||
let mut ret = Vec::new();
|
||||
let mut all = HashSet::new();
|
||||
for target in top_level(build) {
|
||||
@ -186,6 +186,7 @@ pub fn all(build: &Build) -> Vec<Step> {
|
||||
set: &mut HashSet<Step<'a>>) {
|
||||
if set.insert(target.clone()) {
|
||||
for dep in target.deps(build) {
|
||||
build.verbose(&format!("{:?}\n -> {:?}", target, dep));
|
||||
fill(build, &dep, ret, set);
|
||||
}
|
||||
ret.push(target.clone());
|
||||
@ -335,8 +336,7 @@ impl<'a> Step<'a> {
|
||||
vec![self.libstd(compiler)]
|
||||
}
|
||||
Source::Libstd { compiler } => {
|
||||
vec![self.compiler_rt(()),
|
||||
self.rustc(compiler.stage).target(compiler.host)]
|
||||
vec![self.rustc(compiler.stage).target(compiler.host)]
|
||||
}
|
||||
Source::LibrustcLink { compiler, host } => {
|
||||
vec![self.librustc(compiler),
|
||||
@ -349,7 +349,6 @@ impl<'a> Step<'a> {
|
||||
vec![self.libstd(compiler),
|
||||
self.target(host).rustc(compiler.stage)]
|
||||
}
|
||||
Source::CompilerRt { _dummy } => Vec::new(),
|
||||
Source::Llvm { _dummy } => Vec::new(),
|
||||
Source::TestHelpers { _dummy } => Vec::new(),
|
||||
Source::DebuggerScripts { stage: _ } => Vec::new(),
|
||||
@ -366,8 +365,7 @@ impl<'a> Step<'a> {
|
||||
vec![self.libtest(compiler)]
|
||||
}
|
||||
Source::DocBook { stage } |
|
||||
Source::DocNomicon { stage } |
|
||||
Source::DocStyle { stage } => {
|
||||
Source::DocNomicon { stage } => {
|
||||
vec![self.target(&build.config.build).tool_rustbook(stage)]
|
||||
}
|
||||
Source::DocErrorIndex { stage } => {
|
||||
@ -382,8 +380,7 @@ impl<'a> Step<'a> {
|
||||
Source::Doc { stage } => {
|
||||
let mut deps = vec![
|
||||
self.doc_book(stage), self.doc_nomicon(stage),
|
||||
self.doc_style(stage), self.doc_standalone(stage),
|
||||
self.doc_std(stage),
|
||||
self.doc_standalone(stage), self.doc_std(stage),
|
||||
self.doc_error_index(stage),
|
||||
];
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ use filetime::FileTime;
|
||||
|
||||
/// Returns the `name` as the filename of a static library for `target`.
|
||||
pub fn staticlib(name: &str, target: &str) -> String {
|
||||
if target.contains("windows-msvc") {
|
||||
if target.contains("windows") {
|
||||
format!("{}.lib", name)
|
||||
} else {
|
||||
format!("lib{}.a", name)
|
||||
|
||||
@ -24,27 +24,26 @@ COMPILER_RT_ABI fp_t
|
||||
__floatsidf(int a) {
|
||||
|
||||
const int aWidth = sizeof a * CHAR_BIT;
|
||||
|
||||
|
||||
// Handle zero as a special case to protect clz
|
||||
if (a == 0)
|
||||
return fromRep(0);
|
||||
|
||||
// All other cases begin by extracting the sign and absolute value of a
|
||||
rep_t sign = 0;
|
||||
unsigned aAbs = (unsigned)a;
|
||||
if (a < 0) {
|
||||
sign = signBit;
|
||||
a = -a;
|
||||
aAbs = ~(unsigned)a + 1U;
|
||||
}
|
||||
|
||||
// Exponent of (fp_t)a is the width of abs(a).
|
||||
const int exponent = (aWidth - 1) - __builtin_clz(a);
|
||||
const int exponent = (aWidth - 1) - __builtin_clz(aAbs);
|
||||
rep_t result;
|
||||
|
||||
// Shift a into the significand field and clear the implicit bit. Extra
|
||||
// cast to unsigned int is necessary to get the correct behavior for
|
||||
// the input INT_MIN.
|
||||
// Shift a into the significand field and clear the implicit bit.
|
||||
const int shift = significandBits - exponent;
|
||||
result = (rep_t)(unsigned int)a << shift ^ implicitBit;
|
||||
result = (rep_t)aAbs << shift ^ implicitBit;
|
||||
|
||||
// Insert the exponent
|
||||
result += (rep_t)(exponent + exponentBias) << significandBits;
|
||||
|
||||
@ -24,30 +24,31 @@ COMPILER_RT_ABI fp_t
|
||||
__floatsisf(int a) {
|
||||
|
||||
const int aWidth = sizeof a * CHAR_BIT;
|
||||
|
||||
|
||||
// Handle zero as a special case to protect clz
|
||||
if (a == 0)
|
||||
return fromRep(0);
|
||||
|
||||
// All other cases begin by extracting the sign and absolute value of a
|
||||
rep_t sign = 0;
|
||||
unsigned aAbs = (unsigned)a;
|
||||
if (a < 0) {
|
||||
sign = signBit;
|
||||
a = -a;
|
||||
aAbs = ~(unsigned)a + 1U;
|
||||
}
|
||||
|
||||
// Exponent of (fp_t)a is the width of abs(a).
|
||||
const int exponent = (aWidth - 1) - __builtin_clz(a);
|
||||
const int exponent = (aWidth - 1) - __builtin_clz(aAbs);
|
||||
rep_t result;
|
||||
|
||||
// Shift a into the significand field, rounding if it is a right-shift
|
||||
if (exponent <= significandBits) {
|
||||
const int shift = significandBits - exponent;
|
||||
result = (rep_t)a << shift ^ implicitBit;
|
||||
result = (rep_t)aAbs << shift ^ implicitBit;
|
||||
} else {
|
||||
const int shift = exponent - significandBits;
|
||||
result = (rep_t)a >> shift ^ implicitBit;
|
||||
rep_t round = (rep_t)a << (typeWidth - shift);
|
||||
result = (rep_t)aAbs >> shift ^ implicitBit;
|
||||
rep_t round = (rep_t)aAbs << (typeWidth - shift);
|
||||
if (round > signBit) result++;
|
||||
if (round == signBit) result += result & 1;
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
#if __ARM_EABI__
|
||||
# define ARM_EABI_FNALIAS(aeabi_name, name) \
|
||||
void __aeabi_##aeabi_name() __attribute__((alias("__" #name)));
|
||||
# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
|
||||
# define COMPILER_RT_ABI
|
||||
#else
|
||||
# define ARM_EABI_FNALIAS(aeabi_name, name)
|
||||
# define COMPILER_RT_ABI
|
||||
|
||||
@ -67,7 +67,7 @@ trait Graph {
|
||||
Simple enough. Associated types use the `type` keyword, and go inside the body
|
||||
of the trait, with the functions.
|
||||
|
||||
These `type` declarations can have all the same thing as functions do. For example,
|
||||
These type declarations work the same way as those for functions. For example,
|
||||
if we wanted our `N` type to implement `Display`, so we can print the nodes out,
|
||||
we could do this:
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ different. Here’s a quick refresher on what these two traits mean.
|
||||
|
||||
# Borrow
|
||||
|
||||
The `Borrow` trait is used when you’re writing a datastructure, and you want to
|
||||
The `Borrow` trait is used when you’re writing a data structure, and you want to
|
||||
use either an owned or borrowed type as synonymous for some purpose.
|
||||
|
||||
For example, [`HashMap`][hashmap] has a [`get` method][get] which uses `Borrow`:
|
||||
@ -86,7 +86,7 @@ We can see how they’re kind of the same: they both deal with owned and borrowe
|
||||
versions of some type. However, they’re a bit different.
|
||||
|
||||
Choose `Borrow` when you want to abstract over different kinds of borrowing, or
|
||||
when you’re building a datastructure that treats owned and borrowed values in
|
||||
when you’re building a data structure that treats owned and borrowed values in
|
||||
equivalent ways, such as hashing and comparison.
|
||||
|
||||
Choose `AsRef` when you want to convert something to a reference directly, and
|
||||
|
||||
@ -262,7 +262,7 @@ the result:
|
||||
|
||||
```rust
|
||||
fn call_with_one<F>(some_closure: F) -> i32
|
||||
where F : Fn(i32) -> i32 {
|
||||
where F: Fn(i32) -> i32 {
|
||||
|
||||
some_closure(1)
|
||||
}
|
||||
@ -279,7 +279,7 @@ Let’s examine the signature of `call_with_one` in more depth:
|
||||
|
||||
```rust
|
||||
fn call_with_one<F>(some_closure: F) -> i32
|
||||
# where F : Fn(i32) -> i32 {
|
||||
# where F: Fn(i32) -> i32 {
|
||||
# some_closure(1) }
|
||||
```
|
||||
|
||||
@ -288,7 +288,7 @@ isn’t interesting. The next part is:
|
||||
|
||||
```rust
|
||||
# fn call_with_one<F>(some_closure: F) -> i32
|
||||
where F : Fn(i32) -> i32 {
|
||||
where F: Fn(i32) -> i32 {
|
||||
# some_closure(1) }
|
||||
```
|
||||
|
||||
@ -340,7 +340,7 @@ fn call_with_ref<'a, F>(some_closure:F) -> i32
|
||||
where F: Fn(&'a i32) -> i32 {
|
||||
```
|
||||
|
||||
However this presents a problem with in our case. When you specify the explicit
|
||||
However this presents a problem in our case. When you specify the explicit
|
||||
lifetime on a function it binds that lifetime to the *entire* scope of the function
|
||||
instead of just the invocation scope of our closure. This means that the borrow checker
|
||||
will see a mutable reference in the same lifetime as our immutable reference and fail
|
||||
|
||||
@ -46,10 +46,10 @@ extern crate rustc;
|
||||
extern crate rustc_plugin;
|
||||
|
||||
use syntax::parse::token;
|
||||
use syntax::ast::TokenTree;
|
||||
use syntax::tokenstream::TokenTree;
|
||||
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
|
||||
use syntax::ext::build::AstBuilder; // trait for expr_usize
|
||||
use syntax_pos::Span;
|
||||
use syntax::ext::quote::rt::Span;
|
||||
use rustc_plugin::Registry;
|
||||
|
||||
fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
|
||||
@ -69,7 +69,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
|
||||
}
|
||||
|
||||
let text = match args[0] {
|
||||
TokenTree::Token(_, token::Ident(s, _)) => s.to_string(),
|
||||
TokenTree::Token(_, token::Ident(s)) => s.to_string(),
|
||||
_ => {
|
||||
cx.span_err(sp, "argument should be a single identifier");
|
||||
return DummyResult::any(sp);
|
||||
|
||||
@ -59,7 +59,7 @@ handling is reducing the amount of explicit case analysis the programmer has to
|
||||
do while keeping code composable.
|
||||
|
||||
Keeping code composable is important, because without that requirement, we
|
||||
could [`panic`](../std/macro.panic!.html) whenever we
|
||||
could [`panic`](../std/macro.panic.html) whenever we
|
||||
come across something unexpected. (`panic` causes the current task to unwind,
|
||||
and in most cases, the entire program aborts.) Here's an example:
|
||||
|
||||
@ -944,7 +944,7 @@ macro_rules! try {
|
||||
}
|
||||
```
|
||||
|
||||
(The [real definition](../std/macro.try!.html) is a bit more
|
||||
(The [real definition](../std/macro.try.html) is a bit more
|
||||
sophisticated. We will address that later.)
|
||||
|
||||
Using the `try!` macro makes it very easy to simplify our last example. Since
|
||||
@ -1271,7 +1271,7 @@ macro_rules! try {
|
||||
```
|
||||
|
||||
This is not its real definition. Its real definition is
|
||||
[in the standard library](../std/macro.try!.html):
|
||||
[in the standard library](../std/macro.try.html):
|
||||
|
||||
<span id="code-try-def"></span>
|
||||
|
||||
@ -2178,7 +2178,7 @@ heuristics!
|
||||
[`From`](../std/convert/trait.From.html)
|
||||
and
|
||||
[`Error`](../std/error/trait.Error.html)
|
||||
impls to make the [`try!`](../std/macro.try!.html)
|
||||
impls to make the [`try!`](../std/macro.try.html)
|
||||
macro more ergonomic.
|
||||
* If you're writing a library and your code can produce errors, define your own
|
||||
error type and implement the
|
||||
|
||||
@ -471,7 +471,7 @@ extern {
|
||||
|
||||
fn main() {
|
||||
println!("You have readline version {} installed.",
|
||||
rl_readline_version as i32);
|
||||
unsafe { rl_readline_version as i32 });
|
||||
}
|
||||
```
|
||||
|
||||
@ -539,6 +539,7 @@ This is currently hidden behind the `abi_vectorcall` gate and is subject to chan
|
||||
* `system`
|
||||
* `C`
|
||||
* `win64`
|
||||
* `sysv64`
|
||||
|
||||
Most of the abis in this list are self-explanatory, but the `system` abi may
|
||||
seem a little odd. This constraint selects whatever the appropriate ABI is for
|
||||
|
||||
@ -230,12 +230,13 @@ $ cd hello_world
|
||||
|
||||
## Writing and Running a Rust Program
|
||||
|
||||
Next, make a new source file and call it *main.rs*. Rust files always end
|
||||
in a *.rs* extension. If you’re using more than one word in your filename, use
|
||||
an underscore to separate them; for example, you'd use *hello_world.rs* rather
|
||||
than *helloworld.rs*.
|
||||
We need to create a source file for our Rust program. Rust files always end
|
||||
in a *.rs* extension. If you are using more than one word in your filename,
|
||||
use an underscore to separate them; for example, you would use
|
||||
*my_program.rs* rather than *myprogram.rs*.
|
||||
|
||||
Now open the *main.rs* file you just created, and type the following code:
|
||||
Now, make a new file and call it *main.rs*. Open the file and type
|
||||
the following code:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
|
||||
@ -57,8 +57,8 @@ fn main(argc: isize, argv: *const *const u8) -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
||||
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
|
||||
#[lang = "eh_personality"] extern fn rust_eh_personality() {}
|
||||
#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { loop {} }
|
||||
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
|
||||
# #[no_mangle] pub extern fn rust_eh_register_frames () {}
|
||||
# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
|
||||
@ -73,8 +73,8 @@ Other features provided by lang items include:
|
||||
`==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all
|
||||
marked with lang items; those specific four are `eq`, `ord`,
|
||||
`deref`, and `add` respectively.
|
||||
- stack unwinding and general failure; the `eh_personality`, `fail`
|
||||
and `fail_bounds_checks` lang items.
|
||||
- stack unwinding and general failure; the `eh_personality`,
|
||||
`eh_unwind_resume`, `fail` and `fail_bounds_checks` lang items.
|
||||
- the traits in `std::marker` used to indicate types of
|
||||
various kinds; lang items `send`, `sync` and `copy`.
|
||||
- the marker types and variance indicators found in
|
||||
|
||||
@ -662,7 +662,7 @@ Here are some common macros you’ll see in Rust code.
|
||||
This macro causes the current thread to panic. You can give it a message
|
||||
to panic with:
|
||||
|
||||
```rust,no_run
|
||||
```rust,should_panic
|
||||
panic!("oh no!");
|
||||
```
|
||||
|
||||
@ -688,7 +688,7 @@ These two macros are used in tests. `assert!` takes a boolean. `assert_eq!`
|
||||
takes two values and checks them for equality. `true` passes, `false` `panic!`s.
|
||||
Like this:
|
||||
|
||||
```rust,no_run
|
||||
```rust,should_panic
|
||||
// A-ok!
|
||||
|
||||
assert!(true);
|
||||
|
||||
@ -54,7 +54,7 @@ binary downloads][install-page].
|
||||
|
||||
Oh, we should also mention the officially supported platforms:
|
||||
|
||||
* Windows (7, 8, Server 2008 R2)
|
||||
* Windows (7+)
|
||||
* Linux (2.6.18 or later, various distributions), x86 and x86-64
|
||||
* OSX 10.7 (Lion) or greater, x86 and x86-64
|
||||
|
||||
|
||||
@ -55,7 +55,13 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
// provided by libstd.
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
pub extern fn eh_personality() {
|
||||
pub extern fn rust_eh_personality() {
|
||||
}
|
||||
|
||||
// This function may be needed based on the compilation target.
|
||||
#[lang = "eh_unwind_resume"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_unwind_resume() {
|
||||
}
|
||||
|
||||
#[lang = "panic_fmt"]
|
||||
@ -87,12 +93,18 @@ pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {
|
||||
0
|
||||
}
|
||||
|
||||
// These functions and traits are used by the compiler, but not
|
||||
// These functions are used by the compiler, but not
|
||||
// for a bare-bones hello world. These are normally
|
||||
// provided by libstd.
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
pub extern fn eh_personality() {
|
||||
pub extern fn rust_eh_personality() {
|
||||
}
|
||||
|
||||
// This function may be needed based on the compilation target.
|
||||
#[lang = "eh_unwind_resume"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_unwind_resume() {
|
||||
}
|
||||
|
||||
#[lang = "panic_fmt"]
|
||||
@ -104,7 +116,7 @@ pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
|
||||
}
|
||||
```
|
||||
|
||||
## More about the langauge items
|
||||
## More about the language items
|
||||
|
||||
The compiler currently makes a few assumptions about symbols which are
|
||||
available in the executable to call. Normally these functions are provided by
|
||||
@ -112,15 +124,20 @@ the standard library, but without it you must define your own. These symbols
|
||||
are called "language items", and they each have an internal name, and then a
|
||||
signature that an implementation must conform to.
|
||||
|
||||
The first of these two functions, `eh_personality`, is used by the failure
|
||||
The first of these functions, `rust_eh_personality`, is used by the failure
|
||||
mechanisms of the compiler. This is often mapped to GCC's personality function
|
||||
(see the [libstd implementation][unwind] for more information), but crates
|
||||
which do not trigger a panic can be assured that this function is never
|
||||
called. Both the language item and the symbol name are `eh_personality`.
|
||||
|
||||
called. The language item's name is `eh_personality`.
|
||||
|
||||
[unwind]: https://github.com/rust-lang/rust/blob/master/src/libpanic_unwind/gcc.rs
|
||||
|
||||
The second function, `panic_fmt`, is also used by the failure mechanisms of the
|
||||
The second function, `rust_begin_panic`, is also used by the failure mechanisms of the
|
||||
compiler. When a panic happens, this controls the message that's displayed on
|
||||
the screen. While the language item's name is `panic_fmt`, the symbol name is
|
||||
`rust_begin_panic`.
|
||||
|
||||
A third function, `rust_eh_unwind_resume`, is also needed if the `custom_unwind_resume`
|
||||
flag is set in the options of the compilation target. It allows customizing the
|
||||
process of resuming unwind at the end of the landing pads. The language item's name
|
||||
is `eh_unwind_resume`.
|
||||
|
||||
@ -57,13 +57,13 @@ of scope at the end of `foo()`, Rust will clean up everything related to the
|
||||
vector, even the heap-allocated memory. This happens deterministically, at the
|
||||
end of the scope.
|
||||
|
||||
We'll cover [vectors] in detail later in this chapter; we only use them
|
||||
We covered [vectors] in the previous chapter; we use them
|
||||
here as an example of a type that allocates space on the heap at runtime. They
|
||||
behave like [arrays], except their size may change by `push()`ing more
|
||||
elements onto them.
|
||||
|
||||
Vectors have a [generic type][generics] `Vec<T>`, so in this example `v` will have type
|
||||
`Vec<i32>`. We'll cover generics in detail later in this chapter.
|
||||
`Vec<i32>`. We'll cover [generics] in detail in a later chapter.
|
||||
|
||||
[arrays]: primitive-types.html#arrays
|
||||
[vectors]: vectors.html
|
||||
|
||||
@ -152,7 +152,7 @@ the thing `y` points at. You’ll notice that `x` had to be marked `mut` as well
|
||||
If it wasn’t, we couldn’t take a mutable borrow to an immutable value.
|
||||
|
||||
You'll also notice we added an asterisk (`*`) in front of `y`, making it `*y`,
|
||||
this is because `y` is a `&mut` reference. You'll need to use astrisks to
|
||||
this is because `y` is a `&mut` reference. You'll need to use asterisks to
|
||||
access the contents of a reference as well.
|
||||
|
||||
Otherwise, `&mut` references are like references. There _is_ a large
|
||||
|
||||
@ -47,6 +47,34 @@ As you can see, the `trait` block looks very similar to the `impl` block,
|
||||
but we don’t define a body, only a type signature. When we `impl` a trait,
|
||||
we use `impl Trait for Item`, rather than only `impl Item`.
|
||||
|
||||
`Self` may be used in a type annotation to refer to an instance of the type
|
||||
implementing this trait passed as a parameter. `Self`, `&Self` or `&mut Self`
|
||||
may be used depending on the level of ownership required.
|
||||
|
||||
```rust
|
||||
struct Circle {
|
||||
x: f64,
|
||||
y: f64,
|
||||
radius: f64,
|
||||
}
|
||||
|
||||
trait HasArea {
|
||||
fn area(&self) -> f64;
|
||||
|
||||
fn is_larger(&self, &Self) -> bool;
|
||||
}
|
||||
|
||||
impl HasArea for Circle {
|
||||
fn area(&self) -> f64 {
|
||||
std::f64::consts::PI * (self.radius * self.radius)
|
||||
}
|
||||
|
||||
fn is_larger(&self, other: &Self) -> bool {
|
||||
self.area() > other.area()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Trait bounds on generic functions
|
||||
|
||||
Traits are useful because they allow a type to make certain promises about its
|
||||
@ -247,7 +275,7 @@ won’t have its methods:
|
||||
[write]: ../std/io/trait.Write.html
|
||||
|
||||
```rust,ignore
|
||||
let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt");
|
||||
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 result = f.write(buf);
|
||||
# result.unwrap(); // ignore the error
|
||||
@ -263,10 +291,10 @@ let result = f.write(buf);
|
||||
|
||||
We need to `use` the `Write` trait first:
|
||||
|
||||
```rust,ignore
|
||||
```rust,no_run
|
||||
use std::io::Write;
|
||||
|
||||
let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt");
|
||||
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
|
||||
|
||||
@ -172,6 +172,11 @@ token : simple_token | ident | literal | symbol | whitespace token ;
|
||||
Each of these keywords has special meaning in its grammar, and all of them are
|
||||
excluded from the `ident` rule.
|
||||
|
||||
Not all of these keywords are used by the language. Some of them were used
|
||||
before Rust 1.0, and were left reserved once their implementations were
|
||||
removed. Some of them were reserved before 1.0 to make space for possible
|
||||
future features.
|
||||
|
||||
### Literals
|
||||
|
||||
```antlr
|
||||
|
||||
@ -52,7 +52,7 @@ let mut data = vec![1, 2, 3];
|
||||
let x = &data[0];
|
||||
|
||||
// OH NO! `push` causes the backing storage of `data` to be reallocated.
|
||||
// Dangling pointer! User after free! Alas!
|
||||
// Dangling pointer! Use after free! Alas!
|
||||
// (this does not compile in Rust)
|
||||
data.push(4);
|
||||
|
||||
|
||||
@ -26,10 +26,6 @@ can therefore be trusted. You can use `unsafe` on a trait implementation
|
||||
to declare that the implementation of that trait has adhered to whatever
|
||||
contracts the trait's documentation requires.
|
||||
|
||||
There is also the `#[unsafe_no_drop_flag]` attribute, which exists for
|
||||
historic reasons and is being phased out. See the section on [drop flags]
|
||||
for details.
|
||||
|
||||
The standard library has a number of unsafe functions, including:
|
||||
|
||||
* `slice::get_unchecked`, which performs unchecked indexing, allowing
|
||||
|
||||
@ -1677,6 +1677,7 @@ There are also some platform-specific ABI strings:
|
||||
* `extern "cdecl"` -- The default for x86\_32 C code.
|
||||
* `extern "stdcall"` -- The default for the Win32 API on x86\_32.
|
||||
* `extern "win64"` -- The default for C code on x86\_64 Windows.
|
||||
* `extern "sysv64"` -- The default for C code on non-Windows x86\_64.
|
||||
* `extern "aapcs"` -- The default for ARM.
|
||||
* `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's
|
||||
`__fastcall` and GCC and clang's `__attribute__((fastcall))`
|
||||
@ -2058,10 +2059,6 @@ macro scope.
|
||||
outside of its dynamic extent), and thus this attribute has the word
|
||||
"unsafe" in its name. To use this, the
|
||||
`unsafe_destructor_blind_to_params` feature gate must be enabled.
|
||||
- `unsafe_no_drop_flag` - on structs, remove the flag that prevents
|
||||
destructors from being run twice. Destructors might be run multiple times on
|
||||
the same object with this attribute. To use this, the `unsafe_no_drop_flag` feature
|
||||
gate must be enabled.
|
||||
- `doc` - Doc comments such as `/// foo` are equivalent to `#[doc = "foo"]`.
|
||||
- `rustc_on_unimplemented` - Write a custom note to be shown along with the error
|
||||
when the trait is found to be unimplemented on a type.
|
||||
@ -2070,6 +2067,9 @@ macro scope.
|
||||
trait of the same name. `{Self}` will be replaced with the type that is supposed
|
||||
to implement the trait but doesn't. To use this, the `on_unimplemented` feature gate
|
||||
must be enabled.
|
||||
- `must_use` - on structs and enums, will warn if a value of this type isn't used or
|
||||
assigned to a variable. You may also include an optional message by using
|
||||
`#[must_use = "message"]` which will be given alongside the warning.
|
||||
|
||||
### Conditional compilation
|
||||
|
||||
@ -2283,7 +2283,7 @@ the `PartialEq` or `Clone` constraints for the appropriate `impl`:
|
||||
#[derive(PartialEq, Clone)]
|
||||
struct Foo<T> {
|
||||
a: i32,
|
||||
b: T
|
||||
b: T,
|
||||
}
|
||||
```
|
||||
|
||||
@ -2441,6 +2441,9 @@ The currently implemented features of the reference compiler are:
|
||||
into a Rust program. This capability, especially the signature for the
|
||||
annotated function, is subject to change.
|
||||
|
||||
* `static_in_const` - Enables lifetime elision with a `'static` default for
|
||||
`const` and `static` item declarations.
|
||||
|
||||
* `thread_local` - The usage of the `#[thread_local]` attribute is experimental
|
||||
and should be seen as unstable. This attribute is used to
|
||||
declare a `static` as being unique per-thread leveraging
|
||||
@ -2454,12 +2457,6 @@ The currently implemented features of the reference compiler are:
|
||||
* `unboxed_closures` - Rust's new closure design, which is currently a work in
|
||||
progress feature with many known bugs.
|
||||
|
||||
* `unsafe_no_drop_flag` - Allows use of the `#[unsafe_no_drop_flag]` attribute,
|
||||
which removes hidden flag added to a type that
|
||||
implements the `Drop` trait. The design for the
|
||||
`Drop` flag is subject to change, and this feature
|
||||
may be removed in the future.
|
||||
|
||||
* `unmarked_api` - Allows use of items within a `#![staged_api]` crate
|
||||
which have not been marked with a stability marker.
|
||||
Such items should not be allowed by the compiler to exist,
|
||||
@ -2475,8 +2472,7 @@ The currently implemented features of the reference compiler are:
|
||||
* - `default_type_parameter_fallback` - Allows type parameter defaults to
|
||||
influence type inference.
|
||||
|
||||
* - `stmt_expr_attributes` - Allows attributes on expressions and
|
||||
non-item statements.
|
||||
* - `stmt_expr_attributes` - Allows attributes on expressions.
|
||||
|
||||
* - `type_ascription` - Allows type ascription expressions `expr: Type`.
|
||||
|
||||
@ -2485,6 +2481,9 @@ The currently implemented features of the reference compiler are:
|
||||
|
||||
* - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns.
|
||||
|
||||
* - `abi_sysv64` - Allows the usage of the system V AMD64 calling convention
|
||||
(e.g. `extern "sysv64" func fn_();`)
|
||||
|
||||
If a feature is promoted to a language feature, then all existing programs will
|
||||
start to receive compilation warnings about `#![feature]` directives which enabled
|
||||
the new feature (because the directive is no longer necessary). However, if a
|
||||
@ -3896,7 +3895,7 @@ Coercion is allowed between the following types:
|
||||
use std::ops::Deref;
|
||||
|
||||
struct CharContainer {
|
||||
value: char
|
||||
value: char,
|
||||
}
|
||||
|
||||
impl Deref for CharContainer {
|
||||
|
||||
@ -159,7 +159,7 @@ em {
|
||||
|
||||
footer {
|
||||
border-top: 1px solid #ddd;
|
||||
font-size: 14.3px;
|
||||
font-size: 14px;
|
||||
font-style: italic;
|
||||
padding-top: 5px;
|
||||
margin-top: 3em;
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
% Style Guidelines
|
||||
|
||||
This document collects the emerging principles, conventions, abstractions, and
|
||||
best practices for writing Rust code.
|
||||
|
||||
Since Rust is evolving at a rapid pace, these guidelines are
|
||||
preliminary. The hope is that writing them down explicitly will help
|
||||
drive discussion, consensus and adoption.
|
||||
|
||||
Whenever feasible, guidelines provide specific examples from Rust's standard
|
||||
libraries.
|
||||
|
||||
### Guideline statuses
|
||||
|
||||
Every guideline has a status:
|
||||
|
||||
* **[FIXME]**: Marks places where there is more work to be done. In
|
||||
some cases, that just means going through the RFC process.
|
||||
|
||||
* **[FIXME #NNNNN]**: Like **[FIXME]**, but links to the issue tracker.
|
||||
|
||||
* **[RFC #NNNN]**: Marks accepted guidelines, linking to the rust-lang
|
||||
RFC establishing them.
|
||||
|
||||
### Guideline stabilization
|
||||
|
||||
One purpose of these guidelines is to reach decisions on a number of
|
||||
cross-cutting API and stylistic choices. Discussion and development of
|
||||
the guidelines will happen primarily on https://internals.rust-lang.org/,
|
||||
using the Guidelines category. Discussion can also occur on the
|
||||
[guidelines issue tracker](https://github.com/rust-lang/rust-guidelines).
|
||||
|
||||
Guidelines that are under development or discussion will be marked with the
|
||||
status **[FIXME]**, with a link to the issue tracker when appropriate.
|
||||
|
||||
Once a concrete guideline is ready to be proposed, it should be filed
|
||||
as an [FIXME: needs RFC](https://github.com/rust-lang/rfcs). If the RFC is
|
||||
accepted, the official guidelines will be updated to match, and will
|
||||
include the tag **[RFC #NNNN]** linking to the RFC document.
|
||||
|
||||
### What's in this document
|
||||
|
||||
This document is broken into four parts:
|
||||
|
||||
* **[Style](style/README.md)** provides a set of rules governing naming conventions,
|
||||
whitespace, and other stylistic issues.
|
||||
|
||||
* **[Guidelines by Rust feature](features/README.md)** places the focus on each of
|
||||
Rust's features, starting from expressions and working the way out toward
|
||||
crates, dispensing guidelines relevant to each.
|
||||
|
||||
* **Topical guidelines and patterns**. The rest of the document proceeds by
|
||||
cross-cutting topic, starting with
|
||||
[Ownership and resources](ownership/README.md).
|
||||
|
||||
* **APIs for a changing Rust**
|
||||
discusses the forward-compatibility hazards, especially those that interact
|
||||
with the pre-1.0 library stabilization process.
|
||||
|
||||
> **[FIXME]** Add cross-references throughout this document to the tutorial,
|
||||
> reference manual, and other guides.
|
||||
|
||||
> **[FIXME]** What are some _non_-goals, _non_-principles, or _anti_-patterns that
|
||||
> we should document?
|
||||
@ -1,50 +0,0 @@
|
||||
# Summary
|
||||
|
||||
* [Style](style/README.md)
|
||||
* [Whitespace](style/whitespace.md)
|
||||
* [Comments](style/comments.md)
|
||||
* [Braces, semicolons, commas](style/braces.md)
|
||||
* [Naming](style/naming/README.md)
|
||||
* [Ownership variants](style/naming/ownership.md)
|
||||
* [Containers/wrappers](style/naming/containers.md)
|
||||
* [Conversions](style/naming/conversions.md)
|
||||
* [Iterators](style/naming/iterators.md)
|
||||
* [Imports](style/imports.md)
|
||||
* [Organization](style/organization.md)
|
||||
* [Guidelines by Rust feature](features/README.md)
|
||||
* [Let binding](features/let.md)
|
||||
* [Pattern matching](features/match.md)
|
||||
* [Loops](features/loops.md)
|
||||
* [Functions and methods](features/functions-and-methods/README.md)
|
||||
* [Input](features/functions-and-methods/input.md)
|
||||
* [Output](features/functions-and-methods/output.md)
|
||||
* [For convenience](features/functions-and-methods/convenience.md)
|
||||
* [Types](features/types/README.md)
|
||||
* [Conversions](features/types/conversions.md)
|
||||
* [The newtype pattern](features/types/newtype.md)
|
||||
* [Traits](features/traits/README.md)
|
||||
* [For generics](features/traits/generics.md)
|
||||
* [For objects](features/traits/objects.md)
|
||||
* [For overloading](features/traits/overloading.md)
|
||||
* [For extensions](features/traits/extensions.md)
|
||||
* [For reuse](features/traits/reuse.md)
|
||||
* [Common traits](features/traits/common.md)
|
||||
* [Modules](features/modules.md)
|
||||
* [Crates](features/crates.md)
|
||||
* [Ownership and resources](ownership/README.md)
|
||||
* [Constructors](ownership/constructors.md)
|
||||
* [Builders](ownership/builders.md)
|
||||
* [Destructors](ownership/destructors.md)
|
||||
* [RAII](ownership/raii.md)
|
||||
* [Cells and smart pointers](ownership/cell-smart.md)
|
||||
* [Errors](errors/README.md)
|
||||
* [Signaling](errors/signaling.md)
|
||||
* [Handling](errors/handling.md)
|
||||
* [Propagation](errors/propagation.md)
|
||||
* [Ergonomics](errors/ergonomics.md)
|
||||
* [Safety and guarantees](safety/README.md)
|
||||
* [Using unsafe](safety/unsafe.md)
|
||||
* [Library guarantees](safety/lib-guarantees.md)
|
||||
* [Testing](testing/README.md)
|
||||
* [Unit testing](testing/unit.md)
|
||||
* [FFI, platform-specific code](platform.md)
|
||||
@ -1,3 +0,0 @@
|
||||
% Errors
|
||||
|
||||
> **[FIXME]** Add some general text here.
|
||||
@ -1,66 +0,0 @@
|
||||
% Ergonomic error handling
|
||||
|
||||
Error propagation with raw `Result`s can require tedious matching and
|
||||
repackaging. This tedium is largely alleviated by the `try!` macro,
|
||||
and can be completely removed (in some cases) by the "`Result`-`impl`"
|
||||
pattern.
|
||||
|
||||
### The `try!` macro
|
||||
|
||||
Prefer
|
||||
|
||||
```rust,ignore
|
||||
use std::io::{File, Open, Write, IoError};
|
||||
|
||||
struct Info {
|
||||
name: String,
|
||||
age: i32,
|
||||
rating: i32
|
||||
}
|
||||
|
||||
fn write_info(info: &Info) -> Result<(), IoError> {
|
||||
let mut file = File::open_mode(&Path::new("my_best_friends.txt"),
|
||||
Open, Write);
|
||||
// Early return on error
|
||||
try!(file.write_line(&format!("name: {}", info.name)));
|
||||
try!(file.write_line(&format!("age: {}", info.age)));
|
||||
try!(file.write_line(&format!("rating: {}", info.rating)));
|
||||
return Ok(());
|
||||
}
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust,ignore
|
||||
use std::io::{File, Open, Write, IoError};
|
||||
|
||||
struct Info {
|
||||
name: String,
|
||||
age: i32,
|
||||
rating: i32
|
||||
}
|
||||
|
||||
fn write_info(info: &Info) -> Result<(), IoError> {
|
||||
let mut file = File::open_mode(&Path::new("my_best_friends.txt"),
|
||||
Open, Write);
|
||||
// Early return on error
|
||||
match file.write_line(&format!("name: {}", info.name)) {
|
||||
Ok(_) => (),
|
||||
Err(e) => return Err(e)
|
||||
}
|
||||
match file.write_line(&format!("age: {}", info.age)) {
|
||||
Ok(_) => (),
|
||||
Err(e) => return Err(e)
|
||||
}
|
||||
return file.write_line(&format!("rating: {}", info.rating));
|
||||
}
|
||||
```
|
||||
|
||||
See
|
||||
[the `result` module documentation](https://doc.rust-lang.org/stable/std/result/index.html#the-try-macro)
|
||||
for more details.
|
||||
|
||||
### The `Result`-`impl` pattern [FIXME]
|
||||
|
||||
> **[FIXME]** Document the way that the `io` module uses trait impls
|
||||
> on `std::io::Result` to painlessly propagate errors.
|
||||
@ -1,7 +0,0 @@
|
||||
% Handling errors
|
||||
|
||||
### Use thread isolation to cope with failure. [FIXME]
|
||||
|
||||
> **[FIXME]** Explain how to isolate threads and detect thread failure for recovery.
|
||||
|
||||
### Consuming `Result` [FIXME]
|
||||
@ -1,8 +0,0 @@
|
||||
% Propagation
|
||||
|
||||
> **[FIXME]** We need guidelines on how to layer error information up a stack of
|
||||
> abstractions.
|
||||
|
||||
### Error interoperation [FIXME]
|
||||
|
||||
> **[FIXME]** Document the `FromError` infrastructure.
|
||||
@ -1,125 +0,0 @@
|
||||
% Signaling errors [RFC #236]
|
||||
|
||||
> The guidelines below were approved by [RFC #236](https://github.com/rust-lang/rfcs/pull/236).
|
||||
|
||||
Errors fall into one of three categories:
|
||||
|
||||
* Catastrophic errors, e.g. out-of-memory.
|
||||
* Contract violations, e.g. wrong input encoding, index out of bounds.
|
||||
* Obstructions, e.g. file not found, parse error.
|
||||
|
||||
The basic principle of the convention is that:
|
||||
|
||||
* Catastrophic errors and programming errors (bugs) can and should only be
|
||||
recovered at a *coarse grain*, i.e. a thread boundary.
|
||||
* Obstructions preventing an operation should be reported at a maximally *fine
|
||||
grain* -- to the immediate invoker of the operation.
|
||||
|
||||
## Catastrophic errors
|
||||
|
||||
An error is _catastrophic_ if there is no meaningful way for the current thread to
|
||||
continue after the error occurs.
|
||||
|
||||
Catastrophic errors are _extremely_ rare, especially outside of `libstd`.
|
||||
|
||||
**Canonical examples**: out of memory, stack overflow.
|
||||
|
||||
### For catastrophic errors, panic
|
||||
|
||||
For errors like stack overflow, Rust currently aborts the process, but
|
||||
could in principle panic, which (in the best case) would allow
|
||||
reporting and recovery from a supervisory thread.
|
||||
|
||||
## Contract violations
|
||||
|
||||
An API may define a contract that goes beyond the type checking enforced by the
|
||||
compiler. For example, slices support an indexing operation, with the contract
|
||||
that the supplied index must be in bounds.
|
||||
|
||||
Contracts can be complex and involve more than a single function invocation. For
|
||||
example, the `RefCell` type requires that `borrow_mut` not be called until all
|
||||
existing borrows have been relinquished.
|
||||
|
||||
### For contract violations, panic
|
||||
|
||||
A contract violation is always a bug, and for bugs we follow the Erlang
|
||||
philosophy of "let it crash": we assume that software *will* have bugs, and we
|
||||
design coarse-grained thread boundaries to report, and perhaps recover, from these
|
||||
bugs.
|
||||
|
||||
### Contract design
|
||||
|
||||
One subtle aspect of these guidelines is that the contract for a function is
|
||||
chosen by an API designer -- and so the designer also determines what counts as
|
||||
a violation.
|
||||
|
||||
This RFC does not attempt to give hard-and-fast rules for designing
|
||||
contracts. However, here are some rough guidelines:
|
||||
|
||||
* Prefer expressing contracts through static types whenever possible.
|
||||
|
||||
* It *must* be possible to write code that uses the API without violating the
|
||||
contract.
|
||||
|
||||
* Contracts are most justified when violations are *inarguably* bugs -- but this
|
||||
is surprisingly rare.
|
||||
|
||||
* Consider whether the API client could benefit from the contract-checking
|
||||
logic. The checks may be expensive. Or there may be useful programming
|
||||
patterns where the client does not want to check inputs before hand, but would
|
||||
rather attempt the operation and then find out whether the inputs were invalid.
|
||||
|
||||
* When a contract violation is the *only* kind of error a function may encounter
|
||||
-- i.e., there are no obstructions to its success other than "bad" inputs --
|
||||
using `Result` or `Option` instead is especially warranted. Clients can then use
|
||||
`unwrap` to assert that they have passed valid input, or re-use the error
|
||||
checking done by the API for their own purposes.
|
||||
|
||||
* When in doubt, use loose contracts and instead return a `Result` or `Option`.
|
||||
|
||||
## Obstructions
|
||||
|
||||
An operation is *obstructed* if it cannot be completed for some reason, even
|
||||
though the operation's contract has been satisfied. Obstructed operations may
|
||||
have (documented!) side effects -- they are not required to roll back after
|
||||
encountering an obstruction. However, they should leave the data structures in
|
||||
a "coherent" state (satisfying their invariants, continuing to guarantee safety,
|
||||
etc.).
|
||||
|
||||
Obstructions may involve external conditions (e.g., I/O), or they may involve
|
||||
aspects of the input that are not covered by the contract.
|
||||
|
||||
**Canonical examples**: file not found, parse error.
|
||||
|
||||
### For obstructions, use `Result`
|
||||
|
||||
The
|
||||
[`Result<T,E>` type](https://doc.rust-lang.org/stable/std/result/index.html)
|
||||
represents either a success (yielding `T`) or failure (yielding `E`). By
|
||||
returning a `Result`, a function allows its clients to discover and react to
|
||||
obstructions in a fine-grained way.
|
||||
|
||||
#### What about `Option`?
|
||||
|
||||
The `Option` type should not be used for "obstructed" operations; it
|
||||
should only be used when a `None` return value could be considered a
|
||||
"successful" execution of the operation.
|
||||
|
||||
This is of course a somewhat subjective question, but a good litmus
|
||||
test is: would a reasonable client ever ignore the result? The
|
||||
`Result` type provides a lint that ensures the result is actually
|
||||
inspected, while `Option` does not, and this difference of behavior
|
||||
can help when deciding between the two types.
|
||||
|
||||
Another litmus test: can the operation be understood as asking a
|
||||
question (possibly with sideeffects)? Operations like `pop` on a
|
||||
vector can be viewed as asking for the contents of the first element,
|
||||
with the side effect of removing it if it exists -- with an `Option`
|
||||
return value.
|
||||
|
||||
## Do not provide both `Result` and `panic!` variants.
|
||||
|
||||
An API should not provide both `Result`-producing and `panic`king versions of an
|
||||
operation. It should provide just the `Result` version, allowing clients to use
|
||||
`try!` or `unwrap` instead as needed. This is part of the general pattern of
|
||||
cutting down on redundant variants by instead using method chaining.
|
||||
@ -1,9 +0,0 @@
|
||||
% Guidelines by language feature
|
||||
|
||||
Rust provides a unique combination of language features, some new and some
|
||||
old. This section gives guidance on when and how to use Rust's features, and
|
||||
brings attention to some of the tradeoffs between different features.
|
||||
|
||||
Notably missing from this section is an in-depth discussion of Rust's pointer
|
||||
types (both built-in and in the library). The topic of pointers is discussed at
|
||||
length in a [separate section on ownership](../ownership/README.md).
|
||||
@ -1,6 +0,0 @@
|
||||
% Crates
|
||||
|
||||
> **[FIXME]** What general guidelines should we provide for crate design?
|
||||
|
||||
> Possible topics: facades; per-crate preludes (to be imported as globs);
|
||||
> "lib.rs"
|
||||
@ -1,44 +0,0 @@
|
||||
% Functions and methods
|
||||
|
||||
### Prefer methods to functions if there is a clear receiver. **[FIXME: needs RFC]**
|
||||
|
||||
Prefer
|
||||
|
||||
```rust,ignore
|
||||
impl Foo {
|
||||
pub fn frob(&self, w: widget) { ... }
|
||||
}
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust,ignore
|
||||
pub fn frob(foo: &Foo, w: widget) { ... }
|
||||
```
|
||||
|
||||
for any operation that is clearly associated with a particular
|
||||
type.
|
||||
|
||||
Methods have numerous advantages over functions:
|
||||
|
||||
* They do not need to be imported or qualified to be used: all you
|
||||
need is a value of the appropriate type.
|
||||
* Their invocation performs autoborrowing (including mutable borrows).
|
||||
* They make it easy to answer the question "what can I do with a value
|
||||
of type `T`" (especially when using rustdoc).
|
||||
* They provide `self` notation, which is more concise and often more
|
||||
clearly conveys ownership distinctions.
|
||||
|
||||
> **[FIXME]** Revisit these guidelines with
|
||||
> [UFCS](https://github.com/nick29581/rfcs/blob/ufcs/0000-ufcs.md) and
|
||||
> conventions developing around it.
|
||||
|
||||
|
||||
|
||||
### Guidelines for inherent methods. **[FIXME]**
|
||||
|
||||
> **[FIXME]** We need guidelines for when to provide inherent methods on a type,
|
||||
> versus methods through a trait or functions.
|
||||
|
||||
> **NOTE**: Rules for method resolution around inherent methods are in flux,
|
||||
> which may impact the guidelines.
|
||||
@ -1,43 +0,0 @@
|
||||
% Convenience methods
|
||||
|
||||
### Provide small, coherent sets of convenience methods. **[FIXME: needs RFC]**
|
||||
|
||||
_Convenience methods_ wrap up existing functionality in a more convenient
|
||||
way. The work done by a convenience method varies widely:
|
||||
|
||||
* _Re-providing functions as methods_. For example, the `std::path::Path` type
|
||||
provides methods like `stat` on `Path`s that simply invoke the corresponding
|
||||
function in `std::io::fs`.
|
||||
* _Skipping through conversions_. For example, the `str` type provides a
|
||||
`.len()` convenience method which is also expressible as `.as_bytes().len()`.
|
||||
Sometimes the conversion is more complex: the `str` module also provides
|
||||
`from_chars`, which encapsulates a simple use of iterators.
|
||||
* _Encapsulating common arguments_. For example, vectors of `&str`s
|
||||
provide a `connect` as well as a special case, `concat`, that is expressible
|
||||
using `connect` with a fixed separator of `""`.
|
||||
* _Providing more efficient special cases_. The `connect` and `concat` example
|
||||
also applies here: singling out `concat` as a special case allows for a more
|
||||
efficient implementation.
|
||||
|
||||
Note, however, that the `connect` method actually detects the special case
|
||||
internally and invokes `concat`. Usually, it is not necessary to add a public
|
||||
convenience method just for efficiency gains; there should also be a
|
||||
_conceptual_ reason to add it, e.g. because it is such a common special case.
|
||||
|
||||
It is tempting to add convenience methods in a one-off, haphazard way as
|
||||
common use patterns emerge. Avoid this temptation, and instead _design_ small,
|
||||
coherent sets of convenience methods that are easy to remember:
|
||||
|
||||
* _Small_: Avoid combinatorial explosions of convenience methods. For example,
|
||||
instead of adding `_str` variants of methods that provide a `str` output,
|
||||
instead ensure that the normal output type of methods is easily convertible to
|
||||
`str`.
|
||||
* _Coherent_: Look for small groups of convenience methods that make sense to
|
||||
include together. For example, the `Path` API mentioned above includes a small
|
||||
selection of the most common filesystem operations that take a `Path`
|
||||
argument. If one convenience method strongly suggests the existence of others,
|
||||
consider adding the whole group.
|
||||
* _Memorable_: It is not worth saving a few characters of typing if you have to
|
||||
look up the name of a convenience method every time you use it. Add
|
||||
convenience methods with names that are obvious and easy to remember, and add
|
||||
them for the most common or painful use cases.
|
||||
@ -1,203 +0,0 @@
|
||||
% Input to functions and methods
|
||||
|
||||
### Let the client decide when to copy and where to place data. [FIXME: needs RFC]
|
||||
|
||||
#### Copying:
|
||||
|
||||
Prefer
|
||||
|
||||
```rust,ignore
|
||||
fn foo(b: Bar) {
|
||||
// use b as owned, directly
|
||||
}
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust,ignore
|
||||
fn foo(b: &Bar) {
|
||||
let b = b.clone();
|
||||
// use b as owned after cloning
|
||||
}
|
||||
```
|
||||
|
||||
If a function requires ownership of a value of unknown type `T`, but does not
|
||||
otherwise need to make copies, the function should take ownership of the
|
||||
argument (pass by value `T`) rather than using `.clone()`. That way, the caller
|
||||
can decide whether to relinquish ownership or to `clone`.
|
||||
|
||||
Similarly, the `Copy` trait bound should only be demanded it when absolutely
|
||||
needed, not as a way of signaling that copies should be cheap to make.
|
||||
|
||||
#### Placement:
|
||||
|
||||
Prefer
|
||||
|
||||
```rust,ignore
|
||||
fn foo(b: Bar) -> Bar { ... }
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust,ignore
|
||||
fn foo(b: Box<Bar>) -> Box<Bar> { ... }
|
||||
```
|
||||
|
||||
for concrete types `Bar` (as opposed to trait objects). This way, the caller can
|
||||
decide whether to place data on the stack or heap. No overhead is imposed by
|
||||
letting the caller determine the placement.
|
||||
|
||||
### Minimize assumptions about parameters. [FIXME: needs RFC]
|
||||
|
||||
The fewer assumptions a function makes about its inputs, the more widely usable
|
||||
it becomes.
|
||||
|
||||
#### Minimizing assumptions through generics:
|
||||
|
||||
Prefer
|
||||
|
||||
```rust,ignore
|
||||
fn foo<T: Iterator<i32>>(c: T) { ... }
|
||||
```
|
||||
|
||||
over any of
|
||||
|
||||
```rust,ignore
|
||||
fn foo(c: &[i32]) { ... }
|
||||
fn foo(c: &Vec<i32>) { ... }
|
||||
fn foo(c: &SomeOtherCollection<i32>) { ... }
|
||||
```
|
||||
|
||||
if the function only needs to iterate over the data.
|
||||
|
||||
More generally, consider using generics to pinpoint the assumptions a function
|
||||
needs to make about its arguments.
|
||||
|
||||
On the other hand, generics can make it more difficult to read and understand a
|
||||
function's signature. Aim for "natural" parameter types that a neither overly
|
||||
concrete nor overly abstract. See the discussion on
|
||||
[traits](../traits/README.md) for more guidance.
|
||||
|
||||
|
||||
#### Minimizing ownership assumptions:
|
||||
|
||||
Prefer either of
|
||||
|
||||
```rust,ignore
|
||||
fn foo(b: &Bar) { ... }
|
||||
fn foo(b: &mut Bar) { ... }
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust,ignore
|
||||
fn foo(b: Bar) { ... }
|
||||
```
|
||||
|
||||
That is, prefer borrowing arguments rather than transferring ownership, unless
|
||||
ownership is actually needed.
|
||||
|
||||
### Prefer compound return types to out-parameters. [FIXME: needs RFC]
|
||||
|
||||
Prefer
|
||||
|
||||
```rust,ignore
|
||||
fn foo() -> (Bar, Bar)
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust,ignore
|
||||
fn foo(output: &mut Bar) -> Bar
|
||||
```
|
||||
|
||||
for returning multiple `Bar` values.
|
||||
|
||||
Compound return types like tuples and structs are efficiently compiled
|
||||
and do not require heap allocation. If a function needs to return
|
||||
multiple values, it should do so via one of these types.
|
||||
|
||||
The primary exception: sometimes a function is meant to modify data
|
||||
that the caller already owns, for example to re-use a buffer:
|
||||
|
||||
```rust,ignore
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>
|
||||
```
|
||||
|
||||
(From the [Read trait](https://doc.rust-lang.org/stable/std/io/trait.Read.html#tymethod.read).)
|
||||
|
||||
### Consider validating arguments, statically or dynamically. [FIXME: needs RFC]
|
||||
|
||||
_Note: this material is closely related to
|
||||
[library-level guarantees](../../safety/lib-guarantees.md)._
|
||||
|
||||
Rust APIs do _not_ generally follow the
|
||||
[robustness principle](https://en.wikipedia.org/wiki/Robustness_principle): "be
|
||||
conservative in what you send; be liberal in what you accept".
|
||||
|
||||
Instead, Rust code should _enforce_ the validity of input whenever practical.
|
||||
|
||||
Enforcement can be achieved through the following mechanisms (listed
|
||||
in order of preference).
|
||||
|
||||
#### Static enforcement:
|
||||
|
||||
Choose an argument type that rules out bad inputs.
|
||||
|
||||
For example, prefer
|
||||
|
||||
```rust,ignore
|
||||
enum FooMode {
|
||||
Mode1,
|
||||
Mode2,
|
||||
Mode3,
|
||||
}
|
||||
fn foo(mode: FooMode) { ... }
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust,ignore
|
||||
fn foo(mode2: bool, mode3: bool) {
|
||||
assert!(!mode2 || !mode3);
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Static enforcement usually comes at little run-time cost: it pushes the
|
||||
costs to the boundaries. It also catches bugs early, during compilation,
|
||||
rather than through run-time failures.
|
||||
|
||||
On the other hand, some properties are difficult or impossible to
|
||||
express using types.
|
||||
|
||||
#### Dynamic enforcement:
|
||||
|
||||
Validate the input as it is processed (or ahead of time, if necessary). Dynamic
|
||||
checking is often easier to implement than static checking, but has several
|
||||
downsides:
|
||||
|
||||
1. Runtime overhead (unless checking can be done as part of processing the input).
|
||||
2. Delayed detection of bugs.
|
||||
3. Introduces failure cases, either via `panic!` or `Result`/`Option` types (see
|
||||
the [error handling guidelines](../../errors/README.md)), which must then be
|
||||
dealt with by client code.
|
||||
|
||||
#### Dynamic enforcement with `debug_assert!`:
|
||||
|
||||
Same as dynamic enforcement, but with the possibility of easily turning off
|
||||
expensive checks for production builds.
|
||||
|
||||
#### Dynamic enforcement with opt-out:
|
||||
|
||||
Same as dynamic enforcement, but adds sibling functions that opt out of the
|
||||
checking.
|
||||
|
||||
The convention is to mark these opt-out functions with a suffix like
|
||||
`_unchecked` or by placing them in a `raw` submodule.
|
||||
|
||||
The unchecked functions can be used judiciously in cases where (1) performance
|
||||
dictates avoiding checks and (2) the client is otherwise confident that the
|
||||
inputs are valid.
|
||||
|
||||
> **[FIXME]** Should opt-out functions be marked `unsafe`?
|
||||
@ -1,56 +0,0 @@
|
||||
% Output from functions and methods
|
||||
|
||||
### Don't overpromise. [FIXME]
|
||||
|
||||
> **[FIXME]** Add discussion of overly-specific return types,
|
||||
> e.g. returning a compound iterator type rather than hiding it behind
|
||||
> a use of newtype.
|
||||
|
||||
### Let clients choose what to throw away. [FIXME: needs RFC]
|
||||
|
||||
#### Return useful intermediate results:
|
||||
|
||||
Many functions that answer a question also compute interesting related data. If
|
||||
this data is potentially of interest to the client, consider exposing it in the
|
||||
API.
|
||||
|
||||
Prefer
|
||||
|
||||
```rust,ignore
|
||||
struct SearchResult {
|
||||
found: bool, // item in container?
|
||||
expected_index: usize // what would the item's index be?
|
||||
}
|
||||
|
||||
fn binary_search(&self, k: Key) -> SearchResult
|
||||
```
|
||||
or
|
||||
|
||||
```rust,ignore
|
||||
fn binary_search(&self, k: Key) -> (bool, usize)
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust,ignore
|
||||
fn binary_search(&self, k: Key) -> bool
|
||||
```
|
||||
|
||||
#### Yield back ownership:
|
||||
|
||||
Prefer
|
||||
|
||||
```rust,ignore
|
||||
fn from_utf8_owned(vv: Vec<u8>) -> Result<String, Vec<u8>>
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust,ignore
|
||||
fn from_utf8_owned(vv: Vec<u8>) -> Option<String>
|
||||
```
|
||||
|
||||
The `from_utf8_owned` function gains ownership of a vector. In the successful
|
||||
case, the function consumes its input, returning an owned string without
|
||||
allocating or copying. In the unsuccessful case, however, the function returns
|
||||
back ownership of the original slice.
|
||||
@ -1,103 +0,0 @@
|
||||
% Let binding
|
||||
|
||||
### Always separately bind RAII guards. [FIXME: needs RFC]
|
||||
|
||||
Prefer
|
||||
|
||||
```rust,ignore
|
||||
fn use_mutex(m: sync::mutex::Mutex<i32>) {
|
||||
let guard = m.lock();
|
||||
do_work(guard);
|
||||
drop(guard); // unlock the lock
|
||||
// do other work
|
||||
}
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust,ignore
|
||||
fn use_mutex(m: sync::mutex::Mutex<i32>) {
|
||||
do_work(m.lock());
|
||||
// do other work
|
||||
}
|
||||
```
|
||||
|
||||
As explained in the [RAII guide](../ownership/raii.md), RAII guards are values
|
||||
that represent ownership of some resource and whose destructor releases the
|
||||
resource. Because the lifetime of guards are significant, they should always be
|
||||
explicitly `let`-bound to make the lifetime clear. Consider using an explicit
|
||||
`drop` to release the resource early.
|
||||
|
||||
### Prefer conditional expressions to deferred initialization. [FIXME: needs RFC]
|
||||
|
||||
Prefer
|
||||
|
||||
```rust,ignore
|
||||
let foo = match bar {
|
||||
Baz => 0,
|
||||
Quux => 1
|
||||
};
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust,ignore
|
||||
let foo;
|
||||
match bar {
|
||||
Baz => {
|
||||
foo = 0;
|
||||
}
|
||||
Quux => {
|
||||
foo = 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
unless the conditions for initialization are too complex to fit into a simple
|
||||
conditional expression.
|
||||
|
||||
### Use type annotations for clarification; prefer explicit generics when inference fails. [FIXME: needs RFC]
|
||||
|
||||
Prefer
|
||||
|
||||
```rust,ignore
|
||||
let v = s.iter().map(|x| x * 2)
|
||||
.collect::<Vec<_>>();
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust,ignore
|
||||
let v: Vec<_> = s.iter().map(|x| x * 2)
|
||||
.collect();
|
||||
```
|
||||
|
||||
When the type of a value might be unclear to the _reader_ of the code, consider
|
||||
explicitly annotating it in a `let`.
|
||||
|
||||
On the other hand, when the type is unclear to the _compiler_, prefer to specify
|
||||
the type by explicit generics instantiation, which is usually more clear.
|
||||
|
||||
### Shadowing [FIXME]
|
||||
|
||||
> **[FIXME]** Repeatedly shadowing a binding is somewhat common in Rust code. We
|
||||
> need to articulate a guideline on when it is appropriate/useful and when not.
|
||||
|
||||
### Prefer immutable bindings. [FIXME: needs RFC]
|
||||
|
||||
Use `mut` bindings to signal the span during which a value is mutated:
|
||||
|
||||
```rust,ignore
|
||||
let mut v = Vec::new();
|
||||
// push things onto v
|
||||
let v = v;
|
||||
// use v immutably henceforth
|
||||
```
|
||||
|
||||
### Prefer to bind all `struct` or tuple fields. [FIXME: needs RFC]
|
||||
|
||||
When consuming a `struct` or tuple via a `let`, bind all of the fields rather
|
||||
than using `..` to elide the ones you don't need. The benefit is that when
|
||||
fields are added, the compiler will pinpoint all of the places where that type
|
||||
of value was consumed, which will often need to be adjusted to take the new
|
||||
field properly into account.
|
||||
@ -1,13 +0,0 @@
|
||||
% Loops
|
||||
|
||||
### Prefer `for` to `while`. [FIXME: needs RFC]
|
||||
|
||||
A `for` loop is preferable to a `while` loop, unless the loop counts in a
|
||||
non-uniform way (making it difficult to express using `for`).
|
||||
|
||||
### Guidelines for `loop`. [FIXME]
|
||||
|
||||
> **[FIXME]** When is `loop` recommended? Some possibilities:
|
||||
> * For optimistic retry algorithms
|
||||
> * For servers
|
||||
> * To avoid mutating local variables sometimes needed to fit `while`
|
||||
@ -1,26 +0,0 @@
|
||||
% Pattern matching
|
||||
|
||||
### Dereference `match` targets when possible. [FIXME: needs RFC]
|
||||
|
||||
Prefer
|
||||
|
||||
~~~~ignore
|
||||
match *foo {
|
||||
X(...) => ...
|
||||
Y(...) => ...
|
||||
}
|
||||
~~~~
|
||||
|
||||
over
|
||||
|
||||
~~~~ignore
|
||||
match foo {
|
||||
box X(...) => ...
|
||||
box Y(...) => ...
|
||||
}
|
||||
~~~~
|
||||
|
||||
<!-- ### Clearly indicate important scopes. **[FIXME: needs RFC]** -->
|
||||
|
||||
<!-- If it is important that the destructor for a value be executed at a specific -->
|
||||
<!-- time, clearly bind that value using a standalone `let` -->
|
||||
@ -1,133 +0,0 @@
|
||||
% Modules
|
||||
|
||||
> **[FIXME]** What general guidelines should we provide for module design?
|
||||
|
||||
> We should discuss visibility, nesting, `mod.rs`, and any interesting patterns
|
||||
> around modules.
|
||||
|
||||
### Headers [FIXME: needs RFC]
|
||||
|
||||
Organize module headers as follows:
|
||||
1. [Imports](../style/imports.md).
|
||||
1. `mod` declarations.
|
||||
1. `pub mod` declarations.
|
||||
|
||||
### Avoid `path` directives. [FIXME: needs RFC]
|
||||
|
||||
Avoid using `#[path="..."]` directives; make the file system and
|
||||
module hierarchy match, instead.
|
||||
|
||||
### Use the module hierarchy to organize APIs into coherent sections. [FIXME]
|
||||
|
||||
> **[FIXME]** Flesh this out with examples; explain what a "coherent
|
||||
> section" is with examples.
|
||||
>
|
||||
> The module hierarchy defines both the public and internal API of your module.
|
||||
> Breaking related functionality into submodules makes it understandable to both
|
||||
> users and contributors to the module.
|
||||
|
||||
### Place modules in their own file. [FIXME: needs RFC]
|
||||
|
||||
> **[FIXME]**
|
||||
> - "<100 lines" is arbitrary, but it's a clearer recommendation
|
||||
> than "~1 page" or similar suggestions that vary by screen size, etc.
|
||||
|
||||
For all except very short modules (<100 lines) and [tests](../testing/README.md),
|
||||
place the module `foo` in a separate file, as in:
|
||||
|
||||
```rust,ignore
|
||||
pub mod foo;
|
||||
|
||||
// in foo.rs or foo/mod.rs
|
||||
pub fn bar() { println!("..."); }
|
||||
/* ... */
|
||||
```
|
||||
|
||||
rather than declaring it inline:
|
||||
|
||||
```rust,ignore
|
||||
pub mod foo {
|
||||
pub fn bar() { println!("..."); }
|
||||
/* ... */
|
||||
}
|
||||
```
|
||||
|
||||
#### Use subdirectories for modules with children. [FIXME: needs RFC]
|
||||
|
||||
For modules that themselves have submodules, place the module in a separate
|
||||
directory (e.g., `bar/mod.rs` for a module `bar`) rather than the same directory.
|
||||
|
||||
Note the structure of
|
||||
[`std::io`](https://doc.rust-lang.org/std/io/). Many of the submodules lack
|
||||
children, like
|
||||
[`io::fs`](https://doc.rust-lang.org/std/io/fs/)
|
||||
and
|
||||
[`io::stdio`](https://doc.rust-lang.org/std/io/stdio/).
|
||||
On the other hand,
|
||||
[`io::net`](https://doc.rust-lang.org/std/io/net/)
|
||||
contains submodules, so it lives in a separate directory:
|
||||
|
||||
```text
|
||||
io/mod.rs
|
||||
io/extensions.rs
|
||||
io/fs.rs
|
||||
io/net/mod.rs
|
||||
io/net/addrinfo.rs
|
||||
io/net/ip.rs
|
||||
io/net/tcp.rs
|
||||
io/net/udp.rs
|
||||
io/net/unix.rs
|
||||
io/pipe.rs
|
||||
...
|
||||
```
|
||||
|
||||
While it is possible to define all of `io` within a single directory,
|
||||
mirroring the module hierarchy in the directory structure makes
|
||||
submodules of `io::net` easier to find.
|
||||
|
||||
### Consider top-level definitions or reexports. [FIXME: needs RFC]
|
||||
|
||||
For modules with submodules,
|
||||
define or [reexport](https://doc.rust-lang.org/std/io/#reexports) commonly used
|
||||
definitions at the top level:
|
||||
|
||||
* Functionality relevant to the module itself or to many of its
|
||||
children should be defined in `mod.rs`.
|
||||
* Functionality specific to a submodule should live in that
|
||||
submodule. Reexport at the top level for the most important or
|
||||
common definitions.
|
||||
|
||||
For example,
|
||||
[`IoError`](https://doc.rust-lang.org/std/io/struct.IoError.html)
|
||||
is defined in `io/mod.rs`, since it pertains to the entirety of `io`,
|
||||
while
|
||||
[`TcpStream`](https://doc.rust-lang.org/std/io/net/tcp/struct.TcpStream.html)
|
||||
is defined in `io/net/tcp.rs` and reexported in the `io` module.
|
||||
|
||||
### Use internal module hierarchies for organization. [FIXME: needs RFC]
|
||||
|
||||
> **[FIXME]**
|
||||
> - Referencing internal modules from the standard library is subject to
|
||||
> becoming outdated.
|
||||
|
||||
Internal module hierarchies (i.e., private submodules) may be used to
|
||||
hide implementation details that are not part of the module's API.
|
||||
|
||||
For example, in [`std::io`](https://doc.rust-lang.org/std/io/), `mod mem`
|
||||
provides implementations for
|
||||
[`BufReader`](https://doc.rust-lang.org/std/io/struct.BufReader.html)
|
||||
and
|
||||
[`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html),
|
||||
but these are re-exported in `io/mod.rs` at the top level of the module:
|
||||
|
||||
```rust,ignore
|
||||
// libstd/io/mod.rs
|
||||
|
||||
pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter};
|
||||
/* ... */
|
||||
mod mem;
|
||||
```
|
||||
|
||||
This hides the detail that there even exists a `mod mem` in `io`, and
|
||||
helps keep code organized while offering freedom to change the
|
||||
implementation.
|
||||
@ -1,22 +0,0 @@
|
||||
% Traits
|
||||
|
||||
Traits are probably Rust's most complex feature, supporting a wide range of use
|
||||
cases and design tradeoffs. Patterns of trait usage are still emerging.
|
||||
|
||||
### Know whether a trait will be used as an object. [FIXME: needs RFC]
|
||||
|
||||
Trait objects have some [significant limitations](objects.md): methods
|
||||
invoked through a trait object cannot use generics, and cannot use
|
||||
`Self` except in receiver position.
|
||||
|
||||
When designing a trait, decide early on whether the trait will be used
|
||||
as an [object](objects.md) or as a [bound on generics](generics.md);
|
||||
the tradeoffs are discussed in each of the linked sections.
|
||||
|
||||
If a trait is meant to be used as an object, its methods should take
|
||||
and return trait objects rather than use generics.
|
||||
|
||||
|
||||
### Default methods [FIXME]
|
||||
|
||||
> **[FIXME]** Guidelines for default methods.
|
||||
@ -1,71 +0,0 @@
|
||||
% Common traits
|
||||
|
||||
### Eagerly implement common traits. [FIXME: needs RFC]
|
||||
|
||||
Rust's trait system does not allow _orphans_: roughly, every `impl` must live
|
||||
either in the crate that defines the trait or the implementing
|
||||
type. Consequently, crates that define new types should eagerly implement all
|
||||
applicable, common traits.
|
||||
|
||||
To see why, consider the following situation:
|
||||
|
||||
* Crate `std` defines trait `Debug`.
|
||||
* Crate `url` defines type `Url`, without implementing `Debug`.
|
||||
* Crate `webapp` imports from both `std` and `url`,
|
||||
|
||||
There is no way for `webapp` to add `Debug` to `url`, since it defines neither.
|
||||
(Note: the newtype pattern can provide an efficient, but inconvenient
|
||||
workaround; see [newtype for views](../types/newtype.md))
|
||||
|
||||
The most important common traits to implement from `std` are:
|
||||
|
||||
```text
|
||||
Clone, Debug, Hash, Eq
|
||||
```
|
||||
|
||||
#### When safe, derive or otherwise implement `Send` and `Share`. [FIXME]
|
||||
|
||||
> **[FIXME]**. This guideline is in flux while the "opt-in" nature of
|
||||
> built-in traits is being decided. See https://github.com/rust-lang/rfcs/pull/127
|
||||
|
||||
### Prefer to derive, rather than implement. [FIXME: needs RFC]
|
||||
|
||||
Deriving saves implementation effort, makes correctness trivial, and
|
||||
automatically adapts to upstream changes.
|
||||
|
||||
### Do not overload operators in surprising ways. [FIXME: needs RFC]
|
||||
|
||||
Operators with built in syntax (`*`, `|`, and so on) can be provided for a type
|
||||
by implementing the traits in `core::ops`. These operators come with strong
|
||||
expectations: implement `Mul` only for an operation that bears some resemblance
|
||||
to multiplication (and shares the expected properties, e.g. associativity), and
|
||||
so on for the other traits.
|
||||
|
||||
### The `Drop` trait
|
||||
|
||||
The `Drop` trait is treated specially by the compiler as a way of
|
||||
associating destructors with types. See
|
||||
[the section on destructors](../../ownership/destructors.md) for
|
||||
guidance.
|
||||
|
||||
### The `Deref`/`DerefMut` traits
|
||||
|
||||
#### Use `Deref`/`DerefMut` only for smart pointers. [FIXME: needs RFC]
|
||||
|
||||
The `Deref` traits are used implicitly by the compiler in many circumstances,
|
||||
and interact with method resolution. The relevant rules are designed
|
||||
specifically to accommodate smart pointers, and so the traits should be used
|
||||
only for that purpose.
|
||||
|
||||
#### Do not fail within a `Deref`/`DerefMut` implementation. [FIXME: needs RFC]
|
||||
|
||||
Because the `Deref` traits are invoked implicitly by the compiler in sometimes
|
||||
subtle ways, failure during dereferencing can be extremely confusing. If a
|
||||
dereference might not succeed, target the `Deref` trait as a `Result` or
|
||||
`Option` type instead.
|
||||
|
||||
#### Avoid inherent methods when implementing `Deref`/`DerefMut` [FIXME: needs RFC]
|
||||
|
||||
The rules around method resolution and `Deref` are in flux, but inherent methods
|
||||
on a type implementing `Deref` are likely to shadow any methods of the referent
|
||||
with the same name.
|
||||
@ -1,7 +0,0 @@
|
||||
% Using traits to add extension methods
|
||||
|
||||
> **[FIXME]** Elaborate.
|
||||
|
||||
### Consider using default methods rather than extension traits **[FIXME]**
|
||||
|
||||
> **[FIXME]** Elaborate.
|
||||
@ -1,67 +0,0 @@
|
||||
% Using traits for bounds on generics
|
||||
|
||||
The most widespread use of traits is for writing generic functions or types. For
|
||||
example, the following signature describes a function for consuming any iterator
|
||||
yielding items of type `A` to produce a collection of `A`:
|
||||
|
||||
```rust,ignore
|
||||
fn from_iter<T: Iterator<A>>(iterator: T) -> SomeCollection<A>
|
||||
```
|
||||
|
||||
Here, the `Iterator` trait specifies an interface that a type `T` must
|
||||
explicitly implement to be used by this generic function.
|
||||
|
||||
**Pros**:
|
||||
|
||||
* _Reusability_. Generic functions can be applied to an open-ended collection of
|
||||
types, while giving a clear contract for the functionality those types must
|
||||
provide.
|
||||
* _Static dispatch and optimization_. Each use of a generic function is
|
||||
specialized ("monomorphized") to the particular types implementing the trait
|
||||
bounds, which means that (1) invocations of trait methods are static, direct
|
||||
calls to the implementation and (2) the compiler can inline and otherwise
|
||||
optimize these calls.
|
||||
* _Inline layout_. If a `struct` and `enum` type is generic over some type
|
||||
parameter `T`, values of type `T` will be laid out _inline_ in the
|
||||
`struct`/`enum`, without any indirection.
|
||||
* _Inference_. Since the type parameters to generic functions can usually be
|
||||
inferred, generic functions can help cut down on verbosity in code where
|
||||
explicit conversions or other method calls would usually be necessary. See the
|
||||
overloading/implicits use case below.
|
||||
* _Precise types_. Because generics give a _name_ to the specific type
|
||||
implementing a trait, it is possible to be precise about places where that
|
||||
exact type is required or produced. For example, a function
|
||||
|
||||
```rust,ignore
|
||||
fn binary<T: Trait>(x: T, y: T) -> T
|
||||
```
|
||||
|
||||
is guaranteed to consume and produce elements of exactly the same type `T`; it
|
||||
cannot be invoked with parameters of different types that both implement
|
||||
`Trait`.
|
||||
|
||||
**Cons**:
|
||||
|
||||
* _Code size_. Specializing generic functions means that the function body is
|
||||
duplicated. The increase in code size must be weighed against the performance
|
||||
benefits of static dispatch.
|
||||
* _Homogeneous types_. This is the other side of the "precise types" coin: if
|
||||
`T` is a type parameter, it stands for a _single_ actual type. So for example
|
||||
a `Vec<T>` contains elements of a single concrete type (and, indeed, the
|
||||
vector representation is specialized to lay these out in line). Sometimes
|
||||
heterogeneous collections are useful; see
|
||||
trait objects below.
|
||||
* _Signature verbosity_. Heavy use of generics can bloat function signatures.
|
||||
**[Ed. note]** This problem may be mitigated by some language improvements; stay tuned.
|
||||
|
||||
### Favor widespread traits. **[FIXME: needs RFC]**
|
||||
|
||||
Generic types are a form of abstraction, which entails a mental indirection: if
|
||||
a function takes an argument of type `T` bounded by `Trait`, clients must first
|
||||
think about the concrete types that implement `Trait` to understand how and when
|
||||
the function is callable.
|
||||
|
||||
To keep the cost of abstraction low, favor widely-known traits. Whenever
|
||||
possible, implement and use traits provided as part of the standard library. Do
|
||||
not introduce new traits for generics lightly; wait until there are a wide range
|
||||
of types that can implement the type.
|
||||
@ -1,49 +0,0 @@
|
||||
% Using trait objects
|
||||
|
||||
> **[FIXME]** What are uses of trait objects other than heterogeneous collections?
|
||||
|
||||
Trait objects are useful primarily when _heterogeneous_ collections of objects
|
||||
need to be treated uniformly; it is the closest that Rust comes to
|
||||
object-oriented programming.
|
||||
|
||||
```rust,ignore
|
||||
struct Frame { ... }
|
||||
struct Button { ... }
|
||||
struct Label { ... }
|
||||
|
||||
trait Widget { ... }
|
||||
|
||||
impl Widget for Frame { ... }
|
||||
impl Widget for Button { ... }
|
||||
impl Widget for Label { ... }
|
||||
|
||||
impl Frame {
|
||||
fn new(contents: &[Box<Widget>]) -> Frame {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
fn make_gui() -> Box<Widget> {
|
||||
let b: Box<Widget> = box Button::new(...);
|
||||
let l: Box<Widget> = box Label::new(...);
|
||||
|
||||
box Frame::new([b, l]) as Box<Widget>
|
||||
}
|
||||
```
|
||||
|
||||
By using trait objects, we can set up a GUI framework with a `Frame` widget that
|
||||
contains a heterogeneous collection of children widgets.
|
||||
|
||||
**Pros**:
|
||||
|
||||
* _Heterogeneity_. When you need it, you really need it.
|
||||
* _Code size_. Unlike generics, trait objects do not generate specialized
|
||||
(monomorphized) versions of code, which can greatly reduce code size.
|
||||
|
||||
**Cons**:
|
||||
|
||||
* _No generic methods_. Trait objects cannot currently provide generic methods.
|
||||
* _Dynamic dispatch and fat pointers_. Trait objects inherently involve
|
||||
indirection and vtable dispatch, which can carry a performance penalty.
|
||||
* _No Self_. Except for the method receiver argument, methods on trait objects
|
||||
cannot use the `Self` type.
|
||||
@ -1,7 +0,0 @@
|
||||
% Using traits for overloading
|
||||
|
||||
> **[FIXME]** Elaborate.
|
||||
|
||||
> **[FIXME]** We need to decide on guidelines for this use case. There are a few
|
||||
> patterns emerging in current Rust code, but it's not clear how widespread they
|
||||
> should be.
|
||||
@ -1,30 +0,0 @@
|
||||
% Using traits to share implementations
|
||||
|
||||
> **[FIXME]** Elaborate.
|
||||
|
||||
> **[FIXME]** We probably want to discourage this, at least when used in a way
|
||||
> that is publicly exposed.
|
||||
|
||||
Traits that provide default implementations for function can provide code reuse
|
||||
across types. For example, a `print` method can be defined across multiple
|
||||
types as follows:
|
||||
|
||||
``` Rust
|
||||
trait Printable {
|
||||
// Default method implementation
|
||||
fn print(&self) { println!("{:?}", *self) }
|
||||
}
|
||||
|
||||
impl Printable for i32 {}
|
||||
|
||||
impl Printable for String {
|
||||
fn print(&self) { println!("{}", *self) }
|
||||
}
|
||||
|
||||
impl Printable for bool {}
|
||||
|
||||
impl Printable for f32 {}
|
||||
```
|
||||
|
||||
This allows the implementation of `print` to be shared across types, yet
|
||||
overridden where needed, as seen in the `impl` for `String`.
|
||||
@ -1,68 +0,0 @@
|
||||
% Data types
|
||||
|
||||
### Use custom types to imbue meaning; do not abuse `bool`, `Option` or other core types. **[FIXME: needs RFC]**
|
||||
|
||||
Prefer
|
||||
|
||||
```rust,ignore
|
||||
let w = Widget::new(Small, Round)
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust,ignore
|
||||
let w = Widget::new(true, false)
|
||||
```
|
||||
|
||||
Core types like `bool`, `u8` and `Option` have many possible interpretations.
|
||||
|
||||
Use custom types (whether `enum`s, `struct`, or tuples) to convey
|
||||
interpretation and invariants. In the above example,
|
||||
it is not immediately clear what `true` and `false` are conveying without
|
||||
looking up the argument names, but `Small` and `Round` are more suggestive.
|
||||
|
||||
Using custom types makes it easier to expand the
|
||||
options later on, for example by adding an `ExtraLarge` variant.
|
||||
|
||||
See [the newtype pattern](newtype.md) for a no-cost way to wrap
|
||||
existing types with a distinguished name.
|
||||
|
||||
### Prefer private fields, except for passive data. **[FIXME: needs RFC]**
|
||||
|
||||
Making a field public is a strong commitment: it pins down a representation
|
||||
choice, _and_ prevents the type from providing any validation or maintaining any
|
||||
invariants on the contents of the field, since clients can mutate it arbitrarily.
|
||||
|
||||
Public fields are most appropriate for `struct` types in the C spirit: compound,
|
||||
passive data structures. Otherwise, consider providing getter/setter methods
|
||||
and hiding fields instead.
|
||||
|
||||
> **[FIXME]** Cross-reference validation for function arguments.
|
||||
|
||||
### Use custom `enum`s for alternatives, `bitflags` for C-style flags. **[FIXME: needs RFC]**
|
||||
|
||||
Rust supports `enum` types with "custom discriminants":
|
||||
|
||||
~~~~
|
||||
enum Color {
|
||||
Red = 0xff0000,
|
||||
Green = 0x00ff00,
|
||||
Blue = 0x0000ff
|
||||
}
|
||||
~~~~
|
||||
|
||||
Custom discriminants are useful when an `enum` type needs to be serialized to an
|
||||
integer value compatibly with some other system/language. They support
|
||||
"typesafe" APIs: by taking a `Color`, rather than an integer, a function is
|
||||
guaranteed to get well-formed inputs, even if it later views those inputs as
|
||||
integers.
|
||||
|
||||
An `enum` allows an API to request exactly one choice from among many. Sometimes
|
||||
an API's input is instead the presence or absence of a set of flags. In C code,
|
||||
this is often done by having each flag correspond to a particular bit, allowing
|
||||
a single integer to represent, say, 32 or 64 flags. Rust's `std::bitflags`
|
||||
module provides a typesafe way for doing so.
|
||||
|
||||
### Phantom types. [FIXME]
|
||||
|
||||
> **[FIXME]** Add some material on phantom types (https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/)
|
||||
@ -1,22 +0,0 @@
|
||||
% Conversions between types
|
||||
|
||||
### Associate conversions with the most specific type involved. **[FIXME: needs RFC]**
|
||||
|
||||
When in doubt, prefer `to_`/`as_`/`into_` to `from_`, because they are
|
||||
more ergonomic to use (and can be chained with other methods).
|
||||
|
||||
For many conversions between two types, one of the types is clearly more
|
||||
"specific": it provides some additional invariant or interpretation that is not
|
||||
present in the other type. For example, `str` is more specific than `&[u8]`,
|
||||
since it is a utf-8 encoded sequence of bytes.
|
||||
|
||||
Conversions should live with the more specific of the involved types. Thus,
|
||||
`str` provides both the `as_bytes` method and the `from_utf8` constructor for
|
||||
converting to and from `&[u8]` values. Besides being intuitive, this convention
|
||||
avoids polluting concrete types like `&[u8]` with endless conversion methods.
|
||||
|
||||
### Explicitly mark lossy conversions, or do not label them as conversions. **[FIXME: needs RFC]**
|
||||
|
||||
If a function's name implies that it is a conversion (prefix `from_`, `as_`,
|
||||
`to_` or `into_`), but the function loses information, add a suffix `_lossy` or
|
||||
otherwise indicate the lossyness. Consider avoiding the conversion name prefix.
|
||||
@ -1,69 +0,0 @@
|
||||
% The newtype pattern
|
||||
|
||||
A "newtype" is a tuple or `struct` with a single field. The terminology is borrowed from Haskell.
|
||||
|
||||
Newtypes are a zero-cost abstraction: they introduce a new, distinct name for an
|
||||
existing type, with no runtime overhead when converting between the two types.
|
||||
|
||||
### Use newtypes to provide static distinctions. [FIXME: needs RFC]
|
||||
|
||||
Newtypes can statically distinguish between different interpretations of an
|
||||
underlying type.
|
||||
|
||||
For example, a `f64` value might be used to represent a quantity in miles or in
|
||||
kilometers. Using newtypes, we can keep track of the intended interpretation:
|
||||
|
||||
```rust,ignore
|
||||
struct Miles(pub f64);
|
||||
struct Kilometers(pub f64);
|
||||
|
||||
impl Miles {
|
||||
fn as_kilometers(&self) -> Kilometers { ... }
|
||||
}
|
||||
impl Kilometers {
|
||||
fn as_miles(&self) -> Miles { ... }
|
||||
}
|
||||
```
|
||||
|
||||
Once we have separated these two types, we can statically ensure that we do not
|
||||
confuse them. For example, the function
|
||||
|
||||
```rust,ignore
|
||||
fn are_we_there_yet(distance_travelled: Miles) -> bool { ... }
|
||||
```
|
||||
|
||||
cannot accidentally be called with a `Kilometers` value. The compiler will
|
||||
remind us to perform the conversion, thus averting certain
|
||||
[catastrophic bugs](http://en.wikipedia.org/wiki/Mars_Climate_Orbiter).
|
||||
|
||||
### Use newtypes with private fields for hiding. [FIXME: needs RFC]
|
||||
|
||||
A newtype can be used to hide representation details while making precise
|
||||
promises to the client.
|
||||
|
||||
For example, consider a function `my_transform` that returns a compound iterator
|
||||
type `Enumerate<Skip<vec::MoveItems<T>>>`. We wish to hide this type from the
|
||||
client, so that the client's view of the return type is roughly `Iterator<(usize,
|
||||
T)>`. We can do so using the newtype pattern:
|
||||
|
||||
```rust,ignore
|
||||
struct MyTransformResult<T>(Enumerate<Skip<vec::MoveItems<T>>>);
|
||||
impl<T> Iterator<(usize, T)> for MyTransformResult<T> { ... }
|
||||
|
||||
fn my_transform<T, Iter: Iterator<T>>(iter: Iter) -> MyTransformResult<T> {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Aside from simplifying the signature, this use of newtypes allows us to make a
|
||||
expose and promise less to the client. The client does not know _how_ the result
|
||||
iterator is constructed or represented, which means the representation can
|
||||
change in the future without breaking client code.
|
||||
|
||||
> **[FIXME]** Interaction with auto-deref.
|
||||
|
||||
### Use newtypes to provide cost-free _views_ of another type. **[FIXME]**
|
||||
|
||||
> **[FIXME]** Describe the pattern of using newtypes to provide a new set of
|
||||
> inherent or trait methods, providing a different perspective on the underlying
|
||||
> type.
|
||||
@ -1,3 +0,0 @@
|
||||
% Ownership and resource management
|
||||
|
||||
> **[FIXME]** Add general remarks about ownership/resources here.
|
||||
@ -1,176 +0,0 @@
|
||||
% The builder pattern
|
||||
|
||||
Some data structures are complicated to construct, due to their construction needing:
|
||||
|
||||
* a large number of inputs
|
||||
* compound data (e.g. slices)
|
||||
* optional configuration data
|
||||
* choice between several flavors
|
||||
|
||||
which can easily lead to a large number of distinct constructors with
|
||||
many arguments each.
|
||||
|
||||
If `T` is such a data structure, consider introducing a `T` _builder_:
|
||||
|
||||
1. Introduce a separate data type `TBuilder` for incrementally configuring a `T`
|
||||
value. When possible, choose a better name: e.g. `Command` is the builder for
|
||||
`Process`.
|
||||
2. The builder constructor should take as parameters only the data _required_ to
|
||||
make a `T`.
|
||||
3. The builder should offer a suite of convenient methods for configuration,
|
||||
including setting up compound inputs (like slices) incrementally.
|
||||
These methods should return `self` to allow chaining.
|
||||
4. The builder should provide one or more "_terminal_" methods for actually building a `T`.
|
||||
|
||||
The builder pattern is especially appropriate when building a `T` involves side
|
||||
effects, such as spawning a thread or launching a process.
|
||||
|
||||
In Rust, there are two variants of the builder pattern, differing in the
|
||||
treatment of ownership, as described below.
|
||||
|
||||
### Non-consuming builders (preferred):
|
||||
|
||||
In some cases, constructing the final `T` does not require the builder itself to
|
||||
be consumed. The follow variant on
|
||||
[`std::process::Command`](https://doc.rust-lang.org/stable/std/process/struct.Command.html)
|
||||
is one example:
|
||||
|
||||
```rust,ignore
|
||||
// NOTE: the actual Command API does not use owned Strings;
|
||||
// this is a simplified version.
|
||||
|
||||
pub struct Command {
|
||||
program: String,
|
||||
args: Vec<String>,
|
||||
cwd: Option<String>,
|
||||
// etc
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn new(program: String) -> Command {
|
||||
Command {
|
||||
program: program,
|
||||
args: Vec::new(),
|
||||
cwd: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an argument to pass to the program.
|
||||
pub fn arg<'a>(&'a mut self, arg: String) -> &'a mut Command {
|
||||
self.args.push(arg);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add multiple arguments to pass to the program.
|
||||
pub fn args<'a>(&'a mut self, args: &[String])
|
||||
-> &'a mut Command {
|
||||
self.args.push_all(args);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the working directory for the child process.
|
||||
pub fn cwd<'a>(&'a mut self, dir: String) -> &'a mut Command {
|
||||
self.cwd = Some(dir);
|
||||
self
|
||||
}
|
||||
|
||||
/// Executes the command as a child process, which is returned.
|
||||
pub fn spawn(&self) -> std::io::Result<Process> {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that the `spawn` method, which actually uses the builder configuration to
|
||||
spawn a process, takes the builder by immutable reference. This is possible
|
||||
because spawning the process does not require ownership of the configuration
|
||||
data.
|
||||
|
||||
Because the terminal `spawn` method only needs a reference, the configuration
|
||||
methods take and return a mutable borrow of `self`.
|
||||
|
||||
#### The benefit
|
||||
|
||||
By using borrows throughout, `Command` can be used conveniently for both
|
||||
one-liner and more complex constructions:
|
||||
|
||||
```rust,ignore
|
||||
// One-liners
|
||||
Command::new("/bin/cat").arg("file.txt").spawn();
|
||||
|
||||
// Complex configuration
|
||||
let mut cmd = Command::new("/bin/ls");
|
||||
cmd.arg(".");
|
||||
|
||||
if size_sorted {
|
||||
cmd.arg("-S");
|
||||
}
|
||||
|
||||
cmd.spawn();
|
||||
```
|
||||
|
||||
### Consuming builders:
|
||||
|
||||
Sometimes builders must transfer ownership when constructing the final type
|
||||
`T`, meaning that the terminal methods must take `self` rather than `&self`:
|
||||
|
||||
```rust,ignore
|
||||
// A simplified excerpt from std::thread::Builder
|
||||
|
||||
impl ThreadBuilder {
|
||||
/// Name the thread-to-be. Currently the name is used for identification
|
||||
/// only in failure messages.
|
||||
pub fn named(mut self, name: String) -> ThreadBuilder {
|
||||
self.name = Some(name);
|
||||
self
|
||||
}
|
||||
|
||||
/// Redirect thread-local stdout.
|
||||
pub fn stdout(mut self, stdout: Box<Writer + Send>) -> ThreadBuilder {
|
||||
self.stdout = Some(stdout);
|
||||
// ^~~~~~ this is owned and cannot be cloned/re-used
|
||||
self
|
||||
}
|
||||
|
||||
/// Creates and executes a new child thread.
|
||||
pub fn spawn(self, f: proc():Send) {
|
||||
// consume self
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here, the `stdout` configuration involves passing ownership of a `Writer`,
|
||||
which must be transferred to the thread upon construction (in `spawn`).
|
||||
|
||||
When the terminal methods of the builder require ownership, there is a basic tradeoff:
|
||||
|
||||
* If the other builder methods take/return a mutable borrow, the complex
|
||||
configuration case will work well, but one-liner configuration becomes
|
||||
_impossible_.
|
||||
|
||||
* If the other builder methods take/return an owned `self`, one-liners
|
||||
continue to work well but complex configuration is less convenient.
|
||||
|
||||
Under the rubric of making easy things easy and hard things possible, _all_
|
||||
builder methods for a consuming builder should take and returned an owned
|
||||
`self`. Then client code works as follows:
|
||||
|
||||
```rust,ignore
|
||||
// One-liners
|
||||
ThreadBuilder::new().named("my_thread").spawn(proc() { ... });
|
||||
|
||||
// Complex configuration
|
||||
let mut thread = ThreadBuilder::new();
|
||||
thread = thread.named("my_thread_2"); // must re-assign to retain ownership
|
||||
|
||||
if reroute {
|
||||
thread = thread.stdout(mywriter);
|
||||
}
|
||||
|
||||
thread.spawn(proc() { ... });
|
||||
```
|
||||
|
||||
One-liners work as before, because ownership is threaded through each of the
|
||||
builder methods until being consumed by `spawn`. Complex configuration,
|
||||
however, is more verbose: it requires re-assigning the builder at each step.
|
||||
@ -1,4 +0,0 @@
|
||||
% Cells and smart pointers
|
||||
|
||||
> **[FIXME]** Add guidelines about when to use Cell, RefCell, Rc and
|
||||
> Arc (and how to use them together).
|
||||
@ -1,62 +0,0 @@
|
||||
% Constructors
|
||||
|
||||
### Define constructors as static, inherent methods. [FIXME: needs RFC]
|
||||
|
||||
In Rust, "constructors" are just a convention:
|
||||
|
||||
```rust,ignore
|
||||
impl<T> Vec<T> {
|
||||
pub fn new() -> Vec<T> { ... }
|
||||
}
|
||||
```
|
||||
|
||||
Constructors are static (no `self`) inherent methods for the type that they
|
||||
construct. Combined with the practice of
|
||||
[fully importing type names](../style/imports.md), this convention leads to
|
||||
informative but concise construction:
|
||||
|
||||
```rust,ignore
|
||||
use vec::Vec;
|
||||
|
||||
// construct a new vector
|
||||
let mut v = Vec::new();
|
||||
```
|
||||
|
||||
This convention also applied to conversion constructors (prefix `from` rather
|
||||
than `new`).
|
||||
|
||||
### Provide constructors for passive `struct`s with defaults. [FIXME: needs RFC]
|
||||
|
||||
Given the `struct`
|
||||
|
||||
```rust,ignore
|
||||
pub struct Config {
|
||||
pub color: Color,
|
||||
pub size: Size,
|
||||
pub shape: Shape,
|
||||
}
|
||||
```
|
||||
|
||||
provide a constructor if there are sensible defaults:
|
||||
|
||||
```rust,ignore
|
||||
impl Config {
|
||||
pub fn new() -> Config {
|
||||
Config {
|
||||
color: Brown,
|
||||
size: Medium,
|
||||
shape: Square,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
which then allows clients to concisely override using `struct` update syntax:
|
||||
|
||||
```rust,ignore
|
||||
Config { color: Red, .. Config::new() };
|
||||
```
|
||||
|
||||
See the [guideline for field privacy](../features/types/README.md) for
|
||||
discussion on when to create such "passive" `struct`s with public
|
||||
fields.
|
||||
@ -1,22 +0,0 @@
|
||||
% Destructors
|
||||
|
||||
Unlike constructors, destructors in Rust have a special status: they are added
|
||||
by implementing `Drop` for a type, and they are automatically invoked as values
|
||||
go out of scope.
|
||||
|
||||
> **[FIXME]** This section needs to be expanded.
|
||||
|
||||
### Destructors should not fail. [FIXME: needs RFC]
|
||||
|
||||
Destructors are executed on thread failure, and in that context a failing
|
||||
destructor causes the program to abort.
|
||||
|
||||
Instead of failing in a destructor, provide a separate method for checking for
|
||||
clean teardown, e.g. a `close` method, that returns a `Result` to signal
|
||||
problems.
|
||||
|
||||
### Destructors should not block. [FIXME: needs RFC]
|
||||
|
||||
Similarly, destructors should not invoke blocking operations, which can make
|
||||
debugging much more difficult. Again, consider providing a separate method for
|
||||
preparing for an infallible, nonblocking teardown.
|
||||
@ -1,12 +0,0 @@
|
||||
% RAII
|
||||
|
||||
Resource Acquisition is Initialization
|
||||
|
||||
> **[FIXME]** Explain the RAII pattern and give best practices.
|
||||
|
||||
### Whenever possible, tie resource access to guard scopes [FIXME]
|
||||
|
||||
> **[FIXME]** Example: Mutex guards guarantee that access to the
|
||||
> protected resource only happens when the guard is in scope.
|
||||
|
||||
`must_use`
|
||||
@ -1,7 +0,0 @@
|
||||
% FFI and platform-specific code **[FIXME]**
|
||||
|
||||
> **[FIXME]** Not sure where this should live.
|
||||
|
||||
When writing cross-platform code, group platform-specific code into a
|
||||
module called `platform`. Avoid `#[cfg]` directives outside this
|
||||
`platform` module.
|
||||
@ -1,19 +0,0 @@
|
||||
% Safety and guarantees
|
||||
|
||||
> **[FIXME]** Is there a better phrase than "strong guarantees" that encompasses
|
||||
> both e.g. memory safety and e.g. data structure invariants?
|
||||
|
||||
A _guarantee_ is a property that holds no matter what client code does, unless
|
||||
the client explicitly opts out:
|
||||
|
||||
* Rust guarantees memory safety and data-race freedom, with `unsafe`
|
||||
blocks as an opt-out mechanism.
|
||||
|
||||
* APIs in Rust often provide their own guarantees. For example, `std::str`
|
||||
guarantees that its underlying buffer is valid utf-8. The `std::path::Path` type
|
||||
guarantees no interior nulls. Both strings and paths provide `unsafe` mechanisms
|
||||
for opting out of these guarantees (and thereby avoiding runtime checks).
|
||||
|
||||
Thinking about guarantees is an essential part of writing good Rust code. The
|
||||
rest of this subsection outlines some cross-cutting principles around
|
||||
guarantees.
|
||||
@ -1,81 +0,0 @@
|
||||
% Library-level guarantees
|
||||
|
||||
Most libraries rely on internal invariants, e.g. about their data, resource
|
||||
ownership, or protocol states. In Rust, broken invariants cannot produce
|
||||
segfaults, but they can still lead to wrong answers.
|
||||
|
||||
### Provide library-level guarantees whenever practical. **[FIXME: needs RFC]**
|
||||
|
||||
Library-level invariants should be turned into guarantees whenever
|
||||
practical. They should hold no matter what the client does, modulo
|
||||
explicit opt-outs. Depending on the kind of invariant, this can be
|
||||
achieved through a combination of static and dynamic enforcement, as
|
||||
described below.
|
||||
|
||||
#### Static enforcement:
|
||||
|
||||
Guaranteeing invariants almost always requires _hiding_,
|
||||
i.e. preventing the client from directly accessing or modifying
|
||||
internal data.
|
||||
|
||||
For example, the representation of the `str` type is hidden,
|
||||
which means that any value of type `str` must have been produced
|
||||
through an API under the control of the `str` module, and these
|
||||
APIs in turn ensure valid utf-8 encoding.
|
||||
|
||||
Rust's type system makes it possible to provide guarantees even while
|
||||
revealing more of the representation than usual. For example, the
|
||||
`as_bytes()` method on `&str` gives a _read-only_ view into the
|
||||
underlying buffer, which cannot be used to violate the utf-8 property.
|
||||
|
||||
#### Dynamic enforcement:
|
||||
|
||||
Malformed inputs from the client are hazards to library-level
|
||||
guarantees, so library APIs should validate their input.
|
||||
|
||||
For example, `std::str::from_utf8_owned` attempts to convert a `u8`
|
||||
slice into an owned string, but dynamically checks that the slice is
|
||||
valid utf-8 and returns `Err` if not.
|
||||
|
||||
See
|
||||
[the discussion on input validation](../features/functions-and-methods/input.md)
|
||||
for more detail.
|
||||
|
||||
|
||||
### Prefer static enforcement of guarantees. **[FIXME: needs RFC]**
|
||||
|
||||
Static enforcement provides two strong benefits over dynamic enforcement:
|
||||
|
||||
* Bugs are caught at compile time.
|
||||
* There is no runtime cost.
|
||||
|
||||
Sometimes purely static enforcement is impossible or impractical. In these
|
||||
cases, a library should check as much as possible statically, but defer to
|
||||
dynamic checks where needed.
|
||||
|
||||
For example, the `std::string` module exports a `String` type with the guarantee
|
||||
that all instances are valid utf-8:
|
||||
|
||||
* Any _consumer_ of a `String` is statically guaranteed utf-8 contents. For example,
|
||||
the `append` method can push a `&str` onto the end of a `String` without
|
||||
checking anything dynamically, since the existing `String` and `&str` are
|
||||
statically guaranteed to be in utf-8.
|
||||
|
||||
* Some _producers_ of a `String` must perform dynamic checks. For example, the
|
||||
`from_utf8` function attempts to convert a `Vec<u8>` into a `String`, but
|
||||
dynamically checks that the contents are utf-8.
|
||||
|
||||
### Provide opt-outs with caution; make them explicit. **[FIXME: needs RFC]**
|
||||
|
||||
Providing library-level guarantees sometimes entails inconvenience (for static
|
||||
checks) or overhead (for dynamic checks). So it is sometimes desirable to allow
|
||||
clients to sidestep this checking, while promising to use the API in a way that
|
||||
still provides the guarantee. Such escape hatches should only be introduced when
|
||||
there is a demonstrated need for them.
|
||||
|
||||
It should be trivial for clients to audit their use of the library for
|
||||
escape hatches.
|
||||
|
||||
See
|
||||
[the discussion on input validation](../features/functions-and-methods/input.md)
|
||||
for conventions on marking opt-out functions.
|
||||
@ -1,22 +0,0 @@
|
||||
% Using `unsafe`
|
||||
|
||||
### Unconditionally guarantee safety, or mark API as `unsafe`. **[FIXME: needs RFC]**
|
||||
|
||||
Memory safety, type safety, and data race freedom are basic assumptions for all
|
||||
Rust code.
|
||||
|
||||
APIs that use `unsafe` blocks internally thus have two choices:
|
||||
|
||||
* They can guarantee safety _unconditionally_ (i.e., regardless of client
|
||||
behavior or inputs) and be exported as safe code. Any safety violation is then
|
||||
the library's fault, not the client's fault.
|
||||
|
||||
* They can export potentially unsafe functions with the `unsafe` qualifier. In
|
||||
this case, the documentation should make very clear the conditions under which
|
||||
safety is guaranteed.
|
||||
|
||||
The result is that a client program can never violate safety merely by having a
|
||||
bug; it must have explicitly opted out by using an `unsafe` block.
|
||||
|
||||
Of the two options for using `unsafe`, creating such safe abstractions (the
|
||||
first option above) is strongly preferred.
|
||||
@ -1,5 +0,0 @@
|
||||
% Style
|
||||
|
||||
This section gives a set of strict rules for styling Rust code.
|
||||
|
||||
> **[FIXME]** General remarks about the style guidelines
|
||||
@ -1,77 +0,0 @@
|
||||
% Braces, semicolons, and commas [FIXME: needs RFC]
|
||||
|
||||
### Opening braces always go on the same line.
|
||||
|
||||
```rust,ignore
|
||||
fn foo() {
|
||||
...
|
||||
}
|
||||
|
||||
fn frobnicate(a: Bar, b: Bar,
|
||||
c: Bar, d: Bar)
|
||||
-> Bar {
|
||||
...
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
fn baz(&self);
|
||||
}
|
||||
|
||||
impl Bar for Baz {
|
||||
fn baz(&self) {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
frob(|x| {
|
||||
x.transpose()
|
||||
})
|
||||
```
|
||||
|
||||
### `match` arms get braces, except for single-line expressions.
|
||||
|
||||
```rust,ignore
|
||||
match foo {
|
||||
bar => baz,
|
||||
quux => {
|
||||
do_something();
|
||||
do_something_else()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `return` statements get semicolons.
|
||||
|
||||
```rust,ignore
|
||||
fn foo() {
|
||||
do_something();
|
||||
|
||||
if condition() {
|
||||
return;
|
||||
}
|
||||
|
||||
do_something_else();
|
||||
}
|
||||
```
|
||||
|
||||
### Trailing commas
|
||||
|
||||
> **[FIXME]** We should have a guideline for when to include trailing
|
||||
> commas in `struct`s, `match`es, function calls, etc.
|
||||
>
|
||||
> One possible rule: a trailing comma should be included whenever the
|
||||
> closing delimiter appears on a separate line:
|
||||
|
||||
```rust,ignore
|
||||
Foo { bar: 0, baz: 1 }
|
||||
|
||||
Foo {
|
||||
bar: 0,
|
||||
baz: 1,
|
||||
}
|
||||
|
||||
match a_thing {
|
||||
None => 0,
|
||||
Some(x) => 1,
|
||||
}
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user