In my previous blog post NixOS as Container Host I described my approach of running containers due to the incompatibility of some binaries with NixOS 1.
After diving deeper in the world of NixOS, I stumbled over a more NixOS-ish solution for said issue.
Disclaimer: I am a NixOS novice and probably there are better solutions. Compare Binaries in the NixOS wiki.
However, this approach works for me and more importantly, it does not involve advanced stuff like packaging, derivatives, etc.
No such file or directory#
I rely on Mason to download required tools for my Neovim config. One such tool is stylua
which does not work on NixOS.
Unfortunately, this error message is not very intuitive. The file does exist and is executable.
Let’s have a look at the output of file
:
Also looking good. Well, at least for a normal Linux system. The problem is the hard coded interpreter /lib64/ld-linux-x86-64.so.2
which does not exist at this path on NixOS.
Patching the interpreter#
$NIX_CC
is not available on my system, and I was not able to successfully patch my binaries with the described commands.We need to
- Somehow tell the executable that the interpreter path is different.
- Find the interpreter path 😄.
patchelf can help us with both points. Add it to your shell with e.g. nix shell nixpkgs#patchelf
or in your configuration.nix
.
How to find the interpreter path? We can use the following command:
patchelf --print-interpreter `which find`
We can use this information to set the interpreter of our executable with the following command:
patchelf --set-interpreter $(patchelf --print-interpreter `which find`) \
$HOME/.local/share/nvim/mason/packages/stylua/stylua
There it is, it works! The error message is from stylua
itself as we did not provide any Lua file.
Patching dynamic libraries#
We can use this approach to patch dynamic libraries as well!
Another binary downloaded by Mason is marksman
that yields the same error message as before.
In addition to the interpreter, we can also see that there are some libraries missing.
In this case, we need to
- Find which packages provide those libraries.
- Find the path to those libraries in the nix store.
libz.so.1 is provided by zlib
and libstdc++.so.6 is part of the C/C++ compiler tool chain. Make sure that both are installed.
Via nix eval nixpkgs#zlib.outPath --raw
we can find the current path of the zlib package and therefore its library.
Now we can use this information to patch the binaries rpath:
patchelf --set-rpath "$(nix eval nixpkgs#zlib.outPath --raw)/lib:$(nix eval nixpkgs#stdenv.cc.cc.lib.outPath --raw)/lib" \
$HOME/.local/share/nvim/mason/bin/marksman
By patching the rpath, marksman is now aware of the missing libraries and works on NixOS after patching the interpreter as well as shown in Patching the interpreter.
Limitations#
Obviously, this is a rather labor-intensive work that could be automated. In addition, each time, an affected binary is updated, it needs to be patched again.
However, in my current setup, only three binaries are affected, and I will stick to this workaround for now.