Sling Academy
Home/Rust/Conditional Compilation with `#[cfg]` Attributes in Rust

Conditional Compilation with `#[cfg]` Attributes in Rust

Last updated: January 03, 2025

Rust, as a systems programming language, is designed with both performance and safety in mind. One of its powerful features is the ability to use conditional compilation via #[cfg] attributes. This feature enables code to be compiled or omitted based on certain conditions, which proves particularly useful when targeting different platforms or providing optional features.

What is Conditional Compilation?

Conditional compilation allows the programmer to include or exclude parts of the code based on the configuration options specified at compile time. Rust's #[cfg] attribute facilitates this by evaluating boolean expressions written in terms of features, OS targets, and other configurations.

Basic Usage of #[cfg] Attributes

The #[cfg] attribute checks if a condition is true, and if so, compiles the block of code tagged with it.

#[cfg(target_os = "linux")]
fn are_you_on_linux() {
    println!("You are running Linux!");
}

#[cfg(target_os = "windows")]
fn are_you_on_windows() {
    println!("You are running Windows!");
}

In the above example, are_you_on_linux is only compiled if the target operating system is Linux, while are_you_on_windows is compiled if the target is Windows.

Combining #[cfg] Conditions

Conditions can be combined using any or all with a comma-separated list of conditions within parentheses.

#[cfg(any(target_os = "linux", target_os = "macos"))]
fn are_you_on_unix() {
    println!("You are on a Unix-like OS!");
}

#[cfg(all(feature = "foo", target_os = "linux"))]
fn foo_feature_on_linux() {
    println!("Feature 'foo' enabled on Linux.");
}

In this example, are_you_on_unix is only compiled if the target OS is either Linux or macOS. The foo_feature_on_linux function demonstrates a feature flag foo that should be true along with the target OS being Linux for it to be compiled.

Negation with not and cfg! macro

You may use not to negate conditions and the cfg! macro to evaluate conditions in the same way, but within runtime logic:

fn print_message() {
    if cfg!(target_os = "linux") {
        println!("Compiled for a Linux target.");
    } else {
        println!("Not compiled for Linux.");
    }
}

#[cfg(not(feature = "foo"))]
fn default_foo_logic() {
    println!("The 'foo' feature is not enabled.");
}

Here, default_foo_logic only compiles when the feature foo is not enabled.

Platform-Specific Configuration

The Rust Standard Library uses #[cfg] extensively to support platform-specific code.

#[cfg(unix)]
mod unix_specific {
    pub fn run_unix_code() {
        println!("Running Unix-specific code.");
    }
}

#[cfg(windows)]
mod windows_specific {
    pub fn run_windows_code() {
        println!("Running Windows-specific code.");
    }
}

This pattern allows Rust codebases to seamlessly incorporate OS-specific functions and modules. Therefore, using Rust’s #[cfg] attributes allows you to target different environments effortlessly while maintaining readability and modularity of your codebase.

Conclusion

This flexibility offered by #[cfg] attributes makes Rust a versatile language for building cross-platform applications. By understanding and leveraging these conditional compilation techniques, developers can write clear, modular, and adaptable code to handle diverse execution environments. Rust provides this capability in a clean, syntactically powerful manner, reinforcing its suitability for concurrent software development and systems programming.

Next Article: Combining Pattern Matching with Logical Operators in Rust

Previous Article: Dealing with Error Cases Using `return Err(...)` in Rust

Series: Control Flow in Rust

Rust

You May Also Like

  • E0557 in Rust: Feature Has Been Removed or Is Unavailable in the Stable Channel
  • Network Protocol Handling Concurrency in Rust with async/await
  • Using the anyhow and thiserror Crates for Better Rust Error Tests
  • Rust - Investigating partial moves when pattern matching on vector or HashMap elements
  • Rust - Handling nested or hierarchical HashMaps for complex data relationships
  • Rust - Combining multiple HashMaps by merging keys and values
  • Composing Functionality in Rust Through Multiple Trait Bounds
  • E0437 in Rust: Unexpected `#` in macro invocation or attribute
  • Integrating I/O and Networking in Rust’s Async Concurrency
  • E0178 in Rust: Conflicting implementations of the same trait for a type
  • Utilizing a Reactor Pattern in Rust for Event-Driven Architectures
  • Parallelizing CPU-Intensive Work with Rust’s rayon Crate
  • Managing WebSocket Connections in Rust for Real-Time Apps
  • Downloading Files in Rust via HTTP for CLI Tools
  • Mocking Network Calls in Rust Tests with the surf or reqwest Crates
  • Rust - Designing advanced concurrency abstractions using generic channels or locks
  • Managing code expansion in debug builds with heavy usage of generics in Rust
  • Implementing parse-from-string logic for generic numeric types in Rust
  • Rust.- Refining trait bounds at implementation time for more specialized behavior