Cargo 工作区 #
工作区概述 #
Cargo 工作区(Workspace)允许你在一个仓库中管理多个相关的 Rust 包(crate)。这是实现 Monorepo 架构的理想方式,特别适合大型项目和库的集合。
为什么使用工作区? #
text
传统多仓库
├── repo-a/ # 独立仓库
│ ├── Cargo.toml
│ └── Cargo.lock
├── repo-b/ # 独立仓库
│ ├── Cargo.toml
│ └── Cargo.lock
└── repo-c/ # 独立仓库
├── Cargo.toml
└── Cargo.lock
工作区(Monorepo)
├── Cargo.toml # 工作区配置
├── Cargo.lock # 共享锁定文件
├── crates/
│ ├── crate-a/
│ ├── crate-b/
│ └── crate-c/
└── apps/
├── app-1/
└── app-2/
工作区优势 #
| 优势 | 描述 |
|---|---|
| 共享依赖 | 所有成员共享依赖,减少重复 |
| 统一版本 | 共享 Cargo.lock,确保版本一致 |
| 简化 CI/CD | 一次构建所有包 |
| 代码共享 | 内部包可以相互依赖 |
| 原子提交 | 跨包修改一次提交 |
创建工作区 #
手动创建 #
1. 创建根目录 #
bash
mkdir my_workspace
cd my_workspace
2. 创建工作区配置 #
创建根目录的 Cargo.toml:
toml
[workspace]
members = [
"crates/*",
"apps/*",
]
resolver = "2"
3. 创建成员包 #
bash
# 创建库包
mkdir -p crates
cd crates
cargo new my_lib --lib
cargo new my_utils --lib
# 创建应用包
mkdir -p ../apps
cd ../apps
cargo new my_app
cargo new my_cli
4. 最终结构 #
text
my_workspace/
├── Cargo.toml # 工作区配置
├── Cargo.lock # 共享锁定文件
├── crates/
│ ├── my_lib/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ └── my_utils/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
└── apps/
├── my_app/
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
└── my_cli/
├── Cargo.toml
└── src/
└── main.rs
使用命令创建 #
bash
# 创建工作区根目录
mkdir my_workspace && cd my_workspace
# 初始化工作区
cargo init --name my_workspace
# 编辑 Cargo.toml 添加工作区配置
# 然后创建成员
cargo new crates/my_lib --lib
cargo new apps/my_app
工作区配置 #
基本配置 #
toml
[workspace]
# 成员列表
members = [
"crates/*", # 通配符匹配
"apps/*",
"tools/cli", # 具体路径
]
# 排除成员
exclude = [
"crates/experimental",
"examples/old",
]
# 解析器版本(推荐使用 v2)
resolver = "2"
共享包元数据 #
toml
[workspace.package]
version = "0.1.0"
edition = "2021"
license = "MIT"
repository = "https://github.com/user/my_workspace"
成员包可以继承:
toml
# crates/my_lib/Cargo.toml
[package]
name = "my_lib"
version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
共享依赖 #
toml
[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
anyhow = "1.0"
thiserror = "1.0"
成员包使用:
toml
# crates/my_lib/Cargo.toml
[dependencies]
serde.workspace = true
tokio.workspace = true
[dev-dependencies]
anyhow.workspace = true
完整配置示例 #
toml
[workspace]
members = ["crates/*", "apps/*"]
exclude = ["crates/experimental"]
resolver = "2"
[workspace.package]
version = "0.1.0"
edition = "2021"
rust-version = "1.70"
license = "MIT OR Apache-2.0"
repository = "https://github.com/user/my_workspace"
[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1.0", features = ["full"] }
anyhow = "1.0"
thiserror = "1.0"
tracing = "0.1"
tracing-subscriber = "0.3"
# 内部包
my_lib = { path = "crates/my_lib" }
my_utils = { path = "crates/my_utils" }
工作区操作 #
构建操作 #
bash
# 构建所有成员
cargo build
# 构建特定成员
cargo build -p my_lib
cargo build -p my_app
# 构建多个成员
cargo build -p my_lib -p my_utils
# 发布构建
cargo build --release
# 构建所有目标
cargo build --all-targets
运行操作 #
bash
# 运行特定二进制
cargo run -p my_app
cargo run -p my_cli
# 运行并传递参数
cargo run -p my_cli -- --help
# 运行示例
cargo run -p my_lib --example basic
测试操作 #
bash
# 测试所有成员
cargo test
# 测试特定成员
cargo test -p my_lib
# 测试特定测试
cargo test -p my_lib test_name
# 测试所有成员(并行)
cargo test --workspace
检查操作 #
bash
# 检查所有成员
cargo check
# 检查特定成员
cargo check -p my_lib
# 检查所有目标
cargo check --all-targets
清理操作 #
bash
# 清理所有构建输出
cargo clean
# 清理特定成员
cargo clean -p my_lib
成员间依赖 #
内部依赖 #
toml
# apps/my_app/Cargo.toml
[dependencies]
my_lib = { path = "../../crates/my_lib" }
my_utils = { path = "../../crates/my_utils" }
# 使用工作区依赖
[dependencies]
my_lib.workspace = true
my_utils.workspace = true
版本依赖 #
发布时需要指定版本:
toml
[dependencies]
my_lib = { version = "0.1.0", path = "../../crates/my_lib" }
依赖图 #
text
my_app
├── my_lib
│ └── my_utils
└── my_utils
my_cli
└── my_lib
└── my_utils
工作区命令 #
列出成员 #
bash
# 列出所有成员
cargo metadata --format-version 1 | jq '.workspace_members'
# 或使用
cargo tree --depth 0
选择成员 #
bash
# 使用 --package 或 -p
cargo build -p my_lib
# 使用 --workspace 或 --all
cargo build --workspace
cargo build --all
# 排除成员
cargo build --workspace --exclude my_cli
并行操作 #
bash
# 并行构建(默认)
cargo build -j 4
# 串行构建
cargo build -j 1
工作区最佳实践 #
1. 目录结构 #
text
my_workspace/
├── Cargo.toml
├── Cargo.lock
├── README.md
├── .gitignore
├── crates/ # 库包
│ ├── core/
│ ├── utils/
│ └── macros/
├── apps/ # 应用程序
│ ├── server/
│ └── cli/
├── examples/ # 示例
│ └── basic/
├── tests/ # 集成测试
│ └── integration/
└── docs/ # 文档
└── guide/
2. 共享配置 #
toml
# 根 Cargo.toml
[workspace.package]
version = "0.1.0"
edition = "2021"
license = "MIT"
authors = ["Team <team@example.com>"]
repository = "https://github.com/org/repo"
[workspace.dependencies]
# 共享依赖版本
serde = "1.0"
tokio = "1.0"
# 内部包
core = { path = "crates/core" }
utils = { path = "crates/utils" }
3. 版本管理 #
bash
# 统一版本号
cargo install cargo-workspaces
cargo workspaces version patch
# 或手动更新
# 编辑所有 Cargo.toml 的 version 字段
4. 发布管理 #
bash
# 发布所有成员
cargo workspaces publish
# 发布特定成员
cargo publish -p my_lib
5. CI/CD 配置 #
yaml
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Check
run: cargo check --all-targets
- name: Test
run: cargo test --workspace
- name: Lint
run: cargo clippy --workspace -- -D warnings
- name: Format
run: cargo fmt --check
工作区工具 #
cargo-workspaces #
管理多包工作区的工具:
bash
# 安装
cargo install cargo-workspaces
# 创建新包
cargo workspaces create crates/new_lib --lib
# 列出包
cargo workspaces list
# 版本管理
cargo workspaces version patch
cargo workspaces version minor
cargo workspaces version major
# 发布
cargo workspaces publish
# 执行命令
cargo workspaces run -- cargo something
cargo-hack #
扩展 Cargo 命令:
bash
# 安装
cargo install cargo-hack
# 检查所有特性组合
cargo hack check --each-feature
# 检查所有目标
cargo hack check --target-thumbv7m-none-eabi
cargo-nextest #
更快的测试运行器:
bash
# 安装
cargo install cargo-nextest
# 运行测试
cargo nextest run --workspace
常见问题 #
1. 循环依赖 #
bash
# 错误:cyclic package dependency
# 解决:重构代码,提取公共部分
text
# 错误结构
my_app → my_lib → my_app
# 正确结构
my_app → my_lib
→ my_utils
my_lib → my_utils
2. 版本不一致 #
bash
# 确保使用工作区依赖
[dependencies]
serde.workspace = true # ✅
# 而不是
serde = "1.0" # ❌ 可能版本不一致
3. 构建慢 #
bash
# 使用增量编译
# .cargo/config.toml
[build]
incremental = true
# 减少并行任务
cargo build -j 2
4. 依赖冲突 #
bash
# 查看依赖树
cargo tree --duplicates
# 使用 patch 解决
[patch.crates-io]
conflicting-dep = { path = "../fixed" }
工作区示例 #
Web 项目工作区 #
toml
[workspace]
members = [
"crates/api",
"crates/db",
"crates/models",
"crates/utils",
"apps/server",
"apps/cli",
"apps/migrations",
]
resolver = "2"
[workspace.package]
version = "0.1.0"
edition = "2021"
[workspace.dependencies]
tokio = { version = "1.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sqlx = { version = "0.7", features = ["runtime-tokio", "postgres"] }
axum = "0.7"
anyhow = "1.0"
thiserror = "1.0"
# 内部包
api = { path = "crates/api" }
db = { path = "crates/db" }
models = { path = "crates/models" }
utils = { path = "crates/utils" }
库项目工作区 #
toml
[workspace]
members = [
"crates/core",
"crates/derive",
"crates/macros",
"examples/*",
]
resolver = "2"
[workspace.package]
version = "0.1.0"
edition = "2021"
license = "MIT"
[workspace.dependencies]
syn = { version = "2.0", features = ["full"] }
quote = "1.0"
proc-macro2 = "1.0"
core = { path = "crates/core" }
下一步 #
掌握工作区后,继续学习 测试 了解 Rust 的测试框架!
最后更新:2026-03-28