diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:17:33 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:17:33 +0000 |
commit | 5e45211a64149b3c659b90ff2de6fa982a5a93ed (patch) | |
tree | 739caf8c461053357daa9f162bef34516c7bf452 /src/tools/pginclude | |
parent | Initial commit. (diff) | |
download | postgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.tar.xz postgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.zip |
Adding upstream version 15.5.upstream/15.5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/pginclude')
-rw-r--r-- | src/tools/pginclude/README | 103 | ||||
-rwxr-xr-x | src/tools/pginclude/cpluspluscheck | 175 | ||||
-rwxr-xr-x | src/tools/pginclude/headerscheck | 159 | ||||
-rwxr-xr-x | src/tools/pginclude/pgcheckdefines | 305 | ||||
-rwxr-xr-x | src/tools/pginclude/pgcompinclude | 47 | ||||
-rwxr-xr-x | src/tools/pginclude/pgdefine | 25 | ||||
-rwxr-xr-x | src/tools/pginclude/pgfixinclude | 21 | ||||
-rwxr-xr-x | src/tools/pginclude/pgrminclude | 149 |
8 files changed, 984 insertions, 0 deletions
diff --git a/src/tools/pginclude/README b/src/tools/pginclude/README new file mode 100644 index 0000000..49eb4b6 --- /dev/null +++ b/src/tools/pginclude/README @@ -0,0 +1,103 @@ +src/tools/pginclude/README + +pginclude +========= + +These utilities help clean up #include file usage. They should be run +in this order so that the include files have the proper includes before +the C files are tested. + +pgfixinclude change #include's to <> or "" + +pgcompinclude [-v] + report which #include files can not compile on their own + +pgrminclude [-v] + remove extra #include's + +pgcheckdefines + check for #ifdef tests on symbols defined in files that + weren't included --- this is a necessary sanity check on + pgrminclude + +pgdefine create macro calls for all defines in the file (used by + the above routines) + +It is also a good idea to sort the pg-specific include files in +alphabetic order. This is best done with a text editor. Typical usage +order would be: + + pgfixinclude + sort include references + run multiple times: + pgcompinclude + pgrminclude /src/include + pgrminclude / + pgcheckdefines + +There is a complexity when modifying /src/include. If include file 1 +includes file 2, and file 2 includes file 3, then when file 1 is +processed, it needs only file 2, not file 3. However, if later, include +file 2 is processed, and file 3 is not needed by file 2 and is removed, +file 1 might then need to include file 3. For this reason, the +pgcompinclude and pgrminclude /src/include steps must be run several +times until all includes compile cleanly. + +Also, tests should be done with configure settings of --enable-cassert +and EXEC_BACKEND on and off. It is also wise to test a WIN32 compile. + +Another tools that does a similar task is at: + + http://code.google.com/p/include-what-you-use/ + +An include file visualizer script is available at: + + http://archives.postgresql.org/pgsql-hackers/2011-09/msg00311.php + + +headerscheck +============ + +This script can be run to verify that all Postgres include files meet +the project convention that they will compile "standalone", that is +with no prerequisite headers other than postgres.h (or postgres_fe.h +or c.h, as appropriate). + +A small number of header files are exempted from this requirement, +and are skipped by the headerscheck script. + +The easy way to run the script is to say "make -s headerscheck" in +the top-level build directory after completing a build. You should +have included "--with-perl --with-python" in your configure options, +else you're likely to get errors about related headers not being found. + +A limitation of the current script is that it doesn't know which headers +are for frontend or backend, so it tests everything with postgres.h +as prerequisite, even if postgres_fe.h would be more appropriate. Also +note that the contents of macros are not checked; this is intentional. + + +cpluspluscheck +============== + +This script can be run to verify that all Postgres include files meet +the project convention that they will compile as C++ code. Although +the project's coding language is C, some people write extensions in C++, +so it's helpful for include files to be C++-clean. + +A small number of header files are exempted from this requirement, +and are skipped by the cpluspluscheck script. + +The easy way to run the script is to say "make -s cpluspluscheck" in +the top-level build directory after completing a build. You should +have included "--with-perl --with-python" in your configure options, +else you're likely to get errors about related headers not being found. + +If you are using a non-g++-compatible C++ compiler, you may need to +override the script's CXXFLAGS setting by setting a suitable environment +value. + +A limitation of the current script is that it doesn't know which headers +are for frontend or backend, so it tests everything with postgres.h +as prerequisite, even if postgres_fe.h would be more appropriate. Also +note that the contents of macros are not checked; this is intentional. diff --git a/src/tools/pginclude/cpluspluscheck b/src/tools/pginclude/cpluspluscheck new file mode 100755 index 0000000..42688ff --- /dev/null +++ b/src/tools/pginclude/cpluspluscheck @@ -0,0 +1,175 @@ +#!/bin/sh + +# Check (almost) all PostgreSQL include files for C++ compatibility. +# +# Argument 1 is the top-level source directory, argument 2 the +# top-level build directory (they might be the same). If not set, they +# default to the current directory. +# +# Needs to be run after configuring and creating all generated headers. +# It's advisable to configure --with-perl --with-python, else you're +# likely to get errors from associated headers. +# +# No output if everything is OK, else compiler errors. +# +# src/tools/pginclude/cpluspluscheck +# Copyright (c) 2009-2022, PostgreSQL Global Development Group + +if [ -z "$1" ]; then + srcdir="." +else + srcdir="$1" +fi + +if [ -z "$2" ]; then + builddir="." +else + builddir="$2" +fi + +me=`basename $0` + +# These switches are g++ specific, you may override if necessary. +CXXFLAGS=${CXXFLAGS:- -fsyntax-only -Wall} + +# Pull some info from configure's results. +MGLOB="$builddir/src/Makefile.global" +CPPFLAGS=`sed -n 's/^CPPFLAGS[ ]*=[ ]*//p' "$MGLOB"` +CXX=`sed -n 's/^CXX[ ]*=[ ]*//p' "$MGLOB"` +perl_includespec=`sed -n 's/^perl_includespec[ ]*=[ ]*//p' "$MGLOB"` +python_includespec=`sed -n 's/^python_includespec[ ]*=[ ]*//p' "$MGLOB"` + +# Extract any -I and -D switches from CPPFLAGS. +# (If necessary, user can pass more switches by presetting EXTRAFLAGS.) +for flag in $CPPFLAGS; do + case $flag in + -I*|-D*) EXTRAFLAGS="$EXTRAFLAGS $flag";; + esac +done + +# Create temp directory. +tmp=`mktemp -d /tmp/$me.XXXXXX` + +trap 'rm -rf $tmp' 0 1 2 3 15 + +# Scan all of src/ and contrib/ for header files. +for f in `cd "$srcdir" && find src contrib -name '*.h' -print` +do + # Ignore files that are unportable or intentionally not standalone. + + # These files are platform-specific, and c.h will include the + # one that's relevant for our current platform anyway. + test "$f" = src/include/port/aix.h && continue + test "$f" = src/include/port/cygwin.h && continue + test "$f" = src/include/port/darwin.h && continue + test "$f" = src/include/port/freebsd.h && continue + test "$f" = src/include/port/hpux.h && continue + test "$f" = src/include/port/linux.h && continue + test "$f" = src/include/port/netbsd.h && continue + test "$f" = src/include/port/openbsd.h && continue + test "$f" = src/include/port/solaris.h && continue + test "$f" = src/include/port/win32.h && continue + + # Additional Windows-specific headers. + test "$f" = src/include/port/win32_port.h && continue + test "$f" = src/include/port/win32/sys/socket.h && continue + test "$f" = src/include/port/win32_msvc/dirent.h && continue + test "$f" = src/include/port/win32_msvc/utime.h && continue + test "$f" = src/include/port/win32ntdll.h && continue + test "$f" = src/port/pthread-win32.h && continue + + # Likewise, these files are platform-specific, and the one + # relevant to our platform will be included by atomics.h. + test "$f" = src/include/port/atomics/arch-arm.h && continue + test "$f" = src/include/port/atomics/arch-hppa.h && continue + test "$f" = src/include/port/atomics/arch-ia64.h && continue + test "$f" = src/include/port/atomics/arch-ppc.h && continue + test "$f" = src/include/port/atomics/arch-x86.h && continue + test "$f" = src/include/port/atomics/fallback.h && continue + test "$f" = src/include/port/atomics/generic.h && continue + test "$f" = src/include/port/atomics/generic-acc.h && continue + test "$f" = src/include/port/atomics/generic-gcc.h && continue + test "$f" = src/include/port/atomics/generic-msvc.h && continue + test "$f" = src/include/port/atomics/generic-sunpro.h && continue + + # rusagestub.h is also platform-specific, and will be included + # by utils/pg_rusage.h if necessary. + test "$f" = src/include/rusagestub.h && continue + + # sepgsql.h depends on headers that aren't there on most platforms. + test "$f" = contrib/sepgsql/sepgsql.h && continue + + # These files are not meant to be included standalone, because + # they contain lists that might have multiple use-cases. + test "$f" = src/include/access/rmgrlist.h && continue + test "$f" = src/include/parser/kwlist.h && continue + test "$f" = src/pl/plpgsql/src/pl_reserved_kwlist.h && continue + test "$f" = src/pl/plpgsql/src/pl_unreserved_kwlist.h && continue + test "$f" = src/interfaces/ecpg/preproc/c_kwlist.h && continue + test "$f" = src/interfaces/ecpg/preproc/ecpg_kwlist.h && continue + test "$f" = src/include/regex/regerrs.h && continue + test "$f" = src/include/tcop/cmdtaglist.h && continue + test "$f" = src/pl/plpgsql/src/plerrcodes.h && continue + test "$f" = src/pl/plpython/spiexceptions.h && continue + test "$f" = src/pl/tcl/pltclerrcodes.h && continue + + # Also not meant to be included standalone. + test "$f" = src/include/common/unicode_combining_table.h && continue + test "$f" = src/include/common/unicode_east_asian_fw_table.h && continue + + # We can't make these Bison output files compilable standalone + # without using "%code require", which old Bison versions lack. + # parser/gram.h will be included by parser/gramparse.h anyway. + test "$f" = src/include/parser/gram.h && continue + test "$f" = src/backend/parser/gram.h && continue + test "$f" = src/pl/plpgsql/src/pl_gram.h && continue + test "$f" = src/interfaces/ecpg/preproc/preproc.h && continue + + # ppport.h is not under our control, so we can't make it standalone. + test "$f" = src/pl/plperl/ppport.h && continue + + # regression.h is not actually C, but ECPG code. + test "$f" = src/interfaces/ecpg/test/regression.h && continue + # printf_hack.h produces "unused function" warnings. + test "$f" = src/interfaces/ecpg/test/printf_hack.h && continue + + # pg_trace.h and utils/probes.h can include sys/sdt.h from SystemTap, + # which itself contains C++ code and so won't compile with a C++ + # compiler under extern "C" linkage. + test "$f" = src/include/pg_trace.h && continue + test "$f" = src/include/utils/probes.h && continue + + # pg_dump is not C++-clean because it uses "public" and "namespace" + # as field names, which is unfortunate but we won't change it now. + test "$f" = src/bin/pg_dump/compress_io.h && continue + test "$f" = src/bin/pg_dump/parallel.h && continue + test "$f" = src/bin/pg_dump/pg_backup_archiver.h && continue + test "$f" = src/bin/pg_dump/pg_dump.h && continue + + # OK, create .c file to include this .h file. + { + echo 'extern "C" {' + test "$f" != src/include/postgres_fe.h && echo '#include "postgres.h"' + echo "#include \"$f\"" + echo '};' + } >$tmp/test.cpp + + # Some subdirectories need extra -I switches. + case "$f" in + src/pl/plperl/*) + EXTRAINCLUDES="$perl_includespec" ;; + src/pl/plpython/*) + EXTRAINCLUDES="$python_includespec" ;; + src/interfaces/ecpg/*) + EXTRAINCLUDES="-I $builddir/src/interfaces/ecpg/include -I $srcdir/src/interfaces/ecpg/include" ;; + *) + EXTRAINCLUDES="" ;; + esac + + # Run the test. + ${CXX:-g++} -I $builddir -I $srcdir \ + -I $builddir/src/include -I $srcdir/src/include \ + -I $builddir/src/interfaces/libpq -I $srcdir/src/interfaces/libpq \ + $EXTRAINCLUDES $EXTRAFLAGS $CXXFLAGS -c $tmp/test.cpp + +done diff --git a/src/tools/pginclude/headerscheck b/src/tools/pginclude/headerscheck new file mode 100755 index 0000000..f8b0674 --- /dev/null +++ b/src/tools/pginclude/headerscheck @@ -0,0 +1,159 @@ +#!/bin/sh + +# Check (almost) all PostgreSQL include files for standalone build. +# +# Argument 1 is the top-level source directory, argument 2 the +# top-level build directory (they might be the same). If not set, they +# default to the current directory. +# +# Needs to be run after configuring and creating all generated headers. +# It's advisable to configure --with-perl --with-python, else you're +# likely to get errors from associated headers. +# +# No output if everything is OK, else compiler errors. +# +# src/tools/pginclude/headerscheck +# Copyright (c) 2009-2022, PostgreSQL Global Development Group + +if [ -z "$1" ]; then + srcdir="." +else + srcdir="$1" +fi + +if [ -z "$2" ]; then + builddir="." +else + builddir="$2" +fi + +me=`basename $0` + +# Pull some info from configure's results. +MGLOB="$builddir/src/Makefile.global" +CPPFLAGS=`sed -n 's/^CPPFLAGS[ ]*=[ ]*//p' "$MGLOB"` +CFLAGS=`sed -n 's/^CFLAGS[ ]*=[ ]*//p' "$MGLOB"` +CC=`sed -n 's/^CC[ ]*=[ ]*//p' "$MGLOB"` +PG_SYSROOT=`sed -n 's/^PG_SYSROOT[ ]*=[ ]*//p' "$MGLOB"` +perl_includespec=`sed -n 's/^perl_includespec[ ]*=[ ]*//p' "$MGLOB"` +python_includespec=`sed -n 's/^python_includespec[ ]*=[ ]*//p' "$MGLOB"` + +# needed on Darwin +CPPFLAGS=`echo "$CPPFLAGS" | sed "s|\\\$(PG_SYSROOT)|$PG_SYSROOT|g"` + +# (EXTRAFLAGS is not set here, but user can pass it in if need be.) + +# Create temp directory. +tmp=`mktemp -d /tmp/$me.XXXXXX` + +trap 'rm -rf $tmp' 0 1 2 3 15 + +# Scan all of src/ and contrib/ for header files. +for f in `cd "$srcdir" && find src contrib -name '*.h' -print` +do + # Ignore files that are unportable or intentionally not standalone. + + # These files are platform-specific, and c.h will include the + # one that's relevant for our current platform anyway. + test "$f" = src/include/port/aix.h && continue + test "$f" = src/include/port/cygwin.h && continue + test "$f" = src/include/port/darwin.h && continue + test "$f" = src/include/port/freebsd.h && continue + test "$f" = src/include/port/hpux.h && continue + test "$f" = src/include/port/linux.h && continue + test "$f" = src/include/port/netbsd.h && continue + test "$f" = src/include/port/openbsd.h && continue + test "$f" = src/include/port/solaris.h && continue + test "$f" = src/include/port/win32.h && continue + + # Additional Windows-specific headers. + test "$f" = src/include/port/win32_port.h && continue + test "$f" = src/include/port/win32/sys/socket.h && continue + test "$f" = src/include/port/win32_msvc/dirent.h && continue + test "$f" = src/include/port/win32_msvc/utime.h && continue + test "$f" = src/include/port/win32ntdll.h && continue + test "$f" = src/port/pthread-win32.h && continue + + # Likewise, these files are platform-specific, and the one + # relevant to our platform will be included by atomics.h. + test "$f" = src/include/port/atomics/arch-arm.h && continue + test "$f" = src/include/port/atomics/arch-hppa.h && continue + test "$f" = src/include/port/atomics/arch-ia64.h && continue + test "$f" = src/include/port/atomics/arch-ppc.h && continue + test "$f" = src/include/port/atomics/arch-x86.h && continue + test "$f" = src/include/port/atomics/fallback.h && continue + test "$f" = src/include/port/atomics/generic.h && continue + test "$f" = src/include/port/atomics/generic-acc.h && continue + test "$f" = src/include/port/atomics/generic-gcc.h && continue + test "$f" = src/include/port/atomics/generic-msvc.h && continue + test "$f" = src/include/port/atomics/generic-sunpro.h && continue + + # rusagestub.h is also platform-specific, and will be included + # by utils/pg_rusage.h if necessary. + test "$f" = src/include/rusagestub.h && continue + + # sepgsql.h depends on headers that aren't there on most platforms. + test "$f" = contrib/sepgsql/sepgsql.h && continue + + # These files are not meant to be included standalone, because + # they contain lists that might have multiple use-cases. + test "$f" = src/include/access/rmgrlist.h && continue + test "$f" = src/include/parser/kwlist.h && continue + test "$f" = src/pl/plpgsql/src/pl_reserved_kwlist.h && continue + test "$f" = src/pl/plpgsql/src/pl_unreserved_kwlist.h && continue + test "$f" = src/interfaces/ecpg/preproc/c_kwlist.h && continue + test "$f" = src/interfaces/ecpg/preproc/ecpg_kwlist.h && continue + test "$f" = src/include/regex/regerrs.h && continue + test "$f" = src/include/tcop/cmdtaglist.h && continue + test "$f" = src/pl/plpgsql/src/plerrcodes.h && continue + test "$f" = src/pl/plpython/spiexceptions.h && continue + test "$f" = src/pl/tcl/pltclerrcodes.h && continue + + # Also not meant to be included standalone. + test "$f" = src/include/common/unicode_combining_table.h && continue + test "$f" = src/include/common/unicode_east_asian_fw_table.h && continue + + # We can't make these Bison output files compilable standalone + # without using "%code require", which old Bison versions lack. + # parser/gram.h will be included by parser/gramparse.h anyway. + test "$f" = src/include/parser/gram.h && continue + test "$f" = src/backend/parser/gram.h && continue + test "$f" = src/pl/plpgsql/src/pl_gram.h && continue + test "$f" = src/interfaces/ecpg/preproc/preproc.h && continue + + # This produces a "no previous prototype" warning. + test "$f" = src/include/storage/checksum_impl.h && continue + + # ppport.h is not under our control, so we can't make it standalone. + test "$f" = src/pl/plperl/ppport.h && continue + + # regression.h is not actually C, but ECPG code. + test "$f" = src/interfaces/ecpg/test/regression.h && continue + # printf_hack.h produces "unused function" warnings. + test "$f" = src/interfaces/ecpg/test/printf_hack.h && continue + + # OK, create .c file to include this .h file. + { + test "$f" != src/include/postgres_fe.h && echo '#include "postgres.h"' + echo "#include \"$f\"" + } >$tmp/test.c + + # Some subdirectories need extra -I switches. + case "$f" in + src/pl/plperl/*) + EXTRAINCLUDES="$perl_includespec" ;; + src/pl/plpython/*) + EXTRAINCLUDES="$python_includespec" ;; + src/interfaces/ecpg/*) + EXTRAINCLUDES="-I $builddir/src/interfaces/ecpg/include -I $srcdir/src/interfaces/ecpg/include" ;; + *) + EXTRAINCLUDES="" ;; + esac + + # Run the test. + ${CC:-gcc} $CPPFLAGS $CFLAGS -I $builddir -I $srcdir \ + -I $builddir/src/include -I $srcdir/src/include \ + -I $builddir/src/interfaces/libpq -I $srcdir/src/interfaces/libpq \ + $EXTRAINCLUDES $EXTRAFLAGS -c $tmp/test.c -o $tmp/test.o + +done diff --git a/src/tools/pginclude/pgcheckdefines b/src/tools/pginclude/pgcheckdefines new file mode 100755 index 0000000..e46a756 --- /dev/null +++ b/src/tools/pginclude/pgcheckdefines @@ -0,0 +1,305 @@ +#! /usr/bin/perl + +# Copyright (c) 2021-2022, PostgreSQL Global Development Group + +# +# This script looks for symbols that are referenced in #ifdef or defined() +# tests without having #include'd the file that defines them. Since this +# situation won't necessarily lead to any compiler message, it seems worth +# having an automated check for it. In particular, use this to audit the +# results of pgrminclude! +# +# Usage: configure and build a PG source tree (non-VPATH), then start this +# script at the top level. It's best to enable as many configure options +# as you can, especially --enable-cassert which is known to affect include +# requirements. NB: you MUST use gcc, unless you have another compiler that +# can be persuaded to spit out the names of referenced include files. +# +# The results are necessarily platform-dependent, so use care in interpreting +# them. We try to process all .c files, even those not intended for the +# current platform, so there will be some phony failures. +# +# src/tools/pginclude/pgcheckdefines +# + +use strict; +use warnings; + +use Cwd; +use File::Basename; + +my $topdir = cwd(); + +# Programs to use +my $FIND = "find"; +my $MAKE = "make"; + +# +# Build arrays of all the .c and .h files in the tree +# +# We ignore .h files under src/include/port/, since only the one exposed as +# src/include/port.h is interesting. (XXX Windows ports have additional +# files there?) Ditto for .h files in src/backend/port/ subdirectories. +# Including these .h files would clutter the list of define'd symbols and +# cause a lot of false-positive results. +# +my (@cfiles, @hfiles); + +open my $pipe, '-|', "$FIND * -type f -name '*.c'" + or die "can't fork: $!"; +while (<$pipe>) +{ + chomp; + push @cfiles, $_; +} +close $pipe or die "$FIND failed: $!"; + +open $pipe, '-|', "$FIND * -type f -name '*.h'" + or die "can't fork: $!"; +while (<$pipe>) +{ + chomp; + push @hfiles, $_ + unless m|^src/include/port/| + || m|^src/backend/port/\w+/|; +} +close $pipe or die "$FIND failed: $!"; + +# +# For each .h file, extract all the symbols it #define's, and add them to +# a hash table. To cover the possibility of multiple .h files defining +# the same symbol, we make each hash entry a hash of filenames. +# +my %defines; + +foreach my $hfile (@hfiles) +{ + open my $fh, '<', $hfile + or die "can't open $hfile: $!"; + while (<$fh>) + { + if (m/^\s*#\s*define\s+(\w+)/) + { + $defines{$1}{$hfile} = 1; + } + } + close $fh; +} + +# +# For each file (both .h and .c), run the compiler to get a list of what +# files it #include's. Then extract all the symbols it tests for defined-ness, +# and check each one against the previously built hashtable. +# +foreach my $file (@hfiles, @cfiles) +{ + my ($fname, $fpath) = fileparse($file); + chdir $fpath or die "can't chdir to $fpath: $!"; + + # + # Ask 'make' to parse the makefile so we can get the correct flags to + # use. CPPFLAGS in particular varies for each subdirectory. If we are + # processing a .h file, we might be in a subdirectory that has no + # Makefile, in which case we have to fake it. Note that there seems + # no easy way to prevent make from recursing into subdirectories and + # hence printing multiple definitions --- we keep the last one, which + # should come from the current Makefile. + # + my $MAKECMD; + + if (-f "Makefile" || -f "GNUmakefile") + { + $MAKECMD = "$MAKE -qp"; + } + else + { + my $subdir = $fpath; + chop $subdir; + my $top_builddir = ".."; + my $tmp = $fpath; + while (($tmp = dirname($tmp)) ne '.') + { + $top_builddir = $top_builddir . "/.."; + } + $MAKECMD = + "$MAKE -qp 'subdir=$subdir' 'top_builddir=$top_builddir' -f '$top_builddir/src/Makefile.global'"; + } + + my ($CPPFLAGS, $CFLAGS, $CFLAGS_SL, $PTHREAD_CFLAGS, $CC); + + open $pipe, '-|', "$MAKECMD" + or die "can't fork: $!"; + while (<$pipe>) + { + if (m/^CPPFLAGS :?= (.*)/) + { + $CPPFLAGS = $1; + } + elsif (m/^CFLAGS :?= (.*)/) + { + $CFLAGS = $1; + } + elsif (m/^CFLAGS_SL :?= (.*)/) + { + $CFLAGS_SL = $1; + } + elsif (m/^PTHREAD_CFLAGS :?= (.*)/) + { + $PTHREAD_CFLAGS = $1; + } + elsif (m/^CC :?= (.*)/) + { + $CC = $1; + } + } + + # If make exits with status 1, it's not an error, it just means make + # thinks some files may not be up-to-date. Only complain on status 2. + close PIPE; + die "$MAKE failed in $fpath\n" if $? != 0 && $? != 256; + + # Expand out stuff that might be referenced in CFLAGS + $CFLAGS =~ s/\$\(CFLAGS_SL\)/$CFLAGS_SL/; + $CFLAGS =~ s/\$\(PTHREAD_CFLAGS\)/$PTHREAD_CFLAGS/; + + # + # Run the compiler (which had better be gcc) to get the inclusions. + # "gcc -H" reports inclusions on stderr as "... filename" where the + # number of dots varies according to nesting depth. + # + my @includes = (); + my $COMPILE = "$CC $CPPFLAGS $CFLAGS -H -E $fname"; + open $pipe, '-|', "$COMPILE 2>&1 >/dev/null" + or die "can't fork: $!"; + while (<$pipe>) + { + if (m/^\.+ (.*)/) + { + my $include = $1; + + # Ignore system headers (absolute paths); but complain if a + # .c file includes a system header before any PG header. + if ($include =~ m|^/|) + { + warn "$file includes $include before any Postgres inclusion\n" + if $#includes == -1 && $file =~ m/\.c$/; + next; + } + + # Strip any "./" (assume this appears only at front) + $include =~ s|^\./||; + + # Make path relative to top of tree + my $ipath = $fpath; + while ($include =~ s|^\.\./||) + { + $ipath = dirname($ipath) . "/"; + } + $ipath =~ s|^\./||; + push @includes, $ipath . $include; + } + else + { + warn "$CC: $_"; + } + } + + # The compiler might fail, particularly if we are checking a file that's + # not supposed to be compiled at all on the current platform, so don't + # quit on nonzero status. + close PIPE or warn "$COMPILE failed in $fpath\n"; + + # + # Scan the file to find #ifdef, #ifndef, and #if defined() constructs + # We assume #ifdef isn't continued across lines, and that defined(foo) + # isn't split across lines either + # + open my $fh, '<', $fname + or die "can't open $file: $!"; + my $inif = 0; + while (<$fh>) + { + my $line = $_; + if ($line =~ m/^\s*#\s*ifdef\s+(\w+)/) + { + checkit($file, $1, @includes); + } + if ($line =~ m/^\s*#\s*ifndef\s+(\w+)/) + { + checkit($file, $1, @includes); + } + if ($line =~ m/^\s*#\s*if\s+/) + { + $inif = 1; + } + if ($inif) + { + while ($line =~ s/\bdefined(\s+|\s*\(\s*)(\w+)//) + { + checkit($file, $2, @includes); + } + if (!($line =~ m/\\$/)) + { + $inif = 0; + } + } + } + close $fh; + + chdir $topdir or die "can't chdir to $topdir: $!"; +} + +exit 0; + +# Check an is-defined reference +sub checkit +{ + my ($file, $symbol, @includes) = @_; + + # Ignore if symbol isn't defined in any PG include files + if (!defined $defines{$symbol}) + { + return; + } + + # + # Try to match source(s) of symbol to the inclusions of the current file + # (including itself). We consider it OK if any one matches. + # + # Note: these tests aren't bulletproof; in theory the inclusion might + # occur after the use of the symbol. Given our normal file layout, + # however, the risk is minimal. + # + foreach my $deffile (keys %{ $defines{$symbol} }) + { + return if $deffile eq $file; + foreach my $reffile (@includes) + { + return if $deffile eq $reffile; + } + } + + # + # If current file is a .h file, it's OK for it to assume that one of the + # base headers (postgres.h or postgres_fe.h) has been included. + # + if ($file =~ m/\.h$/) + { + foreach my $deffile (keys %{ $defines{$symbol} }) + { + return if $deffile eq 'src/include/c.h'; + return if $deffile eq 'src/include/postgres.h'; + return if $deffile eq 'src/include/postgres_fe.h'; + return if $deffile eq 'src/include/pg_config.h'; + return if $deffile eq 'src/include/pg_config_manual.h'; + } + } + + # + my @places = keys %{ $defines{$symbol} }; + print "$file references $symbol, defined in @places\n"; + + # print "includes: @includes\n"; + + return; +} diff --git a/src/tools/pginclude/pgcompinclude b/src/tools/pginclude/pgcompinclude new file mode 100755 index 0000000..12169db --- /dev/null +++ b/src/tools/pginclude/pgcompinclude @@ -0,0 +1,47 @@ +: +# report which #include files can not compile on their own +# takes -v option to display compile failure message and line numbers +# src/tools/pginclude/pgcompinclude + +: ${CC:=cc} +: ${PGSRC:=src} + +if ! pgdefine +then echo "pgdefine must be in your PATH" 1>&2 + exit 1 +fi + +trap "rm -f /tmp/$$.c /tmp/$$.o /tmp/$$ /tmp/$$a" 0 1 2 3 15 +find . \( -name .git -a -prune \) -o -name '*.h' -type f -print | while read FILE +do + sed 's/->[a-zA-Z0-9_\.]*//g' "$FILE" >/tmp/$$a + echo "#include \"postgres.h\"" >/tmp/$$.c + + # suppress fcinfo errors + echo "struct {Datum arg[1];} *fcinfo;" >>/tmp/$$.c + + echo "#include \"/tmp/$$a\"" >>/tmp/$$.c + + echo "Datum include_test(void);" >>/tmp/$$.c + echo "Datum include_test() {" >>/tmp/$$.c + + pgdefine "$FILE" >>/tmp/$$.c + + echo "return (Datum)0;" >>/tmp/$$.c + echo "}" >>/tmp/$$.c + + # Use -O1 to get warnings only generated by optimization, + # but -O2 is too slow. + $CC -fsyntax-only -Werror -Wall -Wmissing-prototypes \ + -Wmissing-declarations -I$PGSRC/include -I$PGSRC/backend \ + -I$PGSRC/interfaces/libpq -I`dirname $FILE` $CFLAGS -O1 -c /tmp/$$.c \ + -o /tmp/$$.o >/tmp/$$ 2>&1 + if [ "$?" -ne 0 ] + then echo "$FILE" + if [ "$1" = "-v" ] + then cat /tmp/$$ + nl /tmp/$$.c + echo + fi + fi +done diff --git a/src/tools/pginclude/pgdefine b/src/tools/pginclude/pgdefine new file mode 100755 index 0000000..242d035 --- /dev/null +++ b/src/tools/pginclude/pgdefine @@ -0,0 +1,25 @@ +: +# create macro calls for all defines in the file + +# src/tools/pginclude/pgdefine + +trap "rm -f /tmp/$$" 0 1 2 3 15 +for FILE +do + cat "$FILE" | grep "^#define" >/tmp/$$ + cat /tmp/$$ | sed -n 's/^#define[ ][ ]*\([a-zA-Z0-9_]*\)[ ][ ]*[^ ].*\\\\$/\1;/p' + cat /tmp/$$ | sed -n 's/^#define[ ][ ]*\([a-zA-Z0-9_]*\)[ ][ ]*[^ ].*[^\\\\]$/(void)\1;/p' + + ( + cat /tmp/$$ | sed -n 's/^#define[ ][ ]*\([a-zA-Z0-9_]*([^)]*)\).*\\\\$/\1;/p' + cat /tmp/$$ | sed -n 's/^#define[ ][ ]*\([a-zA-Z0-9_]*([^)]*)\).*[^\\\\]$/(=void)\1;/p' + ) | + sed 's/([a-zA-Z0-9_ ][a-zA-Z0-9_ ]*)/(0)/g' | + sed 's/([a-zA-Z0-9_ ]*,/(0,/g' | + sed 's/,[a-zA-Z0-9_ ]*,/,0,/g' | + sed 's/,[a-zA-Z0-9_ ]*)/,0)/g' | + # do not cast 'return' macros as (void) + sed 's/(=void)\(.*return\)/\1/g' | + sed 's/(=void)\(.*RETURN\)/\1/g' | + sed 's/(=void)/(void)/g' +done diff --git a/src/tools/pginclude/pgfixinclude b/src/tools/pginclude/pgfixinclude new file mode 100755 index 0000000..6721566 --- /dev/null +++ b/src/tools/pginclude/pgfixinclude @@ -0,0 +1,21 @@ +: +# change #include's to <> or "" +# src/tools/pginclude/pgfixinclude + +trap "rm -f /tmp/$$.c /tmp/$$.o /tmp/$$ /tmp/$$a /tmp/$$b" 0 1 2 3 15 +find . \( -name .git -a -prune \) -o -type f -name '*.[chyls]' -print | +while read FILE +do + cat "$FILE" | grep "^#include" | + sed 's/^#include[ ]*[<"]\([^>"]*\).*$/\1/g' | + while read INCLUDE + do + if [ -s /usr/include/"$INCLUDE" ] + then cat "$FILE" | + sed 's;^#include[ ][ ]*[<"]'"$INCLUDE"'[>"]$;#include <'"$INCLUDE"'>;g' >/tmp/$$ + else cat "$FILE" | + sed 's;^#include[ ][ ]*[<"]'"$INCLUDE"'[>"]$;#include "'"$INCLUDE"'";g' >/tmp/$$ + fi + cat /tmp/$$ > "$FILE" + done +done diff --git a/src/tools/pginclude/pgrminclude b/src/tools/pginclude/pgrminclude new file mode 100755 index 0000000..7cbd2e7 --- /dev/null +++ b/src/tools/pginclude/pgrminclude @@ -0,0 +1,149 @@ +: +# remove extra #include's + +# pgcompinclude must be run before and after pgrminclude. It must be +# run before because we don't want include dependencies to leak into +# the C program files, and after because removal of includes from headers +# can cause new include unfulfilled dependencies. +# +# Limitations: 2011-09-24 +# +# Pgrminclude, when processing header files, can cause includes to be +# removed that require the addition of new illogical header files. +# This is dependent on what order the header files are processed. +# Manual review of header files now needed to satisfy pgcompinclude is +# required. +# +# C program files that have #ifdef blocks that contain code that cannot +# be compiled on the platform from which pgrminclude is run cannot be +# processed, and are skipped. + +: ${CC:=cc} +: ${PGSRC:=src} + +if ! pgdefine +then echo "pgdefine must be in your PATH" 1>&2 + exit 1 +fi + +trap "rm -f /tmp/$$.c /tmp/$$.o /tmp/$$ /tmp/$$a /tmp/$$b" 0 1 2 3 15 + +if [ "$1" = "-v" ] +then VERBOSE="Y" +else VERBOSE="" +fi + +verbose_output() { + if [ "$VERBOSE" ] + then cat /tmp/$$ + cat /tmp/$$b + nl /tmp/$$.c + fi +} + +process_includes_in_file() { + # loop through all includes mentioned in the file + cat "$FILE" | + grep "^#include\>" | + grep -v '/\* *pgrminclude *ignore *\*/' | + sed 's/^#include[ ]*[<"]\([^>"]*\).*$/\1/g' | + grep -v 'parser/kwlist\.h' | + grep -v '\.c$' | + while read INCLUDE + do if [ "$VERBOSE" ] + then echo "checking $FILE $INCLUDE" + fi + compile_file + done +} + +compile_file() { + [ "$INCLUDE" -a -s /usr/include/"$INCLUDE" ] && continue + [ "$INCLUDE" = "postgres.h" ] && continue + [ "$INCLUDE" = "postgres_fe.h" ] && continue + [ "$INCLUDE" = "pg_config.h" ] && continue + [ "$INCLUDE" = "c.h" ] && continue + # Stringify macros will expand undefined identifiers, so skip files that use it + egrep -q '\<(CppAsString2?|CppConcat)\>' "$FILE" && continue + + # preserve configure-specific includes + # these includes are surrounded by #ifdef's + grep -B1 '^#include[ ][ ]*[<"]'"$INCLUDE"'[>"]' "$FILE" | + egrep -q '^#if|^#else|^#elif' && continue + grep -A1 '^#include[ ][ ]*[<"]'"$INCLUDE"'[>"]' "$FILE" | + egrep -q '^#else|^#elif|^#endif' && continue + + # Remove all #if and #ifdef blocks because the blocks + # might contain code that is not compiled on this platform. + cat "$FILE" | + grep -v "^#if" | + grep -v "^#else" | + grep -v "^#elif" | + grep -v "^#endif" | + # with #if blocks gone, now undef #defines to avoid redefine + # warning and failure + sed 's/#define[ ][ ]*\([A-Za-z0-9_]*\).*$/#undef \1\n&/' >/tmp/$$a + + # set up initial file contents + grep -v '^#include[ ][ ]*[<"]'"$INCLUDE"'[>"]' \ + /tmp/$$a >/tmp/$$b + + if [ "$IS_INCLUDE" = "Y" ] + then echo "#include \"postgres.h\"" >/tmp/$$.c + # suppress fcinfo errors + echo "struct {Datum arg[1];} *fcinfo;" >>/tmp/$$.c + else >/tmp/$$.c + fi + + echo "#include \"/tmp/$$b\"" >>/tmp/$$.c + + if [ "$IS_INCLUDE" = "Y" ] + then echo "Datum include_test(void);" >>/tmp/$$.c + echo "Datum include_test() {" >>/tmp/$$.c + pgdefine "$FILE" >>/tmp/$$.c + echo "return (Datum)0;" >>/tmp/$$.c + echo "}" >>/tmp/$$.c + fi + + # Use -O1 to get warnings only generated by optimization, + # but -O2 is too slow. + $CC -fsyntax-only -Werror -Wall -Wmissing-prototypes \ + -Wmissing-declarations -I$PGSRC/include -I$PGSRC/backend \ + -I$PGSRC/interfaces/libpq -I`dirname $FILE` $CFLAGS -O1 -c /tmp/$$.c \ + -o /tmp/$$.o >/tmp/$$ 2>&1 + if [ "$?" -eq 0 ] + then [ "$INCLUDE" -o "$VERBOSE" ] && echo "$FILE $INCLUDE" + grep -v '^#include[ ][ ]*[<"]'"$INCLUDE"'[>"]' \ + "$FILE" >/tmp/$$b + mv /tmp/$$b "$FILE" + return 0 + else return 1 + fi +} + +# Process include files first because they can affect the compilation +# of *.c files. +(find . \( -name .git -a -prune \) -o -type f -name '*.h' -print | sort; + find . \( -name .git -a -prune \) -o -type f -name '*.c' -print | sort) | +grep -v '/postgres.h$' | +grep -v '/postgres_fe.h$' | +grep -v '/pg_config.h$' | +grep -v '\./c.h$' | +while read FILE +do + if [ `expr $FILE : '.*\.h$'` -ne 0 ] + then IS_INCLUDE="Y" + else IS_INCLUDE="N" + fi + + # Can we compile the file with all existing includes? + INCLUDE="" + compile_file + # If the file can't be compiled on its own, there is no sense + # trying to remove the include files. + if [ "$?" -ne 0 ] + then echo "cannot compile $FILE with existing includes" + verbose_output + else process_includes_in_file + fi +done |