Skip to main content

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 nixpkgs path is provided, it is used.
  • When a supported (tested) compiler is selected and a nixpkgs path is not provided, a known working revisions of nixpkgs is used.
  • When a non-supported (non-tested) compiler is selected and a nixpkgs path 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.

Author

Travis Cardwell

Published

Tags
Related Blog Entries