From: Florian Krohm Date: Thu, 19 Sep 2013 14:55:09 +0000 (+0000) Subject: Add a script 'check_headers_and_includes' to check that #include directives X-Git-Tag: svn/VALGRIND_3_9_0~121 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e9e22a3a007f619cc9bd522c3e7cbafab9ddd13b;p=thirdparty%2Fvalgrind.git Add a script 'check_headers_and_includes' to check that #include directives are not against the grain. Wrap this script together with 'check_makefile_consistency' into 'post_regtest_checks' and invoke that from the toplevel Makefile. So we can easily add new checkers in the future. Add a new make target 'post-regtest-checks' to just run those checks and nothing else. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13570 --- diff --git a/Makefile.am b/Makefile.am index 498463e3d5..28087d9104 100644 --- a/Makefile.am +++ b/Makefile.am @@ -67,15 +67,17 @@ default.supp: $(DEFAULT_SUPP_FILES) cat $(DEFAULT_SUPP_FILES) >> default.supp ## Preprend @PERL@ because tests/vg_regtest isn't executable -## Ensure make exits with error if PERL fails or check_makefile_consistency fails. +## Ensure make exits with error if PERL fails or post_regtest_checks fails. regtest: check gdbserver_tests/make_local_links $(GDB) if @PERL@ tests/vg_regtest gdbserver_tests $(TOOLS) $(EXP_TOOLS) ; then \ - tests/check_makefile_consistency gdbserver_tests $(TOOLS) $(EXP_TOOLS); \ + tests/post_regtest_checks $(abs_top_srcdir) gdbserver_tests $(TOOLS) $(EXP_TOOLS); \ else \ - tests/check_makefile_consistency gdbserver_tests $(TOOLS) $(EXP_TOOLS); \ + tests/post_regtest_checks $(abs_top_srcdir) gdbserver_tests $(TOOLS) $(EXP_TOOLS); \ false; \ fi +post-regtest-checks: + tests/post_regtest_checks $(abs_top_srcdir) gdbserver_tests $(TOOLS) $(EXP_TOOLS) nonexp-regtest: check @PERL@ tests/vg_regtest $(TOOLS) exp-regtest: check diff --git a/tests/check_headers_and_includes b/tests/check_headers_and_includes new file mode 100755 index 0000000000..d558412d5f --- /dev/null +++ b/tests/check_headers_and_includes @@ -0,0 +1,292 @@ +#!/usr/bin/env perl + +#------------------------------------------------------------------- +# Check header files and #include directives +# +# (1) include/*.h must not include pub_core_...h +# (2) coregrind/pub_core_xyzzy.h may include pub_tool_xyzzy.h +# other coregrind headers may not include pub_tool_xyzzy.h +# (3) coregrind/ *.c must not include pub_tool_xyzzy.h +# (4) tool *.[ch] files must not include pub_core_...h +# (5) include pub_core/tool_clreq.h instead of valgrind.h except in tools' +# export headers +#------------------------------------------------------------------- + +use strict; +use warnings; +use Getopt::Long; + +my $this_script = "check_headers_and_includes"; + +# The list of top-level directories is divided into three sets: +# +# (1) coregrind directories +# (2) tool directories +# (3) directories to ignore +# +# If a directory is found that does not belong to any of those sets, the +# script will terminate unsuccessfully. + +my %coregrind_dirs = ( + "include" => 1, + "coregrind" => 1, + ); + +my %tool_dirs = ( + "none" => 1, + "lackey" => 1, + "massif" => 1, + "memcheck" => 1, + "drd" => 1, + "helgrind", => 1, + "callgrind" => 1, + "cachegrind" => 1, + "exp-bbv" => 1, + "exp-dhat" => 1, + "exp-sgcheck" => 1 + ); + +my %dirs_to_ignore = ( + ".deps" => 1, + ".svn" => 1, + ".in_place" => 1, + "VEX" => 1, + "docs" => 1, + "auxprogs" => 1, + "autom4te.cache" => 1, + "nightly" => 1, + "perf" => 1, + "tests" => 1, + "gdbserver_tests" => 1, + "mpi" => 1 + ); + +my %tool_export_header = ( + "drd/drd.h" => 1, + "helgrind/helgrind.h" => 1, + "memcheck/memcheck.h" => 1, + "callgrind/callgrind.h" => 1 + ); + +my $usage=< \$debug ) || die $usage; + + my $argc = $#ARGV + 1; + + if ($argc < 1) { + die $usage; + } + + foreach my $dir (@ARGV) { + process_dir(undef, $dir, 0); + } + + my $rc = ($num_errors == 0) ? 0 : 1; + exit $rc; +} + +sub process_dir { + my ($path, $dir, $depth) = @_; + my $hdir; + + if ($depth == 0) { +# The root directory is always processed + } elsif ($depth == 1) { +# Toplevel directories + return if ($dirs_to_ignore{$dir}); + + if (! $tool_dirs{$dir} && ! $coregrind_dirs{$dir}) { + die "Unknown directory '$dir'. Please update $this_script\n"; + } + } else { +# Subdirectories + return if ($dirs_to_ignore{$dir}); + } + + print "DIR = $dir DEPTH = $depth\n" if ($debug); + + chdir($dir) || die "Cannot chdir '$dir'\n"; + + opendir($hdir, ".") || die "cannot open directory '.'"; + + while (my $file = readdir($hdir)) { + next if ($file eq "."); + next if ($file eq ".."); + +# Subdirectories + if (-d $file) { + my $full_path = defined $path ? "$path/$file" : $file; + process_dir($full_path, $file, $depth + 1); + next; + } + +# Regular files; only interested in *.c and *.h + next if (! ($file =~ /\.[ch]$/)); + my $path_name = defined $path ? "$path/$file" : $file; + process_file($path_name); + } + close($hdir); + chdir("..") || die "Cannot chdir '..'\n"; +} + +#--------------------------------------------------------------------- +# Given a path name strip leading directories. +#--------------------------------------------------------------------- +sub basename { + my ($path_name) = @_; + my $file = $path_name; + + $file =~ s/^.*\///; + + return $file; +} + +#--------------------------------------------------------------------- +# Return 1, if file is located in /include +#--------------------------------------------------------------------- +sub is_coregrind_export_header { + my ($path_name) = @_; + + return ($path_name =~ /^include\//) ? 1 : 0; +} + +#--------------------------------------------------------------------- +# Return 1, if file is located underneath /coregrind +#--------------------------------------------------------------------- +sub is_coregrind_file { + my ($path_name) = @_; + + return ($path_name =~ /^coregrind\//) ? 1 : 0; +} + +#--------------------------------------------------------------------- +# Return 1, if file is located underneath / +#--------------------------------------------------------------------- +sub is_tool_file { + my ($path_name) = @_; + + for my $tool (keys %tool_dirs) { + return 1 if ($path_name =~ /^$tool\//); + } + return 0 +} + +#--------------------------------------------------------------------- +# Return array of files #include'd by file. +#--------------------------------------------------------------------- +sub get_included_files { + my ($path_name) = @_; + my @includes = (); + my $file = basename($path_name); + + open(FILE, "<$file") || die "Cannot open file '$file'"; + + while (my $line = ) { + if ($line =~ /^\s*#\s*include "([^"]*)"/) { + push @includes, $1; + } + if ($line =~ /^\s*#\s*include <([^>]*)>/) { + push @includes, $1; + } + } + close FILE; + return @includes; +} + +#--------------------------------------------------------------------- +# Check a file from /include +#--------------------------------------------------------------------- +sub check_coregrind_export_header { + my ($path_name) = @_; + + foreach my $inc (get_included_files($path_name)) { + $inc = basename($inc); +# Must not include pub_core_.... + if ($inc =~ /pub_core_/) { + error("File $path_name must not include $inc\n"); + } +# Only pub_tool_clreq.h may include valgrind.h + if (($inc eq "valgrind.h") && ($path_name ne "include/pub_tool_clreq.h")) { + error("File $path_name should include pub_tool_clreq.h instead of $inc\n"); + } + } +} + +#--------------------------------------------------------------------- +# Check a file from /coregrind +#--------------------------------------------------------------------- +sub check_coregrind_file { + my ($path_name) = @_; + my $file = basename($path_name); + + foreach my $inc (get_included_files($path_name)) { + print "\tINCLUDE $inc\n" if ($debug); +# Only pub_tool_xyzzy.h may include pub_core_xyzzy.h + if ($inc =~ /pub_tool_/) { + my $buddy = $inc; + $buddy =~ s/pub_tool/pub_core/; + if ($file ne $buddy) { + error("File $path_name must not include $inc\n"); + } + } +# Must not include valgrind.h + if ($inc eq "valgrind.h") { + error("File $path_name should include pub_core_clreq.h instead of $inc\n"); + } + } +} + +#--------------------------------------------------------------------- +# Check a file from / +#--------------------------------------------------------------------- +sub check_tool_file { + my ($path_name) = @_; + my $file = basename($path_name); + + foreach my $inc (get_included_files($path_name)) { + print "\tINCLUDE $inc\n" if ($debug); +# Must not include pub_core_... + if ($inc =~ /pub_core_/) { + error("File $path_name must not include $inc\n"); + } +# Must not include valgrind.h unless this is an export header + if ($inc eq "valgrind.h" && ! $tool_export_header{$path_name}) { + error("File $path_name should include pub_tool_clreq.h instead of $inc\n"); + } + } +} + +sub process_file { + my ($path_name) = @_; + + print "FILE = $path_name\n" if ($debug); + + if (is_coregrind_export_header($path_name)) { + check_coregrind_export_header($path_name); + } elsif (is_coregrind_file($path_name)) { + check_coregrind_file($path_name); + } elsif (is_tool_file($path_name)) { + check_tool_file($path_name); + } +} + +sub error { + my ($message) = @_; + print STDERR "*** $message"; + ++$num_errors; +} diff --git a/tests/post_regtest_checks b/tests/post_regtest_checks new file mode 100755 index 0000000000..8024f40cef --- /dev/null +++ b/tests/post_regtest_checks @@ -0,0 +1,38 @@ +#!/bin/sh + +#------------------------------------------------------------------- +# +# This script is invoked after regression testing has finished +# It performs various consistency checks. +# +# Arguments passed to this script are (from left to right) +# - absolute path name of valgrind's root directory +# - list of directories being passed to check_makefile_consistency +# +#------------------------------------------------------------------- + +# echo "$@" + +abs_top_srcdir="$1" +test_dir="$abs_top_srcdir/tests" +shift + +errors=0 + +#------------------------------------------------------------------- + +echo "...checking makefile consistency" +$test_dir/check_makefile_consistency "$@" +if [ $? != 0 ]; then + errors=1 +fi + +#------------------------------------------------------------------- + +echo "...checking header files and include directives" +$test_dir/check_headers_and_includes "$abs_top_srcdir" +if [ $? != 0 ]; then + errors=1 +fi + +exit $errors