Olá, Cargo!
Cargo é o sistema de build e gerenciador de pacotes do Rust. A maioria dos rustaceanos usa essa ferramenta para gerenciar seus projetos Rust, porque Cargo cuida de muitas tarefas para você, como compilar seu código, baixar as bibliotecas das quais ele depende e compilar essas bibliotecas. Chamamos as bibliotecas de que seu código precisa de dependências.
Os programas mais simples em Rust, como o que escrevemos até agora, não têm dependências. Se tivéssemos criado o projeto “Hello, world!” com o Cargo, ele usaria apenas a parte do Cargo responsável por compilar seu código. Conforme você escrever programas Rust mais complexos, adicionará dependências e, se iniciar o projeto com Cargo, isso será muito mais fácil.
Como a vasta maioria dos projetos Rust usa Cargo, o restante deste livro pressupõe que você também o está usando. Cargo vem instalado com Rust se você usou os instaladores oficiais discutidos na seção “Instalação”. Se instalou o Rust de outra forma, verifique se o Cargo está instalado digitando o seguinte no terminal:
$ cargo --version
Se você vir um número de versão, então está tudo certo! Se vir um erro, como
command not found, consulte a documentação do seu método de instalação para
descobrir como instalar Cargo separadamente.
Criando um projeto com Cargo
Vamos criar um novo projeto usando Cargo e observar como ele difere do nosso projeto original “Hello, world!”. Volte para o diretório projects ou para o local onde decidiu guardar seu código. Em qualquer sistema operacional, execute o seguinte:
$ cargo new hello_cargo
$ cd hello_cargo
O primeiro comando cria um novo diretório e projeto chamados hello_cargo. Demos ao projeto o nome hello_cargo, e o Cargo cria seus arquivos em um diretório com esse mesmo nome.
Entre no diretório hello_cargo e liste os arquivos. Você verá que o Cargo gerou dois arquivos e um diretório para nós: um arquivo Cargo.toml e um diretório src com um arquivo main.rs dentro dele.
Ele também inicializou um novo repositório Git junto com um arquivo
.gitignore. Os arquivos do Git não serão gerados se você executar
cargo new dentro de um repositório Git já existente; você pode mudar esse
comportamento usando cargo new --vcs=git.
Nota: Git é um sistema de controle de versão bastante comum. Você pode mudar
cargo newpara usar outro sistema de controle de versão ou nenhum, usando a flag--vcs. Executecargo new --helppara ver as opções disponíveis.
Abra Cargo.toml no editor de texto de sua preferência. Ele deve se parecer com o código da Listagem 1-2.
[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2024"
[dependencies]
cargo newEsse arquivo está no formato TOML (Tom’s Obvious, Minimal Language), que é o formato de configuração do Cargo.
A primeira linha, [package], é um cabeçalho de seção que indica que as
declarações seguintes configuram um package. À medida que adicionarmos mais
informações a esse arquivo, acrescentaremos outras seções.
As três linhas seguintes definem as informações de configuração de que o Cargo
precisa para compilar seu programa: o nome, a versão e a edição do Rust a ser
usada. Falaremos sobre a chave edition no Apêndice E.
A última linha, [dependencies], marca o começo de uma seção na qual você
listará as dependências do projeto. Em Rust, pacotes de código são chamados de
crates. Não precisaremos de outros crates para este projeto, mas
precisaremos no primeiro projeto do Capítulo 2, então usaremos essa seção
naquela ocasião.
Agora abra src/main.rs e dê uma olhada:
Nome do arquivo: src/main.rs
fn main() {
println!("Hello, world!");
}
O Cargo gerou para você um programa “Hello, world!”, exatamente como o que escrevemos na Listagem 1-1! Até aqui, as diferenças entre o nosso projeto e o projeto gerado pelo Cargo são que o Cargo colocou o código dentro do diretório src e criou um arquivo de configuração Cargo.toml no diretório superior.
O Cargo espera que seus arquivos-fonte fiquem dentro do diretório src. O diretório de topo do projeto deve conter apenas arquivos README, informações de licença, arquivos de configuração e qualquer outra coisa que não esteja diretamente relacionada ao código. Usar Cargo ajuda a organizar seus projetos. Há um lugar para cada coisa, e cada coisa fica em seu lugar.
Se você iniciou um projeto sem usar Cargo, como fizemos com o projeto “Hello,
world!”, pode convertê-lo para um projeto que use Cargo. Mova o código do
projeto para o diretório src e crie um arquivo Cargo.toml adequado. Uma
forma simples de obter esse arquivo Cargo.toml é executar cargo init, que o
criará automaticamente para você.
Compilando e executando um projeto Cargo
Agora vamos ver o que muda quando compilamos e executamos o programa “Hello, world!” com Cargo! No diretório hello_cargo, compile o projeto digitando:
$ cargo build
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs
Esse comando cria um executável em target/debug/hello_cargo ou target\debug\hello_cargo.exe no Windows, em vez de gerá-lo no diretório atual. Como o build padrão é de depuração, o Cargo coloca o binário em um diretório chamado debug. Você pode executar o executável com este comando:
$ ./target/debug/hello_cargo # ou .\target\debug\hello_cargo.exe no Windows
Hello, world!
Se tudo correr bem, Hello, world! deve ser impresso no terminal. Executar
cargo build pela primeira vez também faz o Cargo criar um novo arquivo no
nível superior do projeto: Cargo.lock. Esse arquivo mantém registro das
versões exatas das dependências do projeto. Como este projeto não tem
dependências, o arquivo é bem enxuto. Você nunca precisará alterá-lo
manualmente; o Cargo gerencia seu conteúdo para você.
Acabamos de compilar um projeto com cargo build e executá-lo com
./target/debug/hello_cargo, mas também podemos usar cargo run para compilar
o código e depois executar o binário resultante em um único comando:
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/hello_cargo`
Hello, world!
Usar cargo run é mais conveniente do que lembrar de executar cargo build e
depois usar o caminho completo até o binário, então a maioria dos
desenvolvedores prefere cargo run.
Observe que, desta vez, não vimos a saída indicando que o Cargo estava
compilando hello_cargo. O Cargo percebeu que os arquivos não haviam mudado,
então ele não recompilou nada; apenas executou o binário. Se você tivesse
modificado o código-fonte, o Cargo recompilaria o projeto antes de executá-lo,
e você veria esta saída:
$ cargo run
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.33 secs
Running `target/debug/hello_cargo`
Hello, world!
O Cargo também oferece um comando chamado cargo check. Esse comando verifica
rapidamente se seu código compila, mas não produz um executável:
$ cargo check
Checking hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
Por que você não iria querer um executável? Muitas vezes, cargo check é bem
mais rápido do que cargo build, porque pula a etapa de gerar o executável. Se
você estiver checando seu trabalho continuamente enquanto escreve código, usar
cargo check acelera o processo de descobrir se o projeto ainda está
compilando! Por isso, muitos rustaceanos executam cargo check
periodicamente enquanto escrevem seus programas, para garantir que tudo
continua compilando. Depois, quando estão prontos para usar o executável,
executam cargo build.
Vamos recapitular o que aprendemos até aqui sobre Cargo:
- Podemos criar um projeto usando
cargo new. - Podemos compilar um projeto usando
cargo build. - Podemos compilar e executar um projeto em uma única etapa usando
cargo run. - Podemos verificar se há erros em um projeto sem produzir um binário usando
cargo check. - Em vez de salvar o resultado do build no mesmo diretório do código, o Cargo o armazena no diretório target/debug.
Uma vantagem adicional do Cargo é que os comandos são os mesmos independentemente do sistema operacional em que você está trabalhando. Por isso, a partir deste ponto, deixaremos de fornecer instruções separadas para Linux e macOS versus Windows.
Compilando para release
Quando o projeto finalmente estiver pronto para release, você pode usar
cargo build --release para compilá-lo com otimizações. Esse comando criará um
executável em target/release em vez de target/debug. As otimizações fazem o
código Rust rodar mais rápido, mas ativá-las aumenta o tempo de compilação.
Por isso há dois perfis diferentes: um para desenvolvimento, quando você quer
recompilar rapidamente e com frequência, e outro para gerar o programa final
que será entregue ao usuário, que não será recompilado repetidamente e deverá
executar o mais rápido possível. Se você estiver medindo o tempo de execução do
seu código, lembre-se de rodar cargo build --release e fazer o benchmark com
o executável em target/release.
Aproveitando as convenções do Cargo
Em projetos simples, o Cargo não oferece muito mais valor do que usar rustc
diretamente, mas ele mostra seu valor à medida que os programas ficam mais
complexos. Quando um programa cresce para múltiplos arquivos ou passa a precisar
de dependências, é muito mais fácil deixar o Cargo coordenar o build.
Mesmo sendo simples, o projeto hello_cargo já usa grande parte do ferramental
real que você vai utilizar no restante da sua carreira com Rust. Na prática,
para trabalhar em qualquer projeto existente, você pode usar os comandos a
seguir para baixar o código com Git, entrar no diretório do projeto e compilar:
$ git clone example.org/someproject
$ cd someproject
$ cargo build
Para mais informações sobre Cargo, consulte sua documentação.
Resumo
Você já começou muito bem sua jornada com Rust! Neste capítulo, você aprendeu a:
- Instalar a versão estável mais recente do Rust usando
rustup. - Atualizar para uma versão mais nova do Rust.
- Abrir a documentação instalada localmente.
- Escrever e executar um programa “Hello, world!” usando
rustcdiretamente. - Criar e executar um novo projeto usando as convenções do Cargo.
Este é um ótimo momento para construir um programa mais substancial e se acostumar a ler e escrever código Rust. Então, no Capítulo 2, construiremos um programa de jogo de adivinhação. Se preferir começar entendendo como conceitos comuns de programação funcionam em Rust, veja o Capítulo 3 e depois volte ao Capítulo 2.