First time trying NixOS, random questions

I’ve been meaning to try nixos for a while, and recently I had an issue with ubuntu getting into a corrupt state and discovered how poor the support for rollback was, and that finally pushed me over the hump.

I have heard that nixos is great for developers who want to manage a bunch of environments with different versions of the same libraries and tools, so that was one of the first things I wanted to try.

There is a website called highload.fun where people compete to write the most optimized possible compiled code. However they very specifically use GCC 9.3.0 to evaluate submissions. So installing that was the first thing that I wanted to try… I can’t make it work. But note that I am as interested in understanding why the things I tried below didn’t work as I am in actually getting GCC 9.3.0 installed. How else am I going to learn how the distro works? :slight_smile:

I expect three common use cases for package installs: wanting it to be system wide, wanting it to be the default in PATH for a particular user, and wanting it to be the default for a particular sandbox for a particular user. I have managed to install some packages system wide like htop and git – I can edit /etc/nixos/configuration.nix and add to systemPackages. But to make something the default for a single user I guess I need to use Home Manager? But the README basically tells you not to use it if you’re a newbie, and specifically says it doesn’t support rollbacks which is the main reason for me wanting to try nixos…

So anyway what if in settle for installing system wide? Well then the problem is I can’t get the version I want. After some googling I tried this:

environment.systemPackages = with pkgs; [
  (gcc9.overrideAttrs (oldAttrs: { version = "9.3.0"; }))
];

AFAICT the version is completely ignored and it installs 9.5.0. Disappointingly, I don’t get any errors! It doesn’t give me a lot of faith that a totally reproducible system is actually reproducible that I can ask for one version explicitly and get a completely different version…

More googling then tried this:

{
  environment.systemPackages = with pkgs; [
    (gcc9.overrideAttrs (oldAttrs: {
      version = "9.3.0";
      src = fetchurl {
        url = "mirror://gcc/releases/gcc-9.3.0/gcc-9.3.0.tar.xz";
        sha256 = "I put the hash here";
      };
    }))
  ];
}

to get the hash to insert I tried:

nix-prefetch-url --unpack "https://ftp.gnu.org/gnu/gcc/gcc-9.3.0/gcc-9.3.0.tar.gz"

Which reported 15cyd8gwcyy0cxd4iarb6ns3qfs6vywqhwi6f78sx9h9sr7q52qq. So I put that in…

'/nix/store/bsxmb8x9rswwin2di2kzb6z3d9c0v1ls-gcc-9.3.0.tar.gz.drv':
         specified: sha256-GIuCT9YJpq7RcSZyiLnfRjs8tDUrq0haZ8B7xh9qnpU=
            got:    sha256-Uliptq/pRjwuVrnoNVsaS+4SXKgouAePkQMDvC75H6Y=
error: 1 dependencies of derivation '/nix/store/1zng9pcpkvgn5xgw4i21vqqxs4nvbix0-gcc-wrapper-9.3.0.drv' failed to build
error: 1 dependencies of derivation '/nix/store/a69j2an2yhrwd3xlc3bjg3p3il3gj5qn-system-path.drv' failed to build
error: 1 dependencies of derivation '/nix/store/f43xr2lpca809j1h3j03dkyy1b8plbhm-nixos-system-sliceserv-23.05.3037.f155f0cf4ea4.drv' failed to build

Now what is extremely confusing about this is neither of those hashes are the one I specified! Oh well, I guess I will try using the hash that it explicitly gave me… hey it succeeded! So lets try…

$ gcc --version
gcc (GCC) 9.5.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Not getting an error an still getting the wrong version in this circumstance seems totally bonkers, it means nix downloaded the tarball and then decided not to use it anyway! The command also finished suspiciously fast making me think that it didn’t spend any time building anything…

Alright I do some more reading and somebody suggests something called an overlay file. Don’t really know what overlays are yet, but I try putting this code in ~/.config/nixpkgs/overlays/gcc-overlay.nix:

