~ubuntu-branches/ubuntu/hardy/postgresql-8.4/hardy-backports

« back to all changes in this revision

Viewing changes to src/tools/pginclude/pgcheckdefines

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/perl -w
 
2
 
 
3
#
 
4
# This script looks for symbols that are referenced in #ifdef or defined()
 
5
# tests without having #include'd the file that defines them.  Since this
 
6
# situation won't necessarily lead to any compiler message, it seems worth
 
7
# having an automated check for it.  In particular, use this to audit the
 
8
# results of pgrminclude!
 
9
#
 
10
# Usage: configure and build a PG source tree (non-VPATH), then start this
 
11
# script at the top level.  It's best to enable as many configure options
 
12
# as you can, especially --enable-cassert which is known to affect include
 
13
# requirements.  NB: you MUST use gcc, unless you have another compiler that
 
14
# can be persuaded to spit out the names of referenced include files.
 
15
#
 
16
# The results are necessarily platform-dependent, so use care in interpreting
 
17
# them.  We try to process all .c files, even those not intended for the
 
18
# current platform, so there will be some phony failures.
 
19
#
 
20
# $PostgreSQL$
 
21
#
 
22
 
 
23
use Cwd;
 
24
use File::Basename;
 
25
 
 
26
$topdir = cwd();
 
27
 
 
28
# Programs to use
 
29
$FIND = "find";
 
30
$MAKE = "make";
 
31
 
 
32
#
 
33
# Build arrays of all the .c and .h files in the tree
 
34
#
 
35
# We ignore .h files under src/include/port/, since only the one exposed as
 
36
# src/include/port.h is interesting.  (XXX Windows ports have additional
 
37
# files there?)  Ditto for .h files in src/backend/port/ subdirectories.
 
38
# Including these .h files would clutter the list of define'd symbols and
 
39
# cause a lot of false-positive results.
 
40
#
 
41
open PIPE, "$FIND * -type f -name '*.c' |"
 
42
    or die "can't fork: $!";
 
43
while (<PIPE>) {
 
44
    chomp;
 
45
    push @cfiles, $_;
 
46
}
 
47
close PIPE or die "$FIND failed: $!";
 
48
 
 
49
open PIPE, "$FIND * -type f -name '*.h' |"
 
50
    or die "can't fork: $!";
 
51
while (<PIPE>) {
 
52
    chomp;
 
53
    push @hfiles, $_ unless
 
54
        m|^src/include/port/| ||
 
55
        m|^src/backend/port/\w+/|;
 
56
}
 
57
close PIPE or die "$FIND failed: $!";
 
58
 
 
59
#
 
60
# For each .h file, extract all the symbols it #define's, and add them to
 
61
# a hash table.  To cover the possibility of multiple .h files defining
 
62
# the same symbol, we make each hash entry a hash of filenames.
 
63
#
 
64
foreach $hfile (@hfiles) {
 
65
    open HFILE, $hfile
 
66
        or die "can't open $hfile: $!";
 
67
    while (<HFILE>) {
 
68
        if (m/^\s*#\s*define\s+(\w+)/) {
 
69
            $defines{$1}{$hfile} = 1;
 
70
        }
 
71
    }
 
72
    close HFILE;
 
73
}
 
74
 
 
75
#
 
76
# For each file (both .h and .c), run the compiler to get a list of what
 
77
# files it #include's.  Then extract all the symbols it tests for defined-ness,
 
78
# and check each one against the previously built hashtable.
 
79
#
 
