Cargo 目标

Cargo 包由目标(target)组成,这些目标对应于可以编译成 crate 的源文件。包可以包含库(library)二进制(binary)示例(example)测试(test)基准测试(benchmark)目标。目标列表可以在 Cargo.toml 清单文件中配置,通常由源文件的目录布局自动推断

有关配置目标的详细设置,请参阅下面的配置目标

库(Library)

库目标定义了一个“库”,可以被其他库和可执行文件使用和链接。文件默认为 src/lib.rs,库的名称默认为包的名称,其中所有破折号都被替换为下划线。一个包只能有一个库。库的设置可以在 Cargo.toml[lib] 表中自定义

# Example of customizing the library in Cargo.toml.
[lib]
crate-type = ["cdylib"]
bench = false

二进制(Binaries)

二进制目标是编译后可以运行的可执行程序。二进制文件的源文件可以是 src/main.rs 和/或存储在src/bin/ 目录中。对于 src/main.rs,默认的二进制名称是包的名称。每个二进制文件的设置可以在 Cargo.toml[[bin]] 表中自定义

二进制文件可以使用包库的公共 API。它们也会链接到 Cargo.toml 中定义的[dependencies]

您可以使用 cargo run 命令并带上 --bin <bin-name> 选项来运行单个二进制文件。cargo install 可以用来将可执行文件复制到常用位置。

# Example of customizing binaries in Cargo.toml.
[[bin]]
name = "cool-tool"
test = false
bench = false

[[bin]]
name = "frobnicator"
required-features = ["frobnicate"]

示例(Examples)

位于examples 目录下的文件是库提供的功能的示例用法。编译后,它们会被放置在target/debug/examples 目录中。

示例可以使用包库的公共 API。它们也会链接到 Cargo.toml 中定义的[dependencies][dev-dependencies]

默认情况下,示例是可执行的二进制文件(包含 main() 函数)。您可以指定crate-type 字段,使示例作为库进行编译

[[example]]
name = "foo"
crate-type = ["staticlib"]

您可以使用 cargo run 命令并带上 --example <example-name> 选项来运行单个可执行示例。库示例可以使用 cargo build 命令并带上 --example <example-name> 选项来构建。cargo install 命令并带上 --example <example-name> 选项可以用来将可执行二进制文件复制到常用位置。默认情况下,cargo test 会编译示例以防止它们过时(bit-rotting)。如果您在示例中有希望通过 cargo test 运行的 #[test] 函数,请将test 字段设置为 true

测试(Tests)

Cargo 项目中有两种测试风格

  • 单元测试(Unit tests),这些函数使用#[test] 属性标记,位于您的库或二进制文件内部(或通过test 字段启用的任何目标)。这些测试可以访问它们所定义的**目标**内部的私有 API。
  • 集成测试(Integration tests),它是一个独立的可执行二进制文件,也包含 #[test] 函数,与项目库链接并可以访问其公共 API。

使用 cargo test 命令运行测试。默认情况下,Cargo 和 rustc 使用 libtest 测试框架(harness),它负责收集使用 #[test] 属性标记的函数,并并行执行它们,报告每个测试的成功或失败。如果您想使用不同的测试框架或测试策略,请参阅harness 字段

注意:Cargo 中还有另一种特殊的测试风格:文档测试(documentation tests)。它们由 rustdoc 处理,执行模型略有不同。更多信息请参阅cargo test

集成测试(Integration tests)

位于tests 目录下的文件是集成测试。当您运行 cargo test 时,Cargo 会将这些文件中的每一个编译成一个单独的 crate,然后执行它们。

集成测试可以使用包库的公共 API。它们也会链接到 Cargo.toml 中定义的[dependencies][dev-dependencies]

如果您想在多个集成测试之间共享代码,可以将其放在一个单独的模块中,例如 tests/common/mod.rs,然后在每个测试文件中放入 mod common; 来导入它。

每个集成测试都会生成一个独立的可执行二进制文件,cargo test 将按顺序运行它们。在某些情况下,这可能效率不高,因为它可能需要更长的编译时间,并且在运行测试时可能无法充分利用多个 CPU。如果您有大量的集成测试,您可能需要考虑创建一个单一的集成测试,并将测试分割到多个模块中。libtest 测试框架将自动找到所有带有 #[test] 标记的函数并并行运行它们。您可以将模块名称传递给 cargo test,以便只运行该模块内的测试。

如果存在集成测试,二进制目标会自动构建。这允许集成测试执行该二进制文件来演练和测试其行为。在构建集成测试时会设置 CARGO_BIN_EXE_<name> 环境变量,以便测试可以使用 env来定位可执行文件。

基准测试(Benchmarks)

基准测试提供了一种使用 cargo bench 命令测试代码性能的方法。它们遵循与测试相同的结构,每个基准测试函数都使用 #[bench] 属性进行标记。与测试类似

  • 基准测试文件放置在benches 目录中。
  • 定义在库和二进制文件中的基准测试函数可以访问它们所定义的**目标**内部的私有 API。benches 目录中的基准测试可以使用公共 API。
  • bench 字段可以用来定义默认对哪些目标进行基准测试。
  • harness 字段可以用来禁用内置的测试框架(harness)。

注意#[bench] 属性目前不稳定,仅在nightly channel上可用。crates.io 上有一些包可以帮助在 stable channel 上运行基准测试,例如 Criterion

配置目标

