Conditional Compilation
Both JavaScript and Rust are providing the possibility for compiling specific code based on external conditions.
JavaScript doesn't support conditional compilation natively. However, it is possible to use some third-party tool like babel-plugin-preprocessor
in order to control conditional compilation.
//#if DEBUG
console.log("Debug");
//#else
console.log("Not debug");
//#endif
An example that uses vanilla JavaScript:
let isDebug = true;
if(isDebug)
{
window.eval(`
console.log("Debug");
`);
} else {
window.eval(`
console.log("Not debug");
`);
}
In addition to predefined symbols, it is also possible to use the compiler option DefineConstants to define symbols that can be used with #if
, #else
, #elif
and #endif
to compile source files conditionally.
In Rust it is possible to use the cfg attribute
, the cfg_attr attribute
or the cfg macro
to control conditional compilation
The cfg attribute
is requiring and evaluating a ConfigurationPredicate
use std::fmt::{Display, Formatter};
struct MyStruct;
// This implementation of Display is only included when the OS is unix but foo is not equal to bar
// You can compile an executable for this version, on linux, with 'rustc main.rs --cfg foo=\"baz\"'
#[cfg(all(unix, not(foo = "bar")))]
impl Display for MyStruct {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("Running without foo=bar configuration")
}
}
// This function is only included when both unix and foo=bar are defined
// You can compile an executable for this version, on linux, with 'rustc main.rs --cfg foo=\"bar\"'
#[cfg(all(unix, foo = "bar"))]
impl Display for MyStruct {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("Running with foo=bar configuration")
}
}
// This function is panicking when not compiled for unix
// You can compile an executable for this version, on windows, with 'rustc main.rs'
#[cfg(not(unix))]
impl Display for MyStruct {
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
panic!()
}
}
fn main() {
println!("{}", MyStruct);
}
The cfg_attr attribute
conditionally includes attributes based on a configuration predicate.
#[cfg_attr(feature = "serialization_support", derive(Serialize, Deserialize))]
pub struct MaybeSerializableStruct;
// When the `serialization_support` feature flag is enabled, the above will expand to:
// #[derive(Serialize, Deserialize)]
// pub struct MaybeSerializableStruct;
The built-in cfg macro
takes in a single configuration predicate and evaluates to the true literal when the predicate is true and the false literal when it is false.
if cfg!(unix) {
println!("I'm running on a unix machine!");
}
See also:
Features
Conditional compilation is also helpful when there is a need for providing optional dependencies. With cargo "features", a package defines a set of named features in the [features]
table of Cargo.toml, and each feature can either be enabled or disabled. Features for the package being built can be enabled on the command-line with flags such as --features
. Features for dependencies can be enabled in the dependency declaration in Cargo.toml.
See also: