Biblioteca y binario en Rust: cómo empaquetar sin perder rendimiento

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Un paquete, dos entidades: ¿mito o realidad?

\n\n

Imagina: has escrito en Rust una biblioteca increíble para trabajar con grandes datos. Es ultrarrápida, segura y elegante. Pero no solo necesitas una API para otros desarrolladores, sino también una utilidad CLI lista para probar la biblioteca o usarla en pipelines. Surge la pregunta clásica que ha acumulado miles de visitas en Stack Overflow: «Package with both a library and a binary?» (paquete que contiene tanto una biblioteca como un archivo ejecutable).

\n\n

Para un principiante en Rust, esto suena como un rompecabezas. Para un desarrollador experimentado, es una tarea de optimización de la estructura del proyecto y el rendimiento. En este artículo no solo responderemos a esta pregunta, sino que lo haremos con un enfoque en optimización y rendimiento — las dos cosas por las que Rust es más amado.

\n\n

Analizaremos cómo organizar correctamente dicho paquete, evitar la duplicación de código, acelerar la compilación y hacer que tu binario sea realmente rápido. ¡Allá vamos!

\n\n

Estructura del paquete: Cargo.toml lo resuelve todo

\n\n

En Rust, un solo paquete Cargo puede contener tanto una biblioteca (lib) como varios binarios (bin). Esto no es magia, sino una simple convención sobre la estructura de carpetas. Veamos un ejemplo mínimo.

\n\n

Creemos un proyecto:

\n\n
cargo new my_tool --lib
\n\n

Ahora modifiquemos el archivo Cargo.toml para indicar explícitamente que tenemos tanto una biblioteca como un binario:

\n\n
[package]\nname = "my_tool"\nversion = "0.1.0"\nedition = "2021"\n\n[lib]\nname = "my_tool_lib"\npath = "src/lib.rs"\n\n[[bin]]\nname = "my_tool"\npath = "src/main.rs"\n\n[dependencies]\n
\n\n

La estructura de carpetas se verá así:

\n\n
my_tool/\n├── Cargo.toml\n├── src/\n│   ├── lib.rs      // Biblioteca\n│   └── main.rs     // Binario\n
\n\n

Es sencillo, ¿verdad? Pero el diablo está en los detalles. Si simplemente copias el código de la biblioteca en main.rs, obtendrás duplicación y problemas de rendimiento. Hay que actuar con más inteligencia.

\n\n

Enfoque correcto: el binario usa la biblioteca

\n\n

El binario debe importar la biblioteca como un crate externo. Incluso si están en el mismo paquete. Esto no solo reduce la duplicación, sino que también permite al compilador de Rust optimizar mejor el código mediante optimización entre crates (LTO).

\n\n

Ejemplo de src/lib.rs:

\n\n
pub fn calculate(data: &[u64]) -> u64 {\n    data.iter().sum()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_calculate() {\n        assert_eq!(calculate(&[1, 2, 3]), 6);\n    }\n}\n
\n\n

Ejemplo de src/main.rs:

\n\n
use my_tool_lib::calculate;\n\nfn main() {\n    let numbers = vec![10, 20, 30];\n    println!("Suma: {}", calculate(&numbers));\n}\n
\n\n

Observa: usamos my_tool_lib — el nombre que asignamos a la biblioteca en Cargo.toml. El compilador las vinculará automáticamente en un solo binario, pero manteniendo la modularidad.

\n\n

Optimización del rendimiento: LTO, inline y benchmarks

\n\n

Ahora que la estructura está lista, hablemos de lo principal: cómo exprimir al máximo tu paquete. Porque si estás creando una herramienta para procesar datos, cada microsegundo cuenta.

\n\n

1. Activar la optimización en tiempo de enlace (LTO)

\n\n

LTO permite al compilador optimizar el código a través de los límites de los crates. Sin LTO, las funciones de la biblioteca y el binario se optimizan por separado. Con LTO, como una sola unidad.

\n\n

Añade en Cargo.toml:

\n\n
[profile.release]\nlto = true\ncodegen-units = 1\n
\n\n

Esto aumentará el tiempo de compilación, pero hará que el binario sea notablemente más rápido. Para el sitio educativo pythonlib.ru es importante destacar: LTO es el estándar para compilaciones de producción en Rust.

\n\n

2. Usar sugerencias inline

\n\n

Si en la biblioteca hay funciones críticas,

Blogs

Book Recommendations