条件编译

语法
配置断言 :
      配置选项
   | 配置All
   | 配置Any
   | 配置Not

配置选项 :
   标识符 (= (字符串字面值 | 原始字符串字面值))?

配置All
   all ( 配置断言列表? )

配置Any
   any ( 配置断言列表? )

配置Not
   not ( 配置断言 )

配置断言列表
   配置断言 (, 配置断言)* ,?

条件编译源码 是指根据某些条件来排除部分源码,或者包含部分源码。

条件编译,使用内置的 cfg cfg_attr 属性cfg 来实现。 条件包括: 编译 crate 时的目标架构、传递给编译器的参数,其他一些可选项。

条件编译会进行 配置断言 ,断言的结果为 true 或 false 。 断言有以下几种形式:

  • 配置选项: 如果该选项被设置则为 true ,否则为 false 。
  • all() : 以逗号分隔的配置断言列表。如果至少有一项断言为 false ,则结果为 false 。如果没有断言,则为 true 。
  • any() : 以逗号分隔的配置断言列表。如果至少有一项断言为 true ,则结果为 true 。如果没有断言,则为 false 。
  • not() : 有一个配置断言。如果其断言为 false ,则为 true ,如果其断言为 true ,则为 false 。

配置选项 是被设置或未设置的名称与键值对。 名称是单个标识符,例如 unix 。 键值对是一个标识符,后跟一个字符串 。 例如, target_arch = "x86_64" 配置选项。

注意: 等号周围的空白将被忽略。 foo="bar"foo = "bar" 是等价的配置选项。

键在键值对配置选项的集合中不是唯一的。例如,可以同时设置 feature = "std"feature = "serde"

设置配置选项

哪些配置选项被设置是在编译期确定。 某些配置选项是由编译器的状态来确定,称为编译器设置。 其他选项由用户设置,非源码中,而由外部输入给编译器。 正在编译的 crate 无法通过源码设置配置选项。

注意: 对于 rustc ,用户输入的配置选项可以使用 --cfg 标志设置。

注意: 键为 feature 的配置选项通常通过 Cargo 配置清单设置,可参阅 Cargo 文档。

警告:输入的配置选项有可能与编译器的值相同。 例如,在 Windows 平台编译目标时输入 rustc --cfg "unix" program.rs,这将同时设置 unixwindows 配置选项。 这不是一个良好的做法。

target_arch

目标 CPU 架构。 该值类似于 '目标平台三元组' 的第一个元素,但并不完全一致。

示例值:

  • "x86"
  • "x86_64"
  • "mips"
  • "powerpc"
  • "powerpc64"
  • "arm"
  • "aarch64"

target_feature

当前编译目标平台所提供的特性。

示例值:

  • "avx"
  • "avx2"
  • "crt-static"
  • "rdrand"
  • "sse"
  • "sse2"
  • "sse4.1"

详见 target_feature 属性crt-static 表示可用的 静态 C 运行时库

target_os

是编译时目标平台操作系统,仅可设定一次。 该值类似于 '平台目标三元组' 的第二个和第三个元素。

示例值:

  • "windows"
  • "macos"
  • "ios"
  • "linux"
  • "android"
  • "freebsd"
  • "dragonfly"
  • "openbsd"
  • "netbsd"

target_family

是目标平台更一般的描述,目标平台所处的操作系统或体系结构。 该键可以设置多个。

示例值:

  • "unix"
  • "windows"
  • "wasm"

unixwindows

如果设置了 target_family = "unix",则意味着 unix 被设置。 如果设置了 target_family = "windows",则意味着 windows 被设置。

target_env

是目标平台进一步的区分信息,例如有关所使用的 ABI 或 libc 的信息。 由于历史原因,只有在实际需要区分时,此值才会被定义为非空字符串。 因而,比如在许多 GNU 平台上,此值将为空。此值类似于平台目标三元组的第四个元素。 有所不同的是,像 gnueabihf 这样的嵌入式 ABI 将简单地将 target_env 定义为 "gnu"

示例值:

  • ""
  • "gnu"
  • "msvc"
  • "musl"
  • "sgx"

target_endian

