5

First I am not really comfortable with ELF and all this library linking process. But after having played a bit with Nix/NixOS, there is something I still don't really understand with the way graphic drivers are linked into binaries.

One of the designs of Nix/NixOS is that the OpenGL driver cannot be part of the reproducible environment because it will depend on the target hardware.

Most Nix programs find OpenGL drivers into "/run/opengl-driver/lib".

In the case of a NixOS system, drivers are downloaded and installed at this path and then the LD_LIBRARY_PATH can be defined globally in the configuration using hardware.opengl.setLdLibraryPath = true (see https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/hardware/opengl.nix#L166).

However, in the case of a non-NixOS operating system, I can notice that programs still reference this /run/opengl-driver/lib path while LD_LIBRARY_PATH is not defined anywhere. And so my question is: why does a binary still search drivers into /run/opengl-driver/lib on a non-NixOS system?

My example here is compton. Its derivation in Nixpkgs is at the following address.

https://github.com/NixOS/nixpkgs/blob/274e095f761b2da76a376d105c41591739350b14/pkgs/applications/window-managers/compton/default.nix#L51

I can see using strace that the program tries to load the libGLX_mesa.so library at runtime.

$ strace -e openat $(readlink -f $(which compton)) 2>&1 | grep -E ".*opengl.*.so"

openat(AT_FDCWD, "/run/opengl-driver/lib/tls/haswell/x86_64/libGLX_mesa.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/run/opengl-driver/lib/tls/haswell/libGLX_mesa.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/run/opengl-driver/lib/tls/x86_64/libGLX_mesa.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/run/opengl-driver/lib/tls/libGLX_mesa.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/run/opengl-driver/lib/haswell/x86_64/libGLX_mesa.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/run/opengl-driver/lib/haswell/libGLX_mesa.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/run/opengl-driver/lib/x86_64/libGLX_mesa.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/run/opengl-driver/lib/libGLX_mesa.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

Indeed, using ldd reveals that libGLX_mesa.so is not dynamically linked.

$ ldd $(readlink -f $(which compton)) | grep mesa | wc -l
0

So my guess is that this library is loaded at runtime maybe using dlopen. I cannot find any reference of dlopen in https://github.com/chjj/compton but maybe it is done indirectly from one of the libs linked by compton.

If my guess is true, I have found that dlopen was able to find the desired library searching into paths defined in the LD_LIBRARY_PATH environment variable (when the path is a leaf name).

So my next move was to analyse the environment variables available to compton at runtime using one of the two commands below.

$ strace -v -s 10000 -e execve $(readlink -f $(which compton)) 2>&1 | grep LD_LIBRARY_PATH | wc -l
0

$ ltrace -e getenv $(readlink -f $(which compton)) 2>&1 | grep LD_LIBRARY_PATH | wc -l
0

But this LD_LIBRARY_PATH does not seem to be defined. And I am kind of stuck in my analysis here.

So to recap, my questions are:

  • How is this opengl path /run/opengl-driver/lib injected into compton?
  • What would be the standard way of adding this library path to programs requiring graphic drivers in Nix?
  • And last question not really related to this analysis but: if wanting to make compton work on a non-NixOS system, would it be enough to manually link opengl libraries from /usr/lib/x86_64-linux-gnu/ to /run/opengl-drivers/lib/?
genpfault
  • 51,148
  • 11
  • 85
  • 139
Loric
  • 1,678
  • 8
  • 28
  • 48

0 Answers0