Libtree: Turns ldd into a tree; explains why shared libraries are found or not
github.com
github.com
./libtree_x86_64 $(which vim)
vim
├── libtinfo.so.6 [ld.so.conf]
├── libselinux.so.1 [ld.so.conf]
│ └── libpcre2-8.so.0 [ld.so.conf]
├── libcanberra.so.0 [ld.so.conf]
│ ├── libvorbisfile.so.3 [ld.so.conf]
│ │ ├── libvorbis.so.0 [ld.so.conf]
│ │ │ └── libogg.so.0 [ld.so.conf]
│ │ └── libogg.so.0 (collapsed) [ld.so.conf]
│ ├── libtdb.so.1 [ld.so.conf]
│ └── libltdl.so.7 [ld.so.conf]
├── libacl.so.1 [ld.so.conf]
├── libgpm.so.2 [ld.so.conf]
└── libpython3.8.so.1.0 [ld.so.conf]
surprising(and super neat tool, even though people mentionned ldd could do part of it)
libtree-in-c $ make CC=musl-gcc CFLAGS="-Os -s -static"
musl-gcc -Os -s -static -c libtree.c
musl-gcc -Os -s -static -o libtree libtree.o
libtree-in-c $ hyperfine 'ldd libLLVM.so' './libtree ./libLLVM.so'
Benchmark #1: ldd libLLVM.so
Time (mean ± σ): 6.1 ms ± 0.3 ms [User: 5.2 ms, System: 1.2 ms]
Range (min … max): 5.3 ms … 8.1 ms 348 runs
Benchmark #2: ./libtree ./libLLVM.so
Time (mean ± σ): 2.4 ms ± 0.4 ms [User: 1.2 ms, System: 1.2 ms]
Range (min … max): 1.7 ms … 3.4 ms 840 runs
Warning: Command took less than 5 ms to complete. Results might be inaccurate.
Summary
'./libtree ./libLLVM.so' ran
2.54 ± 0.43 times faster than 'ldd libLLVM.so' $ eu-readelf -d /bin/ls | grep NEEDED
NEEDED Shared library: [libselinux.so.1]
NEEDED Shared library: [libcap.so.2]
NEEDED Shared library: [libc.so.6]
Of course the trick is doing it recursively and having nice output. ldd -s <binary_name>
It gives you the dependency tree, tells you the search paths it used for each dependency in the tree (LD_LIBRARY_PATH, the RUNPATH for the specific binary, and ld.config file), and the reason it rejected any files it did find, e.g. missing symbol version.(The LD_DEBUG environment option is a useful tool in the rare circumstances when you really, really need help debugging the library loading process.)
I'm sure there are better examples but there are a ton of ways the usability of the Linux CLI could be improved but nobody is going to bother because everything's written in horrible C and to contribute you'd have to join some mailing list and convince a load of stuck-in-the-mud it-was-hard-for-me-so-I'm-not-making-it-easy-for-you neckbeards that your change won't break compatibility on a PDP-11, and anyway what's the problem? You just run `ps -fu $(whoami) | less`. Easy.
Way easier and more fun to write a new tool.
From `man ps`:
x Lift the BSD-style "must have a tty" restriction, which is imposed upon the set of all processes when some BSD-style (without "-") options are used or when the
ps personality setting is BSD-like. The set of processes selected in this manner is in addition to the set of processes selected by other means. An alternate
description is that this option causes ps to list all processes owned by you (same EUID as ps), or to list all processes when used together with the a option.Because that is the default behavior.
https://github.com/jveitchmichaelis/deeplabel/blob/master/fi...
Great for demo and standalone prototyping.
And yes it's very useful, can do more than pax-util's lddtree(libtree can help packaging your binary with all its libraries in one package), just installed and looks great.
This type of comment puts me off Rust, slowly but surely.
I use a lot of rust CLI tools myself and love them. Meanwhile I also do c++ coding. they complement each other well.
But you may as well make it a little smarter. Over a decade ago, this utility could be done ad-hoc in 100 lines of Perl (including spacing and comments), and that includes "try to see if yum on RHEL6 knows where to find the missing dep, build a list, and prompt to install": https://gist.github.com/evol262/3d67c4295bbe78135a4927bd1d82...
It would be a fun project for you to try to do this with dpkg/pacman/dnf (which is basically the same as yum for syntax, just that you're not gonna be a sysadmin hacking out Perl to solve a problem)
What does that even mean?