When we are in a `nix develop` shell, how does it make the libraries available to the binaries?

When we are in a nix develop shell, how does it make the libraries available to the binaries?

I thought it set LD_LIBRARY_PATH env var, but echo $LD_LIBRARY_PATH gives /nix/store/qrrxach47c1bhxh97nibb9lyd2fg9j18-pipewire-0.3.48-jack/lib, which is not what I put in devShell = mkShell { buildInputs = [ <<here>> ]; };

  1. What did you put there instead?
  2. Prefer printenv over echo when you want to inspect the environment

Here’s my flake.nix:

{
  description = "Test";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs";
  };

  outputs = { self, nixpkgs }:
  let
    pkgs = nixpkgs.legacyPackages.x86_64-linux;
  in {
    devShell.x86_64-linux =
      pkgs.mkShell {
        buildInputs = with pkgs; [
          zlib        
        ];
      };
  };
}

LD_LIBRARY_PATH:

❯ printenv LD_LIBRARY_PATH
/nix/store/qrrxach47c1bhxh97nibb9lyd2fg9j18-pipewire-0.3.48-jack/lib

I tried grepping for zlib in all env vars:

❯ printenv | grep zlib
NIX_CFLAGS_COMPILE= -frandom-seed=q79x939si6 -isystem /nix/store/yfckbbm9qf5ql7ghvygqmw4d6idib76f-zlib-1.2.11-dev/include -isystem /nix/store/yfckbbm9qf5ql7ghvygqmw4d6idib76f-zlib-1.2.11-dev/include
NIX_LDFLAGS=-rpath /home/farseen/Projects/01.Personal/B2BApp/B2BApp6/backend/outputs/out/lib64 -rpath /home/farseen/Projects/01.Personal/B2BApp/B2BApp6/backend/outputs/out/lib  -L/nix/store/9b9ryxskcwh573jwjz6m5l01whkcb39a-zlib-1.2.11/lib -L/nix/store/9b9ryxskcwh573jwjz6m5l01whkcb39a-zlib-1.2.11/lib
buildInputs=/nix/store/yfckbbm9qf5ql7ghvygqmw4d6idib76f-zlib-1.2.11-dev

So Nix only modifies libraries compile time?

If I compile a binary depending on zlib while inside nix develop and then exit nix develop, will the compiled library run fine?

LD_LIBRARY_PATH is a workaround for making foreign binaries run in a nix environment. When building a standard C application, LD_LIBRARY_PATH should not get modified.

When you compile a program using zlib, the Makefile (or autoconf, or meson, or cmake, or whatever) will use pkg-config to find zlib. nix build will set the environment variable PKG_CONFIG_PATH to directories containing pkg-config configuration files. That’s how zlib will be found.

Finally, at link time, the absolute path to the zlib .so file will be embedded in the linked binary so it gets found at run time.

If I compile a binary depending on zlib while inside nix develop and then exit nix develop , will the compiled library run fine?

So, yes.

packages like cmake or pkg-config, have shellHooks which will run and expose dependencies through environment variables:

$ nix-shell -p pkg-config openssl

[nix-shell:/home/jon/projects/nixpkgs]$ echo $PKG_CONFIG_PATH_FOR_TARGET
/nix/store/8l8cfgxafnl8hb1z6w2z64pg15w7qg0k-openssl-1.1.1n-dev/lib/pkgconfig

[nix-shell:/home/jon/projects/nixpkgs]$ pkg-config --libs openssl
-L/nix/store/v8vpzh3slc5hm4d9id5bim4dsb4d2ndh-openssl-1.1.1n/lib -lssl -lcrypto

The wrapped compilers (exposed through stdenv) also have shell hooks which export the related NIX related flags for the C toolchains:

$ echo $NIX_CFLAGS_COMPILE
-frandom-seed=1gns8agcfq -isystem /nix/store/8l8cfgxafnl8hb1z6w2z64pg15w7qg0k-openssl-1.1.1n-dev/include -isystem /nix/store/8l8cfgxafnl8hb1z6w2z64pg15w7qg0k-openssl-1.1.1n-dev/include

$ echo $NIX_LDFLAGS
-rpath /nix/store/1gns8agcfq32arkyvyl5401vvgjbjb0d-shell/lib64 -rpath /nix/store/1gns8agcfq32arkyvyl5401vvgjbjb0d-shell/lib -L/nix/store/v8vpzh3slc5hm4d9id5bim4dsb4d2ndh-openssl-1.1.1n/lib -L/nix/store/v8vpzh3slc5hm4d9id5bim4dsb4d2ndh-openssl-1.1.1n/lib
1 Like

I see. So in other distros, the binaries don’t embed the absolute path to the .so files?

Yep. NixOS:

$ readelf -d $(which ls) | grep RUNPATH
 0x000000000000001d (RUNPATH)            Library runpath: [/nix/store/5h6q8cmqjd8iqpd99566hrg2a56pwdkc-acl-2.3.1/lib:/nix/store/n239ln3v669s5fkir2fd8niqawyg6qrv-attr-2.5.1/lib:/nix/store/7i4skv2h1q8f8h37n8b8yajfdp3w07yx-openssl-1.1.1n/lib:/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib]

Debian:

$ readelf -d /usr/bin/ls | grep RUNPATH
(nothing)

On other distros the dynamic linker is configured to look in specific paths, e.g. /usr/lib.

1 Like