| 1 | #!/usr/bin/perl -w
 | 
|---|
| 2 | # find a list of #include lines in C code that might not be needed
 | 
|---|
| 3 | # usually called with something like this:
 | 
|---|
| 4 | #    minimal_includes.pl `find . -name "*.c"`
 | 
|---|
| 5 | # Andrew Tridgell <tridge@samba.org>
 | 
|---|
| 6 | 
 | 
|---|
| 7 | use strict;
 | 
|---|
| 8 | use Data::Dumper;
 | 
|---|
| 9 | use Getopt::Long;
 | 
|---|
| 10 | 
 | 
|---|
| 11 | my $opt_help = 0;
 | 
|---|
| 12 | my $opt_remove = 0;
 | 
|---|
| 13 | my $opt_skip_system = 0;
 | 
|---|
| 14 | 
 | 
|---|
| 15 | #####################################################################
 | 
|---|
| 16 | # write a string into a file
 | 
|---|
| 17 | sub FileSave($$)
 | 
|---|
| 18 | {
 | 
|---|
| 19 |     my($filename) = shift;
 | 
|---|
| 20 |     my($v) = shift;
 | 
|---|
| 21 |     local(*FILE);
 | 
|---|
| 22 |     open(FILE, ">$filename") || die "can't open $filename";    
 | 
|---|
| 23 |     print FILE $v;
 | 
|---|
| 24 |     close(FILE);
 | 
|---|
| 25 | }
 | 
|---|
| 26 | 
 | 
|---|
| 27 | sub load_lines($)
 | 
|---|
| 28 | {
 | 
|---|
| 29 |         my $fname = shift;
 | 
|---|
| 30 |         my @lines = split(/^/m, `cat $fname`);
 | 
|---|
| 31 |         return @lines;
 | 
|---|
| 32 | }
 | 
|---|
| 33 | 
 | 
|---|
| 34 | sub save_lines($$)
 | 
|---|
| 35 | {
 | 
|---|
| 36 |         my $fname = shift;
 | 
|---|
| 37 |         my $lines = shift;
 | 
|---|
| 38 |         my $data = join('', @{$lines});
 | 
|---|
| 39 |         FileSave($fname, $data);
 | 
|---|
| 40 | }
 | 
|---|
| 41 | 
 | 
|---|
| 42 | sub test_compile($)
 | 
|---|
| 43 | {
 | 
|---|
| 44 |         my $fname = shift;
 | 
|---|
| 45 |         my $obj;
 | 
|---|
| 46 |         if ($fname =~ s/(.*)\.c$/$1.o/) {
 | 
|---|
| 47 |                 $obj = "$1.o";
 | 
|---|
| 48 |         } else {
 | 
|---|
| 49 |                 return "NOT A C FILE";
 | 
|---|
| 50 |         }
 | 
|---|
| 51 |         unlink($obj);
 | 
|---|
| 52 |         my $ret = `make $obj 2>&1`;
 | 
|---|
| 53 |         if (!unlink("$obj")) {
 | 
|---|
| 54 |                 return "COMPILE FAILED";
 | 
|---|
| 55 |         }
 | 
|---|
| 56 |         return $ret;
 | 
|---|
| 57 | }
 | 
|---|
| 58 | 
 | 
|---|
| 59 | sub test_include($$$$)
 | 
|---|
| 60 | {
 | 
|---|
| 61 |         my $fname = shift;
 | 
|---|
| 62 |         my $lines = shift;
 | 
|---|
| 63 |         my $i = shift;
 | 
|---|
| 64 |         my $original = shift;
 | 
|---|
| 65 |         my $line = $lines->[$i];
 | 
|---|
| 66 |         my $testfname;
 | 
|---|
| 67 | 
 | 
|---|
| 68 |         $lines->[$i] = "";
 | 
|---|
| 69 | 
 | 
|---|
| 70 |         `/bin/mv -f $fname $fname.misaved` && die "failed to rename $fname";
 | 
|---|
| 71 |         save_lines($fname, $lines);
 | 
|---|
| 72 |         
 | 
|---|
| 73 |         my $out = test_compile($fname);
 | 
|---|
| 74 | 
 | 
|---|
| 75 |         if ($out eq $original) {
 | 
|---|
| 76 |                 if ($opt_remove) {
 | 
|---|
| 77 |                         if ($opt_skip_system && 
 | 
|---|
| 78 |                             $line =~ /system\//) {
 | 
|---|
| 79 |                                 print "$fname: not removing system include $line\n";
 | 
|---|
| 80 |                         } else {
 | 
|---|
| 81 |                                 print "$fname: removing $line\n";
 | 
|---|
| 82 |                                 return;
 | 
|---|
| 83 |                         }
 | 
|---|
| 84 |                 } else {
 | 
|---|
| 85 |                         print "$fname: might be able to remove $line\n";
 | 
|---|
| 86 |                 }
 | 
|---|
| 87 |         }
 | 
|---|
| 88 | 
 | 
|---|
| 89 |         $lines->[$i] = $line;
 | 
|---|
| 90 |         `/bin/mv -f $fname.misaved $fname` && die "failed to restore $fname";
 | 
|---|
| 91 | }
 | 
