Skip to content

Commit

Permalink
Auto merge of rust-lang#27265 - steveklabnik:rollup, r=steveklabnik
Browse files Browse the repository at this point in the history
  • Loading branch information
bors committed Jul 24, 2015
2 parents 5e6b534 + 427238c commit 82d40cb
Show file tree
Hide file tree
Showing 14 changed files with 409 additions and 38 deletions.
4 changes: 4 additions & 0 deletions src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1636,6 +1636,10 @@ The type of a function declared in an extern block is `extern "abi" fn(A1, ...,
An) -> R`, where `A1...An` are the declared types of its arguments and `R` is
the declared return type.

It is valid to add the `link` attribute on an empty extern block. You can use
this to satisfy the linking requirements of extern blocks elsewhere in your code
(including upstream crates) instead of adding the attribute to each extern block.

## Visibility and Privacy

These two terms are often used interchangeably, and what they are attempting to
Expand Down
2 changes: 1 addition & 1 deletion src/doc/trpl/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
* [No stdlib](no-stdlib.md)
* [Intrinsics](intrinsics.md)
* [Lang items](lang-items.md)
* [Link args](link-args.md)
* [Advanced linking](advanced-linking.md)
* [Benchmark Tests](benchmark-tests.md)
* [Box Syntax and Patterns](box-syntax-and-patterns.md)
* [Slice Patterns](slice-patterns.md)
Expand Down
151 changes: 151 additions & 0 deletions src/doc/trpl/advanced-linking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
% Advanced Linking

The common cases of linking with Rust have been covered earlier in this book,
but supporting the range of linking possibilities made available by other
languages is important for Rust to achieve seamless interaction with native
libraries.

# Link args

There is one other way to tell `rustc` how to customize linking, and that is via
the `link_args` attribute. This attribute is applied to `extern` blocks and
specifies raw flags which need to get passed to the linker when producing an
artifact. An example usage would be:

``` no_run
#![feature(link_args)]
#[link_args = "-foo -bar -baz"]
extern {}
# fn main() {}
```

Note that this feature is currently hidden behind the `feature(link_args)` gate
because this is not a sanctioned way of performing linking. Right now `rustc`
shells out to the system linker (`gcc` on most systems, `link.exe` on MSVC),
so it makes sense to provide extra command line
arguments, but this will not always be the case. In the future `rustc` may use
LLVM directly to link native libraries, in which case `link_args` will have no
meaning. You can achieve the same effect as the `link-args` attribute with the
`-C link-args` argument to `rustc`.

It is highly recommended to *not* use this attribute, and rather use the more
formal `#[link(...)]` attribute on `extern` blocks instead.

# Static linking

Static linking refers to the process of creating output that contain all
required libraries and so don't need libraries installed on every system where
you want to use your compiled project. Pure-Rust dependencies are statically
linked by default so you can use created binaries and libraries without
installing the Rust everywhere. By contrast, native libraries
(e.g. `libc` and `libm`) usually dynamically linked, but it is possible to
change this and statically link them as well.

Linking is a very platform dependent topic — on some platforms, static linking
may not be possible at all! This section assumes some basic familiarity with
linking on your platform of choice.

## Linux

By default, all Rust programs on Linux will link to the system `libc` along with
a number of other libraries. Let's look at an example on a 64-bit Linux machine
with GCC and `glibc` (by far the most common `libc` on Linux):

``` text
$ cat example.rs
fn main() {}
$ rustc example.rs
$ ldd example
linux-vdso.so.1 => (0x00007ffd565fd000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa81889c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa81867e000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fa818475000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa81825f000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa817e9a000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa818cf9000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa817b93000)
```

Dynamic linking on Linux can be undesirable if you wish to use new library
features on old systems or target systems which do not have the required
dependencies for your program to run.

Static linking is supported via an alternative `libc`, `musl` - this must be
enabled at Rust compile-time with some prerequisites available. You can compile
your own version of Rust with `musl` enabled and install it into a custom
directory with the instructions below:

