Última atualização:

Ambiente de desenvolvimento Rust

Ana Hoverbear
Ana Hoverbear rust

Atenção: este texto foi traduzido, editado e adaptado por @nawarian. Você encontra o texto original, escrito em 2017 em inglês, no blog parceiro Hoverbear.org através deste link.

Conteúdos do post

Neste artigo eu vou te mostrar uma forma de preparar seu ambiente para desenvolver em Rust. Há formas diferentes, principalmente quando se trata do editor de texto, então sinta-se livre pra pular o que não for relevante pra si. Nós vamos focar em:

  • Configurar Rust usando o Rustup
  • Utilitários como clippy e rustfmt
  • Configurar o VS Code para trabalhar com Rust
  • Depurar na linha de comando e no VS Code
  • Utilizar diferentes alvos (targets) de compilação

Tudo o que eu explico aqui funciona tanto no Linux quanto no MacOS, no Windows pode ser que você precise se adaptar um pouco, já que eu não tenho um sistema Windows para testar este artigo.

Para executar as instruções deste artigo você precisará do pacote build-essentials caso utilize Ubuntu ou Debian, base-devel para a distro Arch ou XCode para MacOS.

Configurando Rust utilizando o Rustup

Rustup é um projeto oficial do Rust que nos permite instalar, gerenciar e atualizar várias ferramentas Rust. Para instalar o rustup, rode o seguinte comando:

curl https://sh.rustup.rs -sSf | sh

Depois de baixar, Rustup vai nos fazer algumas perguntas para configurar o ambiente. Vamos apenas aceitar as configurações padrão aqui:

Current installation options:

   default host triple: x86_64-apple-darwin
     default toolchain: stable
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation

E logo depois a ferramenta vai nos propor executar o seguinte comando para atualizar o nosso shell:

source $HOME/.cargo/env

A partir deste momento, podemos executar cargo e rustc para confirmar que temos tanto o compilador Rust quanto a ferramenta Cargo instaladas. A ferramenta rustup também deveria estar instalada agora.

É recomendado instalar o código fonte do Rust e a documentação também, para que possamos utilizar o modo offline ou para auto completar código.

rustup component add rust-src
rustup component add rust-docs

Em algum momento da vida, nós vamos querer atualizar a nossa instalação. O seguinte comando vai nos ajudar a atualizar as ferramentas e componentes do Rust.

rustup update

Pode ser também que você encontre algum projeto ou tutorial que utilize a build nightly (beta) do Rust. Você pode facilmente instalar a versão nightly juntamente da build principal.

rustup toolchain install nightly

Você pode alterar qual o ferramental padrão no seu sistema (entre nightlystable) utilizando os comandos rustup default stable ou rustup default nightly, mas a recomendação é manter a build stable e escrever overrides para projetos que utilizem a build nightly. Você pode criar este override navegando até o projeto que quer usar nightly e rodando o seguinte comando:

rustup override set nightly

Por agora isso é tudo o que precisamos saber sobre Rustup.

Ferramentas úteis

Vamos falar sobre quatro ferramentas muito úteis para trabalhar com Rust:

  • rust-clippy - Um linter.
  • rustfmt - formatador de código.
  • racer - auto completar código.
  • rls - servidor de linguagem (para usar com VIM, VS Code...)

rust-clippy

Pra que serve isso? O compilador Rust já é bem restritivo. clippy vai além e nos ajuda a evitar algumas más práticas. Isto pode ajudar a evitar problemas inesperados no nosso código.

clippy depende de nightly para rodar. Nós já instalamos nightly quando rodamos rustup toolchain install nightly, então não teremos problema nenhum.

Vamos instalar o clippy através do nightly com o seguinte comando:

cargo +nightly install clippy

Agora vamos testar a nossa ferramenta. Rode cargo init --bin test && cd test e modifique o arquivo src/main.rs pra que fique com o seguinte conteúdo:

fn main() {
    // Clippy reclama de statements que não fazem nada,
// como este "true" abandonado
true;
}

Vamos rodar clippy com o seguinte comando:

cargo +nightly clippy

Isto deveria gerar um alerta (warning) do clippy:

warning = "statement with no effect"
 --> src/main.rs:2:5
  |
2 |     true;
  |     ^^^^^
  |
  = note: #[warn(no_effect)] on by default
  = help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#no_effect

Excelente! Você pode ver todas as regras que clippy consegue detectar aqui. Você pode configurar várias regras no arquivo clippy.toml de acordo com as opções listadas na wiki.

Para desabilitar algumas regras (ou torná-las avisos em vez de erros) você pode adicionar as flags deny, warn, ou allow nos atributos da sua crate:

