Help understanding linking in NixOS

TLDR: Executable file fails to run. ldd says “Missing Library”. Add Library path to LD_LIBRARY_PATH. ldd says “Library found”. Executable still fails to run.


I’m facing a problem in NixOS that’s baffling me (not that I’m too smart :)). I’m unable to run an executable. The executable is aapt2 which is part of an android SDK downloaded by android-studio. aapt2 is a standard part of the android/gradle build chain but it fails to run on my machine. I do a file on the aapt2 binary and it’s an ELF 64 executable so that’s fine, but then ldd reveals a missing libz. I find the current version of libz and add it to LD_LIBRARY_PATH. The interpreter can now see libz but it still fails to run the executable.

Here’s a session if that helps find problems-.

$cd /home/zx/Android/Sdk/build-tools/27.0.3/ 

# Try to run aapt2                                                                                                         
zsh: no such file or directory: ./aapt2

# File command says it's 64 bit. Check if dependencies met. 
$ldd ./aapt2                                                                                                                                       (0x00007ffe367b9000) => /home/zx/Android/Sdk/build-tools/27.0.3/./lib64/ (0x00007f504f2d5000) => not found => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib/ (0x00007f504f2b4000) => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib/ (0x00007f504f11e000) => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib/ (0x00007f504ef08000) => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib/ (0x00007f504ed52000)
	/lib64/ => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib64/ (0x00007f504f60c000) => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib/ (0x00007f504ed46000) => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib/ (0x00007f504ed41000)

# Check what kind of file the missing dependency is. 
$ZLIB_PATH=$(dirname $(readlink -e /run/current-system/sw/lib/                                                                            
$file $ZLIB_PATH/                                                                                                                           
/nix/store/f8zs7mknva4rdx7zxr6j54y0igh3pras-zlib-1.2.11/lib/ ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped

# Add missing dependency to LD_LIBRARY_PATH
$export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ZLIB_PATH                                  

# see if the missing dependency is recognized                                                                      
$ldd ./aapt2                                                                                                                                       (0x00007ffd2152d000) => /home/zx/Android/Sdk/build-tools/27.0.3/./lib64/ (0x00007fc5ef21e000) => /nix/store/f8zs7mknva4rdx7zxr6j54y0igh3pras-zlib-1.2.11/lib/ (0x00007fc5ef1ff000) => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib/ (0x00007fc5ef1de000) => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib/ (0x00007fc5ef048000) => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib/ (0x00007fc5eee32000) => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib/ (0x00007fc5eec7c000)
	/lib64/ => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib64/ (0x00007fc5ef555000) => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib/ (0x00007fc5eec70000) => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib/ (0x00007fc5eec6b000)

# try to run again. 
zsh: no such file or directory: ./aapt2

Could somebody give me pointers on how to go about solving my problem? I have what most here would call an intermediate level of understanding of how linking/loading et al work.

Bumping, I hope it’s not considered bad manners here.

You need to change the interpreter. Run patchelf --print-interpreter ./aapt2 and I believe it will point to something like /lib64/ which does not exists in NixOS (that’s my you see no such file or directory from shell).

You could run patchelf --set-interpreter $(nix-build "<nixpkgs>" -A glibc --add-root ~/.cache/gcroots/glibc --indirect --no-out-link)/lib/ ./aapt2 to set an available interpreter. ( the --add-root ... --indirect option add a gcroot to prevent the glibc from being garbage-collected)

Will try when on a computer but isn’t that the 3rd last line in the ldd output? I gathered ldd printed the interpret we too is found in LD_LIBRARY_PATH or rpath, so that’s printed by ldd, but the interpreter is set in another section.

(I’m not an expert, correct me if I’m wrong about the ELF format)

I was talking about the third last line:

 /lib64/ => /nix/store/kksyrix1bpklvgkmvngcv0q9nh8hn2fl-glibc-2.27/lib64/ (0x00007f504f60c000)

This is what threw me off.

You were current in your diagnosis and prescription though. Thank you!

EDIT: I wonder what would it take for the environment to not require me to set LD_LIBRARY_PATH to include zlib- I’d love for zlib to be found automatically. Even after setting the right interpreter it fails to find it.

Ah, then I don’t have a very good explanation now, I still have so much to learn :stuck_out_tongue:

Any way, you could append rpath in the ELF file so the dynamic linker will find libraries under these paths. You could use patchelf --set-rpath "$(patchelf --print-rpath ./aapt2):$(dirname $(readlink -e /run/current-system/sw/lib/" ./aapt2

1 Like

I have written two blog posts that elaborately explain the concepts of patching binaries so that they can be used in NixOS:

Android, in particular, is quite a challenge to make work properly in NixOS, for a variety of reasons.