summaryrefslogtreecommitdiff
path: root/local/minimalist/find-unused-code
diff options
context:
space:
mode:
Diffstat (limited to 'local/minimalist/find-unused-code')
-rwxr-xr-xlocal/minimalist/find-unused-code117
1 files changed, 117 insertions, 0 deletions
diff --git a/local/minimalist/find-unused-code b/local/minimalist/find-unused-code
new file mode 100755
index 0000000..89e3c8c
--- /dev/null
+++ b/local/minimalist/find-unused-code
@@ -0,0 +1,117 @@
+#!/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;
+}