blob: 41b3697350ec18fdd14bd479e1d79258f3a83ca5 [file] [log] [blame]
florian43c56332013-09-19 14:55:09 +00001#!/usr/bin/env perl
2
3#-------------------------------------------------------------------
4# Check header files and #include directives
5#
6# (1) include/*.h must not include pub_core_...h
7# (2) coregrind/pub_core_xyzzy.h may include pub_tool_xyzzy.h
8# other coregrind headers may not include pub_tool_xyzzy.h
9# (3) coregrind/ *.c must not include pub_tool_xyzzy.h
10# (4) tool *.[ch] files must not include pub_core_...h
11# (5) include pub_core/tool_clreq.h instead of valgrind.h except in tools'
12# export headers
13#-------------------------------------------------------------------
14
15use strict;
16use warnings;
bart727033d2013-11-17 10:06:09 +000017use File::Basename;
florian43c56332013-09-19 14:55:09 +000018use Getopt::Long;
19
bart727033d2013-11-17 10:06:09 +000020my $this_script = basename($0);
florian43c56332013-09-19 14:55:09 +000021
22# The list of top-level directories is divided into three sets:
23#
24# (1) coregrind directories
25# (2) tool directories
26# (3) directories to ignore
27#
28# If a directory is found that does not belong to any of those sets, the
29# script will terminate unsuccessfully.
30
31my %coregrind_dirs = (
32 "include" => 1,
33 "coregrind" => 1,
34 );
35
36my %tool_dirs = (
37 "none" => 1,
38 "lackey" => 1,
39 "massif" => 1,
40 "memcheck" => 1,
41 "drd" => 1,
42 "helgrind", => 1,
43 "callgrind" => 1,
44 "cachegrind" => 1,
45 "exp-bbv" => 1,
46 "exp-dhat" => 1,
47 "exp-sgcheck" => 1
48 );
49
50my %dirs_to_ignore = (
51 ".deps" => 1,
52 ".svn" => 1,
mjw782f3702013-10-02 11:39:41 +000053 ".git" => 1, # allow git mirrors of the svn repo
florian43c56332013-09-19 14:55:09 +000054 ".in_place" => 1,
floriandf4aec22013-09-20 12:12:52 +000055 "Inst" => 1, # the nightly scripts creates this
florian43c56332013-09-19 14:55:09 +000056 "VEX" => 1,
57 "docs" => 1,
58 "auxprogs" => 1,
59 "autom4te.cache" => 1,
60 "nightly" => 1,
61 "perf" => 1,
62 "tests" => 1,
63 "gdbserver_tests" => 1,
64 "mpi" => 1
65 );
66
67my %tool_export_header = (
68 "drd/drd.h" => 1,
69 "helgrind/helgrind.h" => 1,
70 "memcheck/memcheck.h" => 1,
71 "callgrind/callgrind.h" => 1
72 );
73
74my $usage=<<EOF;
75USAGE
76
77 $this_script
78
79 [--debug] Debugging output
80
81 dir ... Directories to process
82EOF
83
84my $debug = 0;
85my $num_errors = 0;
86
87&main;
88
89sub main {
90 GetOptions( "debug" => \$debug ) || die $usage;
91
92 my $argc = $#ARGV + 1;
93
94 if ($argc < 1) {
95 die $usage;
96 }
97
98 foreach my $dir (@ARGV) {
99 process_dir(undef, $dir, 0);
100 }
101
102 my $rc = ($num_errors == 0) ? 0 : 1;
103 exit $rc;
104}
105
106sub process_dir {
107 my ($path, $dir, $depth) = @_;
108 my $hdir;
109
110 if ($depth == 0) {
111# The root directory is always processed
112 } elsif ($depth == 1) {
113# Toplevel directories
114 return if ($dirs_to_ignore{$dir});
115
116 if (! $tool_dirs{$dir} && ! $coregrind_dirs{$dir}) {
117 die "Unknown directory '$dir'. Please update $this_script\n";
118 }
119 } else {
120# Subdirectories
121 return if ($dirs_to_ignore{$dir});
122 }
123
124 print "DIR = $dir DEPTH = $depth\n" if ($debug);
125
126 chdir($dir) || die "Cannot chdir '$dir'\n";
127
128 opendir($hdir, ".") || die "cannot open directory '.'";
129
130 while (my $file = readdir($hdir)) {
131 next if ($file eq ".");
132 next if ($file eq "..");
133
134# Subdirectories
135 if (-d $file) {
136 my $full_path = defined $path ? "$path/$file" : $file;
137 process_dir($full_path, $file, $depth + 1);
138 next;
139 }
140
141# Regular files; only interested in *.c and *.h
142 next if (! ($file =~ /\.[ch]$/));
143 my $path_name = defined $path ? "$path/$file" : $file;
144 process_file($path_name);
145 }
146 close($hdir);
147 chdir("..") || die "Cannot chdir '..'\n";
148}
149
150#---------------------------------------------------------------------
florian43c56332013-09-19 14:55:09 +0000151# Return 1, if file is located in <valgrind>/include
152#---------------------------------------------------------------------
153sub is_coregrind_export_header {
154 my ($path_name) = @_;
155
156 return ($path_name =~ /^include\//) ? 1 : 0;
157}
158
159#---------------------------------------------------------------------
160# Return 1, if file is located underneath <valgrind>/coregrind
161#---------------------------------------------------------------------
162sub is_coregrind_file {
163 my ($path_name) = @_;
164
165 return ($path_name =~ /^coregrind\//) ? 1 : 0;
166}
167
168#---------------------------------------------------------------------
169# Return 1, if file is located underneath <valgrind>/<tool>
170#---------------------------------------------------------------------
171sub is_tool_file {
172 my ($path_name) = @_;
173
174 for my $tool (keys %tool_dirs) {
175 return 1 if ($path_name =~ /^$tool\//);
176 }
177 return 0
178}
179
180#---------------------------------------------------------------------
181# Return array of files #include'd by file.
182#---------------------------------------------------------------------
183sub get_included_files {
184 my ($path_name) = @_;
185 my @includes = ();
186 my $file = basename($path_name);
187
188 open(FILE, "<$file") || die "Cannot open file '$file'";
189
190 while (my $line = <FILE>) {
191 if ($line =~ /^\s*#\s*include "([^"]*)"/) {
192 push @includes, $1;
193 }
194 if ($line =~ /^\s*#\s*include <([^>]*)>/) {
195 push @includes, $1;
196 }
197 }
198 close FILE;
199 return @includes;
200}
201
202#---------------------------------------------------------------------
203# Check a file from <valgrind>/include
204#---------------------------------------------------------------------
205sub check_coregrind_export_header {
206 my ($path_name) = @_;
207
208 foreach my $inc (get_included_files($path_name)) {
209 $inc = basename($inc);
210# Must not include pub_core_....
211 if ($inc =~ /pub_core_/) {
212 error("File $path_name must not include $inc\n");
213 }
214# Only pub_tool_clreq.h may include valgrind.h
215 if (($inc eq "valgrind.h") && ($path_name ne "include/pub_tool_clreq.h")) {
216 error("File $path_name should include pub_tool_clreq.h instead of $inc\n");
217 }
218 }
219}
220
221#---------------------------------------------------------------------
222# Check a file from <valgrind>/coregrind
223#---------------------------------------------------------------------
224sub check_coregrind_file {
225 my ($path_name) = @_;
226 my $file = basename($path_name);
227
228 foreach my $inc (get_included_files($path_name)) {
229 print "\tINCLUDE $inc\n" if ($debug);
230# Only pub_tool_xyzzy.h may include pub_core_xyzzy.h
231 if ($inc =~ /pub_tool_/) {
232 my $buddy = $inc;
233 $buddy =~ s/pub_tool/pub_core/;
234 if ($file ne $buddy) {
235 error("File $path_name must not include $inc\n");
236 }
237 }
238# Must not include valgrind.h
239 if ($inc eq "valgrind.h") {
240 error("File $path_name should include pub_core_clreq.h instead of $inc\n");
241 }
242 }
243}
244
245#---------------------------------------------------------------------
246# Check a file from <valgrind>/<tool>
247#---------------------------------------------------------------------
248sub check_tool_file {
249 my ($path_name) = @_;
250 my $file = basename($path_name);
251
252 foreach my $inc (get_included_files($path_name)) {
253 print "\tINCLUDE $inc\n" if ($debug);
254# Must not include pub_core_...
255 if ($inc =~ /pub_core_/) {
256 error("File $path_name must not include $inc\n");
257 }
258# Must not include valgrind.h unless this is an export header
259 if ($inc eq "valgrind.h" && ! $tool_export_header{$path_name}) {
260 error("File $path_name should include pub_tool_clreq.h instead of $inc\n");
261 }
262 }
263}
264
265sub process_file {
266 my ($path_name) = @_;
267
268 print "FILE = $path_name\n" if ($debug);
269
270 if (is_coregrind_export_header($path_name)) {
271 check_coregrind_export_header($path_name);
272 } elsif (is_coregrind_file($path_name)) {
273 check_coregrind_file($path_name);
274 } elsif (is_tool_file($path_name)) {
275 check_tool_file($path_name);
276 }
277}
278
279sub error {
280 my ($message) = @_;
281 print STDERR "*** $message";
282 ++$num_errors;
283}