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