diff options
Diffstat (limited to 'tools/apbuild/scandeps')
-rwxr-xr-x | tools/apbuild/scandeps | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/tools/apbuild/scandeps b/tools/apbuild/scandeps new file mode 100755 index 00000000..7d057129 --- /dev/null +++ b/tools/apbuild/scandeps @@ -0,0 +1,137 @@ +#!/usr/bin/env perl +use strict; +use IPC::Open2; + +if ($ARGV[0] eq '--version') { + print "scandeps version 1.0\n"; + print "Copright (c) 2005 Hongli Lai\n"; + print "Licensed under the GNU General Public License v2.\n"; + exit; +} elsif ($ARGV[0] eq '--help') { + print "Usage: scandeps [FILES...]\n"; + print "This script scans ELF binaries' library dependancies and prints a nice report\n" . + "of the dependancies.\n"; + exit; +} + + +# First, generate a list of binaries. Either scan user-specified files, +# or scan all files in the current directory (including subfolders). +my @files; + +if (@ARGV > 0) { + # Scan user-specified files + @files = @ARGV; +} else { + # Scan directory recursively + @files = scandir("."); +} + +# Now get the dependancies for all binaries +# %fileDeps: hash which contains a list of dependancies. The filename is the key. +# %depFiles: hash which contains a list of files. The dependancy is the key. +my (%fileDeps, %depFiles); +getdeps(\%fileDeps, \%depFiles, \@files); + +print "Common dependancies:\n"; +foreach my $dep (keys %depFiles) { + if (@{$depFiles{$dep}} == @files) { + print " $dep\n"; + } +} +print "\n"; + +print "All dependancies:\n"; +my @keys = keys %depFiles; +@keys = sort { @{$depFiles{$b}} - @{$depFiles{$a}} } @keys; +foreach my $dep (@keys) { + my $num = scalar(@{$depFiles{$dep}}); + my $word = ($num > 1) ? "files" : "file"; + printf " %-40s (used by %3d $word)\n", $dep, $num; +} + +print "\n"; +print "Dependancies and associated binaries:\n"; +foreach my $dep (@keys) { + print " $dep:\n"; + if (@{$depFiles{$dep}} == @files) { + print " All files depend on this library.\n"; + } else { + foreach my $file (@{$depFiles{$dep}}) { + print " $file\n"; + } + } + print "\n"; +} + + +################################## + +sub fatal { + print STDERR $_[0]; + exit 1; +} + +sub isELF { + my ($f, $data); + + if (!open($f, $_[0])) { + print STDERR "Warning: cannot open file '$_[0]' for reading.\n"; + return 0; + } + + binmode $f; + sysread $f, $data, 4; + close $f; + return $data eq "\177ELF"; +} + +sub scandir { + my $d; + + if (!opendir($d, $_[0])) { + print STDERR "Warning: cannot open directory '$_[0]' for reading.\n"; + return; + } + + my @files; + foreach my $file (readdir($d)) { + next if ($file eq "." || $file eq ".."); + + $file = "$_[0]/$file"; + if (-d $file) { + # Recurse into subdirectory + push @files, scandir("$file"); + + } elsif (-f $file && -x $file && isELF($file)) { + push @files, $file; + } + } + closedir($d); + return @files; +} + +sub getdeps { + my ($fileDeps, $depFiles, $files) = @_; + my ($r, $w); + if (!open2($r, $w, 'objdump', '-p', @{$files})) { + fatal("Cannot communicate with objdump.\n"); + } + close $w; + + my $currentFile; + foreach my $line (<$r>) { + if ($line =~ /^(.+):[ \t]+file format /) { + $currentFile = $1; + $currentFile =~ s/^.\///; + + } elsif ($line =~ /NEEDED[ \t]+(.+)$/) { + $fileDeps->{$currentFile} = [] if (!exists $fileDeps->{$currentFile}); + push @{$fileDeps->{$currentFile}}, $1; + + $depFiles->{$1} = [] if (!exists $depFiles->{$1}); + push @{$depFiles->{$1}}, $currentFile; + } + } + close $r; +} |