MSYS2 Default Environment

Hi all, this is my first post, I just wanted to share an experience I had.

I did some Haskell in school, always admired it, but have never really built anything with it. At work, I had the opportunity for a front end of a new web application to choose Elm as the development language, though we are a .NET shop, so we went with C# on the backend (we’ve introduced some F# and loved it).

I really like Elm, which is very similar to Haskell, and thought I’d give my hand at some real Haskell. I remember from https://realworldhaskell.com/ (which sadly seems to be down), that HDBC was a library for database connectivity so I thought I’d try that with SQLite.

My work uses Windows primarily, so even though I had access to WSL, I wanted to try native Windows development. GHCup got me up and running. I’m new to MSYS, but figured out how to use pacman to get SQLite installed. My toy “create table, insert, read, print, and exit” program compiled and ran fine. Yay!

But when I tried to run it through GHCi via cabal repl, it crashed with a memory error (access violation, I couldn’t really tell where) but only after I tried evaluating my main. I was stumped. After a lot of troubleshooting (and as a last resort a little help from AI) this is what I found: I needed the UCRT64/clang package. With that, both my compiled executable and GHCi were able to execute SQLite. So that leads me to…

Did I do something wrong? Configuration - GHCup still says that anything other than the default (MINGW64) is experimental, but ghc --info says GHC itself uses clang. Should I be using clang instead? I was surprised that it “worked” when compiled but not under GHCi but as I understand it, the linker with FFI is different under GHCi than when building native.

4 Likes

To change the environment you essentially need two steps:

  • change global cabal.config (or your cabal.project if you want different environments per project) and adjust extra-prog-path, extra-include-dirs and extra-lib-dirs as described in 5. How to use Cabal in Windows — Cabal 3.16.1.0 User's Guide
  • change GHCUP_MSYS2_ENV user env variable through the windows system settings

Some of the desktop shortcuts that were created may still point to the old env, so you may need to adjust them too.

It appears we still set MINGW64 as default in ghcup, which will also set the cabal variables during first install: ghcup-hs/scripts/bootstrap/bootstrap-haskell.ps1 at cbe14df4cd8c40fb9520a71723853d35918cb1b9 · haskell/ghcup-hs · GitHub

GHCs before 9.4.1 used that environment. GHCs since 9.4.1 use CLANG64. So I guess we should switch to that.

3 Likes

I personally like to manually control my dev env on windows as I know exactly what I’m doing. For my setup I’ve just installed the MSYS2 on my machine. This gives me ability to get the libraries and stuff.

Then I add these paths to my system path environment variables:

C:\msys64\usr\lib
C:\msys64\usr\bin
C:\msys64\usr\include

And after that, I download the cabal and ghc independently from these pages:

Then I put different cabal and ghc versions under these directories on my PC:

%USERPROFILE%\Apps\Haskell\HLS -- I've also noticed I've added language server in the same way
%USERPROFILE%\Apps\Haskell\Cabal\3.10.3.0
%USERPROFILE%\Apps\Haskell\GHC\9.10.1\bin

And finally, I put these paths into my user environment variables path.

I have multiple versions of cabal and ghc so I keep them under sub directories with their version number. That way I can easily switch between them by modifying the version number in my profile paths.

This is honestly pretty easy to manage, it’s just that it’s a bit hard to figure out what you have to download and from where to get the working environment.

But it’s just 2 things that are necessary. Cabal and GHC, and optionally the HLS which can be downloaded from their github page (mingw64 version IIRC):

That means you’re effectively running the MSYS (gcc and cygwin based) environment, see: Environments - MSYS2

Yes. That’s the idea. I had no issues with this setup so far and I’ve been using it on my windows machine for quite a few years now.

MSYS isn’t recommended for producing binaries, since they rely on the posix emulation layer. They’re less portable and you also pay a performance penalty.

But since GHC doesn’t really pick the C compiler from that toolchain anyway, you end up with a mix of two environments. It is probably largely safe, since MSYS is mostly meant for access to unix tools. But in case you want to link to, say, libarchive or other things, I can’t imagine that this is going to work well.

2 Likes

This is just for simple development / practice on Windows and I highly recommend it if you don’t feel like using ghcup for what ever reason. It has also worked well for C and Rust so I can’t complain.

For serious stuff I use my Linux machine and a proper CI/CD + Nix.

I’ve actually done this setup before ghcup even existed, mainly to get the gloss library working on windows natively. It picks up things / libs nicely as far as I remember.

Yup, I forgot to mention I did this in addition to installing the right path. Total noob question then: why did this work for me when I built the binary but not when I ran it through GHCi? I guess naively I wouldn’t have thought that it mattered what GHC used if the MSYS environment was set up. I’m coming from very limited knowledge here - I know linking is a thing but couldn’t describe to you the steps or “when” things happen, especially in GHCi.

Makes sense to me. Under Environments - MSYS2, MINGW64 is classified as “legacy”.

Depends how you started ghci. ghc itself doesn’t know about that cabal configuration. Try cabal repl instead of ghci.

Yep, that’s what I did.

If I had to guess, when you compile code, for external libraries like sqlite3 GHC delegates to what ever’s in your path (which was probably mingw toolchain).

Since you had mingw sqlite3 package installed, that was fine. The new GHC is built with UCRT, and I’d guess that the ghci expects UCRT version of the library which is not what you had in your path.

1 Like

No, newer GHCs ship with CLANG64 toolchain, which is hardcoded into GHCs settings file.

I thought CLANG64 uses UCRT?

Sure, the C library is ucrt. But there’s also a UCRT64 environment, which uses gcc instead of clang.

It’s quite confusing tbh.