cratosw

条件编译

条件编译

.NET 与 Rust 都支持基于外部条件编译不同代码路径。

在 .NET 中,通常通过 预处理指令 控制条件编译:

#if debug
    Console.WriteLine("Debug");
#else
    Console.WriteLine("Not debug");
#endif

除了预定义符号外,还可以使用编译器选项 DefineConstants 定义自定义符号, 并配合 #if#else#elif#endif 做条件分支编译。

在 Rust 中,可通过 cfg attributecfg_attr attributecfg! macro 实现条件编译。

和 .NET 类似,Rust 除了预定义条件,也可使用编译参数 --cfg 自定义配置选项。

cfg attribute 需要一个 ConfigurationPredicate 并在编译期求值:

use std::fmt::{Display, Formatter};

struct MyStruct;

// 仅在 unix 且 foo != "bar" 时编译该实现
// 在 Linux 下可通过 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")
    }
}

// 仅在 unix 且 foo == "bar" 时编译该实现
// 在 Linux 下可通过 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")
    }
}

// 非 unix 平台编译该实现(此处直接 panic)
#[cfg(not(unix))]
impl Display for MyStruct {
    fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
        panic!()
    }
}

fn main() {
    println!("{}", MyStruct);
}

cfg_attr attribute 可以在条件满足时附加属性:

#[cfg_attr(feature = "serialization_support", derive(Serialize, Deserialize))]
pub struct MaybeSerializableStruct;

// 当启用 serialization_support feature 后,上述代码等价于:
// #[derive(Serialize, Deserialize)]
// pub struct MaybeSerializableStruct;

内置的 cfg! macro 会在编译期判断条件并产出布尔字面量:

if cfg!(unix) {
  println!("I'm running on a unix machine!");
}

另见:

特性(Features)

条件编译也常用于“可选依赖”。在 Cargo 中,包可在 Cargo.toml[features] 里定义命名特性,每个特性都可开启/关闭。构建当前包时可通过 --features 在命令行启用;依赖包的特性则可在依赖声明中配置。

另见:

On this page