top | item 38930947

(no title)

Aaronmacaron | 2 years ago

I use nix on my laptop because it's absolutely brilliant when it works. To me it's a fascinating technology. Being able to easily use different versions of some tool in two different projects, declaratively defining my dotfiles using home manager or quickly trying out some software using nix-shell -p is almost magical to me.

Eventhough I've used nix for years now, I have no deep understanding of nix and I'm a very curious person who always tries to understand how stuff actually works. Nix makes me feel really dumb. It makes me feel like when I was twelve and I "programmed" by cluelessly stitching together code examples from online tutorials. I don't really understand what's going on outside of the really common use cases for nix.

I read the entire nix docs but I think it's the kind of documentation that's only useful if you already kind of get what's going on. It feels like you have to gather the knowledge from various random blogs. Last time I checked there surprisingly was not a single book which covers nix. I feel like a comprehensive book which teaches nix from the ground up and explains all the different ways of using nix would really help me and I would purchase such a book without hesitation if it existed.

discuss

order

whatwhaaaaat|2 years ago

When you say run it on your laptop do you mean as the base operating system or on something else through a vm?

Aaronmacaron|2 years ago

I used to run NixOS on my main computer for a few months until I encountered some situation that I couldn't resolve using my nix skills. I think I needed to run some software that wasn't on nixpkgs.

Nowadays, I just use nix (the package manager) on top of PopOS.

thomastjeffery|2 years ago

I can't speak for them, but I can tell you I'm running NixOS directly on my own laptop (and desktop and server).

rustybolt|2 years ago

Thanks for saying this, I felt the same every time I tried Nix.

chriswarbo|2 years ago

> Eventhough I've used nix for years now, I have no deep understanding of nix and I'm a very curious person who always tries to understand how stuff actually works. Nix makes me feel really dumb. It makes me feel like when I was twelve and I "programmed" by cluelessly stitching together code examples from online tutorials. I don't really understand what's going on outside of the really common use cases for nix.

Nix is fundamentally just a build system. It's based around `.drv` files ("derivations", which are like a Makefile rule). These are text files containing a system type (e.g. x86_64-linux), the path to an executable, a list of string arguments to give it and a key/value map of strings to use as environment variables. Those basically form a declarative version of an `exec` syscall.

Each .drv file also specifies some paths as its "outputs", and may optionally specify some "inputs": an input is either a raw file path, or a pair of [path to another .drv file, name of output].

The basic operation in Nix is a "build", like `nix-build /nix/store/...foo.drv`, which tells Nix to produce that derivation's output paths. Nix does this as follows:

- Look in that .drv file to find its output paths. If they already exist on the filesystem, print the paths and halt.

- If some of the output paths don't exist, query any configured binary caches to see if they have those paths. If so: download them, print the paths and halt.

- If some outputs don't exist, and aren't in any configured cache, then Nix will need to execute the derivation's command...

- First Nix checks that all the inputs referenced as raw files exist; if not, it exits with an error.

- Next Nix checks whether all of the inputs which reference other .drv files exist. Any which don't exist will first be built by following these steps (and so on, recursively).

- Once all of the "inputs" exist, Nix will run the derivation's executable (maybe in a sandbox, but that's not important)

- When the executable has finished, Nix will check whether all of its output paths now exist. If not, it prints an error message and exits. If they do exist, it prints the paths and halts.

That's the core idea of what Nix is doing: it's a way to specify individual command invocations, create dependencies between commands using the paths of their outputs, and allowing parts of such dependency trees to be skipped by downloading the desired outputs directly from a cache instead. It's like Make, but spread across multiple files.

The "magic trick" that makes Nix special is that the path of every .drv file must contain a hash of its contents. Since .drv files can reference each other by their paths, these hashes form a Merkle tree which completely specifies the entire dependency graph of each derivation (similar to how a git commit includes the commit ID of its parents, and hence specifies its entire history).

This is a remarkably powerful and general approach to specifying the contents of files/folders. The downside is that it's tedious to write all of these .drv files by hand (especially calculating the hashes), so Nix comes with a simple scripting language to generate them. We can use the -E argument of nix-build to specify a "Nix expression", which will generate a .drv file to build (the `derivation` function will default to specifying a single output called "out"):

  $ nix-build -E 'derivation { name = "myName"; system = "aarch64-linux"; builder = "/bin/sh"; args = [ "-c" "echo foo 1>&2 && echo bar > $out" ]; }'
  this derivation will be built:
    /nix/store/irxpvx4cs8jmyysrd5hhqjx66blg4b8k-myName.drv
  building '/nix/store/irxpvx4cs8jmyysrd5hhqjx66blg4b8k-myName.drv'...
  foo
  /nix/store/mdaw1ajdd6zp8dnbcbxvay4lw9dssaqp-myName
  $ cat /nix/store/mdaw1ajdd6zp8dnbcbxvay4lw9dssaqp-myName
  bar
  $ cat /nix/store/irxpvx4cs8jmyysrd5hhqjx66blg4b8k-myName.drv
  Derive([("out","/nix/store/mdaw1ajdd6zp8dnbcbxvay4lw9dssaqp-myName","","")],[],[],"aarch64-linux","/bin/sh",["-c","echo foo 1>&2 && echo bar > $out"],[("builder","/bin/sh"),("name","myName"),("out","/nix/store/mdaw1ajdd6zp8dnbcbxvay4lw9dssaqp-myName"),("system","aarch64-linux")])
Other projects, like Nixpkgs, build on top of this foundation, by defining elaborate libraries of Nix expressions to generate .drv files for the build commands of thousands of different software projects. (Note that Nixpkgs doesn't use `/bin/sh` like I did; it specifies the URL and SHA256 of a few "bootstrap binaries" for Bash, GCC, etc. and those are used to define everything else)