Una solución alternativa es no tratar de agrupar ambas cosas en un solo paquete. Para proyectos un poco más grandes con un ejecutable amigable, me pareció muy agradable usar un espacio de trabajo
Creamos un proyecto binario que incluye una biblioteca dentro de él:
the-binary
├── Cargo.lock
├── Cargo.toml
├── mylibrary
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
└── src
└── main.rs
Cargo.toml
Esto usa la [workspace]
clave y depende de la biblioteca:
[package]
name = "the-binary"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]
[workspace]
[dependencies]
mylibrary = { path = "mylibrary" }
src / main.rs
extern crate mylibrary;
fn main() {
println!("I'm using the library: {:?}", mylibrary::really_complicated_code(1, 2));
}
mylibrary / src / lib.rs
use std::error::Error;
pub fn really_complicated_code(a: u8, b: u8) -> Result<u8, Box<Error>> {
Ok(a + b)
}
Y ejecutarlo:
$ cargo run
Compiling mylibrary v0.1.0 (file:///private/tmp/the-binary/mylibrary)
Compiling the-binary v0.1.0 (file:///private/tmp/the-binary)
Finished dev [unoptimized + debuginfo] target(s) in 0.73 secs
Running `target/debug/the-binary`
I'm using the library: Ok(3)
Hay dos grandes beneficios para este esquema:
El binario ahora puede usar dependencias que solo se aplican a él. Por ejemplo, puede incluir muchas cajas para mejorar la experiencia del usuario, como analizadores de línea de comandos o formato de terminal. Ninguno de estos "infectará" la biblioteca.
El espacio de trabajo evita compilaciones redundantes de cada componente. Si corremos cargo build
tanto en el mylibrary
y el the-binary
directorio, la biblioteca no se construirá en ambas ocasiones - es compartida entre ambos proyectos.