#![cfg_attr(feature = "cargo-clippy", deny(empty_enum))]
#![cfg_attr(feature = "cargo-clippy", warn(indexing_slicing))]
#![cfg_attr(feature = "cargo-clippy", allow(print_with_newline))]

rustfmt

Pra que serve isso? Um estilo consistente, padrão e automatizado no projeto (e entre vários projetos) pode ser útil durante revisões de código, para atrair novas contribuições e evitar discussões supérfluas.

rustfmt é uma ferramenta de formatação de código similar ao gofmt. Ao contrário do clippy, ela roda sem poblemas com a build stable do Rust. Vamos instalar o rustfmt:

cargo install rustfmt

A partir daqui podemos rodar cargo fmt para reformatar o repositório. Este comando roda rustfmt no modo replace (substituição) que cria arquivos de backup com a extensão .bk. Se o projeto utiliza algum tipo de controle de versão (como o Git) você talvez não deseje este comportamento. Neste caso, podemos escrever o seguinte num arquivo rustfmt.toml para evitar a criação de arquivos .bk:

write_mode = "overwrite"

O arquivo rustfmt.toml nos permite configurar várias opções listadas pelo comando rustfmt --config-help. Agora vamos editar o arquivo main.rs e bagunçar um pouco o estilo dele:

fn       main    ()
{ true
; }

Se você rodar cargo fmt agora vai notar que main.rs está formatado corretamente de novo.

rustfmt ainda não está 100% pronto e pode acontecer de bagunçar o seu código de vez  em quando.

racer

Pra que serve isso? Racer nos ajuda a evitar procurar referências rápidas na documentação e nos ajuda a descobrir novas funcionalidades conforme escrevemos código em Rust.

racer é uma ferramenta para autocompletar código que é utilizada por vários add-ons de editores de código juntamente do rls, que vamos instalar em seguida.

Anteriormente, nós rodamos rustup component add rust-src. Este foi o primeiro passo para instalar o racer. Vamos agora instalar a ferramenta em si:

cargo install racer

Nós precisamos definir uma variável de ambiente para que racer saiba onde buscar o código fonte do Rust. No seu ~/.bashrc (ou ~/.zshrc) adicione o seguinte:

# Mac
export RUST_SRC_PATH=${HOME}/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/src

#
Linux export RUST_SRC_PATH=${HOME}/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src

Se você não usa MacOS ou Linux, vai precisar precisar definir a variável de ambiente de acordo com o que é mostrado pelo comando rustup show.

Você pode testar se racer está funcionando com o seguinte comando:

racer complete std::io::B

Você deveria ver várias sugestões para o comando acima. A partir de agora, racer já está preparado para ser utilizado pelo seu editor de texto ou com o rls.

rls

Pra que serve isso? Para criar uma experiência de desenvolvimento mais agradável e ampliar as funcionalidades do racer.

rls é um servidor de linguagem (language server) especializado em Rust. Ele traz consigo funcionalidades como auto completar código, ir-para definições e refatorações.

Para instalar rls nós precisamos dizer ao Rustup para utilizar uma toolchain específica. MacOS utiliza a nightly-x86_64-apple-darwin e Linux utiliza a nightly-x86_64-unknown-linux-gnu. Se você não usa VS Code, pode pular este passo.

rustup component add rls --toolchain nightly-x86_64-apple-darwin
rustup component add rust-analysis --toolchain nightly-x86_64-apple-darwin
rustup component add rust-src --toolchain nightly-x86_64-apple-darwin

Em seguida, precisamos definir outras duas variáveis de ambiente: DYLD_LIBRARY_PATH e RLS_ROOT:

# Mac
export DYLD_LIBRARY_PATH=${HOME}/.rustup/toolchains/stable-x86_64-apple-darwin/lib
export RLS_ROOT=${HOME}/git/rust/rls

#
Linux export DYLD_LIBRARY_PATH=${HOME}/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib export RLS_ROOT=${HOME}/git/rust/rls

Agora estamos prontos! Nós vamos testar e usar o rls mais tarde, quando configurarmos o VS Code.

Configurando o VS Code para código em Rust

Eu usei o VS Code para Rust por vários meses e achei bem delicinha. Como qualquer editor de textos, há várias configurações a serem ajustadas. Vamos focar nas mais relevantes.

Você pode usar outro editor, e tá tudo bem. Vai em frente! Eu ainda uso o vim para editar coisas rápidas e alguns colegas meus gostam bastante de seus emacs. Diversidade faz bem, use o que é bom pra ti e deixe os outros usarem o que for melhor para eles.

