Use elfutils instead of ldd to dissect ELF DT_NEEDED
g-i currently uses ldd
to read the dependencies (DT_NEEDED
) of ELF binaries and output them for parsing.
This is recursive, which is not actually what we want: ideally we only want to look at direct (first-level) dependencies. It's also likely to be awkward when cross-compiling, even given access to an appropriate user-space emulator like qemu-user
, because glibc's ldd
script contains architecture-specific logic to find the architecture's appropriate runtime dynamic linker (ELF interpreter); and the output is not designed to be machine-readable, and needs some screen-scraping.
On ELF platforms, it's relatively easy to reimplement this in a way that does not require executing code: the structure of ELF headers is well-defined, and can be parsed by architecture-independent tools. I attach an implementation of this, which outputs one DT_NEEDED header per line. It needs compiling and linking with elfutils' libelf, but otherwise does not have any dependencies (in particular, no GLib, so it doesn't introduce any new dependency cycles). For example, on Debian:
$ sudo apt install libelf-dev
$ gcc -oelf-get-needed elf-get-needed.c -lelf
$ ./elf-get-needed /usr/lib/x86_64-linux-gnu/libgirepository-1.0.so.1 # build architecture
libglib-2.0.so.0
libgobject-2.0.so.0
libgmodule-2.0.so.0
libgio-2.0.so.0
libffi.so.8
libm.so.6
libc.so.6
$ ./elf-get-needed /usr/lib/aarch64-linux-gnu/libgirepository-1.0.so.1 # a foreign architecture
libglib-2.0.so.0
libgobject-2.0.so.0
libgmodule-2.0.so.0
libgio-2.0.so.0
libffi.so.8
libm.so.6
libc.so.6
ld-linux-aarch64.so.1
I haven't glued this into the upstream gobject-introspection build system yet, but it seems like this might be more suitable than ldd
, even when not cross-compiling? It could be installed into the giscannerdir
as a simple private-use executable, and would avoid having to screen-scrape ldd's libfoo.so.0 => /usr/lib/foobar/libfoo.so.0
output format, or parse and ignore indirect dependencies.
After replacing ldd
, the only part of g-ir-scanner
that needs to execute host-architecture code is the dumper, which is unavoidable because of the way the GObject type system works, but can be wrapped via something like --use-binary-wrapper=qemu-aarch64
already. At the moment I'm experimenting with teaching Debian's gobject-introspection to be able to cross-compile, via a wrapper script that adds --use-ldd-wrapper=/path/to/elf-get-needed
among other arguments.