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