|  | 
|  | 1 | +Haskell, GHC and Cabal in Windows | 
|  | 2 | +================================= | 
|  | 3 | + | 
|  | 4 | +The Windows toolchain and environment | 
|  | 5 | +------------------------------------- | 
|  | 6 | + | 
|  | 7 | +`MinGW <https://www.mingw-w64.org/>`_ is a set of software packages for the | 
|  | 8 | +Windows platform that enable development and compilation targeting the native | 
|  | 9 | +Windows API. MinGW does not offer a complete developer environment so it usually | 
|  | 10 | +is coupled with `MSYS2 <https://www.msys2.org/>`_ which provides many UNIX-like | 
|  | 11 | +tools such as ``bash``, ``make`` or the package manager ``pacman``. | 
|  | 12 | + | 
|  | 13 | +MSYS2 comes with different environments. You can learn more about the different | 
|  | 14 | +environments in the `MSYS2 documentation | 
|  | 15 | +<https://www.msys2.org/docs/environments/>`_. We will be using ``UCRT64`` in the | 
|  | 16 | +examples below but it can be swapped by ``CLANG64`` (as long as the external | 
|  | 17 | +packages you want to use are available for the ``CLANG64`` environment, see | 
|  | 18 | +:ref:`Using system libraries with GHC`). | 
|  | 19 | + | 
|  | 20 | +.. note:: | 
|  | 21 | + | 
|  | 22 | +    When the code snippets must be run in a MSYS2 shell, we will use the ``msys2>`` | 
|  | 23 | +    prompt and when in a native Windows shell we will use the ``PS>`` or ``cmd>`` | 
|  | 24 | +    prompt. If either shell will do, we will just use ``>``. | 
|  | 25 | + | 
|  | 26 | +A small note on configuring and updating MSYS2 | 
|  | 27 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  | 28 | + | 
|  | 29 | +Before starting with MSYS2, one should make sure it is updated and properly configured. For that: | 
|  | 30 | + | 
|  | 31 | +:: | 
|  | 32 | + | 
|  | 33 | +   # Update the system, run twice | 
|  | 34 | +   msys2> pacman --noconfirm -Syuu | 
|  | 35 | +   msys2> pacman --noconfirm -Syuu | 
|  | 36 | + | 
|  | 37 | +   # install basic utilities | 
|  | 38 | +   msys2> pacman --noconfirm -S --needed curl autoconf mingw-w64-ucrt-x86_64-pkgconf | 
|  | 39 | +   msys2> pacman --noconfirm -S ca-certificates | 
|  | 40 | + | 
|  | 41 | +   # Optionally if you like zsh | 
|  | 42 | +   msys2> pacman --noconfirm -S zsh | 
|  | 43 | + | 
|  | 44 | +   # make $HOME the same in both PowerShell and MSYS2's Bash | 
|  | 45 | +   msys2> sed -i -e 's/db_home:.*$/db_home: windows/' /etc/nsswitch.conf | 
|  | 46 | + | 
|  | 47 | +   # Inherit Windows' path in MSYS2 | 
|  | 48 | +   msys2> sed -i -e 's/rem set MSYS2_PATH_TYPE=inherit/set MSYS2_PATH_TYPE=inherit/' /c/msys64/msys2_shell.cmd | 
|  | 49 | + | 
|  | 50 | +As a terminal, `Windows Terminal | 
|  | 51 | +<https://apps.microsoft.com/detail/9N0DX20HK701>`_ usually comes in handy. I use | 
|  | 52 | +the following profile: | 
|  | 53 | + | 
|  | 54 | +:: | 
|  | 55 | + | 
|  | 56 | +   { | 
|  | 57 | +     "colorScheme": "One Half Dark", | 
|  | 58 | +     "commandline": "C:\\msys64\\msys2_shell.cmd -defterm -here -no-start -ucrt64 -shell zsh", | 
|  | 59 | +     "hidden": false, | 
|  | 60 | +     "icon": "C:\\msys64\\ucrt64.ico", | 
|  | 61 | +     "name": "MSYS2 / UCRT64", | 
|  | 62 | +     "startingDirectory": "C:/Users/<YourName>" | 
|  | 63 | +   } | 
|  | 64 | + | 
|  | 65 | +Installing a Haskell environment on Windows | 
|  | 66 | +------------------------------------------- | 
|  | 67 | + | 
|  | 68 | +The recommended way of installing Haskell in Windows is via `GHCup | 
|  | 69 | +<https://www.haskell.org/ghcup/>`_. There are however two different ways of | 
|  | 70 | +using GHCup on Windows: | 
|  | 71 | + | 
|  | 72 | +GHCup without having installed MSYS2 already | 
|  | 73 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  | 74 | + | 
|  | 75 | +When the user just has fresh system, this option will install MSYS2 as a first | 
|  | 76 | +step. The command, as presented in the front page of `GHCup's website | 
|  | 77 | +<https://www.haskell.org/ghcup/>`_, has to be executed on a PowerShell: | 
|  | 78 | + | 
|  | 79 | +:: | 
|  | 80 | + | 
|  | 81 | +   PS> Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $true } catch { Write-Error $_ } | 
|  | 82 | + | 
|  | 83 | +After installing MSYS2 it will run the same script as the non-Windows systems | 
|  | 84 | +run with the appropriate values for the environment variables. This command will | 
|  | 85 | +also set the appropriate Environment Variables for Windows. | 
|  | 86 | + | 
|  | 87 | +GHCup on a system that already has MSYS2 | 
|  | 88 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  | 89 | + | 
|  | 90 | +GHCup can work with an already existing installation of MSYS2. For that, do the | 
|  | 91 | +following steps: | 
|  | 92 | + | 
|  | 93 | +:: | 
|  | 94 | + | 
|  | 95 | +   msys2> export GHCUP_MSYS2=/c/msys64 | 
|  | 96 | +   msys2> curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh | 
|  | 97 | + | 
|  | 98 | +For more information about other environment variables, refer to `the GHCup | 
|  | 99 | +documentation <https://www.haskell.org/ghcup/guide/#env-variables>`_. | 
|  | 100 | + | 
|  | 101 | +It is advisable also to set ``GHCUP_MSYS2=C:\msys64`` as a System variable on | 
|  | 102 | +Windows: | 
|  | 103 | + | 
|  | 104 | +1. Open the search bar and search for "Edit the system environment variables" | 
|  | 105 | + | 
|  | 106 | +2. Switch to the "Advanced" tab and click on "Environment Variables..." | 
|  | 107 | + | 
|  | 108 | +3. Click on "New..." and fill in the values. | 
|  | 109 | + | 
|  | 110 | +Additionally, in order to be able to invoke the installed tools, the ``PATH`` | 
|  | 111 | +should be modified to include the GHCup binaries directory: | 
|  | 112 | + | 
|  | 113 | +1. Open the search bar and search for "Edit the system environment variables" | 
|  | 114 | + | 
|  | 115 | +2. Switch to the "Advanced" tab and click on "Environment Variables..." | 
|  | 116 | + | 
|  | 117 | +3. Double click on ``PATH`` and add ``;C:\ghcup\bin`` at the end of the already existing value | 
|  | 118 | + | 
|  | 119 | +Invoking GHC on Windows | 
|  | 120 | +----------------------- | 
|  | 121 | + | 
|  | 122 | +GHC for Windows is shipped with a MinGW toolchain included. The set of included | 
|  | 123 | +packages can be found in `the GHC downloads page | 
|  | 124 | +<https://downloads.haskell.org/ghc/mingw>`_. Starting on version 0.7 of the | 
|  | 125 | +MinGW toolchain, the included packages are based on the ``CLANG64`` environment. | 
|  | 126 | +This built-in toolchain allows GHC to run on native Windows by using the bundled | 
|  | 127 | +``clang`` compiler. | 
|  | 128 | + | 
|  | 129 | +Once GHCup installed GHC, it is possible to invoke just it from any Windows | 
|  | 130 | +shell (such as PowerShell or ``cmd``) as long as the ``ghc.exe`` executable is | 
|  | 131 | +in the ``PATH``. When running ``ghc --info``, it can be seen that GHC already | 
|  | 132 | +sets flags for includes and library paths for the bundled toolchain: | 
|  | 133 | + | 
|  | 134 | +:: | 
|  | 135 | + | 
|  | 136 | +    > ghc --info | 
|  | 137 | +    [("Project name","The Glorious Glasgow Haskell Compilation System") | 
|  | 138 | +    ,("C compiler command","C:\\ghcup\\ghc\\9.8.1\\lib\\../mingw/bin/clang.exe") | 
|  | 139 | +    ,("C compiler flags","--rtlib=compiler-rt -D_UCRT -Qunused-arguments -IC:\\ghcup\\ghc\\9.8.1\\lib\\../mingw/include") | 
|  | 140 | +    ,("C++ compiler command","C:\\ghcup\\ghc\\9.8.1\\lib\\../mingw/bin/clang++.exe") | 
|  | 141 | +    ,("C++ compiler flags","-IC:\\ghcup\\ghc\\9.8.1\\lib\\../mingw/include") | 
|  | 142 | +    ,("C compiler link flags","-fuse-ld=lld --rtlib=compiler-rt -D_UCRT  -LC:\\ghcup\\ghc\\9.8.1\\lib\\../mingw/lib -LC:\\ghcup\\ghc\\9.8.1\\lib\\../mingw/x86_64-w64-mingw32/lib") | 
|  | 143 | +    ,("C compiler supports -no-pie","NO") | 
|  | 144 | +    ,("Haskell CPP command","C:\\ghcup\\ghc\\9.8.1\\lib\\../mingw/bin/clang.exe") | 
|  | 145 | +    ,("Haskell CPP flags","-E -undef -traditional -Wno-invalid-pp-token -Wno-unicode -Wno-trigraphs -IC:\\ghcup\\ghc\\9.8.1\\lib\\../mingw/include") | 
|  | 146 | +    ... | 
|  | 147 | + | 
|  | 148 | +However this is of limited use because GHC will only be able to invoke tools | 
|  | 149 | +that are bundled in the installation. It won't be able to call things like | 
|  | 150 | +``make`` or ``autoconf`` which are usually needed for configuring packages, and | 
|  | 151 | +it will also not be able to see any third-party libraries that are installed in | 
|  | 152 | +the system. | 
|  | 153 | + | 
|  | 154 | +.. _Using system libraries with GHC: | 
|  | 155 | + | 
|  | 156 | +Using system libraries with GHC | 
|  | 157 | +------------------------------- | 
|  | 158 | + | 
|  | 159 | +Packages can be installed in an MSYS2 environment via the ``pacman`` package | 
|  | 160 | +manager. The installation of those packages is done in standard directories in | 
|  | 161 | +the system, namely: | 
|  | 162 | + | 
|  | 163 | +- ``C:\msys64\usr\{bin,include,lib}``: for basic POSIX-like utilities. We might | 
|  | 164 | +  use tools that are in ``C:\msys64\usr\bin`` but we should not link against | 
|  | 165 | +  libraries in ``C:\msys64\usr\lib`` as those target ``msys-2.0.dll`` as a | 
|  | 166 | +  runtime dependency which is a fork of Cygwin and not a native Windows DLL. | 
|  | 167 | +  These are referred to as belonging to the ``msys`` repository. | 
|  | 168 | + | 
|  | 169 | +  In order to use tools from ``C:\msys64\usr\bin`` we need to make sure it is | 
|  | 170 | +  present in the ``PATH``. | 
|  | 171 | + | 
|  | 172 | +- ``C:\msys64\<environment>\{bin,include,lib}``: for tools and libraries that | 
|  | 173 | +  are compiled with the appropriate toolchain for that environment. We should | 
|  | 174 | +  provide these directories for includes and library paths if we want to use | 
|  | 175 | +  packages installed in the system. | 
|  | 176 | + | 
|  | 177 | +As an example, see that MSYS2 Packages offer two different versions of | 
|  | 178 | +``openssl``, one for `msys <https://packages.msys2.org/base/openssl>`_ and one | 
|  | 179 | +for `every other environment | 
|  | 180 | +<https://packages.msys2.org/base/mingw-w64-openssl>`_ (and in particular for | 
|  | 181 | +CLANG64 or UCRT64). When installing packages from MSYS2, one should pick the | 
|  | 182 | +options that show ``ucrt64/`` or ``clang64/`` as prefixes, and avoid the ones | 
|  | 183 | +that show ``msys/``. | 
|  | 184 | + | 
|  | 185 | +:: | 
|  | 186 | + | 
|  | 187 | +   msys2> pacman -Ss openssl | 
|  | 188 | +   ucrt64/mingw-w64-ucrt-x86_64-openssl 3.2.0-1 | 
|  | 189 | +       The Open Source toolkit for Secure Sockets Layer and Transport Layer Security (mingw-w64) | 
|  | 190 | +   ... | 
|  | 191 | +   clang64/mingw-w64-clang-x86_64-openssl 3.2.0-1 | 
|  | 192 | +       The Open Source toolkit for Secure Sockets Layer and Transport Layer Security (mingw-w64) | 
|  | 193 | +   ... | 
|  | 194 | +   msys/openssl 3.2.0-1 | 
|  | 195 | +       The Open Source toolkit for Secure Sockets Layer and Transport Layer Security | 
|  | 196 | + | 
|  | 197 | +   msys2> pacman -S ucrt64/mingw-w64-ucrt-x86_64-openssl | 
|  | 198 | + | 
|  | 199 | +Once the package is installed, the appropriate location of the libraries should | 
|  | 200 | +be given to GHC, for example if compiling something that depends on | 
|  | 201 | +``libssl.a``: | 
|  | 202 | + | 
|  | 203 | +:: | 
|  | 204 | + | 
|  | 205 | +   > ghc ... -IC:\\msys64\\ucrt64\\includes -LC:\\msys64\\ucrt64\\lib -lssl | 
|  | 206 | + | 
|  | 207 | +This should result in a succesful compilation. | 
|  | 208 | + | 
|  | 209 | +Using UNIX-like binaries with GHC | 
|  | 210 | +--------------------------------- | 
|  | 211 | + | 
|  | 212 | +As said above, the binaries that we might need to use are (by default) located | 
|  | 213 | +in two places: ``C:\msys64\usr\bin`` and ``C:\msys64\<environment>\bin``. The | 
|  | 214 | +easiest way to give GHC access to these executables is by including those | 
|  | 215 | +directories in your ``PATH``. | 
|  | 216 | + | 
|  | 217 | +- On PowerShell: | 
|  | 218 | +  :: | 
|  | 219 | + | 
|  | 220 | +     PS> $env:Path += ';C:\msys64\usr\bin;C:\msys64\ucrt64\bin' | 
|  | 221 | + | 
|  | 222 | +     PS> (Get-Command make.exe).Path | 
|  | 223 | +     C:\msys64\usr\bin\make.exe | 
|  | 224 | + | 
|  | 225 | +     PS> make --version | 
|  | 226 | +     GNU Make 4.4.1 | 
|  | 227 | +     Built for x86_64-pc-msys | 
|  | 228 | +     ... | 
|  | 229 | + | 
|  | 230 | +- On ``cmd``: | 
|  | 231 | +  :: | 
|  | 232 | + | 
|  | 233 | +     cmd> set PATH=%PATH%;C:\msys64\usr\bin;C:\msys64\ucrt64\bin | 
|  | 234 | + | 
|  | 235 | +     cmd> where make | 
|  | 236 | +     C:\msys64\usr\bin\make.exe | 
|  | 237 | + | 
|  | 238 | +     cmd> make --version | 
|  | 239 | +     GNU Make 4.4.1 | 
|  | 240 | +     Built for x86_64-pc-msys | 
|  | 241 | +     ... | 
|  | 242 | + | 
|  | 243 | +- On MSYS2 this is usually already set (otherwise your whole system is probably | 
|  | 244 | +  broken), but just in case one would do the following: | 
|  | 245 | + | 
|  | 246 | +  :: | 
|  | 247 | + | 
|  | 248 | +     msys2> export PATH=$PATH:/c/msys64/usr/bin:/c/msys64/ucrt64/bin | 
|  | 249 | + | 
|  | 250 | +     msys2> which make | 
|  | 251 | +     /usr/bin/make | 
|  | 252 | + | 
|  | 253 | +     msys2> make --version | 
|  | 254 | +     GNU Make 4.4.1 | 
|  | 255 | +     Built for x86_64-pc-msys | 
|  | 256 | +     ... | 
|  | 257 | + | 
|  | 258 | +If one really wants, it is possible to edit the system ``PATH`` to add these two | 
|  | 259 | +directories (although as explained below, Cabal will automatically add them for | 
|  | 260 | +us) by doing: | 
|  | 261 | + | 
|  | 262 | +1. Open the search bar and search for "Edit the system environment variables" | 
|  | 263 | + | 
|  | 264 | +2. Switch to the "Advanced" tab and click on "Environment Variables..." | 
|  | 265 | + | 
|  | 266 | +3. Double click on ``PATH`` and add ``;<dir1>;<dir2>`` at the end of the already existing value | 
|  | 267 | + | 
|  | 268 | +Once these directories are in the path, any UNIX-like utilities we might need | 
|  | 269 | +will be in scope, so configuring packages should be able to find them. | 
|  | 270 | + | 
|  | 271 | +Using Cabal on Windows | 
|  | 272 | +---------------------- | 
|  | 273 | + | 
|  | 274 | +Cabal will also be installed automatically by GHCup. Once the location of the | 
|  | 275 | +binary is present in the ``PATH``, ``cabal`` can be invoked from any Windows | 
|  | 276 | +shell, just as GHC. | 
|  | 277 | + | 
|  | 278 | +:: | 
|  | 279 | + | 
|  | 280 | +   > cabal --help | 
|  | 281 | +   Command line interface to the Haskell Cabal infrastructure. | 
|  | 282 | + | 
|  | 283 | +   See http://www.haskell.org/cabal/ for more information. | 
|  | 284 | + | 
|  | 285 | +   Usage: cabal-3.10.2.1.exe [GLOBAL FLAGS] [COMMAND [FLAGS]] | 
|  | 286 | + | 
|  | 287 | +   ... | 
|  | 288 | + | 
|  | 289 | +As both ``cabal.exe`` and ``ghc.exe`` are placed in the same location by GHCup, | 
|  | 290 | +normally cabal will be able to invoke GHC as said location will be in the | 
|  | 291 | +``PATH``. | 
|  | 292 | + | 
|  | 293 | +All the above extra configurations will also be needed when using ``cabal``, and | 
|  | 294 | +one can provide all of them via the following local project file: | 
|  | 295 | + | 
|  | 296 | +:: | 
|  | 297 | + | 
|  | 298 | +   msys2> cat << EOF > cabal.project.local | 
|  | 299 | +   package * | 
|  | 300 | +     extra-include-dirs: C:\msys64\ucrt64\include | 
|  | 301 | +     extra-lib-dirs: C:\msys64\ucrt64\lib | 
|  | 302 | +     extra-prog-path: C:\msys64\ucrt64\bin, | 
|  | 303 | +                      C:\msys64\usr\bin | 
|  | 304 | +   EOF | 
|  | 305 | + | 
|  | 306 | +Note that ``extra-include-dirs: x`` translates to the GHC option ``-Ix``, | 
|  | 307 | +``extra-lib-dirs: x`` translates to the GHC option ``-Lx`` and | 
|  | 308 | +``extra-prog-path: x`` results in the path ``x`` being added to the ``PATH`` | 
|  | 309 | +environment when calling an executable by cabal. | 
|  | 310 | + | 
|  | 311 | +However, this has the inconvenience that we would need to set this up for every | 
|  | 312 | +project that we want to build, and we sometimes wouldn't be able to install | 
|  | 313 | +binaries from Hackage directly as there is no local project to refer to. | 
|  | 314 | + | 
|  | 315 | +The recommended way of setting this is then modifying the global cabal | 
|  | 316 | +configuration, whose location you can find by calling ``cabal --help``: | 
|  | 317 | + | 
|  | 318 | +:: | 
|  | 319 | + | 
|  | 320 | +   > cabal --help | 
|  | 321 | +   ... | 
|  | 322 | +   You can edit the cabal configuration file to set defaults: | 
|  | 323 | +      C:\Users\<YourName>\AppData\Roaming\cabal\config | 
|  | 324 | + | 
|  | 325 | +In there, just add the lines mentioned above. For even better user experience, | 
|  | 326 | +it is advisable to add also two additional directories to the | 
|  | 327 | +``extra-prog-path`` section: | 
|  | 328 | + | 
|  | 329 | +- ``C:\ghcup\bin``: in the unexpected case that said directory is not in the | 
|  | 330 | +  ``PATH`` already (which would mean that ``cabal.exe`` was invoked via its full | 
|  | 331 | +  path or that it is not in the standard location). | 
|  | 332 | + | 
|  | 333 | +- ``C:\Users\<YourName>\AppData\Roaming\cabal\bin`` or whichever directory cabal | 
|  | 334 | +  installs binaries, so that other Haskell executables are also findable by | 
|  | 335 | +  cabal-invoked tools. See whether the ``installdir:`` section is uncommented | 
|  | 336 | +  and use its value. | 
|  | 337 | + | 
|  | 338 | +The configuration would then look like this: | 
|  | 339 | + | 
|  | 340 | +:: | 
|  | 341 | + | 
|  | 342 | +   > cat C:\\Users\\<YourName>\\AppData\\Roaming\\cabal\\config | 
|  | 343 | +   ... | 
|  | 344 | +   extra-include-dirs: C:\msys64\ucrt64\include | 
|  | 345 | +   ... | 
|  | 346 | +   extra-lib-dirs: C:\msys64\ucrt64\lib | 
|  | 347 | +   ... | 
|  | 348 | +   extra-prog-path: C:\ghcup\bin, | 
|  | 349 | +                    C:\Users\<YourName>\AppData\Roaming\cabal\bin, | 
|  | 350 | +                    C:\msys64\ucrt64\bin, | 
|  | 351 | +                    C:\msys64\usr\bin | 
|  | 352 | +   ... | 
0 commit comments