条件编译
Syntax
ConfigurationPredicate →
ConfigurationOption
| ConfigurationAll
| ConfigurationAny
| ConfigurationNot
| true
| false
ConfigurationOption →
IDENTIFIER ( = ( STRING_LITERAL | RAW_STRING_LITERAL ) )?
ConfigurationAll →
all ( ConfigurationPredicateList? )
ConfigurationAny →
any ( ConfigurationPredicateList? )
ConfigurationNot →
not ( ConfigurationPredicate )
ConfigurationPredicateList →
ConfigurationPredicate ( , ConfigurationPredicate )* ,?
条件编译的源代码 是指仅在特定条件下才会被编译的源代码。
可以使用cfg和cfg_attr 属性以及内置的cfg!宏来使源代码条件编译。
是否进行编译可以取决于被编译的crate的目标架构、传递给编译器的任意值,以及下面进一步描述的其他因素。
每种形式的条件编译都接受一个 配置断言 ,该断言求值为真或假。该断言是以下形式之一:
- 一个配置选项。如果该选项已设置,则断言为真;如果未设置,则为假。
all(),带有一个逗号分隔的配置断言列表。如果所有给定的断言都为真,或者列表为空,则它为真。
any(),带有一个逗号分隔的配置断言列表。如果至少有一个给定的断言为真,则它为真。如果没有断言,则它为假。
not(),带有一个配置断言。如果其断言为假,则它为真;如果其断言为真,则它为假。
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用于指定编译时选项和可选依赖项的约定。
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"两者
unix和windows
如果设置了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
CfgAttribute → cfg ( 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.rs或windows.rs。#[cfg_attr(target_os = "linux", path = "linux.rs")] #[cfg_attr(windows, path = "windows.rs")] mod os;
cfg_attr属性的语法是:
Syntax
CfgAttrAttribute → cfg_attr ( ConfigurationPredicate , CfgAttrs? )
cfg_attr属性可以在允许属性的任何地方使用。
cfg_attr属性可以用于一个形式任意多次。
crate_type和crate_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);
}