Cargo.toml 中的所有 [lib][[bin]][[example]][[test]][[bench]] 部分都支持类似的配置,用于指定如何构建目标。像 [[bin]] 这样的双括号部分是 TOML 中的表数组(array-of-table),这意味着您可以编写多个 [[bin]] 部分来在 crate 中创建多个可执行文件。您只能指定一个库,因此 [lib] 是一个普通的 TOML 表。

以下是每个目标的 TOML 设置概述,每个字段将在下面详细描述。

[lib]
name = "foo"           # The name of the target.
path = "src/lib.rs"    # The source file of the target.
test = true            # Is tested by default.
doctest = true         # Documentation examples are tested by default.
bench = true           # Is benchmarked by default.
doc = true             # Is documented by default.
proc-macro = false     # Set to `true` for a proc-macro library.
harness = true         # Use libtest harness.
crate-type = ["lib"]   # The crate types to generate.
required-features = [] # Features required to build this target (N/A for lib).

name 字段

name 字段指定目标的名称,它对应于将要生成的制品的 文件名。对于库,这是依赖项将用来引用它的 crate 名称。

对于库目标,它默认为包的名称,其中所有破折号都被替换为下划线。对于默认的二进制文件(src/main.rs),它也默认为包的名称,不替换破折号。对于自动发现的目标,它默认为目录或文件名称。

[lib] 外,所有目标都必须设置此项。

path 字段

path 字段指定 crate 源文件的位置,相对于 Cargo.toml 文件。

如果未指定,则根据目标名称使用推断的路径

test 字段

test 字段指示目标是否默认由 cargo test 进行测试。对于库、二进制文件和测试,默认值为 true

注意:默认情况下,cargo test 会构建示例以确保它们持续编译,但默认情况下不会对它们进行测试。将示例的 test = true 会将其也构建为一个测试,并运行示例中定义的任何 #[test] 函数。

doctest 字段

doctest 字段指示是否默认由 cargo test文档示例进行测试。这仅与库相关,对其他部分无效。对于库,默认值为 true

bench 字段

bench 字段指示目标是否默认由 cargo bench 进行基准测试。对于库、二进制文件和基准测试,默认值为 true

doc 字段

doc 字段指示目标是否默认包含在由 cargo doc 生成的文档中。对于库和二进制文件,默认值为 true

注意:如果二进制文件的名称与库目标的名称相同,则会跳过该二进制文件。

plugin 字段

此选项已废弃且不再使用。

proc-macro 字段

proc-macro 字段指示该库是一个过程宏(procedural macro)参考)。这仅对 [lib] 目标有效。

harness 字段

harness 字段指示将 --test 标志传递给 rustc,这将自动包含 libtest 库,libtest 是用于收集和运行使用 #[test] 属性标记的测试或使用 #[bench] 属性标记的基准测试的驱动程序。所有目标的默认值都是 true

如果设置为 false,则您负责定义一个 main() 函数来运行测试和基准测试。

无论是否启用 harness,测试都会启用 cfg(test) 条件编译表达式

crate-type 字段

crate-type 字段定义了目标将生成的crate 类型。它是一个字符串数组,允许您为一个目标指定多种 crate 类型。这只能为库和示例指定。二进制文件、测试和基准测试始终是“bin” crate 类型。默认值如下

目标Crate 类型
普通库"lib"
过程宏库"proc-macro"
示例"bin"

可用选项有 binlibrlibdylibcdylibstaticlibproc-macro。您可以在Rust 参考手册中阅读更多关于不同 crate 类型的信息。

required-features 字段

required-features 字段指定构建目标所需的特性(features)。如果所需的任何特性未启用,则会跳过该目标。这仅与 [[bin]][[bench]][[test]][[example]] 部分相关,对 [lib] 无效。

[features]
# ...
postgres = []
sqlite = []
tools = []

[[bin]]
name = "my-pg-tool"
required-features = ["postgres", "tools"]

edition 字段

edition 字段定义目标将使用的Rust 版本(edition)。如果未指定,则默认为 [package] 部分的edition 字段

注意:此字段已废弃,并将在未来的版本中移除

目标自动发现

默认情况下,Cargo 根据文件系统上的文件布局自动确定要构建的目标。目标配置表,例如 [lib][[bin]][[test]][[bench]][[example]],可用于添加不遵循标准目录布局的额外目标。

可以禁用自动目标发现,以便只构建手动配置的目标。在 [package] 部分中将键 autolibautobinsautoexamplesautotestsautobenches 设置为 false 将禁用相应目标类型的自动发现。

[package]
# ...
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false

禁用自动发现只应在特殊情况下才需要。例如,如果您的库中需要一个名为 bin模块,这就会有问题,因为 Cargo 通常会尝试将 bin 目录中的任何内容编译为可执行文件。以下是此场景的示例布局

├── Cargo.toml
└── src
    ├── lib.rs
    └── bin
        └── mod.rs

为了防止 Cargo 将 src/bin/mod.rs 推断为可执行文件,请在 Cargo.toml 中设置 autobins = false 来禁用自动发现。

[package]
# …
autobins = false

注意:对于 2015 版本(edition)的包,如果在 Cargo.toml 中至少手动定义了一个目标,则自动发现的默认值为 false。从 2018 版本开始,默认值始终为 true

MSRV: 自 1.27 版本起,对于 autobinsautoexamplesautotestsautobenches 生效。

MSRV: 自 1.83 版本起,对于 autolib 生效。