Skip to content

0x03 - Cargo

MasakiMu319 ·

In Rust communities, “crate” is often discussed like a package unit. You can think of a package as a project/software package wrapper.

Rust projects commonly involve two crate types:

  • library crates
  • binary crates

cargo new creates a new project. By default it creates an executable binary package (--bin is default and can be omitted).

cargo run compiles in debug mode and then runs. With --release, Rust applies heavy optimization for performance.

mod keyword: declares a module and tells the compiler to include module files.

use keyword: imports types/functions from a module into current scope.

Difference between mod and creating lib.rs

  • Using mod in main.rs: modules are visible only inside the current binary crate. main.rs acts as root of this module tree.
  • Creating lib.rs: defines a library crate. Module hierarchy starts from lib.rs, making code reusable by other crates.

Why does lib.rs reduce many mod declarations in main.rs?

Once modules are declared in lib.rs, main.rs can directly use them without repeating top-level mod declarations. This keeps main.rs focused on entry logic.

Basics

  • cargo new {project} --bin --vcs none: create binary/lib project without auto git init.
  • cargo build: compile in debug mode by default.
  • cargo run: compile in debug mode and run.
  • cargo build --release: compile in release mode; rustc performs optimization.

After pulling a remote Rust project, cargo build will automatically resolve dependencies and build.

Cargo manages dependencies and versions via Cargo.toml (similar role to pyproject.toml in Python). During build, it also generates Cargo.lock (similar idea to uv.lock), containing more specific resolved dependency metadata.

To update dependency versions, run cargo update; otherwise Cargo uses the versions declared/resolved from current configuration.

Cargo Project Layout Conventions

.
├── Cargo.lock
├── Cargo.toml
├── src/
│   ├── lib.rs
│   ├── main.rs
│   └── bin/
│       ├── named-executable.rs
│       ├── another-executable.rs
│       └── multi-file-executable/
│           ├── main.rs
│           └── some_module.rs
├── benches/
│   ├── large-input.rs
│   └── multi-file-bench/
│       ├── main.rs
│       └── bench_module.rs
├── examples/
│   ├── simple.rs
│   └── multi-file-example/
│       ├── main.rs
│       └── ex_module.rs
└── tests/
    ├── some-integration-tests.rs
    └── multi-file-test/
        ├── main.rs
        └── test_module.rs
  • Cargo.toml and Cargo.lock are at package root.
  • Source files live in src.
  • Default library entry: src/lib.rs.
  • Default binary entry: src/main.rs.
    • Additional binaries go in src/bin/.
  • Benchmarks go in benches/.
  • Examples go in examples/.
  • Integration tests go in tests/.

If a binary/example/bench/integration-test has multiple source files, place them in a subdirectory with a main.rs. The executable name follows the folder name.