工作空间允许在同一个仓库中组织和管理多个相关的 mcpp 包(库或应用程序)。各成员包共享统一的依赖版本配置和工具链设置,同时保持独立的 mcpp.toml 工程文件。
工作空间解决以下问题:
- 依赖版本统一管理 — 多个子包使用相同版本的第三方依赖,避免重复声明和版本不一致
- 工具链配置共享 — 在工作空间根目录统一声明工具链,各成员继承或覆盖
- 多包协同开发 — 库与应用在同一仓库中开发,通过
path依赖相互引用
工作空间不改变依赖声明方式。成员之间通过已有的 path = "..." 机制声明依赖关系,与非工作空间项目的用法完全一致。
在仓库根目录的 mcpp.toml 中声明 [workspace]:
[workspace]
members = [
"libs/core",
"libs/http",
"apps/server",
]members 列出各成员包的相对路径,每个路径下须包含独立的 mcpp.toml。
可选 exclude 字段排除特定路径:
[workspace]
members = ["libs/*"]
exclude = ["libs/experimental"]虚拟工作空间:根 mcpp.toml 仅包含 [workspace],不包含 [package]。根目录不产出构建产物,仅作为管理节点。
# 虚拟工作空间 — 只有 [workspace]
[workspace]
members = ["libs/core", "apps/server"]根包工作空间:根 mcpp.toml 同时包含 [package] 和 [workspace]。根目录本身也是一个可构建的包。
[workspace]
members = ["libs/core"]
[package]
name = "myapp"
version = "0.1.0"
[dependencies]
core = { path = "libs/core" }各成员维护独立的 mcpp.toml,结构与普通项目一致:
# libs/core/mcpp.toml
[package]
namespace = "myproject"
name = "core"
version = "0.1.0"
[targets.core]
kind = "lib"成员之间通过 path 依赖引用:
# libs/http/mcpp.toml
[package]
namespace = "myproject"
name = "http"
version = "0.1.0"
[dependencies]
core = { path = "../core" }
[dependencies.compat]
mbedtls.workspace = true在 [workspace.dependencies] 中集中声明依赖版本,成员通过 .workspace = true 继承:
# 根 mcpp.toml
[workspace.dependencies]
cmdline = "0.0.2"
capi.lua = "0.0.3" # dotted selector: mcpplibs.capi/lua, then capi/lua
[workspace.dependencies.compat]
mbedtls = "3.6.1"
gtest = "1.15.2"# 成员 mcpp.toml
[dependencies.compat]
mbedtls.workspace = true # 继承版本 → "3.6.1"
[dev-dependencies.compat]
gtest.workspace = true # 继承版本 → "1.15.2"成员可以覆盖继承的版本:
[dependencies.compat]
mbedtls = "4.0.0" # 覆盖,不使用 workspace 版本工作空间根的 [toolchain] 和 [target.<triple>] 配置自动继承到所有成员。成员可在自身的工程文件中覆盖。
配置优先级(从高到低):
- 命令行参数(
--target、--static) - 成员
mcpp.toml中的声明 - 工作空间根
mcpp.toml中的声明 - 全局配置(
~/.mcpp/config.toml) - 内置默认值
# 工作空间根
[toolchain]
default = "gcc@16.1.0"
[target.x86_64-linux-musl]
toolchain = "gcc@15.1.0-musl"
linkage = "static"# 某成员覆盖工具链
[toolchain]
default = "clang@19.0"mcpp build # 虚拟工作空间 → 构建所有成员;带根包 → 构建根包
mcpp build -p server # 构建指定成员及其依赖
mcpp build --workspace # 显式构建每个成员
mcpp test # 虚拟工作空间 → 测试所有成员;带根包 → 测试根包
mcpp test -p core # 测试单个成员
mcpp test --workspace # 测试每个成员(逐成员汇报;遇失败继续)在虚拟工作空间根(只有 [workspace]、无 [package])下,裸 mcpp build /
mcpp test 作用于所有成员;在带根包工作空间([package] + [workspace])下作用于
根包,用 --workspace 纳入全部成员。mcpp test --workspace 独立构建+运行每个成员的
tests/**/*.cpp——测试发现按成员隔离,因此两个成员各有一个 tests/main.cpp 也不会冲突。
cd libs/http
mcpp build # 自动检测工作空间,构建当前成员mcpp 从当前目录向上搜索,若发现包含 [workspace] 的 mcpp.toml 且当前目录在 members 列表中,则自动进入工作空间模式,继承工作空间配置。
-p 可用于 build、test、run 等命令,指定构建的目标成员。参数值为成员路径的最后一段目录名或完整相对路径:
mcpp build -p server # 匹配 apps/server
mcpp test -p core # 匹配 libs/core
mcpp run -p server -- --port 8080--workspace(用于 build 和 test)是扇出形式:作用于每个成员。
mcpp test --workspace 逐成员独立汇报、遇失败继续,只要有任一成员失败即非零退出——
非常适合作为「一个测试众多库的工作空间」的单条、无 shell 的 CI 步骤。
工作空间推荐的目录布局:
myproject/
├── mcpp.toml # [workspace] 声明
├── libs/
│ ├── core/
│ │ ├── mcpp.toml # [package] namespace="myproject" name="core"
│ │ └── src/
│ │ └── core.cppm # export module myproject.core;
│ └── http/
│ ├── mcpp.toml
│ └── src/
│ └── http.cppm # export module myproject.http;
└── apps/
└── server/
├── mcpp.toml
└── src/
└── main.cpp # import myproject.http;
各成员的构建产物位于各自的 target/ 子目录下。
工作空间与 C++23 模块机制协同工作:
- 接口可见性由语言控制 —
export module和import语句决定模块的公开接口,工作空间不做额外的可见性限制 - 模块名由库作者决定 — 工作空间不强制模块名与包名或命名空间一致
- partition 用于内部组织 —
import :internal;(不带export)的 partition 对消费者不可见,无需构建工具介入
参见 examples/04-workspace/,包含一个三成员工作空间的完整可运行示例。