Installing Essential Software In NixOS

This entry is part 3 of 6 in the series Setting Up Haskell Development on NixOS Linux from Scratch

Welcome to part 3 of my series on setting up NixOS for Haskell development!  In this part, we’ll learn how to discover and install essential software for NixOS.  We won’t cover the particulars of installing Haskell-related components (I’m saving that for a post on its own), but some of our decisions here will be motivated by the foresight that Haskell development is what we eventually want to do.  As always, if you see an error, please let me know.  I’m figuring this stuff out as I go.

In the last post, we learned a bit about the Nix package manager.  Let’s recap the essential points:

  • All software components in NixOS are installed using the Nix package manager.
  • Packages in Nix are defined using the nix language to create nix expressions.
  • Nix expressions define all inputs to a build process, including dependencies, which can themselves be nix expressions.
  • Nix will build all required dependencies if they do not already exist on your system.
  • Packages installed for all users are defined in the nix expression /etc/nixos/configuration.nix

The rest of this post will focus on how to install packages into your user environment.  These are the packages that are active on a per-user basis, so other users won’t necessarily have the same active packages as you do.

Finding and Installing Packages

Packages are installed by running Nix expressions, so how do we find Nix expressions?  There are actually a few different ways to get them.

  • Use the nix expressions that are included with your installation of NixOS, which are part of a nix channel.  A nix channel allows you to easily download updated expressions as well as pre-compiled binaries.
  • Download a set of nix expressions from the internet.
  • Subscribe to a new nix channel to download more up-to-date software packages than are available in the default channel.

Let’s explore each one of these in turn.  Spoiler alert: we’ll use 1) early on but most of our time will be spent with 2).  I’ll touch on 3), but honestly it’s not something I recommend if you’re doing Haskell development because I don’t think it offers much, if anything, over option 2).

Expressions Available through NixOS Installation

Your NixOS installation comes with a set of packages that are included by default.  These are installed in /nix/var/nix/profiles/per-user/root/channels/nixos, but NixOS is kind enough to give you a shortcut via ~/.nix-defexpr/channels_root/nixos.  This is the default location from which nix expressions are run.  It also happens to be a nix channel, but I’ll discuss nix channels later.  The key point is that NixOS comes with oodles of expressions built-in and ready to be run.  In fact, let’s run one right now in preparation for later steps.  We’ll install git. All of the manipulations of the user environment are invoked using the nix-env command. For example, if we want to see a list of all available packages from the built-in expressions

#!bash
nix-env -qaP --description *

Here, q means query, a means available packages, and P means show the attribute path, which is essentially a way to specify a particular expression instead of using the software package name.  The description option includes the description of the packages, as well.  In the case of git, we’ll see this among the long list of available packages:

#!bash
nixos.pkgs.gitAndTools.gitFull  git-1.9.4  Git, a popular distributed version control system

The software is named git-1.9.4, but the attribute path specifying the nix expression used to build it is nixos.pkgs.gitAndTools.gitFull.  We can use either the package name or the attribute path to install git, but the attribute path is the recommended strategy since it removes all ambiguity about which package should be installed and how. 

So let’s install git using the following command:

#!bash
nix-env -iA nixos.pkgs.gitAndTools.gitFull

Nix will then download all dependencies that you don’t already have (which, since this is our first installation, is all of them) and install git.  Here the flag i means install and A means by attribute path (yes, it bothers me that query commands use -P and install commands use -A).  We can verify the installation worked successfully by querying the list of installed packages in the user environment.

#!bash
nix-env -q --installed

The command above should list git as being an installed package.

Installing from Downloaded Expressions

Another approach to getting expressions is to download a collection of them from the internet.  The most popular collection is the nixpkgs repository on github.  In fact, the nix expressions that are bundled with NixOS (and which we explored above) are simply a stable version of this nixpkgs repository.

While the nixpkgs repository has a lot of available Haskell packages already, I quickly ran into ones that I needed but weren’t included.  Properly installing these packages requires adding new nix expressions to the available set.  This is why I recommend running downloaded nix expressions as the default method of installation for Haskell developers; most likely, you’ll be adding and running your own expressions anyway, and you can pull in updates with git just as easily as you can using nix channels.

Since Nix is declarative, our expressions will be useful for everyone else, too, so why not contribute them back to nixpkgs?  For this, we’ll need to fork the nixpkgs repository and then clone our fork to our local machine.  Any updates made locally can be made on a branch, pushed back to github, and then pulled into the main nixpkgs repository. FYI: when I cloned the repository, it was about 125 MB in size.

After you fork and clone the repo locally, cd to its root.  We’re going to run pretty much the same nix-env command we did before, except now we use the -f flag to read the nix expressions from the directory.  Personally, I’m trying to get good at vim, so I’ll be querying for it with the following:

