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