Multiple consts within single `#[cfg()]`

Hello all,

What is the preferred way to define multiple const values based on a cfg macro? I'm looking for sort of an analog to the C #ifdef/#endif, something like the below:

#[cfg(target_family = "unix")] {
    const PLAT: Plat = Plat::Posix;
    const ENV_PATH_SEP: u8 =  0x3a;   // ":" on Posix
    const SOME_ARR: [u8; 3] = [4u8, 5, 2, 1];
}

#[cfg(target_family = "windows")] {
    const PLAT: Plat = Plat::Windows;
    const ENV_PATH_SEP: u8 = 0x3b; // ";" on Windows
    const SOME_ARR: [u8; 6] = [4u8, 5, 2, 1, 1, 1];
}

Currently the best option I have found is to either repeat the #[cfg] items (messy), or use

const PLAT: Plat = if cfg!(..) {...} else {...}

which doesn't work for arrays, since type with length must be specified before the if block.

I found Tracking issue for stmt_expr_attributes: Add attributes to expressions, etc. · Issue #15701 · rust-lang/rust · GitHub and the (I think) corresponding #![feature(stmt_expr_attributes)], but that seems to only allow the syntax within functions.

What is the current best way to accomplish this?

In Tokio, we define macros as seen here. Then you use them like here.

4 Likes

Thanks for the blazing fast response, that's perfect!

I don't know what the best practice is, but modules are another alternative.

3 Likes

Great suggestion, that's super clean. Thanks

I took Alice's idea and created a macro that allows specifying the macro within the block, possibly useful to others

macro_rules! cfg_block {
    ($( #[$meta:meta] {$($item:item)*} )*) => {
        $($(
            #[$meta]
            $item
        )*)*
    }
}

cfg_block! {
    // Unix config
    #[cfg(not(target_family = "windows"))] {
        const ENV_PATH_SEP: &str = ":";
        const SOME_ARR: [u8; 4] = [4u8, 5, 2, 1];
    }
    // Windows config
    #[cfg(target_family = "windows")] {
        const ENV_PATH_SEP: &str = ";";
        const SOME_ARR: [u8; 2] = [4u8, 5];
    }
}

Just to simplify things,, I created a simple crate in case anyone would like to quickly use the macro: cfg_block - Rust

Also added an if/else syntax that works with #[cfg()] items.

There's a crate for that: https://crates.io/crates/cfg-if

4 Likes

Wow, that's the 5th most downloaded on crates.io.... And I spent two hours trying to replicate it. Should have known I was reinventing the wheel, thanks for the tip

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.