blob: 32ff74e8f7d5954b0ce13addc904e11bb127bcbe [file] [log] [blame] [view]
% Cargo Guide
Welcome to the Cargo guide. This guide will give you all that you need to know
about how to use Cargo to develop Rust projects.
# Why Cargo exists
Cargo is a tool that allows Rust projects to declare their various
dependencies and ensure that youll always get a repeatable build.
To accomplish this goal, Cargo does four things:
* Introduces two metadata files with various bits of project information.
* Fetches and builds your projects dependencies.
* Invokes `rustc` or another build tool with the correct parameters to build your project.
* Introduces conventions to make working with Rust projects easier.
# Creating a new project
To start a new project with Cargo, use `cargo new`:
```shell
$ cargo new hello_world --bin
```
Were passing `--bin` because were making a binary program: if we
were making a library, wed leave it off. This also initializes a new `git`
repository by default. If you don't want it to do that, pass `--vcs none`.
Let’s check out what Cargo has generated for us:
```shell
$ cd hello_world
$ tree .
.
├── Cargo.toml
└── src
└── main.rs
1 directory, 2 files
```
If we had just used `cargo new hello_world` without the `--bin` flag, then
we would have a `lib.rs` instead of a `main.rs`. For now, however, this is all
we need to get started. First, let’s check out `Cargo.toml`:
```toml
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
```
This is called a **manifest**, and it contains all of the metadata that Cargo
needs to compile your project.
Here’s what’s in `src/main.rs`:
```
fn main() {
println!("Hello, world!");
}
```
Cargo generated a “hello world” for us. Let’s compile it:
<pre><code class="language-shell"><span class="gp">$</span> cargo build
<span style="font-weight: bold"
class="s1"> Compiling</span> hello_world v0.1.0 (file:///path/to/project/hello_world)</code></pre>
And then run it:
```shell
$ ./target/debug/hello_world
Hello, world!
```
We can also use `cargo run` to compile and then run it, all in one step (You
won't see the `Compiling` line if you have not made any changes since you last
compiled):
<pre><code class="language-shell"><span class="gp">$</span> cargo run
<span style="font-weight: bold"
class="s1"> Compiling</span> hello_world v0.1.0 (file:///path/to/project/hello_world)
<span style="font-weight: bold"
class="s1"> Running</span> `target/debug/hello_world`
Hello, world!</code></pre>
You’ll now notice a new file, `Cargo.lock`. It contains information about our
dependencies. Since we don’t have any yet, it’s not very interesting.
Once you’re ready for release, you can use `cargo build --release` to compile your files with optimizations turned on:
<pre><code class="language-shell"><span class="gp">$</span> cargo build --release
<span style="font-weight: bold"
class="s1"> Compiling</span> hello_world v0.1.0 (file:///path/to/project/hello_world)</code></pre>
`cargo build --release` puts the resulting binary in
`target/release` instead of `target/debug`.
Compiling in debug mode is the default for development-- compilation time is
shorter since the compiler doesn't do optimizations, but the code will run
slower. Release mode takes longer to compile, but the code will run faster.
# Working on an existing Cargo project
If you download an existing project that uses Cargo, it’s really easy
to get going.
First, get the project from somewhere. In this example, we’ll use `rand`
cloned from its repository on GitHub:
```sh
$ git clone https://github.com/rust-lang-nursery/rand.git
$ cd rand
```
To build, use `cargo build`:
<pre><code class="language-shell"><span class="gp">$</span> cargo build
<span style="font-weight: bold" class="s1"> Compiling</span> rand v0.1.0 (file:///path/to/project/rand)</code></pre>
This will fetch all of the dependencies and then build them, along with the
project.
# Adding dependencies from crates.io
[crates.io] is the Rust community's central repository that serves
as a location to discover and download packages. `cargo` is configured to use
it by default to find requested packages.
To depend on a library hosted on [crates.io], add it to your `Cargo.toml`.
[crates.io]: https://crates.io/
## Adding a dependency
If your `Cargo.toml` doesn't already have a `[dependencies]` section, add that,
then list the crate name and version that you would like to use. This example
adds a dependency of the `time` crate:
```toml
[dependencies]
time = "0.1.12"
```
The version string is a [semver] version requirement. The [specifying
dependencies](specifying-dependencies.html) docs have more information about
the options you have here.
[semver]: https://github.com/steveklabnik/semver#requirements
If we also wanted to add a dependency on the `regex` crate, we would not need
to add `[dependencies]` for each crate listed. Here's what your whole
`Cargo.toml` file would look like with dependencies on the `time` and `regex`
crates:
```toml
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
[dependencies]
time = "0.1.12"
regex = "0.1.41"
```
Re-run `cargo build`, and Cargo will fetch the new dependencies and all of
their dependencies, compile them all, and update the `Cargo.lock`:
<pre><code class="language-shell"><span class="gp">$</span> cargo build
<span style="font-weight: bold" class="s1"> Updating</span> registry `https://github.com/rust-lang/crates.io-index`
<span style="font-weight: bold" class="s1"> Downloading</span> memchr v0.1.5
<span style="font-weight: bold" class="s1"> Downloading</span> libc v0.1.10
<span style="font-weight: bold" class="s1"> Downloading</span> regex-syntax v0.2.1
<span style="font-weight: bold" class="s1"> Downloading</span> memchr v0.1.5
<span style="font-weight: bold" class="s1"> Downloading</span> aho-corasick v0.3.0
<span style="font-weight: bold" class="s1"> Downloading</span> regex v0.1.41
<span style="font-weight: bold" class="s1"> Compiling</span> memchr v0.1.5
<span style="font-weight: bold" class="s1"> Compiling</span> libc v0.1.10
<span style="font-weight: bold" class="s1"> Compiling</span> regex-syntax v0.2.1
<span style="font-weight: bold" class="s1"> Compiling</span> memchr v0.1.5
<span style="font-weight: bold" class="s1"> Compiling</span> aho-corasick v0.3.0
<span style="font-weight: bold" class="s1"> Compiling</span> regex v0.1.41
<span style="font-weight: bold" class="s1"> Compiling</span> hello_world v0.1.0 (file:///path/to/project/hello_world)</code></pre>
Our `Cargo.lock` contains the exact information about which revision of all of
these dependencies we used.
Now, if `regex` gets updated, we will still build with the same revision until
we choose to `cargo update`.
You can now use the `regex` library using `extern crate` in `main.rs`.
```
extern crate regex;
use regex::Regex;
fn main() {
let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
println!("Did our date match? {}", re.is_match("2014-01-01"));
}
```
Running it will show:
<pre><code class="language-shell"><span class="gp">$</span> cargo run
<span style="font-weight: bold" class="s1"> Running</span> `target/hello_world`
Did our date match? true</code></pre>
# Project layout
Cargo uses conventions for file placement to make it easy to dive into a new
Cargo project:
```shell
.
├── Cargo.lock
├── Cargo.toml
├── benches
│   └── large-input.rs
├── examples
│   └── simple.rs
├── src
│   ├── bin
│   │   └── another_executable.rs
│   ├── lib.rs
│   └── main.rs
└── tests
└── some-integration-tests.rs
```
* `Cargo.toml` and `Cargo.lock` are stored in the root of your project.
* Source code goes in the `src` directory.
* The default library file is `src/lib.rs`.
* The default executable file is `src/main.rs`.
* Other executables can be placed in `src/bin/*.rs`.
* Integration tests go in the `tests` directory (unit tests go in each file they're testing).
* Examples go in the `examples` directory.
* Benchmarks go in the `benches` directory.
These are explained in more detail in the [manifest
description](manifest.html#the-project-layout).
# Cargo.toml vs Cargo.lock
`Cargo.toml` and `Cargo.lock` serve two different purposes. Before we talk
about them, here’s a summary:
* `Cargo.toml` is about describing your dependencies in a broad sense, and is written by you.
* `Cargo.lock` contains exact information about your dependencies. It is maintained by Cargo and should not be manually edited.
If you’re building a library that other projects will depend on, put
`Cargo.lock` in your `.gitignore`. If you’re building an executable like a
command-line tool or an application, check `Cargo.lock` into `git`. If you're
curious about why that is, see ["Why do binaries have `Cargo.lock` in version
control, but not libraries?" in the
FAQ](faq.html#why-do-binaries-have-cargolock-in-version-control-but-not-libraries).
Let’s dig in a little bit more.
`Cargo.toml` is a **manifest** file in which we can specify a bunch of
different metadata about our project. For example, we can say that we depend
on another project:
```toml
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
[dependencies]
rand = { git = "https://github.com/rust-lang-nursery/rand.git" }
```
This project has a single dependency, on the `rand` library. We’ve stated in
this case that we’re relying on a particular Git repository that lives on
GitHub. Since we haven’t specified any other information, Cargo assumes that
we intend to use the latest commit on the `master` branch to build our project.
Sound good? Well, there’s one problem: If you build this project today, and
then you send a copy to me, and I build this project tomorrow, something bad
could happen. There could be more commits to `rand` in the meantime, and my
build would include new commits while yours would not. Therefore, we would
get different builds. This would be bad because we want reproducible builds.
We could fix this problem by putting a `rev` line in our `Cargo.toml`:
```toml
[dependencies]
rand = { git = "https://github.com/rust-lang-nursery/rand.git", rev = "9f35b8e" }
```
Now our builds will be the same. But there’s a big drawback: now we have to
manually think about SHA-1s every time we want to update our library. This is
both tedious and error prone.
Enter the `Cargo.lock`. Because of its existence, we don’t need to manually
keep track of the exact revisions: Cargo will do it for us. When we have a
manifest like this:
```toml
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
[dependencies]
rand = { git = "https://github.com/rust-lang-nursery/rand.git" }
```
Cargo will take the latest commit and write that information out into our
`Cargo.lock` when we build for the first time. That file will look like this:
```toml
[root]
name = "hello_world"
version = "0.1.0"
dependencies = [
"rand 0.1.0 (git+https://github.com/rust-lang-nursery/rand.git#9f35b8e439eeedd60b9414c58f389bdc6a3284f9)",
]
[[package]]
name = "rand"
version = "0.1.0"
source = "git+https://github.com/rust-lang-nursery/rand.git#9f35b8e439eeedd60b9414c58f389bdc6a3284f9"
```
You can see that there’s a lot more information here, including the exact
revision we used to build. Now when you give your project to someone else,
they’ll use the exact same SHA, even though we didn’t specify it in our
`Cargo.toml`.
When we’re ready to opt in to a new version of the library, Cargo can
re-calculate the dependencies and update things for us:
```shell
$ cargo update # updates all dependencies
$ cargo update -p rand # updates just “rand”
```
This will write out a new `Cargo.lock` with the new version information. Note
that the argument to `cargo update` is actually a
[Package ID Specification](pkgid-spec.html) and `rand` is just a short
specification.
# Tests
Cargo can run your tests with the `cargo test` command. Cargo looks for tests
to run in two places: in each of your `src` files and any tests in `tests/`.
Tests in your `src` files should be unit tests, and tests in `tests/` should be
integration-style tests. As such, you’ll need to import your crates into
the files in `tests`.
Here's an example of running `cargo test` in our project, which currently has
no tests:
<pre><code class="language-shell"><span class="gp">$</span> cargo test
<span style="font-weight: bold"
class="s1"> Compiling</span> rand v0.1.0 (https://github.com/rust-lang-nursery/rand.git#9f35b8e)
<span style="font-weight: bold"
class="s1"> Compiling</span> hello_world v0.1.0 (file:///path/to/project/hello_world)
<span style="font-weight: bold"
class="s1"> Running</span> target/test/hello_world-9c2b65bbb79eabce
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
</code></pre>
If our project had tests, we would see more output with the correct number of
tests.
You can also run a specific test by passing a filter:
<pre><code class="language-shell"><span class="gp">$</span> cargo test foo
</code></pre>
This will run any test with `foo` in its name.
`cargo test` runs additional checks as well. For example, it will compile any
examples you’ve included and will also test the examples in your
documentation. Please see the [testing guide][testing] in the Rust
documentation for more details.
[testing]: https://doc.rust-lang.org/book/testing.html
## Travis CI
To test your project on Travis CI, here is a sample `.travis.yml` file:
```
language: rust
rust:
- stable
- beta
- nightly
matrix:
allow_failures:
- rust: nightly
```
This will test all three release channels, but any breakage in nightly
will not fail your overall build. Please see the [Travis CI Rust
documentation](https://docs.travis-ci.com/user/languages/rust/) for more
information.
# Further reading
Now that you have an overview of how to use cargo and have created your first crate, you may be interested in:
* [Publishing your crate on crates.io](crates-io.html)
* [Reading about all the possible ways of specifying dependencies](specifying-dependencies.html)
* [Learning more details about what you can specify in your `Cargo.toml` manifest](manifest.html)
Even more topics are available in the Docs menu at the top!