O Cargo é muito mais do que um simples gerenciador de pacotes — ele é o coração do ecossistema Rust. Desde a criação de projetos até a publicação de crates no crates.io, o Cargo gerencia dependências, compila código, executa testes, gera documentação e orquestra todo o fluxo de trabalho de desenvolvimento Rust.
Todo projeto Rust utiliza o Cargo. Ele foi projetado para ser determinístico, reproduzível e eficiente, garantindo que builds funcionem de maneira consistente em qualquer máquina. Se você já usou npm, pip ou Maven, vai se sentir em casa — mas com garantias muito mais fortes.
Neste guia, vamos explorar desde os fundamentos até recursos avançados como workspaces, build profiles customizados, features flags e plugins que turbinarão sua produtividade.
Instalação
O Cargo vem instalado automaticamente junto com o Rust quando você usa o rustup:
# Instalar Rust e Cargo via rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Verificar a instalação
cargo --version
# cargo 1.77.0 (3fe68eabf 2024-02-29)
Se você já tem o Rust instalado, o Cargo já está disponível. Para atualizar:
# Atualizar Rust e Cargo para a versão mais recente
rustup update stable
Uso Básico
Criando um Novo Projeto
# Criar um novo projeto binário (executável)
cargo new meu-projeto
cd meu-projeto
# Criar um novo projeto de biblioteca
cargo new minha-lib --lib
# Inicializar Cargo em um diretório existente
cargo init
cargo init --lib # como biblioteca
Estrutura de um Projeto Cargo
Ao criar um projeto, o Cargo gera a seguinte estrutura:
meu-projeto/
├── Cargo.toml # Manifesto do projeto
├── Cargo.lock # Lockfile com versões exatas (committar para binários)
├── src/
│ ├── main.rs # Ponto de entrada para binários
│ └── lib.rs # Ponto de entrada para bibliotecas
├── tests/ # Testes de integração
├── benches/ # Benchmarks
├── examples/ # Exemplos de uso
└── target/ # Artefatos de build (ignorar no git)
Estrutura do Cargo.toml
O Cargo.toml é o manifesto do projeto, escrito em formato TOML:
[package]
name = "meu-projeto"
version = "0.1.0"
edition = "2021"
authors = ["Seu Nome <seu@email.com>"]
description = "Uma descrição do meu projeto"
license = "MIT OR Apache-2.0"
repository = "https://github.com/usuario/meu-projeto"
readme = "README.md"
keywords = ["rust", "exemplo"]
categories = ["development-tools"]
rust-version = "1.70" # Versão mínima do Rust
[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
anyhow = "1.0"
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
tempfile = "3"
[build-dependencies]
cc = "1.0"
[profile.release]
opt-level = 3
lto = true
Comandos Essenciais
# Compilar o projeto (modo debug)
cargo build
# Compilar em modo release (otimizado)
cargo build --release
# Compilar e executar
cargo run
# Executar com argumentos
cargo run -- --flag argumento
# Verificar se compila sem gerar binário (mais rápido)
cargo check
# Executar todos os testes
cargo test
# Executar testes com saída do println!
cargo test -- --nocapture
# Executar um teste específico
cargo test nome_do_teste
# Gerar documentação
cargo doc --open
# Limpar artefatos de build
cargo clean
# Atualizar dependências
cargo update
# Mostrar árvore de dependências
cargo tree
Gerenciando Dependências
# Adicionar uma dependência (requer cargo-edit ou Cargo 1.62+)
cargo add serde --features derive
cargo add tokio --features full
# Adicionar dependência de desenvolvimento
cargo add --dev criterion
# Adicionar dependência de build
cargo add --build cc
# Remover uma dependência
cargo remove serde
# Ver dependências desatualizadas
cargo outdated # requer cargo-outdated
Especificando versões no Cargo.toml:
[dependencies]
# Versão compatível (padrão) — aceita patches e minor updates
serde = "1.0" # equivale a >=1.0.0, <2.0.0
# Versão exata
serde = "=1.0.193"
# Intervalo de versões
rand = ">=0.8, <0.9"
# Qualquer versão
log = "*"
# Dependência do Git
minha-crate = { git = "https://github.com/user/repo", branch = "main" }
minha-crate = { git = "https://github.com/user/repo", rev = "abc123" }
# Dependência local (path)
minha-lib = { path = "../minha-lib" }
# Dependência opcional
serde_yaml = { version = "0.9", optional = true }
Recursos Avançados
Workspaces
Workspaces permitem gerenciar múltiplos pacotes relacionados em um único repositório:
# Cargo.toml na raiz do workspace
[workspace]
members = [
"crates/core",
"crates/api",
"crates/cli",
"crates/utils",
]
resolver = "2"
# Dependências compartilhadas pelo workspace
[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
anyhow = "1.0"
thiserror = "1.0"
# Metadados compartilhados
[workspace.package]
version = "0.1.0"
edition = "2021"
authors = ["Equipe <equipe@empresa.com>"]
license = "MIT"
Nos pacotes individuais, herde do workspace:
# crates/api/Cargo.toml
[package]
name = "meu-projeto-api"
version.workspace = true
edition.workspace = true
authors.workspace = true
[dependencies]
serde.workspace = true
tokio.workspace = true
meu-projeto-core = { path = "../core" }
Comandos para workspaces:
# Compilar todo o workspace
cargo build --workspace
# Compilar apenas um pacote
cargo build -p meu-projeto-api
# Testar todo o workspace
cargo test --workspace
# Executar um binário específico
cargo run -p meu-projeto-cli
Build Profiles
Customize como o Cargo compila seu código:
# Perfil de desenvolvimento (cargo build)
[profile.dev]
opt-level = 0 # Sem otimização (compilação rápida)
debug = true # Informações de debug completas
debug-assertions = true
overflow-checks = true
incremental = true # Compilação incremental
codegen-units = 256 # Mais unidades = compilação mais rápida
# Perfil de release (cargo build --release)
[profile.release]
opt-level = 3 # Otimização máxima
debug = false # Sem informações de debug
debug-assertions = false
overflow-checks = false
lto = "fat" # Link-Time Optimization completo
codegen-units = 1 # Menos unidades = código mais otimizado
panic = "abort" # Menos código gerado para panics
strip = true # Remove símbolos do binário
# Perfil customizado para testes de performance
[profile.bench]
opt-level = 3
debug = true # Debug info para profiling
# Perfil customizado (Rust 1.57+)
[profile.profiling]
inherits = "release"
debug = true # Release com debug info para profiling
strip = false
# Otimizar dependências mesmo em modo debug
[profile.dev.package."*"]
opt-level = 2
Features Flags e Compilação Condicional
Features permitem compilação condicional de funcionalidades:
# Cargo.toml
[features]
# Feature padrão (ativada por padrão)
default = ["json", "logging"]
# Features individuais
json = ["dep:serde_json"]
yaml = ["dep:serde_yaml"]
logging = ["dep:tracing"]
full = ["json", "yaml", "logging", "async"]
async = ["dep:tokio"]
# Feature que ativa feature de dependência
derive = ["serde/derive"]
[dependencies]
serde = "1.0"
serde_json = { version = "1.0", optional = true }
serde_yaml = { version = "0.9", optional = true }
tracing = { version = "0.1", optional = true }
tokio = { version = "1", features = ["full"], optional = true }
Usando features no código:
// src/lib.rs
// Módulo disponível apenas com a feature "json"
#[cfg(feature = "json")]
pub mod json {
use serde_json;
/// Serializa um valor para JSON
pub fn para_json<T: serde::Serialize>(valor: &T) -> Result<String, serde_json::Error> {
serde_json::to_string_pretty(valor)
}
/// Desserializa JSON para um tipo
pub fn de_json<'a, T: serde::Deserialize<'a>>(json: &'a str) -> Result<T, serde_json::Error> {
serde_json::from_str(json)
}
}
// Módulo disponível apenas com a feature "yaml"
#[cfg(feature = "yaml")]
pub mod yaml {
use serde_yaml;
pub fn para_yaml<T: serde::Serialize>(valor: &T) -> Result<String, serde_yaml::Error> {
serde_yaml::to_string(valor)
}
}
// Logging condicional
#[cfg(feature = "logging")]
pub fn inicializar_logs() {
tracing_subscriber::fmt::init();
}
#[cfg(not(feature = "logging"))]
pub fn inicializar_logs() {
// Sem operação quando logging está desativado
}
// Compilação condicional por plataforma
#[cfg(target_os = "linux")]
pub fn caminho_config() -> &'static str {
"/etc/meu-app/config.toml"
}
#[cfg(target_os = "windows")]
pub fn caminho_config() -> &'static str {
"C:\\ProgramData\\meu-app\\config.toml"
}
#[cfg(target_os = "macos")]
pub fn caminho_config() -> &'static str {
"/Library/Application Support/meu-app/config.toml"
}
Compilando com features:
# Compilar com features padrão
cargo build
# Compilar sem features padrão
cargo build --no-default-features
# Compilar com features específicas
cargo build --features "json,yaml"
# Compilar com todas as features
cargo build --all-features
Build Scripts (build.rs)
Build scripts executam antes da compilação:
// build.rs
use std::env;
use std::fs;
use std::path::Path;
fn main() {
// Informar ao Cargo para re-executar se estes arquivos mudarem
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=proto/api.proto");
println!("cargo:rerun-if-env-changed=MEU_APP_VERSION");
// Definir variáveis de ambiente acessíveis em compile-time
let versao = env::var("MEU_APP_VERSION").unwrap_or_else(|_| "dev".to_string());
println!("cargo:rustc-env=APP_VERSION={}", versao);
// Gerar código
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("generated.rs");
fs::write(
&dest_path,
"pub const BUILD_TIME: &str = \"2024-01-01T00:00:00Z\";\n",
)
.unwrap();
// Linkar bibliotecas C
println!("cargo:rustc-link-lib=static=minha_lib_c");
println!("cargo:rustc-link-search=native=/usr/local/lib");
// Passar flags para o compilador
println!("cargo:rustc-cfg=feature_personalizada");
}
Usando código gerado:
// src/main.rs
// Incluir código gerado pelo build script
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
fn main() {
// Variável definida no build.rs
println!("Versão: {}", env!("APP_VERSION"));
println!("Build time: {}", BUILD_TIME);
}
Publicando no crates.io
# Fazer login no crates.io
cargo login seu-token-api
# Verificar o pacote antes de publicar
cargo package --list # lista arquivos incluídos
cargo publish --dry-run # simula publicação
# Publicar!
cargo publish
# Publicar com verificações ignoradas (use com cuidado)
cargo publish --no-verify
# Yank (despublicar) uma versão
cargo yank --version 0.1.0
cargo yank --version 0.1.0 --undo # desfazer
Configurando o que é incluído no pacote:
[package]
# Incluir apenas estes arquivos
include = [
"src/**/*",
"Cargo.toml",
"LICENSE",
"README.md",
]
# Ou excluir arquivos específicos
exclude = [
"tests/fixtures/*",
".github/*",
"*.log",
]
Boas Práticas
1. Sempre Commite o Cargo.lock para Binários
# Para projetos binários: COMMITE o Cargo.lock
# Garante builds reproduzíveis
# Para bibliotecas: NÃO commite o Cargo.lock
# Adicione ao .gitignore
echo "Cargo.lock" >> .gitignore
2. Use Workspace Dependencies
# Evite duplicação de versões no workspace
[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
# Em cada crate do workspace:
[dependencies]
serde.workspace = true
3. Minimize Dependencies
// Prefira usar a stdlib quando possível
// Em vez de adicionar uma crate para isso:
use std::collections::HashMap;
use std::fs;
use std::io::{self, Read, Write};
use std::path::PathBuf;
4. Use cargo-deny para Auditoria
# deny.toml
[advisories]
vulnerability = "deny"
unmaintained = "warn"
[licenses]
allow = ["MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause"]
confidence-threshold = 0.8
[bans]
multiple-versions = "warn"
wildcards = "deny"
[sources]
unknown-registry = "deny"
unknown-git = "deny"
5. Configure Aliases Úteis
# .cargo/config.toml
[alias]
br = "build --release"
t = "test"
tw = "test --workspace"
rr = "run --release"
cl = "clippy --all-targets --all-features -- -D warnings"
fmt-check = "fmt --all -- --check"
[build]
# Usar linker mais rápido (instale com: cargo install lld)
# Linux
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
# macOS (requer: brew install llvm)
# rustflags = ["-C", "link-arg=-fuse-ld=/opt/homebrew/opt/llvm/bin/ld64.lld"]
# Número de jobs paralelos
jobs = 8
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
Exemplos Práticos
Exemplo 1: Projeto Completo com Múltiplas Crates
meu-saas/
├── Cargo.toml # Workspace root
├── crates/
│ ├── core/
│ │ ├── Cargo.toml
│ │ └── src/lib.rs # Lógica de domínio
│ ├── api/
│ │ ├── Cargo.toml
│ │ └── src/main.rs # Servidor HTTP
│ ├── worker/
│ │ ├── Cargo.toml
│ │ └── src/main.rs # Processamento em background
│ └── cli/
│ ├── Cargo.toml
│ └── src/main.rs # Ferramenta de administração
└── shared/
├── Cargo.toml
└── src/lib.rs # Tipos e utilitários compartilhados
# Cargo.toml (raiz)
[workspace]
members = [
"crates/*",
"shared",
]
resolver = "2"
[workspace.package]
version = "0.1.0"
edition = "2021"
license = "MIT"
rust-version = "1.75"
[workspace.dependencies]
# Dependências compartilhadas com versões centralizadas
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
anyhow = "1.0"
thiserror = "1.0"
uuid = { version = "1", features = ["v4", "serde"] }
chrono = { version = "0.4", features = ["serde"] }
Exemplo 2: Cargo.toml Completo para uma API
# crates/api/Cargo.toml
[package]
name = "meu-saas-api"
version.workspace = true
edition.workspace = true
license.workspace = true
[[bin]]
name = "api-server"
path = "src/main.rs"
[dependencies]
# Do workspace
serde.workspace = true
serde_json.workspace = true
tokio.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
anyhow.workspace = true
uuid.workspace = true
chrono.workspace = true
# Específicas desta crate
axum = { version = "0.7", features = ["macros"] }
tower = { version = "0.4", features = ["full"] }
tower-http = { version = "0.5", features = ["cors", "trace", "compression-gzip"] }
sqlx = { version = "0.7", features = ["runtime-tokio", "postgres", "chrono", "uuid"] }
# Dependências internas
meu-saas-core = { path = "../core" }
shared = { path = "../../shared" }
[dev-dependencies]
reqwest = { version = "0.11", features = ["json"] }
wiremock = "0.5"
testcontainers = "0.15"
[features]
default = ["postgres"]
postgres = ["sqlx/postgres"]
mysql = ["sqlx/mysql"]
Exemplo 3: Script de CI/CD com Cargo
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
# Cache de dependências
- uses: Swatinem/rust-cache@v2
# Verificar formatação
- run: cargo fmt --all -- --check
# Linting com Clippy
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings
# Compilar
- run: cargo build --workspace --all-features
# Testes
- run: cargo test --workspace --all-features
# Auditoria de segurança
- run: cargo install cargo-audit && cargo audit
Comparação com Alternativas
| Característica | Cargo (Rust) | npm (Node.js) | pip (Python) | Maven (Java) |
|---|---|---|---|---|
| Gerenciamento de deps | Integrado | Integrado | Básico | Integrado |
| Build system | Integrado | Scripts | Externo | Integrado |
| Lockfile | Cargo.lock | package-lock.json | requirements.txt | pom.xml |
| Reprodutibilidade | Excelente | Boa | Fraca | Boa |
| Workspaces | Nativo | Nativo | Não | Multi-módulo |
| Testes | Integrado | Externo (jest) | Externo (pytest) | Integrado |
| Docs | Integrado | Externo (jsdoc) | Externo (sphinx) | Integrado |
| Benchmarks | Integrado | Externo | Externo | Externo |
| Compilação condicional | Features | Não | Não | Profiles |
| Velocidade de resolução | Rápida | Média | Lenta | Média |
| Registro | crates.io | npmjs.com | PyPI | Maven Central |
Plugins Essenciais do Cargo
# Instalar plugins úteis
cargo install cargo-watch # Recompilar ao salvar
cargo install cargo-expand # Expandir macros
cargo install cargo-audit # Auditoria de segurança
cargo install cargo-outdated # Ver deps desatualizadas
cargo install cargo-deny # Políticas de dependências
cargo install cargo-flamegraph # Gráficos de performance
cargo install cargo-nextest # Test runner mais rápido
cargo install cargo-machete # Encontrar deps não usadas
cargo install cargo-bloat # Análise de tamanho do binário
# Usar plugins
cargo watch -x check -x test # Checar e testar ao salvar
cargo expand nome_do_modulo # Ver macro expandida
cargo audit # Checar vulnerabilidades
cargo outdated # Listar deps desatualizadas
cargo deny check # Verificar políticas
cargo flamegraph # Gerar flamegraph
cargo nextest run # Testes paralelos rápidos
cargo machete # Deps não utilizadas
cargo bloat --release --crates # Tamanho por crate
Conclusão
O Cargo é uma ferramenta indispensável no ecossistema Rust, combinando gerenciamento de dependências, build system, test runner e muito mais em uma única ferramenta coesa. Dominar o Cargo significa dominar o fluxo de trabalho Rust.
Pontos-chave para lembrar:
- Cargo.toml é o centro de configuração do seu projeto
- Workspaces organizam projetos complexos com múltiplas crates
- Features permitem compilação condicional flexível
- Build profiles otimizam para desenvolvimento ou produção
- Plugins estendem funcionalidades com ferramentas da comunidade
- Cargo.lock garante builds reproduzíveis para binários
Para aprofundar seus conhecimentos, consulte a documentação oficial do Cargo e explore o The Cargo Book para referência completa de todas as opções disponíveis.
No próximo passo, aprenda sobre o Rustup para gerenciar toolchains e targets de compilação.