```text
$ mkdir musldist
$ PREFIX=$(pwd)/musldist
$
$ # Build musl
$ wget http://www.musl-libc.org/releases/musl-1.1.10.tar.gz
[...]
$ tar xf musl-1.1.10.tar.gz
$ cd musl-1.1.10/
musl-1.1.10 $ ./configure --disable-shared --prefix=$PREFIX
[...]
musl-1.1.10 $ make
[...]
musl-1.1.10 $ make install
[...]
musl-1.1.10 $ cd ..
$ du -h musldist/lib/libc.a
2.2M musldist/lib/libc.a
$
$ # Build libunwind.a
$ wget http://llvm.org/releases/3.6.1/llvm-3.6.1.src.tar.xz
$ tar xf llvm-3.6.1.src.tar.xz
$ cd llvm-3.6.1.src/projects/
llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libcxxabi/trunk/ libcxxabi
llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libunwind/trunk/ libunwind
llvm-3.6.1.src/projects $ sed -i 's#^\(include_directories\).*$#\0\n\1(../libcxxabi/include)#' libunwind/CMakeLists.txt
llvm-3.6.1.src/projects $ mkdir libunwind/build
llvm-3.6.1.src/projects $ cd libunwind/build
llvm-3.6.1.src/projects/libunwind/build $ cmake -DLLVM_PATH=../../.. -DLIBUNWIND_ENABLE_SHARED=0 ..
llvm-3.6.1.src/projects/libunwind/build $ make
llvm-3.6.1.src/projects/libunwind/build $ cp lib/libunwind.a $PREFIX/lib/
llvm-3.6.1.src/projects/libunwind/build $ cd cd ../../../../
$ du -h musldist/lib/libunwind.a
164K musldist/lib/libunwind.a
$
$ # Build musl-enabled rust
$ git clone https://github.com/rust-lang/rust.git muslrust
$ cd muslrust
muslrust $ ./configure --target=x86_64-unknown-linux-musl --musl-root=$PREFIX --prefix=$PREFIX
muslrust $ make
muslrust $ make install
muslrust $ cd ..
$ du -h musldist/bin/rustc
12K musldist/bin/rustc
```

You now have a build of a `musl`-enabled Rust! Because we've installed it to a
custom prefix we need to make sure our system can the binaries and appropriate
libraries when we try and run it:

```text
$ export PATH=$PREFIX/bin:$PATH
$ export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH
```

Let's try it out!

```text
$ echo 'fn main() { println!("hi!"); panic!("failed"); }' > example.rs
$ rustc --target=x86_64-unknown-linux-musl example.rs
$ ldd example
not a dynamic executable
$ ./example
hi!
thread '<main>' panicked at 'failed', example.rs:1
```

Success! This binary can be copied to almost any Linux machine with the same
machine architecture and run without issues.

`cargo build` also permits the `--target` option so you should be able to build
your crates as normal. However, you may need to recompile your native libraries
against `musl` before they can be linked against.
25 changes: 0 additions & 25 deletions src/doc/trpl/link-args.md

This file was deleted.

