On this page
Cargo.toml Deep Dive
Cargo.toml is more than just "listing dependencies"—features handle conditional compilation and optional functionality, profiles control optimization levels for debug/release builds, and build scripts execute arbitrary code before compilation (generating bindings, compiling C libraries). The correct way to write each configuration corresponds to a common pitfall.
[dependencies]: Version Specification
[dependencies]
serde = "1" # ^1.0.0: >=1.0.0, <2.0.0 (semver compatible)
tokio = { version = "1", features = ["full"] }
anyhow = "1.0" # ^1.0.0
[dev-dependencies]
criterion = "0.5" # Only available in tests/benches
[build-dependencies]
cc = "1" # Only available in build.rs
[target.'cfg(target_os = "linux")'.dependencies]
x11 = "2" # Linux only
Version Rules: Cargo uses semver (Semantic Versioning). "1.2.3" = exact match, ^1.2.3 (default) = >=1.2.3 and <2.0.0. Cargo.lock pins exact versions—library crates should not commit the lockfile, while binary crates should.
[features]: Conditional Compilation
[features]
default = ["std", "tls"]
std = []
tls = ["tokio", "rustls"] # Activates tokio + rustls
json = ["serde", "serde_json"]
nightly = []
Usage: cargo build --no-default-features --features "json,nightly". Features are additive—you can only add code, not remove it. Two independent features cannot conflict with each other.
[profile]: Compilation Optimization
[profile.release]
opt-level = 3 # Maximum optimization (0-3, s=size, z=size aggressively)
lto = "fat" # Link-Time Optimization
codegen-units = 1 # Single codegen unit → more inlining, slower compilation
panic = "abort" # No unwinding (smaller binary, suitable for embedded)
[profile.dev]
opt-level = 0 # Fast compilation, no optimization
debug = true
Release Configuration Trade-offs: opt-level=3 + lto=fat + codegen-units=1 = smallest and fastest binary, but longest compilation time (possibly 10-30 minutes). Use defaults for daily development (opt-level=3, thin lto, codegen-units=16), and highest settings in CI.
[workspace.dependencies]: Shared Versions
# root Cargo.toml:
[workspace.dependencies]
serde = "1"
tokio = "1"
[dependencies]
serde = { workspace = true } # References the workspace version
This feature (1.64+) solves the classic problem of "inconsistent dependency versions across multiple crates"—upgrading serde requires changing only one place.
build.rs: Compile-Time Scripts
// build.rs — executed **before** Cargo compiles the main code:
build.rs is commonly used for: compiling C/C++ dependencies, detecting system libraries, code generation (protobuf, OpenAPI), and setting environment variables. Output is in the OUT_DIR environment variable—managed by Cargo, no manual cleanup needed.
References
- Cargo Book: doc.rust-lang.org/cargo
- The Cargo Book: profiles, features, build scripts
Keywords: Cargo.toml, features, dependencies, profile, LTO, build.rs, workspace