Where to call patchelf in a derivation?

Hello all

I’m trying to manually add an extra path to the rpath of a pre-existing binary I have. I would have expected that adding this to the derivation might work:

postFixup = 
  ''
      patchelf \
        --add-rpath "${openssl_1_0_2}/lib" \
        $out/bin/my_executable
  '';

(both patchelf and openssl_1_0_2 are in scope)

This builds fine, but the openssl_1_0_2 path does not end up in the rpath of my_executable. The instructions here: Packaging/Binaries - NixOS Wiki suggest that preFixup would be the right place to put this, but I can’t see why (I’d have thought that Nix would deem the openssl_1_0_2 path superfluous and remove it in the fixupPhase). It also doesn’t work using preFixup either (nor in the patchPhase, or wherever else I’ve put it).

Has anyone been able to make something similar work?

Thanks!

1 Like

I haven’t exactly got to the bottom of this, but I think that autoPatchelfHook is replacing the whole of the fixupPhase, and so my postFixup hook is never being called. I’ve got things working in a slightly different way, which I overall prefer, by adding

patchelf --add-needed libssl.so.10 $out/bin/my_executable

to the end of the installPhase. By way of explanation:

  • openssl.so.10 is the dynamic dependency that was missing when I tried to run my_executable, and which is being provided by the openssl_1_0_2 package that I tried to manually add to the rpath.
  • patchelf --add-needed just adds a dynamic dependency to the binary
  • autoPatchelfHook then realizes that this dynamic dependency is needed, and that it can be satisfied by the openssl_1_0_2 in the buildInputs. So it adds openssl_1_0_2 to the rpath.

Have you tried preCheck? It’s directly after postBuild (at least if doCheck is true).

if I add this to my derivation:

doCheck = true;
preCheck = ''
  patchelf --add-rpath ${openssl_1_0_2}/lib $out/bin/my_executable
'';

then the build errors with:

patchelf: getting info about '/nix/store/66...-my_executable/bin/my_executable': No such file or directory

Because the checkPhase happens before the installPhase, and this derivation is modifying a pre-existing binary (which is copied in in the installPhase), not building one.

If you’re not using too many of the other phases you may be able to get around this by just calling builtins.derivation directly instead of using mkDerivation. You’ll have full control over patching at least.