Skip to content

Commit 0928b72

Browse files
committed
How to use Cabal in Windows
1 parent 3d3622f commit 0928b72

File tree

2 files changed

+353
-0
lines changed

2 files changed

+353
-0
lines changed

doc/how-to-run-in-windows.rst

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
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+
...

doc/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Welcome to the Cabal User Guide
1515

1616
how-to-package-haskell-code
1717
how-to-build-like-nix
18+
how-to-run-in-windows
1819
how-to-use-backpack
1920
how-to-report-bugs
2021

0 commit comments

Comments
 (0)