用于描述目标平台的字节序,取值为 "little" 或 "big" ,即 '大端' 或 '小端' ,根据目标机器的 CPU 决定。

target_pointer_width

该值只设置一次,为目标平台的指针宽度 (以位为单位) 。

示例值:

  • "16"
  • "32"
  • "64"

target_vendor

该值只设置一次,其键是目标平台的供应商 (vendor) 。

示例值:

  • "apple"
  • "fortanix"
  • "pc"
  • "unknown"

target_has_atomic

目标平台支持每个比特宽度原子加载、存储和比较交换操作时,将设置该值。

当这个配置项存在时,所有适用于相关原子宽度的稳定的 core::sync::atomic API 可用。

可能值:

  • "8"
  • "16"
  • "32"
  • "64"
  • "128"
  • "ptr"

test

该值在执行测试时启用,即 rustc 添加 --test 标志。 可参阅 测试 部分。

debug_assertions

在未开启优化时,默认启用。 这可以用于在开发时包含额外的调试代码,发布时排除。 比如,标准库中 debug_assert! 宏的行为受到该值控制。

proc_macro

当编译的 crate 时,使用 proc_macro crate 类型 而设置。

panic

根据 panic 策略而设置。需注意,将来可能会添加更多可选值。

示例值:

  • "abort"
  • "unwind"

条件编译的形式

cfg 属性

语法
CfgAttr属性 :
   cfg ( 配置断言 )

cfg 属性 根据 配置断言 决定是否排除所附着的条目。

语法为 cfg ( 配置断言 )

如果断言为 true,则将重新编写所附条目,移除 cfg 属性。 如果断言为 false,则排除对应条目源码。

一些示例:

#![allow(unused)]
fn main() {
// 仅为 macOS 平台编译时,包含该函数源码。
#[cfg(target_os = "macos")]
fn macos_only() {
  // ...
}

// 只有在定义了 foo 或 bar 的时,包含该函数源码
#[cfg(any(foo, bar))]
fn needs_foo_or_bar() {
  // ...
}

// 只有在 32 位架构的 unixish 操作系统编译时,包含该函数源码。
#[cfg(all(unix, target_pointer_width = "32"))]
fn on_32bit_unix() {
  // ...
}

// 只有未定义 foo 的情况下,包含该函数源码。
#[cfg(not(foo))]
fn needs_not_foo() {
  // ...
}

// 仅在恐慌策略被设置为 unwind 时,包含该函数源码。
#[cfg(panic = "unwind")]
fn when_unwinding() {
  // ...
}

}

cfg 属性可在任何允许属性的位置使用。

cfg_attr 属性

语法
CfgAttr属性 :
   cfg_attr ( _配置断言 , CfgAttr组? )

CfgAttr组 :
   Attr (, Attr)* ,?

cfg_attr 属性 可根据条件断言来选择性为所属条目添加其他属性。

当配置断言为真,将展开断言部分后面所列出的属性。 例如,以下模块将基于目标平台在 linux.rswindows.rs 中找到:

#[cfg_attr(target_os = "linux", path = "linux.rs")]
#[cfg_attr(windows, path = "windows.rs")]
mod os;

所列出的属性可以是 0 个、 1 个或多个。多个属性将会分别展开为单独的属性。比如:

#[cfg_attr(feature = "magic", sparkles, crackles)]
fn bewitched() {}

// 当 `magic` 特性标志启用时,上述源码将展开为:
#[sparkles]
#[crackles]
fn bewitched() {}

注意: cfg_attr 可以去展开另一个 cfg_attr 。 比如, #[cfg_attr(target_os = "linux", cfg_attr(feature = "multithreaded", some_other_attribute))] 是有效的。 这个例子等价于 #[cfg_attr(all(target_os = "linux", feature ="multithreaded"), some_other_attribute)]

cfg_attr 属性可在任何允许属性的地方使用。

cfg

内置的 cfg 宏经过配置断言,展开为 truefalse 的字面值源码。

示例:

#![allow(unused)]
fn main() {
let machine_kind = if cfg!(unix) {
  "unix"
} else if cfg!(windows) {
  "windows"
} else {
  "unknown"
};

println!("I'm running on a {} machine!", machine_kind);
}