Biblioteca e binário em Rust: como empacotar e não perder desempenho

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Um pacote — duas entidades: mito ou realidade?

\n\n

Imagine: você escreveu em Rust uma biblioteca incrível para trabalhar com grandes dados. Ela é relâmpago, segura e elegante. Mas você precisa não apenas de uma API para outros desenvolvedores, mas também de um utilitário CLI pronto para testar a biblioteca ou usá-la em pipelines. Surge a pergunta clássica que reuniu milhares de visualizações no Stack Overflow: «Package with both a library and a binary?» (pacote contendo tanto uma biblioteca quanto um arquivo executável).

\n\n

Para um iniciante em Rust, isso soa como um quebra-cabeça. Para um desenvolvedor experiente, é uma tarefa de otimização da estrutura do projeto e do desempenho. Neste artigo, não apenas responderemos a essa pergunta, mas o faremos com foco em otimização e desempenho — duas coisas pelas quais Rust é mais amado.

\n\n

Vamos analisar como organizar corretamente esse pacote, evitar duplicação de código, acelerar a compilação e tornar seu binário realmente rápido. Vamos lá!

\n\n

Estrutura do pacote: Cargo.toml resolve tudo

\n\n

Em Rust, um único pacote Cargo pode conter tanto uma biblioteca (lib) quanto vários binários (bin). Isso não é mágica, mas sim uma simples convenção de estrutura de pastas. Vamos ver um exemplo mínimo.

\n\n

Criaremos um projeto:

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

Agora modificaremos o arquivo Cargo.toml para indicar explicitamente que temos tanto uma biblioteca quanto um binário:

\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

A estrutura de pastas ficará assim:

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

Simples, não é? Mas o diabo está nos detalhes. Se você simplesmente copiar o código da biblioteca para o main.rs, terá duplicação e problemas de desempenho. É preciso agir de forma mais inteligente.

\n\n

Abordagem correta: o binário usa a biblioteca

\n\n

O binário deve importar a biblioteca como um crate externo. Mesmo que estejam no mesmo pacote. Isso não apenas reduz a duplicação, mas também permite que o compilador Rust otimize melhor o código através da otimização entre crates (LTO).

\n\n

Exemplo 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

Exemplo de src/main.rs:

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

Observe: usamos my_tool_lib — este é o nome que definimos para a biblioteca em Cargo.toml. O compilador automaticamente os vinculará em um único binário, mas manterá a modularidade.

\n\n

Otimização de desempenho: LTO, inline e benchmarks

\n\n

Agora que a estrutura está pronta, vamos falar sobre o principal — como extrair o máximo do seu pacote. Afinal, se você está criando uma ferramenta para processamento de dados, cada microssegundo conta.

\n\n

1. Ative a Link-Time Optimization (LTO)

\n\n

LTO permite que o compilador otimize o código através dos limites dos crates. Sem LTO, as funções da biblioteca e do binário são otimizadas separadamente. Com LTO, como um todo único.

\n\n

Adicione em Cargo.toml:

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

Isso aumentará o tempo de compilação, mas tornará o binário visivelmente mais rápido. Para o site educacional pythonlib.ru é importante destacar: LTO é o padrão para builds de produção em Rust.

\n\n

2. Use dicas de inline

\n\n

Se houver funções criticamente importantes na biblioteca,

Blogs

Book Recommendations