cargo, el gestor todo-en-uno
cargo new, check, build, run y test: qué hace exactamente cada orden, en qué se diferencian, y cómo Cargo.toml y Cargo.lock gobiernan tus dependencias con semver.
En otros lenguajes juntas a mano un compilador, un gestor de paquetes, un runner de tests y un generador de documentación, cada uno con su cultura y sus rarezas. En Rust todo eso es una sola herramienta: cargo. Aprender sus verbos es aprender el flujo de trabajo entero.
- Crear paquetes binarios y de librería con
cargo new. - Dominar el ciclo
check,buildyrun, y cuándo usar cada uno. - Ejecutar la batería de pruebas con
cargo test. - Declarar dependencias en
Cargo.tomly entender semver y el lockfile.
Crear un paquete
cargo new hola # paquete binario (con src/main.rs)cargo new --lib mi_lib # paquete de librería (con src/lib.rs)cargo init # inicializa cargo en un directorio ya existentecargo new hola genera la estructura mínima y un repositorio git:
hola/├── Cargo.toml # el manifiesto: metadatos y dependencias├── .gitignore # ignora /target└── src/ └── main.rs # el punto de entradaEl ciclo diario: check, build, run
Estas tres órdenes son el 90% de tu día, y confundirlas cuesta tiempo:
cargo checkanaliza y comprueba tipos y borrow checker, pero no genera el binario final. Es varias veces más rápido quebuild: es tu bucle de feedback mientras escribes.cargo buildcompila de verdad. Sin flags, produce un binario debug entarget/debug/(rápido de compilar, sin optimizar, con símbolos). Con--releaseproduce uno optimizado entarget/release/(lento de compilar, veloz de ejecutar).cargo runhacebuildsi hace falta y ejecuta el binario. Acepta los mismos flags:cargo run --release.
cargo check # el más rápido: solo validacargo build # binario debugcargo build --release # binario optimizadocargo run -- arg1 arg2 # ejecuta; lo que va tras -- son args del programacheck es tu compañero de escritura
Deja cargo check (o rust-analyzer, que lo hace por ti) corriendo mientras programas. Como omite la generación de código máquina, te da los errores de tipos y de ownership en una fracción del tiempo de un build completo. Reserva build --release para medir rendimiento o publicar.
Probar: cargo test
cargo test compila un harness especial y ejecuta todo lo que sea una prueba: funciones marcadas con #[test], los tests de integración en tests/ y hasta los ejemplos de tu documentación.
pub fn suma(a: i32, b: i32) -> i32 { a + b}#[cfg(test)]mod tests { use super::*; #[test] fn suma_positivos() { assert_eq!(suma(2, 3), 5); }}cargo test # toda la bateríacargo test suma_positivos # solo los tests cuyo nombre contenga esocargo test -- --nocapture # deja ver los println de los testsEl #[cfg(test)] hace que ese módulo solo se compile al probar: no pesa ni un byte en tu binario final.
Cargo.toml y las dependencias
El manifiesto declara qué es tu paquete y de qué depende:
[package]name = "hola"version = "0.1.0"edition = "2024"[dependencies]serde = { version = "1.0", features = ["derive"] }rand = "0.9"[dev-dependencies]criterion = "0.5" # solo para tests y benchmarksLa forma más cómoda de añadir dependencias es dejar que cargo edite el manifiesto:
cargo add serde --features derivecargo add tokio --features fullUna versión como "1.0" es, por defecto, un requisito caret: equivale a >=1.0.0, <2.0.0. Cargo elige la versión más alta compatible y la congela en Cargo.lock, con hashes y versiones exactas de todo el árbol de dependencias.
Más allá de las dependencias, el manifiesto controla cómo se compila. Los perfiles ajustan la optimización, y un workspace agrupa varios crates que comparten Cargo.lock y el directorio target/:
[profile.release]opt-level = 3 # optimización agresivalto = true # link-time optimization entre cratescodegen-units = 1 # compila más lento, binario más rápido[workspace]members = ["app", "core", "cli"]Cargo.lock: cuándo se versiona
Para una aplicación (un binario), commitea Cargo.lock: garantiza que todos compilan bits idénticos. Para una librería el criterio clásico era no versionarlo, aunque hoy se recomienda hacerlo también para que tu CI sea reproducible. cargo update recalcula el lockfile dentro de los rangos de semver.
cargo es por qué el ecosistema de Rust es coherente
Cargo no es un lujo: es una de las razones por las que Rust se adopta tan rápido. Un manifiesto declarativo, un resolvedor de dependencias con semver de verdad, un lockfile reproducible, un runner de tests integrado, doctests que garantizan que tus ejemplos compilan, y cargo doc, cargo bench, cargo tree y cargo add, todo con la misma interfaz y sin configuración. Compáralo con el mundo de C, donde el build system, el gestor de paquetes y el runner de tests son decisiones separadas que cada proyecto resuelve a su manera. La consecuencia es cultural: como todos usan cargo, cualquier crate de crates.io se compila con cargo build sin leer instrucciones. Esa uniformidad —una sola herramienta que todos comparten— es un activo de ingeniería tan valioso como el propio borrow checker. Dominar sus verbos no es aprender un comando: es adoptar el flujo de trabajo estándar de todo un ecosistema.
Ejercita todos los verbos
- Crea un paquete binario con
cargo newe inspecciona elCargo.tomly el árbol de archivos. - Lanza
cargo check,cargo buildycargo build --release, y compara qué aparece entarget/. - Añade
randconcargo addy úsalo para imprimir un número aleatorio concargo run. - Escribe una función con un
#[test]y córrelo concargo test. - Mira el árbol de dependencias con
cargo treey abre la doc de tu crate concargo doc --open.