Cross-Platform

86. cfg_select! — Compile-Time Match on Platform and Features

Stop stacking #[cfg] blocks that contradict each other — cfg_select! gives you a match-like syntax for conditional compilation, right in the standard library.

The old way: a wall of #[cfg]

When you need platform-specific code, the traditional approach is a series of #[cfg(...)] attributes. It works, but nothing ties the branches together — you can easily miss a platform or accidentally define the same function twice.

1
2
3
4
5
6
7
8
#[cfg(unix)]
fn default_shell() -> &'static str { "/bin/sh" }

#[cfg(windows)]
fn default_shell() -> &'static str { "cmd.exe" }

// Forgot wasm? Forgot the fallback? The compiler won't tell you
// until someone tries to build on an unsupported target.

The fix: cfg_select!

Stabilized in Rust 1.95, cfg_select! works like a compile-time match. The compiler evaluates each cfg predicate top to bottom and emits only the first matching arm. Add a _ wildcard for a catch-all.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
cfg_select! {
    unix => {
        fn default_shell() -> &'static str { "/bin/sh" }
    }
    windows => {
        fn default_shell() -> &'static str { "cmd.exe" }
    }
    _ => {
        fn default_shell() -> &'static str { "sh" }
    }
}

The branches are mutually exclusive by design — exactly one fires. No more worrying about overlapping #[cfg] blocks or missing targets.

It works in expression position too

Need a quick platform-dependent value? Skip the braces:

1
2
3
4
5
6
let path_sep = cfg_select! {
    windows => '\\',
    _ => '/',
};

assert_eq!(path_sep, '/'); // on unix

This is far cleaner than wrapping a let in two separate #[cfg] attributes or pulling in the cfg-if crate.

Why this matters

Before 1.95, the community relied on the cfg-if crate for this exact pattern — it has over 300 million downloads. Now the same functionality ships in std, with one less dependency to track and a syntax the compiler can verify directly.