tests/vg_regtest: Always evaluate prerequisite expressions with sh
[valgrind.git] / tests / check_headers_and_includes
blobb154f416e7442a3d5a9d0cc32d1212f5910f031d
1 #!/usr/bin/env perl
3 #-------------------------------------------------------------------
4 # Check header files and #include directives
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 # (6) coregrind/ *.[ch] must not use tl_assert
14 # (7) include/*.h and tool *.[ch] must not use vg_assert
15 # (8) coregrind/ *.[ch] must not use VG_(tool_panic)
16 # (9) include/*.h and tool *.[ch] must not use VG_(core_panic)
17 #-------------------------------------------------------------------
19 use strict;
20 use warnings;
21 use File::Basename;
22 use Getopt::Long;
24 my $this_script = basename($0);
26 # The list of top-level directories is divided into three sets:
28 # (1) coregrind directories
29 # (2) tool directories
30 # (3) directories to ignore
32 # If a directory is found that does not belong to any of those sets, the
33 # script will terminate unsuccessfully.
35 my %coregrind_dirs = (
36 "include" => 1,
37 "coregrind" => 1,
40 my %tool_dirs = (
41 "none" => 1,
42 "lackey" => 1,
43 "massif" => 1,
44 "memcheck" => 1,
45 "drd" => 1,
46 "helgrind", => 1,
47 "callgrind" => 1,
48 "cachegrind" => 1,
49 "shared" => 1,
50 "exp-bbv" => 1,
51 "exp-dhat" => 1,
52 "exp-sgcheck" => 1
55 my %dirs_to_ignore = (
56 ".deps" => 1,
57 ".svn" => 1,
58 ".git" => 1, # allow git mirrors of the svn repo
59 ".in_place" => 1,
60 "Inst" => 1, # the nightly scripts creates this
61 "VEX" => 1,
62 "docs" => 1,
63 "auxprogs" => 1,
64 "autom4te.cache" => 1,
65 "nightly" => 1,
66 "perf" => 1,
67 "tests" => 1,
68 "gdbserver_tests" => 1,
69 "mpi" => 1,
70 "solaris" => 1
73 my %tool_export_header = (
74 "drd/drd.h" => 1,
75 "helgrind/helgrind.h" => 1,
76 "memcheck/memcheck.h" => 1,
77 "callgrind/callgrind.h" => 1
80 my $usage=<<EOF;
81 USAGE
83 $this_script
85 [--debug] Debugging output
87 dir ... Directories to process
88 EOF
90 my $debug = 0;
91 my $num_errors = 0;
93 &main;
95 sub main {
96 GetOptions( "debug" => \$debug ) || die $usage;
98 my $argc = $#ARGV + 1;
100 if ($argc < 1) {
101 die $usage;
104 foreach my $dir (@ARGV) {
105 process_dir(undef, $dir, 0);
108 my $rc = ($num_errors == 0) ? 0 : 1;
109 exit $rc;
112 sub process_dir {
113 my ($path, $dir, $depth) = @_;
114 my $hdir;
116 if ($depth == 0) {
117 # The root directory is always processed
118 } elsif ($depth == 1) {
119 # Toplevel directories
120 return if ($dirs_to_ignore{$dir});
122 if (! $tool_dirs{$dir} && ! $coregrind_dirs{$dir}) {
123 die "Unknown directory '$dir'. Please update $this_script\n";
125 } else {
126 # Subdirectories
127 return if ($dirs_to_ignore{$dir});
130 print "DIR = $dir DEPTH = $depth\n" if ($debug);
132 chdir($dir) || die "Cannot chdir '$dir'\n";
134 opendir($hdir, ".") || die "cannot open directory '.'";
136 while (my $file = readdir($hdir)) {
137 next if ($file eq ".");
138 next if ($file eq "..");
140 # Subdirectories
141 if (-d $file) {
142 my $full_path = defined $path ? "$path/$file" : $file;
143 process_dir($full_path, $file, $depth + 1);
144 next;
147 # Regular files; only interested in *.c and *.h
148 next if (! ($file =~ /\.[ch]$/));
149 my $path_name = defined $path ? "$path/$file" : $file;
150 process_file($path_name);
152 close($hdir);
153 chdir("..") || die "Cannot chdir '..'\n";
156 #---------------------------------------------------------------------
157 # Return 1, if file is located in <valgrind>/include
158 #---------------------------------------------------------------------
159 sub is_coregrind_export_header {
160 my ($path_name) = @_;
162 return ($path_name =~ /^include\//) ? 1 : 0;
165 #---------------------------------------------------------------------
166 # Return 1, if file is located underneath <valgrind>/coregrind
167 #---------------------------------------------------------------------
168 sub is_coregrind_file {
169 my ($path_name) = @_;
171 return ($path_name =~ /^coregrind\//) ? 1 : 0;
174 #---------------------------------------------------------------------
175 # Return 1, if file is located underneath <valgrind>/<tool>
176 #---------------------------------------------------------------------
177 sub is_tool_file {
178 my ($path_name) = @_;
180 for my $tool (keys %tool_dirs) {
181 return 1 if ($path_name =~ /^$tool\//);
183 return 0
186 #---------------------------------------------------------------------
187 # Return array of files #include'd by file.
188 #---------------------------------------------------------------------
189 sub get_included_files {
190 my ($path_name) = @_;
191 my @includes = ();
192 my $file = basename($path_name);
194 open(FILE, "<$file") || die "Cannot open file '$file'";
196 while (my $line = <FILE>) {
197 if ($line =~ /^\s*#\s*include "([^"]*)"/) {
198 push @includes, $1;
200 if ($line =~ /^\s*#\s*include <([^>]*)>/) {
201 push @includes, $1;
204 close FILE;
205 return @includes;
208 #---------------------------------------------------------------------
209 # Check a file from <valgrind>/include
210 #---------------------------------------------------------------------
211 sub check_coregrind_export_header {
212 my ($path_name) = @_;
213 my $file = basename($path_name);
215 foreach my $inc (get_included_files($path_name)) {
216 $inc = basename($inc);
217 # Must not include pub_core_....
218 if ($inc =~ /pub_core_/) {
219 error("File $path_name must not include $inc\n");
221 # Only pub_tool_clreq.h may include valgrind.h
222 if (($inc eq "valgrind.h") && ($path_name ne "include/pub_tool_clreq.h")) {
223 error("File $path_name should include pub_tool_clreq.h instead of $inc\n");
226 # Must not use vg_assert
227 my $assert = `grep vg_assert $file`;
228 if ($assert ne "") {
229 error("File $path_name must not use vg_assert\n");
231 # Must not use VG_(core_panic)
232 my $panic = `grep 'VG_(core_panic)' $file`;
233 if ($panic ne "") {
234 error("File $path_name must not use VG_(core_panic)\n");
238 #---------------------------------------------------------------------
239 # Check a file from <valgrind>/coregrind
240 #---------------------------------------------------------------------
241 sub check_coregrind_file {
242 my ($path_name) = @_;
243 my $file = basename($path_name);
245 foreach my $inc (get_included_files($path_name)) {
246 print "\tINCLUDE $inc\n" if ($debug);
247 # Only pub_tool_xyzzy.h may include pub_core_xyzzy.h
248 if ($inc =~ /pub_tool_/) {
249 my $buddy = $inc;
250 $buddy =~ s/pub_tool/pub_core/;
251 if ($file ne $buddy) {
252 error("File $path_name must not include $inc\n");
255 # Must not include valgrind.h
256 if ($inc eq "valgrind.h") {
257 error("File $path_name should include pub_core_clreq.h instead of $inc\n");
260 # Must not use tl_assert
261 my $assert = `grep tl_assert $file`;
262 if ($assert ne "") {
263 error("File $path_name must not use tl_assert\n");
265 # Must not use VG_(tool_panic)
266 my $panic = `grep 'VG_(tool_panic)' $file`;
267 if ($panic ne "") {
268 chomp($panic);
269 # Do not complain about the definition of VG_(tool_panic)
270 if (($path_name eq "coregrind/m_libcassert.c") &&
271 ($panic eq "void VG_(tool_panic) ( const HChar* str )")) {
272 # OK
273 } else {
274 error("File $path_name must not use VG_(tool_panic)\n");
279 #---------------------------------------------------------------------
280 # Check a file from <valgrind>/<tool>
281 #---------------------------------------------------------------------
282 sub check_tool_file {
283 my ($path_name) = @_;
284 my $file = basename($path_name);
286 foreach my $inc (get_included_files($path_name)) {
287 print "\tINCLUDE $inc\n" if ($debug);
288 # Must not include pub_core_...
289 if ($inc =~ /pub_core_/) {
290 error("File $path_name must not include $inc\n");
292 # Must not include valgrind.h unless this is an export header
293 if ($inc eq "valgrind.h" && ! $tool_export_header{$path_name}) {
294 error("File $path_name should include pub_tool_clreq.h instead of $inc\n");
297 # Must not use vg_assert
298 my $assert = `grep vg_assert $file`;
299 if ($assert ne "") {
300 error("File $path_name must not use vg_assert\n");
302 # Must not use VG_(core_panic)
303 my $panic = `grep 'VG_(core_panic)' $file`;
304 if ($panic ne "") {
305 error("File $path_name must not use VG_(core_panic)\n");
309 sub process_file {
310 my ($path_name) = @_;
312 print "FILE = $path_name\n" if ($debug);
314 if (is_coregrind_export_header($path_name)) {
315 check_coregrind_export_header($path_name);
316 } elsif (is_coregrind_file($path_name)) {
317 check_coregrind_file($path_name);
318 } elsif (is_tool_file($path_name)) {
319 check_tool_file($path_name);
323 sub error {
324 my ($message) = @_;
325 print STDERR "*** $message";
326 ++$num_errors;