18 changes: 18 additions & 0 deletions src/doc/trpl/while-loops.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,24 @@ for x in 0..10 {
}
```

You may also encounter situations where you have nested loops and need to
specify which one your `break` or `continue` statement is for. Like most
other languages, by default a `break` or `continue` will apply to innermost
loop. In a sitation where you would like to a `break` or `continue` for one
of the outer loops, you can use labels to specify which loop the `break` or
`continue` statement applies to. This will only print when both `x` and `y` are
odd:

```rust
'outer: for x in 0..10 {
'inner: for y in 0..10 {
if x % 2 == 0 { continue 'outer; } // continues the loop over x
if y % 2 == 0 { continue 'inner; } // continues the loop over y
println!("x: {}, y: {}", x, y);
}
}
```

Both `continue` and `break` are valid in both `while` loops and [`for` loops][for].

[for]: for-loops.html
8 changes: 8 additions & 0 deletions src/libcore/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,10 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeTo<Idx> {
/// The `Deref` trait is used to specify the functionality of dereferencing
/// operations like `*v`.
///
/// `Deref` also enables ['`Deref` coercions'][coercions].
///
/// [coercions]: ../../book/deref-coercions.html
///
/// # Examples
///
/// A struct with a single field which is accessible via dereferencing the
Expand Down Expand Up @@ -1111,6 +1115,10 @@ impl<'a, T: ?Sized> Deref for &'a mut T {
/// The `DerefMut` trait is used to specify the functionality of dereferencing
/// mutably like `*v = 1;`
///
/// `DerefMut` also enables ['`Deref` coercions'][coercions].
///
/// [coercions]: ../../book/deref-coercions.html
///
/// # Examples
///
/// A struct with a single field which is modifiable via dereferencing the
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,9 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
Some(def::DefVariant(enum_def, variant_def, _)) => {
(lookup_variant_by_id(tcx, enum_def, variant_def), None)
}
Some(def::DefStruct(_)) => {
return Ok(ConstVal::Struct(e.id))
}
_ => (None, None)
};
let const_expr = match const_expr {
Expand Down
4 changes: 1 addition & 3 deletions src/librustc_back/target/bitrig_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ pub fn opts() -> TargetOptions {
linker_is_gnu: true,
has_rpath: true,
position_independent_executables: true,
pre_link_args: vec!(
),
archive_format: "bsd".to_string(),
archive_format: "gnu".to_string(),

.. Default::default()
}
Expand Down
51 changes: 50 additions & 1 deletion src/librustc_borrowck/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,56 @@

register_long_diagnostics! {

E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:
```
fn foo() -> Box<Fn(u32) -> u32> {
let x = 0u32;
Box::new(|y| x + y)
}
```
Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be unsafe.
Another situation where this might be encountered is when spawning threads:
```
fn foo() {
let x = 0u32;
let y = 1u32;
let thr = std::thread::spawn(|| {
x + y
});
}
```
Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behaviour is safe, and so won't let us do it.
The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:
```
fn foo() -> Box<Fn(u32) -> u32> {
let x = 0u32;
Box::new(move |y| x + y)
}
```
Now that the closure has its own copy of the data, there's no need to worry
about safety.
"##,

E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:
Expand All @@ -28,7 +78,6 @@ used.
}

register_diagnostics! {
E0373, // closure may outlive current fn, but it borrows {}, which is owned by current fn
E0382, // use of partially/collaterally moved value
E0383, // partial reinitialization of uninitialized structure
E0384, // reassignment of immutable variable
Expand Down
53 changes: 51 additions & 2 deletions src/librustc_resolve/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,57 @@ use something_which_doesnt_exist;
Please verify you didn't misspell the import's name.
"##,

E0437: r##"
Trait impls can only implement associated types that are members of the trait in
question. This error indicates that you attempted to implement an associated
type whose name does not match the name of any associated type in the trait.
Here is an example that demonstrates the error:
```
trait Foo {}
impl Foo for i32 {
type Bar = bool;
}
```
The solution to this problem is to remove the extraneous associated type:
```
trait Foo {}
impl Foo for i32 {}
```
"##,

E0438: r##"
Trait impls can only implement associated constants that are members of the
trait in question. This error indicates that you attempted to implement an
associated constant whose name does not match the name of any associated
constant in the trait.
Here is an example that demonstrates the error:
```
#![feature(associated_consts)]
trait Foo {}
impl Foo for i32 {
const BAR: bool = true;
}
```
The solution to this problem is to remove the extraneous associated constant:
```
trait Foo {}
impl Foo for i32 {}
```
"##

}

register_diagnostics! {
Expand Down Expand Up @@ -468,6 +519,4 @@ register_diagnostics! {
E0432, // unresolved import
E0434, // can't capture dynamic environment in a fn item
E0435, // attempt to use a non-constant value in a constant
E0437, // type is not a member of trait
E0438, // const is not a member of trait
}
Loading

0 comments on commit 82d40cb

Please sign in to comment.