Setup an Apple Silicon Mac

I recently got an M1 mac, and I’ll be cataloging my experience with using it for scientific software development. I’ll be returning to update this page periodically, and will eventually have a focused recommendation for Apple Silicon setup, similar to my Intel setup.

Base system observations

Before getting into setup, here are my observations on the base system setup

  • python is installed, 2.7.16, with the standard warning not to use it.
  • python3 (from the CLT) is 3.8.2 with pip 19.2.3. (macOS 11, but no change to 12).
  • Note that Python 3.9 + Pip 21.0.1 are required for a proper experience on macOS, these must be custom Apple builds.
  • git is 2.24.3, not bad at all. 2.30.1 for macOS 12.
  • ruby is 2.6.3p62 and a Universal build, gives a warning about going away in the future. Good, built-ins get in the way of brew.

Basic setup

Always update macOS first thing. I forgot this, so had to reinstall the CLT and wipe and reinstall brew, since it was complaining that “git” was invalid. Hopefully that won’t happen again next update…

First things first, to install pretty much anything you need the “Xcode command-line tools” (CLT). That is triggered automatically lots of different ways, including typing python3 into a terminal. The best way to trigger it is:

xcode-select --install

This includes all the useful open-source tools Unix developers expect, like git, clang, and more. You’ll have to agree to the license.

Brew installs

Next, install HomeBrew, this is the my favorite package manager for Macs.

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

echo 'eval $(/opt/homebrew/bin/brew shellenv)' >> /Users/henryfs/.zprofile
eval $(/opt/homebrew/bin/brew shellenv)

This goes into /opt/homebrew, as is normal for the M1, instead of the normal /usr/local.

I’m stripping down my usual recommendations, non-casks and many casks work just fine, but starting as clean as possible for now.

tap "homebrew/bundle"       # First line of a bundle
tap "homebrew/cask"         # Not needed on command line
tap "homebrew/cask-fonts"   # Just needed for font casks below
tap "homebrew/core"         # Not needed on command line


# Building tools
# brew "boost"        # C++ library
brew "ccache"       # Faster builds by caching
brew "cmake"        # Build software projects
brew "ninja"        # Replacement for make
brew "doxygen"      # Doxygen generates C++ documentation
brew "pre-commit"   # Allows pre-commit hooks to be installed and managed
# brew "tbb"          # Threaded building blocks from Intel
# brew "swig"         # Software wrapper interface generator
# brew "qt"           # The Qt Toolkit

# # General utilities
# brew "colordiff"    # More colorful diffs outside of git
# brew "coreutils"    # Basic stuff with a g prefix
# brew "gnu-sed"      # Adds the gsed command, more powerful than BSD sed
# brew "gnu-time"     # Nicer timing
# brew "openssl"      # Security stuff
# brew "git"          # The latest version of git instead of Apple's older one
# brew "git-gui"      # A quicker way to apply partial changes
# brew "htop"         # htop is better than top for checking processes
# brew "tree"         # tree is nice for looking at directories
# brew "wget"         # Mac's have curl by default, but not wget
# brew "bash"         # Bash 5 instead of 3, in case you need it
# brew "rename"       # Rename files utility
# brew "clang-format" # Format C++ files
# brew "tmux"         # Split windows and saving terminal sessions (screen replacement)
brew "gh"           # GitHub's command line interface, from gh's tap

# # Personal customization options
brew "fish"         # My favorite shell. Might move to zsh when macOS does, though
# brew "lmod"         # See my posts on lmod
brew "macvim"       # VI for macOS, with mvim graphical interface too
# brew "interactive-rebase-tool" # Run git config --global sequence.editor interactive-rebase-tool
# brew "bash-completion" # Nicer completion for bash if you use it

# # Programming languages
brew "python"       # Python 3.8
brew "numpy"        # Now is Python3 only (numpy@1.16 is for python@2)
brew "go"           # Used by hugo, can be useful to have
brew "node"         # Javascript (for gitbooks, etc)
brew "yarn"         # Package manager for node.js
brew "ruby"         # Just to be extra sure the system Ruby never gets modified
brew "rbenv"        # Use this for Ruby (pyenv also exists)
brew "rust"         # Was trying out mdbook
# brew "lua"          # Lightweight language like Python
# brew "java"         # Meh. What can I say?

# # Python programs
brew "pipx"         # Better way to add PyPI applications
brew "nox"          # Tool for standard development environments
brew "tox"          # Old tool for standard development environments
# brew "poetry"       # Nice all-in-one packaging tool
# brew "jupyterlab"   # Programming environment
# brew "black"        # Python formatting
# brew "mypy"         # Python type checking
brew "cookiecutter" # Quickly start new projects

# # Packages
brew "hugo"         # Fast website generator
# brew "pandoc"       # Convert between document formats
# brew "pdftk-java"   # PDF Tool Kit (Java port)
# brew "qt"           # The #1 graphics library for C++ and Python
# brew "root"         # High Energy Physics toolkit
# brew "libsodium"    # Have no idea why I needed this

# # Fonts
cask "font-hack-nerd-font"
cask "font-sauce-code-pro-nerd-font"

# # Core
cask "iterm2"       # A great terminal
# cask "mactex"       # LaTeX. Huge.
# cask "miniconda"    # Nice way to get a system Conda install

# # Programs
cask "google-chrome"# Since once and a while a site doesn't work with Safari
# cask "gimp"         # Photo editor
cask "blender"      # The 3D application

# # Editors
# cask "macdown"      # Nice Markdown
# cask "texstudio"    # Nice IDE for LaTeX
# cask "meld"         # Compare files graphically.

