Cargo and Package Management

Packages and Crates

In Rust terminology, a crate is a single compilation unit passed to rustc (producing either a library or an executable binary), whereas a package is a bundle of one or more crates defined by a single Cargo.toml file.

+-------------------------------------------------------------------+
|                     Cargo Package (`Cargo.toml`)                  |
|                                                                   |
|  +---------------------------+   +-----------------------------+  |
|  |   Library Crate (Max 1)   |   |  Binary Crates (0 or more)  |  |
|  |   Crate Root: src/lib.rs  |   |  - src/main.rs              |  |
|  |   Produces: libmy_pkg.rlib|   |  - src/bin/worker.rs        |  |
|  +---------------------------+   |  - src/bin/migrator.rs      |  |
|                ^                 +-----------------------------+  |
|                |                                |                 |
|                +------ Links automatically -----+                 |
+-------------------------------------------------------------------+

Rules Connecting Packages, Crates, and Modules

Concept Definition Cardinality & Rules
Module (mod) A namespace unit inside a crate controlling item paths and privacy (pub). A crate contains a tree of 1 or more modules rooted at the crate root (lib.rs or main.rs). Does not define a compilation boundary on its own.
Crate A single compilation unit compiled by one invocation of rustc. Either a library crate (--crate-type lib) or a binary crate (--crate-type bin).
Package A Cargo.toml manifest and all the targets it builds. Must contain at least 1 crate (library or binary), at most 1 library crate, and any number of binary crates.
Workspace A collection of related packages sharing a single Cargo.lock and target/ directory. Contains 1 or more member packages.

How Binary Crates Use the Package's Library Crate

When a package contains both src/lib.rs and src/main.rs (say, in a package named image-tools), Cargo compiles two separate crates:

  1. First, Cargo compiles src/lib.rs as the library crate image_tools.
  2. Second, Cargo compiles src/main.rs as the binary crate image-tools, linking image_tools as an external crate dependency.

Note that src/main.rs must import items from src/lib.rs using the library crate's public name (use image_tools::...)—not crate::...—because src/main.rs has its own separate crate root!

// Simulating the separation between the library crate and binary crate root:
pub mod image_tools_lib {
    #[derive(Debug, PartialEq, Eq)]
    pub struct Dimensions {
        pub width: u32,
        pub height: u32,
    }

    pub fn aspect_ratio(dim: &Dimensions) -> f64 {
        f64::from(dim.width) / f64::from(dim.height)
    }
}

fn main() {
    // In `src/main.rs`, the binary imports public items from the library crate:
    use image_tools_lib::{Dimensions, aspect_ratio};

    let hd = Dimensions {
        width: 1920,
        height: 1080,
    };
    println!("1920x1080 aspect ratio: {:.4}", aspect_ratio(&hd));
}
1920x1080 aspect ratio: 1.7778

All Target Crate Types inside a Single Package

A single Cargo package can contain up to five kinds of compilation targets:

  1. Library ([lib]): src/lib.rs (at most one).
  2. Binaries ([[bin]]): src/main.rs and src/bin/*.rs.
  3. Examples ([[example]]): examples/*.rs (compiled with cargo build --examples or run via cargo run --example <name>).
  4. Integration Tests ([[test]]): tests/*.rs (compiled during cargo test).
  5. Benchmarks ([[bench]]): benches/*.rs (compiled during cargo bench).