Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@
- [Library](crates/lib.md)
- [`extern crate`](crates/link.md)

- [Cargo](cargo.md)
- [Dependencies](cargo/deps.md)
- [Conventions](cargo/conventions.md)
- [Tests](cargo/test.md)

- [Attributes](attribute.md)
- [`dead_code`](attribute/unused.md)
- [Crates](attribute/crate.md)
Expand Down
12 changes: 12 additions & 0 deletions src/cargo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Cargo

`cargo` is the official Rust package management tool. It has lots of really
useful features to improve code quality and developer velocity! These include

- Dependency management and integration with [crates.io](https://crates.io) (the
official Rust package registry)
- Awareness of unit tests
- Awareness of benchmarks

This chapter will go through some quick basics, but you can find the
comprehensive docs [here](http://doc.crates.io/index.html).
36 changes: 36 additions & 0 deletions src/cargo/conventions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Conventions

In the previous chapter, we saw the following directory heirarcy:

```txt
foo
├── Cargo.toml
└── src
└── main.rs
```

Suppose that we wanted to have two binaries in the same project, though. What
then?

It turns out that cargo supports this. The default binary name is `main.rs`, as
we saw before, but you can add additional binaries by placing them in a `bin/`
directory:

```txt
foo
├── Cargo.toml
└── src
├── main.rs
└── bin
└── my_other_bin.rs
```

To tell cargo to compile or run this binary as opposed to the default or other
binaries, we just pass cargo the `--bin my_other_bin` flag, where `my_other_bin`
is the name of the binary we want to work with.

In addition to extra binaries, there is support for benchmarks, tests, and
examples. The full capaibilities are documented
[here](http://doc.crates.io/book/guide/project-layout.html).

In the next chapter, we will look more closely at tests.
88 changes: 88 additions & 0 deletions src/cargo/deps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Dependencies

Most programs have dependencies on some libraries. If you have ever managed
dependencies by hand, you know how much of a pain this. Luckily, the Rust
ecosystem comes standard with `cargo`! `cargo` can manage dependcies for a
project.

To create a new Rust project,

```sh
# A binary
cargo new --bin foo

# OR A library
cargo new foo
```

For the rest of this chapter, I will assume we are making a binary, rather than
a library, but all of the concepts are the same.

After the above commands, you should see something like this:

```txt
foo
├── Cargo.toml
└── src
└── main.rs
```

The `main.rs` is the root source file for your new project -- nothing new there.
The `Cargo.toml` is the config file for `cargo` for this project (`foo`). If you
look inside it, you should see something like this:

```toml
[package]
name = "foo"
version = "0.1.0"
authors = ["mark"]

[dependencies]
```

You can read more extensively about all of the available configuration options
[here](http://doc.crates.io/manifest.html).

The `name` field under `package` determines the name of the project. This is
used by `crates.io` if you publish the crate (more later). It is also the name
of the output binary when you compile.

The `version` field is a crate version number using [Semantic
Versioning](http://semver.org/).

The `authors` field is a list of authors used when publishing the crate.

The `dependencies` section lets you add a dependency for your project.

For example, suppose that I want my program to have a great CLI. You can find
lots of great packages on [crates.io](https://crates.io) (the official Rust
package registry). One popular choice is [clap](https://crates.io/crates/clap).
As of this writing, the most recent published version of `clap` is `2.27.1`. To
add a dependency to our program, we can simply add the following to our
`Cargo.toml` under `dependencies`: `clap = "2.27.1"`. And of course, `extern
crate clap` in `main.rs`, just like normal. And that's it! You can start using
`clap` in your program.

`cargo` also supports other types of dependencies. Here is just a small
sampling. You can find out more
[here](http://doc.crates.io/specifying-dependencies.html).

```toml
[package]
name = "foo"
version = "0.1.0"
authors = ["mark"]

[dependencies]
clap = "2.27.1" # from crates.io
rand = { git = "https://github.com/rust-lang-nursery/rand" } # from online repo
bar = { path = "../bar" } # from a path in the local filesystem
```

To build our project we can execute `cargo build` anywhere in the project
directory (including subdirectories!). We can also do `cargo run` to build and
run. Notice that these commands will resolve all dependencies, download crates
if needed, and build everything, including your crate. (Note that it only
rebuilds what it has not already built, similar to `make`).

Voila! That's all there is too it!
69 changes: 69 additions & 0 deletions src/cargo/test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Testing

As we know testing is integral to any piece of software! Rust has first-class
support for unit and integration testing ([see that chapter for
more](https://rustbyexample.com/meta/test.html); or [this
chapter](https://doc.rust-lang.org/book/second-edition/ch11-00-testing.html) in
TRPL).

From the testing chapters linked above, we see how to write unit tests and
integration tests. Organizationally, we can place unit tests in the modules they
test and integration tests in their own `tests/` directory:

```txt
foo
├── Cargo.toml
├── src
│ └── main.rs
└── tests
├── my_test.rs
└── my_other_test.rs
```

Each file in `tests` is a separate integration test.

`cargo` naturally provides an easy way to run all of your tests!

```sh
cargo test
```

You should see output like this:

```txt
$ cargo test
Compiling blah v0.1.0 (file:///nobackup/blah)
Finished dev [unoptimized + debuginfo] target(s) in 0.89 secs
Running target/debug/deps/blah-d3b32b97275ec472

running 3 tests
test test_bar ... ok
test test_baz ... ok
test test_foo_bar ... ok
test test_foo ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
```

You can also run tests whose name matches a pattern:

```sh
cargo test test_foo
```

```txt
$ cargo test test_foo
Compiling blah v0.1.0 (file:///nobackup/blah)
Finished dev [unoptimized + debuginfo] target(s) in 0.35 secs
Running target/debug/deps/blah-d3b32b97275ec472

running 2 tests
test test_foo ... ok
test test_foo_bar ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out
```

One word of caution: Cargo may run multiple tests concurrently, so make sure
that they don't race with each other. For example, if they all output to a
file, you should make them write to different files.