17.2 Crates: The Building Blocks of Rust
A crate is Rust’s fundamental unit of compilation. Each crate compiles independently, which means Rust can optimize and link crates with a high degree of control. The compiler treats each crate as either a library (commonly .rlib
) or an executable.
17.2.1 Binary and Library Crates
- Binary Crate: Includes a
main()
function and produces an executable. - Library Crate: Lacks a
main()
function, compiling to a.rlib
(or a dynamic library format if configured). Other crates import this library crate as a dependency.
By default:
- Binary Crate Root:
src/main.rs
- Library Crate Root:
src/lib.rs
17.2.2 The Crate Root
The crate root is the initial source file the compiler processes. Modules declared within this file (or in sub-files) form a hierarchical tree. You can refer to the crate root explicitly with the crate::
prefix.
17.2.3 External Crates and Dependencies
You specify dependencies in your Cargo.toml
under [dependencies]
:
[dependencies]
rand = "0.8"
serde = { version = "1.0", features = ["derive"] }
After this, you can bring external items into scope with use
:
use rand::Rng; fn main() { let mut rng = rand::thread_rng(); let n: u32 = rng.gen_range(1..101); println!("Generated: {}", n); }
The Rust standard library (std
) is always in scope by default; you don’t need to declare it in Cargo.toml
.
17.2.4 Legacy extern crate
Syntax
Prior to Rust 2018, code often used extern crate foo;
to make the crate foo
visible. With modern editions of Rust, this step is unnecessary—Cargo handles this automatically using your Cargo.toml
entries.