| 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 | } | 
|---|