Nix Progress (Part 3)
This blog entry is a continuation of the Nix Progress and Nix Progress (Part 2) blog entries. It discusses some of the things that I have learned.
Default Values
Nix functions can provide default values for arguments using syntax like the following:
{ compiler ? "ghc8104"
, nixpkgs ? null
}:
In this example, the default compiler value is specified
in the argument list while the nixpkgs value has a default
of null and is determined in the body of the function (not
shown). When should a value be specified, and when should
null be used?
TTC
Nix configuration consists of a shell.nix file that
configures a shell environment for development and testing. There is no
default.nix file. The arguments in shell.nix
are like the above, and the default compiler is set in a single
location: the argument list.
LiterateX
Nix configuration, on the other hand, has both a
default.nix and a shell.nix. Both files
include a compiler argument. In this case, the default
value should be null and the compiler value should be
determined in the body of the function defined in
default.nix. The default compiler is set in a single
location, in default.nix. If a default value were specified
like in the example above, then the default compiler would need to be
specified in two separate files, which is not preferred because one
could be forgotten during maintenance and lead to issues.
The default for the nixpkgs argument is
null in both cases. One might consider the option of
setting the known working nixpkgs revision hash for the
default compiler as the default value for nixpkgs, but this
should be avoided because of types. The nixpkgs argument is
a path type, not a (revision) string type. In the current
implementation, the following possibilities are supported:
- When a
nixpkgspath is provided, it is used. - When a supported (tested) compiler is selected and a
nixpkgspath is not provided, a known working revisions ofnixpkgsis used. - When a non-supported (non-tested) compiler is selected and a
nixpkgspath is not provided, packages configured on the filesystem (<nixpkgs>) are used.
isShell Flag
In projects that have both a default.nix and
shell.nix configuration, I needed to figure out how to add
build tools to the shell using the appropriate revision of
nixpkgs. I ended up adding an isShell argument
to the function defined in default.nix, with a default
value of false. The shell.nix implementation
imports default.nix with the value set to
true. This allows the tooling to be added using the
appropriate revision, keeping all of the revision logic in one
place.
Problematic
default.nix?
Before getting help from Divam, I used a fixed nixpkgs
revision in default.nix. This is problematic because other
software that uses the library via Nix by fetching the tarball from
GitHub likely uses a different revision.
LiterateX makes use of TTC, so I tried it out to see what happens. At least in this simple case, it worked without issue! I suspect that it works because no system libraries are used.
Broken Flags
When refactoring the Nix configuration for the LiterateX animation, I initially planned on using GHC 8.10.4 with the nix-versions revision. The build failed immediately, reporting that the diagrams-cairo package was marked as “broken!” I was happy to get a quick error instead of waiting a long time for it to eventually fail.
The broken
flag is a standard meta-attribute that can be passed as an argument to
mkDerivation. Investigating, I found the flag set in the
derivation used in my attempted build: haskell-packages.nix.
A comment says that this file is auto-generated. The configuration-hackage2nix.yaml
file is where the package is actually marked as broken.