Search code examples
rustconditional-compilation

Using conditionally compiled module under `cfg` macro


I wonder how to use a conditionally compiled module under cfg! macro. I am trying this:

pub fn f() { ... }

#[cfg(feature = "x")]
pub mod xmodule {
   pub fn f() { ... }
}

pub fn test() {
  if cfg!(feature = "x") {
    xmodule::f();
  } else {
    f();
  }; 
}

It works fine when I compile it with cargo check --features x, but if I don't enable the feature it fails with the following error:

use of undeclared type or module `xmodule`

Am I doing something wrong or the compilation is not smart enough to understand that the module should not be used if the feature is not set?


Solution

  • While the #[cfg] attribute will conditionally compile code, cfg! is gives the equivalent boolean value (e.g. true if a feature is enabled, false otherwise). So your code essentially compiles into:

    pub fn test() {
      if false { // assuming "x" feature is not set
        xmodule::f();
      } else {
        f();
      }; 
    }
    

    Therefore both branches must still contain valid code, even if only one is ever run.

    To get actual conditional compilation, you may do something like this:

    pub fn test() {
      #[cfg(feature = "x")]
      fn inner() {
        xmodule::f()
      }
    
      #[cfg(not(feature = "x"))]
      fn inner() {
        f()
      }
    
      inner();
    }
    

    Playground example

    Or you can use a third-party macro like cfg-if:

    use cfg_if::cfg_if;
    
    pub fn test() {
      cfg_if! {
        if #[cfg(feature = "x")] {
          xmodule::f();
        } else {
          f();
        }
      }
    }
    

    Playground example