Uma solução alternativa é realmente não tentar empilhar as duas coisas em um único pacote. Para projetos um pouco maiores com um executável amigável, achei muito bom usar um espaço de trabalho
Criamos um projeto binário que inclui uma biblioteca dentro dele:
the-binary
├── Cargo.lock
├── Cargo.toml
├── mylibrary
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
└── src
└── main.rs
Cargo.toml
Isso usa a [workspace]
chave e depende da 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)
}
E execute:
$ 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)
Existem dois grandes benefícios para esse esquema:
O binário agora pode usar dependências que se aplicam apenas a ele. Por exemplo, você pode incluir várias caixas para melhorar a experiência do usuário, como analisadores de linha de comando ou formatação de terminal. Nada disso "infectará" a biblioteca.
O espaço de trabalho evita construções redundantes de cada componente. Se rodarmos cargo build
no diretório mylibrary
e the-binary
, a biblioteca não será construída nas duas vezes - será compartilhada entre os dois projetos.