LD Crawler

Sometimes it is useful to know what all libraries a particular executable actually requires. While the ldd command will tell you this information, the libraries may require other libraries, and ldd is not recursive. This script recursively searches through the tree of libraries and finds them all (and resolves symlinks).

#!perl
#! /usr/bin/perl
use strict;
use File::Spec;

my $show_links = 0;

my $help_message = <<END;
Usage: ldcrawler.pl [-hl] file1 [file2 ...]
  -h    print this help and exit
  -l    show which libraries are links to other libraries
END

while ($ARGV[0] =~ /^-[hl]/) {
    my $arg = shift(@ARGV);
    if ($arg eq '-h') {
    print $help_message;
        exit;
    } elsif ($arg eq '-l') {
        $show_links = 1;
    }
}

my %found_libs;

# Handle a library. This function is safe to call multiple times on the
# same library.
sub handle_file {
    my $file = shift;

    # If we've already found it, return. Otherwise, make not of it.
    if ($found_libs{$file}) {
        return;
    } else {
        $found_libs{$file} = 1;
    }

    # Print the library name. We don't print the new-line character yet
    # because it may be a link and I'd like to display that nicely.
    print $file;

    # If it's a link, work on what it points to
    if (readlink($file)) {
        my $dir = (File::Spec->splitpath($file))[1];
        my $link = File::Spec->rel2abs(readlink($file), $dir);
        if (! $found_libs{$link}) {
            if ($show_links) {
                print ' -> ';
            } else {
                print "\n";
            }
            return handle_file($link);
        }
    }

    # Print the newline character
    print "\n";

    handle_lib($file);
}

sub handle_lib {
    my $lib = shift;

    # Now we look at all of its ldd entries
    foreach my $dep (`ldd $lib`) {
        if ($dep =~ / => ((?:\S|\\\s)*) / && $1) {
            handle_file($1);
        } elsif ($dep =~ /\s((?:\S|\\\s)*) \(/ && $1) {
            handle_file($1);
        }
    }
}

foreach my $lib (@ARGV) {
    handle_lib($lib);
}