# # Daemons
# cask "docker"       # Allows running and building docker images
# cask "dropbox"      # The cloud
# cask "synergy"      # Share a mouse and keyboard between computers. Free option is okay.
# cask "amethyst"     # Simulate a non-overlapping window manager with keyboard shortcuts
#
# # Chat
# cask "mattermost"
# cask "skype"
cask "slack"

GH tool

You’ll want to setup the gh tool with:

gh config set git_protocol ssh

Other

ITerm2

You should open up ITerm2 (installed above) and make it the default shell and install the terminal utilities (both in the main menu). Pin to dock. Set SauceCodePro Nerd Font as the main font (you can/should do this in the normal terminal, too).

SSH Key

If you want to download the brew bundle (or anything, really) from GitHub, it’s a good idea to setup an SSH Key. In short:

ssh-keygen
# enter a passphrase
pbcopy < ~/.ssh/id_rsa.pub

This will keep you from entering the passphrase as long as you are logged in:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_rsa

And add the following to .ssh/config:

Host *
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/id_rsa

While you are at it, feel free to set git config --global user.name and git config --global user.email.

Fish

If you want to use fish, add /opt/homebrew/bin/fish to /etc/shells and then run:

chsh -s /opt/homebrew/bin/fish

Load a new terminal in a separate tab (before closing the current one) to make sure it works.

For some reason (probably due to fish expecting /usr/local/bin but not expecting /opt/homebrew/bin), the brew path is missing, so you’ll need to add it to Fish:

fish_add_path /opt/homebrew/bin

Install fisher:

curl https://git.io/fisher --create-dirs -sLo ~/.config/fish/functions/fisher.fish

This works best when you use the extended fonts in your terminal (Select SauceCodePro Nerd Font), and then run:

set -g theme_nerd_fonts yes
fisher install oh-my-fish/theme-bobthefish

Note:

Now that zsh comes default, there is less of a need to switch. You may prefer Oh MyZsh instead. Use sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" to install. I still find bob-the-fish too good to pass up.

Here are a few useful environment variables to set. I don’t like getting too far from the default, but these are pretty useful. These persist across logins:

set -Ux CMAKE_GENERATOR Ninja
set -Ux VIRTUAL_ENV_DISABLE_PROMPT 1
set -Ux CTEST_OUTPUT_ON_FAILURE 1

Use set -UxL to list.

Quality of life

I like to change capslock into escape, which is in keyboard settings, and must be done per-keyboard. Also, the keyboard repeat was very slow for some reason.

VIM

It is important to have installed macvim from brew directly, and not the cask, or otherwise the vi command will not be changed to the new vim. Here is my vimrc, which includes directions. I used to use the ultimate VIM package, but this is much more flexible; still adjusting to fill in gaps. Things will break if you use the system vim; you should at least run:

git config --global core.editor $(which vim)

to make sure you do not open the old vim instead when committing with git. Remove the $ if you took my suggestion and are using fish.

" On startup, Vim Plug: https://github.com/junegunn/vim-plug will be
" installed. Also, all initial plugs will also be installed.
" After changing the Plugs or adding this fill run :PlugInstall
" Use git config --global core.editor $(which vim) to ensure you do
" not run system VIM!
"
" Based on searches from https://vimawesome.com

" Automatic install if not yet installed
if empty(glob('~/.vim/autoload/plug.vim'))
  silent !curl -fLo ~/.vim/autoload/plug.vim --create-dirs
    \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
  autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
endif

" Vim-Plug
call plug#begin('~/.vim/plugged')

" Nicer defaults
Plug 'tpope/vim-sensible'

" Nicer searching
Plug 'haya14busa/is.vim'

" Nicer status bar
Plug 'vim-airline/vim-airline'

" Code completer for VIM
" Requires brew install vim or macvim
Plug 'valloric/youcompleteme', {'do':'./install.py --clangd-completer --ts-completer'}

" Github marks in the gutter
Plug 'airblade/vim-gitgutter'

" Pretty for HTML + Jinga2
Plug 'Glench/Vim-Jinja2-Syntax'

" File browser
Plug 'scrooloose/nerdtree'
Plug 'Xuyuanp/nerdtree-git-plugin'

" Support EditorConfig
Plug 'editorconfig/editorconfig-vim'

" Remember position when entering a file
Plug 'farmergreg/vim-lastplace'

" Git support in vim
Plug 'tpope/vim-fugitive'

" TOML support for vim
Plug 'cespare/vim-toml'

" Linter/fixer support (LSP)
Plug 'dense-analysis/ale'

call plug#end()

" Nicer powerline
let g:airline_powerline_fonts = 1
let g:airline#extensions#ale#enabled = 1

" Ale should use virtualenv by default
let g:ale_python_auto_virtualenv = 1

let g:ale_linters = {
\   'python': ['ruff'],
\}
let g:ale_fixers = {
\   'python': ['ruff', 'black'],
\}

" Nerdtree customize
map <C-n> :NERDTreeToggle<CR>

" Extra customization
set mouse=a
set spell

" Needed to use is.vim
:set hlsearch

" MacVim needs a nicer font too
set guifont=SauceCodePro\ Nerd\ Font

" Reasonable indentations
set expandtab tabstop=4 shiftwidth=4 softtabstop=4

" Putting should not copy too by default in visual mode
vnoremap p "_dP

autocmd Filetype python setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4
autocmd Filetype ruby setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2
autocmd Filetype html setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2
autocmd Filetype markdown setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2
autocmd Filetype css setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2
autocmd Filetype scss setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2
autocmd Filetype cmake setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2

command Date execute "normal a<C-R>=strftime('%FT%T%z')<CR><ESC>"
macos