四. crate 和源文章
注意:尽管像任何其他语言一样,Rust 也都可以通过解释器和编译器实现,但现在唯一存在的实现是编译器,并且该语言也是一直被设计为可编译的。因为这些原因,所以本章节所有的讨论都是基于编译器这条路径的。
句法
Crate :
UTF8BOM?
SHEBANG?
InnerAttribute*
Item*
词法
UTF8BOM :\uFEFF
SHEBANG :#!
~\n
+†
Rust 的语义有编译时和运行时之间的阶段差异(phase distinction)。1 其中静态解释的语义规则控制编译的成败,而动态解释的语义规则控制程序在运行时的行为。
#![allow(unused)]
fn main() {
// 指定 crate 名称.
#![crate_name = "projx"]// 指定编译输出文件的类型
#![crate_type = "lib"]// 打开一种警告
// 这句可以放在任何模块中, 而不是只能放在匿名 crate 模块里。
#![warn(non_camel_case_types)]
}
源文件可以有一个shebang(SHEBANG产生式),它指示操作系统使用什么程序来执行此文件。它本质上是将源文件作为可执行脚本处理。shebang 只能出现在文件的开头(但是要在可选的 UTF8BOM 生产式之后)。它会被编译器忽略。例如:
#!/usr/bin/env rustx
fn main() {
println!("Hello!");
}
包含 main
函数的 crate 可以被编译成可执行文件。如果一个 main
函数存在,它必须不能有参数,不能对其声明任何 trait约束或生存期约束,不能有任何 where子句,并且它的返回类型必须是以下类型之一:
()
Result<(), E> where E: Error
4.1 no_main属性
可在 crate 层级使用 *no_main
属性*来禁止对可执行二进制文件发布 main
symbol,即禁止当前 crate 的 main 函数的执行。当链接的其他对象定义了 main
函数时,这很有用。
4.2 crate_name 属性
可在 crate 层级应用 crate_name
属性,并通过使用 MetaNameValueStr元项属性句法来指定 crate 的名称。
#![allow(unused)] #![crate_name = "mycrate"] fn main() { }
五. 条件编译;
句法
ConfigurationPredicate :
ConfigurationOption
| ConfigurationAll
| ConfigurationAny
| ConfigurationNotConfigurationOption :
IDENTIFIER (=
(STRING_LITERAL | RAW_STRING_LITERAL))?ConfigurationAll
all
(
ConfigurationPredicateList?)
ConfigurationAny
any
(
ConfigurationPredicateList?)
ConfigurationNot
not
(
ConfigurationPredicate)
ConfigurationPredicateList
ConfigurationPredicate (,
ConfigurationPredicate)*,
?
可以使用属性 cfg 和 cfg_attr 以及内置的 cfg macro 来有条件地对源代码进行编译。这些条件可以基于被编译的 crate 的目标架构、传递给编译器的值,以及下面将详细描述的一些其他事项。
每种形式的编译条件都有一个计算结果为真或假的配置谓词(configuration predicate)。谓词是以下内容之一:
- 一个配置选项。如果设置了该选项,则为真,如果未设置则为假。
all()
这样的配置谓词列表,列表内的配置谓词以逗号分隔。如果至少有一个谓词为假,则为假。如果没有谓词,则为真。any()
这样的配置谓词列表,列表内的配置谓词以逗号分隔。如果至少有一个谓词为真,则为真。如果没有谓词,则为假。- 带一个配置谓词的
not()
模式 。如果此谓词为假,整个配置它为真;如果此谓词为真,整个配置为假。
配置选项可以是名称,也可以是键值对,它们可以设置,也可以不设置。名称以单个标识符形式写入,例如 unix
。键值对被写为标识符后跟 =
,然后再跟一个字符串。例如,target_arch=“x86_64”
就是一个配置选项。
注意: 对于 rustc
,任意配置集的配置选项要使用命令行参数 --cfg 来设置。
警告:任意配置集的配置选项可能与编译器设置集的配置选项设置相同的值。例如,在编译一个 Windows 目标时,可以执行命令行 rustc --cfg "unix" program.rs
,这样就同时设置了 unix
和 windows
配置选项。但实际上这样做是不明智的。
5.1 target_arch
键值对选项,用于一次性设置编译目标的 CPU 架构。该值类似于平台的目标三元组(target triple)1中的第一个元素,但也不完全相同。
示例值:
"x86"
"x86_64"
"mips"
"powerpc"
"powerpc64"
"arm"
"aarch64"
5.2 target_feature
键值对选项,用于设置当前编译目标的可用平台特性。
示例值:
"avx"
"avx2"
"crt-static"
"rdrand"
"sse"
"sse2"
"sse4.1"
5.3 target_os
键值对选项,用于一次性设置编译目标的操作系统类型。该值类似于平台目标三元组中的第二和第三个元素。
示例值:
"windows"
"macos"
"ios"
"linux"
"android"
"freebsd"
"dragonfly"
"openbsd"
"netbsd"
5.4 target_family
键值对选项提供了对具体目标平台更通用化的描述,比如编译目标操作系统或架构。可以设置任意数量的键值对。 最多设置一次,用于设置编译目标的操作系统类别。
示例值:
"unix"
"windows"
"wasm"
5.5 target_env
键值对选项,用来进一步消除编译目标平台信息与所用 ABI 或 libc
相关的歧义。由于历史原因,仅当实际需要消除歧义时,才将此值定义为非空字符串。因此,例如在许多 GNU 平台上,此值将为空。该值类似于平台目标三元组的第四个元素,但也有区别。一个区别是在嵌入式 ABI 上,比如在目标为嵌入式系统时,gnueabihf
会简单地将 target_env
定义为 "gnu"
。
示例值:
""
"gnu"
"msvc"
"musl"
"sgx"
5.6 target_endian
键值对选项,根据编译目标的 CPU 的字节序(endianness)属性一次性设置值为 “little” 或 “big”。
5.7 target_pointer_width
键值对选项,用于一次性设置编译目标的指针位宽(pointer width in bits)。
示例值:
"16"
"32"
"64"
5.8 target_vendor
键值对选项,用于一次性设置编译目标的供应商。
示例值:
"apple"
"fortanix"
"pc"
"unknown"
5.9 test
在编译测试套件时启用。通过在 rustc
里使用 --test 命令行参数来完成此启用。请参阅测试章节来获取更多和测试支持相关的信息
5.10 debug_assertions
在进行非优化编译时默认启用。这可以用于在开发中启用额外的代码调试功能,但不能在生产中启用。例如,它控制着标准库的 debug_assert!宏(是否可用)。
5.11 proc_macro
当须要指定当前 crate 的编译输出文件类型(crate-type)为 proc_macro
时设置。
5.12 条件编译形式
5.12.1 cfg 属性
句法
CfgAttrAttribute :
cfg
(
ConfigurationPredicate)
#![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() {
// ...
}
}
5.12.2 cfg_attr 属性
句法
CfgAttrAttribute :
cfg_attr
(
ConfigurationPredicate,
CfgAttrs?)
#[cfg_attr(target_os = "linux", path = "linux.rs")]
#[cfg_attr(windows, path = "windows.rs")]
mod os;
可以列出零个、一个或多个属性。多个属性将各自展开为单独的属性。例如:
#[cfg_attr(feature = "magic", sparkles, crackles)]
fn bewitched() {}
// 当启用了 `magic` 特性时, 上面的代码将会被展开为:
#[sparkles]
#[crackles]
fn bewitched() {}
cfg_attr
属性允许在任何允许属性的地方上使用。
5.12.3 cfg 宏
内置的 cfg
宏接受单个配置谓词,当谓词为真时计算为 true
字面量,当谓词为假时计算为 false
字面量。