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 7use strict; 8use Data::Dumper; 9use Getopt::Long; 10 11my $opt_help = 0; 12my $opt_remove = 0; 13my $opt_skip_system = 0; 14 15##################################################################### 16# write a string into a file 17sub 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 27sub load_lines($) 28{ 29 my $fname = shift; 30 my @lines = split(/^/m, `cat $fname`); 31 return @lines; 32} 33 34sub save_lines($$) 35{ 36 my $fname = shift; 37 my $lines = shift; 38 my $data = join('', @{$lines}); 39 FileSave($fname, $data); 40} 41 42sub 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 59sub 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 93sub 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 129sub 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 146GetOptions ( 147 'h|help|?' => \$opt_help, 148 'remove' => \$opt_remove, 149 'skip-system' => \$opt_skip_system, 150 ); 151 152if ($opt_help) { 153 ShowHelp(); 154 exit(0); 155} 156 157for (my $i=0;$i<=$#ARGV;$i++) { 158 my $fname = $ARGV[$i]; 159 process_file($fname); 160} 161