# The Ecosystem & Tooling - Cargo Does Everything

If you've come from a language where the toolchain is a pile of separate things you bolt together - a build tool here, a package manager there, a formatter you had to be talked into, a test runner with its own config file - Rust's tooling story feels like a vacation. There's basically one tool, **Cargo**, and it does almost everything. It came with your Rust install in [Phase 1](01-install-and-first-program.md), and you'll spend your whole Rust life in it.

The point of this phase isn't to memorize commands - it's to give you the mental model, *what each tool is for and why it exists*, so the commands make sense and you reach for the right one without thinking.

📝 **Terminology.** A **crate** is Rust's word for a package - a library or program. **crates.io** is the public registry where the community publishes crates (like npm for JavaScript or PyPI for Python). A **dependency** is a crate your project uses. *(The backend of this very project - The Missing Manual's search engine - is a Rust crate built and tested with exactly these commands.)*

## Cargo: your one tool

**What it actually is.** Cargo is Rust's build tool *and* package manager *and* test runner, rolled into one. Where other ecosystems make you assemble that toolchain yourself, Rust ships it as a single, opinionated program: every Rust project on earth is built and tested the same way, so you can drop into any repo already knowing the commands.

Here are the four you'll use constantly, each the same `cargo <verb>` shape.

**`cargo build`** - compile your project.
```console
$ cargo build
   Compiling myapp v0.1.0 (/home/you/myapp)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.42s
```
*What just happened:* Cargo compiled your code (and any dependencies not yet built) and dropped the binary in `target/debug/`. "unoptimized + debuginfo" means a fast-to-compile *debug* build, great for development, not shipping. When ready to ship, `cargo build --release` produces an optimized binary in `target/release/` that's much faster to run (and slower to compile). The runtime-overflow check from [Phase 9](09-idioms-and-gotchas.md) is on in debug and off in release, another reason the two profiles exist.

**`cargo run`** - build *and* run in one step.
```console
$ cargo run
   Compiling myapp v0.1.0 (/home/you/myapp)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.40s
     Running `target/debug/myapp`
Hello, world!
```
*What just happened:* `cargo run` is `cargo build` plus "now execute the binary." The command you'll hammer most while developing - edit, `cargo run`, repeat. If nothing changed since the last build, it skips straight to "Running" without recompiling.

**`cargo add`** - add a dependency from crates.io.
```console
$ cargo add serde
    Updating crates.io index
      Adding serde v1.0.219 to dependencies
```
*What just happened:* Cargo looked up `serde` (a popular serialization crate) on crates.io, picked a compatible version, and wrote it into `Cargo.toml`. The next `cargo build` downloads and compiles it. Before `cargo add` existed you edited `Cargo.toml` by hand and guessed the version string - now the tool does it correctly.

**`cargo test`** - run your tests (we'll come back to this below).

## `Cargo.toml` and `Cargo.lock`: the manifest and the receipt

**What `Cargo.toml` actually is.** Your project's manifest - a small, human-edited file declaring the project's name, version, and dependencies. After `cargo add serde`, it looks like this:

```text
[package]
name = "myapp"
version = "0.1.0"
edition = "2024"

[dependencies]
serde = "1.0.219"
```
*What just happened:* `[package]` is your project's identity. `[dependencies]` lists the crates you depend on and the version ranges you accept (`"1.0.219"` means "1.0.219 or any compatible 1.x"). This is the file to read and edit to understand or change what a project depends on.

⚠️ **`Cargo.lock` is different - don't hand-edit it.** Alongside `Cargo.toml`, Cargo maintains `Cargo.lock`: the *exact* versions of every dependency (and sub-dependency) actually resolved. Think of `Cargo.toml` as "what I asked for" and `Cargo.lock` as "what I got, precisely." It's auto-generated; commit it (for applications) so teammates and CI build the identical dependency set, but never edit it yourself.

## `rustfmt`: stop arguing about formatting

**What it actually is.** `rustfmt` is the official code formatter. Run `cargo fmt` and it rewrites your code into the standard Rust style - indentation, spacing, line breaks - instantly and consistently.

**Why it exists.** Formatting debates are a waste of a team's life. With one official formatter everyone runs, every codebase looks the same, diffs stay clean, and nobody reviews a PR complaining about brace placement. You stop *thinking* about formatting at all.

```console
$ cargo fmt
```
*What just happened:* It said nothing and changed your files in place - that's success. `cargo fmt` is silent when it works. (In CI, `cargo fmt --check` instead *reports* any unformatted file and exits non-zero, without changing anything - that's how teams enforce it.) Run it before every commit and formatting stops being your problem.

