Rust #1: Creating your development environment
Tags: rust, vscode
Published: 2021-06-19 13:32:32

## Overview

This blog is my attempt at documenting what I've learnt on my journey using Rust.  I have worked as a video game programmer for over 25 years and as a result have used C++ as my main language of choice, even for personal projects.  Today, I will never touch C++ willingly again since discovering and learning about Rust.  I will restrict C++'s use to my day job, and that's all.  In my opinion, Rust has made C++ redundant for writing new software.

I have managed to hone my development environment for Rust programming over the last few months and I want to share my approach.  This is what my first article is about - setting up a development environment for effective Rust programming.

## Prerequisites

I will assume the reader knows their way around a terminal (or shell).  That is, they know how to make folders, set the current folder, and launch commands all via their terminal.

I will also assume that the reader has prior programming experience, perhaps in C, C++ or similar language.  These guides will not be teaching you how to program, but rather how to apply your current programming skills to a new language.

You will also need an internet connection.  The Rust build system will constantly download packages (called crates) from the world wide web.

## Installing Rust

The best way to install Rust is using the tool `Rustup`.  Windows' users will require downloading an executable, but for operating systems with more sane command shells, a single cut & paste will suffice.

Hop over to http://rustup.rs and follow the instructions.  After running the executable `rustup-init.exe` on Windows, or executing the shell command on other operating systems, you will see a screen-full of text and 3 options:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uiwebemv23i027szbsto.png)

Go ahead and choose option 1 and you will have Rust and its associated tools installed.  To make sure, open up your favourite terminal and type:

```
$ rustc --version
```

if everything went well (and I hope it does because this guide will not help you otherwise), you should see something like:

```
rustc 1.53.0 (53cb7b09b 2021-06-17)
```

The installation procedure involves `rustup` downloading and installing "components".  The components you might have seen being installed would be:

* __cargo__ - the ultimate, bad-ass package/build/do-everything tool that will be the centre of your Rust-programming experience.
* __clippy__ - this is a linting tool that can scan your code and make suggestions on how to improve it, or catch problems.  This is an essential part of your workflow.
* __rust-docs__ - a cargo plug-in that provides auto-generation of documentation from your source code.  If you're familiar with Doxygen, it's similar to that.
* __rustc__ - the compiler, nuff said!
* __rustfmt__ - Rust's very opinionated code formatter.  It will auto-format your code according to a set of standards so that everyone's Rust code looks the same.  This can be annoying at first but you reap the benefits if you stick with it.

## Your first Rust program

