Nix doesn't infer all the binary dependencies

I’m trying to package a binary executable using nix. This is the derivation I’m using:

let
  pkgs = import <nixpkgs> {};
in
  with pkgs;
builtins.derivation {
  name = "service";
  builder = "${bash}/bin/bash";
  args = [./package.sh];
  bin = ./program;
  binutils = binutils-unwrapped;
  system = builtins.currentSystem;
}

package.sh:

${binutils}/bin/strip $bin -o $out

When I build this derivation, nix adds only glibc to the dependency list of the output, even though it requires openssl to run as well:

$ nix-build default.nix
/nix/store/p5f2fdsn056bavx6ykkvpgb3q5792pv8-service
$ nix-store --query --references /nix/store/p5f2fdsn056bavx6ykkvpgb3q5792pv8-service | cat
/nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74
$ ldd /nix/store/p5f2fdsn056bavx6ykkvpgb3q5792pv8-service
        linux-vdso.so.1 (0x00007fff35df8000)
        libssl.so.1.1 => /nix/store/g9r6l6mymsknrg0mc394iiggih16jkzm-openssl-1.1.1i/lib/libssl.so.1.1 (0x00007fecdb2ca000)
        libcrypto.so.1.1 => /nix/store/g9r6l6mymsknrg0mc394iiggih16jkzm-openssl-1.1.1i/lib/libcrypto.so.1.1 (0x00007fecdafdc000)
        libgcc_s.so.1 => /nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libgcc_s.so.1 (0x00007fecdafc2000)
        libpthread.so.0 => /nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libpthread.so.0 (0x00007fecdafa1000)
        libm.so.6 => /nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libm.so.6 (0x00007fecdae60000)
        libdl.so.2 => /nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libdl.so.2 (0x00007fecdae59000)
        libc.so.6 => /nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libc.so.6 (0x00007fecdac9a000)
        /nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/ld-linux-x86-64.so.2 => /nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib64/ld-linux-x86-64.so.2 (0x00007fecdb80d000)
$

The executable contains a reference to the openssl package in its rpath:

$ objdump -p /nix/store/p5f2fdsn056bavx6ykkvpgb3q5792pv8-service | rg 'RPATH|RUNPATH'
  RUNPATH              /nix/store/1208c1hw7z2qg1jyqmh545096l5g931q-nix-shell/lib64:/nix/store/1208c1hw7z2qg1jyqmh545096l5g931q-nix-shell/lib:/nix/store/g9r6l6mymsknrg0mc394iiggih16jkzm-openssl-1.1.1i/lib:/nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib:/nix/store/g490crrmig6ffbjk5qxd5siavypng6ld-gcc-9.3.0-lib/lib

How do I fix this problem?

Maybe you have seen this page already, but in case not: Packaging/Binaries - NixOS Wiki

I think it’s simply that you have to specify dependencies “by hand”? I.e., you need to include openssl in your derivation somehow I think. But I’m not really sure either, might be completely wrong!

Thanks, I got a derivation working with the help of this link:

let
  pkgs = import <nixpkgs> {};
in
  with pkgs;
stdenv.mkDerivation {
  name = "service";
  src = ../target/release/service;
  buildInputs = [ openssl ];
  phases = [ "installPhase" ];
  installPhase = ''
    ${binutils-unwrapped}/bin/strip $src -o $out
  '';
}

I’d read somewhere that nix can automatically infer dependencies by scanning output files for nix store paths. I guess that feature is unrelated to what I’m trying to do.

Awesome, congratulation! :slight_smile: Not 100% sure either, but it reminds me of this project: GitHub - Lassulus/nix-autobahn. Maybe something interesting there.

Nix only infers dependencies if it’s part of the inputs of a derivation or otherwise a transitive dependency. This means it needs to be passed as part of an argument to derivation somehow (you’re using the low-level derivation). stdenv.mkDerivation passes the inputs in for you.

It would be a pain to have to search for all of the paths when scanning for dependencies. And wiith sandboxing, your build process isn’t even supposed to see the extra paths anyway. If you already have sandboxing on then that’s kinda unexpected…