#!/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(

) { 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() { $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() { 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; }