Fix for C++.
[nethome.git] / bin / checkstatic
1 #! /usr/bin/perl
2
3 use strict;
4 use warnings;
5 use Cwd;
6 use Data::Dumper;
7 use Getopt::Long;
8
9
10 my(%symtab)=();
11
12 my $D;
13 my $opt_nm="nm";
14 my $opt_headers=1;
15 die if !GetOptions(
16                 "d|debug+",\$D,
17                 "nm=s"    ,\$opt_nm,
18                 "headers!",\$opt_headers,
19                 );
20
21
22 sub defmiss
23 {
24 my($ref,$missval,$sub)=@_;
25
26         $$ref=$missval if !defined $$ref;
27         &{$sub}($ref);
28 }
29
30 sub addsymtype
31 {
32 my($slot,$type,$symref)=@_;
33
34         defmiss(\$slot,{},sub {
35                 my($typeref)=@_;
36                 push(@{$$$typeref{$type}},$symref);
37                 });
38 }
39
40 sub storesym
41 {
42 my(%sym)=@_;
43
44         $sym{"fn_c"}=~s#^$ENV{PWD}/#./# if defined $sym{"fn_c"};
45         defmiss(\$symtab{$sym{"name"}},{},sub {
46                 my($slotref)=@_;
47                 my($type)=$sym{"type"};
48                 addsymtype($$slotref,$type,\%sym);
49                 addsymtype($$slotref,$type,\%sym)
50                                 if ($type!~/nU/ && ($type=~s/(n)[[:upper:]]/$1+/ || $type=~s/(n)[[:lower:]]/$1-/));
51                 });
52 }
53
54 open(NM,"-|",'find -name "*.o"|xargs -- '.$opt_nm.' -f posix --print-file-name --no-sort --line-numbers')
55                 or die "Cannot get nm output: $!";
56 while (<NM>) {
57         chomp;
58         die "Line $. of nm output not recognized: $_"
59                 #     $1         $2    $3              $4
60                 if !/^([^:]*):\s*(\S*) (\w) [^\t]*(?:\t(.*))?$/;
61         storesym(
62                 "fn_o"=>$1,
63                 "name"=>$2,
64                 "type"=>"n$3",
65                 "fn_c"=>$4,
66                 );
67         }
68 close NM;
69
70 if ($opt_headers) {
71         open(CTAGS,"-|",'find -name "*.h"|xargs ctags -f - --c-types=xp')
72                         or die "Cannot get ctags output: $!";
73         while (<CTAGS>) {
74                 chomp;
75                 die "Line $. of ctags output not recognized: $_"
76                         #     $1        $2            $3
77                         if !/^([^\t]*)\t([^\t]*)\t.*\t(\S+)$/;
78                 storesym(
79                         "name"=>$1,
80                         "fn_c"=>$2,
81                         "type"=>"c$3",
82                         );
83                 }
84         close CTAGS;
85         }
86
87 print Data::Dumper->Dump([\%symtab],["%symtab"]) if $D;
88
89 sub dumpsyms
90 {
91 my($error,@arr)=@_;
92
93         print("$error ".$arr[0]{"name"}.($arr[0]{"type"}=~/cp|n[tT]/ ? "()" : "").":\n");
94         my($symref);
95         while ($symref=shift(@arr)) {
96                 print("\t");
97                 if (defined($$symref{"fn_c"})) {
98                         print($$symref{"fn_c"});
99                         print("\t(".$$symref{"fn_o"}.")") if defined $$symref{"fn_o"};
100                         }
101                 else {
102                         my($fn)=$$symref{"fn_o"};
103                         $fn=~s/\.o$/.c/;
104                         print($fn);
105                         }
106                 print("\n");
107                 }
108 }
109
110 sub refendef
111 {
112 my($ref)=@_;
113
114         return [] if !defined($ref);
115         return $ref;
116 }
117
118 my($symname);
119 foreach $symname (sort keys %symtab) {
120         my($typesref)=$symtab{$symname};
121         my($ref,$ref1,$ref2);
122
123 # >=2 n[:upper:]\U symbols => global conflict
124         if (@{refendef($ref=$$typesref{"n+"})}>=2) {
125                 dumpsyms("global conflict",@{$ref});
126                 }
127
128 # >=1 n[:upper:]\U symbol && >=1 n[:lower:] symbol => local override
129         if (@{refendef($ref1=$$typesref{"n+"})}>=1 && @{refendef($ref2=$$typesref{"n-"})}>=1) {
130                 dumpsyms("local override of global",@{$ref1});
131                 dumpsyms(" -- with local",@{$ref2});
132                 }
133
134 # >=1 n[:upper:]\U symbol && ==0 nU symbol => global singularity
135         if (@{refendef($ref=$$typesref{"n+"})}>=1 && @{refendef($$typesref{"nU"})}==0) {
136                 dumpsyms("global singularity",@{$ref});
137                 }
138
139 # >=1 cx symbol && ==0 n[:upper:]\U symbol => floating extern data
140         if (@{refendef($ref=$$typesref{"cx"})}>=1 && @{refendef($$typesref{"n+"})}==0) {
141                 dumpsyms("floating extern data",@{$ref});
142                 }
143
144 # >=1 cp symbol && ==0 n[:upper:]\U symbol => floating extern func
145         if (@{refendef($ref=$$typesref{"cp"})}>=1 && @{refendef($$typesref{"n+"})}==0) {
146                 dumpsyms("floating extern func",@{$ref});
147                 }
148         }