1 # Dhall {#sec-language-dhall}
3 The Nixpkgs support for Dhall assumes some familiarity with Dhall's language
4 support for importing Dhall expressions, which is documented here:
6 * [`dhall-lang.org` - Installing packages](https://docs.dhall-lang.org/tutorials/Language-Tour.html#installing-packages)
8 ## Remote imports {#ssec-dhall-remote-imports}
10 Nixpkgs bypasses Dhall's support for remote imports using Dhall's
11 semantic integrity checks. Specifically, any Dhall import can be protected by
12 an integrity check like:
15 https://prelude.dhall-lang.org/v20.1.0/package.dhall
16 sha256:26b0ef498663d269e4dc6a82b0ee289ec565d683ef4c00d0ebdd25333a5a3c98
19 … and if the import is cached then the interpreter will load the import from
20 cache instead of fetching the URL.
22 Nixpkgs uses this trick to add all of a Dhall expression's dependencies into the
23 cache so that the Dhall interpreter never needs to resolve any remote URLs. In
24 fact, Nixpkgs uses a Dhall interpreter with remote imports disabled when
25 packaging Dhall expressions to enforce that the interpreter never resolves a
26 remote import. This means that Nixpkgs only supports building Dhall expressions
27 if all of their remote imports are protected by semantic integrity checks.
29 Instead of remote imports, Nixpkgs uses Nix to fetch remote Dhall code. For
30 example, the Prelude Dhall package uses `pkgs.fetchFromGitHub` to fetch the
31 `dhall-lang` repository containing the Prelude. Relying exclusively on Nix
32 to fetch Dhall code ensures that Dhall packages built using Nix remain pure and
33 also behave well when built within a sandbox.
35 ## Packaging a Dhall expression from scratch {#ssec-dhall-packaging-expression}
37 We can illustrate how Nixpkgs integrates Dhall by beginning from the following
38 trivial Dhall expression with one dependency (the Prelude):
43 let Prelude = https://prelude.dhall-lang.org/v20.1.0/package.dhall
45 in Prelude.Bool.not False
48 As written, this expression cannot be built using Nixpkgs because the
49 expression does not protect the Prelude import with a semantic integrity
50 check, so the first step is to freeze the expression using `dhall freeze`,
54 $ dhall freeze --inplace ./true.dhall
63 https://prelude.dhall-lang.org/v20.1.0/package.dhall
64 sha256:26b0ef498663d269e4dc6a82b0ee289ec565d683ef4c00d0ebdd25333a5a3c98
66 in Prelude.Bool.not False
69 To package that expression, we create a `./true.nix` file containing the
70 following specification for the Dhall package:
75 { buildDhallPackage, Prelude }:
80 dependencies = [ Prelude ];
85 … and we complete the build by incorporating that Dhall package into the
86 `pkgs.dhallPackages` hierarchy using an overlay, like this:
92 nixpkgs = builtins.fetchTarball {
93 url = "https://github.com/NixOS/nixpkgs/archive/94b2848559b12a8ed1fe433084686b2a81123c99.tar.gz";
94 hash = "sha256-B4Q3c6IvTLg3Q92qYa8y+i4uTaphtFdjp+Ir3QQjdN0=";
97 dhallOverlay = self: super: {
98 true = self.callPackage ./true.nix { };
101 overlay = self: super: {
102 dhallPackages = super.dhallPackages.override (old: {
104 self.lib.composeExtensions (old.overrides or (_: _: {})) dhallOverlay;
108 pkgs = import nixpkgs { config = {}; overlays = [ overlay ]; };
114 … which we can then build using this command:
117 $ nix build --file ./example.nix dhallPackages.true
120 ## Contents of a Dhall package {#ssec-dhall-package-contents}
122 The above package produces the following directory tree:
129 │ └── 122027abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
136 * `source.dhall` contains the result of interpreting our Dhall package:
139 $ cat ./result/source.dhall
143 * The `.cache` subdirectory contains one binary cache product encoding the
144 same result as `source.dhall`:
147 $ dhall decode < ./result/.cache/dhall/122027abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
151 * `binary.dhall` contains a Dhall expression which handles fetching and decoding
152 the same cache product:
155 $ cat ./result/binary.dhall
156 missing sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
157 $ cp -r ./result/.cache .cache
159 $ chmod -R u+w .cache
161 $ XDG_CACHE_HOME=.cache dhall --file ./result/binary.dhall
165 The `source.dhall` file is only present for packages that specify
166 `source = true;`. By default, Dhall packages omit the `source.dhall` in order
167 to conserve disk space when they are used exclusively as dependencies. For
168 example, if we build the Prelude package it will only contain the binary
169 encoding of the expression:
172 $ nix build --file ./example.nix dhallPackages.Prelude
178 │ └── 122026b0ef498663d269e4dc6a82b0ee289ec565d683ef4c00d0ebdd25333a5a3c98
181 2 directories, 2 files
184 Typically, you only specify `source = true;` for the top-level Dhall expression
185 of interest (such as our example `true.nix` Dhall package). However, if you
186 wish to specify `source = true` for all Dhall packages, then you can amend the
187 Dhall overlay like this:
191 dhallOverrides = self: super: {
192 # Enable source for all Dhall packages
194 args: super.buildDhallPackage (args // { source = true; });
196 true = self.callPackage ./true.nix { };
201 … and now the Prelude will contain the fully decoded result of interpreting
205 $ nix build --file ./example.nix dhallPackages.Prelude
211 │ └── 122026b0ef498663d269e4dc6a82b0ee289ec565d683ef4c00d0ebdd25333a5a3c98
215 $ cat ./result/source.dhall
219 List/fold Bool _ Bool (\(_ : Bool) -> \(_ : Bool) -> _@1 && _) True
220 , build = \(_ : Type -> _ -> _@1 -> _@2) -> _ Bool True False
223 List/fold Bool _ Bool (\(_ : Bool) -> \(_ : Bool) -> _@1 == _) True
229 ## Packaging functions {#ssec-dhall-packaging-functions}
231 We already saw an example of using `buildDhallPackage` to create a Dhall
232 package from a single file, but most Dhall packages consist of more than one
233 file and there are two derived utilities that you may find more useful when
234 packaging multiple files:
236 * `buildDhallDirectoryPackage` - build a Dhall package from a local directory
238 * `buildDhallGitHubPackage` - build a Dhall package from a GitHub repository
240 The `buildDhallPackage` is the lowest-level function and accepts the following
243 * `name`: The name of the derivation
245 * `dependencies`: Dhall dependencies to build and cache ahead of time
247 * `code`: The top-level expression to build for this package
249 Note that the `code` field accepts an arbitrary Dhall expression. You're
250 not limited to just a file.
252 * `source`: Set to `true` to include the decoded result as `source.dhall` in the
253 build product, at the expense of requiring more disk space
255 * `documentationRoot`: Set to the root directory of the package if you want
256 `dhall-docs` to generate documentation underneath the `docs` subdirectory of
259 The `buildDhallDirectoryPackage` is a higher-level function implemented in terms
260 of `buildDhallPackage` that accepts the following arguments:
262 * `name`: Same as `buildDhallPackage`
264 * `dependencies`: Same as `buildDhallPackage`
266 * `source`: Same as `buildDhallPackage`
268 * `src`: The directory containing Dhall code that you want to turn into a Dhall
271 * `file`: The top-level file (`package.dhall` by default) that is the entrypoint
272 to the rest of the package
274 * `document`: Set to `true` to generate documentation for the package
276 The `buildDhallGitHubPackage` is another higher-level function implemented in
277 terms of `buildDhallPackage` that accepts the following arguments:
279 * `name`: Same as `buildDhallPackage`
281 * `dependencies`: Same as `buildDhallPackage`
283 * `source`: Same as `buildDhallPackage`
285 * `owner`: The owner of the repository
287 * `repo`: The repository name
289 * `rev`: The desired revision (or branch, or tag)
291 * `directory`: The subdirectory of the Git repository to package (if a
292 directory other than the root of the repository)
294 * `file`: The top-level file (`${directory}/package.dhall` by default) that is
295 the entrypoint to the rest of the package
297 * `document`: Set to `true` to generate documentation for the package
299 Additionally, `buildDhallGitHubPackage` accepts the same arguments as
300 `fetchFromGitHub`, such as `hash` or `fetchSubmodules`.
302 ## `dhall-to-nixpkgs` {#ssec-dhall-dhall-to-nixpkgs}
304 You can use the `dhall-to-nixpkgs` command-line utility to automate
305 packaging Dhall code. For example:
308 $ nix-shell -p haskellPackages.dhall-nixpkgs nix-prefetch-git
309 [nix-shell]$ dhall-to-nixpkgs github https://github.com/Gabriella439/dhall-semver.git
310 { buildDhallGitHubPackage, Prelude }:
311 buildDhallGitHubPackage {
312 name = "dhall-semver";
313 githubBase = "github.com";
314 owner = "Gabriella439";
315 repo = "dhall-semver";
316 rev = "2d44ae605302ce5dc6c657a1216887fbb96392a4";
317 fetchSubmodules = false;
318 hash = "sha256-n0nQtswVapWi/x7or0O3MEYmAkt/a1uvlOtnje6GGnk=";
320 file = "package.dhall";
323 dependencies = [ (Prelude.overridePackage { file = "package.dhall"; }) ];
328 `nix-prefetch-git` is added to the `nix-shell -p` invocation above, because it has to be in `$PATH` for `dhall-to-nixpkgs` to work.
331 The utility takes care of automatically detecting remote imports and converting
332 them to package dependencies. You can also use the utility on local
333 Dhall directories, too:
336 $ dhall-to-nixpkgs directory ~/proj/dhall-semver
337 { buildDhallDirectoryPackage, Prelude }:
338 buildDhallDirectoryPackage {
340 src = ~/proj/dhall-semver;
341 file = "package.dhall";
344 dependencies = [ (Prelude.overridePackage { file = "package.dhall"; }) ];
348 ### Remote imports as fixed-output derivations {#ssec-dhall-remote-imports-as-fod}
350 `dhall-to-nixpkgs` has the ability to fetch and build remote imports as
351 fixed-output derivations by using their Dhall integrity check. This is
352 sometimes easier than manually packaging all remote imports.
354 This can be used like the following:
357 $ dhall-to-nixpkgs directory --fixed-output-derivations ~/proj/dhall-semver
358 { buildDhallDirectoryPackage, buildDhallUrl }:
359 buildDhallDirectoryPackage {
361 src = ~/proj/dhall-semver;
362 file = "package.dhall";
367 url = "https://prelude.dhall-lang.org/v17.0.0/package.dhall";
368 hash = "sha256-ENs8kZwl6QRoM9+Jeo/+JwHcOQ+giT2VjDQwUkvlpD4=";
369 dhallHash = "sha256:10db3c919c25e9046833df897a8ffe2701dc390fa0893d958c3430524be5a43e";
375 Here, `dhall-semver`'s `Prelude` dependency is fetched and built with the
376 `buildDhallUrl` helper function, instead of being passed in as a function
379 ## Overriding dependency versions {#ssec-dhall-overriding-dependency-versions}
381 Suppose that we change our `true.dhall` example expression to depend on an older
382 version of the Prelude (19.0.0):
388 https://prelude.dhall-lang.org/v19.0.0/package.dhall
389 sha256:eb693342eb769f782174157eba9b5924cf8ac6793897fc36a31ccbd6f56dafe2
391 in Prelude.Bool.not False
394 If we try to rebuild that expression the build will fail:
397 $ nix build --file ./example.nix dhallPackages.true
398 builder for '/nix/store/0f1hla7ff1wiaqyk1r2ky4wnhnw114fi-true.drv' failed with exit code 1; last 10 log lines:
400 Dhall was compiled without the 'with-http' flag.
402 The requested URL was: https://prelude.dhall-lang.org/v19.0.0/package.dhall
405 4│ https://prelude.dhall-lang.org/v19.0.0/package.dhall
406 5│ sha256:eb693342eb769f782174157eba9b5924cf8ac6793897fc36a31ccbd6f56dafe2
408 /nix/store/rsab4y99h14912h4zplqx2iizr5n4rc2-true.dhall:4:7
409 [1 built (1 failed), 0.0 MiB DL]
410 error: build of '/nix/store/0f1hla7ff1wiaqyk1r2ky4wnhnw114fi-true.drv' failed
413 … because the default Prelude selected by Nixpkgs revision
414 `94b2848559b12a8ed1fe433084686b2a81123c99is` is version 20.1.0, which doesn't
415 have the same integrity check as version 19.0.0. This means that version
416 19.0.0 is not cached and the interpreter is not allowed to fall back to
419 However, we can override the default Prelude version by using `dhall-to-nixpkgs`
420 to create a Dhall package for our desired Prelude:
423 $ dhall-to-nixpkgs github https://github.com/dhall-lang/dhall-lang.git \
425 --directory Prelude \
430 … and then referencing that package in our Dhall overlay, by either overriding
431 the Prelude globally for all packages, like this:
435 dhallOverrides = self: super: {
436 true = self.callPackage ./true.nix { };
438 Prelude = self.callPackage ./Prelude.nix { };
443 … or selectively overriding the Prelude dependency for just the `true` package,
448 dhallOverrides = self: super: {
449 true = self.callPackage ./true.nix {
450 Prelude = self.callPackage ./Prelude.nix { };
456 ## Overrides {#ssec-dhall-overrides}
458 You can override any of the arguments to `buildDhallGitHubPackage` or
459 `buildDhallDirectoryPackage` using the `overridePackage` attribute of a package.
460 For example, suppose we wanted to selectively enable `source = true` just for the Prelude. We can do that like this:
464 dhallOverrides = self: super: {
465 Prelude = super.Prelude.overridePackage { source = true; };
472 [semantic-integrity-checks]: https://docs.dhall-lang.org/tutorials/Language-Tour.html#installing-packages