Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

条件编译

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

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

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

每种形式的条件编译都接受一个 配置断言 ,该断言求值为真或假。该断言是以下形式之一:

  • 一个配置选项。如果该选项已设置,则断言为真;如果未设置,则为假。
  • all(),带有一个逗号分隔的配置断言列表。如果所有给定的断言都为真,或者列表为空,则它为真。
  • any(),带有一个逗号分隔的配置断言列表。如果至少有一个给定的断言为真,则它为真。如果没有断言,则它为假。
  • not(),带有一个配置断言。如果其断言为假,则它为真;如果其断言为真,则它为假。
  • truefalse字面量,分别总是为真或假。

配置选项 可以是名称,也可以是键值对,它们要么已设置,要么未设置。

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

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

注意

=周围的空白符会被忽略,所以foo="bar"foo = "bar"是等效的。

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

已设置的配置选项

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

一些选项是 编译器设置的,基于编译的相关数据。

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

无法在被编译的crate的源代码内部设置配置选项。

注意

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

注意

键为feature的配置选项是Cargo用于指定编译时选项和可选依赖项的约定。

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"
  • "sim"
  • "macabi"

target_abi

键值选项,包含关于目标ABI的进一步区分信息。

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

示例值:

  • ""
  • "llvm"
  • "eabihf"
  • "abi64"

target_endian

键值选项,根据目标CPU的字节序设置为"little""big"

target_pointer_width

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

示例值:

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

target_vendor

键值选项,设置为目标供应商一次。

示例值:

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

target_has_atomic

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

当此cfg存在时,所有稳定的core::sync::atomicAPI都可用于相关的原子位宽。

可能的值:

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

test

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

debug_assertions

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

proc_macro

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

panic

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

示例值:

  • "abort"
  • "unwind"

条件编译的形式

cfg属性

cfg属性 根据配置断言有条件地包含其所附加的形式。

例子

#![allow(unused)]
fn main() {
// 该函数只在为 macOS 编译时才会被包含在构建中
#[cfg(target_os = "macos")]
fn macos_only() {
  // ...
}

// 该函数只在 foo 或 bar 被定义时才会被包含
#[cfg(any(foo, bar))]
fn needs_foo_or_bar() {
  // ...
}

// 该函数只在为 32 位架构的类 Unix 操作系统编译时才会被包含
#[cfg(all(unix, target_pointer_width = "32"))]
fn on_32bit_unix() {
  // ...
}

// 该函数只在 foo 未定义时才会被包含
#[cfg(not(foo))]
fn needs_not_foo() {
  // ...
}

// 该函数只在恐慌策略设置为 unwound 时才会被包含
#[cfg(panic = "unwind")]
fn when_unwinding() {
  // ...
}
}

cfg属性的语法是:

Syntax
CfgAttributecfg ( ConfigurationPredicate )

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

cfg属性可以用于一个形式任意多次。如果任何cfg断言为假,则附加了这些属性的形式将不会被包含,cfg.attr.crate-level-attrs中描述的情况除外。

如果断言为真,则该形式将被重写为不带cfg属性。如果任何断言为假,则该形式将从源代码中删除。

当crate级别的cfg有一个假断言时,crate本身仍然存在。任何在cfg之前的crate属性会被保留,而任何在cfg之后的crate属性以及所有后续的crate内容都会被移除。

例子

不移除前面属性的行为允许您执行诸如包含#![no_std]以避免链接std之类的操作,即使#![cfg(...)]已经移除了crate的内容。例如:

// 即使 crate 级别的 `cfg` 属性为 false,此 `no_std` 属性也会被保留。
#![no_std]
#![cfg(false)]

// 该函数未被包含。
pub fn example() {}

cfg_attr属性

cfg_attr属性 根据配置断言有条件地包含属性。

例子

以下模块将根据目标平台,位于linux.rswindows.rs

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

cfg_attr属性的语法是:

Syntax
CfgAttrAttributecfg_attr ( ConfigurationPredicate , CfgAttrs? )

CfgAttrsAttr ( , Attr )* ,?

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

cfg_attr属性可以用于一个形式任意多次。

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

当配置断言为真时,cfg_attr会展开为断言后列出的属性。

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

例子

#[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!宏

内置的cfg!宏接受一个配置断言,并在断言为真时求值为true字面量,在断言为假时求值为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);
}