Haskell & AppVeyor Chocolatey Introduction

July 22, 2018

For those who are unaware, Windows has had quite a push lately to provide script-able ways to install packages. One such attempt that has gained quite a lot of traction is Chocolatey https://chocolatey.org/.

Chocolatey also contains some of my own packages for installing GHC and cabal (along with packages to fully automate setting up a GHC dev environment etc, more on these at a later date).

The GHC package https://chocolatey.org/packages/ghc goes all the way back to GHC 6.10.1 and the cabal-install package https://chocolatey.org/packages/cabal to cabal-install 0.6.0.

These are quite handy for those who use the cabal+ghc workflow like myself and like to switch compiler versions easy, or script environment setups.

After installing Chocolatey one can install GHC simply using the command

choco install ghc
refreshenv

which will install and reconfigure the latest released GHC along with the latest cabal-install. The refreshenv is needed in order to reload the PATH variables which an install of the package changes. This is normally not needed for a Chocolatey package but for GHC it is needed to preserve an assumption the GHC bindists make about their layout.

For older packages this dependencies on cabal isn’t specified so one way that works with all versions is:

choco install cabal ghc
refreshenv

You can also use chocolatey to install the latest GHC Alpha, Beta and RC simply by adding -pre to the install command. e.g.:

choco install cabal ghc -pre
refreshenv

An existing install can be upgraded using the upgrade command

choco upgrade ghc
refreshenv

and specific versions can be installed using --version:

choco install ghc --version 8.4.1
refreshenv

The chocolatey packages are self contained, which means you can also install multiple GHC versions side-by-side and switch between them using the full versioned form. e.g.

choco install ghc --version 8.4.1
choco install ghc --version 8.2.2 -m
refreshenv

Will install both GHC 8.4.1 and 8.2.2 at once, with GHC 8.4.1 being accessible by the un-suffixed ghc command. The -m option means allow multiple which won’t force only one version to be installed. Using cabal new-build’s -w flag you can easily switch between the two versions:

cabal new-build -w ghc-8.4.1.exe
cabal new-build -w ghc-8.2.2.exe

So take a look at the Chocolatey based distributions, which can also be used to install a full Haskell dev environment using e.g. vscode.

choco install ghc vscode
Update-SessionEnvironment
code --install-extension justusadam.language-haskell

For those who like to test their packages against the bleeding edge, just like Hvr’s excellent PPA for Ubuntu I provide nightlies for both GHC and cabal-install under my NuGet feed.

The current build frequency for both is Nightly, but depending on popularity/activity I may scale them to weekly or longer. Builds are retained for a year before they are deleted, just as before I may extend or shorten the period in the future depending on feedback. GHC builds are currently 64 bit ONLY.

To use them first add my NuGet feed as a Chocolatey source and that will give you access to the packages cabal-head and ghc-head.

choco source add -n mistuke -s https://www.myget.org/F/mistuke/api/v2
choco install ghc-head cabal-head -pre
refreshenv

ghc-head will always install cabal-head, this is because newer GHC may require a bleeding edge Cabal. If you have them already installed you can just upgrade existing nightlies or downgrade as long as the build is still around. These are unsupported builds, If you do feel like you’ve found a genuine bug, when reporting them my package feed can tell you which commit the build was made from.

In the future I will also be providing some of my own internal builds for wider testing before they get merged into upstream master.

AppVeyor Continuous Integration

AppVeyor comes with Chocolatey pre-installed. Which means you can use the exact same commands as above to set up a CI script for your project using AppVeyor. For instance the Win32 library I maintain uses the following AppVeyor script for Windows testing:

clone_folder: "c:\\WORK"

environment:
  global:
    CABOPTS:  "--store-dir=C:\\SR --http-transport=plain-http"
  matrix:
    # 64 bit builds
    - GHCVER: "8.4.2"
      CHOCOPTS:
    - GHCVER: "8.2.2"
      CHOCOPTS:
    - GHCVER: "8.0.2"
      CHOCOPTS:
    - GHCVER: "7.10.3.2"
      CHOCOPTS:
    - GHCVER: "7.8.4.1"
      CHOCOPTS:
    # 32 bit builds
    - GHCVER: "8.4.2"
      CHOCOPTS: --forcex86
    - GHCVER: "8.2.2"
      CHOCOPTS: --forcex86
    - GHCVER: "8.0.2"
      CHOCOPTS: --forcex86
    - GHCVER: "7.10.3.2"
      CHOCOPTS: --forcex86
    - GHCVER: "7.8.4.1"
      CHOCOPTS: --forcex86

cache:
- "C:\\SR"

install:
 - "choco install -y ghc --version %GHCVER% %CHOCOPTS%"
 - "choco install -y cabal %CHOCOPTS%"
 - "refreshenv"
 - "set PATH=C:\\ghc\\ghc-%GHCVER%:C:\\msys64\\mingw64\\bin;C:\\msys64\\usr\\bin;%PATH%"
 - "cabal --version"
 - "ghc --version"
 - "cabal %CABOPTS% update -v"

build: off

test_script:
 - IF EXIST configure.ac bash -c "autoreconf -i"
 - "echo packages:. > cabal.project"
 - "cabal %CABOPTS% new-build -j1 all"

This tests both x86_64 and x86 versions of the last 5 GHC against any pull requests to Win32.

To point out some important bits:

  global:
    CABOPTS:  "--store-dir=C:\\SR --http-transport=plain-http"

The --store-dir flag is used to shorten the path of the new-build nix style package store folder so it doesn’t hit MAX_PATH as easily. (NOTE: GHC 8.6 and newer no longer have this limitation for end user programs. So in the future once cabal is compiled with GHC 8.6 this won’t be needed, but for backwards compatibility should still be used for now.)

The http-transport is unimportant, it can be omitted but I prefer to not have it use curl from msys2 just because it’s an emulated binary and will be slower than the plain http-transport or powershell transport options.

cache:
- "C:\\SR"

This caches the nix style package cache so that dependencies don’t get built over and over again. This can save a significant amount of time when building your project. AppVeyor has an hour build limit.

 - IF EXIST configure.ac bash -c "autoreconf -i"

This allows packages like network to be used from the repo where there is no final configure script yet.

 - "choco install -y ghc --version %GHCVER% %CHOCOPTS%"
 - "choco install -y cabal %CHOCOPTS%"

This command installs the compiler and the latest cabal-install which is backward compatible with older GHCs. The explicit cabal install is for older packages which didn’t have a dependency on cabal. For newer GHC this would be a no-op. The -y makes Chocolatey suppress the script execution question with a default answer of yes.

 - "refreshenv"
 - "set PATH=C:\\ghc\\ghc-%GHCVER%:C:\\msys64\\mingw64\\bin;C:\\msys64\\usr\\bin;%PATH%"

As before we reload the environment variables, which unfortunately also clears the custom ones AppVeyor sets. To restore the ones we need we modify the PATH to contain msys2 and where we expect older GHCs to have been installed.

NOTE: If you actually intend to use pacman packages, please set the appropriate mingw for the architecture you intend to use. The above examples all set the 64 bit paths.

If you want to report a bug against the packaging (the chocolatey packages and not the binaries themselves) please do so on my GitHub project for the packages. Cabal and GHC.

I do plan on adding a Haskell Platform package in the near future. Happy hacking.

– Tamar