configure.ac: Sort AC_CHECK_FUNCS() arguments alphabetically
[valgrind.git] / tests / check_headers_and_includes
blob509f24488f1cf0b2286e58ebdcd70f2f1dafaf78
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 # (10) *.S must unconditionally instantiate MARK_STACK_NO_EXEC
19 # There can be false positives as we don't really parse the source files.
20 # Instead we only match regular expressions.
21 #-------------------------------------------------------------------
23 use strict;
24 use warnings;
25 use File::Basename;
26 use Getopt::Long;
28 my $this_script = basename($0);
30 # The list of top-level directories is divided into three sets:
32 # (1) coregrind directories
33 # (2) tool directories
34 # (3) directories to ignore
36 # If a directory is found that does not belong to any of those sets, the
37 # script will terminate unsuccessfully.
39 my %coregrind_dirs = (
40 "include" => 1,
41 "coregrind" => 1,
44 my %tool_dirs = (
45 "memcheck" => 1,
46 "cachegrind" => 1,
47 "callgrind" => 1,
48 "helgrind", => 1,
49 "drd" => 1,
50 "massif" => 1,
51 "dhat" => 1,
52 "lackey" => 1,
53 "none" => 1,
54 "exp-bbv" => 1,
55 "shared" => 1,
58 my %dirs_to_ignore = (
59 ".deps" => 1,
60 ".git" => 1,
61 ".in_place" => 1,
62 "Inst" => 1, # the nightly scripts creates this
63 "VEX" => 1,
64 "docs" => 1,
65 "auxprogs" => 1,
66 "autom4te.cache" => 1,
67 "nightly" => 1,
68 "perf" => 1,
69 "tests" => 1,
70 "gdbserver_tests" => 1,
71 "mpi" => 1,
72 "solaris" => 1
75 my %tool_export_header = (
76 "dhat/dhat.h" => 1,
77 "drd/drd.h" => 1,
78 "helgrind/helgrind.h" => 1,
79 "memcheck/memcheck.h" => 1,
80 "callgrind/callgrind.h" => 1
83 my $usage=<<EOF;
84 USAGE
86 $this_script
88 [--debug] Debugging output
90 dir ... Directories to process
91 EOF
93 my $debug = 0;
94 my $num_errors = 0;
96 &main;
98 sub main {
99 GetOptions( "debug" => \$debug ) || die $usage;
101 my $argc = $#ARGV + 1;
103 if ($argc < 1) {
104 die $usage;
107 foreach my $dir (@ARGV) {
108 process_dir(undef, $dir, 0);
111 my $rc = ($num_errors == 0) ? 0 : 1;
112 exit $rc;
115 sub process_dir {
116 my ($path, $dir, $depth) = @_;
117 my $hdir;
119 if ($depth == 0) {
120 # The root directory is always processed
121 } elsif ($depth == 1) {
122 # Toplevel directories
123 return if ($dirs_to_ignore{$dir});
125 if (! $tool_dirs{$dir} && ! $coregrind_dirs{$dir}) {
126 die "Unknown directory '$dir'. Please update $this_script\n";
128 } else {
129 # Subdirectories
130 return if ($dirs_to_ignore{$dir});
133 print "DIR = $dir DEPTH = $depth\n" if ($debug);
135 chdir($dir) || die "Cannot chdir '$dir'\n";
137 opendir($hdir, ".") || die "cannot open directory '.'";
139 while (my $file = readdir($hdir)) {
140 next if ($file eq ".");
141 next if ($file eq "..");
143 # Subdirectories
144 if (-d $file) {
145 my $full_path = defined $path ? "$path/$file" : $file;
146 process_dir($full_path, $file, $depth + 1);
147 next;
150 # Regular files; only interested in *.c, *.S and *.h
151 next if (! ($file =~ /\.[cSh]$/));
152 my $path_name = defined $path ? "$path/$file" : $file;
153 process_file($path_name);
155 close($hdir);
156 chdir("..") || die "Cannot chdir '..'\n";
159 #---------------------------------------------------------------------
160 # Return 1, if file is located in <valgrind>/include
161 #---------------------------------------------------------------------
162 sub is_coregrind_export_header {
163 my ($path_name) = @_;
165 return ($path_name =~ /^include\//) ? 1 : 0;
168 #---------------------------------------------------------------------
169 # Return 1, if file is located underneath <valgrind>/coregrind
170 #---------------------------------------------------------------------
171 sub is_coregrind_file {
172 my ($path_name) = @_;
174 return ($path_name =~ /^coregrind\//) ? 1 : 0;
177 #---------------------------------------------------------------------
178 # Return 1, if file is located underneath <valgrind>/<tool>
179 #---------------------------------------------------------------------
180 sub is_tool_file {
181 my ($path_name) = @_;
183 for my $tool (keys %tool_dirs) {
184 return 1 if ($path_name =~ /^$tool\//);
186 return 0
189 #---------------------------------------------------------------------
190 # Return array of files #include'd by file.
191 #---------------------------------------------------------------------
192 sub get_included_files {
193 my ($path_name) = @_;
194 my @includes = ();
195 my $file = basename($path_name);
197 open(FILE, "<$file") || die "Cannot open file '$file'";
199 while (my $line = <FILE>) {
200 if ($line =~ /^\s*#\s*include "([^"]*)"/) {
201 push @includes, $1;
203 if ($line =~ /^\s*#\s*include <([^>]*)>/) {
204 push @includes, $1;
207 close FILE;
208 return @includes;
211 #---------------------------------------------------------------------
212 # Check a file from <valgrind>/include
213 #---------------------------------------------------------------------
214 sub check_coregrind_export_header {
215 my ($path_name) = @_;
216 my $file = basename($path_name);
218 foreach my $inc (get_included_files($path_name)) {
219 $inc = basename($inc);
220 # Must not include pub_core_....
221 if ($inc =~ /pub_core_/) {
222 error("File $path_name must not include $inc\n");
224 # Only pub_tool_clreq.h may include valgrind.h
225 if (($inc eq "valgrind.h") && ($path_name ne "include/pub_tool_clreq.h")) {
226 error("File $path_name should include pub_tool_clreq.h instead of $inc\n");
229 # Must not use vg_assert
230 my $assert = `grep vg_assert $file`;
231 if ($assert ne "") {
232 error("File $path_name must not use vg_assert\n");
234 # Must not use VG_(core_panic)
235 my $panic = `grep 'VG_(core_panic)' $file`;
236 if ($panic ne "") {
237 error("File $path_name must not use VG_(core_panic)\n");
241 #---------------------------------------------------------------------
242 # Check a file from <valgrind>/coregrind
243 #---------------------------------------------------------------------
244 sub check_coregrind_file {
245 my ($path_name) = @_;
246 my $file = basename($path_name);
248 foreach my $inc (get_included_files($path_name)) {
249 print "\tINCLUDE $inc\n" if ($debug);
250 # Only pub_tool_xyzzy.h may include pub_core_xyzzy.h
251 if ($inc =~ /pub_tool_/) {
252 my $buddy = $inc;
253 $buddy =~ s/pub_tool/pub_core/;
254 if ($file ne $buddy) {
255 error("File $path_name must not include $inc\n");
258 # Must not include valgrind.h
259 if ($inc eq "valgrind.h") {
260 error("File $path_name should include pub_core_clreq.h instead of $inc\n");
263 # Must not use tl_assert
264 my $assert = `grep tl_assert $file`;
265 if ($assert ne "") {
266 error("File $path_name must not use tl_assert\n");
268 # Must not use VG_(tool_panic)
269 my $panic = `grep 'VG_(tool_panic)' $file`;
270 if ($panic ne "") {
271 chomp($panic);
272 # Do not complain about the definition of VG_(tool_panic)
273 if (($path_name eq "coregrind/m_libcassert.c") &&
274 ($panic eq "void VG_(tool_panic) ( const HChar* str )")) {
275 # OK
276 } else {
277 error("File $path_name must not use VG_(tool_panic)\n");
282 #---------------------------------------------------------------------
283 # Check a file from <valgrind>/<tool>
284 #---------------------------------------------------------------------
285 sub check_tool_file {
286 my ($path_name) = @_;
287 my $file = basename($path_name);
289 foreach my $inc (get_included_files($path_name)) {
290 print "\tINCLUDE $inc\n" if ($debug);
291 # Must not include pub_core_...
292 if ($inc =~ /pub_core_/) {
293 error("File $path_name must not include $inc\n");
295 # Must not include valgrind.h unless this is an export header
296 if ($inc eq "valgrind.h" && ! $tool_export_header{$path_name}) {
297 error("File $path_name should include pub_tool_clreq.h instead of $inc\n");
300 # Must not use vg_assert
301 my $assert = `grep vg_assert $file`;
302 if ($assert ne "") {
303 error("File $path_name must not use vg_assert\n");
305 # Must not use VG_(core_panic)
306 my $panic = `grep 'VG_(core_panic)' $file`;
307 if ($panic ne "") {
308 error("File $path_name must not use VG_(core_panic)\n");
312 #---------------------------------------------------------------------
313 # Check an assembler file
314 #---------------------------------------------------------------------
315 sub check_assembler_file {
316 my ($path_name) = @_;
317 my $file = basename($path_name);
318 my $found = 0;
320 open(FILE, "<$file") || die "Cannot open file '$file'";
322 while (my $line = <FILE>) {
323 if ($line =~ /^\s*MARK_STACK_NO_EXEC/) {
324 $found = 1;
325 last;
328 if ($found == 0) {
329 error("File $path_name does not instantiate MARK_STACK_NO_EXEC\n");
330 } else {
331 while (my $line = <FILE>) {
332 if ($line =~ /^\s*#\s*endif/) {
333 error("File $path_name instantiates MARK_STACK_NO_EXEC"
334 . " under a condition\n");
335 last;
339 close FILE;
342 sub process_file {
343 my ($path_name) = @_;
345 print "FILE = $path_name\n" if ($debug);
347 if (is_coregrind_export_header($path_name)) {
348 check_coregrind_export_header($path_name);
349 } elsif (is_coregrind_file($path_name)) {
350 check_coregrind_file($path_name);
351 } elsif (is_tool_file($path_name)) {
352 check_tool_file($path_name);
355 if ($path_name =~ /\.S$/) {
356 check_assembler_file($path_name);
360 sub error {
361 my ($message) = @_;
362 print STDERR "*** $message";
363 ++$num_errors;