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!cfg_select! 来实现条件编译源代码。

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

每种条件编译形式都接受一个求值为 true 或 false 的配置谓词。谓词是以下之一:

  • 一个配置选项。如果该选项被设置,则谓词为 true;如果未被设置,则为 false。
  • all() 后跟一个逗号分隔的配置谓词列表。如果所有给定的谓词都为 true,或者列表为空,则为 true。
  • any() 后跟一个逗号分隔的配置谓词列表。如果至少有一个给定的谓词为 true,则为 true。如果没有谓词,则为 false。
  • not() 后跟一个配置谓词。如果其谓词为 false,则为 true;如果其谓词为 true,则为 false。
  • truefalse 字面量,分别始终为 true 或 false。

配置选项是名称或键值对,要么被设置,要么未被设置。

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

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

Note

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

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

设置的配置选项

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

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

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

不可能从正在编译的 crate 的源代码中设置配置选项。

Note

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

Note

键为 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 平台上,此值将是空字符串。该值类似于平台目标三元组的第四个元素。一个区别是嵌入式 ABI(如 gnueabihf)将简单地将 target_env 定义为 "gnu"

示例值:

  • ""
  • "gnu"
  • "msvc"
  • "musl"
  • "sgx"
  • "sim"
  • "macabi"

target_abi

键值选项,设置用于进一步消歧目标的有关目标 ABI 的信息。

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

示例值:

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

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

在编译测试框架时启用。使用 rustc--test 标志完成。更多测试支持信息请参阅测试

debug_assertions

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

proc_macro

当正在编译的 crate 是以 proc_macro crate 类型编译时设置。

panic

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

示例值:

  • "abort"
  • "unwind"

条件编译的形式

cfg 属性

cfg 属性 根据配置谓词有条件地包含其所附着的代码形式。

Example

#![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 类 OS 编译时才包含。
#[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 属性的语法为:

Syntax
CfgAttributecfg ( ConfigurationPredicate )

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

cfg 属性可以在一个代码形式上使用任意多次。如果任何一个 cfg 谓词为 false,则这些属性所附着的代码形式将不会被包含,除非 cfg.attr.crate-level-attrs 中有说明。

如果谓词为 true,则该代码形式被改写为不带 cfg 属性。如果任何谓词为 false,则该代码形式从源代码中被移除。

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

Example

保留前置属性的行为允许你做一些事情,例如包含 #![no_std] 以避免链接 std,即使 #![cfg(...)] 已经移除了 crate 的内容。例如:

// 虽然 crate 级别的 `cfg`
// 属性为 false,此 `no_std` 属性仍然保留。
#![no_std]
#![cfg(false)]

// 此函数不会被包含。
pub fn example() {}

cfg_attr 属性

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

Example

以下模块将根据目标从 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 一起使用。

当配置谓词为 true 时,cfg_attr 展开为谓词之后列出的那些属性。

可以列出零个、一个或多个属性。多个属性将各自展开为独立的属性。

Example

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

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

Note

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 时求值为 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);
}

cfg_select

内置的 cfg_select! 宏可以在编译时根据多个配置谓词选择代码。

Example

#![allow(unused)]
fn main() {
cfg_select! {
    unix => {
        fn foo() { /* unix specific functionality */ }
    }
    target_pointer_width = "32" => {
        fn foo() { /* non-unix, 32-bit functionality */ }
    }
    _ => {
        fn foo() { /* fallback implementation */ }
    }
}

let is_unix_str = cfg_select! {
    unix => "unix",
    _ => "not unix",
};
}

Syntax
CfgSelectCfgSelectArms?

CfgSelectArms
    CfgSelectConfigurationPredicate =>
    (
        { ^ TokenTree } ,? CfgSelectArms?
      | ExpressionWithBlockNoAttrs ,? CfgSelectArms?
      | ExpressionWithoutBlockNoAttrs ( , CfgSelectArms? )?
    )

CfgSelectConfigurationPredicate
    ConfigurationPredicate | _

cfg_select 展开为第一个配置谓词求值为 true 的分支的有效载荷。

如果整个有效载荷被花括号包裹,则在展开时移除花括号。

配置谓词 _ 始终求值为 true。

如果没有谓词求值为 true,则产生编译错误。

每个右侧必须是宏调用位置上的语法有效展开。