## `clippy`: the linter that teaches you Rust

**What it actually is.** Clippy is Rust's linter, genuinely one of the best in any language. Where the compiler tells you what's *wrong*, clippy tells you what's *not idiomatic*: code that works but that an experienced Rust developer would write differently. It's earned its reputation as a patient teacher, since each warning explains the better way and *why*.

```rust
fn main() {
    let name = "world".to_string();
    if name.len() > 0 {
        println!("Hello, {}", name);
    }
}
```
```console
$ cargo clippy
    Checking myapp v0.1.0 (/home/you/myapp)
warning: length comparison to zero
 --> src/main.rs:3:8
  |
3 |     if name.len() > 0 {
  |        ^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!name.is_empty()`
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.95.0/index.html#len_zero
  = note: `#[warn(clippy::len_zero)]` on by default
```
*What just happened:* The code compiles fine - clippy isn't reporting an error. It's noticing `name.len() > 0` is a roundabout way of saying "not empty," and suggests the clearer `!name.is_empty()`, with a link to a fuller explanation. Follow clippy's advice for a few weeks and you'll absorb idiomatic Rust by osmosis, like a senior reviewer commenting on every line, for free.

💡 **Key point.** The everyday loop: `cargo fmt`, then `cargo clippy`, then `cargo test`, before you commit. Format, lint, verify. Many teams wire all three into CI so nothing un-formatted, un-lint-clean, or un-tested can merge.

## `cargo test`: tests live next to your code

**What it actually is.** Rust has testing built into the language and Cargo - no separate framework to install, no config file. Mark a function `#[test]`, put your tests in a module beside the code they test, and `cargo test` finds and runs them all.

```rust
fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn main() {
    println!("{}", add(2, 2));
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn adds() {
        assert_eq!(add(2, 2), 4);
    }

    #[test]
    fn adds_negatives() {
        assert_eq!(add(-1, -1), -2);
    }
}
```
```console
$ cargo test
   Compiling myapp v0.1.0 (/home/you/myapp)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.13s
     Running unittests src/main.rs (target/debug/deps/myapp-8e8c850d1f800cd0)

running 2 tests
test tests::adds ... ok
test tests::adds_negatives ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```
*What just happened:* Cargo compiled a special test build, found both `#[test]` functions, ran them, and reported each one. `assert_eq!(add(2, 2), 4)` checks the two values are equal and fails the test (with a clear diff) otherwise. `#[cfg(test)]` on the module means "only compile this when testing" - tests add zero weight to your shipped binary. Sitting tests right next to the code they cover is deliberate: writing one is so easy you actually do it.

> ⏭️ This is just enough to run tests. For *how to think about testing* - what to test, how much, and why - see [the Testing category](/guides/) guides.

## Recap

1. **Cargo is the one tool**: `cargo build` (compile), `cargo run` (build + run), `cargo add <crate>` (add a dependency), `cargo test` (run tests).
2. **`Cargo.toml`** is the manifest you edit (name, version, dependencies); **`Cargo.lock`** is the auto-generated exact-versions receipt you commit but don't touch.
3. **crates.io** is the public crate registry; `cargo add` pulls from it and updates `Cargo.toml` for you.
4. **`cargo fmt`** (rustfmt) formats your code to the one standard style - silent when it succeeds.
5. **`cargo clippy`** is the famously helpful linter: it teaches idiomatic Rust by explaining the better way, not just flagging the wrong way.
6. **`cargo test`** runs `#[test]` functions that live right beside your code - testing is built in, no framework required.
