Setting up Rust on macOS in a clean way
Tags: rust, macos
Published: 2022-07-10 13:11:19

## Introduction

When I first wanted to get started with Rust, I was a bit confused about the suggested way of installation for its toolchain, at least on a Mac device. If you're not familiar, there are mainly 3 common ways that people install Rust on Mac:

1. A lot of people simply run the following command as suggested by the Rust website: `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`  
My concern with this method is that it's not immediately clear how to do a clean uninstall in the future. You'd also need to read through the shell script to understand what it's exactly doing.

2. Another option is to install the [rust](https://formulae.brew.sh/formula/rust#default) formula with `brew`.  
This is better, however, you're essentially installing a single toolchain for your given native hardware, as it looks like `rustup` is not part of this formula, so you cannot easily cross-compile by adding other toolchains.

3. The last option is to install the [rustup-init formula](https://formulae.brew.sh/formula/rustup-init#default) instead, which I consider to be the best option, however, some extra manual work is needed and I will walk you through it.

## Setting up your environment variables for rustup

I like to keep my `$HOME` directory clean, so I try to conform to the [XDG Base Directory Specification](https://wiki.archlinux.org/title/XDG_Base_Directory) as much as possible. Here are the XDG variables I've set in my `~/.zshenv`.

```bash
export XDG_CONFIG_HOME="$HOME"/.config
export XDG_DATA_HOME="$HOME"/.local/share
export XDG_CACHE_HOME="$HOME"/.cache
```

Rust allows us to configure the location for its toolchain as well with environmental variables, here I've set the two most important ones like so.
```bash
export CARGO_HOME="$XDG_DATA_HOME"/cargo
export RUSTUP_HOME="$XDG_DATA_HOME"/rustup
```

### Installation
We can now install `rustup-init` and run it
```bash
brew install rustup-init
rustup-init
```

We will be greeted with the rust installation process
```
Welcome to Rust!

This will download and install the official compiler for the Rust
programming language, and its package manager, Cargo.

Rustup metadata and toolchains will be installed into the Rustup
home directory, located at:

  /Users/xs/.local/share/rustup

This can be modified with the RUSTUP_HOME environment variable.

The Cargo home directory located at:

  /Users/xs/.local/share/cargo

This can be modified with the CARGO_HOME environment variable.

The cargo, rustc, rustup and other commands will be added to
Cargo's bin directory, located at:

  /Users/xs/.local/share/cargo/bin

This path will then be added to your PATH environment variable by
modifying the profile files located at:

  /Users/xs/.profile
  /Users/xs/.zshenv

You can uninstall at any time with rustup self uninstall and
these changes will be reverted.

Current installation options:


   default host triple: aarch64-apple-darwin
     default toolchain: stable (default)
               profile: default
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
```
Confirm that the suggested directories line up with directories that you set using the env vars. I personally like to disable the PATH var modification since I like to control that manually. Here's my current `PATH` in my `.zshrc`
```bash
path=(
    "$HOME"/go/bin
    "$XDG_DATA_HOME"/cargo/bin
    "$HOME"/.krew/bin
    /opt/homebrew/opt/make/libexec/gnubin
    /opt/homebrew/opt/man-db/libexec/bin
    /opt/homebrew/opt/grep/libexec/gnubin
    /opt/homebrew/opt/gnu-tar/libexec/gnubin
    /opt/homebrew/opt/gnu-sed/libexec/gnubin
    /opt/homebrew/opt/findutils/libexec/gnubin
    /opt/homebrew/opt/coreutils/libexec/gnubin
    $path
)
```

### Setting up shell completion
By default, most formulae will install the shell completion into the `$(brew --prefix)/share/zsh/site-functions`. I'd prefer not to do manual changes on the Homebrew directory, so we can set up another directory in our home dir. I like to set the `$fpath` variable in my `.zshrc` like so:
```bash
fpath=(
    /opt/homebrew/share/zsh/site-functions
    "$XDG_DATA_HOME"/zsh/site-functions
    $fpath
)
```
So I simply create the directory in `"$XDG_DATA_HOME"/zsh/site-functions` and write my shell completion files there like so.
```bash
rustup completion zsh cargo > $XDG_DATA_HOME/zsh/site-functions/_cargo
rustup completion zsh rustup > "$XDG_DATA_HOME"/zsh/site-functions/_rustup
```

Note: *If you use `bash` or `fish`, you can simply just read more using `rustup completions --help`*

Relaunch your shell and your shell completion should work as intended. And now you can finally manage all your toolchains easily with `rustup toolchain` command. I consider this to be the "cleanest" way to install and manage Rust on Mac and hope this was helpful for some.