80
foreach $file (@hfiles, @cfiles) {
 
81
    ($fname, $fpath) = fileparse($file);
 
82
    chdir $fpath or die "can't chdir to $fpath: $!";
 
83
    #
 
84
    # Ask 'make' to parse the makefile so we can get the correct flags to
 
85
    # use.  CPPFLAGS in particular varies for each subdirectory.  If we are
 
86
    # processing a .h file, we might be in a subdirectory that has no
 
87
    # Makefile, in which case we have to fake it.  Note that there seems
 
88
    # no easy way to prevent make from recursing into subdirectories and
 
89
    # hence printing multiple definitions --- we keep the last one, which
 
90
    # should come from the current Makefile.
 
91
    #
 
92
    if (-f "Makefile" || -f "GNUmakefile") {
 
93
        $MAKECMD = "$MAKE -qp";
 
94
    } else {
 
95
        $subdir = $fpath;
 
96
        chop $subdir;
 
97
        $top_builddir = "..";
 
98
        $tmp = $fpath;
 
99
        while (($tmp = dirname($tmp)) ne '.') {
 
100
            $top_builddir = $top_builddir . "/..";
 
101
        }
 
102
        $MAKECMD = "$MAKE -qp 'subdir=$subdir' 'top_builddir=$top_builddir' -f '$top_builddir/src/Makefile.global'";
 
103
    }
 
104
    open PIPE, "$MAKECMD |"
 
105
        or die "can't fork: $!";
 
106
    while (<PIPE>) {
 
107
        if (m/^CPPFLAGS :?= (.*)/) {
 
108
            $CPPFLAGS = $1;
 
109
        } elsif (m/^CFLAGS :?= (.*)/) {
 
110
            $CFLAGS = $1;
 
111
        } elsif (m/^CFLAGS_SL :?= (.*)/) {
 
112
            $CFLAGS_SL = $1;
 
113
        } elsif (m/^PTHREAD_CFLAGS :?= (.*)/) {
 
114
            $PTHREAD_CFLAGS = $1;
 
115
        } elsif (m/^CC :?= (.*)/) {
 
116
            $CC = $1;
 
117
        }
 
118
    }
 
119
    # If make exits with status 1, it's not an error, it just means make
 
120
    # thinks some files may not be up-to-date.  Only complain on status 2.
 
121
    close PIPE;
 
122
    die "$MAKE failed in $fpath\n" if $? != 0 && $? != 256;
 
123
 
 
124
    # Expand out stuff that might be referenced in CFLAGS
 
125
    $CFLAGS =~ s/\$\(CFLAGS_SL\)/$CFLAGS_SL/;
 
126
    $CFLAGS =~ s/\$\(PTHREAD_CFLAGS\)/$PTHREAD_CFLAGS/;
 
127
 
 
128
    #
 
129
    # Run the compiler (which had better be gcc) to get the inclusions.
 
130
    # "gcc -H" reports inclusions on stderr as "... filename" where the
 
131
    # number of dots varies according to nesting depth.
 
132
    #
 
133
    @includes = ();
 
134
    $COMPILE = "$CC $CPPFLAGS $CFLAGS -H -E $fname";
 
135
    open PIPE, "$COMPILE 2>&1 >/dev/null |"
 
136
        or die "can't fork: $!";
 
137
    while (<PIPE>) {
 
138
        if (m/^\.+ (.*)/) {
 
139
            $include = $1;
 
140
            # Ignore system headers (absolute paths); but complain if a
 
141
            # .c file includes a system header before any PG header.
 
142
            if ($include =~ m|^/|) {
 
143
                warn "$file includes $include before any Postgres inclusion\n"
 
144
                    if $#includes == -1 && $file =~ m/\.c$/;
 
145
                next;
 
146
            }
 
147
            # Strip any "./" (assume this appears only at front)
 
148
            $include =~ s|^\./||;
 
149
            # Make path relative to top of tree
 
150
            $ipath = $fpath;
 
151
            while ($include =~ s|^\.\./||) {
 
152
                $ipath = dirname($ipath) . "/";
 
153
            }
 
154
            $ipath =~ s|^\./||;
 
155
            push @includes, $ipath . $include;
 
156
        } else {
 
157
            warn "$CC: $_";
 
158
        }
 
159
    }
 
160
    # The compiler might fail, particularly if we are checking a file that's
 
161
    # not supposed to be compiled at all on the current platform, so don't
 
162
    # quit on nonzero status.
 
163
    close PIPE or warn "$COMPILE failed in $fpath\n";
 
164
 
 
165
    #
 
166
    # Scan the file to find #ifdef, #ifndef, and #if defined() constructs
 
167
    # We assume #ifdef isn't continued across lines, and that defined(foo)
 
168
    # isn't split across lines either
 
169
    #
 
170
    open FILE, $fname
 
171
        or die "can't open $file: $!";
 
172
    $inif = 0;
 
173
    while (<FILE>) {
 
174
        $line = $_;
 
175
        if ($line =~ m/^\s*#\s*ifdef\s+(\w+)/) {
 
176
            $symbol = $1;
 
177
            &checkit;
 
178
        }
 
179
        if ($line =~ m/^\s*#\s*ifndef\s+(\w+)/) {
 
180
            $symbol = $1;
 
181
            &checkit;
 
182
        }
 
183
        if ($line =~ m/^\s*#\s*if\s+/) {
 
184
            $inif = 1;
 
185
        }
 
186
        if ($inif) {
 
187
            while ($line =~ s/\bdefined(\s+|\s*\(\s*)(\w+)//) {
 
188
                $symbol = $2;
 
189
                &checkit;
 
190
            }
 
191
            if (!($line =~ m/\\$/)) {
 
192
                $inif = 0;
 
193
            }
 
194
        }
 
195
    }
 
196
    close FILE;
 
197
 
 
198
    chdir $topdir or die "can't chdir to $topdir: $!";
 
199
}
 
200
 
 
201
exit 0;
 
202
 
 
203
# Check an is-defined reference
 
204
sub checkit {
 
205
    # Ignore if symbol isn't defined in any PG include files
 
206
    if (! defined $defines{$symbol}) {
 
207
        return;
 
208
    }
 
209
    #
 
210
    # Try to match source(s) of symbol to the inclusions of the current file
 
211
    # (including itself).  We consider it OK if any one matches.
 
212
    #
 
213
    # Note: these tests aren't bulletproof; in theory the inclusion might
 
214
    # occur after the use of the symbol.  Given our normal file layout,
 
215
    # however, the risk is minimal.
 
216
    #
 
217
    foreach $deffile (keys %{ $defines{$symbol} }) {
 
218
        return if $deffile eq $file;
 
219
        foreach $reffile (@includes) {
 
220
            return if $deffile eq $reffile;
 
221
        }
 
222
    }
 
223
    #
 
224
    # If current file is a .h file, it's OK for it to assume that one of the
 
225
    # base headers (postgres.h or postgres_fe.h) has been included.
 
226
    #
 
227
    if ($file =~ m/\.h$/) {
 
228
        foreach $deffile (keys %{ $defines{$symbol} }) {
 
229
            return if $deffile eq 'src/include/c.h';
 
230
            return if $deffile eq 'src/include/postgres.h';
 
231
            return if $deffile eq 'src/include/postgres_fe.h';
 
232
            return if $deffile eq 'src/include/pg_config.h';
 
233
            return if $deffile eq 'src/include/pg_config_manual.h';
 
234
        }
 
235
    }
 
236
    #
 
237
    @places = keys %{ $defines{$symbol} };
 
238
    print "$file references $symbol, defined in @places\n";
 
239
    # print "includes: @includes\n";
 
240
}