Interpolate `ident` in string literal in `macro_rules!`

Viewed 823

Is it possible to interpolate a macro_rules! variable, of type ident, into a string literal in a macro? In other words is it possible to "escape" the double quotes of the literal?

// `trace_macros!` requires nightly
#![feature(trace_macros)]
trace_macros!(true);

macro_rules! export_mod_if_feature {
    ($system:ident) => {
        #[cfg(target_os = "$system")] // <-- problem is here
        pub mod $system;
    };
}

export_mod_if_feature!(linux);

// ... should translate to:
#[cfg(target_os = "linux")]
pub mod linux;

// ... but instead it becomes:
#[cfg(target_os = "$system")]
pub mod linux;`

I have tried using #[cfg(target_os = stringify!($system))] but the cfg requires an actual string literal after target_os =, not just a compile-time string.

2 Answers

Since the cfg attribute expects a literal and the pub mod expects a ident, I think you can use two values as the input of your macro and match one as a literal metavariable and the other as a ident metavariable. This would be more flexible when the names of the feature and the module are different.

#![feature(trace_macros)]
trace_macros!(true);

macro_rules! export_mod_if_feature {
    ($system:literal, $module:ident) => {
        #[cfg(target_os = $system)]
        pub mod $module;
    };
}

export_mod_if_feature!("linux", linux);

Playground

Related