tezvyn:

Rust `cfg`: Compile Code for Specific Targets

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

Rust's `cfg` attribute acts like a compile-time switch, including or excluding code based on the target platform or features. It's used for cross-platform support (e.g., Windows vs. Unix) or enabling optional dependencies.

WHY IT EXISTS Programs often need to behave differently depending on the environment they're compiled for. A server running on Linux needs different system calls than a desktop app on Windows. Conditional compilation provides a clean, built-in way to manage this complexity without cluttering the code with runtime checks for things that are known before the program even runs.

THE MENTAL MODEL Think of cfg as a set of compile-time gates. Before the compiler builds the final binary, it checks these gates. If a gate's condition is true (e.g., the target is unix), the code it guards is included. If the condition is false, the code is completely ignored, as if it were commented out. This applies to functions, structs, modules, or even single expressions.

HOW IT WORKS You apply the #[cfg(...)] attribute to a piece of code. Inside the parentheses is a configuration predicate. This can be a simple name like #[cfg(unix)], a key-value pair like #[cfg(target_arch = "aarch64")], or a combination using any(), all(), and not(). For example, #[cfg(all(unix, target_pointer_width = "64"))] means "only compile this for 64-bit Unix-like systems." These configuration options are set by the compiler based on the target triple (e.g., target_os) or passed manually with the --cfg flag, often managed by Cargo's features system.

WHEN TO USE IT Use cfg for platform-specific code, like different implementations for file I/O on Windows versus Linux. It's also the standard way to handle optional features. For instance, you can provide serialization support via Serde but only compile it if a user enables the serde feature for your crate, avoiding an unnecessary dependency for users who don't need it.

WHEN NOT TO USE IT Do not use cfg for logic that needs to be decided at runtime. If your program's behavior depends on user input, a configuration file, or a network response, use a standard if/else block. cfg is strictly for compile-time decisions. Using it for runtime logic is a fundamental misunderstanding of its purpose, as the excluded code doesn't even exist in the final binary.

ONE CANONICAL EXAMPLE A common pattern is providing different function implementations for different operating systems. For a function get_home_dir(), you could have two versions. One is decorated with #[cfg(unix)] and contains the logic for Linux and macOS. The other is decorated with #[cfg(windows)] and contains the logic for Windows. When you compile on Linux, only the unix version of get_home_dir is included in the binary. When you compile on Windows, only the windows version is included. The compiler ensures that exactly one version exists for any given target.

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.