#!bash
nix-env -f . -qaP --description vim
vim  vim-7.4.316  The most popular clone of the VI editor

Pretty easy.  In this case, I got lucky and was able to guess the package name “vim” correctly, but in general there are better ways to search, as we’ll find later. Installation is also an analogous command.

#!bash
nix-env -f . -iA vim

We’ll investigate how to update this local nixpkgs repository with our own additions in a future post.

Subscribing to a New Channel

The third option for getting expressions is to subscribe to a new channel.  I say new channel because all NixOS installations are automatically subscribed to the channel associated with the released OS version.  For instance, I can inspect the default channel’s manifest and see that it’s for NixOS version 14.04.

#!bash
cat ~/.nix-defexpr/channels_root/manifest.nix 
[ { meta = { }; name = "nixos-14.04.312.b84584f"; .......

Ok, but what is a channel?  A channel is a set of nix expressions combined with a manifest file.  The manifest file describes what binaries are available for downloading instead of building from scratch, so they can save you a lot of time if you are doing many installations. 

You can pull in new updates from a channel using the nix-channel --update command. The default channel is not really sufficient for development purposes because we want to add and run our own nix expressions.  As such, I’m glossing over channels in favor of pulling updates in from the git repository directly.  I admit I’m not the most knowledgeable about channels, so if there some best practices out there to make working with them easier, please let me know.

Enhancing the Nix Experience

We have seen how to query and install packages using Nix, but there are some small customizations we can make to make our development lives a bit easier.  Instead of using nix-env and specifying our standard set of flags again and again, we can write some custom bash commands to do most of the typing for us. One problem: how can we search for packages by keyword?  The nix-env command takes a package name as an input, not a general keyword. Thankfully, we have grep, which can search through the large list of available packages and find keywords and regular expressions for us. The code below defines a new bash command nix-search that will search through all the expressions in our git repository looking for matches of a particular keyword or regular expression.  Searching for the right expression to install will be much easier.

#!bash
nix-search(){ echo "Searching..."; nix-env -f ~/Code/nixpkgs -qaP --description \* | grep -i "$1"; }

All this hard-coding of -f ~/Code/nixpkgs is a problem waiting to happen, though. A better way is to use the .nix-defexpr folder to simply change the default location that Nix searches for expressions. In doing so, we won’t even need the -f flag anymore.

One thing I’d like is to have .nix-defexpr be a link itself to my ~/Code/nixpkgs directory. Otherwise, my attribute paths will need some kind of prefix, and since I only want to use expressions under ~/Code/nixpkgs, using this unnecessary prefix will get a little annoying. Normally, we could simply make .nix-defexpr a link to the right directory, but it turns out that if .nix-defexpr is a link, it is deleted when you log in and replaced with the Nix default. So, as a work around, I’m adding code to my .bashrc file to set up .nix-defexpr the way I want when I open the terminal.

We also should change the NIX_PATH environment variable similarly to what I have done below.

#!bash
# In ~/.bashrc
rm -r ~/.nix-defexpr
ln -s /home/dan/Code/nixpkgs ~/.nix-defexpr

# Then export the right env variables:
export NIX_PATH=/home/dan/Code:nixos-config=/etc/nixos/configuration.nix;
nix-search(){ echo "Searching..."; nix-env -qaP --description \* | grep -i "$1"; }

We can make installing easier too by writing a new command to run expressions from our git repo, specified by attribute path.

#!bash
nix-install(){ nix-env -iA $1; }

The first version of this post used the -f flag exclusively because I didn’t yet know about NIX_PATH and .nix-defexpr. Having a nix-install helper function makes more sense when the -f flag was being used, but in its current form it doesn’t save any keystrokes. The user may use her discretion when deciding whether or not to use nix-install.

Put both functions into the .bashrc file in your home directory, then use source ~/.bashrc to reload the .bashrc file for the updates to take effect.  We can use the new commands like this (might need to scroll right!):

#!bash
[dan@nixos:~]$ nix-search vim
Searching...
bvi                                                                 bvi-1.3.2                                                                     Hex editor with vim style keybindings
qvim                                                                qvim-7.4                                                                      The most popular clone of the VI editor (Qt GUI fork)
vim                                                                 vim-7.4.316                                                                   The most popular clone of the VI editor
vimWrapper                                                          vim-with-vimrc-7.4.316                                                        The most popular clone of the VI editor
vimb                                                                vimb-2.4                                                                      A Vim-like browser
vimbWrapper                                                         vimb-with-plugins-2.4                                                         A Vim-like browser (with plugins: )
vimprobable2                                                        vimprobable2-1.4.2                                                            Vimprobable is a web browser that behaves like the Vimperator plugin available for Mozilla Firefox 
vimprobable2Wrapper                                                 vimprobable2-with-plugins-1.4.2                                               Vimprobable is a web browser that behaves like the Vimperator plugin available for Mozilla Firefox  (with plugins: )
vimNox                                                              vim_configurable-7.4.316                                                      The most popular clone of the VI editor
vimHugeX                                                            vim_configurable-7.4.316                                                      The most popular clone of the VI editor
vimHugeXWrapper                                                     vim_configurable-with-vimrc-7.4.316                                           The most popular clone of the VI editor

[dan@nixos:~]$ nix-install vim
replacing old `vim-7.4.316'
installing `vim-7.4.316'

An Aside About Nix Search Paths

I have had to update this post a few times as I learn more about how Nix search paths work. I have tried to keep everything mentioned here correct and consistent, but having everything clearly spelled out is valuable. Here’s my most up-to-date knowledge:

  • By default, the nix-env command searches the expressions contained in the ~/.nix-defexpr directory. This directory can have subfolders or symbolic links to any other directories, and Nix will prepend any attributes with the symbolic link name. For instance, if .nix-defexpr contained a link dans_nixpkgs -> ~/Code/nixpkgs, then searches using nix-env will show attributes as dans_nixpkgs.haskellPackages.snap, for instance.
  • By making .nix-defexpr a symbolic link itself, you can eliminate the prefixes, but .nix-defexpr will be reset back to the default the next time you boot the machine. As a work around, I have placed code in my .bashrc file to set it up the way I want each time a terminal is opened.
  • The .nix-defexpr default location is what is overridden when using the -f flag.
  • The NIX_PATH environment variable is used when resolving <brackets> in nix expressions. For example, NIX_PATH=/home/dan/Code will lead to <nixpkgs> resolving to /home/dan/Code/nixpkgs. It has no effect on the nix-env command itself.
  • nixos-config must point to the configuration.nix file or else nixos-rebuild calls will fail.

Installing Haskell Platform and GHC

We can use our new bash commands to start installing our required Haskell packages.  In the past, I have tried to avoid Haskell Platform because, invariably, I would need a different version of one of the packages it offers or I would need a package that isn’t included.  Unfortunately, following either of these scenarios has sometimes required that I re-install all my packages from scratch to resolve odd dependency conflicts. But, this is NixOS, and the claim is that NixOS is designed to prevent that kind of baloney from happening.  Only time and experience will tell if that’s true, but in the meantime we’ll barge right ahead and get Haskell Platform since it is often suggested as the best way to get started with Haskell.

#!bash
[dan@nixos:~]$ nix-search "haskell platform"
Searching...
&lt;omitted&gt;
haskellPlatform                                                     haskell-platform-2013.2.0.0                                                   Haskell Platform meta package
[dan@nixos:~]$ nix-install haskellPlatform 

After installation is complete, we will have Haskell Platform 2013.2.0.0 installed, which used ghc 7.6.3 to build.   However, we did not yet install ghc because NixOS only puts packages we install on the path, not their dependencies. Installing ghc is now a fast operation because all NixOS is doing is adding the existing executable to the path. At the same time, let’s install cabal.

#!bash
nix-install haskellPackages.ghc
nix-install haskellPackages.cabalInstall

I have received reports from some users that haskellPackages.ghc doesn’t work for them, but haskellPlatform.ghc does, so give that a try if the above doesn’t work for you.


That’s it for this installment.  Check back soon for the next *exciting *post in this series, although I’m not yet sure what it will be.

Series Navigation<< Installing NixOSSetting Up Vim (for Haskell) >>

5 thoughts on “Installing Essential Software In NixOS

  1. Couldn’t get ‘haskellPackages.ghc’ to work, but ‘haskellPlatform.ghc’ installed just fine. Typo in your article?

    • For me it’s definitely haskellPackages, but I’ll add a note indicating it could be haskellPlatform for some users.

      FYI I also made new updates in the aside about nix search paths. My best recommendations continue to be a work in progress.

  2. Hi,

    I’m finding that nix-search(){ echo "Searching..."; nix-env -qaP --description * | grep -i "$1"; } gives me the following error: error: selector ‘Code’ matches no derivations

    The solution appears to be to use .\* instead of * in the above. This solution came from the man pages of nix-env.

    • Thanks for the heads up. I think there might have been some recent changes to nix-env that changed this behavior (I think nix-env now support regex out of the box, so no need to do grep).

    • This error comes because the * is unquoted, which means shell globbing will grab whatever files/directories are in . and pass them into nix-env as arguments. In your case, it’s likely that you have a directory named ‘Code’ in the directory where you are running nix-search. Simple fix is to quote the *:

      nix-search(){ echo "Searching..."; nix-env -qaP --description '*' | grep -i "$1"; }

Comments are closed.