I haven't tested the following code, since I've just attempted to re-write this from memory, but the one I wrote to solve this earlier (it looks roughly like this one) works fine:
#!/usr/bin/env perl
using IPC::Open3;
my $queryFile = $ARGV[0];
shift;
my %missingSymbols = getSymbols( "nm -Aau", $queryFile );
my %symtbl;
foreach $lib ( @ARGV ) {
my %temp = getSymbols( "nm -Aa --defined-only", $lib );
foreach $key ( keys( %temp ) ) {
$symtbl{$key} = (defined($symtbl{$key}) ? "${symtbl{$key}} " : "")
. $temp{$key};
}
}
my %dependencies;
foreach $symbol ( keys( %missingSymbols ) ) {
if( defined( $symtbl{$symbol} ) ) {
foreach $lib ( split( / +/, $symtbl{$symbol} ) ) {
if( !defined( $dependencies{$lib} ) ) {
$dependencies{$lib} = 1;
}
}
}
}
if( scalar( keys( %dependencies ) ) > 0 ) {
print( "$queryFile depends on one or more of the following libs:\n\n" );
print join( "\n", sort( keys( %dependencies ) ) ) . "\n\n";
} else {
print( "Unable to resolve dependencies for $queryFile.\n\n" );
}
# Done.
sub getSymbols {
my $cmd = shift;
my $fname = shift;
checkFileType( $fname );
open3( IN, OUT, ERR, "$cmd $fname" );
my %symhash;
close( IN );
# If you leave ERR open and nm prints to STDERR, reads from
# OUT can block. You could make reads from both handles be
# non-blocking so you could examine STDERR if needed, but I
# don't need to.
close( ERR );
while( <OUT> ) {
chomp;
if( m/^(?:[^:]*:)+[a-zA-Z0-9]*\s*[a-zA-Z] ([^\s]+)$/ ) {
my $temp = defined( $symhash{$1} ) ? "${symhash{$1}} " : "";
$symhash{$1} = $temp . $fname;
}
}
close( OUT );
return %symhash;
}
sub checkFileType {
my $fname = shift;
die "$fname does not exist\n" if( ! -e $fname );
die "Not an ELF or archive file\n" if( `file $fname` !~ m/ELF| ar archive/ );
}