Primeiro, vamos baixar o VS Code. Basta entrar no site oficial e baixar o instalador.

Para poder rodar o comando code na CLI nós precisamos abrir o VS Code e abrir a paleta de comandos (Command Palette) com o atalho Shift + Command + P (MacOS) ou Shift + Control + P (Linux). Aqui, escreva shell command e procure pela opção Shell Command: Install 'code' command in PATH. Após selecionar esta opção, qualquer nova sessão de terminal deverá ter o comando code preparado.

Extensão: Rust

A extensão Rust traz alguns utilitários para fazer o build, formatar código e outras coisas úteis.

Extensão: rls_vscode

Nós vamos precisar do node instalado, você pode utilizar seu gerenciador de pacotes para isso. No MacOS, brew já resolve o problema.

Com o node já instalado, vamos instalar a extensão rls_vscode. Mas já que esta extensão ainda não foi lançada, nós vamos precisar fazer um pouco de trabalho manual. Vamos clonar e instalar as dependências do repositório rls_vscode;

git clone https://github.com/jonathandturner/rls_vscode.git
cd rls_vscode
npm install

O próximo passo é fazer o build da extensão, que podemos fazer diretamente utilizando o VS Code. Rode o comando code . dentro do repositório que acabamos de clonar para abrir o VS Code naquele diretório. Já dentro do VS Code, aperte o botão de Build perto da opção Launch Extension no painel da esquerda. Uma nova janela do VS Code vai abrir, mas você pode fechá-la imediatamente.

Agora que nós compilamos a extensão, vamos criar um link simbólico (symlink) para instalar no VS Code. Se você estiver usando o VS Code Insiders, o diretório é .vscode-insiders em vez de .vscode.

ln -s ${HOME}/git/rust/rls_vscode/ ${HOME}/.vscode/extensions/rls_vscode

Depois você pode atualizar a extensão com utilizando um processo parecido. É recomendado atualizar a extensão com frequência porque várias atualizações estão sendo lançadas.

Agora pode fechar e abrir o VS Code de novo. Ao abrir qualquer projeto Rust você deverá ver uma barra azul na parte de baixo da tela dizendo "RLS analysis: Starting up" e, alguns minutos depois, "RLS analysis: Done".

Se você reiniciar a sua máquina você vai precisar abrir um terminal antes de abrir o VS Code, ou usar o terminal integrado do VS Code e logo após reiniciar o programa. Há algumas formas de corrigir isto, mas dá muito trabalho. Talvez num futuro próximo a gente veja alguma configuração do VS Code que melhore esta situação.

Extensão: Better TOML

O ecossistema Rust usa bastante arquivos TOML para gerenciar configuração. A extensão 'Rusty code' já traz algum suporte ao formato TOML, mas a extensão 'Better TOML' é bem melhor e vale a pena ter no seu VS Code.

Extensão: Depurador LLDB

A extensão 'LLDB Debugger' (Low Level Debugger Debugger) nos permite depurar aplicações Rust dentro do VS Code. Você vai precisar também da biblioteca six do Python, que você pode instalar com o comando pip install six.

Como depurar código em Rust

Vamos criar uma aplicação basiquinha pra testar como a depuração funciona antes de fazer qualquer teste mais complicado. Rode o comando cargo init --bin example e coloque o seguinte conteúdo no arquivo src/main.rs:

pub enum Direction { North, South, East, West }

pub fn is_north(dir: Direction) -> bool {
    match dir {
        Direction::North => true,
        _ => false,
    }
}

fn main() {
    let two = 1+1;
    println!("{}", two);

    let points = Direction::South;
    let compass = is_north(points);
    println!("{}", compass);
}

Com isso a gente já consegue praticar a depuração. Bora debugar!

Na linha de comando

Antes de qualquer coisa, a gente precisa rodar o debugger. Vamos primeiro compilar com cargo build e depois rodar o nosso programa através do depurador rust-lldb.

cargo build
rust-lldb ./target/debug/example

Daí em diante a gente pode interagir com o depurador como normalmente faríamos usando o LLDB. Ah, sim, também existe a alternativa rust-gdb se você quiser se aventurar.

Por exemplo:

(lldb) breakpoint set -f main.rs -l 3
Breakpoint 1: where = example`example::is_north + 10 at main.rs:3, address = 0x0000000100000ffa
(lldb) process launch
Process 8376 launched: '/Users/hoverbear/git/rust/example/target/debug/example' (x86_64)
2
Process 8376 stopped
* thread #1: tid = 0x2c222, 0x0000000100000ffa example`example::is_north(dir=South) + 10 at main.rs:3, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100000ffa example`example::is_north(dir=South) + 10 at main.rs:3
   1   	pub enum Direction { North, South, East, West }
   2
-> 3   	fn is_north(dir: Direction) -> bool {
   4   	    match dir {
   5   	        Direction::North => true,
   6   	        _ => false,
   7   	    }
(lldb) print dir
(example::Direction) $0 = South

No VS Code

Depois de instalar a extensão 'LLDB Debugger' você pode definir um breakpoint ao clicar à esquerda dos números de linha, você deverá ver um ponto vermelho indicando que colocou um breakpoint. Mas para depurar mesmo a aplicação, a gente precisa configurar o VS Code direito.

Adicione o seguinte no arquivo .vscode/launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "launch",
            "name": "Debug",
            "program": "${workspaceRoot}/target/debug/example",
            "args": [],
            "cwd": "${workspaceRoot}",
            "preLaunchTask": "cargo",
            "sourceLanguages": ["rust"]
        }
    ]
}

E depois adicione um arquivo .vscode/tasks.json com o seguinte conteúdo:

{
    "version": "0.1.0",
    "command": "cargo",
    "isShellCommand": true,
    "args": ["build"],
    "showOutput": "always"
}

Depois, vamos colocar um breakpoint no código. Daí é só clicar no ícone do insetinho (quarto ícone de cima para baixo, no painel esquerdo) e apertar o botão Play. Você deverá ver algo assim:

Depurador do VS Code, depurando um código Rust.
Depurador do VS Code, depurando um código Rust.

Compilando para diferentes alvos (targets)

Até aqui a gente só compilou programas para a arquitetura x86_64-apple-darwin. Se estivéssemos usando Linux, nós teríamos compilado para x86_64-unknown-linux-gnu. Vamos mudar um pouquinho e compilar para javascript: asmjs-unknown-emscripten.

Primeiro, precisamos instalar o pacote emscripten. No Mac você pode fazer isso com brew install emscripten. Algumas distros Linux também oferecem o pacote emscripten, mas você pode encontrar um manual de instalação aqui.

Depois, vamos instalar o alvo (target) usando o rustup:

rustup target add asmjs-unknown-emscripten

Se você estiver usando Mac, provavelmente vai precisar adicionar as seguintes linhas no arquivo ~/.emscripten:

LLVM_ROOT = "/usr/local/opt/emscripten/libexec/llvm/bin"
#LLVM_ROOT = os.path.expanduser(os.getenv('LLVM') or '/usr/bin') # directory
#BINARYEN_ROOT = os.path.expanduser(os.getenv('BINARYEN') or '/usr/bin') # directory

# Avoid annoying popups about Java.
#JAVA = 'java'

Agora nós já podemos compilar o nosso código em asm.js e rodar direto com o interpretador node:

cargo build --target=asmjs-unknown-emscripten
node target/asmjs-unknown-emscripten/debug/example.js

A saída deverá ser a seguinte:

2
false

Compilar para outros sistemas e arquiteturas funciona de forma semelhante. A parte mais chatinha é instalar o ferramental, como nós acabamos de fazer para o emscripten.

Conclusão

Agora nós já temos um ambiente de desenvolvimento Rust preparado para compilar programas tanto na arquitetura do computador local, quanto para asm.js. O editor VS Code está preparado para depurar código e tem algumas funcionalidades bacanudas como autocompletar e navegar no código. Além disso, instalamos algumas ferramentas utilíssimas como o clippy para nos ajudar a detectar erros.

Algumas das ferramentas que instalamos ainda estão em alpha, ou não funcionam como gostaríamos. Mas este é só o começo! E se você tiver interesse, pode sempre contribuir com estes projetos. De tempos em tempos você pode atualizar a sua caixa de ferramentas e com certeza vai notar várias melhorias.

Agora você não tem nenhuma desculpa pra não se divertir programando em Rust! Vai procurar um repositório interessante e faz seu primeiro Pull Request! E se não achar nada, dá uma olhada no r/rust pra sacar sobre quais projetos as pessoas estão conversando, procure por issues marcadas como E - Easy no rustc, ou pegue pra desenvolver algo pequeno no projeto rust-rosetta.

Now, we don't have any excuses not to have fun with Rust! Why not find something that looks interesting and try to make your first PR? Can't find something? Check out /r/rust and look at the projects people are talking about, look at the E - Easy issues on rustc, or tackle something small from rust-rosetta!

Obrigado Asquera, por me arranjar tempo para escrever este artigo! O mesmo texto também está presente aqui.

Comentários