Skip to main content

My setup for hacking on GHC with VsCode

· 4 min read

I haven't posted on here in a good while, but since this blog also serves as a sort of "backup" for my brain, I wanted to take a second to jot down my ghc environment setup.

I've long wanted to get into compiler development, and I find that I've always done better by diving in rather than poking around at the edges; I think I'm good enough at Haskell to take a crack at GHC, so here I am!

After reading through the machine prep section of the ghc wiki (which is vast but also immensely helpful), along with the aid of blog post from terrorjack, I decided I would alter the setup slightly to hopefully achieve something thats a little more ergonomic. For me, the path of least resistance is to use a docker container.

Lets see the config

I created the following Dockerfile (in the project root) which seems to work great, and IDE support is working out of the box.

FROM registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb10:9e4c540d9e4972a36291dfdf81f079f37d748890

# Install ghcup
RUN curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

# Add ghcup bin to path so haskell ide extension can find
# the all of the ghc binaries
ENV PATH=${PATH}:/home/ghc/.ghcup/bin

# We override these variables that way `hadrian` will use
# the ghc binaries provided by ghcup instead of those in `/opt`
ENV CABAL=/home/ghc/.ghcup/bin/cabal
ENV GHC=/home/ghc/.ghcup/bin/ghc

# Finally explicitly install HLS so its ready for us right away!
RUN ghcup install hls

NOTE: The hash we use for the docker image changes from time to time. Refer to the ghc CI config for the latest hash

In addition to the dockerfile, I also use the following devcontainer.json file (located at: <ghc-root>/.devcontainer/devcontainer.json)

{
"name": "Existing Dockerfile",

// Sets the run context to one level up instead of the .devcontainer folder.
"context": "..",

// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
"dockerFile": "../Dockerfile",
"customizations": {
"vscode": {
"extensions": [
"haskell.haskell"
]
}
}
}

Another NOTE: This file can be generated. Clone the ghc repo, open the folder in vscode, and then use the remote containers extension to "Open folder in a container". It will prompt you how to open it, and you pick the dockerfile created up above. You can install Haskell Language Server and then "add to devcontainer.json" and it'll be there. But I just put this here in case you're feeling lazy.

Why?

I decided to try and alter the prescribed setup mainly for the reason that HLS (the IDE) really likes ghcup to run the show. ghcup does a good job of coordinating your environment to ensure the hls and the compiler play nice together. Also, using vscode dev containers, some of the hassle of fixing userids/groupids is taken care of for you automatically.
Initially I tried ghc.nix, but I ran into some errors with hls setup. Although I love the concept of nix, I find that debugging nix configuration is extremely difficult (atleast for me it is).

Issues I ran into

Bad .hie-bios directory:

Because I first attempted to setup my ghc environment with nix, I ended up with a bad .hie-bios directory which contained stale build artifacts. This manifested as a bunch of errors to the effect of Package X is broken due to missing package 'base-4.16.1.0.

In this case, the remedy was simply to delete the .hie-bios directory and then restart HLS and let it generate a new build.

Docker on Windows doesn't work

Before trying ghc.nix, I actually tried to set up ghc on windows with docker. Unfortunately, it seems that docker is in a some-what malformed state on windows and so I ran into many compilation errors when running hadrian/build -j. Files kept failing to generate for some reason.

I may try again to get it working on windows one day, but for now, linux is the way. I run linux in a VM, but WSL (which is essentially a vm) would probably work as well.