blob: 89e3c8c677f74e9976307d719045cc941097f78e [file] [log] [blame]
#!/usr/bin/perl
# searches for .o files in the current directory and examines each for
# defined functions (T) and undefined references (U) and lists
# anything that isn't required by something else or itself
# useful calling sorted by file:
# perl minimal/find-unused-code | sort
use File::Find;
use Data::Dumper;
use strict;
use Getopt::GUI::Long;
my %opts;
LocalGetOptions(\%opts,
['g|grep', "run find/grep to look for string usages"],
);
my (@files, %defined, %lookingfor);
find(\&dot_os, ".");
foreach my $file (@files) {
collect_from_file($file);
}
if ($#ARGV > -1) {
print "Dumping found symbol usages:\n\n";
foreach my $arg (@ARGV) {
print "$arg:\n";
print " ", join("\n ", @{$defined{$arg}{'usages'}}),"\n\n";
}
exit;
}
foreach my $function (sort { $defined{$a}{'source'} cmp $defined{$b}{'source'} } keys(%defined)) {
if (exists($defined{$function}{'source'}) &&
!exists($defined{$function}{'usages'})) {
if (check_for_once_only($defined{$function}{'source'}, $function)) {
printf("%-38s %-38s\n", $defined{$function}{'source'}, $function);
if ($opts{'g'}) {
open(P,"find . -regex '.*.\\(c\\|xs\\)' | xargs grep -n $function|");
while(<P>) {
print " $_";
}
close(P);
print "\n";
}
}
}
}
sub dot_os {
return if (!/\.o$/);
return if ($File::Find::name =~ /\/.libs\//);
# return if ($File::Find::name =~ /\/(perl|python)\//);
push @files, $File::Find::name;
}
sub collect_from_file {
my $file = shift;
# print "searching $file\n";
open(I,"nm $file|");
while(<I>) {
$defined{$1}{'source'} = $file if (/ T (.*)/);
push @{$defined{$1}{'usages'}}, $file if (/ U (.*)/);
}
close(I);
}
sub check_for_once_only {
my ($file, $function) = @_;
$file =~ s/\.o/.c/;
open(I, $file);
my $usages = 0;
while(<I>) {
if (/$function/) {
$usages++;
}
if ($usages > 1) {
close(I);
return 0;
}
}
return 1;
}
sub LocalGetOptions {
if (eval {require Getopt::GUI::Long;}) {
import Getopt::GUI::Long;
# optional configure call
Getopt::GUI::Long::Configure(qw(display_help no_ignore_case capture_output no_gui allow_zero));
return GetOptions(@_);
}
require Getopt::Long;
import Getopt::Long;
# optional configure call
Getopt::Long::Configure(qw(display_help no_ignore_case capture_output));
GetOptions(LocalOptionsMap(@_));
}
sub LocalOptionsMap {
my ($st, $cb, @opts) = ((ref($_[0]) eq 'HASH')
? (1, 1, $_[0]) : (0, 2));
for (my $i = $st; $i <= $#_; $i += $cb) {
if ($_[$i]) {
next if (ref($_[$i]) eq 'ARRAY' && $_[$i][0] =~ /^GUI:/);
push @opts, ((ref($_[$i]) eq 'ARRAY') ? $_[$i][0] : $_[$i]);
push @opts, $_[$i+1] if ($cb == 2);
}
}
return @opts;
}