Como compilar vários binários com Cargo e não perder desempenho?
\n\nVocê já se deparou com uma situação em que seu projeto Rust cresce tanto que um único arquivo binário já não é suficiente? Talvez você esteja escrevendo um utilitário CLI que precisa ter arquivos executáveis separados para diferentes tarefas: um para análise de dados, outro para geração de relatórios, um terceiro para interagir com APIs. Ou você está criando uma aplicação servidora, onde precisa separar monitoramento, processamento de requisições e tarefas em segundo plano.
\n\nA pergunta "How can I build multiple binaries with Cargo?" é uma das mais populares no Stack Overflow entre desenvolvedores Rust. E não é por acaso. Quando um projeto vai além do simples "Hello, World!", saber organizar corretamente a compilação de múltiplos binários se torna uma habilidade crítica. Mas como fazer isso sem perder desempenho? Como não se afogar em duplicação de código e não tornar a compilação mais lenta?
\n\nNeste artigo, não vamos apenas responder a essa pergunta — vamos mostrar como transformar a compilação de múltiplos binários de uma dor de cabeça em uma poderosa ferramenta de otimização. Você aprenderá sobre as melhores práticas, desempenho e até mesmo truques secretos do Cargo que desenvolvedores Rust experientes utilizam.
\n\nPor que múltiplos binários? O problema de um único arquivo executável
\n\nImagine: você escreveu uma excelente biblioteca para trabalhar com dados. Depois adicionou uma interface CLI. Depois um servidor web. Depois um agendador de tarefas. Tudo em um único projeto. Resultado? Um monolito que:
\n\n- \n
- Compila eternamente, mesmo se você alterar apenas uma linha no CLI. \n
- Exige reiniciar toda a aplicação ao atualizar um único componente. \n
- É complexo de testar e implantar. \n
A solução — dividir o projeto em vários binários. Mas como fazer isso corretamente em Rust?
\n\nFundamentos: Cargo.toml e a seção [[bin]]
\n\nA maneira mais simples é declarar vários alvos binários no seu Cargo.toml. Vamos analisar um exemplo básico.
// Cargo.toml\n[package]\nname = "my_project"\nversion = "0.1.0"\nedition = "2021"\n\n[[bin]]\nname = "analyzer"\npath = "src/bin/analyzer.rs"\n\n[[bin]]\nname = "reporter"\npath = "src/bin/reporter.rs"\n\n[[bin]]\nname = "server"\npath = "src/bin/server.rs"\n\n[dependencies]\nserde = { version = "1.0", features = ["derive"] }\ntokio = { version = "1", features = ["full"] }\n\n\nAgora, na pasta src/bin/, você tem três arquivos: analyzer.rs, reporter.rs e server.rs. Cada um deles é um binário completo com sua própria função main().
Para compilar tudo de uma vez:
\ncargo build --release\n\nOu um binário específico:
\ncargo build --release --bin analyzer\n\nSimples? Sim. Mas é aí que está o truque. Se você não otimizar a compilação, cada binário será compilado novamente, mesmo que usem as mesmas dependências. E isso é um caminho direto para a perda de desempenho.
\n\nOtimização do desempenho da compilação: perfis Cargo
\n\nO segredo da compilação eficiente de múltiplos binários está nos perfis Cargo. Esta é uma ferramenta poderosa que permite configurar parâmetros de compilação para diferentes cenários.
\n\nPerfis básicos: dev e release
\n\nPor padrão, o Cargo usa dois perfis: dev (para desenvolvimento) e release (para produção). Mas você pode criar seus próprios perfis ou modificar os existentes.
// Cargo.toml\n[profile.release]\nopt-level = 3 # Otimização máxima de código\nlto = "fat" # Link-Time Optimization (fusão de todas as crates)\ncodegen-units = 1 # Um único thread de codegen para melhor otimização\nstrip = true # Remoção de informações de depuração\n\n\nEssas configurações são especialmente importantes para binários que precisam ser rápidos. Mas há um detalhe: quanto mais agress