《Cargo 参考手册》第二章:工作区(Workspaces)
工作区是一个或多个包的集合,这些包被称为工作区成员,会被统一管理。
工作区的核心特点
- 可在所有工作区成员中执行通用命令,比如
cargo check --workspace
。 - 所有包共享一个公共的
Cargo.lock
文件,该文件位于工作区根目录。 - 所有包共享一个公共的输出目录,默认是工作区根目录下名为
target
的目录。 - 可共享包元数据,比如通过
workspace.package
配置。 Cargo.toml
中的[patch]
、[replace]
和[profile.*]
部分,仅在根清单中生效,在成员 crate 的清单中会被忽略。
工作区根目录的 Cargo.toml
支持的部分
工作区根目录的 Cargo.toml
包含以下可配置部分:
[workspace]
— 定义一个工作区。resolver
— 设置要使用的依赖解析器。members
— 要包含在工作区中的包。exclude
— 要从工作区中排除的包。default-members
— 未选择特定包时,默认要操作的包。package
— 供成员包继承的配置项。dependencies
— 供成员包依赖继承的配置项。lints
— 供成员包代码检查(lint)继承的配置项。metadata
— 外部工具的额外设置。[patch]
— 覆盖依赖项。[replace]
— 覆盖依赖项(已弃用)。[profile]
— 编译器设置和优化选项。
[workspace]
部分
要创建工作区,只需在 Cargo.toml
中添加 [workspace]
表即可:
toml
[workspace]
# ...
工作区至少需要包含一个成员,要么有一个根包,要么是一个虚拟清单。
根包(Root Package)
如果在已定义 [package]
的 Cargo.toml
中添加 [workspace]
部分,这个包就是工作区的根包。工作区根目录就是该 Cargo.toml
所在的目录。
toml
[workspace][package]
name = "hello_world" # 包的名称
version = "0.1.0" # 当前版本,遵循 semver 规范
虚拟工作区(Virtual Workspace)
另外,也可以创建一个只含 [workspace]
部分、不含 [package]
部分的 Cargo.toml
,这被称为虚拟清单。当没有 “主包”,或者想把所有包整理在独立目录中时,这种方式非常实用。
toml
# [项目目录]/Cargo.toml
[workspace]
members = ["hello_world"]
resolver = "3"
toml
# [项目目录]/hello_world/Cargo.toml
[package]
name = "hello_world" # 包的名称
version = "0.1.0" # 当前版本,遵循 semver 规范
edition = "2024" # Rust 版本(edition),对工作区使用的解析器无影响
对于没有根包的工作区,有两点需要注意:
- 虚拟工作区必须显式设置
resolver
—— 因为它们没有package.edition
可用来推断解析器版本。 - 在工作区根目录执行命令时,默认会对所有工作区成员生效,具体可参考
default-members
配置。
members
和 exclude
字段
members
和 exclude
字段用于定义工作区的成员包:
toml
[workspace]
members = ["member1", "path/to/member2", "crates/*"]
exclude = ["crates/foo", "path/to/other"]
- 所有位于工作区目录内的路径依赖,会自动成为工作区成员。
- 可通过
members
键添加额外成员,它接收一个字符串数组,每个字符串对应一个含Cargo.toml
的目录路径。 members
列表还支持通配符(glob)匹配多个路径,比如*
(匹配任意字符)、?
(匹配单个字符)等常见文件名通配符模式。exclude
键可用于排除某些路径,避免其成为工作区成员。比如有些路径依赖根本不想加入工作区,或者用通配符匹配后想剔除某个目录时,就可以用它。
当处于工作区的子目录中时,Cargo 会自动向上搜索父目录,寻找含 [workspace]
定义的 Cargo.toml
,以此确定当前使用的工作区。成员 crate 也可以通过 package.workspace
清单键,手动指定工作区根目录,从而覆盖这种自动搜索机制。当成员包不在工作区根目录的子目录中时,这种手动设置会很有用。
包选择(Package Selection)
在工作区中,cargo build
这类与包相关的 Cargo 命令,可以通过 -p / --package
或 --workspace
命令行参数,指定要操作的包。
- 如果未指定这两个参数,Cargo 会操作当前工作目录下的包。
- 但如果当前目录是工作区根目录,则会使用
default-members
配置的包。
default-members
字段
default-members
字段用于指定:当在工作区根目录且未使用包选择参数时,默认要操作的成员路径:
toml
[workspace]
members = ["path/to/member1", "path/to/member2", "path/to/member3/*"]
default-members = ["path/to/member2", "path/to/member3/foo"]
注意:如果工作区有根包,只能通过 --package
和 --workspace
参数操作它。
- 若未配置
default-members
:有根包则默认操作根包;若是虚拟工作区,则默认操作所有成员(相当于在命令行加了--workspace
参数)。
package
表
workspace.package
表用于定义可被工作区成员继承的配置项。成员包只需在自身配置中设置 {键名}.workspace = true
,就能继承这些配置。
支持继承的配置项如下:authors
、categories
、description
、documentation
、edition
、exclude
、homepage
、include
、keywords
、license
、license-file
、publish
、readme
、repository
、rust-version
、version
其中需要注意:
license-file
和readme
的路径是相对于工作区根目录的。include
和exclude
的路径是相对于成员包自身根目录的。
示例:
toml
# [项目目录]/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"
toml
# [项目目录]/bar/Cargo.toml
[package]
name = "bar"
version.workspace = true # 继承工作区的 version 配置
authors.workspace = true # 继承工作区的 authors 配置
description.workspace = true # 继承工作区的 description 配置
documentation.workspace = true # 继承工作区的 documentation 配置
最低支持的 Rust 版本(MSRV):需要 1.64 及以上版本。
dependencies
表
workspace.dependencies
表用于定义可被工作区成员继承的依赖项。
工作区依赖的配置规则与包依赖类似,但有两点不同:
- 该表中的依赖不能声明为可选依赖。
- 该表中声明的特性(features),会与成员包
[dependencies]
中的特性叠加。
成员包只需在自身依赖配置中引用工作区依赖,即可完成继承。
示例:
toml
# [项目目录]/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"] }
toml
# [项目目录]/bar/Cargo.toml
[package]
name = "bar"
version = "0.2.0"[dependencies]
# 继承工作区的 regex 依赖,并额外添加 "unicode" 特性
regex = { workspace = true, features = ["unicode"] }[build-dependencies]
# 继承工作区的 cc 依赖
cc.workspace = true[dev-dependencies]
# 继承工作区的 rand 依赖
rand.workspace = true
最低支持的 Rust 版本(MSRV):需要 1.64 及以上版本。
lints
表
workspace.lints
表用于定义可被工作区成员继承的代码检查(lint)配置。
工作区代码检查配置的规则,与包代码检查配置类似。
示例:
toml
# [项目目录]/Cargo.toml
[workspace]
members = ["crates/*"][workspace.lints.rust]
unsafe_code = "forbid" # 工作区统一禁止使用 unsafe 代码
toml
# [项目目录]/crates/bar/Cargo.toml
[package]
name = "bar"
version = "0.1.0"[lints]
workspace = true # 继承工作区的代码检查配置
最低支持的 Rust 版本(MSRV):从 1.74 版本开始支持。
metadata
表
workspace.metadata
表会被 Cargo 忽略,且不会触发未使用配置的警告。外部工具可通过该表,在 Cargo.toml
中存储工作区相关的配置。
示例:
toml
[workspace]
members = ["member1", "member2"][workspace.metadata.webcontents]
root = "path/to/webproject" # Web 项目的根路径
tool = ["npm", "run", "build"] # 构建 Web 项目的工具命令
# ...
在包级别也有类似的 package.metadata
表。Cargo 并未为这两个表的内容指定格式,但建议外部工具采用统一的使用方式 —— 比如当 package.metadata
中缺少某个配置时,可引用 workspace.metadata
中的对应数据(如果工具逻辑允许)。
要不要我帮你整理一份工作区核心配置项速查表?表里会汇总 [workspace]
下关键字段的作用、使用场景和示例代码,方便你快速查阅。