1#!/usr/bin/perl 2# 3# A somewhat specialised dependency checker; checks the contents of 4# gs/base and lib.mak to ensure that lib.mak properly lists all the 5# dependencies for each .h and .c file. 6 7use List::MoreUtils qw(uniq); 8 9sub gather_includes { 10 my ($dir) = @_; 11 12 # First, gather all the #includes. 13 my @rawincludes=`cd $dir;grep include *.h *.c`; 14 15 # Extract just the #includes that start on a line, and aren't system 16 # ones. 17 my %include=(); 18 foreach $inc (@rawincludes) { 19 if ((my $a, my $b) = $inc =~ /(\S+):\s*#\s*include\s*\"(\S+)\"/) { 20 if (!exists $include{$a}) { 21 $include{$a} = []; 22 } 23 $b =~ s/(\S+)\.h/\$\($1_h\)/; 24 #print "$a:$b\n"; 25 push @{ $include{$a} }, $b; 26 } 27 } 28 return %include; 29} 30 31sub read_makefile { 32 my ($dir, $file) = @_; 33 34 # Now, run through lib.mak 35 my %depend=(); 36 my %vars=(); 37 open(IN, "$dir/$file") or die "can't open $dir/$file"; 38 LINE: while (<IN>) { 39 # Reassemble split lines 40 chomp $_; 41 my $line=$_; 42 while (substr($line,-1) eq "\\") { 43 my $nextline = <IN>; 44 chomp $nextline; 45 substr($line,-1) = $nextline; 46 } 47 48 # Now, we're interested in 2 classes of lines. 49 # Firstly those of the form: file.blah : [dependency | symbol] * 50 if ((my $f, my $deps) = $line =~ /^([A-Za-z0-9_\$\(\)\.]+)\s*:\s*(.*)/) { 51 next LINE if (@deps eq ""); 52 my @deplist = split /\s+/, $deps; 53 if (!exists $depend{$f}) { 54 $depend{$f} = (); 55 } 56 push @{ $depend{$f} }, @deplist; 57 } 58 # And secondly, those of the form: something = filelist 59 elsif ((my $var, $val) = $line =~ /^([A-Za-z0-9_]+)\s*=\s*(.*)/) { 60 next LINE if (@val eq ""); 61 my @values = split /\s+/, $val; 62 if (!exists $vars{$var}) { 63 $vars{$var} = []; 64 } 65 push @{ $vars{$var} }, @values; 66 } 67 } 68 close(IN); 69 return (\%depend, \%vars); 70} 71 72sub check_vars 73{ 74 (my $include_ref, my $vars_ref) = @_; 75 my %include = %$include_ref; 76 my %vars = %$vars_ref; 77 # Now, check the vars 78 VAR: foreach $var (sort keys %vars) { 79 # We only care about vars of the form: blah_h 80 next VAR if !((my $v) = $var =~ /(\w+)_h/); 81 my @inclist = ( "\$(GLSRC)$v.h" ); 82 if (exists $include{"$v.h"}) { 83 push @inclist, @ { $include{"$v.h"} }; 84 } 85 @inclist = uniq(sort @inclist); 86 @deplist = sort @ { $vars{$var} }; 87 # Compare the dependency lists 88 #print "DEP=".join(', ', @deplist)."\n"; 89 #print "INC=".join(', ', @inclist)."\n"; 90 $a = shift @deplist; 91 $b = shift @inclist; 92 while (defined($a) || defined($b)) { 93 #print ("comparing $a and $b\n"); 94 95 # We are too crap to properly know the paths of things, so fudge it 96 if (defined($a) && defined($b) && $a ne $b && 97 ($a =~ m/\$\(.*\)(\S+).h/) && 98 ($b =~ m/\$\(.*\)$1.h/)) 99 { 100 print "$v.h: accepting $a ($b expected)\n"; 101 $a = shift @deplist; 102 $b = shift @inclist; 103 } 104 elsif (defined($a) && ($a lt $b || !defined($b))) { 105 print "$v.h: extra dependency on $a\n"; 106 $a = shift @deplist; 107 } elsif (defined($b) && ($a gt $b || !defined($a))) { 108 print "$v.h: missing dependency on $b\n"; 109 $b = shift @inclist; 110 } else { 111 $a = shift @deplist; 112 $b = shift @inclist; 113 } 114 } 115 #print "==\n"; 116 } 117} 118 119sub check_depend 120{ 121 (my $include_ref, my $depend_ref) = @_; 122 my %include = %$include_ref; 123 my %depend = %$depend_ref; 124 # Now, check the depends 125 VAR: foreach $dep (sort keys %depend) { 126 if ((my $path,my $d) = $dep =~ /^(\S+?)([a-zA-Z0-9_]+)\.\$\(OBJ\)/) { 127 # $(GLOBJ)file.$(OBJ) 128 my @inclist = ( "\$(GLSRC)$d.c" ); 129 if (exists $include{"$d.c"}) { 130 push @inclist, @ { $include{"$d.c"} }; 131 } 132 @inclist = uniq(sort @inclist); 133 @deplist = sort @ { $depend{$dep} }; 134 # Compare the dependency lists 135 #print "DEP=".join(', ', @deplist)."\n"; 136 #print "INC=".join(', ', @inclist)."\n"; 137 $a = shift @deplist; 138 $b = shift @inclist; 139 while (defined($a) || defined($b)) { 140 #print ("comparing $a and $b\n"); 141 142 # We are too crap to properly know the paths, so fudge it 143 if (defined($a) && defined($b) && $a ne $b && 144 ($a =~ m/\$\(.*\)(\S+).h/) && 145 ($b =~ m/\$\(.*\)$1.h/)) 146 { 147 print "$d.\$(OBJ): accepting $a ($b expected)\n"; 148 $a = shift @deplist; 149 $b = shift @inclist; 150 } 151 elsif ($a eq "\$(AK)") { 152 # Silently accept the AKs 153 $a = shift @deplist; 154 } 155 elsif ($a eq "STDDIRS") { 156 # Silently accept the STDDIRSs (should probably insist on 157 # these!) 158 $a = shift @deplist; 159 } 160 elsif (defined($a) && ($a lt $b || !defined($b))) { 161 print "$d.\$(OBJ): extra dependency on $a\n"; 162 $a = shift @deplist; 163 } elsif (defined($b) && ($a gt $b || !defined($a))) { 164 print "$d.\$(OBJ): missing dependency on $b\n"; 165 $b = shift @inclist; 166 } else { 167 $a = shift @deplist; 168 $b = shift @inclist; 169 } 170 } 171 #print "==\n"; 172 } 173 } 174} 175 176# Main. 177 178my %include, %depend, %vars; 179my $depend_ref, $vars_ref; 180 181%include = gather_includes("gs/base"); 182($depend_ref, $vars_ref) = read_makefile("gs/base", "lib.mak"); 183%depend = %$depend_ref; 184%vars = %$vars_ref; 185check_vars(\%include, \%vars); 186check_depend(\%include, \%depend); 187