Let's try the obligatory Hello World program.  And because of Cargo, you can do this without typing a line of code!  Most guides, will demonstrate how to use `rustc` but you do not need to touch this directly.  You will use Cargo to check, build, test, benchmark and run your code as well as many other things.  So jump into your favourite terminal, `cd` to your folder you've set aside for Rust development (I use Windows and so my folder of choice will be `r:\`) and type:

```
$ cargo new hello
$ cd hello
```

You will get a message back telling you that you've created a binary package called 'hello'.

Let's look inside your folder that you've just created.  First, you will see a `Cargo.toml` file.  This gives information to Cargo on how to build your project and other meta-data (like authorship, version etc).  We'll cover this later.

Secondly, there is a hidden file and directory related to `git`, which is the default source control system used by most Rust programmers.  You can switch it to Mercurial or something else.  To read about that, rush over to https://doc.rust-lang.org/cargo/commands/cargo-new.html and checkout the `--vcs` command line option.  I will be ignoring this file and folder in this guide.

Finally, there is a `src` folder, and that is where all your rust source code lies.  If you look inside, you will see a lonely file called `main.rs`.  Let's view it.  You can use `type` (Windows) or `cat` (other operating systems) to show the contents of `src/main.rs`:

```
fn main() {
    println!("Hello, world!");
}
```

The hello world program has already been written, courtesy of Cargo.  Let's examine the code:

* __fn__ marks the start of a function and in this case defines the function called `main`.  All Rust applications start at this function, like C/C++ does.  If you build with Cargo, which we will, there also has to be a `main.rs` file in the root of the `src` folder.  The parentheses following it usually contain parameters (we have none right now), and the code belonging to that function is in between the braces.  If you are used to C, C++, C#, JavaScript etc, all this will be familiar to you.
* __println!__ will print text to standard output.  The exclamation mark in the name indicates that `println!` is not a function but a macro.  As in Lisp macros, not the useless C style macros.  Rust can generate code during compilation.  In this case, `println!` will expand to many statements, depending on its arguments, that will be inserted at the point of the call.

OK, let's run it.  Type:

```
$ cargo run
   Compiling hello v0.1.0 (R:\hello)
    Finished dev [unoptimized + debuginfo] target(s) in 1.11s
     Running `target\debug\hello.exe`
Hello, world!
```

This will compile the code and run it.  The astute of you will have noticed a new folder appearing called `target`.  Dig deeper and inside that you will see a `debug` folder.  Finally, inside that you will see the `hello.exe` you just built and that Cargo just ran.

In fact, the compiler output before the 'Hello, world!' message describes the type of application you just built (unoptimised and including debug information) and where to find it.

We can build and run an optimised one too:

```
$ cargo run --release
   Compiling hello v0.1.0 (R:\hello)
    Finished release [optimized] target(s) in 0.66s
     Running `target\release\hello.exe`
Hello, world!
```

Here are some other Cargo commands worth knowing to begin with:

* `cargo build` - this will just build the final executable.  `cargo run` will call this implicitly if it needs to.
* `cargo clean` - this will delete the `target` folder and all the generated files within.
* `cargo check` - useful while writing code.  This will compile your code but without generating the code.  This is a lot faster than `cargo build` and is useful if you just want to check for syntax errors.  Because of the excellent IDE integration that I will demonstrate later, this is rarely needed.

One more point, after building your executables, a `Cargo.lock` file appeared too.  This file is generated to lock down versions of other packages you might have used to build your program.  This allows the Rust compiler to recreate the exact executable after a clean.  It ensures that the same versions of packages are downloaded, built and linked with your application as before.  For now, we don't use packages so this file contains very little information.  If you use source control (like Git), you should include this file during submission, along with `Cargo.toml` and your source code.

## The Editor

The second step in starting to learn Rust is setting up your programming environment just right so as to minimise friction between you and your work.  The main part of that decision is which editor to use.  I've tried writing Rust code in Emacs, Vim, Sublime but the text editor I eventually settled on is `Visual Studio Code`.  For me, it's the best product Microsoft have ever created.

Why Visual Studio Code?  In my opinion, it has the most mature tooling for writing Rust code, and for interacting with Rust's ecosystem and build tools (i.e. Cargo).

So go over to https://code.visualstudio.com/ and download and install it.

Restart your terminal, and enter:

```
$ code .
```

And lo and behold:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cihq0k4ls4nf28z0b8v7.png)

The terminal is nice and all but there's all that typing.  Don't we do enough while coding?  So let's see if we can build from Visual Studio Code (hereafter referred to as VS Code).  Currently, it can't because it needs extensions.

### VS Code Extensions

To turn VS Code into a powerhouse editor of Rust, we need to install some extensions.  By clicking on the 5th icon on the left (it looks like 4 squares, with one of them offset) you open up the extensions interface.  Use the search box to find the necessary extensions listed below, then click on the blue 'install' buttons beside the extension's entry:

* __rust-analyzer__ - provides the 'intellisense' for Rust and many other Rust-related utilities.
* __C/C++__ - what???  You need a C/C++ extension?  Yes, it contains the debugger and it's useful for inserting breakpoints and stepping through your code.  You can also use `CodeLLDB` but for me, the `C/C++` one feels quicker.

Also, there are some useful extensions to install, that while unnecessary, are very useful all the same:

* __crates__ - checks the versions of any crates you reference (more on that later).
* __Markdown All in One__ - you will be writing several markdown files (files with `.md` extensions).  This extension makes it easier to do so and provides a useful preview mode.
* __Even Better TOML__ - some editor support for editing TOML files such as `Cargo.TOML`.
* __Rewrap__ - not related to Rust but provides the ability to reformat text (in markdown files and Rust comments) so that they fit on the lines better.  By pressing `Alt+Q`, you can change a couple of long comments into several shorter ones that fit on the screen.  As you will eventually see, Rust comments will take a big part in document generation.

If you clear the search box, you will see the extensions you've installed.  Some buttons beside them may be labelled 'Reload Required', and if you do, press it to restart VS Code in a matter of seconds.

After installing `rust-analyzer`, you will see a dialog box pop up in the bottom right corner of the window.  If you miss it, click on the `notifications` icon in the bottom-right of the window.  It should look like this:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zf02qyu18p5xrwscxibx.png)

Click the 'Download now' button.  If you don't see it, restart VS Code and it should show again.  This will download the Rust Language Server (RLS), which is the external program that can analyse your source code and communicate back to VS Code, via the extension, to display useful information about your program, including auto-complete.

When downloaded, 'rust-analyzer' will get to work looking at your code.  Open up `src/main.rs` using VS Code and you will see two new links above the `main` function:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6dnrztlk2l9gwic0y9xa.png)

Click on `Run` and VS Code will build and run your program.  You can see the results in the terminal window that automatically opens up.

Alternatively, you can click on `Debug` to do the same thing.  But right now VS Code isn't properly set up for debugging. 

### Debugging in VS Code

If you haven't used VS Code before, it probably isn't set up for debugging facilities like breakpoints.  So press `Ctrl+Comma` to open up VS Code's settings window.  Type `breakpoints` in the search bar at the top of this window, and make sure `Debug: Allow Breakpoints Everywhere` is selected:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nt39ll3za681kl7nqbtt.png)

While you're in the settings window, retype the search parameter to be `formatter`.  Ensure `Editor: Default Formatter` is set to `rust-analyzer` and `Editor: Format On Save` is checked.  This will allow the `rustfmt` component mentioned earlier to do its magic every time you save a file.  It's a really nice time-saver.  You can type code as messily as you want in the sweet knowledge that when you save, everything will move to its correct place, and missing trailing commas and spacing will be inserted.

Now you've done this, you can hit `F9` while editing to add a breakpoint to the very line you're on.  Try doing this now on the `println!` statement in `src/main.rs`:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zd6a2lzn33q92w9128cl.png)

Click on 'Debug' and see the code stop on the line before it executes it.  Tap `F10` to step over the next line and you will see 'Hello, world!' appear as it executes it.  Press `F5` to continue running, or `Shift+F5` to stop debugging altogether.  Don't forget to tap `F9` again on the line with the breakpoint to remove it!

### Launchers and Tasks in VS Code

These links in your code are very convenient, but it requires that you have `src/main.rs` open at the `main` function to see them.  Wouldn't it be better if we could press a key and have it run or build?

First step is coercing VS Code to build your source code at a press of a key.  Press `F1` to bring up the command palette, which is an interface in VS Code that contains all the possible commands you can give to it.  Now type `build` and the command menu will whittle down to a few entries, one of which is `Tasks: Configure Default Build Task`.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0phjdiaddkam5prnth5z.png)

Select it.  A new menu will appear with a list of possible Cargo commands.  We want to choose `rust: cargo build`.  This will create a new file in your project at `.vscode/tasks.json`.  This file defines a task that VS Code can run.  It calls `cargo build` and that's all.  But let's improve on it.

Firstly, change the `label` entry to something shorter.  It can be anything you want, but I usually change it to `build`.  It will be referenced by another file later.

Secondly, we would like the terminal window in VS Code to clear every time we start a build so we can clear distinguish current messages from a previous build's messages.  Add a comma at the end of the `label` line and then start typing `presentation`.  After a few characters you should see an intellisense window open up suggesting `presentation`.  Hit ENTER and VS Code will auto-complete the entry.  Very handy!  Now change the `clear` entry so it says `true` instead of `false`.  The final version should look like this:

```json
{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "cargo",
      "command": "build",
      "problemMatcher": [
        "$rustc"
      ],
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "label": "build",
      "presentation": {
        "echo": true,
        "reveal": "always",
        "focus": false,
        "panel": "shared",
        "showReuseMessage": true,
        "clear": true
      }
    }
  ]
}
``` 

Now, select `File > Preferences > Keyboard Shortcuts` from the menu and type `build` in the search bar of the new keyboard shortcuts window.

Double-click under the `Keybinding` column on the row that says `Tasks: Run Build Task`.  This will allow you to bind a key to that command.  Type `F7` followed by `ENTER` and you're done.  VS Code will warn you that other bindings use the same key, but ignore those as they will not conflict.  I chose F7 because that's the usual key on the Visual Studio IDE for building and I am used to it.  Of course, you can choose any other key combination that suits you.

Let's test it!  Hit F7 now (or whichever key combination you chose) and the terminal window in VS Code will clear and start your build!

Now have it building at a press of a key, we want it to run (after building) at a press of another key.  VS Code already has `F5` set up for that task, but currently doesn't know how.

Click on the 4th icon on the left side of VS Code, the one that looks like a triangle with a bug on the corner.  When you do this, you will see a new interface with a big `Run and Debug` button (but don't press it!).

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4h2vv2g349ak9dp30sbp.png)

Under that button, you should see a link that says `create a launch.json file`.  To run your program at a press of a button, we need to create a launcher.  Launchers are configured via this `launch.json` file, so go ahead and click on that link. You will see a dialog asking you to select and environment.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sirx0c7aew8piwszlbrm.png)

Choose `C++ (Windows)` if you're on Windows and you used the `C/C++` extension, or choose `C++ (GDB/LLDB)` otherwise.  This will create a new file called `.vscode/launch.json`.  As before, let's make a few changes:

1. Change the `program` value so it reads `${workspaceFolder}/target/debug/hello.exe`.  This needs to match the final executable you're running.
2. Change the `console` value so it reads `integratedTerminal` and add a comma at the end.
3. After the `console` entry, and the reason you added a comma, add the entry `"preLaunchTask": "build"`.  This is the line that references the label text you entered in `tasks.json`.  They must match.  This line tells the launcher to ensure that the build task is run first.  We want to run the latest version of our program, don't we?

The final result will be: 

```json
{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "(Windows) Launch",
      "type": "cppvsdbg",
      "request": "launch",
      "program": "${workspaceFolder}/target/debug/hello.exe",
      "args": [],
      "stopAtEntry": false,
      "cwd": "${fileDirname}",
      "environment": [],
      "preLaunchTask": "build"
    }
  ]
}
```

Press `F5` and the launcher should run.  You should see in your terminal, build messages and the output of the program.

Occasionally, I have seen VS Code struggle with this.  If it doesn't run, check your `tasks.json` and `launch.json` files, and run `cargo clean` from the terminal within your project folder.

## Compiler Errors

This blog is getting a bit long now, so one last thing to talk about.  What happens if you have errors in your code.  The good news is that the `rust-analyzer` extension and VS Code will conspire to help you out.  Let's add an error in our code.  After the `println!` statement, add a new one:

```rust
fn main() {
    println!("Hello, world!");
    foo();
}
```

Then hit save (`Ctrl+S`).  `rust-analyzer` will generally only see your changes after saving.  Now the error is in the program, without building multiple things will happen:

1. A red line will be visible under `foo`.  Move your mouse pointer over it and you will see a popup describing the error.
2. Looking at the tab above your editing window, you will see that the filename has turned red with a number after it.  (There is also a letter U but that's related to source control so ignore it).  That number is how many errors there are.  The tab text can turn yellow too, which means there are warnings but no errors.  This time the number counts how many warnings there are.  At a glance you can see how many errors in your program.
3. On the scrollbar in your window, you will see a little red marker.  This shows roughly where your error is.
4. If your terminal window is still open in VS Code, you will see a number next to the `Problems` tab.  Inside this tab, you will see a list of errors.  Click on them to jump to the line of code with the error.

Wow, that's a lot of clues something has gone wrong with your program.  Now hit your build key to run the build task (remember mine was `F7`).  In the `Terminal` tab below you will see the output of the compiler.  It usually has a better error message than seen elsewhere:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4zerdnevnrf9xdjyn43n.png)

Rust provides the best error messages EVER!  You can even go to your terminal and type `rustc --explain E0765`, as described, to explain the error above in more detail.  Truly amazing!

## Summary

That was a lot to go over.  But we installed Rust and it's tools, installed VS Code and extended it to support Rust, and then showed how to use VS Code to build and run your program.

Part #2 will talk about the borrow checker, ownership, lifetimes and all those nice things.  See you then!