diff --git a/doc/rust.md b/doc/rust.md index 969e40e632a..92d9cb3ae38 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -2070,6 +2070,38 @@ The currently implemented features of the compiler are: closure as `once` is unlikely to be supported going forward. So they are hidden behind this feature until they are to be removed. +* `managed_boxes` - Usage of `@` pointers is gated due to many + planned changes to this feature. In the past, this has meant + "a GC pointer", but the current implementation uses + reference counting and will likely change drastically over + time. Additionally, the `@` syntax will no longer be used to + create GC boxes. + +* `asm` - The `asm!` macro provides a means for inline assembly. This is often + useful, but the exact syntax for this feature along with its semantics + are likely to change, so this macro usage must be opted into. + +* `non_ascii_idents` - The compiler supports the use of non-ascii identifiers, + but the implementation is a little rough around the + edges, so this can be seen as an experimental feature for + now until the specification of identifiers is fully + fleshed out. + +* `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 + LLVM's implementation which works in concert with the kernel + loader and dynamic linker. This is not necessarily available + on all platforms, and usage of it is discouraged (rust + focuses more on task-local data instead of thread-local + data). + +* `link_args` - This attribute is used to specify custom flags to the linker, + but usage is strongly discouraged. The compiler's usage of the + system linker is not guaranteed to continue in the future, and + if the system linker is not used then specifying custom flags + doesn't have much meaning. + 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 @@ -3611,6 +3643,111 @@ queues, as well as code to copy values between queues and their recipients and to serialize values for transmission over operating-system inter-process communication facilities. +### Linkage + +The Rust compiler supports various methods to link crates together both +statically and dynamically. This section will explore the various methods to +link Rust crates together, and more information about native libraries can be +found in the [ffi tutorial][ffi]. + +In one session of compilation, the compiler can generate multiple artifacts +through the usage of command line flags and the `crate_type` attribute. + +* `--bin`, `#[crate_type = "bin"]` - A runnable executable will be produced. + This requires that there is a `main` function in the crate which will be run + when the program begins executing. This will link in all Rust and native + dependencies, producing a distributable binary. + +* `--lib`, `#[crate_type = "lib"]` - A Rust library will be produced. This is + an ambiguous concept as to what exactly is produced because a library can + manifest itself in several forms. The purpose of this generic `lib` option is + to generate the "compiler recommended" style of library. The output library + will always be usable by rustc, but the actual type of library may change + from time-to-time. The remaining output types are all different flavors of + libraries, and the `lib` type can be seen as an alias for one of them (but + the actual one is compiler-defined). + +* `--dylib`, `#[crate_type = "dylib"]` - A dynamic Rust library will be + produced. This is different from the `lib` output type in that this forces + dynamic library generation. The resulting dynamic library can be used as a + dependency for other libraries and/or executables. This output type will + create `*.so` files on linux, `*.dylib` files on osx, and `*.dll` files on + windows. + +* `--staticlib`, `#[crate_type = "staticlib"]` - A static system library will + be produced. This is different from other library outputs in that the Rust + compiler will never attempt to link to `staticlib` outputs. The purpose of + this output type is to create a static library containing all of the local + crate's code along with all upstream dependencies. The static library is + actually a `*.a` archive on linux and osx and a `*.lib` file on windows. This + format is recommended for use in situtations such as linking Rust code into an + existing non-Rust application because it will not have dynamic dependencies on + other Rust code. + +* `--rlib`, `#[crate_type = "rlib"]` - A "Rust library" file will be produced. + This is used as an intermediate artifact and can be thought of as a "static + Rust library". These `rlib` files, unlike `staticlib` files, are interpreted + by the Rust compiler in future linkage. This essentially means that `rustc` + will look for metadata in `rlib` files like it looks for metadata in dynamic + libraries. This form of output is used to produce statically linked + executables as well as `staticlib` outputs. + +Note that these outputs are stackable in the sense that if multiple are +specified, then the compiler will produce each form of output at once without +having to recompile. + +With all these different kinds of outputs, if crate A depends on crate B, then +the compiler could find B in various different forms throughout the system. The +only forms looked for by the compiler, however, are the `rlib` format and the +dynamic library format. With these two options for a dependent library, the +compiler must at some point make a choice between these two formats. With this +in mind, the compiler follows these rules when determining what format of +dependencies will be used: + +1. If a dynamic library is being produced, then it is required for all upstream + Rust dependencies to also be dynamic. This is a limitation of the current + implementation of the linkage model. The reason behind this limitation is to + prevent multiple copies of the same upstream library from showing up, and in + the future it is planned to support a mixture of dynamic and static linking. + + When producing a dynamic library, the compiler will generate an error if an + upstream dependency could not be found, and also if an upstream dependency + could only be found in an `rlib` format. Remember that `staticlib` formats + are always ignored by `rustc` for crate-linking purposes. + +2. If a static library is being produced, all upstream dependecies are + required to be available in `rlib` formats. This requirement stems from the + same reasons that a dynamic library must have all dynamic dependencies. + + Note that it is impossible to link in native dynamic dependencies to a static + library, and in this case warnings will be printed about all unlinked native + dynamic dependencies. + +3. If an `rlib` file is being produced, then there are no restrictions on what + format the upstream dependencies are available in. It is simply required that + all upstream dependencies be available for reading metadata from. + + The reason for this is that `rlib` files do not contain any of their upstream + dependencies. It wouldn't be very efficient for all `rlib` files to contain a + copy of `libstd.rlib`! + +4. If an executable is being produced, then things get a little interesting. As + with the above limitations in dynamic and static libraries, it is required + for all upstream dependencies to be in the same format. The next question is + whether to prefer a dynamic or a static format. The compiler currently favors + static linking over dynamic linking, but this can be inverted with the `-Z + prefer-dynamic` flag to the compiler. + + What this means is that first the compiler will attempt to find all upstream + dependencies as `rlib` files, and if successful, it will create a statically + linked executable. If an upstream dependency is missing as an `rlib` file, + then the compiler will force all dependencies to be dynamic and will generate + errors if dynamic versions could not be found. + +In general, `--bin` or `--lib` should be sufficient for all compilation needs, +and the other options are just available if more fine-grained control is desired +over the output format of a Rust crate. + ### Logging system The runtime contains a system for directing [logging @@ -3762,3 +3899,5 @@ Additional specific influences can be seen from the following languages: * The typeclass system of Haskell. * The lexical identifier rule of Python. * The block syntax of Ruby. + +[ffi]: tutorial-ffi.html diff --git a/doc/tutorial-ffi.md b/doc/tutorial-ffi.md index c4fea5e48c9..f3a72971007 100644 --- a/doc/tutorial-ffi.md +++ b/doc/tutorial-ffi.md @@ -8,13 +8,13 @@ foreign code. Rust is currently unable to call directly into a C++ library, but snappy includes a C interface (documented in [`snappy-c.h`](https://code.google.com/p/snappy/source/browse/trunk/snappy-c.h)). -The following is a minimal example of calling a foreign function which will compile if snappy is -installed: +The following is a minimal example of calling a foreign function which will +compile if snappy is installed: ~~~~ {.xfail-test} use std::libc::size_t; -#[link_args = "-lsnappy"] +#[link(name = "snappy")] extern { fn snappy_max_compressed_length(source_length: size_t) -> size_t; } @@ -25,26 +25,28 @@ fn main() { } ~~~~ -The `extern` block is a list of function signatures in a foreign library, in this case with the -platform's C ABI. The `#[link_args]` attribute is used to instruct the linker to link against the -snappy library so the symbols are resolved. +The `extern` block is a list of function signatures in a foreign library, in +this case with the platform's C ABI. The `#[link(...)]` attribute is used to +instruct the linker to link against the snappy library so the symbols are +resolved. -Foreign functions are assumed to be unsafe so calls to them need to be wrapped with `unsafe {}` as a -promise to the compiler that everything contained within truly is safe. C libraries often expose -interfaces that aren't thread-safe, and almost any function that takes a pointer argument isn't -valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of +Foreign functions are assumed to be unsafe so calls to them need to be wrapped +with `unsafe {}` as a promise to the compiler that everything contained within +truly is safe. C libraries often expose interfaces that aren't thread-safe, and +almost any function that takes a pointer argument isn't valid for all possible +inputs since the pointer could be dangling, and raw pointers fall outside of Rust's safe memory model. -When declaring the argument types to a foreign function, the Rust compiler will not check if the -declaration is correct, so specifying it correctly is part of keeping the binding correct at -runtime. +When declaring the argument types to a foreign function, the Rust compiler can +not check if the declaration is correct, so specifying it correctly is part of +keeping the binding correct at runtime. The `extern` block can be extended to cover the entire snappy API: ~~~~ {.xfail-test} use std::libc::{c_int, size_t}; -#[link_args = "-lsnappy"] +#[link(name = "snappy")] extern { fn snappy_compress(input: *u8, input_length: size_t, @@ -232,9 +234,72 @@ fn main() { # Linking -In addition to the `#[link_args]` attribute for explicitly passing arguments to the linker, an -`extern mod` block will pass `-lmodname` to the linker by default unless it has a `#[nolink]` -attribute applied. +The `link` attribute on `extern` blocks provides the basic building block for +instructing rustc how it will link to native libraries. There are two accepted +forms of the link attribute today: + +* `#[link(name = "foo")]` +* `#[link(name = "foo", kind = "bar")]` + +In both of these cases, `foo` is the name of the native library that we're +linking to, and in the second case `bar` is the type of native library that the +compiler is linking to. There are currently three known types of native +libraries: + +* Dynamic - `#[link(name = "readline")] +* Static - `#[link(name = "my_build_dependency", kind = "static")] +* Frameworks - `#[link(name = "CoreFoundation", kind = "framework")] + +Note that frameworks are only available on OSX targets. + +The different `kind` values are meant to differentiate how the native library +participates in linkage. From a linkage perspective, the rust compiler creates +two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary). +Native dynamic libraries and frameworks are propagated to the final artifact +boundary, while static libraries are not propagated at all. + +A few examples of how this model can be used are: + +* A native build dependency. Sometimes some C/C++ glue is needed when writing + some rust code, but distribution of the C/C++ code in a library format is just + a burden. In this case, the code will be archived into `libfoo.a` and then the + rust crate would declare a dependency via `#[link(name = "foo", kind = + "static")]`. + + Regardless of the flavor of output for the crate, the native static library + will be included in the output, meaning that distribution of the native static + library is not necessary. + +* A normal dynamic dependency. Common system libraries (like `readline`) are + available on a large number of systems, and often a static copy of these + libraries cannot be found. When this dependency is included in a rust crate, + partial targets (like rlibs) will not link to the library, but when the rlib + is included in a final target (like a binary), the native library will be + linked in. + +On OSX, frameworks behave with the same semantics as a dynamic library. + +## The `link_args` attribute + +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: + +~~~ {.xfail-test} +#[link_args = "-foo -bar -baz"] +extern {} +~~~ + +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, 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. + +It is highly recommended to *not* use this attribute, and rather use the more +formal `#[link(...)]` attribute on `extern` blocks instead. # Unsafe blocks @@ -260,7 +325,7 @@ blocks with the `static` keyword: ~~~{.xfail-test} use std::libc; -#[link_args = "-lreadline"] +#[link(name = "readline")] extern { static rl_readline_version: libc::c_int; } @@ -279,7 +344,7 @@ them. use std::libc; use std::ptr; -#[link_args = "-lreadline"] +#[link(name = "readline")] extern { static mut rl_prompt: *libc::c_char; }