59 comments

[ 2.5 ms ] story [ 117 ms ] thread
Now I'm wondering why ldd doesn't offer this feature in the first place.
Trees are quite hard to do well in a CLI app. Everything from the Unicode drawing to the sizing to the color choices. This one looks great.
Unicode isn't necessary if the terminal supports ACS.
What is ACS?
Most terminals (even non-unicode-capable ones) offer a feature to switch into "alt charset mode" which provides glyphs for drawing lines.
Thanks! It’s getting rare to learn about a feature that surprises me, but I had no idea about this.
You can do a passable job with just + - and | if you need to. Have done that for a ucontroller's cli.
It's not like ldd is a paragon of cli design to begin with. Indentation isn't difficult, you just pass in the indentation level and increment as needed as you recursively walk the tree.
just saying: pstree figured it out
The output format isn't nice, but LD_DEBUG=files will tell you which file requested each library.

(The LD_DEBUG environment option is a useful tool in the rare circumstances when you really, really need help debugging the library loading process.)

Because it's a core Linux tool and they basically never change. Why doesn't ps have an option to only show your processes? Why doesn't objdump tell you what all the symbol flags mean so I don't have to look them up on StackOverflow every time?

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.

I agree that the interface of ps is awful with its two conflicting ways to define options, but `ps u` does show all your processes on Linux. I usually type `ps fux` to get a nice tree. Sadly that's Linux-specific and doesn't work on the Mac.
`ps u` just changes the output format. It's not the same as `ps -u $(whoami)`
You are right! I misremembered. It's `ps x`.

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.
> Why doesn't ps have an option to only show your processes?

Because that is the default behavior.

No, by default it shows you processes for the current terminal.
Only your processes for this terminal.
Yes. I meant "show me all my processes". A very common task that doesn't have a good solution.
Sure it does: “ps x” does that.
https://github.com/gentoo/pax-utils/blob/master/lddtree.py already does this. Cool to see though, very useful
Seems like it uses ELF parsing, I wonder if it works on non-native binaries (lddtree does not)
lddtree is much faster, but libtree has more detailed info.
If you want something fast, note that (https://github.com/haampie/libtree-in-c) is currently faster than ldd:

    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'
The C rewrite was released in libtree 3.0.0
Or even more basic:

  $ 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.
That's not the same. ldd actually finds the libraries and their dependencies.
Of course. I'm just pointing out how the source data is encoded in the ELF file. As I said in the comment there is much value in the tools that take this data and the locations of the libraries and build up a nice tree.
It's not though, an ELF file only lists its immediate dependencies. To find the complete tree you actually need to find the dependencies and parse those, which is exactly what this does.
(comment deleted)
What? new CLI utilities are not in rust?

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.

Where are you seeing rust? Or is this just tongue in cheek?
Please don't do this. There is nothing that says CLI utilities (or any other programs for that matter) HAVE to be written in Rust.

This type of comment puts me off Rust, slowly but surely.

I took the comment as a jest.
It is just a harmless joke, sorry if it offends anyone.

I use a lot of rust CLI tools myself and love them. Meanwhile I also do c++ coding. they complement each other well.

If some bad apples in a community (every community has them) can make you give up on a technology then you never actually considered it in the first place.
I doubt that the grandparent is a Rust developer.
It is a huge assumption to think the parent comment was from anyone in the Rust community. It could be a Rust hater.
(comment deleted)
On Solaris, you can get the tree with:

    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.
This is fine. It's a great beginner project -- C++ is probably painful even statically compiled, and Go/Rust would be better.

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)

> C++ is probably painful even statically compiled, and Go/Rust would be better

What does that even mean?

That code does not work, it won't even compile with `-Mstrict`.
Got me to learn that vim requires libcanberra requires libvorbisfile ... libogg

    ./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)

I like your other implementation more, libtree-in-c. Actually, I think it is better to exchange the names and let's libtree be in C and the other one be called libtree-in-cpp or libtree-in-c++.
Yes, I agree, this is the plan :)
On Linux with glibc, ldd -v will give you similar information, though less pretty of course.
Beware that ldd needs to run the binary to check for dependencies. It can be a security risk to use it without a sandbox.
Huh, any reference about this? How much of the binary does it run?
SUPER GREAT for bundling software into a folder.

Great for demo and standalone prototyping.