7

I am trying to use Rusts feature to conditionally compile a module in my crate and also use it only when a feature is enabled. The conditional compilation works fine when the feature is set, but refuses to compile when the feature is not set.

I use the same feature flag to conditionally import the module in my main so my assumption is that the module shouldn't be imported when the feature isn't used.

#[cfg(feature = "debug")]
pub mod k {
    pub struct S { pub x: i32, pub y: i32}
}

And how I use it in main

pub fn main() {
    if cfg!(feature = "debug") {
        use self::k;
        let _s = k::S {x: 4, y: 5};
    }

    let g = vec![1, 2, 4];
    println!("{:?}", g);
}

If I enable the feature via the --features flag then it compiles as expected:

cargo build --features "debug" 
    Finished dev [unoptimized + debuginfo] target(s) in 0.08s

But when I do not pass the --features it fails and my expectation is that it should skip the block with the cfg! set.

error[E0432]: unresolved import `self::k`
  --> src/main.rs:32:13
   |
32 |         use self::k;
   |             ^^^^^^^ no `k` in the root

error: aborting due to previous error

For more information about this error, try `rustc --explain E0432`.

This is how my Cargo.toml looks like

[features]
default = []
debug = []

Can someone explain why this happens and a better way to conditionally compile such blocks of code ?

hellow
  • 12,430
  • 7
  • 56
  • 79
draklor40
  • 453
  • 7
  • 17
  • Possible duplicate of [How to mark use statements for conditional compilation?](https://stackoverflow.com/questions/54515989/how-to-mark-use-statements-for-conditional-compilation) – Stargateur Apr 04 '19 at 12:17
  • @Stargateur No particular reason. I based my tiny projects on an old template and it seemed to have main public. Fixed it. Thanks for pointing it out. – draklor40 Apr 04 '19 at 12:22
  • @Stargateur Not quite, although I see where I might have made the mistake. The ` if cfg!(feature = "debug") {` would be replaced with something like `if false` during compilation if `debug` is not enabled, but the next 2 lines would still be compiled. However, `mod k` is not compiled as it is compiled only when `feature =debug` is enabled. So the compiler complains about the missing module. I could replace the `if else` with a `#[cfg(feature = "debug")]` followed by a block where I create the structs I need. – draklor40 Apr 04 '19 at 12:25
  • @draklor40 you are right, 'cfg!' evaluates into an expression like and not an attribute – sn99 Apr 04 '19 at 13:13

1 Answers1

2

I can see in the comments that you have found the solution.

But what if you want to create a variable depending on the feature flags?

Here's my idea:

#[cfg(feature = "debug")]
pub mod k {
    pub struct S { pub x: i32, pub y: i32}
}

pub fn main() {
    #[cfg(feature = "debug")]
    let variable = {
        use self::k;
        let _s = k::S {x: 4, y: 5};
        // this is now a struct
        _s
    };

    #[cfg(not(feature = "debug"))]
    let variable = {
        // this is now a string
        String::from("same variable; \
        different data types depending on feature flags")
        
    };

    println!("conditional compilation is cool:\n{:?}", variable);
}

playground

Basically, it's like cfg!(feature = "debug"). The difference is that the things inside cfg! macro must be valid at compile time, meaning data types or method must exist in the current scope to be called.

So you can't use structs that are conditionally compiled inside a cfg!-if statement, for example.

António Ribeiro
  • 4,129
  • 5
  • 32
  • 49
alexzander
  • 1,586
  • 1
  • 9
  • 21