Workspaces
Um workspace do Cargo é um conjunto de crates compiladas juntas com um Cargo.lock compartilhado, versões unificadas de dependências e fluxos de trabalho de teste/build com um único comando.
Receita
# Cargo.toml (raiz do workspace)
[workspace]
members = ["crates/api", "crates/cli", "crates/domain"]
resolver = "2"
[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }# crates/api/Cargo.toml
[package]
name = "api"
version = "0.1.0"
edition = "2024"
[dependencies]
domain = { path = "../domain" }
serde = { workspace = true }
tokio = { workspace = true }Quando usar isso: Múltiplas crates relacionadas (API, CLI, domínio compartilhado) que lançam e testam juntas.
Exemplo de Trabalho
my_workspace/
├── Cargo.toml
├── Cargo.lock
├── crates/
│ ├── domain/
│ ├── api/
│ └── cli/
└── .cargo/config.toml
cargo build --workspace
cargo test -p domain
cargo run -p cli -- --helpO que isso demonstra:
- Um único
Cargo.lockna raiz fixa as versões para todos os membros. - Dependências de caminho conectam crates internas sem publicação.
-pseleciona um único pacote membro.resolver = "2"é o resolvedor de recursos moderno (padrão para edição 2021+).
Mergulho Profundo
Padrões de Layout de Workspace
| Padrão | Layout |
|---|---|
| Membros planos | api/, cli/ na raiz do repositório |
Diretório crates/ | crates/api, crates/domain |
| Aninhado | Apenas quando um membro não é a raiz |
Metadados Compartilhados
[workspace.package]
edition = "2024"
rust-version = "1.97"
license = "MIT OR Apache-2.0"
[workspace.dependencies]
axum = "0.8"Membros herdam com:
[package]
name = "api"
version = "0.1.0"
edition.workspace = true
rust-version.workspace = trueWorkspaces Virtuais
Um Cargo.toml raiz com apenas [workspace] (sem [package]) é um workspace virtual. Comum para monorepos que distribuem múltiplos binários e bibliotecas.
Armadilhas
- Publicando dependências de caminho -
cargo publishem um membro deve substituirpathpor dependências de versão. Correção: usecargo publish --dry-rune as verificações de metadados do crates.io. - Surpresas na unificação de recursos - habilitar um recurso em um membro afeta dependências compartilhadas em todo o workspace. Correção: isole backends conflitantes em crates separadas.
- Dependências circulares de caminho - A depende de B depende de A falha na resolução. Correção: extraia tipos compartilhados para uma terceira crate
core. - Nomes de pacotes duplicados - dois membros não podem compartilhar um nome. Correção: renomeie ou mescle crates.
- CI testando apenas a raiz - membros quebram silenciosamente. Correção:
cargo test --workspace --all-targets.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Crate única + módulos | O aplicativo cabe em um único binário | Ciclos de publicação/versão independentes necessários |
| Repositórios múltiplos | Equipes possuem a cadência de lançamento | Tipos compartilhados mudam diariamente |
| Orquestração Bazel / Nx | Monorepo poliglota | Equipes puramente Rust com fluxos de trabalho nativos do Cargo |
FAQs
Quantas crates pertencem a um workspace?
O suficiente para expressar limites (domínio, adaptadores, binários), não tantas que cada mudança de uma linha reconstrua o mundo. Divida quando os grafos de compilação prejudicarem a iteração.
O que é workspace.default-members?
Lista as crates que cargo build executa quando invocado na raiz sem -p. Útil quando a raiz é virtual.
Membros do workspace podem ter edições diferentes?
Sim, por [package] edition, mas alinhar em 2024 reduz a carga cognitiva.
Como excluo uma pasta do workspace?
Use exclude = ["tools/experimental"] em [workspace] ou simplesmente omita-a de members.
Onde o Cargo.lock vive?
Na raiz do workspace. Membros não obtêm seus próprios lockfiles.
Como as crates internas versionam?
Dependências de caminho ignoram a versão para resolução; ainda aumente o semver em crates internas publicadas se houver consumidores externos.
Posso executar clippy em todo o workspace?
cargo clippy --workspace --all-targets -- -D warnings é a invocação padrão de CI.
O que é resolver = 2?
O resolvedor de recursos versão 2 evita ativar recursos em alvos que não são construídos (por exemplo, dev-deps em plataformas não utilizadas).
Como compartilho um script build.rs?
Extraia a lógica para uma pequena crate interna ou copie scripts mínimos; o Cargo não compartilha build.rs entre membros automaticamente.
Workspace vs módulos dentro de uma crate?
Módulos são gratuitos, mas compilam como uma unidade. Crates de workspace impõem limites de API e compilação paralela.
Relacionados
- Noções Básicas do Cargo - comandos na raiz do workspace
- Limites de Workspace e Crate - orientação de design
- Gerenciamento de Dependências - atualizações de lockfile
- Cargo.toml Explicado - tabelas de workspace
Versões da Pilha: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4 e Polars 0.46+.