crate 和源文件

crates-and-source-files.md
commit: eabdf09207bf3563ae96db9d576de0758c413d5d
本章译文最后维护日期:2021-1-24

句法
Crate :
   UTF8BOM?
   SHEBANG?
   InnerAttribute*
   Item*

词法
UTF8BOM : \uFEFF
SHEBANG : #! ~\n+

注意:尽管像任何其他语言一样,Rust 也都可以通过解释器和编译器实现,但现在唯一存在的实现是编译器,并且该语言也是一直被设计为可编译的。因为这些原因,所以本章节所有的讨论都是基于编译器这条路径的。

Rust 的语义有编译时和运行时之间的阶段差异(phase distinction)1 其中静态解释的语义规则控制编译的成败,而动态解释的语义规则控制程序在运行时的行为。

编译模型以 crate 为中心。每次编译都以源码的形式处理单个的 crate,如果成功,将生成二进制形式的单个 crate:可执行文件或某种类型的库文件。2

crate 是编译和链接的单元,也是版本控制、版本分发和运行时加载的基本单元。一个 crate 包含一个嵌套的带作用域的模块。这个树的顶层是一个匿名的模块(从模块内部路径的角度来看),并且一个 crate 中的任何程序项都有一个规范的模块路径来表示它在 crate 的模块树中的位置。

Rust 编译器总是使用单个源文件作为输入来开启编译过程的,并且总是生成单个输出 crate。对输入源文件的处理可能导致其他源文件作为模块被加载进来。源文件的扩展名为 .rs

Rust 源文件描述了一个模块,其名称和(在当前 crate 的模块树中的)位置是从源文件外部定义的:要么通过引用源文件中的显式模块(Module)项,要么由 crate 本身的名称定义。每个源文件都是一个模块,但并非每个模块都需要自己的源文件:多个模块定义可以嵌套在同一个文件中。

每个源文件包含一个由零个或多个程序项定义组成的代码序列,并且这些源文件都可选地从应用于其内部模块的任意数量的属性开始,大部分这些属性都会会影响编译器行为。匿名的 crate 根模块可附带一些应用于整个 crate 的属性。


#![allow(unused)]
fn main() {
// 指定 crate 名称.
#![crate_name = "projx"]

// 指定编译输出文件的类型
#![crate_type = "lib"]

// 打开一种警告
// 这句可以放在任何模块中, 而不是只能放在匿名 crate 模块里。
#![warn(non_camel_case_types)]
}

字节顺序标记(BOM)

可选的UTF8字节序标记(UTF8BOM产生式)表示该文件是用 UTF8 编码的。它只能出现在文件的开头,并且编译器会忽略它。

Shebang

源文件可以有一个shebang(SHEBANG产生式),它指示操作系统使用什么程序来执行此文件。它本质上是将源文件作为可执行脚本处理。shebang 只能出现在文件的开头(但是要在可选的 UTF8BOM 生产式之后)。它会被编译器忽略。例如:

#!/usr/bin/env rustx

fn main() {
    println!("Hello!");
}

为了避免与属性混淆, Rust 对 shebang 句法做了一个限制:是 #! 字符不能后跟 token [,忽略中间的注释空白符。如果违反此限制,则不会将其视为 shebang,而会将其视为属性的开始。

预导入包和 no_std

本节内容已经移入预导入包那章里了。

main函数

包含 main函数的 crate 可以被编译成可执行文件。如果一个 main函数存在,它必须不能有参数,不能对其声明任何 trait约束或生存期约束,不能有任何 where子句,并且它的返回类型必须是以下类型之一:

  • ()
  • Result<(), E> where E: Error

注意: 允许哪些返回类型的实现是由暂未稳定的 Termination trait 决定的。

no_main属性

可在 crate 层级使用 *no_main属性*来禁止对可执行二进制文件发布 main symbol,即禁止当前 crate 的 main 函数的执行。当链接的其他对象定义了 main函数时,这很有用。

crate_name属性

可在 crate 层级应用 crate_name属性,并通过使用 MetaNameValueStr元项属性句法来指定 crate 的名称。


#![allow(unused)]
#![crate_name = "mycrate"]
fn main() {
}

crate 名称不能为空,且只能包含 [Unicode字母数字]或字符 -(U+002D)。

1

这种区别也存在于解释器中。静态检查,如语法分析、类型检查和 lint检查,都应该在程序执行之前进行,而不要去管程序何时执行。

2

crate 有点类似于 ECMA-335 CLI 模型中的 assembly、SML/NJ 编译管理器中的 library、Owens 和 Flatt 模块系统中的 unit, 或 Mesa 中的 configuration