Usability study session #9

< previous study | top | next study >

1. Bio / Persona

Math student. Programming experience: scientific programming and implementing algorithms. Hasn’t done any larger software projects yet, but confident with C, C++, Python, Matlab, Lisp, and has a bit of Haskell and Java knowledge.

2. Prior Nix experience


3. Approaches to learning Nix

This session will be the first attempt.

4. Using Nix

Goal for this session: compile a C++ project on Arch Linux. Pre-Nix attemtps failed because the project needs gcc 11, but gcc 12 is installed, and manual downgrade is a pain. Presumes that Nix will solve this issue.

Goes to, scrolls through the front page looking for examples, but not interested in videos, and simply installs Nix with yay -S nix.

Wants to understand how to declaratively add packages to the shell, and starts the learning journey on

  • Chooses the Learn tab

    • Clicks on the First steps with Nix button. (At the time, it was linking to Set up a development environment article.)

      Recreates default.nix, inspects first line - seems to be unspecific to Python, looks very mysterious, and ? and : does not make any sense. Doesn’t know what pkgs.python3Packages means, then skims Python-specific lines. Skims rest of the page, and decides to go back to Learn.

    • Chooses Ad hoc developer environments article after scanning the list of guides. “Probably not what I want, but it’s the first guide.” Somewhat confused when scanning each section as they appear to be unrelated mini-articles.

      Comes across the link to, navigates there, looks up gcc, and the most relevant result shows that its version number is 10.3.0. Finds this very arbitrary and wonders why that specific version?

      The next section demonstrates nix-shell -p. Gives nix-shell -p gcc a try, and the gcc's version in the shell is indeed 10.3.0.

      Slightly frustrated now because none of the guides so far showed how to declaratively put a specific package into a Nix environment. “How does it work for something that is not Python?

      Goes back to Learn once again, scrolls past the guides, and examines the section headings of the manuals. Sees nix-build, and thinks that this may be it.

    • Interviewer: Would you take a look at the Declarative and reproducible developer environments article?

      Finds it promising as the ad hoc way (i.e., nix-shell -p) works already. Looks at the example in the “Getting started” section, finds fetchTarball kind of mysterious, but the note below is helpful; still a bit unclear about it, but accepts that there is a valid reason behind using it.

      Creates a shell.nix by copying the example, and runs nix-shell as instructed. No errors, and a quick inspection with which htop shows that the htop command in the shell links to the one in the Nix store and not to the system-wide one.

      Reads rest of the article, deems the sections about setting environment variables and direnv intriguing, but doesn’t need it right now.

      Exits the Nix shell, adds gcc to list of packages in shell.nix, runs nix-shell, and confirms again that gcc is provided by Nix.

Confident that all’s there that is needed for creating the C++ project’s development environment under Nix, and starts checking the dependencies on

  • nasm - check
  • gdb - check
  • qemu - check

The results for the last one show several packages starting with qemu, and all have the same descriptions, but isn’t fazed as Arch also has similar convention for splitting packages. Chooses qemu_full, but nix-shell throws an error:

error: attribute 'qemu_full' missing

       at /home/my-user/shell.nix:5:5:

            4|   buildInputs = [
            5|     pkgs.qemu_full
             |     ^
            6|     pkgs.htop
(use '--show-trace' to show detailed location information)

nix-shell -p qemu works, but takes a lot of time. Tries nix-shell -p qemu<TAB> next, nothing happens so completes it to nix-shell -p qemu_full and that also works. Odd. Re-checks the search results, but everything seems to be in order.

Interviewer explains that when pinning in shell.nix, the commit hash in fetchTarball references a revision of Nixpkgs which may be old enough not to contain qemu_full. On the other hand,nix-shell -p works, because it is grabbing packages from the default channel. Advises using qemu for now as it should be good enough.

shell.nix works now, but remarks that make would be also good to have. Mild surprise when there are no search results for make. “Why is something so basic not there? Is it provided by default?” Tests hypothesis, and make is indeed available in the shell.

First attempt at compiling the project fails:

error: /nix/store/.../bin/ld architecture of input file `/nix/store/...-gcc/lib/gc/.../crtbegin.o` incompatible with  i386 output

Notices that ld is from the Nix store, but can’t do much with this information. Removes pinning from shell.nix, but is greeted with another issue: root partition is full. Goes back to the Learn page, hoping to find a solution. Scrolls past the guides, and the nix-store link in the Nix manual column seems to be what is needed. The description starts with:

You generally do not need to run this command manually.

It may not be relevant then, so goes back to the Nix manual column, and chooses “Basic package management” this time. At least, it seems to be the place to document how to clear up old or unneeded packages. Starts reading about nix-env.

Interviewer: Don’t do that or you will get a Primer XKCD movie plot experience

Insists on trying nix-env. Checks man nix-env, and does

$ nix-env --uninstall qemu qemu_full

warning: selector 'qemu' matched no installed derivations
warning: selector 'qemu_full' matched no installed derivations

Next attempt is nix-collect-garbage, which frees 5.3 GB. Re-run nix-shell, but assumes it’s broken again as the command line still hangs after 10s on an x270. Finally, lines starts pouring in. Catches glimpses of Python being mentioned, and wonders why it is needed.

Participant: A status bar would inspire more confidence. With Arch, you may get onto the wrong mirror, and when you see that the download goes with 30K/s for example, you can take action right away.

Meanwhile, the compilation errored out with the same message. Appears to be a cross compilation error as we want to compile to i386. Checks gcc -v output, but confused as Configured with: line is empty:

$ gcc -v

Using built-in specs.
Target: x86_64-unknown-linux-gnu
Configured with:
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.3.0 (GCC)

Searches for gcc on, reads description, but it’s no help. Inspects the other gcc packages, gcc_multi sounds promising, but all prove irrelevant in the end.

Googles cross compiling with nix:

  • NixOS wiki: Cross Compiling

    First example of cross-compiling a package is dismissed promptly. Next section shows crossShell.nix, but unfamiliar with the syntax. The first lines look somehow similar though, but this doesn’t help much.

    • Participant’s shell.nix:

      { pkgs ? import <nixpkgs> {} }:
    • crossShell.nix:

      with import <nixpkgs> {

    Arrives at the line:

    Examples of how to specify your target system can be found in lib/systems/examples.nix.

    Follows it, searches for “i386”, but the only result is something related to iPhones. Widens the search by using “86”, but no joy.

    Participant: What could be the architecture’s name? Is it just gnu32? Maybe it’s just my lack of knowledge on computer architectures…

    Tries replacing the example line with i386 (has both header lines at the top), but it doesn’t work. What about i686? gcc -v output still does not visibly change.

    QUESTION TO @fricklerhandwerk: The notes here simply say:

    • intervention: correct the Nix expr invocation
    • that would have been the other option
    • the weird thing

    I have no clue what the fix could have been, and these lines are just cryptic.

    It looks that gcc is being entirely re-built, and every single package on top of that. Abort.

  • Looks at the Cross compilation article on next:

    Looks helpful.” Only wants to change the host platform, and there is already a section on choosing host platform with Nix.

    These attribute names for cross compilation packages have been chosen somewhat freely over the course of time. They usually do not match the corresponding platform config string.

    What does it mean that “these names have been chosen freely”? Which one would I want? Probably gnu32.” Goes forward with pkgs.pkgsCross.gnu32.gcc, and re-runs nix-shell. Looks good, dependencies appear to be relevant to gcc, but stumped when seeing a Linux kernel name pop up, wondering why it would need that.

The session ends here.


Hosted by Flying Circus.