条件编译

语法
ConfigurationPredicate :
      ConfigurationOption
   | ConfigurationAll
   | ConfigurationAny
   | ConfigurationNot

ConfigurationOption :
   IDENTIFIER (= (STRING_LITERAL | RAW_STRING_LITERAL))?

ConfigurationAll
   all ( ConfigurationPredicateList? )

ConfigurationAny
   any ( ConfigurationPredicateList? )

ConfigurationNot
   not ( ConfigurationPredicate )

ConfigurationPredicateList
   ConfigurationPredicate (, ConfigurationPredicate)* ,?

条件编译的源代码是指仅在特定条件下编译的源代码。

可以使用cfgcfg_attr属性以及内置的cfg来使源代码有条件地编译。

是否编译可以取决于被编译 crate 的目标架构、传递给编译器的任意值以及下面进一步描述的其他内容。

每种条件编译形式都采用一个评估为 true 或 false 的配置谓词。 谓词是以下之一

  • 配置选项。如果设置了该选项,则谓词为 true;如果未设置,则为 false。
  • 带有逗号分隔的配置谓词列表的all()。 如果所有给定谓词都为 true,或者列表为空,则为 true。
  • 带有逗号分隔的配置谓词列表的any()。 如果至少一个给定的谓词为 true,则为 true。如果没有谓词,则为 false。
  • 带有配置谓词的not()。 如果其谓词为 false,则为 true;如果其谓词为 true,则为 false。

配置选项可以是名称或键值对,并且已设置或未设置。

名称写为单个标识符,例如 unix

键值对写为标识符、=,然后是一个字符串,例如 target_arch = "x86_64"

注意: = 周围的空格将被忽略,因此 foo="bar"foo = "bar" 是等效的。

键不需要是唯一的。 例如,可以同时设置 feature = "std"feature = "serde"

设置配置选项

哪些配置选项被设置是在 crate 编译期间静态确定的。

某些选项是基于有关编译的数据由编译器设置的。

其他选项是基于在代码之外传递给编译器的输入任意设置的。

无法从正在编译的 crate 的源代码中设置配置选项。

注意:对于 rustc,任意设置的配置选项是使用 --cfg 标志设置的。可以使用 rustc --print cfg --target $TARGET 显示指定目标的配置值。

注意:键为 feature 的配置选项是 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属性

target_feature 选项还提供了 crt-static 的一个附加功能,用于指示存在静态 C 运行时

target_os

使用目标操作系统设置一次的键值选项。 此值类似于平台目标三元组的第二和第三个元素。

示例值

  • "windows"
  • "macos"
  • "ios"
  • "linux"
  • "android"
  • "freebsd"
  • "dragonfly"
  • "openbsd"
  • "netbsd"
  • "none"(嵌入式目标的典型情况)

target_family

键值选项,提供对目标的更通用描述,例如目标通常所属的操作系统或架构系列。 可以设置任意数量的 target_family 键值对。

示例值

  • "unix"
  • "windows"
  • "wasm"
  • "unix""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_abi

键值选项,用于使用有关目标 ABI 的信息进一步消除 target_env 的歧义。

由于历史原因,此值仅在实际需要消除歧义时定义为非空字符串。 因此,例如,在许多 GNU 平台上,此值将为空。

示例值

  • ""
  • "llvm"
  • "eabihf"
  • "abi64"
  • "sim"
  • "macabi"

target_endian

键值选项,使用值“little”或“big”设置一次,具体取决于目标 CPU 的字节序。

target_pointer_width

使用目标指针宽度(以位为单位)设置一次的键值选项。

示例值

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

target_vendor

使用目标供应商设置一次的键值选项。

示例值

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

target_has_atomic

为目标支持原子加载、存储和比较和交换操作的每个位宽度设置的键值选项。

如果存在此 cfg,则所有稳定的core::sync::atomic API 都可用于相关的原子宽度。

可能的值

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

test

在编译测试工具时启用。 通过使用 --test 标志使用 rustc 完成。 有关测试支持的更多信息,请参阅 Testing

debug_assertions

默认情况下,在不进行优化的情况下编译时启用。 这可用于在开发中启用额外的调试代码,但不在生产中使用。 例如,它控制标准库的debug_assert!宏的行为。

proc_macro

当正在编译的 crate 使用 proc_macro crate 类型进行编译时设置。

panic

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

示例值

  • "abort"
  • "unwind"

条件编译的形式

cfg 属性

语法
CfgAttrAttribute :
   cfg ( ConfigurationPredicate )

cfg 属性根据配置谓词有条件地包含它所附加的内容。

它写为 cfg(、一个配置谓词,最后是 )

如果谓词为 true,则该内容将被重写为没有 cfg 属性。 如果谓词为 false,则该内容将从源代码中删除。

当 crate 级别的 cfg 具有 false 谓词时,其行为略有不同:保留 cfg 之前的任何 crate 属性,并删除 cfg 之后的任何 crate 属性。 这使得 #![no_std]#![no_core] crate 即使 #![cfg(...)] 删除了整个 crate,也可以避免链接 std/core

有关函数的示例

#![allow(unused)]
fn main() {
// The function is only included in the build when compiling for macOS
#[cfg(target_os = "macos")]
fn macos_only() {
  // ...
}

// This function is only included when either foo or bar is defined
#[cfg(any(foo, bar))]
fn needs_foo_or_bar() {
  // ...
}

// This function is only included when compiling for a unixish OS with a 32-bit
// architecture
#[cfg(all(unix, target_pointer_width = "32"))]
fn on_32bit_unix() {
  // ...
}

// This function is only included when foo is not defined
#[cfg(not(foo))]
fn needs_not_foo() {
  // ...
}

// This function is only included when the panic strategy is set to unwind
#[cfg(panic = "unwind")]
fn when_unwinding() {
  // ...
}

}

cfg 属性允许出现在允许属性的任何位置。

cfg_attr 属性

语法
CfgAttrAttribute :
   cfg_attr ( ConfigurationPredicate , CfgAttrs? )

CfgAttrs :
   Attr (, Attr)* ,?

cfg_attr 属性根据配置谓词有条件地包含 属性

当配置谓词为 true 时,此属性会扩展为谓词之后列出的属性。 例如,以下模块将根据目标在 linux.rswindows.rs 中找到。

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

可以列出零个、一个或多个属性。 多个属性将分别扩展为单独的属性。 例如

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

// When the `magic` feature flag is enabled, the above will expand to:
#[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 属性允许出现在允许属性的任何位置。

crate_typecrate_name 属性不能与 cfg_attr 一起使用。

cfg

内置的 cfg 宏接受单个配置谓词,并在谓词为 true 时计算为 true 字面量,并在谓词为 false 时计算为 false 字面量。

例如

#![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);
}