self: super: {
  gcc9custom = super.gcc9.overrideAttrs (old: {
    version = "9.3.0";
    src = fetchurl {
      url = "mirror://gnu/gcc/gcc-9.3.0/gcc-9.3.0.tar.xz";
      sha256 = "I put the hash here";
    };
  });

Then I ran:

nix-env -iA nixos.gcc9custom

…nope still GCC 9.5.

Okay, surely if I just google a little bit more… I find this thread which seems to be suggesting to use a special build hack to deal with packages that expect a typical file system layout… Something I’m guessing the official package already does under the hood? But the version that they have put together is using something called flakes… So I google to trying to figure out what flakes are, and I find THIS thread, which says that flakes, like home manager, are not yet stable and not really ready for prime time, and also apparently have some design problems, but also they are what everybody is using instead of the stable method? @_@

So at this point what I am trying to understand is whether or not what I’m doing is extremely weird compared to what people would normally want to use NixOS for? I thought the raison d’ etre here was easy rollbacks (turns out not for your home directory), reproducibility (except versions other than the one that you requested are silently installed), and having multiple versions of the same toolchain and libraries simultaneously (same problem). I wasn’t expecting this much friction on the first thing I tried, multiple compiler versions doesn’t seem that exotic? I could download gcc on Ubuntu and install it with --prefix into my home folder pretty easily.

--unpack is wrong here. fetchurl produces the file as it is, i.e. compressed.

1 Like

IMO the main issue is that you override something and don’t know what it really is. gcc9 attribute does not build the compiler. It’s a wrapper about the real compiler, in order to set some extra options (e.g. include paths). gcc9.cc is the vanilla (unwrapped) compiler – so that’s the one which needs changing src.

EDIT: here I think you’re unlucky, as gcc is much more complex than most packages.

3 Likes

No, you can use users.users.name.packages.

You can think of this as changing the package metadata. You changed the version reported, but the source archive is still the same as before.
Are you familiar with Nix and how packages are built? If not, I recommend to look at that before fooling around with overrideAttrs. In particular, give a read to the stdenv chapter of the Nixpkgs manual.

You used .xz in one case and .gz in the other, so you downloaded two different archives. I tried

nix-prefetch-url mirror://gcc/releases/gcc-9.3.0/gcc-9.3.0.tar.xz

and got the expected one. Note that nix-prefetch-url outputs a sha256 hash in hexadecimal form, while the error specified it in the new SRI format. It’s still the same binary content, but expressed in different forms. You are supposed to put SRI hashes into the hash = "...", but if it’s sha256 it works also in sha256 = "...".

You just put your custom package into the list of packages to install globally. It may be some other package that provides the gcc binary had a higher priority, so it took over. I would put your expression in a file.nix and build it with nix-build file.nix to inspect the result more directly.

I leave the rest of the questions to someone else, but feel free to ask for clarifications if you need.

1 Like

Hmm, but does this still go in the central configuration.nix or somewhere else? Hopefully users can mess with their own package choices without needing to bug someone with root to edit configuration.nix and run nixos-rebuild switch?

Yeah, the gcc package is very special due to being the main compiler of the standard build environment. I would not expect to get any meaningful result by touching it directly.

If you need a particular version of gcc it may be easier to pick a Nixpkgs commit where gcc was in fact 9.3, fetch the corresponding Nixpkgs tarball and use the gcc9 package.

1 Like

Yes, but users can install packages without root if needed.
There’s nix-env, or nix profile for that. Also nix-shell if you need something temporarely.

1 Like

Ah, okay, but then why does it happily download and not use the source tarball? If it doesn’t normally use one, shouldn’t it be an error to have one? If it does normally use one, shouldn’t the tarball I gave not have what it needs inside?

Nix doesn’t give any semantic meaning to src, all it does is set the environment variable $src in the build environment to whatever is specified in the derivation. It is then up to the build script to decide what to do with it. In this case, it simply ignores it.

3 Likes

I’d say a standalone home-manager is probably more appropriate here, as OP seems to be more interested in declarative configuration, and not in the imperative escape hatches.

Users can manage their own home-manager profile independent of the system config, which works really well in my experience and doesn’t require root.

1 Like

It’s little known, but you can install packages declaratively even with nix-env. It’s much simpler than setting up home-manager. Here’s how:

  1. create a packages.nix file with
with import <nixpkgs> {};
[
  hello
  # packages here
]
  1. run nix-env -irf packages.nix: packages listed in the file will be installed, all packages not listed will be removed.
  2. change packages.nix, rerun the command and the changes will be applied.
3 Likes

Just a heads up, as I don’t see anyone has mentioned it, overriding gcc will cause you to have to build it yourself. If instead, you find an older revision of nixpkgs containing the version you desire and pull it from there, you will likely hit the official cache and not have to build it.

2 Likes

Yes, for some cases it’s even more important due to incompatible changes among dependencies. Caveat is usually that you’ll be using glibc with known vulnerabilities, etc. There are multiple tools which assist with finding a suitable nixpkgs commit for the version you want, e.g. Nixhub.io | Search Historical Versions of Nix Packages

1 Like

Sorry for some cases what is more important? Can’t tell which post you’re replying too and I want to know if I’m opening myself up to security issues :sweat_smile:

But also not sure what you mean about incompatible changes between deps. I’d expect if I’m going back in time to an old commit that should represent a point in time where all the packages as of that commit worked together?

In case of gcc 9.x → 9.3.0, I don’t expect an issue with dependencies even if you only change gcc itself. Maybe just something about dropping or adjusting patches applied to it.

If it was about some other package, you could get into situation that some of other packages also need adjusting to work with the different version, and that can get pretty hairy. So you could instead use older nixpkgs commit at some point where your desired version was there, but that means getting most likely also some known vulnerabilities in the closure (and all binaries in cache).

For running gcc itself you probably don’t care about security, but e.g. keeping compiled results linked against old glibc might already be some risk (in relatively extreme edge cases only, I think).

1 Like