Skip to content

Commit cb32fd7

Browse files
authored
Merge pull request #5779 from malteneuss/extend_nix_doc_section
Expand Nix integration docs with more context and NixOS section
2 parents 1bf7f85 + a96e8e9 commit cb32fd7

File tree

1 file changed

+165
-59
lines changed

1 file changed

+165
-59
lines changed

doc/nix_integration.md

Lines changed: 165 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,27 @@
44

55
(since 0.1.10.0)
66

7-
When using the Nix integration, Haskell dependencies are handled as usual: They
8-
are downloaded from Stackage and built locally by Stack. Nix is used by Stack to
9-
provide the _non-Haskell_ dependencies needed by these Haskell packages.
10-
11-
`stack` can automatically create a build environment (the equivalent
12-
of a "container" in Docker parlance) using `nix-shell`, provided Nix
13-
is already installed on your system. To do so, please visit the
14-
[Nix download page](http://nixos.org/nix/download.html).
15-
16-
There are two ways to create a build environment:
17-
18-
- providing a list of packages (by "attribute name") from
19-
[Nixpkgs](http://nixos.org/nixos/packages.html), or
20-
- providing a custom `shell.nix` file containing a Nix expression that
21-
determines a *derivation*, i.e. a specification of what resources
22-
are available inside the shell.
23-
24-
The second requires writing code in Nix's custom language. So use this
25-
option only if you already know Nix and have special requirements,
7+
When using the Nix integration, Stack handles Haskell dependencies as usual
8+
while the Nix handles _non-Haskell_ dependencies needed by these Haskell packages.
9+
So Stack downloads Haskell packages from [Stackage](https://www.stackage.org/lts)
10+
and builds them locally but uses Nix to download
11+
[Nix packages][nix-search-packages] that provide the GHC compiler and
12+
external C libraries that you would normally install manually.
13+
You can install the Nix package manager with all the necessary commandline tools
14+
from the [Nix download page](http://nixos.org/nix/download.html).
15+
16+
`stack` can automatically create a Nix build environment in the background
17+
using `nix-shell`, similar to building inside an isolated
18+
[Docker](https://www.docker.com/) container.
19+
There are two options to create such a build environment:
20+
21+
- provide a list of [Nix packages][nix-search-packages]
22+
- provide a `shell.nix` file that gives you more control
23+
of what libraries and tools are available inside the shell.
24+
25+
The second requires writing code in
26+
[Nix's custom language][nix-language].
27+
So use this option only if you already know Nix and have special requirements,
2628
such as using custom Nix packages that override the standard ones or
2729
using system libraries with special requirements.
2830

@@ -38,34 +40,47 @@ You should either run `source ~/.nix-profile/etc/profile.d/nix.sh` manually
3840
every time you open a terminal and need Nix or add this command to your
3941
`~/.bashrc` or `~/.bash_profile`.
4042

41-
### Additions to your `stack.yaml`
43+
### External C libraries through Nix packages
4244

43-
Add a section to your `stack.yaml` as follows:
45+
To let Nix manage external C libraries by default
46+
add the following section to your `stack.yaml` file:
4447
```yaml
4548
nix:
4649
enable: true
47-
packages: [glpk, pcre]
50+
packages: [zlib, glpk, pcre]
4851
```
4952
5053
This will instruct `stack` to build inside a local build environment
51-
that will have the `glpk` and `pcre` libraries installed and
52-
available. Further, the build environment will implicitly also include
53-
a version of GHC matching the configured resolver. Enabling Nix
54-
support means packages will always be built using a GHC available
55-
inside the shell, rather than your globally installed one if any.
56-
57-
Note that in this mode `stack` can use only GHC versions that have
54+
that will have the Nix packages
55+
[zlib](https://search.nixos.org/packages?query=zlib),
56+
[glpk](https://search.nixos.org/packages?query=glpk) and
57+
[pcre](https://search.nixos.org/packages?query=pcre)
58+
installed, which provide the C libraries of the same names.
59+
Further, the build environment will implicitly also download and use
60+
a [GHC Nix package](https://search.nixos.org/packages?query=haskell.compiler.ghc)
61+
matching the required version of the configured
62+
[Stack resolver](https://docs.haskellstack.org/en/stable/GUIDE/#resolvers-and-changing-your-compiler-version).
63+
So, enabling Nix support means that packages will always be built using the
64+
local GHC from Nix inside your shell, rather than your
65+
globally installed system GHC if any.
66+
67+
Note that *in this mode every developer of your project needs to have Nix installed*,
68+
but also gets all external libraries automatically*. Quite convenient.
69+
If some developers don't have or want Nix, there's a nice tutorial on
70+
[how to add Nix integration optionally](https://www.tweag.io/blog/2022-06-02-haskell-stack-nix-shell/).
71+
72+
Also note that `stack` can use only GHC versions that have
5873
already been mirrored into the Nix package repository.
5974
The [Nixpkgs master branch](https://github.com/NixOS/nixpkgs/tree/master/pkgs/development/haskell-modules)
6075
usually picks up new versions quickly, but it takes two or three
6176
days before those updates arrive in the `unstable` channel. Release
62-
channels, like `nixos-15.09`, receive those updates only
77+
channels, like `nixos-22.05`, receive those updates only
6378
occasionally -- say, every two or three months --, so you should not
6479
expect them to have the latest compiler available. Fresh NixOS installs
6580
use a release version by default.
6681

6782
To know for sure whether a given compiler is available on your system,
68-
you can use the command
83+
you can use the Nix command
6984

7085
```sh
7186
$ nix-env -f "<nixpkgs>" -qaP -A haskell.compiler.ghc801
@@ -110,7 +125,7 @@ the `include/` folder. If you're dealing with a package that doesn't
110125
follow this standard layout, you'll have to deal with that using
111126
a custom shell file (see below).
112127

113-
### Use stack as normal
128+
### Using Stack with Nix enabled
114129

115130
With Nix enabled, `stack build` and `stack exec` will automatically
116131
launch themselves in a local build environment (using `nix-shell`
@@ -122,15 +137,16 @@ happen when running `stack build` if no setup has been performed
122137
before. Therefore it is no longer necessary to run `stack setup` unless you
123138
want to cache a GHC installation before running the build.
124139

125-
If `enable:` is omitted or set to `false`, you can still build in a nix-shell by
126-
passing the `--nix` flag to stack, for instance `stack --nix build`. Passing
127-
any `--nix*` option to the command line will do the same.
140+
If `enable:` is omitted or set to `false` in your `stack.yaml` file,
141+
you can still build within a nix-shell by
142+
overriding Stack through the `--nix` flag, for instance `stack --nix build`.
143+
Passing any `--nix*` option to the command line will do the same.
128144

129145
**Known limitation on macOS:** currently, `stack --nix ghci` fails on
130146
macOS, due to a bug in GHCi when working with external shared
131147
libraries.
132148

133-
### The Nix shell
149+
### Pure and impure Nix shell
134150

135151
By default, stack will run the build in a *pure* Nix build environment (or
136152
*shell*), which means two important things:
@@ -151,12 +167,20 @@ due soon to be resolved locale issues. So on macOS you'll need to be
151167
a bit more careful to check that you really have listed all
152168
dependencies.
153169

154-
### Package sources
170+
### Nix package sources
155171

156-
By default, `nix-shell` will look for the nixpkgs package set located
157-
by your `NIX_PATH` environment variable.
172+
Nix organizes its packages in snapshots of packages (each snapshot being
173+
a "package set")
174+
similar to how Stackage organizes Haskell packages.
175+
By default, `nix-shell` will look for the "nixpkgs" package set located
176+
by your `NIX_PATH` environment variable. This package set can be different
177+
depending on when you installed Nix and which nixpkgs channel you're using
178+
(similar to the LTS channel for stable packages and the nightly channel for bleeding
179+
edge packages in [Stackage](https://www.stackage.org/)).
180+
This is bad for reproducibilty so that nixpkgs should be pinned, i.e.,
181+
set to the same package set for every developer of your project.
158182

159-
You can override this by passing
183+
You can set or override the Nix package set by passing
160184
`--nix-path="nixpkgs=/my/own/nixpkgs/clone"` to ask Nix to use your
161185
own local checkout of the nixpkgs repository. You could in this way
162186
use a bleeding edge nixpkgs, cloned from the
@@ -168,19 +192,21 @@ nix:
168192
path: [nixpkgs=/my/own/nixpkgs/clone]
169193
```
170194

171-
in your `stack.yaml` will do the same.
195+
in your `stack.yaml` will do the same.
196+
[This example repository](https://github.com/tweag/haskell-stack-nix-example)
197+
shows how you can pin a package set.
172198

173199
## Command-line options
174200

175201
The configuration present in your `stack.yaml` can be overridden on the
176202
command-line. See `stack --nix-help` for a list of all Nix options.
177203

178-
## Configuration
204+
## Configuration options
179205

180-
`stack.yaml` contains a `nix:` section with Nix settings.
181-
Without this section, Nix will not be used.
206+
`stack.yaml` contains a `nix:` section for Nix settings.
207+
Without this section, Nix won't be used.
182208

183-
Here is a commented configuration file, showing the default values:
209+
Here's a working configuration file with all settings, mentioning default values:
184210

185211
```yaml
186212
nix:
@@ -189,7 +215,7 @@ nix:
189215
# NixOS where it is enabled by default (see #3938). You can set set it in your
190216
# `$HOME/.stack/config.yaml` to enable Nix for all your projects without having
191217
# to repeat it
192-
# enable: true
218+
enable: true
193219

194220
# true by default. Tells Nix whether to run in a pure shell or not.
195221
pure: true
@@ -221,15 +247,14 @@ nix:
221247
add-gc-roots: false
222248
```
223249
224-
## Using a custom shell.nix file
250+
## External C libraries through shell.nix
225251
226-
Nix is also a programming language, and as specified
227-
[here](#nix-integration) if you know it you can provide to the shell
228-
a fully customized derivation as an environment to use. Here is the
229-
equivalent of the configuration used in
230-
[this section](#additions-to-your-stackyaml), but with an explicit
231-
`shell.nix` file (make sure you're using a nixpkgs version later than
232-
2015-03-05):
252+
There's also the [Nix programming language][nix-language]
253+
to provide a fully customized derivation as an environment to use.
254+
Here's the equivalent of the configuration used in the
255+
[previous example](#external-c-libraries-through-nix-packages),
256+
but with an explicit `shell.nix` file
257+
(make sure you're using a nixpkgs version later than 2015-03-05):
233258

234259
```nix
235260
{ghc}:
@@ -238,19 +263,19 @@ with (import <nixpkgs> {});
238263
haskell.lib.buildStackProject {
239264
inherit ghc;
240265
name = "myEnv";
241-
buildInputs = [ glpk pcre ];
266+
buildInputs = [ zlib glpk pcre ];
242267
}
243268
```
244269

245-
Defining manually a `shell.nix` file gives you the possibility to override some
270+
Defining a `shell.nix` file manually gives you the possibility to override some
246271
Nix derivations ("packages"), for instance to change some build options of the
247272
libraries you use, or to set additional environment variables. See the
248273
[Nix manual][nix-manual-exprs] for more. The `buildStackProject` utility
249274
function is documented in the [Nixpkgs manual][nixpkgs-manual-haskell]. In such
250-
case, stack expect this file to define a function of exactly one argument that
275+
case, stack expects this file to define a function of exactly one argument that
251276
should be called `ghc` (as arguments within a set are non-positional), which you
252-
should give to `buildStackProject`. This is the ghc from the resolver you set in
253-
the `stack.yaml`.
277+
should give to `buildStackProject`. This is a GHC Nix package in the version as
278+
defined in the resolver you set in the `stack.yaml` file.
254279

255280
And now for the `stack.yaml` file:
256281

@@ -264,5 +289,86 @@ The `stack build` command will behave exactly the same as above. Note
264289
that specifying both `packages:` and a `shell-file:` results in an
265290
error. (Comment one out before adding the other.)
266291

292+
## Stack and developer tools on NixOS
293+
294+
When using Stack on NixOS, you have no choice but to use Stack's Nix integration to
295+
install GHC, because external C libraries in NixOS are not installed in the usual
296+
distro folders. So a GHC compiler installed through Stack (without Nix) can't find
297+
those libraries and therefore can't build most projects. However, GHC provided through Nix
298+
can be modified to find the external C libraries provided through Nix.
299+
300+
A detailed tutorial on how to configure Stack so that it supports NixOS and non-Nix users
301+
can be found [here](https://www.tweag.io/blog/2022-06-02-haskell-stack-nix-shell/). A corresponding
302+
example project can be found [here](https://github.com/tweag/haskell-stack-nix-example).
303+
304+
If you're already using Nix flakes, here's an adaptation of that example extended with typical developer
305+
tools like the [Haskell Language Server](https://haskell-language-server.readthedocs.io/en/latest/what-is-hls.html):
306+
Add the following `flake.nix` file to your project.
307+
308+
```nix
309+
{
310+
description = "my project description";
311+
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
312+
inputs.flake-utils.url = "github:numtide/flake-utils";
313+
314+
outputs = { self, nixpkgs, flake-utils }:
315+
flake-utils.lib.eachDefaultSystem (system:
316+
let
317+
pkgs = nixpkgs.legacyPackages.${system};
318+
319+
hPkgs =
320+
pkgs.haskell.packages."ghc8107"; # need to match Stackage LTS version from stack.yaml resolver
321+
322+
myDevTools = [
323+
hPkgs.ghc # GHC compiler in the desired version (will be available on PATH)
324+
hPkgs.ghcid # Continous terminal Haskell compile checker
325+
hPkgs.ormolu # Haskell formatter
326+
hPkgs.hlint # Haskell codestyle checker
327+
hPkgs.hoogle # Lookup Haskell documentation
328+
hPkgs.haskell-language-server # LSP server for editor
329+
hPkgs.implicit-hie # auto generate LSP hie.yaml file from cabal
330+
hPkgs.retrie # Haskell refactoring tool
331+
# hPkgs.cabal-install
332+
stack-wrapped
333+
pkgs.zlib # External C library needed by some Haskell packages
334+
];
335+
336+
# Wrap Stack to work with our Nix integration. We don't want to modify stack.yaml so non-Nix users don't notice anything.
337+
# - no-nix: We don't want Stack's way of integrating Nix.
338+
# --system-ghc # Use the existing GHC on PATH (will come from this Nix file)
339+
# --no-install-ghc # Don't try to install GHC if no matching GHC found on PATH
340+
stack-wrapped = pkgs.symlinkJoin {
341+
name = "stack"; # will be available as the usual `stack` in terminal
342+
paths = [ pkgs.stack ];
343+
buildInputs = [ pkgs.makeWrapper ];
344+
postBuild = ''
345+
wrapProgram $out/bin/stack \
346+
--add-flags "\
347+
--no-nix \
348+
--system-ghc \
349+
--no-install-ghc \
350+
"
351+
'';
352+
};
353+
in {
354+
devShells.default = pkgs.mkShell {
355+
buildInputs = myDevTools;
356+
357+
# Make external Nix c libraries like zlib known to GHC, like pkgs.haskell.lib.buildStackProject does
358+
# https://github.com/NixOS/nixpkgs/blob/d64780ea0e22b5f61cd6012a456869c702a72f20/pkgs/development/haskell-modules/generic-stack-builder.nix#L38
359+
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath myDevTools;
360+
};
361+
});
362+
}
363+
```
364+
365+
Commit this file to Git, run `nix develop` (it searches for `flake.nix` by default),
366+
and you'll find a new `flake.lock` file that pins the precise nixpkgs package set.
367+
Commit this file to Git as well so that every developer of your project will use precisely
368+
the same package set.
369+
267370
[nix-manual-exprs]: http://nixos.org/nix/manual/#chap-writing-nix-expressions
268371
[nixpkgs-manual-haskell]: https://nixos.org/nixpkgs/manual/#users-guide-to-the-haskell-infrastructure
372+
[nix-search-packages]: https://nixos.org/nixos/packages.html
373+
[nix-language]: https://nixos.wiki/wiki/Nix_Expression_Language
374+

0 commit comments

Comments
 (0)