入门 The Cargo Team 2026-09-13 15:48:21 · 0 阅读

第15章 工作区(Workspaces)

Workspace(工作区)是一个集合,包含一个或多个称为工作区成员的软件包,这些软件包会被统一管理。

工作区的关键特性包括:

  • 通用命令可以跨所有工作区成员运行,例如 cargo check --workspace
  • 所有软件包共享一个位于工作区根目录的通用 Cargo.lock 文件。
  • 所有软件包共享一个通用的输出目录,默认是位于工作区根目录下名为 target 的目录。
  • 共享软件包元数据,例如通过 workspace.package
  • Cargo.toml 中的 [patch][replace][profile.*] 章节仅在被清单中识别,在成员 crate 的清单中会被忽略。

工作区的根 Cargo.toml 支持以下章节:

  • [workspace] — 定义一个工作区。
    • resolver — 设置要使用的依赖解析器。
    • members — 要包含在工作区中的软件包。
    • exclude — 要排除在工作区之外的软件包。
    • default-members — 当未选择特定软件包时,默认操作的软件包。
    • package — 软件包可继承的键。
    • dependencies — 软件包依赖项可继承的键。
    • lints — 软件包 lints 可继承的键。
    • metadata — 外部工具的额外设置。
  • [patch] — 覆盖依赖项。
  • [replace] — 覆盖依赖项(已弃用)。
  • [profile] — 编译器设置和优化。

[workspace] 章节

要创建工作区,需在 Cargo.toml 中添加 [workspace] 表:

[workspace]
# ...

至少,工作区必须包含一个成员,无论是带有根包,还是作为虚拟清单。

根包

如果在一个已定义 [package]Cargo.toml 中添加了 [workspace] 部分,该包即为工作区的根包工作区根指存放工作区 Cargo.toml 文件的目录。

[workspace]

[package]
name = "hello_world" # 包的名称
version = "0.1.0"    # 当前版本,遵循 semver

虚拟工作区

或者,可以创建一个仅包含 [workspace] 部分而不包含 [package] 部分Cargo.toml 文件。这被称为虚拟清单。当没有“主要”包,或希望将所有包组织在独立的目录中时,这种方式通常很有用。

# [PROJECT_DIR]/Cargo.toml
[workspace]
members = ["hello_world"]
resolver = "3"
# [PROJECT_DIR]/hello_world/Cargo.toml
[package]
name = "hello_world" # 包的名称
version = "0.1.0"    # 当前版本,遵循 semver
edition = "2024"     # 版本版式,对工作区中使用的 resolver 无影响

由于虚拟工作区没有根包,

membersexclude 字段

membersexclude 字段定义了哪些包是工作区的成员:

[workspace]
members = ["member1", "path/to/member2", "crates/*"]
exclude = ["crates/foo", "path/to/other"]

工作区目录中的所有 path 依赖会自动成为成员。还可以通过 members 键添加其他成员,它的值是一个字符串数组,包含各 Cargo.toml 文件所在的目录。

members 列表还支持使用 globs 匹配多个路径,例如 *? 等常见的文件名通配符。

exclude 键可以用来把某些路径排除在工作区之外。当你不希望某些 path 依赖进入工作区,或者在使用 glob 模式时想排除某个目录,这个键就很有用。

当你在工作区的子目录中操作时,Cargo 会自动向上搜索父目录,查找带有 [workspace] 定义的 Cargo.toml 文件,以确定使用哪个工作区。成员 crate 可以通过 package.workspace 清单键指向工作区根目录,从而覆盖这个自动搜索过程。如果成员不在工作区根目录的子目录中,手动设置就很有用。

Package selection

在工作区中,与包相关的 Cargo 命令(如 cargo build)可以通过 -p / --package--workspace 命令行参数指定要操作的包。如果没有指定这些参数,Cargo 会使用当前工作目录中的包;但如果当前目录是工作区根目录,则会使用 default-members

The default-members field

default-members 字段指定了在位于工作区根目录且未使用包选择参数时要操作的成员路径:

[workspace]
members = ["path/to/member1", "path/to/member2", "path/to/member3/*"]
default-members = ["path/to/member2", "path/to/member3/foo"]

注意:当存在 根包 时,只能使用 --package--workspace 标志对其进行操作。

如果未指定,将使用 根包。对于 虚拟工作区,所有成员包都将被使用(相当于在命令行中指定了 --workspace)。

package

workspace.package 表用于定义可由工作区成员继承的键。在成员包中设置 {key}.workspace = true 即可继承这些键。

支持的键如下:

authorscategories
descriptiondocumentation
editionexclude
homepageinclude
keywordslicense
license-filepublish
readmerepository
rust-versionversion
  • license-filereadme 相对于工作区根目录
  • includeexclude 相对于包根目录

示例:

# [PROJECT_DIR]/Cargo.toml
[workspace]
members = ["bar"]

[workspace.package]
version = "1.2.3"
authors = ["Nice Folks"]
description = "A short description of my package"
documentation = "https://example.com/bar"
# [PROJECT_DIR]/bar/Cargo.toml
[package]
name = "bar"
version.workspace = true
authors.workspace = true
description.workspace = true
documentation.workspace = true

MSRV: 需要 1.64 或更高版本

dependencies

workspace.dependencies 表用于定义供工作区成员继承的依赖项。

指定 workspace 依赖与包依赖类似,区别在于:

  • 此表中的依赖不能声明为optional
  • 在此表中声明的features会与[dependencies]中的features累加

之后你可以将 workspace 依赖继承为包依赖

示例:

# [PROJECT_DIR]/Cargo.toml
[workspace]
members = ["bar"]

[workspace.dependencies]
cc = "1.0.73"
rand = "0.8.5"
regex = { version = "1.6.0", default-features = false, features = ["std"] }
# [PROJECT_DIR]/bar/Cargo.toml
[package]
name = "bar"
version = "0.2.0"

[dependencies]
regex = { workspace = true, features = ["unicode"] }

[build-dependencies]
cc.workspace = true

[dev-dependencies]
rand.workspace = true

MSRV:需要 1.64+

lints

workspace.lints 表用于定义供 workspace 成员继承的 lint 配置。

指定 workspace lint 配置与包 lints类似。

示例:

# [PROJECT_DIR]/Cargo.toml
[workspace]
members = ["crates/*"]

[workspace.lints.rust]
unsafe_code = "forbid"
# [PROJECT_DIR]/crates/bar/Cargo.toml
[package]
name = "bar"
version = "0.1.0"

[lints]
workspace = true

MSRV:从 1.74 开始支持

metadata

workspace.metadata 表会被 Cargo 忽略,不会产生警告。此部分可用于希望将 workspace 配置存储在Cargo.toml中的工具。示例:

[workspace]
members = ["member1", "member2"]

[workspace.metadata.webcontents]
root = "path/to/webproject"
tool = ["npm", "run", "build"]
# ...

包级别也有一组类似的表,即package.metadata。Cargo 并不规定这两个表的内容格式,但建议外部工具尽量以一致的方式使用它们——比如当 package.metadata 中缺少数据时,可以回退读取 workspace.metadata 中的数据(前提是该工具适合这么做)。

评论 (0)