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.