tezvyn:

Rust Cargo Features: Conditional Compilation & Dependencies

AI-drafted, machine-checkedSource: doc.rust-lang.orgadvanced

Cargo features are compile-time switches for conditional compilation and optional dependencies. They let you build tailored versions of a crate from one source, like an image library that only includes code for the formats you need.

WHY IT EXISTS Cargo features solve the problem of monolithic libraries. Without them, a crate would have to include all its code and dependencies for every possible use case, leading to slower compile times and larger binaries. Features allow a single crate to be flexible, serving many needs without forcing every user to pay the cost for functionality they don't use.

THE MENTAL MODEL Think of Cargo features as compile-time switches or optional toppings on a pizza. You declare in your Cargo.toml which features you want to enable for a dependency. The compiler then includes only the code and dependencies associated with those switches, giving you a customized build of the crate tailored to your exact needs.

HOW IT WORKS Features are defined in a package's Cargo.toml file under the [features] table. Each feature is a name that maps to an array of other features or optional dependencies it enables. In your Rust code, you use the #[cfg(feature = "your_feature")] attribute to mark code that should only be compiled when that feature is active. Dependencies can be marked as optional with optional = true, which implicitly creates a feature of the same name. To avoid this, or to group dependencies under a different name, you can use the dep:dependency_name syntax inside a feature definition.

WHEN TO USE IT Use features to provide optional functionality, such as serialization support via a serde feature. They are ideal for crates that support multiple formats (like an image library with png, jpeg, and webp features) or need to gate platform-specific code. They also allow you to offer different performance trade-offs by enabling or disabling certain optimizations.

WHEN NOT TO USE IT Features are for compile-time configuration, not runtime choices. If a user needs to decide between options while the program is running, use standard language constructs like enums or trait objects. Avoid using features for mutually exclusive options, as this can lead to confusing build failures if a user accidentally enables both.

ONE CANONICAL EXAMPLE An image processing library, image-lib, wants to support PNG and WebP formats, but not force all users to compile both. It defines two features in its Cargo.toml: png = ["dep:png_crate"] and webp = ["dep:webp_crate"]. A user who only needs PNG support would declare the dependency as: image-lib = { version = "1.0", default-features = false, features = ["png"] }. This command ensures only the PNG-related code and its dependencies are compiled, resulting in a smaller, faster build.

Read the original → doc.rust-lang.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.