I’ve recently ran a nix-collect-garbage -d
which freed a LOT of space, I was surprised.
But I noticed after that, in particular for some go binaries, that they were not running anymore.
For example,
./gopls
zsh: no such file or directory: ./gopls
Although the file exists, inspecting the file lead to:
objdump -s -j .interp gopls ✘ 127
gopls: file format elf64-x86-64
Contents of section .interp:
400fad 2f6e6978 2f73746f 72652f64 62637731 /nix/store/dbcw1
400fbd 39647368 64776e78 64763571 32673677 9dshdwnxdv5q2g6w
400fcd 6c646a36 73797976 71376c2d 676c6962 ldj6syyvq7l-glib
400fdd 632d322e 33392d35 322f6c69 622f6c64 c-2.39-52/lib/ld
400fed 2d6c696e 75782d78 38362d36 342e736f -linux-x86-64.so
400ffd 2e3200 .2.
But that path on the on the right column does not exist!
I’ve tried to delete and install it again (go install golang.org/x/tools/gopls@latest
) and I endup with the same problem.
Any idea on how to fix this?
Where are those go binaries stored?
They are under $HOME/go/bin, the default path for Go.
But it looks like they are liked against something that doesn’t exist anymore - even when fresh installed
I think your observation is correct. With Nix, the typical means of ending up with executables available to a user is home-manager. For one, it prevents garbage collection of the dependency tree of the home.
Yeah, I think this problem/bug is a bit more weird than I initially thought.
It seems that everything that my current go
installation generates (installed wihtin home-manager), is linked to that ghost library path.
If I install another go package using nix (home-manager or not) it will work - I guess it uses a different go binary to build it then.
So it seems that garbage collecting can break the Go in a very subtle way, where the compiled binaries become unusable because of the removed library.
As a mitigation I wonder if there’s a way to “Reinstall” go from scratch. Maybe if I remove it from the config, garbage-collect, and add again?
https://nix.dev/manual/nix/2.18/package-management/garbage-collector-roots
If you’re building stuff for dev, either use devshells (with nix-direnv, which creates gc roots automatically), or create the gc roots manually as linked above.
PS forget about the idea of “reinstalling” when it comes to nix, the idea makes zero sense unless the package is wildly irreproducible and you’re rebuilding it locally. In any case, whatever you are thinking of reinstalling, will not have its state wiped; state is not part of the nix store, so nix won’t know/care about it.
This makes some sense to me
Does it mean that when you install go
for example, that binary is only “usable” (able to create actual executables) by chance of not getting the glibc garbage collected by the user?
I guess my surprise came because I’ve been using nix for more than one year now, and just faced this now (not the first time I garbage collect things).
PS forget about the idea of “reinstalling” when it comes to nix, the idea makes zero sense unless the package is wildly irreproducible and you’re rebuilding it locally. In any case, whatever you are thinking of reinstalling, will not have its state wiped; state is not part of the nix store, so nix won’t know/care about it.
I get this, but does this also means that everyone with go1.22.3 linux/amd64
has it linked to the same store path?
How would you go about restoring that glibc path in this case?
Thanks for the links, I’m going to do some digging!
Assuming all the inputs (nixpkgs revision, package args, derivation attributes, …) are the same, then yes.
If you have overrides, overlays, etc. then the path changes.