|---|
| 92 | 
 | 
|---|
| 93 | sub process_file($)
 | 
|---|
| 94 | {
 | 
|---|
| 95 |         my $fname = shift;
 | 
|---|
| 96 |         my @lines = load_lines($fname);
 | 
|---|
| 97 |         my $num_lines = $#lines;
 | 
|---|
| 98 | 
 | 
|---|
| 99 |         my $original = test_compile($fname);
 | 
|---|
| 100 | 
 | 
|---|
| 101 |         if ($original eq "COMPILE FAILED") {
 | 
|---|
| 102 |                 print "Failed to compile $fname\n";
 | 
|---|
| 103 |                 return;
 | 
|---|
| 104 |         }
 | 
|---|
| 105 | 
 | 
|---|
| 106 |         print "Processing $fname (with $num_lines lines)\n";
 | 
|---|
| 107 |         
 | 
|---|
| 108 |         my $if_level = 0;
 | 
|---|
| 109 | 
 | 
|---|
| 110 |         for (my $i=0;$i<=$num_lines;$i++) {
 | 
|---|
| 111 |                 my $line = $lines[$i];
 | 
|---|
| 112 |                 if ($line =~ /^\#\s*if/) {
 | 
|---|
| 113 |                         $if_level++;
 | 
|---|
| 114 |                 }
 | 
|---|
| 115 |                 if ($line =~ /^\#\s*endif/) {
 | 
|---|
| 116 |                         $if_level--;
 | 
|---|
| 117 |                 }
 | 
|---|
| 118 |                 if ($if_level == 0 &&
 | 
|---|
| 119 |                     $line =~ /^\#\s*include/ && 
 | 
|---|
| 120 |                     !($line =~ /needed/)) {
 | 
|---|
| 121 |                         test_include($fname, \@lines, $i, $original);
 | 
|---|
| 122 |                 }
 | 
|---|
| 123 |         }
 | 
|---|
| 124 | }
 | 
|---|
| 125 | 
 | 
|---|
| 126 | 
 | 
|---|
| 127 | #########################################
 | 
|---|
| 128 | # display help text
 | 
|---|
| 129 | sub ShowHelp()
 | 
|---|
| 130 | {
 | 
|---|
| 131 |     print "
 | 
|---|
| 132 |            minimise includes
 | 
|---|
| 133 |            Copyright (C) tridge\@samba.org
 | 
|---|
| 134 | 
 | 
|---|
| 135 |            Usage: minimal_includes.pl [options] <C files....>
 | 
|---|
| 136 |            
 | 
|---|
| 137 |            Options:
 | 
|---|
| 138 |                  --help         show help
 | 
|---|
| 139 |                  --remove       remove includes, don't just list them
 | 
|---|
| 140 |                  --skip-system  don't remove system/ includes
 | 
|---|
| 141 | ";
 | 
|---|
| 142 | }
 | 
|---|
| 143 | 
 | 
|---|
| 144 | 
 | 
|---|
| 145 | # main program
 | 
|---|
| 146 | GetOptions (
 | 
|---|
| 147 |             'h|help|?' => \$opt_help,
 | 
|---|
| 148 |             'remove' => \$opt_remove,
 | 
|---|
| 149 |             'skip-system' => \$opt_skip_system,
 | 
|---|
| 150 |             );
 | 
|---|
| 151 | 
 | 
|---|
| 152 | if ($opt_help) {
 | 
|---|
| 153 |         ShowHelp();
 | 
|---|
| 154 |         exit(0);
 | 
|---|
| 155 | }
 | 
|---|
| 156 | 
 | 
|---|
| 157 | for (my $i=0;$i<=$#ARGV;$i++) {
 | 
|---|
| 158 |         my $fname = $ARGV[$i];
 | 
|---|
| 159 |         process_file($fname);
 | 
|---|
| 160 | }
 | 
|---|