Cargo 目标

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

有关配置目标的详细信息,请参阅下文的配置目标

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

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

二进制文件

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

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

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

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

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

示例

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

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

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

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

您可以使用带有 --example <example-name> 选项的 cargo run 命令运行单个可执行示例。库示例可以使用带有 --example <example-name> 选项的 cargo build 构建。带有 --example <example-name> 选项的 cargo install 可用于将可执行二进制文件复制到通用位置。默认情况下,示例由 cargo test 编译,以防止它们出现位腐烂。如果您在要使用 cargo test 运行的示例中有 #[test] 函数,请将test 字段设置为 true

测试

在 Cargo 项目中有两种测试样式

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

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

注意:Cargo 中还有另一种特殊的测试样式:文档测试。它们由 rustdoc 处理,并具有略有不同的执行模型。有关更多信息,请参阅cargo test

集成测试

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

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

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

每个集成测试都会生成一个单独的可执行二进制文件,并且 cargo test 会串行运行它们。在某些情况下,这可能效率低下,因为它可能需要更长的编译时间,并且在运行测试时可能无法充分利用多个 CPU。如果您有很多集成测试,您可能需要考虑创建一个单独的集成测试,并将测试拆分为多个模块。libtest harness 会自动找到所有使用 #[test] 注释的函数并并行运行它们。您可以将模块名称传递给 cargo test 以仅运行该模块内的测试。

如果有集成测试,则会自动构建二进制目标。这允许集成测试执行二进制文件以练习和测试其行为。当构建集成测试时,将设置 CARGO_BIN_EXE_<name> 环境变量,以便它可以用来使用 env查找可执行文件。

基准测试

基准测试提供了一种使用 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 的表数组,这意味着您可以编写多个 [[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.
edition = "2015"       # The edition of the target.
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 测试。对于 lib、bins 和 tests,默认值为 true

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

doctest 字段

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

bench 字段

bench 字段指示目标是否默认由 cargo bench 进行基准测试。对于 lib、bins 和 benchmarks,默认值为 true

doc 字段

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

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

plugin 字段

此选项已弃用且未使用。

proc-macro 字段

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

harness 字段

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

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

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

edition 字段

edition 字段定义目标将使用的 Rust 版本。如果未指定,则默认为 [package]edition 字段。此字段通常不应设置,仅用于高级场景,例如将大型包逐步过渡到新版本。

crate-type 字段

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

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

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

required-features 字段

required-features 字段指定了目标构建所需的 特性。如果任何必需的特性未启用,则会跳过该目标。这仅适用于 [[bin]][[bench]][[test]][[example]] 部分,对 [lib] 没有影响。

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

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

目标自动发现

默认情况下,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 版的包,如果在 Cargo.toml 中手动定义了至少一个目标,则自动发现的默认值为 false。从 2018 版开始,默认值始终为 true

MSRV: 对于 autobinsautoexamplesautotestsautobenches,从 1.27 版本开始生效

MSRV: 对于 autolib,从 1.83 版本开始生效